xref: /illumos-gate/usr/src/uts/common/os/sunddi.c (revision 7c478bd9)
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 #include <sys/note.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/param.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/systm.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/buf.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/uio.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/cred.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/poll.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/mman.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/model.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/file.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/proc.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/open.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/user.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/t_lock.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/vm.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
47*7c478bd9Sstevel@tonic-gate #include <vm/hat.h>
48*7c478bd9Sstevel@tonic-gate #include <vm/seg.h>
49*7c478bd9Sstevel@tonic-gate #include <vm/seg_vn.h>
50*7c478bd9Sstevel@tonic-gate #include <vm/seg_dev.h>
51*7c478bd9Sstevel@tonic-gate #include <vm/as.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
53*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
54*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/esunddi.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/sunndi.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/conf.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h>	/* include implementation structure defs */
62*7c478bd9Sstevel@tonic-gate #include <sys/ndi_impldefs.h>	/* include prototypes */
63*7c478bd9Sstevel@tonic-gate #include <sys/hwconf.h>
64*7c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
66*7c478bd9Sstevel@tonic-gate #include <sys/epm.h>
67*7c478bd9Sstevel@tonic-gate #include <sys/devctl.h>
68*7c478bd9Sstevel@tonic-gate #include <sys/callb.h>
69*7c478bd9Sstevel@tonic-gate #include <sys/cladm.h>
70*7c478bd9Sstevel@tonic-gate #include <sys/sysevent.h>
71*7c478bd9Sstevel@tonic-gate #include <sys/dacf_impl.h>
72*7c478bd9Sstevel@tonic-gate #include <sys/ddidevmap.h>
73*7c478bd9Sstevel@tonic-gate #include <sys/bootconf.h>
74*7c478bd9Sstevel@tonic-gate #include <sys/disp.h>
75*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
76*7c478bd9Sstevel@tonic-gate #include <sys/promif.h>
77*7c478bd9Sstevel@tonic-gate #include <sys/instance.h>
78*7c478bd9Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
79*7c478bd9Sstevel@tonic-gate #include <sys/task.h>
80*7c478bd9Sstevel@tonic-gate #include <sys/project.h>
81*7c478bd9Sstevel@tonic-gate #include <sys/taskq.h>
82*7c478bd9Sstevel@tonic-gate #include <sys/devpolicy.h>
83*7c478bd9Sstevel@tonic-gate #include <sys/ctype.h>
84*7c478bd9Sstevel@tonic-gate #include <net/if.h>
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate extern	pri_t	minclsyspri;
87*7c478bd9Sstevel@tonic-gate 
88*7c478bd9Sstevel@tonic-gate extern	rctl_hndl_t rc_project_devlockmem;
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
91*7c478bd9Sstevel@tonic-gate static int sunddi_debug = 0;
92*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
93*7c478bd9Sstevel@tonic-gate 
94*7c478bd9Sstevel@tonic-gate /* ddi_umem_unlock miscellaneous */
95*7c478bd9Sstevel@tonic-gate 
96*7c478bd9Sstevel@tonic-gate static	void	i_ddi_umem_unlock_thread_start(void);
97*7c478bd9Sstevel@tonic-gate 
98*7c478bd9Sstevel@tonic-gate static	kmutex_t	ddi_umem_unlock_mutex; /* unlock list mutex */
99*7c478bd9Sstevel@tonic-gate static	kcondvar_t	ddi_umem_unlock_cv; /* unlock list block/unblock */
100*7c478bd9Sstevel@tonic-gate static	kthread_t	*ddi_umem_unlock_thread;
101*7c478bd9Sstevel@tonic-gate /*
102*7c478bd9Sstevel@tonic-gate  * The ddi_umem_unlock FIFO list.  NULL head pointer indicates empty list.
103*7c478bd9Sstevel@tonic-gate  */
104*7c478bd9Sstevel@tonic-gate static	struct	ddi_umem_cookie *ddi_umem_unlock_head = NULL;
105*7c478bd9Sstevel@tonic-gate static	struct	ddi_umem_cookie *ddi_umem_unlock_tail = NULL;
106*7c478bd9Sstevel@tonic-gate 
107*7c478bd9Sstevel@tonic-gate /*
108*7c478bd9Sstevel@tonic-gate  * This lock protects the project.max-device-locked-memory counter.
109*7c478bd9Sstevel@tonic-gate  * When both p_lock (proc_t) and this lock need to acquired, p_lock
110*7c478bd9Sstevel@tonic-gate  * should be acquired first.
111*7c478bd9Sstevel@tonic-gate  */
112*7c478bd9Sstevel@tonic-gate static kmutex_t umem_devlockmem_rctl_lock;
113*7c478bd9Sstevel@tonic-gate 
114*7c478bd9Sstevel@tonic-gate 
115*7c478bd9Sstevel@tonic-gate /*
116*7c478bd9Sstevel@tonic-gate  * DDI(Sun) Function and flag definitions:
117*7c478bd9Sstevel@tonic-gate  */
118*7c478bd9Sstevel@tonic-gate 
119*7c478bd9Sstevel@tonic-gate #if defined(__x86)
120*7c478bd9Sstevel@tonic-gate /*
121*7c478bd9Sstevel@tonic-gate  * Used to indicate which entries were chosen from a range.
122*7c478bd9Sstevel@tonic-gate  */
123*7c478bd9Sstevel@tonic-gate char	*chosen_reg = "chosen-reg";
124*7c478bd9Sstevel@tonic-gate #endif
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate /*
127*7c478bd9Sstevel@tonic-gate  * Function used to ring system console bell
128*7c478bd9Sstevel@tonic-gate  */
129*7c478bd9Sstevel@tonic-gate void (*ddi_console_bell_func)(clock_t duration);
130*7c478bd9Sstevel@tonic-gate 
131*7c478bd9Sstevel@tonic-gate /*
132*7c478bd9Sstevel@tonic-gate  * Creating register mappings and handling interrupts:
133*7c478bd9Sstevel@tonic-gate  */
134*7c478bd9Sstevel@tonic-gate 
135*7c478bd9Sstevel@tonic-gate /*
136*7c478bd9Sstevel@tonic-gate  * Generic ddi_map: Call parent to fulfill request...
137*7c478bd9Sstevel@tonic-gate  */
138*7c478bd9Sstevel@tonic-gate 
139*7c478bd9Sstevel@tonic-gate int
140*7c478bd9Sstevel@tonic-gate ddi_map(dev_info_t *dp, ddi_map_req_t *mp, off_t offset,
141*7c478bd9Sstevel@tonic-gate     off_t len, caddr_t *addrp)
142*7c478bd9Sstevel@tonic-gate {
143*7c478bd9Sstevel@tonic-gate 	dev_info_t *pdip;
144*7c478bd9Sstevel@tonic-gate 
145*7c478bd9Sstevel@tonic-gate 	ASSERT(dp);
146*7c478bd9Sstevel@tonic-gate 	pdip = (dev_info_t *)DEVI(dp)->devi_parent;
147*7c478bd9Sstevel@tonic-gate 	return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)(pdip,
148*7c478bd9Sstevel@tonic-gate 	    dp, mp, offset, len, addrp));
149*7c478bd9Sstevel@tonic-gate }
150*7c478bd9Sstevel@tonic-gate 
151*7c478bd9Sstevel@tonic-gate /*
152*7c478bd9Sstevel@tonic-gate  * ddi_apply_range: (Called by nexi only.)
153*7c478bd9Sstevel@tonic-gate  * Apply ranges in parent node dp, to child regspec rp...
154*7c478bd9Sstevel@tonic-gate  */
155*7c478bd9Sstevel@tonic-gate 
156*7c478bd9Sstevel@tonic-gate int
157*7c478bd9Sstevel@tonic-gate ddi_apply_range(dev_info_t *dp, dev_info_t *rdip, struct regspec *rp)
158*7c478bd9Sstevel@tonic-gate {
159*7c478bd9Sstevel@tonic-gate 	return (i_ddi_apply_range(dp, rdip, rp));
160*7c478bd9Sstevel@tonic-gate }
161*7c478bd9Sstevel@tonic-gate 
162*7c478bd9Sstevel@tonic-gate int
163*7c478bd9Sstevel@tonic-gate ddi_map_regs(dev_info_t *dip, uint_t rnumber, caddr_t *kaddrp, off_t offset,
164*7c478bd9Sstevel@tonic-gate     off_t len)
165*7c478bd9Sstevel@tonic-gate {
166*7c478bd9Sstevel@tonic-gate 	ddi_map_req_t mr;
167*7c478bd9Sstevel@tonic-gate #if defined(__x86)
168*7c478bd9Sstevel@tonic-gate 	struct {
169*7c478bd9Sstevel@tonic-gate 		int	bus;
170*7c478bd9Sstevel@tonic-gate 		int	addr;
171*7c478bd9Sstevel@tonic-gate 		int	size;
172*7c478bd9Sstevel@tonic-gate 	} reg, *reglist;
173*7c478bd9Sstevel@tonic-gate 	uint_t	length;
174*7c478bd9Sstevel@tonic-gate 	int	rc;
175*7c478bd9Sstevel@tonic-gate 
176*7c478bd9Sstevel@tonic-gate 	/*
177*7c478bd9Sstevel@tonic-gate 	 * get the 'registers' or the 'reg' property.
178*7c478bd9Sstevel@tonic-gate 	 * We look up the reg property as an array of
179*7c478bd9Sstevel@tonic-gate 	 * int's.
180*7c478bd9Sstevel@tonic-gate 	 */
181*7c478bd9Sstevel@tonic-gate 	rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
182*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "registers", (int **)&reglist, &length);
183*7c478bd9Sstevel@tonic-gate 	if (rc != DDI_PROP_SUCCESS)
184*7c478bd9Sstevel@tonic-gate 		rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
185*7c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "reg", (int **)&reglist, &length);
186*7c478bd9Sstevel@tonic-gate 	if (rc == DDI_PROP_SUCCESS) {
187*7c478bd9Sstevel@tonic-gate 		/*
188*7c478bd9Sstevel@tonic-gate 		 * point to the required entry.
189*7c478bd9Sstevel@tonic-gate 		 */
190*7c478bd9Sstevel@tonic-gate 		reg = reglist[rnumber];
191*7c478bd9Sstevel@tonic-gate 		reg.addr += offset;
192*7c478bd9Sstevel@tonic-gate 		if (len != 0)
193*7c478bd9Sstevel@tonic-gate 			reg.size = len;
194*7c478bd9Sstevel@tonic-gate 		/*
195*7c478bd9Sstevel@tonic-gate 		 * make a new property containing ONLY the required tuple.
196*7c478bd9Sstevel@tonic-gate 		 */
197*7c478bd9Sstevel@tonic-gate 		if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
198*7c478bd9Sstevel@tonic-gate 		    chosen_reg, (int *)&reg, (sizeof (reg)/sizeof (int)))
199*7c478bd9Sstevel@tonic-gate 		    != DDI_PROP_SUCCESS) {
200*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: cannot create '%s' "
201*7c478bd9Sstevel@tonic-gate 			    "property", DEVI(dip)->devi_name,
202*7c478bd9Sstevel@tonic-gate 			    DEVI(dip)->devi_instance, chosen_reg);
203*7c478bd9Sstevel@tonic-gate 		}
204*7c478bd9Sstevel@tonic-gate 		/*
205*7c478bd9Sstevel@tonic-gate 		 * free the memory allocated by
206*7c478bd9Sstevel@tonic-gate 		 * ddi_prop_lookup_int_array ().
207*7c478bd9Sstevel@tonic-gate 		 */
208*7c478bd9Sstevel@tonic-gate 		ddi_prop_free((void *)reglist);
209*7c478bd9Sstevel@tonic-gate 	}
210*7c478bd9Sstevel@tonic-gate #endif
211*7c478bd9Sstevel@tonic-gate 	mr.map_op = DDI_MO_MAP_LOCKED;
212*7c478bd9Sstevel@tonic-gate 	mr.map_type = DDI_MT_RNUMBER;
213*7c478bd9Sstevel@tonic-gate 	mr.map_obj.rnumber = rnumber;
214*7c478bd9Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
215*7c478bd9Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
216*7c478bd9Sstevel@tonic-gate 	mr.map_handlep = NULL;
217*7c478bd9Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate 	/*
220*7c478bd9Sstevel@tonic-gate 	 * Call my parent to map in my regs.
221*7c478bd9Sstevel@tonic-gate 	 */
222*7c478bd9Sstevel@tonic-gate 
223*7c478bd9Sstevel@tonic-gate 	return (ddi_map(dip, &mr, offset, len, kaddrp));
224*7c478bd9Sstevel@tonic-gate }
225*7c478bd9Sstevel@tonic-gate 
226*7c478bd9Sstevel@tonic-gate void
227*7c478bd9Sstevel@tonic-gate ddi_unmap_regs(dev_info_t *dip, uint_t rnumber, caddr_t *kaddrp, off_t offset,
228*7c478bd9Sstevel@tonic-gate     off_t len)
229*7c478bd9Sstevel@tonic-gate {
230*7c478bd9Sstevel@tonic-gate 	ddi_map_req_t mr;
231*7c478bd9Sstevel@tonic-gate 
232*7c478bd9Sstevel@tonic-gate 	mr.map_op = DDI_MO_UNMAP;
233*7c478bd9Sstevel@tonic-gate 	mr.map_type = DDI_MT_RNUMBER;
234*7c478bd9Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
235*7c478bd9Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;	/* who cares? */
236*7c478bd9Sstevel@tonic-gate 	mr.map_obj.rnumber = rnumber;
237*7c478bd9Sstevel@tonic-gate 	mr.map_handlep = NULL;
238*7c478bd9Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	/*
241*7c478bd9Sstevel@tonic-gate 	 * Call my parent to unmap my regs.
242*7c478bd9Sstevel@tonic-gate 	 */
243*7c478bd9Sstevel@tonic-gate 
244*7c478bd9Sstevel@tonic-gate 	(void) ddi_map(dip, &mr, offset, len, kaddrp);
245*7c478bd9Sstevel@tonic-gate 	*kaddrp = (caddr_t)0;
246*7c478bd9Sstevel@tonic-gate #if defined(__x86)
247*7c478bd9Sstevel@tonic-gate 	(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, chosen_reg);
248*7c478bd9Sstevel@tonic-gate #endif
249*7c478bd9Sstevel@tonic-gate }
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate int
252*7c478bd9Sstevel@tonic-gate ddi_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
253*7c478bd9Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *vaddrp)
254*7c478bd9Sstevel@tonic-gate {
255*7c478bd9Sstevel@tonic-gate 	return (i_ddi_bus_map(dip, rdip, mp, offset, len, vaddrp));
256*7c478bd9Sstevel@tonic-gate }
257*7c478bd9Sstevel@tonic-gate 
258*7c478bd9Sstevel@tonic-gate /*
259*7c478bd9Sstevel@tonic-gate  * nullbusmap:	The/DDI default bus_map entry point for nexi
260*7c478bd9Sstevel@tonic-gate  *		not conforming to the reg/range paradigm (i.e. scsi, etc.)
261*7c478bd9Sstevel@tonic-gate  *		with no HAT/MMU layer to be programmed at this level.
262*7c478bd9Sstevel@tonic-gate  *
263*7c478bd9Sstevel@tonic-gate  *		If the call is to map by rnumber, return an error,
264*7c478bd9Sstevel@tonic-gate  *		otherwise pass anything else up the tree to my parent.
265*7c478bd9Sstevel@tonic-gate  */
266*7c478bd9Sstevel@tonic-gate int
267*7c478bd9Sstevel@tonic-gate nullbusmap(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
268*7c478bd9Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *vaddrp)
269*7c478bd9Sstevel@tonic-gate {
270*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(rdip))
271*7c478bd9Sstevel@tonic-gate 	if (mp->map_type == DDI_MT_RNUMBER)
272*7c478bd9Sstevel@tonic-gate 		return (DDI_ME_UNSUPPORTED);
273*7c478bd9Sstevel@tonic-gate 
274*7c478bd9Sstevel@tonic-gate 	return (ddi_map(dip, mp, offset, len, vaddrp));
275*7c478bd9Sstevel@tonic-gate }
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate /*
278*7c478bd9Sstevel@tonic-gate  * ddi_rnumber_to_regspec: Not for use by leaf drivers.
279*7c478bd9Sstevel@tonic-gate  *			   Only for use by nexi using the reg/range paradigm.
280*7c478bd9Sstevel@tonic-gate  */
281*7c478bd9Sstevel@tonic-gate struct regspec *
282*7c478bd9Sstevel@tonic-gate ddi_rnumber_to_regspec(dev_info_t *dip, int rnumber)
283*7c478bd9Sstevel@tonic-gate {
284*7c478bd9Sstevel@tonic-gate 	return (i_ddi_rnumber_to_regspec(dip, rnumber));
285*7c478bd9Sstevel@tonic-gate }
286*7c478bd9Sstevel@tonic-gate 
287*7c478bd9Sstevel@tonic-gate 
288*7c478bd9Sstevel@tonic-gate /*
289*7c478bd9Sstevel@tonic-gate  * Note that we allow the dip to be nil because we may be called
290*7c478bd9Sstevel@tonic-gate  * prior even to the instantiation of the devinfo tree itself - all
291*7c478bd9Sstevel@tonic-gate  * regular leaf and nexus drivers should always use a non-nil dip!
292*7c478bd9Sstevel@tonic-gate  *
293*7c478bd9Sstevel@tonic-gate  * We treat peek in a somewhat cavalier fashion .. assuming that we'll
294*7c478bd9Sstevel@tonic-gate  * simply get a synchronous fault as soon as we touch a missing address.
295*7c478bd9Sstevel@tonic-gate  *
296*7c478bd9Sstevel@tonic-gate  * Poke is rather more carefully handled because we might poke to a write
297*7c478bd9Sstevel@tonic-gate  * buffer, "succeed", then only find some time later that we got an
298*7c478bd9Sstevel@tonic-gate  * asynchronous fault that indicated that the address we were writing to
299*7c478bd9Sstevel@tonic-gate  * was not really backed by hardware.
300*7c478bd9Sstevel@tonic-gate  */
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate static int
303*7c478bd9Sstevel@tonic-gate i_ddi_peekpoke(dev_info_t *devi, ddi_ctl_enum_t cmd, size_t size,
304*7c478bd9Sstevel@tonic-gate     void *addr, void *value_p)
305*7c478bd9Sstevel@tonic-gate {
306*7c478bd9Sstevel@tonic-gate 	union {
307*7c478bd9Sstevel@tonic-gate 		uint64_t	u64;
308*7c478bd9Sstevel@tonic-gate 		uint32_t	u32;
309*7c478bd9Sstevel@tonic-gate 		uint16_t	u16;
310*7c478bd9Sstevel@tonic-gate 		uint8_t		u8;
311*7c478bd9Sstevel@tonic-gate 	} peekpoke_value;
312*7c478bd9Sstevel@tonic-gate 
313*7c478bd9Sstevel@tonic-gate 	peekpoke_ctlops_t peekpoke_args;
314*7c478bd9Sstevel@tonic-gate 	uint64_t dummy_result;
315*7c478bd9Sstevel@tonic-gate 	int rval;
316*7c478bd9Sstevel@tonic-gate 
317*7c478bd9Sstevel@tonic-gate 	/* Note: size is assumed to be correct;  it is not checked. */
318*7c478bd9Sstevel@tonic-gate 	peekpoke_args.size = size;
319*7c478bd9Sstevel@tonic-gate 	peekpoke_args.dev_addr = (uint64_t)addr;
320*7c478bd9Sstevel@tonic-gate 	peekpoke_args.handle = NULL;
321*7c478bd9Sstevel@tonic-gate 	peekpoke_args.repcount = 1;
322*7c478bd9Sstevel@tonic-gate 	peekpoke_args.flags = 0;
323*7c478bd9Sstevel@tonic-gate 
324*7c478bd9Sstevel@tonic-gate 	if (cmd == DDI_CTLOPS_POKE) {
325*7c478bd9Sstevel@tonic-gate 		switch (size) {
326*7c478bd9Sstevel@tonic-gate 		case sizeof (uint8_t):
327*7c478bd9Sstevel@tonic-gate 			peekpoke_value.u8 = *(uint8_t *)value_p;
328*7c478bd9Sstevel@tonic-gate 			break;
329*7c478bd9Sstevel@tonic-gate 		case sizeof (uint16_t):
330*7c478bd9Sstevel@tonic-gate 			peekpoke_value.u16 = *(uint16_t *)value_p;
331*7c478bd9Sstevel@tonic-gate 			break;
332*7c478bd9Sstevel@tonic-gate 		case sizeof (uint32_t):
333*7c478bd9Sstevel@tonic-gate 			peekpoke_value.u32 = *(uint32_t *)value_p;
334*7c478bd9Sstevel@tonic-gate 			break;
335*7c478bd9Sstevel@tonic-gate 		case sizeof (uint64_t):
336*7c478bd9Sstevel@tonic-gate 			peekpoke_value.u64 = *(uint64_t *)value_p;
337*7c478bd9Sstevel@tonic-gate 			break;
338*7c478bd9Sstevel@tonic-gate 		}
339*7c478bd9Sstevel@tonic-gate 	}
340*7c478bd9Sstevel@tonic-gate 
341*7c478bd9Sstevel@tonic-gate 	peekpoke_args.host_addr = (uint64_t)&peekpoke_value.u64;
342*7c478bd9Sstevel@tonic-gate 
343*7c478bd9Sstevel@tonic-gate 	if (devi != NULL)
344*7c478bd9Sstevel@tonic-gate 		rval = ddi_ctlops(devi, devi, cmd, &peekpoke_args,
345*7c478bd9Sstevel@tonic-gate 		    &dummy_result);
346*7c478bd9Sstevel@tonic-gate 	else
347*7c478bd9Sstevel@tonic-gate 		rval = peekpoke_mem(cmd, &peekpoke_args);
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	/*
350*7c478bd9Sstevel@tonic-gate 	 * A NULL value_p is permitted by ddi_peek(9F); discard the result.
351*7c478bd9Sstevel@tonic-gate 	 */
352*7c478bd9Sstevel@tonic-gate 	if ((cmd == DDI_CTLOPS_PEEK) & (value_p != NULL)) {
353*7c478bd9Sstevel@tonic-gate 		switch (size) {
354*7c478bd9Sstevel@tonic-gate 		case sizeof (uint8_t):
355*7c478bd9Sstevel@tonic-gate 			*(uint8_t *)value_p = peekpoke_value.u8;
356*7c478bd9Sstevel@tonic-gate 			break;
357*7c478bd9Sstevel@tonic-gate 		case sizeof (uint16_t):
358*7c478bd9Sstevel@tonic-gate 			*(uint16_t *)value_p = peekpoke_value.u16;
359*7c478bd9Sstevel@tonic-gate 			break;
360*7c478bd9Sstevel@tonic-gate 		case sizeof (uint32_t):
361*7c478bd9Sstevel@tonic-gate 			*(uint32_t *)value_p = peekpoke_value.u32;
362*7c478bd9Sstevel@tonic-gate 			break;
363*7c478bd9Sstevel@tonic-gate 		case sizeof (uint64_t):
364*7c478bd9Sstevel@tonic-gate 			*(uint64_t *)value_p = peekpoke_value.u64;
365*7c478bd9Sstevel@tonic-gate 			break;
366*7c478bd9Sstevel@tonic-gate 		}
367*7c478bd9Sstevel@tonic-gate 	}
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 	return (rval);
370*7c478bd9Sstevel@tonic-gate }
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate /*
373*7c478bd9Sstevel@tonic-gate  * Keep ddi_peek() and ddi_poke() in case 3rd parties are calling this.
374*7c478bd9Sstevel@tonic-gate  * they shouldn't be, but the 9f manpage kind of pseudo exposes it.
375*7c478bd9Sstevel@tonic-gate  */
376*7c478bd9Sstevel@tonic-gate int
377*7c478bd9Sstevel@tonic-gate ddi_peek(dev_info_t *devi, size_t size, void *addr, void *value_p)
378*7c478bd9Sstevel@tonic-gate {
379*7c478bd9Sstevel@tonic-gate 	switch (size) {
380*7c478bd9Sstevel@tonic-gate 	case sizeof (uint8_t):
381*7c478bd9Sstevel@tonic-gate 	case sizeof (uint16_t):
382*7c478bd9Sstevel@tonic-gate 	case sizeof (uint32_t):
383*7c478bd9Sstevel@tonic-gate 	case sizeof (uint64_t):
384*7c478bd9Sstevel@tonic-gate 		break;
385*7c478bd9Sstevel@tonic-gate 	default:
386*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
387*7c478bd9Sstevel@tonic-gate 	}
388*7c478bd9Sstevel@tonic-gate 
389*7c478bd9Sstevel@tonic-gate 	return (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, size, addr, value_p));
390*7c478bd9Sstevel@tonic-gate }
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate int
393*7c478bd9Sstevel@tonic-gate ddi_poke(dev_info_t *devi, size_t size, void *addr, void *value_p)
394*7c478bd9Sstevel@tonic-gate {
395*7c478bd9Sstevel@tonic-gate 	switch (size) {
396*7c478bd9Sstevel@tonic-gate 	case sizeof (uint8_t):
397*7c478bd9Sstevel@tonic-gate 	case sizeof (uint16_t):
398*7c478bd9Sstevel@tonic-gate 	case sizeof (uint32_t):
399*7c478bd9Sstevel@tonic-gate 	case sizeof (uint64_t):
400*7c478bd9Sstevel@tonic-gate 		break;
401*7c478bd9Sstevel@tonic-gate 	default:
402*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
403*7c478bd9Sstevel@tonic-gate 	}
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	return (i_ddi_peekpoke(devi, DDI_CTLOPS_POKE, size, addr, value_p));
406*7c478bd9Sstevel@tonic-gate }
407*7c478bd9Sstevel@tonic-gate 
408*7c478bd9Sstevel@tonic-gate #ifdef _LP64
409*7c478bd9Sstevel@tonic-gate int
410*7c478bd9Sstevel@tonic-gate ddi_peek8(dev_info_t *dip, int8_t *addr, int8_t *val_p)
411*7c478bd9Sstevel@tonic-gate #else /* _ILP32 */
412*7c478bd9Sstevel@tonic-gate int
413*7c478bd9Sstevel@tonic-gate ddi_peekc(dev_info_t *dip, int8_t *addr, int8_t *val_p)
414*7c478bd9Sstevel@tonic-gate #endif
415*7c478bd9Sstevel@tonic-gate {
416*7c478bd9Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
417*7c478bd9Sstevel@tonic-gate 	    val_p));
418*7c478bd9Sstevel@tonic-gate }
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate #ifdef _LP64
421*7c478bd9Sstevel@tonic-gate int
422*7c478bd9Sstevel@tonic-gate ddi_peek16(dev_info_t *dip, int16_t *addr, int16_t *val_p)
423*7c478bd9Sstevel@tonic-gate #else /* _ILP32 */
424*7c478bd9Sstevel@tonic-gate int
425*7c478bd9Sstevel@tonic-gate ddi_peeks(dev_info_t *dip, int16_t *addr, int16_t *val_p)
426*7c478bd9Sstevel@tonic-gate #endif
427*7c478bd9Sstevel@tonic-gate {
428*7c478bd9Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
429*7c478bd9Sstevel@tonic-gate 	    val_p));
430*7c478bd9Sstevel@tonic-gate }
431*7c478bd9Sstevel@tonic-gate 
432*7c478bd9Sstevel@tonic-gate #ifdef _LP64
433*7c478bd9Sstevel@tonic-gate int
434*7c478bd9Sstevel@tonic-gate ddi_peek32(dev_info_t *dip, int32_t *addr, int32_t *val_p)
435*7c478bd9Sstevel@tonic-gate #else /* _ILP32 */
436*7c478bd9Sstevel@tonic-gate int
437*7c478bd9Sstevel@tonic-gate ddi_peekl(dev_info_t *dip, int32_t *addr, int32_t *val_p)
438*7c478bd9Sstevel@tonic-gate #endif
439*7c478bd9Sstevel@tonic-gate {
440*7c478bd9Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
441*7c478bd9Sstevel@tonic-gate 	    val_p));
442*7c478bd9Sstevel@tonic-gate }
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate #ifdef _LP64
445*7c478bd9Sstevel@tonic-gate int
446*7c478bd9Sstevel@tonic-gate ddi_peek64(dev_info_t *dip, int64_t *addr, int64_t *val_p)
447*7c478bd9Sstevel@tonic-gate #else /* _ILP32 */
448*7c478bd9Sstevel@tonic-gate int
449*7c478bd9Sstevel@tonic-gate ddi_peekd(dev_info_t *dip, int64_t *addr, int64_t *val_p)
450*7c478bd9Sstevel@tonic-gate #endif
451*7c478bd9Sstevel@tonic-gate {
452*7c478bd9Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
453*7c478bd9Sstevel@tonic-gate 	    val_p));
454*7c478bd9Sstevel@tonic-gate }
455*7c478bd9Sstevel@tonic-gate 
456*7c478bd9Sstevel@tonic-gate #ifdef _LP64
457*7c478bd9Sstevel@tonic-gate int
458*7c478bd9Sstevel@tonic-gate ddi_poke8(dev_info_t *dip, int8_t *addr, int8_t val)
459*7c478bd9Sstevel@tonic-gate #else /* _ILP32 */
460*7c478bd9Sstevel@tonic-gate int
461*7c478bd9Sstevel@tonic-gate ddi_pokec(dev_info_t *dip, int8_t *addr, int8_t val)
462*7c478bd9Sstevel@tonic-gate #endif
463*7c478bd9Sstevel@tonic-gate {
464*7c478bd9Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
465*7c478bd9Sstevel@tonic-gate }
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate #ifdef _LP64
468*7c478bd9Sstevel@tonic-gate int
469*7c478bd9Sstevel@tonic-gate ddi_poke16(dev_info_t *dip, int16_t *addr, int16_t val)
470*7c478bd9Sstevel@tonic-gate #else /* _ILP32 */
471*7c478bd9Sstevel@tonic-gate int
472*7c478bd9Sstevel@tonic-gate ddi_pokes(dev_info_t *dip, int16_t *addr, int16_t val)
473*7c478bd9Sstevel@tonic-gate #endif
474*7c478bd9Sstevel@tonic-gate {
475*7c478bd9Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
476*7c478bd9Sstevel@tonic-gate }
477*7c478bd9Sstevel@tonic-gate 
478*7c478bd9Sstevel@tonic-gate #ifdef _LP64
479*7c478bd9Sstevel@tonic-gate int
480*7c478bd9Sstevel@tonic-gate ddi_poke32(dev_info_t *dip, int32_t *addr, int32_t val)
481*7c478bd9Sstevel@tonic-gate #else /* _ILP32 */
482*7c478bd9Sstevel@tonic-gate int
483*7c478bd9Sstevel@tonic-gate ddi_pokel(dev_info_t *dip, int32_t *addr, int32_t val)
484*7c478bd9Sstevel@tonic-gate #endif
485*7c478bd9Sstevel@tonic-gate {
486*7c478bd9Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
487*7c478bd9Sstevel@tonic-gate }
488*7c478bd9Sstevel@tonic-gate 
489*7c478bd9Sstevel@tonic-gate #ifdef _LP64
490*7c478bd9Sstevel@tonic-gate int
491*7c478bd9Sstevel@tonic-gate ddi_poke64(dev_info_t *dip, int64_t *addr, int64_t val)
492*7c478bd9Sstevel@tonic-gate #else /* _ILP32 */
493*7c478bd9Sstevel@tonic-gate int
494*7c478bd9Sstevel@tonic-gate ddi_poked(dev_info_t *dip, int64_t *addr, int64_t val)
495*7c478bd9Sstevel@tonic-gate #endif
496*7c478bd9Sstevel@tonic-gate {
497*7c478bd9Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
498*7c478bd9Sstevel@tonic-gate }
499*7c478bd9Sstevel@tonic-gate 
500*7c478bd9Sstevel@tonic-gate /*
501*7c478bd9Sstevel@tonic-gate  * ddi_peekpokeio() is used primarily by the mem drivers for moving
502*7c478bd9Sstevel@tonic-gate  * data to and from uio structures via peek and poke.  Note that we
503*7c478bd9Sstevel@tonic-gate  * use "internal" routines ddi_peek and ddi_poke to make this go
504*7c478bd9Sstevel@tonic-gate  * slightly faster, avoiding the call overhead ..
505*7c478bd9Sstevel@tonic-gate  */
506*7c478bd9Sstevel@tonic-gate int
507*7c478bd9Sstevel@tonic-gate ddi_peekpokeio(dev_info_t *devi, struct uio *uio, enum uio_rw rw,
508*7c478bd9Sstevel@tonic-gate     caddr_t addr, size_t len, uint_t xfersize)
509*7c478bd9Sstevel@tonic-gate {
510*7c478bd9Sstevel@tonic-gate 	int64_t	ibuffer;
511*7c478bd9Sstevel@tonic-gate 	int8_t w8;
512*7c478bd9Sstevel@tonic-gate 	size_t sz;
513*7c478bd9Sstevel@tonic-gate 	int o;
514*7c478bd9Sstevel@tonic-gate 
515*7c478bd9Sstevel@tonic-gate 	if (xfersize > sizeof (long))
516*7c478bd9Sstevel@tonic-gate 		xfersize = sizeof (long);
517*7c478bd9Sstevel@tonic-gate 
518*7c478bd9Sstevel@tonic-gate 	while (len != 0) {
519*7c478bd9Sstevel@tonic-gate 		if ((len | (uintptr_t)addr) & 1) {
520*7c478bd9Sstevel@tonic-gate 			sz = sizeof (int8_t);
521*7c478bd9Sstevel@tonic-gate 			if (rw == UIO_WRITE) {
522*7c478bd9Sstevel@tonic-gate 				if ((o = uwritec(uio)) == -1)
523*7c478bd9Sstevel@tonic-gate 					return (DDI_FAILURE);
524*7c478bd9Sstevel@tonic-gate 				if (ddi_poke8(devi, (int8_t *)addr,
525*7c478bd9Sstevel@tonic-gate 				    (int8_t)o) != DDI_SUCCESS)
526*7c478bd9Sstevel@tonic-gate 					return (DDI_FAILURE);
527*7c478bd9Sstevel@tonic-gate 			} else {
528*7c478bd9Sstevel@tonic-gate 				if (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, sz,
529*7c478bd9Sstevel@tonic-gate 				    (int8_t *)addr, &w8) != DDI_SUCCESS)
530*7c478bd9Sstevel@tonic-gate 					return (DDI_FAILURE);
531*7c478bd9Sstevel@tonic-gate 				if (ureadc(w8, uio))
532*7c478bd9Sstevel@tonic-gate 					return (DDI_FAILURE);
533*7c478bd9Sstevel@tonic-gate 			}
534*7c478bd9Sstevel@tonic-gate 		} else {
535*7c478bd9Sstevel@tonic-gate 			switch (xfersize) {
536*7c478bd9Sstevel@tonic-gate 			case sizeof (int64_t):
537*7c478bd9Sstevel@tonic-gate 				if (((len | (uintptr_t)addr) &
538*7c478bd9Sstevel@tonic-gate 				    (sizeof (int64_t) - 1)) == 0) {
539*7c478bd9Sstevel@tonic-gate 					sz = xfersize;
540*7c478bd9Sstevel@tonic-gate 					break;
541*7c478bd9Sstevel@tonic-gate 				}
542*7c478bd9Sstevel@tonic-gate 				/*FALLTHROUGH*/
543*7c478bd9Sstevel@tonic-gate 			case sizeof (int32_t):
544*7c478bd9Sstevel@tonic-gate 				if (((len | (uintptr_t)addr) &
545*7c478bd9Sstevel@tonic-gate 				    (sizeof (int32_t) - 1)) == 0) {
546*7c478bd9Sstevel@tonic-gate 					sz = xfersize;
547*7c478bd9Sstevel@tonic-gate 					break;
548*7c478bd9Sstevel@tonic-gate 				}
549*7c478bd9Sstevel@tonic-gate 				/*FALLTHROUGH*/
550*7c478bd9Sstevel@tonic-gate 			default:
551*7c478bd9Sstevel@tonic-gate 				/*
552*7c478bd9Sstevel@tonic-gate 				 * This still assumes that we might have an
553*7c478bd9Sstevel@tonic-gate 				 * I/O bus out there that permits 16-bit
554*7c478bd9Sstevel@tonic-gate 				 * transfers (and that it would be upset by
555*7c478bd9Sstevel@tonic-gate 				 * 32-bit transfers from such locations).
556*7c478bd9Sstevel@tonic-gate 				 */
557*7c478bd9Sstevel@tonic-gate 				sz = sizeof (int16_t);
558*7c478bd9Sstevel@tonic-gate 				break;
559*7c478bd9Sstevel@tonic-gate 			}
560*7c478bd9Sstevel@tonic-gate 
561*7c478bd9Sstevel@tonic-gate 			if (rw == UIO_READ) {
562*7c478bd9Sstevel@tonic-gate 				if (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, sz,
563*7c478bd9Sstevel@tonic-gate 				    addr, &ibuffer) != DDI_SUCCESS)
564*7c478bd9Sstevel@tonic-gate 					return (DDI_FAILURE);
565*7c478bd9Sstevel@tonic-gate 			}
566*7c478bd9Sstevel@tonic-gate 
567*7c478bd9Sstevel@tonic-gate 			if (uiomove(&ibuffer, sz, rw, uio))
568*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
569*7c478bd9Sstevel@tonic-gate 
570*7c478bd9Sstevel@tonic-gate 			if (rw == UIO_WRITE) {
571*7c478bd9Sstevel@tonic-gate 				if (i_ddi_peekpoke(devi, DDI_CTLOPS_POKE, sz,
572*7c478bd9Sstevel@tonic-gate 				    addr, &ibuffer) != DDI_SUCCESS)
573*7c478bd9Sstevel@tonic-gate 					return (DDI_FAILURE);
574*7c478bd9Sstevel@tonic-gate 			}
575*7c478bd9Sstevel@tonic-gate 		}
576*7c478bd9Sstevel@tonic-gate 		addr += sz;
577*7c478bd9Sstevel@tonic-gate 		len -= sz;
578*7c478bd9Sstevel@tonic-gate 	}
579*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
580*7c478bd9Sstevel@tonic-gate }
581*7c478bd9Sstevel@tonic-gate 
582*7c478bd9Sstevel@tonic-gate /*
583*7c478bd9Sstevel@tonic-gate  * These routines are used by drivers that do layered ioctls
584*7c478bd9Sstevel@tonic-gate  * On sparc, they're implemented in assembler to avoid spilling
585*7c478bd9Sstevel@tonic-gate  * register windows in the common (copyin) case ..
586*7c478bd9Sstevel@tonic-gate  */
587*7c478bd9Sstevel@tonic-gate #if !defined(__sparc)
588*7c478bd9Sstevel@tonic-gate int
589*7c478bd9Sstevel@tonic-gate ddi_copyin(const void *buf, void *kernbuf, size_t size, int flags)
590*7c478bd9Sstevel@tonic-gate {
591*7c478bd9Sstevel@tonic-gate 	if (flags & FKIOCTL)
592*7c478bd9Sstevel@tonic-gate 		return (kcopy(buf, kernbuf, size) ? -1 : 0);
593*7c478bd9Sstevel@tonic-gate 	return (copyin(buf, kernbuf, size));
594*7c478bd9Sstevel@tonic-gate }
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate int
597*7c478bd9Sstevel@tonic-gate ddi_copyout(const void *buf, void *kernbuf, size_t size, int flags)
598*7c478bd9Sstevel@tonic-gate {
599*7c478bd9Sstevel@tonic-gate 	if (flags & FKIOCTL)
600*7c478bd9Sstevel@tonic-gate 		return (kcopy(buf, kernbuf, size) ? -1 : 0);
601*7c478bd9Sstevel@tonic-gate 	return (copyout(buf, kernbuf, size));
602*7c478bd9Sstevel@tonic-gate }
603*7c478bd9Sstevel@tonic-gate #endif	/* !__sparc */
604*7c478bd9Sstevel@tonic-gate 
605*7c478bd9Sstevel@tonic-gate /*
606*7c478bd9Sstevel@tonic-gate  * Conversions in nexus pagesize units.  We don't duplicate the
607*7c478bd9Sstevel@tonic-gate  * 'nil dip' semantics of peek/poke because btopr/btop/ptob are DDI/DKI
608*7c478bd9Sstevel@tonic-gate  * routines anyway.
609*7c478bd9Sstevel@tonic-gate  */
610*7c478bd9Sstevel@tonic-gate unsigned long
611*7c478bd9Sstevel@tonic-gate ddi_btop(dev_info_t *dip, unsigned long bytes)
612*7c478bd9Sstevel@tonic-gate {
613*7c478bd9Sstevel@tonic-gate 	unsigned long pages;
614*7c478bd9Sstevel@tonic-gate 
615*7c478bd9Sstevel@tonic-gate 	(void) ddi_ctlops(dip, dip, DDI_CTLOPS_BTOP, &bytes, &pages);
616*7c478bd9Sstevel@tonic-gate 	return (pages);
617*7c478bd9Sstevel@tonic-gate }
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate unsigned long
620*7c478bd9Sstevel@tonic-gate ddi_btopr(dev_info_t *dip, unsigned long bytes)
621*7c478bd9Sstevel@tonic-gate {
622*7c478bd9Sstevel@tonic-gate 	unsigned long pages;
623*7c478bd9Sstevel@tonic-gate 
624*7c478bd9Sstevel@tonic-gate 	(void) ddi_ctlops(dip, dip, DDI_CTLOPS_BTOPR, &bytes, &pages);
625*7c478bd9Sstevel@tonic-gate 	return (pages);
626*7c478bd9Sstevel@tonic-gate }
627*7c478bd9Sstevel@tonic-gate 
628*7c478bd9Sstevel@tonic-gate unsigned long
629*7c478bd9Sstevel@tonic-gate ddi_ptob(dev_info_t *dip, unsigned long pages)
630*7c478bd9Sstevel@tonic-gate {
631*7c478bd9Sstevel@tonic-gate 	unsigned long bytes;
632*7c478bd9Sstevel@tonic-gate 
633*7c478bd9Sstevel@tonic-gate 	(void) ddi_ctlops(dip, dip, DDI_CTLOPS_PTOB, &pages, &bytes);
634*7c478bd9Sstevel@tonic-gate 	return (bytes);
635*7c478bd9Sstevel@tonic-gate }
636*7c478bd9Sstevel@tonic-gate 
637*7c478bd9Sstevel@tonic-gate unsigned int
638*7c478bd9Sstevel@tonic-gate ddi_enter_critical(void)
639*7c478bd9Sstevel@tonic-gate {
640*7c478bd9Sstevel@tonic-gate 	return ((uint_t)spl7());
641*7c478bd9Sstevel@tonic-gate }
642*7c478bd9Sstevel@tonic-gate 
643*7c478bd9Sstevel@tonic-gate void
644*7c478bd9Sstevel@tonic-gate ddi_exit_critical(unsigned int spl)
645*7c478bd9Sstevel@tonic-gate {
646*7c478bd9Sstevel@tonic-gate 	splx((int)spl);
647*7c478bd9Sstevel@tonic-gate }
648*7c478bd9Sstevel@tonic-gate 
649*7c478bd9Sstevel@tonic-gate /*
650*7c478bd9Sstevel@tonic-gate  * Nexus ctlops punter
651*7c478bd9Sstevel@tonic-gate  */
652*7c478bd9Sstevel@tonic-gate 
653*7c478bd9Sstevel@tonic-gate #if !defined(__sparc)
654*7c478bd9Sstevel@tonic-gate /*
655*7c478bd9Sstevel@tonic-gate  * Request bus_ctl parent to handle a bus_ctl request
656*7c478bd9Sstevel@tonic-gate  *
657*7c478bd9Sstevel@tonic-gate  * (The sparc version is in sparc_ddi.s)
658*7c478bd9Sstevel@tonic-gate  */
659*7c478bd9Sstevel@tonic-gate int
660*7c478bd9Sstevel@tonic-gate ddi_ctlops(dev_info_t *d, dev_info_t *r, ddi_ctl_enum_t op, void *a, void *v)
661*7c478bd9Sstevel@tonic-gate {
662*7c478bd9Sstevel@tonic-gate 	int (*fp)();
663*7c478bd9Sstevel@tonic-gate 
664*7c478bd9Sstevel@tonic-gate 	if (!d || !r)
665*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
666*7c478bd9Sstevel@tonic-gate 
667*7c478bd9Sstevel@tonic-gate 	if ((d = (dev_info_t *)DEVI(d)->devi_bus_ctl) == NULL)
668*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 	fp = DEVI(d)->devi_ops->devo_bus_ops->bus_ctl;
671*7c478bd9Sstevel@tonic-gate 	return ((*fp)(d, r, op, a, v));
672*7c478bd9Sstevel@tonic-gate }
673*7c478bd9Sstevel@tonic-gate 
674*7c478bd9Sstevel@tonic-gate #endif
675*7c478bd9Sstevel@tonic-gate 
676*7c478bd9Sstevel@tonic-gate /*
677*7c478bd9Sstevel@tonic-gate  * DMA/DVMA setup
678*7c478bd9Sstevel@tonic-gate  */
679*7c478bd9Sstevel@tonic-gate 
680*7c478bd9Sstevel@tonic-gate #if defined(__sparc)
681*7c478bd9Sstevel@tonic-gate static ddi_dma_lim_t standard_limits = {
682*7c478bd9Sstevel@tonic-gate 	(uint_t)0,	/* addr_t dlim_addr_lo */
683*7c478bd9Sstevel@tonic-gate 	(uint_t)-1,	/* addr_t dlim_addr_hi */
684*7c478bd9Sstevel@tonic-gate 	(uint_t)-1,	/* uint_t dlim_cntr_max */
685*7c478bd9Sstevel@tonic-gate 	(uint_t)1,	/* uint_t dlim_burstsizes */
686*7c478bd9Sstevel@tonic-gate 	(uint_t)1,	/* uint_t dlim_minxfer */
687*7c478bd9Sstevel@tonic-gate 	0		/* uint_t dlim_dmaspeed */
688*7c478bd9Sstevel@tonic-gate };
689*7c478bd9Sstevel@tonic-gate #elif defined(__x86)
690*7c478bd9Sstevel@tonic-gate static ddi_dma_lim_t standard_limits = {
691*7c478bd9Sstevel@tonic-gate 	(uint_t)0,		/* addr_t dlim_addr_lo */
692*7c478bd9Sstevel@tonic-gate 	(uint_t)0xffffff,	/* addr_t dlim_addr_hi */
693*7c478bd9Sstevel@tonic-gate 	(uint_t)0,		/* uint_t dlim_cntr_max */
694*7c478bd9Sstevel@tonic-gate 	(uint_t)0x00000001,	/* uint_t dlim_burstsizes */
695*7c478bd9Sstevel@tonic-gate 	(uint_t)DMA_UNIT_8,	/* uint_t dlim_minxfer */
696*7c478bd9Sstevel@tonic-gate 	(uint_t)0,		/* uint_t dlim_dmaspeed */
697*7c478bd9Sstevel@tonic-gate 	(uint_t)0x86<<24+0,	/* uint_t dlim_version */
698*7c478bd9Sstevel@tonic-gate 	(uint_t)0xffff,		/* uint_t dlim_adreg_max */
699*7c478bd9Sstevel@tonic-gate 	(uint_t)0xffff,		/* uint_t dlim_ctreg_max */
700*7c478bd9Sstevel@tonic-gate 	(uint_t)512,		/* uint_t dlim_granular */
701*7c478bd9Sstevel@tonic-gate 	(int)1,			/* int dlim_sgllen */
702*7c478bd9Sstevel@tonic-gate 	(uint_t)0xffffffff	/* uint_t dlim_reqsizes */
703*7c478bd9Sstevel@tonic-gate };
704*7c478bd9Sstevel@tonic-gate 
705*7c478bd9Sstevel@tonic-gate #endif
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate int
708*7c478bd9Sstevel@tonic-gate ddi_dma_setup(dev_info_t *dip, struct ddi_dma_req *dmareqp,
709*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t *handlep)
710*7c478bd9Sstevel@tonic-gate {
711*7c478bd9Sstevel@tonic-gate 	int (*funcp)() = ddi_dma_map;
712*7c478bd9Sstevel@tonic-gate 	struct bus_ops *bop;
713*7c478bd9Sstevel@tonic-gate #if defined(__sparc)
714*7c478bd9Sstevel@tonic-gate 	auto ddi_dma_lim_t dma_lim;
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	if (dmareqp->dmar_limits == (ddi_dma_lim_t *)0) {
717*7c478bd9Sstevel@tonic-gate 		dma_lim = standard_limits;
718*7c478bd9Sstevel@tonic-gate 	} else {
719*7c478bd9Sstevel@tonic-gate 		dma_lim = *dmareqp->dmar_limits;
720*7c478bd9Sstevel@tonic-gate 	}
721*7c478bd9Sstevel@tonic-gate 	dmareqp->dmar_limits = &dma_lim;
722*7c478bd9Sstevel@tonic-gate #endif
723*7c478bd9Sstevel@tonic-gate #if defined(__x86)
724*7c478bd9Sstevel@tonic-gate 	if (dmareqp->dmar_limits == (ddi_dma_lim_t *)0)
725*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
726*7c478bd9Sstevel@tonic-gate #endif
727*7c478bd9Sstevel@tonic-gate 
728*7c478bd9Sstevel@tonic-gate 	/*
729*7c478bd9Sstevel@tonic-gate 	 * Handle the case that the requester is both a leaf
730*7c478bd9Sstevel@tonic-gate 	 * and a nexus driver simultaneously by calling the
731*7c478bd9Sstevel@tonic-gate 	 * requester's bus_dma_map function directly instead
732*7c478bd9Sstevel@tonic-gate 	 * of ddi_dma_map.
733*7c478bd9Sstevel@tonic-gate 	 */
734*7c478bd9Sstevel@tonic-gate 	bop = DEVI(dip)->devi_ops->devo_bus_ops;
735*7c478bd9Sstevel@tonic-gate 	if (bop && bop->bus_dma_map)
736*7c478bd9Sstevel@tonic-gate 		funcp = bop->bus_dma_map;
737*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(dip, dip, dmareqp, handlep));
738*7c478bd9Sstevel@tonic-gate }
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate int
741*7c478bd9Sstevel@tonic-gate ddi_dma_addr_setup(dev_info_t *dip, struct as *as, caddr_t addr, size_t len,
742*7c478bd9Sstevel@tonic-gate     uint_t flags, int (*waitfp)(), caddr_t arg,
743*7c478bd9Sstevel@tonic-gate     ddi_dma_lim_t *limits, ddi_dma_handle_t *handlep)
744*7c478bd9Sstevel@tonic-gate {
745*7c478bd9Sstevel@tonic-gate 	int (*funcp)() = ddi_dma_map;
746*7c478bd9Sstevel@tonic-gate 	ddi_dma_lim_t dma_lim;
747*7c478bd9Sstevel@tonic-gate 	struct ddi_dma_req dmareq;
748*7c478bd9Sstevel@tonic-gate 	struct bus_ops *bop;
749*7c478bd9Sstevel@tonic-gate 
750*7c478bd9Sstevel@tonic-gate 	if (len == 0) {
751*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_NOMAPPING);
752*7c478bd9Sstevel@tonic-gate 	}
753*7c478bd9Sstevel@tonic-gate 	if (limits == (ddi_dma_lim_t *)0) {
754*7c478bd9Sstevel@tonic-gate 		dma_lim = standard_limits;
755*7c478bd9Sstevel@tonic-gate 	} else {
756*7c478bd9Sstevel@tonic-gate 		dma_lim = *limits;
757*7c478bd9Sstevel@tonic-gate 	}
758*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_limits = &dma_lim;
759*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_flags = flags;
760*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_fp = waitfp;
761*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_arg = arg;
762*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_object.dmao_size = len;
763*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR;
764*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_object.dmao_obj.virt_obj.v_as = as;
765*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_object.dmao_obj.virt_obj.v_addr = addr;
766*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
767*7c478bd9Sstevel@tonic-gate 
768*7c478bd9Sstevel@tonic-gate 	/*
769*7c478bd9Sstevel@tonic-gate 	 * Handle the case that the requester is both a leaf
770*7c478bd9Sstevel@tonic-gate 	 * and a nexus driver simultaneously by calling the
771*7c478bd9Sstevel@tonic-gate 	 * requester's bus_dma_map function directly instead
772*7c478bd9Sstevel@tonic-gate 	 * of ddi_dma_map.
773*7c478bd9Sstevel@tonic-gate 	 */
774*7c478bd9Sstevel@tonic-gate 	bop = DEVI(dip)->devi_ops->devo_bus_ops;
775*7c478bd9Sstevel@tonic-gate 	if (bop && bop->bus_dma_map)
776*7c478bd9Sstevel@tonic-gate 		funcp = bop->bus_dma_map;
777*7c478bd9Sstevel@tonic-gate 
778*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(dip, dip, &dmareq, handlep));
779*7c478bd9Sstevel@tonic-gate }
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate int
782*7c478bd9Sstevel@tonic-gate ddi_dma_buf_setup(dev_info_t *dip, struct buf *bp, uint_t flags,
783*7c478bd9Sstevel@tonic-gate     int (*waitfp)(), caddr_t arg, ddi_dma_lim_t *limits,
784*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t *handlep)
785*7c478bd9Sstevel@tonic-gate {
786*7c478bd9Sstevel@tonic-gate 	int (*funcp)() = ddi_dma_map;
787*7c478bd9Sstevel@tonic-gate 	ddi_dma_lim_t dma_lim;
788*7c478bd9Sstevel@tonic-gate 	struct ddi_dma_req dmareq;
789*7c478bd9Sstevel@tonic-gate 	struct bus_ops *bop;
790*7c478bd9Sstevel@tonic-gate 
791*7c478bd9Sstevel@tonic-gate 	if (limits == (ddi_dma_lim_t *)0) {
792*7c478bd9Sstevel@tonic-gate 		dma_lim = standard_limits;
793*7c478bd9Sstevel@tonic-gate 	} else {
794*7c478bd9Sstevel@tonic-gate 		dma_lim = *limits;
795*7c478bd9Sstevel@tonic-gate 	}
796*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_limits = &dma_lim;
797*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_flags = flags;
798*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_fp = waitfp;
799*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_arg = arg;
800*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_object.dmao_size = (uint_t)bp->b_bcount;
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	if ((bp->b_flags & (B_PAGEIO|B_REMAPPED)) == B_PAGEIO) {
803*7c478bd9Sstevel@tonic-gate 		dmareq.dmar_object.dmao_type = DMA_OTYP_PAGES;
804*7c478bd9Sstevel@tonic-gate 		dmareq.dmar_object.dmao_obj.pp_obj.pp_pp = bp->b_pages;
805*7c478bd9Sstevel@tonic-gate 		dmareq.dmar_object.dmao_obj.pp_obj.pp_offset =
806*7c478bd9Sstevel@tonic-gate 		    (uint_t)(((uintptr_t)bp->b_un.b_addr) & MMU_PAGEOFFSET);
807*7c478bd9Sstevel@tonic-gate 	} else {
808*7c478bd9Sstevel@tonic-gate 		dmareq.dmar_object.dmao_type = DMA_OTYP_BUFVADDR;
809*7c478bd9Sstevel@tonic-gate 		dmareq.dmar_object.dmao_obj.virt_obj.v_addr = bp->b_un.b_addr;
810*7c478bd9Sstevel@tonic-gate 		if ((bp->b_flags & (B_SHADOW|B_REMAPPED)) == B_SHADOW) {
811*7c478bd9Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_priv =
812*7c478bd9Sstevel@tonic-gate 							bp->b_shadow;
813*7c478bd9Sstevel@tonic-gate 		} else {
814*7c478bd9Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
815*7c478bd9Sstevel@tonic-gate 		}
816*7c478bd9Sstevel@tonic-gate 
817*7c478bd9Sstevel@tonic-gate 		/*
818*7c478bd9Sstevel@tonic-gate 		 * If the buffer has no proc pointer, or the proc
819*7c478bd9Sstevel@tonic-gate 		 * struct has the kernel address space, or the buffer has
820*7c478bd9Sstevel@tonic-gate 		 * been marked B_REMAPPED (meaning that it is now
821*7c478bd9Sstevel@tonic-gate 		 * mapped into the kernel's address space), then
822*7c478bd9Sstevel@tonic-gate 		 * the address space is kas (kernel address space).
823*7c478bd9Sstevel@tonic-gate 		 */
824*7c478bd9Sstevel@tonic-gate 		if (bp->b_proc == NULL || bp->b_proc->p_as == &kas ||
825*7c478bd9Sstevel@tonic-gate 		    (bp->b_flags & B_REMAPPED) != 0) {
826*7c478bd9Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_as = 0;
827*7c478bd9Sstevel@tonic-gate 		} else {
828*7c478bd9Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_as =
829*7c478bd9Sstevel@tonic-gate 			    bp->b_proc->p_as;
830*7c478bd9Sstevel@tonic-gate 		}
831*7c478bd9Sstevel@tonic-gate 	}
832*7c478bd9Sstevel@tonic-gate 
833*7c478bd9Sstevel@tonic-gate 	/*
834*7c478bd9Sstevel@tonic-gate 	 * Handle the case that the requester is both a leaf
835*7c478bd9Sstevel@tonic-gate 	 * and a nexus driver simultaneously by calling the
836*7c478bd9Sstevel@tonic-gate 	 * requester's bus_dma_map function directly instead
837*7c478bd9Sstevel@tonic-gate 	 * of ddi_dma_map.
838*7c478bd9Sstevel@tonic-gate 	 */
839*7c478bd9Sstevel@tonic-gate 	bop = DEVI(dip)->devi_ops->devo_bus_ops;
840*7c478bd9Sstevel@tonic-gate 	if (bop && bop->bus_dma_map)
841*7c478bd9Sstevel@tonic-gate 		funcp = bop->bus_dma_map;
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(dip, dip, &dmareq, handlep));
844*7c478bd9Sstevel@tonic-gate }
845*7c478bd9Sstevel@tonic-gate 
846*7c478bd9Sstevel@tonic-gate #if !defined(__sparc)
847*7c478bd9Sstevel@tonic-gate /*
848*7c478bd9Sstevel@tonic-gate  * Request bus_dma_ctl parent to fiddle with a dma request.
849*7c478bd9Sstevel@tonic-gate  *
850*7c478bd9Sstevel@tonic-gate  * (The sparc version is in sparc_subr.s)
851*7c478bd9Sstevel@tonic-gate  */
852*7c478bd9Sstevel@tonic-gate int
853*7c478bd9Sstevel@tonic-gate ddi_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
854*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
855*7c478bd9Sstevel@tonic-gate     off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags)
856*7c478bd9Sstevel@tonic-gate {
857*7c478bd9Sstevel@tonic-gate 	int (*fp)();
858*7c478bd9Sstevel@tonic-gate 
859*7c478bd9Sstevel@tonic-gate 	dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_ctl;
860*7c478bd9Sstevel@tonic-gate 	fp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_ctl;
861*7c478bd9Sstevel@tonic-gate 	return ((*fp) (dip, rdip, handle, request, offp, lenp, objp, flags));
862*7c478bd9Sstevel@tonic-gate }
863*7c478bd9Sstevel@tonic-gate #endif
864*7c478bd9Sstevel@tonic-gate 
865*7c478bd9Sstevel@tonic-gate /*
866*7c478bd9Sstevel@tonic-gate  * For all DMA control functions, call the DMA control
867*7c478bd9Sstevel@tonic-gate  * routine and return status.
868*7c478bd9Sstevel@tonic-gate  *
869*7c478bd9Sstevel@tonic-gate  * Just plain assume that the parent is to be called.
870*7c478bd9Sstevel@tonic-gate  * If a nexus driver or a thread outside the framework
871*7c478bd9Sstevel@tonic-gate  * of a nexus driver or a leaf driver calls these functions,
872*7c478bd9Sstevel@tonic-gate  * it is up to them to deal with the fact that the parent's
873*7c478bd9Sstevel@tonic-gate  * bus_dma_ctl function will be the first one called.
874*7c478bd9Sstevel@tonic-gate  */
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate #define	HD	((ddi_dma_impl_t *)h)->dmai_rdip
877*7c478bd9Sstevel@tonic-gate 
878*7c478bd9Sstevel@tonic-gate int
879*7c478bd9Sstevel@tonic-gate ddi_dma_kvaddrp(ddi_dma_handle_t h, off_t off, size_t len, caddr_t *kp)
880*7c478bd9Sstevel@tonic-gate {
881*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_KVADDR, &off, &len, kp, 0));
882*7c478bd9Sstevel@tonic-gate }
883*7c478bd9Sstevel@tonic-gate 
884*7c478bd9Sstevel@tonic-gate int
885*7c478bd9Sstevel@tonic-gate ddi_dma_htoc(ddi_dma_handle_t h, off_t o, ddi_dma_cookie_t *c)
886*7c478bd9Sstevel@tonic-gate {
887*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_HTOC, &o, 0, (caddr_t *)c, 0));
888*7c478bd9Sstevel@tonic-gate }
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate int
891*7c478bd9Sstevel@tonic-gate ddi_dma_coff(ddi_dma_handle_t h, ddi_dma_cookie_t *c, off_t *o)
892*7c478bd9Sstevel@tonic-gate {
893*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_COFF,
894*7c478bd9Sstevel@tonic-gate 	    (off_t *)c, 0, (caddr_t *)o, 0));
895*7c478bd9Sstevel@tonic-gate }
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate int
898*7c478bd9Sstevel@tonic-gate ddi_dma_movwin(ddi_dma_handle_t h, off_t *o, size_t *l, ddi_dma_cookie_t *c)
899*7c478bd9Sstevel@tonic-gate {
900*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_MOVWIN, o,
901*7c478bd9Sstevel@tonic-gate 	    l, (caddr_t *)c, 0));
902*7c478bd9Sstevel@tonic-gate }
903*7c478bd9Sstevel@tonic-gate 
904*7c478bd9Sstevel@tonic-gate int
905*7c478bd9Sstevel@tonic-gate ddi_dma_curwin(ddi_dma_handle_t h, off_t *o, size_t *l)
906*7c478bd9Sstevel@tonic-gate {
907*7c478bd9Sstevel@tonic-gate 	if ((((ddi_dma_impl_t *)h)->dmai_rflags & DDI_DMA_PARTIAL) == 0)
908*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
909*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_REPWIN, o, l, 0, 0));
910*7c478bd9Sstevel@tonic-gate }
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate /*
913*7c478bd9Sstevel@tonic-gate  * Note:  The astute might notice that in the next two routines
914*7c478bd9Sstevel@tonic-gate  * the SPARC case passes a pointer to a ddi_dma_win_t as the 5th
915*7c478bd9Sstevel@tonic-gate  * argument while the x86 case passes the ddi_dma_win_t directly.
916*7c478bd9Sstevel@tonic-gate  *
917*7c478bd9Sstevel@tonic-gate  * While it would be nice if the "correct" behavior was
918*7c478bd9Sstevel@tonic-gate  * platform independent and specified someplace, it isn't.
919*7c478bd9Sstevel@tonic-gate  * Until that point, what's required is that this call and
920*7c478bd9Sstevel@tonic-gate  * the relevant bus nexus drivers agree, and in this case they
921*7c478bd9Sstevel@tonic-gate  * do, at least for the cases I've looked at.
922*7c478bd9Sstevel@tonic-gate  */
923*7c478bd9Sstevel@tonic-gate int
924*7c478bd9Sstevel@tonic-gate ddi_dma_nextwin(ddi_dma_handle_t h, ddi_dma_win_t win,
925*7c478bd9Sstevel@tonic-gate     ddi_dma_win_t *nwin)
926*7c478bd9Sstevel@tonic-gate {
927*7c478bd9Sstevel@tonic-gate #if defined(__sparc)
928*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_NEXTWIN, (off_t *)&win, 0,
929*7c478bd9Sstevel@tonic-gate 	    (caddr_t *)nwin, 0));
930*7c478bd9Sstevel@tonic-gate #elif defined(__x86)
931*7c478bd9Sstevel@tonic-gate 	return (((ddi_dma_impl_t *)h)->dmai_mctl(HD, HD, h, DDI_DMA_NEXTWIN,
932*7c478bd9Sstevel@tonic-gate 		(off_t *)win, 0, (caddr_t *)nwin, 0));
933*7c478bd9Sstevel@tonic-gate #else
934*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_NEXTWIN,
935*7c478bd9Sstevel@tonic-gate 		(off_t *)win, 0, (caddr_t *)nwin, 0));
936*7c478bd9Sstevel@tonic-gate #endif
937*7c478bd9Sstevel@tonic-gate }
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate int
940*7c478bd9Sstevel@tonic-gate ddi_dma_nextseg(ddi_dma_win_t win, ddi_dma_seg_t seg, ddi_dma_seg_t *nseg)
941*7c478bd9Sstevel@tonic-gate {
942*7c478bd9Sstevel@tonic-gate #if defined(__sparc)
943*7c478bd9Sstevel@tonic-gate 	ddi_dma_handle_t h = (ddi_dma_handle_t)win;
944*7c478bd9Sstevel@tonic-gate 
945*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_NEXTSEG, (off_t *)&win,
946*7c478bd9Sstevel@tonic-gate 	    (size_t *)&seg, (caddr_t *)nseg, 0));
947*7c478bd9Sstevel@tonic-gate #else
948*7c478bd9Sstevel@tonic-gate 	ddi_dma_handle_t h = (ddi_dma_handle_t)
949*7c478bd9Sstevel@tonic-gate 	    ((impl_dma_segment_t *)win)->dmais_hndl;
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate #if defined(__x86)
952*7c478bd9Sstevel@tonic-gate 	return (((ddi_dma_impl_t *)h)->dmai_mctl(HD, HD, h, DDI_DMA_NEXTSEG,
953*7c478bd9Sstevel@tonic-gate 		(off_t *)win, (size_t *)seg, (caddr_t *)nseg, 0));
954*7c478bd9Sstevel@tonic-gate #else
955*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_NEXTSEG,
956*7c478bd9Sstevel@tonic-gate 		(off_t *)win, (size_t *)seg, (caddr_t *)nseg, 0));
957*7c478bd9Sstevel@tonic-gate #endif
958*7c478bd9Sstevel@tonic-gate #endif
959*7c478bd9Sstevel@tonic-gate }
960*7c478bd9Sstevel@tonic-gate 
961*7c478bd9Sstevel@tonic-gate #if (defined(__i386) && !defined(__amd64)) || defined(__sparc)
962*7c478bd9Sstevel@tonic-gate /*
963*7c478bd9Sstevel@tonic-gate  * This routine is Obsolete and should be removed from ALL architectures
964*7c478bd9Sstevel@tonic-gate  * in a future release of Solaris.
965*7c478bd9Sstevel@tonic-gate  *
966*7c478bd9Sstevel@tonic-gate  * It is deliberately NOT ported to amd64; please fix the code that
967*7c478bd9Sstevel@tonic-gate  * depends on this routine to use ddi_dma_nextcookie(9F).
968*7c478bd9Sstevel@tonic-gate  */
969*7c478bd9Sstevel@tonic-gate int
970*7c478bd9Sstevel@tonic-gate ddi_dma_segtocookie(ddi_dma_seg_t seg, off_t *o, off_t *l,
971*7c478bd9Sstevel@tonic-gate     ddi_dma_cookie_t *cookiep)
972*7c478bd9Sstevel@tonic-gate {
973*7c478bd9Sstevel@tonic-gate #if defined(__sparc)
974*7c478bd9Sstevel@tonic-gate 	ddi_dma_handle_t h = (ddi_dma_handle_t)seg;
975*7c478bd9Sstevel@tonic-gate 
976*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_SEGTOC, o, (size_t *)l,
977*7c478bd9Sstevel@tonic-gate 	    (caddr_t *)cookiep, 0));
978*7c478bd9Sstevel@tonic-gate #elif defined(__i386) && !defined(__amd64)
979*7c478bd9Sstevel@tonic-gate 	ddi_dma_handle_t h = (ddi_dma_handle_t)
980*7c478bd9Sstevel@tonic-gate 	    ((impl_dma_segment_t *)seg)->dmais_hndl;
981*7c478bd9Sstevel@tonic-gate 
982*7c478bd9Sstevel@tonic-gate 	/*
983*7c478bd9Sstevel@tonic-gate 	 * The hack used for i386 won't work here; we can't squeeze a
984*7c478bd9Sstevel@tonic-gate 	 * pointer through the 'cache_flags' field.
985*7c478bd9Sstevel@tonic-gate 	 */
986*7c478bd9Sstevel@tonic-gate 	return (((ddi_dma_impl_t *)h)->dmai_mctl(HD, HD, h, DDI_DMA_SEGTOC,
987*7c478bd9Sstevel@tonic-gate 		o, (size_t *)l, (caddr_t *)cookiep, (uint_t)seg));
988*7c478bd9Sstevel@tonic-gate #endif
989*7c478bd9Sstevel@tonic-gate }
990*7c478bd9Sstevel@tonic-gate #endif	/* (__i386 && !__amd64) || __sparc */
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate #if !defined(__sparc)
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate /*
995*7c478bd9Sstevel@tonic-gate  * The SPARC versions of these routines are done in assembler to
996*7c478bd9Sstevel@tonic-gate  * save register windows, so they're in sparc_subr.s.
997*7c478bd9Sstevel@tonic-gate  */
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate int
1000*7c478bd9Sstevel@tonic-gate ddi_dma_map(dev_info_t *dip, dev_info_t *rdip,
1001*7c478bd9Sstevel@tonic-gate 	struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
1002*7c478bd9Sstevel@tonic-gate {
1003*7c478bd9Sstevel@tonic-gate 	dev_info_t	*hdip;
1004*7c478bd9Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, struct ddi_dma_req *,
1005*7c478bd9Sstevel@tonic-gate 	    ddi_dma_handle_t *);
1006*7c478bd9Sstevel@tonic-gate 
1007*7c478bd9Sstevel@tonic-gate 	hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_map;
1008*7c478bd9Sstevel@tonic-gate 
1009*7c478bd9Sstevel@tonic-gate 	funcp = DEVI(hdip)->devi_ops->devo_bus_ops->bus_dma_map;
1010*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(hdip, rdip, dmareqp, handlep));
1011*7c478bd9Sstevel@tonic-gate }
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate int
1014*7c478bd9Sstevel@tonic-gate ddi_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
1015*7c478bd9Sstevel@tonic-gate     int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
1016*7c478bd9Sstevel@tonic-gate {
1017*7c478bd9Sstevel@tonic-gate 	dev_info_t	*hdip;
1018*7c478bd9Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_attr_t *,
1019*7c478bd9Sstevel@tonic-gate 	    int (*)(caddr_t), caddr_t, ddi_dma_handle_t *);
1020*7c478bd9Sstevel@tonic-gate 
1021*7c478bd9Sstevel@tonic-gate 	hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_allochdl;
1022*7c478bd9Sstevel@tonic-gate 
1023*7c478bd9Sstevel@tonic-gate 	funcp = DEVI(hdip)->devi_ops->devo_bus_ops->bus_dma_allochdl;
1024*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(hdip, rdip, attr, waitfp, arg, handlep));
1025*7c478bd9Sstevel@tonic-gate }
1026*7c478bd9Sstevel@tonic-gate 
1027*7c478bd9Sstevel@tonic-gate int
1028*7c478bd9Sstevel@tonic-gate ddi_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handlep)
1029*7c478bd9Sstevel@tonic-gate {
1030*7c478bd9Sstevel@tonic-gate 	dev_info_t	*hdip;
1031*7c478bd9Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
1032*7c478bd9Sstevel@tonic-gate 
1033*7c478bd9Sstevel@tonic-gate 	hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_allochdl;
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	funcp = DEVI(hdip)->devi_ops->devo_bus_ops->bus_dma_freehdl;
1036*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(hdip, rdip, handlep));
1037*7c478bd9Sstevel@tonic-gate }
1038*7c478bd9Sstevel@tonic-gate 
1039*7c478bd9Sstevel@tonic-gate int
1040*7c478bd9Sstevel@tonic-gate ddi_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
1041*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
1042*7c478bd9Sstevel@tonic-gate     ddi_dma_cookie_t *cp, uint_t *ccountp)
1043*7c478bd9Sstevel@tonic-gate {
1044*7c478bd9Sstevel@tonic-gate 	dev_info_t	*hdip;
1045*7c478bd9Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
1046*7c478bd9Sstevel@tonic-gate 	    struct ddi_dma_req *, ddi_dma_cookie_t *, uint_t *);
1047*7c478bd9Sstevel@tonic-gate 
1048*7c478bd9Sstevel@tonic-gate 	hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 	funcp = DEVI(hdip)->devi_ops->devo_bus_ops->bus_dma_bindhdl;
1051*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(hdip, rdip, handle, dmareq, cp, ccountp));
1052*7c478bd9Sstevel@tonic-gate }
1053*7c478bd9Sstevel@tonic-gate 
1054*7c478bd9Sstevel@tonic-gate int
1055*7c478bd9Sstevel@tonic-gate ddi_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
1056*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle)
1057*7c478bd9Sstevel@tonic-gate {
1058*7c478bd9Sstevel@tonic-gate 	dev_info_t	*hdip;
1059*7c478bd9Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
1060*7c478bd9Sstevel@tonic-gate 
1061*7c478bd9Sstevel@tonic-gate 	hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
1062*7c478bd9Sstevel@tonic-gate 
1063*7c478bd9Sstevel@tonic-gate 	funcp = DEVI(hdip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl;
1064*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(hdip, rdip, handle));
1065*7c478bd9Sstevel@tonic-gate }
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate 
1068*7c478bd9Sstevel@tonic-gate int
1069*7c478bd9Sstevel@tonic-gate ddi_dma_flush(dev_info_t *dip, dev_info_t *rdip,
1070*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle, off_t off, size_t len,
1071*7c478bd9Sstevel@tonic-gate     uint_t cache_flags)
1072*7c478bd9Sstevel@tonic-gate {
1073*7c478bd9Sstevel@tonic-gate 	dev_info_t	*hdip;
1074*7c478bd9Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
1075*7c478bd9Sstevel@tonic-gate 	    off_t, size_t, uint_t);
1076*7c478bd9Sstevel@tonic-gate 
1077*7c478bd9Sstevel@tonic-gate 	hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_flush;
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 	funcp = DEVI(hdip)->devi_ops->devo_bus_ops->bus_dma_flush;
1080*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(hdip, rdip, handle, off, len, cache_flags));
1081*7c478bd9Sstevel@tonic-gate }
1082*7c478bd9Sstevel@tonic-gate 
1083*7c478bd9Sstevel@tonic-gate int
1084*7c478bd9Sstevel@tonic-gate ddi_dma_win(dev_info_t *dip, dev_info_t *rdip,
1085*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle, uint_t win, off_t *offp,
1086*7c478bd9Sstevel@tonic-gate     size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
1087*7c478bd9Sstevel@tonic-gate {
1088*7c478bd9Sstevel@tonic-gate 	dev_info_t	*hdip;
1089*7c478bd9Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
1090*7c478bd9Sstevel@tonic-gate 	    uint_t, off_t *, size_t *, ddi_dma_cookie_t *, uint_t *);
1091*7c478bd9Sstevel@tonic-gate 
1092*7c478bd9Sstevel@tonic-gate 	hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_win;
1093*7c478bd9Sstevel@tonic-gate 
1094*7c478bd9Sstevel@tonic-gate 	funcp = DEVI(hdip)->devi_ops->devo_bus_ops->bus_dma_win;
1095*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(hdip, rdip, handle, win, offp, lenp,
1096*7c478bd9Sstevel@tonic-gate 	    cookiep, ccountp));
1097*7c478bd9Sstevel@tonic-gate }
1098*7c478bd9Sstevel@tonic-gate 
1099*7c478bd9Sstevel@tonic-gate int
1100*7c478bd9Sstevel@tonic-gate ddi_dma_sync(ddi_dma_handle_t h, off_t o, size_t l, uint_t whom)
1101*7c478bd9Sstevel@tonic-gate {
1102*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)h;
1103*7c478bd9Sstevel@tonic-gate 	dev_info_t *hdip, *dip;
1104*7c478bd9Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t, off_t,
1105*7c478bd9Sstevel@tonic-gate 		size_t, uint_t);
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate 	/*
1108*7c478bd9Sstevel@tonic-gate 	 * the DMA nexus driver will set DMP_NOSYNC if the
1109*7c478bd9Sstevel@tonic-gate 	 * platform does not require any sync operation. For
1110*7c478bd9Sstevel@tonic-gate 	 * example if the memory is uncached or consistent
1111*7c478bd9Sstevel@tonic-gate 	 * and without any I/O write buffers involved.
1112*7c478bd9Sstevel@tonic-gate 	 */
1113*7c478bd9Sstevel@tonic-gate 	if ((hp->dmai_rflags & DMP_NOSYNC) == DMP_NOSYNC)
1114*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
1115*7c478bd9Sstevel@tonic-gate 
1116*7c478bd9Sstevel@tonic-gate 	dip = hp->dmai_rdip;
1117*7c478bd9Sstevel@tonic-gate 	hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_flush;
1118*7c478bd9Sstevel@tonic-gate 	funcp = DEVI(hdip)->devi_ops->devo_bus_ops->bus_dma_flush;
1119*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(hdip, dip, h, o, l, whom));
1120*7c478bd9Sstevel@tonic-gate }
1121*7c478bd9Sstevel@tonic-gate 
1122*7c478bd9Sstevel@tonic-gate int
1123*7c478bd9Sstevel@tonic-gate ddi_dma_unbind_handle(ddi_dma_handle_t h)
1124*7c478bd9Sstevel@tonic-gate {
1125*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)h;
1126*7c478bd9Sstevel@tonic-gate 	dev_info_t *hdip, *dip;
1127*7c478bd9Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
1128*7c478bd9Sstevel@tonic-gate 
1129*7c478bd9Sstevel@tonic-gate 	dip = hp->dmai_rdip;
1130*7c478bd9Sstevel@tonic-gate 	hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
1131*7c478bd9Sstevel@tonic-gate 	funcp = DEVI(dip)->devi_bus_dma_unbindfunc;
1132*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(hdip, dip, h));
1133*7c478bd9Sstevel@tonic-gate }
1134*7c478bd9Sstevel@tonic-gate 
1135*7c478bd9Sstevel@tonic-gate #endif	/* !__sparc */
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate int
1138*7c478bd9Sstevel@tonic-gate ddi_dma_free(ddi_dma_handle_t h)
1139*7c478bd9Sstevel@tonic-gate {
1140*7c478bd9Sstevel@tonic-gate #if !defined(__x86)
1141*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_FREE, 0, 0, 0, 0));
1142*7c478bd9Sstevel@tonic-gate #else
1143*7c478bd9Sstevel@tonic-gate 	return (((ddi_dma_impl_t *)h)->dmai_mctl(HD, HD, h, DDI_DMA_FREE,
1144*7c478bd9Sstevel@tonic-gate 		0, 0, 0, 0));
1145*7c478bd9Sstevel@tonic-gate #endif
1146*7c478bd9Sstevel@tonic-gate }
1147*7c478bd9Sstevel@tonic-gate 
1148*7c478bd9Sstevel@tonic-gate int
1149*7c478bd9Sstevel@tonic-gate ddi_iopb_alloc(dev_info_t *dip, ddi_dma_lim_t *limp, uint_t len, caddr_t *iopbp)
1150*7c478bd9Sstevel@tonic-gate {
1151*7c478bd9Sstevel@tonic-gate 	ddi_dma_lim_t defalt;
1152*7c478bd9Sstevel@tonic-gate 	size_t size = len;
1153*7c478bd9Sstevel@tonic-gate 
1154*7c478bd9Sstevel@tonic-gate 	if (!limp) {
1155*7c478bd9Sstevel@tonic-gate 		defalt = standard_limits;
1156*7c478bd9Sstevel@tonic-gate 		limp = &defalt;
1157*7c478bd9Sstevel@tonic-gate 	}
1158*7c478bd9Sstevel@tonic-gate #if defined(__sparc)
1159*7c478bd9Sstevel@tonic-gate 	return (i_ddi_mem_alloc_lim(dip, limp, size, 0, 0, 0,
1160*7c478bd9Sstevel@tonic-gate 	    iopbp, NULL, NULL));
1161*7c478bd9Sstevel@tonic-gate #else
1162*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(dip, dip, 0, DDI_DMA_IOPB_ALLOC, (off_t *)limp,
1163*7c478bd9Sstevel@tonic-gate 	    &size, iopbp, 0));
1164*7c478bd9Sstevel@tonic-gate #endif
1165*7c478bd9Sstevel@tonic-gate }
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate void
1168*7c478bd9Sstevel@tonic-gate ddi_iopb_free(caddr_t iopb)
1169*7c478bd9Sstevel@tonic-gate {
1170*7c478bd9Sstevel@tonic-gate 	i_ddi_mem_free(iopb, 0);
1171*7c478bd9Sstevel@tonic-gate }
1172*7c478bd9Sstevel@tonic-gate 
1173*7c478bd9Sstevel@tonic-gate int
1174*7c478bd9Sstevel@tonic-gate ddi_mem_alloc(dev_info_t *dip, ddi_dma_lim_t *limits, uint_t length,
1175*7c478bd9Sstevel@tonic-gate 	uint_t flags, caddr_t *kaddrp, uint_t *real_length)
1176*7c478bd9Sstevel@tonic-gate {
1177*7c478bd9Sstevel@tonic-gate 	ddi_dma_lim_t defalt;
1178*7c478bd9Sstevel@tonic-gate 	size_t size = length;
1179*7c478bd9Sstevel@tonic-gate 
1180*7c478bd9Sstevel@tonic-gate 	if (!limits) {
1181*7c478bd9Sstevel@tonic-gate 		defalt = standard_limits;
1182*7c478bd9Sstevel@tonic-gate 		limits = &defalt;
1183*7c478bd9Sstevel@tonic-gate 	}
1184*7c478bd9Sstevel@tonic-gate #if defined(__sparc)
1185*7c478bd9Sstevel@tonic-gate 	return (i_ddi_mem_alloc_lim(dip, limits, size, flags & 0x1,
1186*7c478bd9Sstevel@tonic-gate 	    1, 0, kaddrp, real_length, NULL));
1187*7c478bd9Sstevel@tonic-gate #else
1188*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(dip, dip, (ddi_dma_handle_t)real_length,
1189*7c478bd9Sstevel@tonic-gate 	    DDI_DMA_SMEM_ALLOC, (off_t *)limits, &size,
1190*7c478bd9Sstevel@tonic-gate 	    kaddrp, (flags & 0x1)));
1191*7c478bd9Sstevel@tonic-gate #endif
1192*7c478bd9Sstevel@tonic-gate }
1193*7c478bd9Sstevel@tonic-gate 
1194*7c478bd9Sstevel@tonic-gate void
1195*7c478bd9Sstevel@tonic-gate ddi_mem_free(caddr_t kaddr)
1196*7c478bd9Sstevel@tonic-gate {
1197*7c478bd9Sstevel@tonic-gate 	i_ddi_mem_free(kaddr, 1);
1198*7c478bd9Sstevel@tonic-gate }
1199*7c478bd9Sstevel@tonic-gate 
1200*7c478bd9Sstevel@tonic-gate /*
1201*7c478bd9Sstevel@tonic-gate  * DMA attributes, alignment, burst sizes, and transfer minimums
1202*7c478bd9Sstevel@tonic-gate  */
1203*7c478bd9Sstevel@tonic-gate int
1204*7c478bd9Sstevel@tonic-gate ddi_dma_get_attr(ddi_dma_handle_t handle, ddi_dma_attr_t *attrp)
1205*7c478bd9Sstevel@tonic-gate {
1206*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *dimp = (ddi_dma_impl_t *)handle;
1207*7c478bd9Sstevel@tonic-gate 
1208*7c478bd9Sstevel@tonic-gate 	if (attrp == NULL)
1209*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1210*7c478bd9Sstevel@tonic-gate 	*attrp = dimp->dmai_attr;
1211*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1212*7c478bd9Sstevel@tonic-gate }
1213*7c478bd9Sstevel@tonic-gate 
1214*7c478bd9Sstevel@tonic-gate int
1215*7c478bd9Sstevel@tonic-gate ddi_dma_burstsizes(ddi_dma_handle_t handle)
1216*7c478bd9Sstevel@tonic-gate {
1217*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *dimp = (ddi_dma_impl_t *)handle;
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate 	if (!dimp)
1220*7c478bd9Sstevel@tonic-gate 		return (0);
1221*7c478bd9Sstevel@tonic-gate 	else
1222*7c478bd9Sstevel@tonic-gate 		return (dimp->dmai_burstsizes);
1223*7c478bd9Sstevel@tonic-gate }
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate int
1226*7c478bd9Sstevel@tonic-gate ddi_dma_devalign(ddi_dma_handle_t handle, uint_t *alignment, uint_t *mineffect)
1227*7c478bd9Sstevel@tonic-gate {
1228*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *dimp = (ddi_dma_impl_t *)handle;
1229*7c478bd9Sstevel@tonic-gate 
1230*7c478bd9Sstevel@tonic-gate 	if (!dimp || !alignment || !mineffect)
1231*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
1232*7c478bd9Sstevel@tonic-gate 	if (!(dimp->dmai_rflags & DDI_DMA_SBUS_64BIT)) {
1233*7c478bd9Sstevel@tonic-gate 		*alignment = 1 << ddi_ffs(dimp->dmai_burstsizes);
1234*7c478bd9Sstevel@tonic-gate 	} else {
1235*7c478bd9Sstevel@tonic-gate 		if (dimp->dmai_burstsizes & 0xff0000) {
1236*7c478bd9Sstevel@tonic-gate 			*alignment = 1 << ddi_ffs(dimp->dmai_burstsizes >> 16);
1237*7c478bd9Sstevel@tonic-gate 		} else {
1238*7c478bd9Sstevel@tonic-gate 			*alignment = 1 << ddi_ffs(dimp->dmai_burstsizes);
1239*7c478bd9Sstevel@tonic-gate 		}
1240*7c478bd9Sstevel@tonic-gate 	}
1241*7c478bd9Sstevel@tonic-gate 	*mineffect = dimp->dmai_minxfer;
1242*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
1243*7c478bd9Sstevel@tonic-gate }
1244*7c478bd9Sstevel@tonic-gate 
1245*7c478bd9Sstevel@tonic-gate int
1246*7c478bd9Sstevel@tonic-gate ddi_iomin(dev_info_t *a, int i, int stream)
1247*7c478bd9Sstevel@tonic-gate {
1248*7c478bd9Sstevel@tonic-gate 	int r;
1249*7c478bd9Sstevel@tonic-gate 
1250*7c478bd9Sstevel@tonic-gate 	/*
1251*7c478bd9Sstevel@tonic-gate 	 * Make sure that the initial value is sane
1252*7c478bd9Sstevel@tonic-gate 	 */
1253*7c478bd9Sstevel@tonic-gate 	if (i & (i - 1))
1254*7c478bd9Sstevel@tonic-gate 		return (0);
1255*7c478bd9Sstevel@tonic-gate 	if (i == 0)
1256*7c478bd9Sstevel@tonic-gate 		i = (stream) ? 4 : 1;
1257*7c478bd9Sstevel@tonic-gate 
1258*7c478bd9Sstevel@tonic-gate 	r = ddi_ctlops(a, a,
1259*7c478bd9Sstevel@tonic-gate 	    DDI_CTLOPS_IOMIN, (void *)(uintptr_t)stream, (void *)&i);
1260*7c478bd9Sstevel@tonic-gate 	if (r != DDI_SUCCESS || (i & (i - 1)))
1261*7c478bd9Sstevel@tonic-gate 		return (0);
1262*7c478bd9Sstevel@tonic-gate 	return (i);
1263*7c478bd9Sstevel@tonic-gate }
1264*7c478bd9Sstevel@tonic-gate 
1265*7c478bd9Sstevel@tonic-gate /*
1266*7c478bd9Sstevel@tonic-gate  * Given two DMA attribute structures, apply the attributes
1267*7c478bd9Sstevel@tonic-gate  * of one to the other, following the rules of attributes
1268*7c478bd9Sstevel@tonic-gate  * and the wishes of the caller.
1269*7c478bd9Sstevel@tonic-gate  *
1270*7c478bd9Sstevel@tonic-gate  * The rules of DMA attribute structures are that you cannot
1271*7c478bd9Sstevel@tonic-gate  * make things *less* restrictive as you apply one set
1272*7c478bd9Sstevel@tonic-gate  * of attributes to another.
1273*7c478bd9Sstevel@tonic-gate  *
1274*7c478bd9Sstevel@tonic-gate  */
1275*7c478bd9Sstevel@tonic-gate void
1276*7c478bd9Sstevel@tonic-gate ddi_dma_attr_merge(ddi_dma_attr_t *attr, ddi_dma_attr_t *mod)
1277*7c478bd9Sstevel@tonic-gate {
1278*7c478bd9Sstevel@tonic-gate 	attr->dma_attr_addr_lo =
1279*7c478bd9Sstevel@tonic-gate 	    MAX(attr->dma_attr_addr_lo, mod->dma_attr_addr_lo);
1280*7c478bd9Sstevel@tonic-gate 	attr->dma_attr_addr_hi =
1281*7c478bd9Sstevel@tonic-gate 	    MIN(attr->dma_attr_addr_hi, mod->dma_attr_addr_hi);
1282*7c478bd9Sstevel@tonic-gate 	attr->dma_attr_count_max =
1283*7c478bd9Sstevel@tonic-gate 	    MIN(attr->dma_attr_count_max, mod->dma_attr_count_max);
1284*7c478bd9Sstevel@tonic-gate 	attr->dma_attr_align =
1285*7c478bd9Sstevel@tonic-gate 	    MAX(attr->dma_attr_align,  mod->dma_attr_align);
1286*7c478bd9Sstevel@tonic-gate 	attr->dma_attr_burstsizes =
1287*7c478bd9Sstevel@tonic-gate 	    (uint_t)(attr->dma_attr_burstsizes & mod->dma_attr_burstsizes);
1288*7c478bd9Sstevel@tonic-gate 	attr->dma_attr_minxfer =
1289*7c478bd9Sstevel@tonic-gate 	    maxbit(attr->dma_attr_minxfer, mod->dma_attr_minxfer);
1290*7c478bd9Sstevel@tonic-gate 	attr->dma_attr_maxxfer =
1291*7c478bd9Sstevel@tonic-gate 	    MIN(attr->dma_attr_maxxfer, mod->dma_attr_maxxfer);
1292*7c478bd9Sstevel@tonic-gate 	attr->dma_attr_seg = MIN(attr->dma_attr_seg, mod->dma_attr_seg);
1293*7c478bd9Sstevel@tonic-gate 	attr->dma_attr_sgllen = MIN((uint_t)attr->dma_attr_sgllen,
1294*7c478bd9Sstevel@tonic-gate 	    (uint_t)mod->dma_attr_sgllen);
1295*7c478bd9Sstevel@tonic-gate 	attr->dma_attr_granular =
1296*7c478bd9Sstevel@tonic-gate 	    MAX(attr->dma_attr_granular, mod->dma_attr_granular);
1297*7c478bd9Sstevel@tonic-gate }
1298*7c478bd9Sstevel@tonic-gate 
1299*7c478bd9Sstevel@tonic-gate /*
1300*7c478bd9Sstevel@tonic-gate  * mmap/segmap interface:
1301*7c478bd9Sstevel@tonic-gate  */
1302*7c478bd9Sstevel@tonic-gate 
1303*7c478bd9Sstevel@tonic-gate /*
1304*7c478bd9Sstevel@tonic-gate  * ddi_segmap:		setup the default segment driver. Calls the drivers
1305*7c478bd9Sstevel@tonic-gate  *			XXmmap routine to validate the range to be mapped.
1306*7c478bd9Sstevel@tonic-gate  *			Return ENXIO of the range is not valid.  Create
1307*7c478bd9Sstevel@tonic-gate  *			a seg_dev segment that contains all of the
1308*7c478bd9Sstevel@tonic-gate  *			necessary information and will reference the
1309*7c478bd9Sstevel@tonic-gate  *			default segment driver routines. It returns zero
1310*7c478bd9Sstevel@tonic-gate  *			on success or non-zero on failure.
1311*7c478bd9Sstevel@tonic-gate  */
1312*7c478bd9Sstevel@tonic-gate int
1313*7c478bd9Sstevel@tonic-gate ddi_segmap(dev_t dev, off_t offset, struct as *asp, caddr_t *addrp, off_t len,
1314*7c478bd9Sstevel@tonic-gate     uint_t prot, uint_t maxprot, uint_t flags, cred_t *credp)
1315*7c478bd9Sstevel@tonic-gate {
1316*7c478bd9Sstevel@tonic-gate 	extern int spec_segmap(dev_t, off_t, struct as *, caddr_t *,
1317*7c478bd9Sstevel@tonic-gate 	    off_t, uint_t, uint_t, uint_t, struct cred *);
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate 	return (spec_segmap(dev, offset, asp, addrp, len,
1320*7c478bd9Sstevel@tonic-gate 	    prot, maxprot, flags, credp));
1321*7c478bd9Sstevel@tonic-gate }
1322*7c478bd9Sstevel@tonic-gate 
1323*7c478bd9Sstevel@tonic-gate /*
1324*7c478bd9Sstevel@tonic-gate  * ddi_map_fault:	Resolve mappings at fault time.  Used by segment
1325*7c478bd9Sstevel@tonic-gate  *			drivers. Allows each successive parent to resolve
1326*7c478bd9Sstevel@tonic-gate  *			address translations and add its mappings to the
1327*7c478bd9Sstevel@tonic-gate  *			mapping list supplied in the page structure. It
1328*7c478bd9Sstevel@tonic-gate  *			returns zero on success	or non-zero on failure.
1329*7c478bd9Sstevel@tonic-gate  */
1330*7c478bd9Sstevel@tonic-gate 
1331*7c478bd9Sstevel@tonic-gate int
1332*7c478bd9Sstevel@tonic-gate ddi_map_fault(dev_info_t *dip, struct hat *hat, struct seg *seg,
1333*7c478bd9Sstevel@tonic-gate     caddr_t addr, struct devpage *dp, pfn_t pfn, uint_t prot, uint_t lock)
1334*7c478bd9Sstevel@tonic-gate {
1335*7c478bd9Sstevel@tonic-gate 	return (i_ddi_map_fault(dip, dip, hat, seg, addr, dp, pfn, prot, lock));
1336*7c478bd9Sstevel@tonic-gate }
1337*7c478bd9Sstevel@tonic-gate 
1338*7c478bd9Sstevel@tonic-gate /*
1339*7c478bd9Sstevel@tonic-gate  * ddi_device_mapping_check:	Called from ddi_segmap_setup.
1340*7c478bd9Sstevel@tonic-gate  *	Invokes platform specific DDI to determine whether attributes specified
1341*7c478bd9Sstevel@tonic-gate  *	in attr(9s) are	valid for the region of memory that will be made
1342*7c478bd9Sstevel@tonic-gate  *	available for direct access to user process via the mmap(2) system call.
1343*7c478bd9Sstevel@tonic-gate  */
1344*7c478bd9Sstevel@tonic-gate int
1345*7c478bd9Sstevel@tonic-gate ddi_device_mapping_check(dev_t dev, ddi_device_acc_attr_t *accattrp,
1346*7c478bd9Sstevel@tonic-gate     uint_t rnumber, uint_t *hat_flags)
1347*7c478bd9Sstevel@tonic-gate {
1348*7c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t handle;
1349*7c478bd9Sstevel@tonic-gate 	ddi_map_req_t mr;
1350*7c478bd9Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
1351*7c478bd9Sstevel@tonic-gate 	int result;
1352*7c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
1353*7c478bd9Sstevel@tonic-gate 
1354*7c478bd9Sstevel@tonic-gate 	/*
1355*7c478bd9Sstevel@tonic-gate 	 * we use e_ddi_hold_devi_by_dev to search for the devi.  We
1356*7c478bd9Sstevel@tonic-gate 	 * release it immediately since it should already be held by
1357*7c478bd9Sstevel@tonic-gate 	 * a devfs vnode.
1358*7c478bd9Sstevel@tonic-gate 	 */
1359*7c478bd9Sstevel@tonic-gate 	if ((dip =
1360*7c478bd9Sstevel@tonic-gate 	    e_ddi_hold_devi_by_dev(dev, E_DDI_HOLD_DEVI_NOATTACH)) == NULL)
1361*7c478bd9Sstevel@tonic-gate 		return (-1);
1362*7c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);		/* for e_ddi_hold_devi_by_dev() */
1363*7c478bd9Sstevel@tonic-gate 
1364*7c478bd9Sstevel@tonic-gate 	/*
1365*7c478bd9Sstevel@tonic-gate 	 * Allocate and initialize the common elements of data
1366*7c478bd9Sstevel@tonic-gate 	 * access handle.
1367*7c478bd9Sstevel@tonic-gate 	 */
1368*7c478bd9Sstevel@tonic-gate 	handle = impl_acc_hdl_alloc(KM_SLEEP, NULL);
1369*7c478bd9Sstevel@tonic-gate 	if (handle == NULL)
1370*7c478bd9Sstevel@tonic-gate 		return (-1);
1371*7c478bd9Sstevel@tonic-gate 
1372*7c478bd9Sstevel@tonic-gate 	hp = impl_acc_hdl_get(handle);
1373*7c478bd9Sstevel@tonic-gate 	hp->ah_vers = VERS_ACCHDL;
1374*7c478bd9Sstevel@tonic-gate 	hp->ah_dip = dip;
1375*7c478bd9Sstevel@tonic-gate 	hp->ah_rnumber = rnumber;
1376*7c478bd9Sstevel@tonic-gate 	hp->ah_offset = 0;
1377*7c478bd9Sstevel@tonic-gate 	hp->ah_len = 0;
1378*7c478bd9Sstevel@tonic-gate 	hp->ah_acc = *accattrp;
1379*7c478bd9Sstevel@tonic-gate 
1380*7c478bd9Sstevel@tonic-gate 	/*
1381*7c478bd9Sstevel@tonic-gate 	 * Set up the mapping request and call to parent.
1382*7c478bd9Sstevel@tonic-gate 	 */
1383*7c478bd9Sstevel@tonic-gate 	mr.map_op = DDI_MO_MAP_HANDLE;
1384*7c478bd9Sstevel@tonic-gate 	mr.map_type = DDI_MT_RNUMBER;
1385*7c478bd9Sstevel@tonic-gate 	mr.map_obj.rnumber = rnumber;
1386*7c478bd9Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
1387*7c478bd9Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
1388*7c478bd9Sstevel@tonic-gate 	mr.map_handlep = hp;
1389*7c478bd9Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
1390*7c478bd9Sstevel@tonic-gate 	result = ddi_map(dip, &mr, 0, 0, NULL);
1391*7c478bd9Sstevel@tonic-gate 
1392*7c478bd9Sstevel@tonic-gate 	/*
1393*7c478bd9Sstevel@tonic-gate 	 * Region must be mappable, pick up flags from the framework.
1394*7c478bd9Sstevel@tonic-gate 	 */
1395*7c478bd9Sstevel@tonic-gate 	*hat_flags = hp->ah_hat_flags;
1396*7c478bd9Sstevel@tonic-gate 
1397*7c478bd9Sstevel@tonic-gate 	impl_acc_hdl_free(handle);
1398*7c478bd9Sstevel@tonic-gate 
1399*7c478bd9Sstevel@tonic-gate 	/*
1400*7c478bd9Sstevel@tonic-gate 	 * check for end result.
1401*7c478bd9Sstevel@tonic-gate 	 */
1402*7c478bd9Sstevel@tonic-gate 	if (result != DDI_SUCCESS)
1403*7c478bd9Sstevel@tonic-gate 		return (-1);
1404*7c478bd9Sstevel@tonic-gate 	return (0);
1405*7c478bd9Sstevel@tonic-gate }
1406*7c478bd9Sstevel@tonic-gate 
1407*7c478bd9Sstevel@tonic-gate 
1408*7c478bd9Sstevel@tonic-gate /*
1409*7c478bd9Sstevel@tonic-gate  * Property functions:	 See also, ddipropdefs.h.
1410*7c478bd9Sstevel@tonic-gate  *
1411*7c478bd9Sstevel@tonic-gate  * These functions are the framework for the property functions,
1412*7c478bd9Sstevel@tonic-gate  * i.e. they support software defined properties.  All implementation
1413*7c478bd9Sstevel@tonic-gate  * specific property handling (i.e.: self-identifying devices and
1414*7c478bd9Sstevel@tonic-gate  * PROM defined properties are handled in the implementation specific
1415*7c478bd9Sstevel@tonic-gate  * functions (defined in ddi_implfuncs.h).
1416*7c478bd9Sstevel@tonic-gate  */
1417*7c478bd9Sstevel@tonic-gate 
1418*7c478bd9Sstevel@tonic-gate /*
1419*7c478bd9Sstevel@tonic-gate  * nopropop:	Shouldn't be called, right?
1420*7c478bd9Sstevel@tonic-gate  */
1421*7c478bd9Sstevel@tonic-gate int
1422*7c478bd9Sstevel@tonic-gate nopropop(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
1423*7c478bd9Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
1424*7c478bd9Sstevel@tonic-gate {
1425*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dev, dip, prop_op, mod_flags, name, valuep, lengthp))
1426*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_NOT_FOUND);
1427*7c478bd9Sstevel@tonic-gate }
1428*7c478bd9Sstevel@tonic-gate 
1429*7c478bd9Sstevel@tonic-gate #ifdef	DDI_PROP_DEBUG
1430*7c478bd9Sstevel@tonic-gate int ddi_prop_debug_flag = 0;
1431*7c478bd9Sstevel@tonic-gate 
1432*7c478bd9Sstevel@tonic-gate int
1433*7c478bd9Sstevel@tonic-gate ddi_prop_debug(int enable)
1434*7c478bd9Sstevel@tonic-gate {
1435*7c478bd9Sstevel@tonic-gate 	int prev = ddi_prop_debug_flag;
1436*7c478bd9Sstevel@tonic-gate 
1437*7c478bd9Sstevel@tonic-gate 	if ((enable != 0) || (prev != 0))
1438*7c478bd9Sstevel@tonic-gate 		printf("ddi_prop_debug: debugging %s\n",
1439*7c478bd9Sstevel@tonic-gate 		    enable ? "enabled" : "disabled");
1440*7c478bd9Sstevel@tonic-gate 	ddi_prop_debug_flag = enable;
1441*7c478bd9Sstevel@tonic-gate 	return (prev);
1442*7c478bd9Sstevel@tonic-gate }
1443*7c478bd9Sstevel@tonic-gate 
1444*7c478bd9Sstevel@tonic-gate #endif	/* DDI_PROP_DEBUG */
1445*7c478bd9Sstevel@tonic-gate 
1446*7c478bd9Sstevel@tonic-gate /*
1447*7c478bd9Sstevel@tonic-gate  * Search a property list for a match, if found return pointer
1448*7c478bd9Sstevel@tonic-gate  * to matching prop struct, else return NULL.
1449*7c478bd9Sstevel@tonic-gate  */
1450*7c478bd9Sstevel@tonic-gate 
1451*7c478bd9Sstevel@tonic-gate ddi_prop_t *
1452*7c478bd9Sstevel@tonic-gate i_ddi_prop_search(dev_t dev, char *name, uint_t flags, ddi_prop_t **list_head)
1453*7c478bd9Sstevel@tonic-gate {
1454*7c478bd9Sstevel@tonic-gate 	ddi_prop_t	*propp;
1455*7c478bd9Sstevel@tonic-gate 
1456*7c478bd9Sstevel@tonic-gate 	/*
1457*7c478bd9Sstevel@tonic-gate 	 * find the property in child's devinfo:
1458*7c478bd9Sstevel@tonic-gate 	 */
1459*7c478bd9Sstevel@tonic-gate 
1460*7c478bd9Sstevel@tonic-gate 	/*
1461*7c478bd9Sstevel@tonic-gate 	 * Search order defined by this search function is
1462*7c478bd9Sstevel@tonic-gate 	 * first matching property with input dev ==
1463*7c478bd9Sstevel@tonic-gate 	 * DDI_DEV_T_ANY matching any dev or dev == propp->prop_dev,
1464*7c478bd9Sstevel@tonic-gate 	 * name == propp->name, and the correct data type as specified
1465*7c478bd9Sstevel@tonic-gate 	 * in the flags
1466*7c478bd9Sstevel@tonic-gate 	 */
1467*7c478bd9Sstevel@tonic-gate 
1468*7c478bd9Sstevel@tonic-gate 	for (propp = *list_head; propp != NULL; propp = propp->prop_next)  {
1469*7c478bd9Sstevel@tonic-gate 
1470*7c478bd9Sstevel@tonic-gate 		if (strcmp(propp->prop_name, name) != 0)
1471*7c478bd9Sstevel@tonic-gate 			continue;
1472*7c478bd9Sstevel@tonic-gate 
1473*7c478bd9Sstevel@tonic-gate 		if ((dev != DDI_DEV_T_ANY) && (propp->prop_dev != dev))
1474*7c478bd9Sstevel@tonic-gate 			continue;
1475*7c478bd9Sstevel@tonic-gate 
1476*7c478bd9Sstevel@tonic-gate 		if (((propp->prop_flags & flags) & DDI_PROP_TYPE_MASK) == 0)
1477*7c478bd9Sstevel@tonic-gate 			continue;
1478*7c478bd9Sstevel@tonic-gate 
1479*7c478bd9Sstevel@tonic-gate 		return (propp);
1480*7c478bd9Sstevel@tonic-gate 	}
1481*7c478bd9Sstevel@tonic-gate 
1482*7c478bd9Sstevel@tonic-gate 	return ((ddi_prop_t *)0);
1483*7c478bd9Sstevel@tonic-gate }
1484*7c478bd9Sstevel@tonic-gate 
1485*7c478bd9Sstevel@tonic-gate /*
1486*7c478bd9Sstevel@tonic-gate  * Search for property within devnames structures
1487*7c478bd9Sstevel@tonic-gate  */
1488*7c478bd9Sstevel@tonic-gate ddi_prop_t *
1489*7c478bd9Sstevel@tonic-gate i_ddi_search_global_prop(dev_t dev, char *name, uint_t flags)
1490*7c478bd9Sstevel@tonic-gate {
1491*7c478bd9Sstevel@tonic-gate 	major_t		major;
1492*7c478bd9Sstevel@tonic-gate 	struct devnames	*dnp;
1493*7c478bd9Sstevel@tonic-gate 	ddi_prop_t	*propp;
1494*7c478bd9Sstevel@tonic-gate 
1495*7c478bd9Sstevel@tonic-gate 	/*
1496*7c478bd9Sstevel@tonic-gate 	 * Valid dev_t value is needed to index into the
1497*7c478bd9Sstevel@tonic-gate 	 * correct devnames entry, therefore a dev_t
1498*7c478bd9Sstevel@tonic-gate 	 * value of DDI_DEV_T_ANY is not appropriate.
1499*7c478bd9Sstevel@tonic-gate 	 */
1500*7c478bd9Sstevel@tonic-gate 	ASSERT(dev != DDI_DEV_T_ANY);
1501*7c478bd9Sstevel@tonic-gate 	if (dev == DDI_DEV_T_ANY) {
1502*7c478bd9Sstevel@tonic-gate 		return ((ddi_prop_t *)0);
1503*7c478bd9Sstevel@tonic-gate 	}
1504*7c478bd9Sstevel@tonic-gate 
1505*7c478bd9Sstevel@tonic-gate 	major = getmajor(dev);
1506*7c478bd9Sstevel@tonic-gate 	dnp = &(devnamesp[major]);
1507*7c478bd9Sstevel@tonic-gate 
1508*7c478bd9Sstevel@tonic-gate 	if (dnp->dn_global_prop_ptr == NULL)
1509*7c478bd9Sstevel@tonic-gate 		return ((ddi_prop_t *)0);
1510*7c478bd9Sstevel@tonic-gate 
1511*7c478bd9Sstevel@tonic-gate 	LOCK_DEV_OPS(&dnp->dn_lock);
1512*7c478bd9Sstevel@tonic-gate 
1513*7c478bd9Sstevel@tonic-gate 	for (propp = dnp->dn_global_prop_ptr->prop_list;
1514*7c478bd9Sstevel@tonic-gate 	    propp != NULL;
1515*7c478bd9Sstevel@tonic-gate 	    propp = (ddi_prop_t *)propp->prop_next) {
1516*7c478bd9Sstevel@tonic-gate 
1517*7c478bd9Sstevel@tonic-gate 		if (strcmp(propp->prop_name, name) != 0)
1518*7c478bd9Sstevel@tonic-gate 			continue;
1519*7c478bd9Sstevel@tonic-gate 
1520*7c478bd9Sstevel@tonic-gate 		if ((!(flags & LDI_DEV_T_ANY)) && (propp->prop_dev != dev))
1521*7c478bd9Sstevel@tonic-gate 			continue;
1522*7c478bd9Sstevel@tonic-gate 
1523*7c478bd9Sstevel@tonic-gate 		if (((propp->prop_flags & flags) & DDI_PROP_TYPE_MASK) == 0)
1524*7c478bd9Sstevel@tonic-gate 			continue;
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate 		/* Property found, return it */
1527*7c478bd9Sstevel@tonic-gate 		UNLOCK_DEV_OPS(&dnp->dn_lock);
1528*7c478bd9Sstevel@tonic-gate 		return (propp);
1529*7c478bd9Sstevel@tonic-gate 	}
1530*7c478bd9Sstevel@tonic-gate 
1531*7c478bd9Sstevel@tonic-gate 	UNLOCK_DEV_OPS(&dnp->dn_lock);
1532*7c478bd9Sstevel@tonic-gate 	return ((ddi_prop_t *)0);
1533*7c478bd9Sstevel@tonic-gate }
1534*7c478bd9Sstevel@tonic-gate 
1535*7c478bd9Sstevel@tonic-gate static char prop_no_mem_msg[] = "can't allocate memory for ddi property <%s>";
1536*7c478bd9Sstevel@tonic-gate 
1537*7c478bd9Sstevel@tonic-gate /*
1538*7c478bd9Sstevel@tonic-gate  * ddi_prop_search_global:
1539*7c478bd9Sstevel@tonic-gate  *	Search the global property list within devnames
1540*7c478bd9Sstevel@tonic-gate  *	for the named property.  Return the encoded value.
1541*7c478bd9Sstevel@tonic-gate  */
1542*7c478bd9Sstevel@tonic-gate static int
1543*7c478bd9Sstevel@tonic-gate i_ddi_prop_search_global(dev_t dev, uint_t flags, char *name,
1544*7c478bd9Sstevel@tonic-gate     void *valuep, uint_t *lengthp)
1545*7c478bd9Sstevel@tonic-gate {
1546*7c478bd9Sstevel@tonic-gate 	ddi_prop_t	*propp;
1547*7c478bd9Sstevel@tonic-gate 	caddr_t		buffer;
1548*7c478bd9Sstevel@tonic-gate 
1549*7c478bd9Sstevel@tonic-gate 	propp =  i_ddi_search_global_prop(dev, name, flags);
1550*7c478bd9Sstevel@tonic-gate 
1551*7c478bd9Sstevel@tonic-gate 	/* Property NOT found, bail */
1552*7c478bd9Sstevel@tonic-gate 	if (propp == (ddi_prop_t *)0)
1553*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
1554*7c478bd9Sstevel@tonic-gate 
1555*7c478bd9Sstevel@tonic-gate 	if (propp->prop_flags & DDI_PROP_UNDEF_IT)
1556*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_UNDEFINED);
1557*7c478bd9Sstevel@tonic-gate 
1558*7c478bd9Sstevel@tonic-gate 	if ((buffer = kmem_alloc(propp->prop_len, KM_NOSLEEP)) == NULL) {
1559*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, prop_no_mem_msg, name);
1560*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
1561*7c478bd9Sstevel@tonic-gate 	}
1562*7c478bd9Sstevel@tonic-gate 
1563*7c478bd9Sstevel@tonic-gate 	/*
1564*7c478bd9Sstevel@tonic-gate 	 * Return the encoded data
1565*7c478bd9Sstevel@tonic-gate 	 */
1566*7c478bd9Sstevel@tonic-gate 	*(caddr_t *)valuep = buffer;
1567*7c478bd9Sstevel@tonic-gate 	*lengthp = propp->prop_len;
1568*7c478bd9Sstevel@tonic-gate 	bcopy(propp->prop_val, buffer, propp->prop_len);
1569*7c478bd9Sstevel@tonic-gate 
1570*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
1571*7c478bd9Sstevel@tonic-gate }
1572*7c478bd9Sstevel@tonic-gate 
1573*7c478bd9Sstevel@tonic-gate /*
1574*7c478bd9Sstevel@tonic-gate  * ddi_prop_search_common:	Lookup and return the encoded value
1575*7c478bd9Sstevel@tonic-gate  */
1576*7c478bd9Sstevel@tonic-gate int
1577*7c478bd9Sstevel@tonic-gate ddi_prop_search_common(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1578*7c478bd9Sstevel@tonic-gate     uint_t flags, char *name, void *valuep, uint_t *lengthp)
1579*7c478bd9Sstevel@tonic-gate {
1580*7c478bd9Sstevel@tonic-gate 	ddi_prop_t	*propp;
1581*7c478bd9Sstevel@tonic-gate 	int		i;
1582*7c478bd9Sstevel@tonic-gate 	caddr_t		buffer;
1583*7c478bd9Sstevel@tonic-gate 	caddr_t		prealloc = NULL;
1584*7c478bd9Sstevel@tonic-gate 	int		plength = 0;
1585*7c478bd9Sstevel@tonic-gate 	dev_info_t	*pdip;
1586*7c478bd9Sstevel@tonic-gate 	int		(*bop)();
1587*7c478bd9Sstevel@tonic-gate 
1588*7c478bd9Sstevel@tonic-gate 	/*CONSTANTCONDITION*/
1589*7c478bd9Sstevel@tonic-gate 	while (1)  {
1590*7c478bd9Sstevel@tonic-gate 
1591*7c478bd9Sstevel@tonic-gate 		mutex_enter(&(DEVI(dip)->devi_lock));
1592*7c478bd9Sstevel@tonic-gate 
1593*7c478bd9Sstevel@tonic-gate 
1594*7c478bd9Sstevel@tonic-gate 		/*
1595*7c478bd9Sstevel@tonic-gate 		 * find the property in child's devinfo:
1596*7c478bd9Sstevel@tonic-gate 		 * Search order is:
1597*7c478bd9Sstevel@tonic-gate 		 *	1. driver defined properties
1598*7c478bd9Sstevel@tonic-gate 		 *	2. system defined properties
1599*7c478bd9Sstevel@tonic-gate 		 *	3. driver global properties
1600*7c478bd9Sstevel@tonic-gate 		 *	4. boot defined properties
1601*7c478bd9Sstevel@tonic-gate 		 */
1602*7c478bd9Sstevel@tonic-gate 
1603*7c478bd9Sstevel@tonic-gate 		propp = i_ddi_prop_search(dev, name, flags,
1604*7c478bd9Sstevel@tonic-gate 		    &(DEVI(dip)->devi_drv_prop_ptr));
1605*7c478bd9Sstevel@tonic-gate 		if (propp == NULL)  {
1606*7c478bd9Sstevel@tonic-gate 			propp = i_ddi_prop_search(dev, name, flags,
1607*7c478bd9Sstevel@tonic-gate 			    &(DEVI(dip)->devi_sys_prop_ptr));
1608*7c478bd9Sstevel@tonic-gate 		}
1609*7c478bd9Sstevel@tonic-gate 		if ((propp == NULL) && DEVI(dip)->devi_global_prop_list) {
1610*7c478bd9Sstevel@tonic-gate 			propp = i_ddi_prop_search(dev, name, flags,
1611*7c478bd9Sstevel@tonic-gate 			    &DEVI(dip)->devi_global_prop_list->prop_list);
1612*7c478bd9Sstevel@tonic-gate 		}
1613*7c478bd9Sstevel@tonic-gate 
1614*7c478bd9Sstevel@tonic-gate 		if (propp == NULL)  {
1615*7c478bd9Sstevel@tonic-gate 			propp = i_ddi_prop_search(dev, name, flags,
1616*7c478bd9Sstevel@tonic-gate 			    &(DEVI(dip)->devi_hw_prop_ptr));
1617*7c478bd9Sstevel@tonic-gate 		}
1618*7c478bd9Sstevel@tonic-gate 
1619*7c478bd9Sstevel@tonic-gate 		/*
1620*7c478bd9Sstevel@tonic-gate 		 * Software property found?
1621*7c478bd9Sstevel@tonic-gate 		 */
1622*7c478bd9Sstevel@tonic-gate 		if (propp != (ddi_prop_t *)0)	{
1623*7c478bd9Sstevel@tonic-gate 
1624*7c478bd9Sstevel@tonic-gate 			/*
1625*7c478bd9Sstevel@tonic-gate 			 * If explicit undefine, return now.
1626*7c478bd9Sstevel@tonic-gate 			 */
1627*7c478bd9Sstevel@tonic-gate 			if (propp->prop_flags & DDI_PROP_UNDEF_IT) {
1628*7c478bd9Sstevel@tonic-gate 				mutex_exit(&(DEVI(dip)->devi_lock));
1629*7c478bd9Sstevel@tonic-gate 				if (prealloc)
1630*7c478bd9Sstevel@tonic-gate 					kmem_free(prealloc, plength);
1631*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_UNDEFINED);
1632*7c478bd9Sstevel@tonic-gate 			}
1633*7c478bd9Sstevel@tonic-gate 
1634*7c478bd9Sstevel@tonic-gate 			/*
1635*7c478bd9Sstevel@tonic-gate 			 * If we only want to know if it exists, return now
1636*7c478bd9Sstevel@tonic-gate 			 */
1637*7c478bd9Sstevel@tonic-gate 			if (prop_op == PROP_EXISTS) {
1638*7c478bd9Sstevel@tonic-gate 				mutex_exit(&(DEVI(dip)->devi_lock));
1639*7c478bd9Sstevel@tonic-gate 				ASSERT(prealloc == NULL);
1640*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_SUCCESS);
1641*7c478bd9Sstevel@tonic-gate 			}
1642*7c478bd9Sstevel@tonic-gate 
1643*7c478bd9Sstevel@tonic-gate 			/*
1644*7c478bd9Sstevel@tonic-gate 			 * If length only request or prop length == 0,
1645*7c478bd9Sstevel@tonic-gate 			 * service request and return now.
1646*7c478bd9Sstevel@tonic-gate 			 */
1647*7c478bd9Sstevel@tonic-gate 			if ((prop_op == PROP_LEN) ||(propp->prop_len == 0)) {
1648*7c478bd9Sstevel@tonic-gate 				*lengthp = propp->prop_len;
1649*7c478bd9Sstevel@tonic-gate 
1650*7c478bd9Sstevel@tonic-gate 				/*
1651*7c478bd9Sstevel@tonic-gate 				 * if prop_op is PROP_LEN_AND_VAL_ALLOC
1652*7c478bd9Sstevel@tonic-gate 				 * that means prop_len is 0, so set valuep
1653*7c478bd9Sstevel@tonic-gate 				 * also to NULL
1654*7c478bd9Sstevel@tonic-gate 				 */
1655*7c478bd9Sstevel@tonic-gate 				if (prop_op == PROP_LEN_AND_VAL_ALLOC)
1656*7c478bd9Sstevel@tonic-gate 					*(caddr_t *)valuep = NULL;
1657*7c478bd9Sstevel@tonic-gate 
1658*7c478bd9Sstevel@tonic-gate 				mutex_exit(&(DEVI(dip)->devi_lock));
1659*7c478bd9Sstevel@tonic-gate 				if (prealloc)
1660*7c478bd9Sstevel@tonic-gate 					kmem_free(prealloc, plength);
1661*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_SUCCESS);
1662*7c478bd9Sstevel@tonic-gate 			}
1663*7c478bd9Sstevel@tonic-gate 
1664*7c478bd9Sstevel@tonic-gate 			/*
1665*7c478bd9Sstevel@tonic-gate 			 * If LEN_AND_VAL_ALLOC and the request can sleep,
1666*7c478bd9Sstevel@tonic-gate 			 * drop the mutex, allocate the buffer, and go
1667*7c478bd9Sstevel@tonic-gate 			 * through the loop again.  If we already allocated
1668*7c478bd9Sstevel@tonic-gate 			 * the buffer, and the size of the property changed,
1669*7c478bd9Sstevel@tonic-gate 			 * keep trying...
1670*7c478bd9Sstevel@tonic-gate 			 */
1671*7c478bd9Sstevel@tonic-gate 			if ((prop_op == PROP_LEN_AND_VAL_ALLOC) &&
1672*7c478bd9Sstevel@tonic-gate 			    (flags & DDI_PROP_CANSLEEP))  {
1673*7c478bd9Sstevel@tonic-gate 				if (prealloc && (propp->prop_len != plength)) {
1674*7c478bd9Sstevel@tonic-gate 					kmem_free(prealloc, plength);
1675*7c478bd9Sstevel@tonic-gate 					prealloc = NULL;
1676*7c478bd9Sstevel@tonic-gate 				}
1677*7c478bd9Sstevel@tonic-gate 				if (prealloc == NULL)  {
1678*7c478bd9Sstevel@tonic-gate 					plength = propp->prop_len;
1679*7c478bd9Sstevel@tonic-gate 					mutex_exit(&(DEVI(dip)->devi_lock));
1680*7c478bd9Sstevel@tonic-gate 					prealloc = kmem_alloc(plength,
1681*7c478bd9Sstevel@tonic-gate 					    KM_SLEEP);
1682*7c478bd9Sstevel@tonic-gate 					continue;
1683*7c478bd9Sstevel@tonic-gate 				}
1684*7c478bd9Sstevel@tonic-gate 			}
1685*7c478bd9Sstevel@tonic-gate 
1686*7c478bd9Sstevel@tonic-gate 			/*
1687*7c478bd9Sstevel@tonic-gate 			 * Allocate buffer, if required.  Either way,
1688*7c478bd9Sstevel@tonic-gate 			 * set `buffer' variable.
1689*7c478bd9Sstevel@tonic-gate 			 */
1690*7c478bd9Sstevel@tonic-gate 			i = *lengthp;			/* Get callers length */
1691*7c478bd9Sstevel@tonic-gate 			*lengthp = propp->prop_len;	/* Set callers length */
1692*7c478bd9Sstevel@tonic-gate 
1693*7c478bd9Sstevel@tonic-gate 			switch (prop_op) {
1694*7c478bd9Sstevel@tonic-gate 
1695*7c478bd9Sstevel@tonic-gate 			case PROP_LEN_AND_VAL_ALLOC:
1696*7c478bd9Sstevel@tonic-gate 
1697*7c478bd9Sstevel@tonic-gate 				if (prealloc == NULL) {
1698*7c478bd9Sstevel@tonic-gate 					buffer = kmem_alloc(propp->prop_len,
1699*7c478bd9Sstevel@tonic-gate 					    KM_NOSLEEP);
1700*7c478bd9Sstevel@tonic-gate 				} else {
1701*7c478bd9Sstevel@tonic-gate 					buffer = prealloc;
1702*7c478bd9Sstevel@tonic-gate 				}
1703*7c478bd9Sstevel@tonic-gate 
1704*7c478bd9Sstevel@tonic-gate 				if (buffer == NULL)  {
1705*7c478bd9Sstevel@tonic-gate 					mutex_exit(&(DEVI(dip)->devi_lock));
1706*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT, prop_no_mem_msg, name);
1707*7c478bd9Sstevel@tonic-gate 					return (DDI_PROP_NO_MEMORY);
1708*7c478bd9Sstevel@tonic-gate 				}
1709*7c478bd9Sstevel@tonic-gate 				/* Set callers buf ptr */
1710*7c478bd9Sstevel@tonic-gate 				*(caddr_t *)valuep = buffer;
1711*7c478bd9Sstevel@tonic-gate 				break;
1712*7c478bd9Sstevel@tonic-gate 
1713*7c478bd9Sstevel@tonic-gate 			case PROP_LEN_AND_VAL_BUF:
1714*7c478bd9Sstevel@tonic-gate 
1715*7c478bd9Sstevel@tonic-gate 				if (propp->prop_len > (i)) {
1716*7c478bd9Sstevel@tonic-gate 					mutex_exit(&(DEVI(dip)->devi_lock));
1717*7c478bd9Sstevel@tonic-gate 					return (DDI_PROP_BUF_TOO_SMALL);
1718*7c478bd9Sstevel@tonic-gate 				}
1719*7c478bd9Sstevel@tonic-gate 
1720*7c478bd9Sstevel@tonic-gate 				buffer = valuep;  /* Get callers buf ptr */
1721*7c478bd9Sstevel@tonic-gate 				break;
1722*7c478bd9Sstevel@tonic-gate 
1723*7c478bd9Sstevel@tonic-gate 			default:
1724*7c478bd9Sstevel@tonic-gate 				break;
1725*7c478bd9Sstevel@tonic-gate 			}
1726*7c478bd9Sstevel@tonic-gate 
1727*7c478bd9Sstevel@tonic-gate 			/*
1728*7c478bd9Sstevel@tonic-gate 			 * Do the copy.
1729*7c478bd9Sstevel@tonic-gate 			 */
1730*7c478bd9Sstevel@tonic-gate 			bcopy(propp->prop_val, buffer, propp->prop_len);
1731*7c478bd9Sstevel@tonic-gate 			mutex_exit(&(DEVI(dip)->devi_lock));
1732*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_SUCCESS);
1733*7c478bd9Sstevel@tonic-gate 		}
1734*7c478bd9Sstevel@tonic-gate 
1735*7c478bd9Sstevel@tonic-gate 		mutex_exit(&(DEVI(dip)->devi_lock));
1736*7c478bd9Sstevel@tonic-gate 		if (prealloc)
1737*7c478bd9Sstevel@tonic-gate 			kmem_free(prealloc, plength);
1738*7c478bd9Sstevel@tonic-gate 		prealloc = NULL;
1739*7c478bd9Sstevel@tonic-gate 
1740*7c478bd9Sstevel@tonic-gate 		/*
1741*7c478bd9Sstevel@tonic-gate 		 * Prop not found, call parent bus_ops to deal with possible
1742*7c478bd9Sstevel@tonic-gate 		 * h/w layer (possible PROM defined props, etc.) and to
1743*7c478bd9Sstevel@tonic-gate 		 * possibly ascend the hierarchy, if allowed by flags.
1744*7c478bd9Sstevel@tonic-gate 		 */
1745*7c478bd9Sstevel@tonic-gate 		pdip = (dev_info_t *)DEVI(dip)->devi_parent;
1746*7c478bd9Sstevel@tonic-gate 
1747*7c478bd9Sstevel@tonic-gate 		/*
1748*7c478bd9Sstevel@tonic-gate 		 * One last call for the root driver PROM props?
1749*7c478bd9Sstevel@tonic-gate 		 */
1750*7c478bd9Sstevel@tonic-gate 		if (dip == ddi_root_node())  {
1751*7c478bd9Sstevel@tonic-gate 			return (ddi_bus_prop_op(dev, dip, dip, prop_op,
1752*7c478bd9Sstevel@tonic-gate 			    flags, name, valuep, (int *)lengthp));
1753*7c478bd9Sstevel@tonic-gate 		}
1754*7c478bd9Sstevel@tonic-gate 
1755*7c478bd9Sstevel@tonic-gate 		/*
1756*7c478bd9Sstevel@tonic-gate 		 * We may have been called to check for properties
1757*7c478bd9Sstevel@tonic-gate 		 * within a single devinfo node that has no parent -
1758*7c478bd9Sstevel@tonic-gate 		 * see make_prop()
1759*7c478bd9Sstevel@tonic-gate 		 */
1760*7c478bd9Sstevel@tonic-gate 		if (pdip == NULL) {
1761*7c478bd9Sstevel@tonic-gate 			ASSERT((flags &
1762*7c478bd9Sstevel@tonic-gate 			    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM)) ==
1763*7c478bd9Sstevel@tonic-gate 			    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM));
1764*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_NOT_FOUND);
1765*7c478bd9Sstevel@tonic-gate 		}
1766*7c478bd9Sstevel@tonic-gate 
1767*7c478bd9Sstevel@tonic-gate 		/*
1768*7c478bd9Sstevel@tonic-gate 		 * Instead of recursing, we do iterative calls up the tree.
1769*7c478bd9Sstevel@tonic-gate 		 * As a bit of optimization, skip the bus_op level if the
1770*7c478bd9Sstevel@tonic-gate 		 * node is a s/w node and if the parent's bus_prop_op function
1771*7c478bd9Sstevel@tonic-gate 		 * is `ddi_bus_prop_op', because we know that in this case,
1772*7c478bd9Sstevel@tonic-gate 		 * this function does nothing.
1773*7c478bd9Sstevel@tonic-gate 		 *
1774*7c478bd9Sstevel@tonic-gate 		 * 4225415: If the parent isn't attached, or the child
1775*7c478bd9Sstevel@tonic-gate 		 * hasn't been named by the parent yet, use the default
1776*7c478bd9Sstevel@tonic-gate 		 * ddi_bus_prop_op as a proxy for the parent.  This
1777*7c478bd9Sstevel@tonic-gate 		 * allows property lookups in any child/parent state to
1778*7c478bd9Sstevel@tonic-gate 		 * include 'prom' and inherited properties, even when
1779*7c478bd9Sstevel@tonic-gate 		 * there are no drivers attached to the child or parent.
1780*7c478bd9Sstevel@tonic-gate 		 */
1781*7c478bd9Sstevel@tonic-gate 
1782*7c478bd9Sstevel@tonic-gate 		bop = ddi_bus_prop_op;
1783*7c478bd9Sstevel@tonic-gate 		if ((i_ddi_node_state(pdip) == DS_READY) &&
1784*7c478bd9Sstevel@tonic-gate 		    (i_ddi_node_state(dip) >= DS_INITIALIZED))
1785*7c478bd9Sstevel@tonic-gate 			bop = DEVI(pdip)->devi_ops->devo_bus_ops->bus_prop_op;
1786*7c478bd9Sstevel@tonic-gate 
1787*7c478bd9Sstevel@tonic-gate 		i = DDI_PROP_NOT_FOUND;
1788*7c478bd9Sstevel@tonic-gate 
1789*7c478bd9Sstevel@tonic-gate 		if ((bop != ddi_bus_prop_op) || ndi_dev_is_prom_node(dip)) {
1790*7c478bd9Sstevel@tonic-gate 			i = (*bop)(dev, pdip, dip, prop_op,
1791*7c478bd9Sstevel@tonic-gate 			    flags | DDI_PROP_DONTPASS,
1792*7c478bd9Sstevel@tonic-gate 			    name, valuep, lengthp);
1793*7c478bd9Sstevel@tonic-gate 		}
1794*7c478bd9Sstevel@tonic-gate 
1795*7c478bd9Sstevel@tonic-gate 		if ((flags & DDI_PROP_DONTPASS) ||
1796*7c478bd9Sstevel@tonic-gate 		    (i != DDI_PROP_NOT_FOUND))
1797*7c478bd9Sstevel@tonic-gate 			return (i);
1798*7c478bd9Sstevel@tonic-gate 
1799*7c478bd9Sstevel@tonic-gate 		dip = pdip;
1800*7c478bd9Sstevel@tonic-gate 	}
1801*7c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
1802*7c478bd9Sstevel@tonic-gate }
1803*7c478bd9Sstevel@tonic-gate 
1804*7c478bd9Sstevel@tonic-gate 
1805*7c478bd9Sstevel@tonic-gate /*
1806*7c478bd9Sstevel@tonic-gate  * ddi_prop_op: The basic property operator for drivers.
1807*7c478bd9Sstevel@tonic-gate  *
1808*7c478bd9Sstevel@tonic-gate  * In ddi_prop_op, the type of valuep is interpreted based on prop_op:
1809*7c478bd9Sstevel@tonic-gate  *
1810*7c478bd9Sstevel@tonic-gate  *	prop_op			valuep
1811*7c478bd9Sstevel@tonic-gate  *	------			------
1812*7c478bd9Sstevel@tonic-gate  *
1813*7c478bd9Sstevel@tonic-gate  *	PROP_LEN		<unused>
1814*7c478bd9Sstevel@tonic-gate  *
1815*7c478bd9Sstevel@tonic-gate  *	PROP_LEN_AND_VAL_BUF	Pointer to callers buffer
1816*7c478bd9Sstevel@tonic-gate  *
1817*7c478bd9Sstevel@tonic-gate  *	PROP_LEN_AND_VAL_ALLOC	Address of callers pointer (will be set to
1818*7c478bd9Sstevel@tonic-gate  *				address of allocated buffer, if successful)
1819*7c478bd9Sstevel@tonic-gate  */
1820*7c478bd9Sstevel@tonic-gate int
1821*7c478bd9Sstevel@tonic-gate ddi_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
1822*7c478bd9Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
1823*7c478bd9Sstevel@tonic-gate {
1824*7c478bd9Sstevel@tonic-gate 	int	i;
1825*7c478bd9Sstevel@tonic-gate 
1826*7c478bd9Sstevel@tonic-gate 	ASSERT((mod_flags & DDI_PROP_TYPE_MASK) == 0);
1827*7c478bd9Sstevel@tonic-gate 
1828*7c478bd9Sstevel@tonic-gate 	/*
1829*7c478bd9Sstevel@tonic-gate 	 * If this was originally an LDI prop lookup then we bail here.
1830*7c478bd9Sstevel@tonic-gate 	 * The reason is that the LDI property lookup interfaces first call
1831*7c478bd9Sstevel@tonic-gate 	 * a drivers prop_op() entry point to allow it to override
1832*7c478bd9Sstevel@tonic-gate 	 * properties.  But if we've made it here, then the driver hasn't
1833*7c478bd9Sstevel@tonic-gate 	 * overriden any properties.  We don't want to continue with the
1834*7c478bd9Sstevel@tonic-gate 	 * property search here because we don't have any type inforamtion.
1835*7c478bd9Sstevel@tonic-gate 	 * When we return failure, the LDI interfaces will then proceed to
1836*7c478bd9Sstevel@tonic-gate 	 * call the typed property interfaces to look up the property.
1837*7c478bd9Sstevel@tonic-gate 	 */
1838*7c478bd9Sstevel@tonic-gate 	if (mod_flags & DDI_PROP_DYNAMIC)
1839*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
1840*7c478bd9Sstevel@tonic-gate 
1841*7c478bd9Sstevel@tonic-gate 	/*
1842*7c478bd9Sstevel@tonic-gate 	 * check for pre-typed property consumer asking for typed property:
1843*7c478bd9Sstevel@tonic-gate 	 * see e_ddi_getprop_int64.
1844*7c478bd9Sstevel@tonic-gate 	 */
1845*7c478bd9Sstevel@tonic-gate 	if (mod_flags & DDI_PROP_CONSUMER_TYPED)
1846*7c478bd9Sstevel@tonic-gate 		mod_flags |= DDI_PROP_TYPE_INT64;
1847*7c478bd9Sstevel@tonic-gate 	mod_flags |= DDI_PROP_TYPE_ANY;
1848*7c478bd9Sstevel@tonic-gate 
1849*7c478bd9Sstevel@tonic-gate 	i = ddi_prop_search_common(dev, dip, prop_op,
1850*7c478bd9Sstevel@tonic-gate 		mod_flags, name, valuep, (uint_t *)lengthp);
1851*7c478bd9Sstevel@tonic-gate 	if (i == DDI_PROP_FOUND_1275)
1852*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_SUCCESS);
1853*7c478bd9Sstevel@tonic-gate 	return (i);
1854*7c478bd9Sstevel@tonic-gate }
1855*7c478bd9Sstevel@tonic-gate 
1856*7c478bd9Sstevel@tonic-gate /*
1857*7c478bd9Sstevel@tonic-gate  * ddi_prop_op_nblocks: The basic property operator for drivers that maintain
1858*7c478bd9Sstevel@tonic-gate  * size in number of DEV_BSIZE blocks.  Provides a dynamic property
1859*7c478bd9Sstevel@tonic-gate  * implementation for size oriented properties based on nblocks64 values passed
1860*7c478bd9Sstevel@tonic-gate  * in by the driver.  Fallback to ddi_prop_op if the nblocks64 is too large.
1861*7c478bd9Sstevel@tonic-gate  * This interface should not be used with a nblocks64 that represents the
1862*7c478bd9Sstevel@tonic-gate  * driver's idea of how to represent unknown, if nblocks is unknown use
1863*7c478bd9Sstevel@tonic-gate  * ddi_prop_op.
1864*7c478bd9Sstevel@tonic-gate  */
1865*7c478bd9Sstevel@tonic-gate int
1866*7c478bd9Sstevel@tonic-gate ddi_prop_op_nblocks(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1867*7c478bd9Sstevel@tonic-gate     int mod_flags, char *name, caddr_t valuep, int *lengthp, uint64_t nblocks64)
1868*7c478bd9Sstevel@tonic-gate {
1869*7c478bd9Sstevel@tonic-gate 	uint64_t size64;
1870*7c478bd9Sstevel@tonic-gate 
1871*7c478bd9Sstevel@tonic-gate 	/*
1872*7c478bd9Sstevel@tonic-gate 	 * There is no point in supporting nblocks64 values that don't have
1873*7c478bd9Sstevel@tonic-gate 	 * an accurate uint64_t byte count representation.
1874*7c478bd9Sstevel@tonic-gate 	 */
1875*7c478bd9Sstevel@tonic-gate 	if (nblocks64 >= (UINT64_MAX >> DEV_BSHIFT))
1876*7c478bd9Sstevel@tonic-gate 		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
1877*7c478bd9Sstevel@tonic-gate 		    name, valuep, lengthp));
1878*7c478bd9Sstevel@tonic-gate 
1879*7c478bd9Sstevel@tonic-gate 	size64 = nblocks64 << DEV_BSHIFT;
1880*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_op_size(dev, dip, prop_op, mod_flags,
1881*7c478bd9Sstevel@tonic-gate 	    name, valuep, lengthp, size64));
1882*7c478bd9Sstevel@tonic-gate }
1883*7c478bd9Sstevel@tonic-gate 
1884*7c478bd9Sstevel@tonic-gate /*
1885*7c478bd9Sstevel@tonic-gate  * ddi_prop_op_size: The basic property operator for drivers that maintain size
1886*7c478bd9Sstevel@tonic-gate  * in bytes. Provides a of dynamic property implementation for size oriented
1887*7c478bd9Sstevel@tonic-gate  * properties based on size64 values passed in by the driver.  Fallback to
1888*7c478bd9Sstevel@tonic-gate  * ddi_prop_op if the size64 is too large. This interface should not be used
1889*7c478bd9Sstevel@tonic-gate  * with a size64 that represents the driver's idea of how to represent unknown,
1890*7c478bd9Sstevel@tonic-gate  * if size is unknown use ddi_prop_op.
1891*7c478bd9Sstevel@tonic-gate  *
1892*7c478bd9Sstevel@tonic-gate  * NOTE: the legacy "nblocks"/"size" properties are treated as 32-bit unsigned
1893*7c478bd9Sstevel@tonic-gate  * integers. While the most likely interface to request them ([bc]devi_size)
1894*7c478bd9Sstevel@tonic-gate  * is declared int (signed) there is no enforcement of this, which means we
1895*7c478bd9Sstevel@tonic-gate  * can't enforce limitations here without risking regression.
1896*7c478bd9Sstevel@tonic-gate  */
1897*7c478bd9Sstevel@tonic-gate int
1898*7c478bd9Sstevel@tonic-gate ddi_prop_op_size(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1899*7c478bd9Sstevel@tonic-gate     int mod_flags, char *name, caddr_t valuep, int *lengthp, uint64_t size64)
1900*7c478bd9Sstevel@tonic-gate {
1901*7c478bd9Sstevel@tonic-gate 	uint64_t nblocks64;
1902*7c478bd9Sstevel@tonic-gate 	int	callers_length;
1903*7c478bd9Sstevel@tonic-gate 	caddr_t	buffer;
1904*7c478bd9Sstevel@tonic-gate 
1905*7c478bd9Sstevel@tonic-gate 	/* compute DEV_BSIZE nblocks value */
1906*7c478bd9Sstevel@tonic-gate 	nblocks64 = lbtodb(size64);
1907*7c478bd9Sstevel@tonic-gate 
1908*7c478bd9Sstevel@tonic-gate 	/* get callers length, establish length of our dynamic properties */
1909*7c478bd9Sstevel@tonic-gate 	callers_length = *lengthp;
1910*7c478bd9Sstevel@tonic-gate 
1911*7c478bd9Sstevel@tonic-gate 	if (strcmp(name, "Nblocks") == 0)
1912*7c478bd9Sstevel@tonic-gate 		*lengthp = sizeof (uint64_t);
1913*7c478bd9Sstevel@tonic-gate 	else if (strcmp(name, "Size") == 0)
1914*7c478bd9Sstevel@tonic-gate 		*lengthp = sizeof (uint64_t);
1915*7c478bd9Sstevel@tonic-gate 	else if ((strcmp(name, "nblocks") == 0) && (nblocks64 < UINT_MAX))
1916*7c478bd9Sstevel@tonic-gate 		*lengthp = sizeof (uint32_t);
1917*7c478bd9Sstevel@tonic-gate 	else if ((strcmp(name, "size") == 0) && (size64 < UINT_MAX))
1918*7c478bd9Sstevel@tonic-gate 		*lengthp = sizeof (uint32_t);
1919*7c478bd9Sstevel@tonic-gate 	else {
1920*7c478bd9Sstevel@tonic-gate 		/* fallback to ddi_prop_op */
1921*7c478bd9Sstevel@tonic-gate 		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
1922*7c478bd9Sstevel@tonic-gate 		    name, valuep, lengthp));
1923*7c478bd9Sstevel@tonic-gate 	}
1924*7c478bd9Sstevel@tonic-gate 
1925*7c478bd9Sstevel@tonic-gate 	/* service request for the length of the property */
1926*7c478bd9Sstevel@tonic-gate 	if (prop_op == PROP_LEN)
1927*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_SUCCESS);
1928*7c478bd9Sstevel@tonic-gate 
1929*7c478bd9Sstevel@tonic-gate 	/* the length of the property and the request must match */
1930*7c478bd9Sstevel@tonic-gate 	if (callers_length != *lengthp)
1931*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
1932*7c478bd9Sstevel@tonic-gate 
1933*7c478bd9Sstevel@tonic-gate 	switch (prop_op) {
1934*7c478bd9Sstevel@tonic-gate 	case PROP_LEN_AND_VAL_ALLOC:
1935*7c478bd9Sstevel@tonic-gate 		if ((buffer = kmem_alloc(*lengthp,
1936*7c478bd9Sstevel@tonic-gate 		    (mod_flags & DDI_PROP_CANSLEEP) ?
1937*7c478bd9Sstevel@tonic-gate 		    KM_SLEEP : KM_NOSLEEP)) == NULL)
1938*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_NO_MEMORY);
1939*7c478bd9Sstevel@tonic-gate 
1940*7c478bd9Sstevel@tonic-gate 		*(caddr_t *)valuep = buffer;	/* set callers buf ptr */
1941*7c478bd9Sstevel@tonic-gate 		break;
1942*7c478bd9Sstevel@tonic-gate 
1943*7c478bd9Sstevel@tonic-gate 	case PROP_LEN_AND_VAL_BUF:
1944*7c478bd9Sstevel@tonic-gate 		buffer = valuep;		/* get callers buf ptr */
1945*7c478bd9Sstevel@tonic-gate 		break;
1946*7c478bd9Sstevel@tonic-gate 
1947*7c478bd9Sstevel@tonic-gate 	default:
1948*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
1949*7c478bd9Sstevel@tonic-gate 	}
1950*7c478bd9Sstevel@tonic-gate 
1951*7c478bd9Sstevel@tonic-gate 	/* transfer the value into the buffer */
1952*7c478bd9Sstevel@tonic-gate 	if (strcmp(name, "Nblocks") == 0)
1953*7c478bd9Sstevel@tonic-gate 		*((uint64_t *)buffer) = nblocks64;
1954*7c478bd9Sstevel@tonic-gate 	else if (strcmp(name, "Size") == 0)
1955*7c478bd9Sstevel@tonic-gate 		*((uint64_t *)buffer) = size64;
1956*7c478bd9Sstevel@tonic-gate 	else if (strcmp(name, "nblocks") == 0)
1957*7c478bd9Sstevel@tonic-gate 		*((uint32_t *)buffer) = (uint32_t)nblocks64;
1958*7c478bd9Sstevel@tonic-gate 	else if (strcmp(name, "size") == 0)
1959*7c478bd9Sstevel@tonic-gate 		*((uint32_t *)buffer) = (uint32_t)size64;
1960*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
1961*7c478bd9Sstevel@tonic-gate }
1962*7c478bd9Sstevel@tonic-gate 
1963*7c478bd9Sstevel@tonic-gate /*
1964*7c478bd9Sstevel@tonic-gate  * Variable length props...
1965*7c478bd9Sstevel@tonic-gate  */
1966*7c478bd9Sstevel@tonic-gate 
1967*7c478bd9Sstevel@tonic-gate /*
1968*7c478bd9Sstevel@tonic-gate  * ddi_getlongprop:	Get variable length property len+val into a buffer
1969*7c478bd9Sstevel@tonic-gate  *		allocated by property provider via kmem_alloc. Requester
1970*7c478bd9Sstevel@tonic-gate  *		is responsible for freeing returned property via kmem_free.
1971*7c478bd9Sstevel@tonic-gate  *
1972*7c478bd9Sstevel@tonic-gate  *	Arguments:
1973*7c478bd9Sstevel@tonic-gate  *
1974*7c478bd9Sstevel@tonic-gate  *	dev_t:	Input:	dev_t of property.
1975*7c478bd9Sstevel@tonic-gate  *	dip:	Input:	dev_info_t pointer of child.
1976*7c478bd9Sstevel@tonic-gate  *	flags:	Input:	Possible flag modifiers are:
1977*7c478bd9Sstevel@tonic-gate  *		DDI_PROP_DONTPASS:	Don't pass to parent if prop not found.
1978*7c478bd9Sstevel@tonic-gate  *		DDI_PROP_CANSLEEP:	Memory allocation may sleep.
1979*7c478bd9Sstevel@tonic-gate  *	name:	Input:	name of property.
1980*7c478bd9Sstevel@tonic-gate  *	valuep:	Output:	Addr of callers buffer pointer.
1981*7c478bd9Sstevel@tonic-gate  *	lengthp:Output:	*lengthp will contain prop length on exit.
1982*7c478bd9Sstevel@tonic-gate  *
1983*7c478bd9Sstevel@tonic-gate  *	Possible Returns:
1984*7c478bd9Sstevel@tonic-gate  *
1985*7c478bd9Sstevel@tonic-gate  *		DDI_PROP_SUCCESS:	Prop found and returned.
1986*7c478bd9Sstevel@tonic-gate  *		DDI_PROP_NOT_FOUND:	Prop not found
1987*7c478bd9Sstevel@tonic-gate  *		DDI_PROP_UNDEFINED:	Prop explicitly undefined.
1988*7c478bd9Sstevel@tonic-gate  *		DDI_PROP_NO_MEMORY:	Prop found, but unable to alloc mem.
1989*7c478bd9Sstevel@tonic-gate  */
1990*7c478bd9Sstevel@tonic-gate 
1991*7c478bd9Sstevel@tonic-gate int
1992*7c478bd9Sstevel@tonic-gate ddi_getlongprop(dev_t dev, dev_info_t *dip, int flags,
1993*7c478bd9Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
1994*7c478bd9Sstevel@tonic-gate {
1995*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_op(dev, dip, PROP_LEN_AND_VAL_ALLOC,
1996*7c478bd9Sstevel@tonic-gate 	    flags, name, valuep, lengthp));
1997*7c478bd9Sstevel@tonic-gate }
1998*7c478bd9Sstevel@tonic-gate 
1999*7c478bd9Sstevel@tonic-gate /*
2000*7c478bd9Sstevel@tonic-gate  *
2001*7c478bd9Sstevel@tonic-gate  * ddi_getlongprop_buf:		Get long prop into pre-allocated callers
2002*7c478bd9Sstevel@tonic-gate  *				buffer. (no memory allocation by provider).
2003*7c478bd9Sstevel@tonic-gate  *
2004*7c478bd9Sstevel@tonic-gate  *	dev_t:	Input:	dev_t of property.
2005*7c478bd9Sstevel@tonic-gate  *	dip:	Input:	dev_info_t pointer of child.
2006*7c478bd9Sstevel@tonic-gate  *	flags:	Input:	DDI_PROP_DONTPASS or NULL
2007*7c478bd9Sstevel@tonic-gate  *	name:	Input:	name of property
2008*7c478bd9Sstevel@tonic-gate  *	valuep:	Input:	ptr to callers buffer.
2009*7c478bd9Sstevel@tonic-gate  *	lengthp:I/O:	ptr to length of callers buffer on entry,
2010*7c478bd9Sstevel@tonic-gate  *			actual length of property on exit.
2011*7c478bd9Sstevel@tonic-gate  *
2012*7c478bd9Sstevel@tonic-gate  *	Possible returns:
2013*7c478bd9Sstevel@tonic-gate  *
2014*7c478bd9Sstevel@tonic-gate  *		DDI_PROP_SUCCESS	Prop found and returned
2015*7c478bd9Sstevel@tonic-gate  *		DDI_PROP_NOT_FOUND	Prop not found
2016*7c478bd9Sstevel@tonic-gate  *		DDI_PROP_UNDEFINED	Prop explicitly undefined.
2017*7c478bd9Sstevel@tonic-gate  *		DDI_PROP_BUF_TOO_SMALL	Prop found, callers buf too small,
2018*7c478bd9Sstevel@tonic-gate  *					no value returned, but actual prop
2019*7c478bd9Sstevel@tonic-gate  *					length returned in *lengthp
2020*7c478bd9Sstevel@tonic-gate  *
2021*7c478bd9Sstevel@tonic-gate  */
2022*7c478bd9Sstevel@tonic-gate 
2023*7c478bd9Sstevel@tonic-gate int
2024*7c478bd9Sstevel@tonic-gate ddi_getlongprop_buf(dev_t dev, dev_info_t *dip, int flags,
2025*7c478bd9Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
2026*7c478bd9Sstevel@tonic-gate {
2027*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
2028*7c478bd9Sstevel@tonic-gate 	    flags, name, valuep, lengthp));
2029*7c478bd9Sstevel@tonic-gate }
2030*7c478bd9Sstevel@tonic-gate 
2031*7c478bd9Sstevel@tonic-gate /*
2032*7c478bd9Sstevel@tonic-gate  * Integer/boolean sized props.
2033*7c478bd9Sstevel@tonic-gate  *
2034*7c478bd9Sstevel@tonic-gate  * Call is value only... returns found boolean or int sized prop value or
2035*7c478bd9Sstevel@tonic-gate  * defvalue if prop not found or is wrong length or is explicitly undefined.
2036*7c478bd9Sstevel@tonic-gate  * Only flag is DDI_PROP_DONTPASS...
2037*7c478bd9Sstevel@tonic-gate  *
2038*7c478bd9Sstevel@tonic-gate  * By convention, this interface returns boolean (0) sized properties
2039*7c478bd9Sstevel@tonic-gate  * as value (int)1.
2040*7c478bd9Sstevel@tonic-gate  *
2041*7c478bd9Sstevel@tonic-gate  * This never returns an error, if property not found or specifically
2042*7c478bd9Sstevel@tonic-gate  * undefined, the input `defvalue' is returned.
2043*7c478bd9Sstevel@tonic-gate  */
2044*7c478bd9Sstevel@tonic-gate 
2045*7c478bd9Sstevel@tonic-gate int
2046*7c478bd9Sstevel@tonic-gate ddi_getprop(dev_t dev, dev_info_t *dip, int flags, char *name, int defvalue)
2047*7c478bd9Sstevel@tonic-gate {
2048*7c478bd9Sstevel@tonic-gate 	int	propvalue = defvalue;
2049*7c478bd9Sstevel@tonic-gate 	int	proplength = sizeof (int);
2050*7c478bd9Sstevel@tonic-gate 	int	error;
2051*7c478bd9Sstevel@tonic-gate 
2052*7c478bd9Sstevel@tonic-gate 	error = ddi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
2053*7c478bd9Sstevel@tonic-gate 	    flags, name, (caddr_t)&propvalue, &proplength);
2054*7c478bd9Sstevel@tonic-gate 
2055*7c478bd9Sstevel@tonic-gate 	if ((error == DDI_PROP_SUCCESS) && (proplength == 0))
2056*7c478bd9Sstevel@tonic-gate 		propvalue = 1;
2057*7c478bd9Sstevel@tonic-gate 
2058*7c478bd9Sstevel@tonic-gate 	return (propvalue);
2059*7c478bd9Sstevel@tonic-gate }
2060*7c478bd9Sstevel@tonic-gate 
2061*7c478bd9Sstevel@tonic-gate /*
2062*7c478bd9Sstevel@tonic-gate  * Get prop length interface: flags are 0 or DDI_PROP_DONTPASS
2063*7c478bd9Sstevel@tonic-gate  * if returns DDI_PROP_SUCCESS, length returned in *lengthp.
2064*7c478bd9Sstevel@tonic-gate  */
2065*7c478bd9Sstevel@tonic-gate 
2066*7c478bd9Sstevel@tonic-gate int
2067*7c478bd9Sstevel@tonic-gate ddi_getproplen(dev_t dev, dev_info_t *dip, int flags, char *name, int *lengthp)
2068*7c478bd9Sstevel@tonic-gate {
2069*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_op(dev, dip, PROP_LEN, flags, name, NULL, lengthp));
2070*7c478bd9Sstevel@tonic-gate }
2071*7c478bd9Sstevel@tonic-gate 
2072*7c478bd9Sstevel@tonic-gate /*
2073*7c478bd9Sstevel@tonic-gate  * Allocate a struct prop_driver_data, along with 'size' bytes
2074*7c478bd9Sstevel@tonic-gate  * for decoded property data.  This structure is freed by
2075*7c478bd9Sstevel@tonic-gate  * calling ddi_prop_free(9F).
2076*7c478bd9Sstevel@tonic-gate  */
2077*7c478bd9Sstevel@tonic-gate static void *
2078*7c478bd9Sstevel@tonic-gate ddi_prop_decode_alloc(size_t size, void (*prop_free)(struct prop_driver_data *))
2079*7c478bd9Sstevel@tonic-gate {
2080*7c478bd9Sstevel@tonic-gate 	struct prop_driver_data *pdd;
2081*7c478bd9Sstevel@tonic-gate 
2082*7c478bd9Sstevel@tonic-gate 	/*
2083*7c478bd9Sstevel@tonic-gate 	 * Allocate a structure with enough memory to store the decoded data.
2084*7c478bd9Sstevel@tonic-gate 	 */
2085*7c478bd9Sstevel@tonic-gate 	pdd = kmem_zalloc(sizeof (struct prop_driver_data) + size, KM_SLEEP);
2086*7c478bd9Sstevel@tonic-gate 	pdd->pdd_size = (sizeof (struct prop_driver_data) + size);
2087*7c478bd9Sstevel@tonic-gate 	pdd->pdd_prop_free = prop_free;
2088*7c478bd9Sstevel@tonic-gate 
2089*7c478bd9Sstevel@tonic-gate 	/*
2090*7c478bd9Sstevel@tonic-gate 	 * Return a pointer to the location to put the decoded data.
2091*7c478bd9Sstevel@tonic-gate 	 */
2092*7c478bd9Sstevel@tonic-gate 	return ((void *)((caddr_t)pdd + sizeof (struct prop_driver_data)));
2093*7c478bd9Sstevel@tonic-gate }
2094*7c478bd9Sstevel@tonic-gate 
2095*7c478bd9Sstevel@tonic-gate /*
2096*7c478bd9Sstevel@tonic-gate  * Allocated the memory needed to store the encoded data in the property
2097*7c478bd9Sstevel@tonic-gate  * handle.
2098*7c478bd9Sstevel@tonic-gate  */
2099*7c478bd9Sstevel@tonic-gate static int
2100*7c478bd9Sstevel@tonic-gate ddi_prop_encode_alloc(prop_handle_t *ph, size_t size)
2101*7c478bd9Sstevel@tonic-gate {
2102*7c478bd9Sstevel@tonic-gate 	/*
2103*7c478bd9Sstevel@tonic-gate 	 * If size is zero, then set data to NULL and size to 0.  This
2104*7c478bd9Sstevel@tonic-gate 	 * is a boolean property.
2105*7c478bd9Sstevel@tonic-gate 	 */
2106*7c478bd9Sstevel@tonic-gate 	if (size == 0) {
2107*7c478bd9Sstevel@tonic-gate 		ph->ph_size = 0;
2108*7c478bd9Sstevel@tonic-gate 		ph->ph_data = NULL;
2109*7c478bd9Sstevel@tonic-gate 		ph->ph_cur_pos = NULL;
2110*7c478bd9Sstevel@tonic-gate 		ph->ph_save_pos = NULL;
2111*7c478bd9Sstevel@tonic-gate 	} else {
2112*7c478bd9Sstevel@tonic-gate 		if (ph->ph_flags == DDI_PROP_DONTSLEEP) {
2113*7c478bd9Sstevel@tonic-gate 			ph->ph_data = kmem_zalloc(size, KM_NOSLEEP);
2114*7c478bd9Sstevel@tonic-gate 			if (ph->ph_data == NULL)
2115*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_NO_MEMORY);
2116*7c478bd9Sstevel@tonic-gate 		} else
2117*7c478bd9Sstevel@tonic-gate 			ph->ph_data = kmem_zalloc(size, KM_SLEEP);
2118*7c478bd9Sstevel@tonic-gate 		ph->ph_size = size;
2119*7c478bd9Sstevel@tonic-gate 		ph->ph_cur_pos = ph->ph_data;
2120*7c478bd9Sstevel@tonic-gate 		ph->ph_save_pos = ph->ph_data;
2121*7c478bd9Sstevel@tonic-gate 	}
2122*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
2123*7c478bd9Sstevel@tonic-gate }
2124*7c478bd9Sstevel@tonic-gate 
2125*7c478bd9Sstevel@tonic-gate /*
2126*7c478bd9Sstevel@tonic-gate  * Free the space allocated by the lookup routines.  Each lookup routine
2127*7c478bd9Sstevel@tonic-gate  * returns a pointer to the decoded data to the driver.  The driver then
2128*7c478bd9Sstevel@tonic-gate  * passes this pointer back to us.  This data actually lives in a struct
2129*7c478bd9Sstevel@tonic-gate  * prop_driver_data.  We use negative indexing to find the beginning of
2130*7c478bd9Sstevel@tonic-gate  * the structure and then free the entire structure using the size and
2131*7c478bd9Sstevel@tonic-gate  * the free routine stored in the structure.
2132*7c478bd9Sstevel@tonic-gate  */
2133*7c478bd9Sstevel@tonic-gate void
2134*7c478bd9Sstevel@tonic-gate ddi_prop_free(void *datap)
2135*7c478bd9Sstevel@tonic-gate {
2136*7c478bd9Sstevel@tonic-gate 	struct prop_driver_data *pdd;
2137*7c478bd9Sstevel@tonic-gate 
2138*7c478bd9Sstevel@tonic-gate 	/*
2139*7c478bd9Sstevel@tonic-gate 	 * Get the structure
2140*7c478bd9Sstevel@tonic-gate 	 */
2141*7c478bd9Sstevel@tonic-gate 	pdd = (struct prop_driver_data *)
2142*7c478bd9Sstevel@tonic-gate 		((caddr_t)datap - sizeof (struct prop_driver_data));
2143*7c478bd9Sstevel@tonic-gate 	/*
2144*7c478bd9Sstevel@tonic-gate 	 * Call the free routine to free it
2145*7c478bd9Sstevel@tonic-gate 	 */
2146*7c478bd9Sstevel@tonic-gate 	(*pdd->pdd_prop_free)(pdd);
2147*7c478bd9Sstevel@tonic-gate }
2148*7c478bd9Sstevel@tonic-gate 
2149*7c478bd9Sstevel@tonic-gate /*
2150*7c478bd9Sstevel@tonic-gate  * Free the data associated with an array of ints,
2151*7c478bd9Sstevel@tonic-gate  * allocated with ddi_prop_decode_alloc().
2152*7c478bd9Sstevel@tonic-gate  */
2153*7c478bd9Sstevel@tonic-gate static void
2154*7c478bd9Sstevel@tonic-gate ddi_prop_free_ints(struct prop_driver_data *pdd)
2155*7c478bd9Sstevel@tonic-gate {
2156*7c478bd9Sstevel@tonic-gate 	kmem_free(pdd, pdd->pdd_size);
2157*7c478bd9Sstevel@tonic-gate }
2158*7c478bd9Sstevel@tonic-gate 
2159*7c478bd9Sstevel@tonic-gate /*
2160*7c478bd9Sstevel@tonic-gate  * Free a single string property or a single string contained within
2161*7c478bd9Sstevel@tonic-gate  * the argv style return value of an array of strings.
2162*7c478bd9Sstevel@tonic-gate  */
2163*7c478bd9Sstevel@tonic-gate static void
2164*7c478bd9Sstevel@tonic-gate ddi_prop_free_string(struct prop_driver_data *pdd)
2165*7c478bd9Sstevel@tonic-gate {
2166*7c478bd9Sstevel@tonic-gate 	kmem_free(pdd, pdd->pdd_size);
2167*7c478bd9Sstevel@tonic-gate 
2168*7c478bd9Sstevel@tonic-gate }
2169*7c478bd9Sstevel@tonic-gate 
2170*7c478bd9Sstevel@tonic-gate /*
2171*7c478bd9Sstevel@tonic-gate  * Free an array of strings.
2172*7c478bd9Sstevel@tonic-gate  */
2173*7c478bd9Sstevel@tonic-gate static void
2174*7c478bd9Sstevel@tonic-gate ddi_prop_free_strings(struct prop_driver_data *pdd)
2175*7c478bd9Sstevel@tonic-gate {
2176*7c478bd9Sstevel@tonic-gate 	kmem_free(pdd, pdd->pdd_size);
2177*7c478bd9Sstevel@tonic-gate }
2178*7c478bd9Sstevel@tonic-gate 
2179*7c478bd9Sstevel@tonic-gate /*
2180*7c478bd9Sstevel@tonic-gate  * Free the data associated with an array of bytes.
2181*7c478bd9Sstevel@tonic-gate  */
2182*7c478bd9Sstevel@tonic-gate static void
2183*7c478bd9Sstevel@tonic-gate ddi_prop_free_bytes(struct prop_driver_data *pdd)
2184*7c478bd9Sstevel@tonic-gate {
2185*7c478bd9Sstevel@tonic-gate 	kmem_free(pdd, pdd->pdd_size);
2186*7c478bd9Sstevel@tonic-gate }
2187*7c478bd9Sstevel@tonic-gate 
2188*7c478bd9Sstevel@tonic-gate /*
2189*7c478bd9Sstevel@tonic-gate  * Reset the current location pointer in the property handle to the
2190*7c478bd9Sstevel@tonic-gate  * beginning of the data.
2191*7c478bd9Sstevel@tonic-gate  */
2192*7c478bd9Sstevel@tonic-gate void
2193*7c478bd9Sstevel@tonic-gate ddi_prop_reset_pos(prop_handle_t *ph)
2194*7c478bd9Sstevel@tonic-gate {
2195*7c478bd9Sstevel@tonic-gate 	ph->ph_cur_pos = ph->ph_data;
2196*7c478bd9Sstevel@tonic-gate 	ph->ph_save_pos = ph->ph_data;
2197*7c478bd9Sstevel@tonic-gate }
2198*7c478bd9Sstevel@tonic-gate 
2199*7c478bd9Sstevel@tonic-gate /*
2200*7c478bd9Sstevel@tonic-gate  * Restore the current location pointer in the property handle to the
2201*7c478bd9Sstevel@tonic-gate  * saved position.
2202*7c478bd9Sstevel@tonic-gate  */
2203*7c478bd9Sstevel@tonic-gate void
2204*7c478bd9Sstevel@tonic-gate ddi_prop_save_pos(prop_handle_t *ph)
2205*7c478bd9Sstevel@tonic-gate {
2206*7c478bd9Sstevel@tonic-gate 	ph->ph_save_pos = ph->ph_cur_pos;
2207*7c478bd9Sstevel@tonic-gate }
2208*7c478bd9Sstevel@tonic-gate 
2209*7c478bd9Sstevel@tonic-gate /*
2210*7c478bd9Sstevel@tonic-gate  * Save the location that the current location pointer is pointing to..
2211*7c478bd9Sstevel@tonic-gate  */
2212*7c478bd9Sstevel@tonic-gate void
2213*7c478bd9Sstevel@tonic-gate ddi_prop_restore_pos(prop_handle_t *ph)
2214*7c478bd9Sstevel@tonic-gate {
2215*7c478bd9Sstevel@tonic-gate 	ph->ph_cur_pos = ph->ph_save_pos;
2216*7c478bd9Sstevel@tonic-gate }
2217*7c478bd9Sstevel@tonic-gate 
2218*7c478bd9Sstevel@tonic-gate /*
2219*7c478bd9Sstevel@tonic-gate  * Property encode/decode functions
2220*7c478bd9Sstevel@tonic-gate  */
2221*7c478bd9Sstevel@tonic-gate 
2222*7c478bd9Sstevel@tonic-gate /*
2223*7c478bd9Sstevel@tonic-gate  * Decode a single integer property
2224*7c478bd9Sstevel@tonic-gate  */
2225*7c478bd9Sstevel@tonic-gate static int
2226*7c478bd9Sstevel@tonic-gate ddi_prop_fm_decode_int(prop_handle_t *ph, void *data, uint_t *nelements)
2227*7c478bd9Sstevel@tonic-gate {
2228*7c478bd9Sstevel@tonic-gate 	int	i;
2229*7c478bd9Sstevel@tonic-gate 	int	tmp;
2230*7c478bd9Sstevel@tonic-gate 
2231*7c478bd9Sstevel@tonic-gate 	/*
2232*7c478bd9Sstevel@tonic-gate 	 * If there is nothing to decode return an error
2233*7c478bd9Sstevel@tonic-gate 	 */
2234*7c478bd9Sstevel@tonic-gate 	if (ph->ph_size == 0)
2235*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
2236*7c478bd9Sstevel@tonic-gate 
2237*7c478bd9Sstevel@tonic-gate 	/*
2238*7c478bd9Sstevel@tonic-gate 	 * Decode the property as a single integer and return it
2239*7c478bd9Sstevel@tonic-gate 	 * in data if we were able to decode it.
2240*7c478bd9Sstevel@tonic-gate 	 */
2241*7c478bd9Sstevel@tonic-gate 	i = DDI_PROP_INT(ph, DDI_PROP_CMD_DECODE, &tmp);
2242*7c478bd9Sstevel@tonic-gate 	if (i < DDI_PROP_RESULT_OK) {
2243*7c478bd9Sstevel@tonic-gate 		switch (i) {
2244*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
2245*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
2246*7c478bd9Sstevel@tonic-gate 
2247*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
2248*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
2249*7c478bd9Sstevel@tonic-gate 		}
2250*7c478bd9Sstevel@tonic-gate 	}
2251*7c478bd9Sstevel@tonic-gate 
2252*7c478bd9Sstevel@tonic-gate 	*(int *)data = tmp;
2253*7c478bd9Sstevel@tonic-gate 	*nelements = 1;
2254*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
2255*7c478bd9Sstevel@tonic-gate }
2256*7c478bd9Sstevel@tonic-gate 
2257*7c478bd9Sstevel@tonic-gate /*
2258*7c478bd9Sstevel@tonic-gate  * Decode a single 64 bit integer property
2259*7c478bd9Sstevel@tonic-gate  */
2260*7c478bd9Sstevel@tonic-gate static int
2261*7c478bd9Sstevel@tonic-gate ddi_prop_fm_decode_int64(prop_handle_t *ph, void *data, uint_t *nelements)
2262*7c478bd9Sstevel@tonic-gate {
2263*7c478bd9Sstevel@tonic-gate 	int	i;
2264*7c478bd9Sstevel@tonic-gate 	int64_t	tmp;
2265*7c478bd9Sstevel@tonic-gate 
2266*7c478bd9Sstevel@tonic-gate 	/*
2267*7c478bd9Sstevel@tonic-gate 	 * If there is nothing to decode return an error
2268*7c478bd9Sstevel@tonic-gate 	 */
2269*7c478bd9Sstevel@tonic-gate 	if (ph->ph_size == 0)
2270*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
2271*7c478bd9Sstevel@tonic-gate 
2272*7c478bd9Sstevel@tonic-gate 	/*
2273*7c478bd9Sstevel@tonic-gate 	 * Decode the property as a single integer and return it
2274*7c478bd9Sstevel@tonic-gate 	 * in data if we were able to decode it.
2275*7c478bd9Sstevel@tonic-gate 	 */
2276*7c478bd9Sstevel@tonic-gate 	i = DDI_PROP_INT64(ph, DDI_PROP_CMD_DECODE, &tmp);
2277*7c478bd9Sstevel@tonic-gate 	if (i < DDI_PROP_RESULT_OK) {
2278*7c478bd9Sstevel@tonic-gate 		switch (i) {
2279*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
2280*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
2281*7c478bd9Sstevel@tonic-gate 
2282*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
2283*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
2284*7c478bd9Sstevel@tonic-gate 		}
2285*7c478bd9Sstevel@tonic-gate 	}
2286*7c478bd9Sstevel@tonic-gate 
2287*7c478bd9Sstevel@tonic-gate 	*(int64_t *)data = tmp;
2288*7c478bd9Sstevel@tonic-gate 	*nelements = 1;
2289*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
2290*7c478bd9Sstevel@tonic-gate }
2291*7c478bd9Sstevel@tonic-gate 
2292*7c478bd9Sstevel@tonic-gate /*
2293*7c478bd9Sstevel@tonic-gate  * Decode an array of integers property
2294*7c478bd9Sstevel@tonic-gate  */
2295*7c478bd9Sstevel@tonic-gate static int
2296*7c478bd9Sstevel@tonic-gate ddi_prop_fm_decode_ints(prop_handle_t *ph, void *data, uint_t *nelements)
2297*7c478bd9Sstevel@tonic-gate {
2298*7c478bd9Sstevel@tonic-gate 	int	i;
2299*7c478bd9Sstevel@tonic-gate 	int	cnt = 0;
2300*7c478bd9Sstevel@tonic-gate 	int	*tmp;
2301*7c478bd9Sstevel@tonic-gate 	int	*intp;
2302*7c478bd9Sstevel@tonic-gate 	int	n;
2303*7c478bd9Sstevel@tonic-gate 
2304*7c478bd9Sstevel@tonic-gate 	/*
2305*7c478bd9Sstevel@tonic-gate 	 * Figure out how many array elements there are by going through the
2306*7c478bd9Sstevel@tonic-gate 	 * data without decoding it first and counting.
2307*7c478bd9Sstevel@tonic-gate 	 */
2308*7c478bd9Sstevel@tonic-gate 	for (;;) {
2309*7c478bd9Sstevel@tonic-gate 		i = DDI_PROP_INT(ph, DDI_PROP_CMD_SKIP, NULL);
2310*7c478bd9Sstevel@tonic-gate 		if (i < 0)
2311*7c478bd9Sstevel@tonic-gate 			break;
2312*7c478bd9Sstevel@tonic-gate 		cnt++;
2313*7c478bd9Sstevel@tonic-gate 	}
2314*7c478bd9Sstevel@tonic-gate 
2315*7c478bd9Sstevel@tonic-gate 	/*
2316*7c478bd9Sstevel@tonic-gate 	 * If there are no elements return an error
2317*7c478bd9Sstevel@tonic-gate 	 */
2318*7c478bd9Sstevel@tonic-gate 	if (cnt == 0)
2319*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
2320*7c478bd9Sstevel@tonic-gate 
2321*7c478bd9Sstevel@tonic-gate 	/*
2322*7c478bd9Sstevel@tonic-gate 	 * If we cannot skip through the data, we cannot decode it
2323*7c478bd9Sstevel@tonic-gate 	 */
2324*7c478bd9Sstevel@tonic-gate 	if (i == DDI_PROP_RESULT_ERROR)
2325*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_DECODE);
2326*7c478bd9Sstevel@tonic-gate 
2327*7c478bd9Sstevel@tonic-gate 	/*
2328*7c478bd9Sstevel@tonic-gate 	 * Reset the data pointer to the beginning of the encoded data
2329*7c478bd9Sstevel@tonic-gate 	 */
2330*7c478bd9Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
2331*7c478bd9Sstevel@tonic-gate 
2332*7c478bd9Sstevel@tonic-gate 	/*
2333*7c478bd9Sstevel@tonic-gate 	 * Allocated memory to store the decoded value in.
2334*7c478bd9Sstevel@tonic-gate 	 */
2335*7c478bd9Sstevel@tonic-gate 	intp = ddi_prop_decode_alloc((cnt * sizeof (int)),
2336*7c478bd9Sstevel@tonic-gate 		ddi_prop_free_ints);
2337*7c478bd9Sstevel@tonic-gate 
2338*7c478bd9Sstevel@tonic-gate 	/*
2339*7c478bd9Sstevel@tonic-gate 	 * Decode each element and place it in the space we just allocated
2340*7c478bd9Sstevel@tonic-gate 	 */
2341*7c478bd9Sstevel@tonic-gate 	tmp = intp;
2342*7c478bd9Sstevel@tonic-gate 	for (n = 0; n < cnt; n++, tmp++) {
2343*7c478bd9Sstevel@tonic-gate 		i = DDI_PROP_INT(ph, DDI_PROP_CMD_DECODE, tmp);
2344*7c478bd9Sstevel@tonic-gate 		if (i < DDI_PROP_RESULT_OK) {
2345*7c478bd9Sstevel@tonic-gate 			/*
2346*7c478bd9Sstevel@tonic-gate 			 * Free the space we just allocated
2347*7c478bd9Sstevel@tonic-gate 			 * and return an error.
2348*7c478bd9Sstevel@tonic-gate 			 */
2349*7c478bd9Sstevel@tonic-gate 			ddi_prop_free(intp);
2350*7c478bd9Sstevel@tonic-gate 			switch (i) {
2351*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
2352*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
2353*7c478bd9Sstevel@tonic-gate 
2354*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
2355*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_DECODE);
2356*7c478bd9Sstevel@tonic-gate 			}
2357*7c478bd9Sstevel@tonic-gate 		}
2358*7c478bd9Sstevel@tonic-gate 	}
2359*7c478bd9Sstevel@tonic-gate 
2360*7c478bd9Sstevel@tonic-gate 	*nelements = cnt;
2361*7c478bd9Sstevel@tonic-gate 	*(int **)data = intp;
2362*7c478bd9Sstevel@tonic-gate 
2363*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
2364*7c478bd9Sstevel@tonic-gate }
2365*7c478bd9Sstevel@tonic-gate 
2366*7c478bd9Sstevel@tonic-gate /*
2367*7c478bd9Sstevel@tonic-gate  * Decode a 64 bit integer array property
2368*7c478bd9Sstevel@tonic-gate  */
2369*7c478bd9Sstevel@tonic-gate static int
2370*7c478bd9Sstevel@tonic-gate ddi_prop_fm_decode_int64_array(prop_handle_t *ph, void *data, uint_t *nelements)
2371*7c478bd9Sstevel@tonic-gate {
2372*7c478bd9Sstevel@tonic-gate 	int	i;
2373*7c478bd9Sstevel@tonic-gate 	int	n;
2374*7c478bd9Sstevel@tonic-gate 	int	cnt = 0;
2375*7c478bd9Sstevel@tonic-gate 	int64_t	*tmp;
2376*7c478bd9Sstevel@tonic-gate 	int64_t	*intp;
2377*7c478bd9Sstevel@tonic-gate 
2378*7c478bd9Sstevel@tonic-gate 	/*
2379*7c478bd9Sstevel@tonic-gate 	 * Count the number of array elements by going
2380*7c478bd9Sstevel@tonic-gate 	 * through the data without decoding it.
2381*7c478bd9Sstevel@tonic-gate 	 */
2382*7c478bd9Sstevel@tonic-gate 	for (;;) {
2383*7c478bd9Sstevel@tonic-gate 		i = DDI_PROP_INT64(ph, DDI_PROP_CMD_SKIP, NULL);
2384*7c478bd9Sstevel@tonic-gate 		if (i < 0)
2385*7c478bd9Sstevel@tonic-gate 			break;
2386*7c478bd9Sstevel@tonic-gate 		cnt++;
2387*7c478bd9Sstevel@tonic-gate 	}
2388*7c478bd9Sstevel@tonic-gate 
2389*7c478bd9Sstevel@tonic-gate 	/*
2390*7c478bd9Sstevel@tonic-gate 	 * If there are no elements return an error
2391*7c478bd9Sstevel@tonic-gate 	 */
2392*7c478bd9Sstevel@tonic-gate 	if (cnt == 0)
2393*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
2394*7c478bd9Sstevel@tonic-gate 
2395*7c478bd9Sstevel@tonic-gate 	/*
2396*7c478bd9Sstevel@tonic-gate 	 * If we cannot skip through the data, we cannot decode it
2397*7c478bd9Sstevel@tonic-gate 	 */
2398*7c478bd9Sstevel@tonic-gate 	if (i == DDI_PROP_RESULT_ERROR)
2399*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_DECODE);
2400*7c478bd9Sstevel@tonic-gate 
2401*7c478bd9Sstevel@tonic-gate 	/*
2402*7c478bd9Sstevel@tonic-gate 	 * Reset the data pointer to the beginning of the encoded data
2403*7c478bd9Sstevel@tonic-gate 	 */
2404*7c478bd9Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
2405*7c478bd9Sstevel@tonic-gate 
2406*7c478bd9Sstevel@tonic-gate 	/*
2407*7c478bd9Sstevel@tonic-gate 	 * Allocate memory to store the decoded value.
2408*7c478bd9Sstevel@tonic-gate 	 */
2409*7c478bd9Sstevel@tonic-gate 	intp = ddi_prop_decode_alloc((cnt * sizeof (int64_t)),
2410*7c478bd9Sstevel@tonic-gate 		ddi_prop_free_ints);
2411*7c478bd9Sstevel@tonic-gate 
2412*7c478bd9Sstevel@tonic-gate 	/*
2413*7c478bd9Sstevel@tonic-gate 	 * Decode each element and place it in the space allocated
2414*7c478bd9Sstevel@tonic-gate 	 */
2415*7c478bd9Sstevel@tonic-gate 	tmp = intp;
2416*7c478bd9Sstevel@tonic-gate 	for (n = 0; n < cnt; n++, tmp++) {
2417*7c478bd9Sstevel@tonic-gate 		i = DDI_PROP_INT64(ph, DDI_PROP_CMD_DECODE, tmp);
2418*7c478bd9Sstevel@tonic-gate 		if (i < DDI_PROP_RESULT_OK) {
2419*7c478bd9Sstevel@tonic-gate 			/*
2420*7c478bd9Sstevel@tonic-gate 			 * Free the space we just allocated
2421*7c478bd9Sstevel@tonic-gate 			 * and return an error.
2422*7c478bd9Sstevel@tonic-gate 			 */
2423*7c478bd9Sstevel@tonic-gate 			ddi_prop_free(intp);
2424*7c478bd9Sstevel@tonic-gate 			switch (i) {
2425*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
2426*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
2427*7c478bd9Sstevel@tonic-gate 
2428*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
2429*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_DECODE);
2430*7c478bd9Sstevel@tonic-gate 			}
2431*7c478bd9Sstevel@tonic-gate 		}
2432*7c478bd9Sstevel@tonic-gate 	}
2433*7c478bd9Sstevel@tonic-gate 
2434*7c478bd9Sstevel@tonic-gate 	*nelements = cnt;
2435*7c478bd9Sstevel@tonic-gate 	*(int64_t **)data = intp;
2436*7c478bd9Sstevel@tonic-gate 
2437*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
2438*7c478bd9Sstevel@tonic-gate }
2439*7c478bd9Sstevel@tonic-gate 
2440*7c478bd9Sstevel@tonic-gate /*
2441*7c478bd9Sstevel@tonic-gate  * Encode an array of integers property (Can be one element)
2442*7c478bd9Sstevel@tonic-gate  */
2443*7c478bd9Sstevel@tonic-gate int
2444*7c478bd9Sstevel@tonic-gate ddi_prop_fm_encode_ints(prop_handle_t *ph, void *data, uint_t nelements)
2445*7c478bd9Sstevel@tonic-gate {
2446*7c478bd9Sstevel@tonic-gate 	int	i;
2447*7c478bd9Sstevel@tonic-gate 	int	*tmp;
2448*7c478bd9Sstevel@tonic-gate 	int	cnt;
2449*7c478bd9Sstevel@tonic-gate 	int	size;
2450*7c478bd9Sstevel@tonic-gate 
2451*7c478bd9Sstevel@tonic-gate 	/*
2452*7c478bd9Sstevel@tonic-gate 	 * If there is no data, we cannot do anything
2453*7c478bd9Sstevel@tonic-gate 	 */
2454*7c478bd9Sstevel@tonic-gate 	if (nelements == 0)
2455*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_ENCODE);
2456*7c478bd9Sstevel@tonic-gate 
2457*7c478bd9Sstevel@tonic-gate 	/*
2458*7c478bd9Sstevel@tonic-gate 	 * Get the size of an encoded int.
2459*7c478bd9Sstevel@tonic-gate 	 */
2460*7c478bd9Sstevel@tonic-gate 	size = DDI_PROP_INT(ph, DDI_PROP_CMD_GET_ESIZE, NULL);
2461*7c478bd9Sstevel@tonic-gate 
2462*7c478bd9Sstevel@tonic-gate 	if (size < DDI_PROP_RESULT_OK) {
2463*7c478bd9Sstevel@tonic-gate 		switch (size) {
2464*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
2465*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
2466*7c478bd9Sstevel@tonic-gate 
2467*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
2468*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_ENCODE);
2469*7c478bd9Sstevel@tonic-gate 		}
2470*7c478bd9Sstevel@tonic-gate 	}
2471*7c478bd9Sstevel@tonic-gate 
2472*7c478bd9Sstevel@tonic-gate 	/*
2473*7c478bd9Sstevel@tonic-gate 	 * Allocate space in the handle to store the encoded int.
2474*7c478bd9Sstevel@tonic-gate 	 */
2475*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_encode_alloc(ph, size * nelements) !=
2476*7c478bd9Sstevel@tonic-gate 		DDI_PROP_SUCCESS)
2477*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
2478*7c478bd9Sstevel@tonic-gate 
2479*7c478bd9Sstevel@tonic-gate 	/*
2480*7c478bd9Sstevel@tonic-gate 	 * Encode the array of ints.
2481*7c478bd9Sstevel@tonic-gate 	 */
2482*7c478bd9Sstevel@tonic-gate 	tmp = (int *)data;
2483*7c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < nelements; cnt++, tmp++) {
2484*7c478bd9Sstevel@tonic-gate 		i = DDI_PROP_INT(ph, DDI_PROP_CMD_ENCODE, tmp);
2485*7c478bd9Sstevel@tonic-gate 		if (i < DDI_PROP_RESULT_OK) {
2486*7c478bd9Sstevel@tonic-gate 			switch (i) {
2487*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
2488*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
2489*7c478bd9Sstevel@tonic-gate 
2490*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
2491*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_ENCODE);
2492*7c478bd9Sstevel@tonic-gate 			}
2493*7c478bd9Sstevel@tonic-gate 		}
2494*7c478bd9Sstevel@tonic-gate 	}
2495*7c478bd9Sstevel@tonic-gate 
2496*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
2497*7c478bd9Sstevel@tonic-gate }
2498*7c478bd9Sstevel@tonic-gate 
2499*7c478bd9Sstevel@tonic-gate 
2500*7c478bd9Sstevel@tonic-gate /*
2501*7c478bd9Sstevel@tonic-gate  * Encode a 64 bit integer array property
2502*7c478bd9Sstevel@tonic-gate  */
2503*7c478bd9Sstevel@tonic-gate int
2504*7c478bd9Sstevel@tonic-gate ddi_prop_fm_encode_int64(prop_handle_t *ph, void *data, uint_t nelements)
2505*7c478bd9Sstevel@tonic-gate {
2506*7c478bd9Sstevel@tonic-gate 	int i;
2507*7c478bd9Sstevel@tonic-gate 	int cnt;
2508*7c478bd9Sstevel@tonic-gate 	int size;
2509*7c478bd9Sstevel@tonic-gate 	int64_t *tmp;
2510*7c478bd9Sstevel@tonic-gate 
2511*7c478bd9Sstevel@tonic-gate 	/*
2512*7c478bd9Sstevel@tonic-gate 	 * If there is no data, we cannot do anything
2513*7c478bd9Sstevel@tonic-gate 	 */
2514*7c478bd9Sstevel@tonic-gate 	if (nelements == 0)
2515*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_ENCODE);
2516*7c478bd9Sstevel@tonic-gate 
2517*7c478bd9Sstevel@tonic-gate 	/*
2518*7c478bd9Sstevel@tonic-gate 	 * Get the size of an encoded 64 bit int.
2519*7c478bd9Sstevel@tonic-gate 	 */
2520*7c478bd9Sstevel@tonic-gate 	size = DDI_PROP_INT64(ph, DDI_PROP_CMD_GET_ESIZE, NULL);
2521*7c478bd9Sstevel@tonic-gate 
2522*7c478bd9Sstevel@tonic-gate 	if (size < DDI_PROP_RESULT_OK) {
2523*7c478bd9Sstevel@tonic-gate 		switch (size) {
2524*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
2525*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
2526*7c478bd9Sstevel@tonic-gate 
2527*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
2528*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_ENCODE);
2529*7c478bd9Sstevel@tonic-gate 		}
2530*7c478bd9Sstevel@tonic-gate 	}
2531*7c478bd9Sstevel@tonic-gate 
2532*7c478bd9Sstevel@tonic-gate 	/*
2533*7c478bd9Sstevel@tonic-gate 	 * Allocate space in the handle to store the encoded int.
2534*7c478bd9Sstevel@tonic-gate 	 */
2535*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_encode_alloc(ph, size * nelements) !=
2536*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_SUCCESS)
2537*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
2538*7c478bd9Sstevel@tonic-gate 
2539*7c478bd9Sstevel@tonic-gate 	/*
2540*7c478bd9Sstevel@tonic-gate 	 * Encode the array of ints.
2541*7c478bd9Sstevel@tonic-gate 	 */
2542*7c478bd9Sstevel@tonic-gate 	tmp = (int64_t *)data;
2543*7c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < nelements; cnt++, tmp++) {
2544*7c478bd9Sstevel@tonic-gate 		i = DDI_PROP_INT64(ph, DDI_PROP_CMD_ENCODE, tmp);
2545*7c478bd9Sstevel@tonic-gate 		if (i < DDI_PROP_RESULT_OK) {
2546*7c478bd9Sstevel@tonic-gate 			switch (i) {
2547*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
2548*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
2549*7c478bd9Sstevel@tonic-gate 
2550*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
2551*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_ENCODE);
2552*7c478bd9Sstevel@tonic-gate 			}
2553*7c478bd9Sstevel@tonic-gate 		}
2554*7c478bd9Sstevel@tonic-gate 	}
2555*7c478bd9Sstevel@tonic-gate 
2556*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
2557*7c478bd9Sstevel@tonic-gate }
2558*7c478bd9Sstevel@tonic-gate 
2559*7c478bd9Sstevel@tonic-gate /*
2560*7c478bd9Sstevel@tonic-gate  * Decode a single string property
2561*7c478bd9Sstevel@tonic-gate  */
2562*7c478bd9Sstevel@tonic-gate static int
2563*7c478bd9Sstevel@tonic-gate ddi_prop_fm_decode_string(prop_handle_t *ph, void *data, uint_t *nelements)
2564*7c478bd9Sstevel@tonic-gate {
2565*7c478bd9Sstevel@tonic-gate 	char		*tmp;
2566*7c478bd9Sstevel@tonic-gate 	char		*str;
2567*7c478bd9Sstevel@tonic-gate 	int		i;
2568*7c478bd9Sstevel@tonic-gate 	int		size;
2569*7c478bd9Sstevel@tonic-gate 
2570*7c478bd9Sstevel@tonic-gate 	/*
2571*7c478bd9Sstevel@tonic-gate 	 * If there is nothing to decode return an error
2572*7c478bd9Sstevel@tonic-gate 	 */
2573*7c478bd9Sstevel@tonic-gate 	if (ph->ph_size == 0)
2574*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
2575*7c478bd9Sstevel@tonic-gate 
2576*7c478bd9Sstevel@tonic-gate 	/*
2577*7c478bd9Sstevel@tonic-gate 	 * Get the decoded size of the encoded string.
2578*7c478bd9Sstevel@tonic-gate 	 */
2579*7c478bd9Sstevel@tonic-gate 	size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
2580*7c478bd9Sstevel@tonic-gate 	if (size < DDI_PROP_RESULT_OK) {
2581*7c478bd9Sstevel@tonic-gate 		switch (size) {
2582*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
2583*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
2584*7c478bd9Sstevel@tonic-gate 
2585*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
2586*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
2587*7c478bd9Sstevel@tonic-gate 		}
2588*7c478bd9Sstevel@tonic-gate 	}
2589*7c478bd9Sstevel@tonic-gate 
2590*7c478bd9Sstevel@tonic-gate 	/*
2591*7c478bd9Sstevel@tonic-gate 	 * Allocated memory to store the decoded value in.
2592*7c478bd9Sstevel@tonic-gate 	 */
2593*7c478bd9Sstevel@tonic-gate 	str = ddi_prop_decode_alloc((size_t)size, ddi_prop_free_string);
2594*7c478bd9Sstevel@tonic-gate 
2595*7c478bd9Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
2596*7c478bd9Sstevel@tonic-gate 
2597*7c478bd9Sstevel@tonic-gate 	/*
2598*7c478bd9Sstevel@tonic-gate 	 * Decode the str and place it in the space we just allocated
2599*7c478bd9Sstevel@tonic-gate 	 */
2600*7c478bd9Sstevel@tonic-gate 	tmp = str;
2601*7c478bd9Sstevel@tonic-gate 	i = DDI_PROP_STR(ph, DDI_PROP_CMD_DECODE, tmp);
2602*7c478bd9Sstevel@tonic-gate 	if (i < DDI_PROP_RESULT_OK) {
2603*7c478bd9Sstevel@tonic-gate 		/*
2604*7c478bd9Sstevel@tonic-gate 		 * Free the space we just allocated
2605*7c478bd9Sstevel@tonic-gate 		 * and return an error.
2606*7c478bd9Sstevel@tonic-gate 		 */
2607*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(str);
2608*7c478bd9Sstevel@tonic-gate 		switch (i) {
2609*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
2610*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
2611*7c478bd9Sstevel@tonic-gate 
2612*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
2613*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
2614*7c478bd9Sstevel@tonic-gate 		}
2615*7c478bd9Sstevel@tonic-gate 	}
2616*7c478bd9Sstevel@tonic-gate 
2617*7c478bd9Sstevel@tonic-gate 	*(char **)data = str;
2618*7c478bd9Sstevel@tonic-gate 	*nelements = 1;
2619*7c478bd9Sstevel@tonic-gate 
2620*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
2621*7c478bd9Sstevel@tonic-gate }
2622*7c478bd9Sstevel@tonic-gate 
2623*7c478bd9Sstevel@tonic-gate /*
2624*7c478bd9Sstevel@tonic-gate  * Decode an array of strings.
2625*7c478bd9Sstevel@tonic-gate  */
2626*7c478bd9Sstevel@tonic-gate int
2627*7c478bd9Sstevel@tonic-gate ddi_prop_fm_decode_strings(prop_handle_t *ph, void *data, uint_t *nelements)
2628*7c478bd9Sstevel@tonic-gate {
2629*7c478bd9Sstevel@tonic-gate 	int		cnt = 0;
2630*7c478bd9Sstevel@tonic-gate 	char		**strs;
2631*7c478bd9Sstevel@tonic-gate 	char		**tmp;
2632*7c478bd9Sstevel@tonic-gate 	char		*ptr;
2633*7c478bd9Sstevel@tonic-gate 	int		i;
2634*7c478bd9Sstevel@tonic-gate 	int		n;
2635*7c478bd9Sstevel@tonic-gate 	int		size;
2636*7c478bd9Sstevel@tonic-gate 	size_t		nbytes;
2637*7c478bd9Sstevel@tonic-gate 
2638*7c478bd9Sstevel@tonic-gate 	/*
2639*7c478bd9Sstevel@tonic-gate 	 * Figure out how many array elements there are by going through the
2640*7c478bd9Sstevel@tonic-gate 	 * data without decoding it first and counting.
2641*7c478bd9Sstevel@tonic-gate 	 */
2642*7c478bd9Sstevel@tonic-gate 	for (;;) {
2643*7c478bd9Sstevel@tonic-gate 		i = DDI_PROP_STR(ph, DDI_PROP_CMD_SKIP, NULL);
2644*7c478bd9Sstevel@tonic-gate 		if (i < 0)
2645*7c478bd9Sstevel@tonic-gate 			break;
2646*7c478bd9Sstevel@tonic-gate 		cnt++;
2647*7c478bd9Sstevel@tonic-gate 	}
2648*7c478bd9Sstevel@tonic-gate 
2649*7c478bd9Sstevel@tonic-gate 	/*
2650*7c478bd9Sstevel@tonic-gate 	 * If there are no elements return an error
2651*7c478bd9Sstevel@tonic-gate 	 */
2652*7c478bd9Sstevel@tonic-gate 	if (cnt == 0)
2653*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
2654*7c478bd9Sstevel@tonic-gate 
2655*7c478bd9Sstevel@tonic-gate 	/*
2656*7c478bd9Sstevel@tonic-gate 	 * If we cannot skip through the data, we cannot decode it
2657*7c478bd9Sstevel@tonic-gate 	 */
2658*7c478bd9Sstevel@tonic-gate 	if (i == DDI_PROP_RESULT_ERROR)
2659*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_DECODE);
2660*7c478bd9Sstevel@tonic-gate 
2661*7c478bd9Sstevel@tonic-gate 	/*
2662*7c478bd9Sstevel@tonic-gate 	 * Reset the data pointer to the beginning of the encoded data
2663*7c478bd9Sstevel@tonic-gate 	 */
2664*7c478bd9Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
2665*7c478bd9Sstevel@tonic-gate 
2666*7c478bd9Sstevel@tonic-gate 	/*
2667*7c478bd9Sstevel@tonic-gate 	 * Figure out how much memory we need for the sum total
2668*7c478bd9Sstevel@tonic-gate 	 */
2669*7c478bd9Sstevel@tonic-gate 	nbytes = (cnt + 1) * sizeof (char *);
2670*7c478bd9Sstevel@tonic-gate 
2671*7c478bd9Sstevel@tonic-gate 	for (n = 0; n < cnt; n++) {
2672*7c478bd9Sstevel@tonic-gate 		/*
2673*7c478bd9Sstevel@tonic-gate 		 * Get the decoded size of the current encoded string.
2674*7c478bd9Sstevel@tonic-gate 		 */
2675*7c478bd9Sstevel@tonic-gate 		size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
2676*7c478bd9Sstevel@tonic-gate 		if (size < DDI_PROP_RESULT_OK) {
2677*7c478bd9Sstevel@tonic-gate 			switch (size) {
2678*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
2679*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
2680*7c478bd9Sstevel@tonic-gate 
2681*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
2682*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_DECODE);
2683*7c478bd9Sstevel@tonic-gate 			}
2684*7c478bd9Sstevel@tonic-gate 		}
2685*7c478bd9Sstevel@tonic-gate 
2686*7c478bd9Sstevel@tonic-gate 		nbytes += size;
2687*7c478bd9Sstevel@tonic-gate 	}
2688*7c478bd9Sstevel@tonic-gate 
2689*7c478bd9Sstevel@tonic-gate 	/*
2690*7c478bd9Sstevel@tonic-gate 	 * Allocate memory in which to store the decoded strings.
2691*7c478bd9Sstevel@tonic-gate 	 */
2692*7c478bd9Sstevel@tonic-gate 	strs = ddi_prop_decode_alloc(nbytes, ddi_prop_free_strings);
2693*7c478bd9Sstevel@tonic-gate 
2694*7c478bd9Sstevel@tonic-gate 	/*
2695*7c478bd9Sstevel@tonic-gate 	 * Set up pointers for each string by figuring out yet
2696*7c478bd9Sstevel@tonic-gate 	 * again how long each string is.
2697*7c478bd9Sstevel@tonic-gate 	 */
2698*7c478bd9Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
2699*7c478bd9Sstevel@tonic-gate 	ptr = (caddr_t)strs + ((cnt + 1) * sizeof (char *));
2700*7c478bd9Sstevel@tonic-gate 	for (tmp = strs, n = 0; n < cnt; n++, tmp++) {
2701*7c478bd9Sstevel@tonic-gate 		/*
2702*7c478bd9Sstevel@tonic-gate 		 * Get the decoded size of the current encoded string.
2703*7c478bd9Sstevel@tonic-gate 		 */
2704*7c478bd9Sstevel@tonic-gate 		size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
2705*7c478bd9Sstevel@tonic-gate 		if (size < DDI_PROP_RESULT_OK) {
2706*7c478bd9Sstevel@tonic-gate 			ddi_prop_free(strs);
2707*7c478bd9Sstevel@tonic-gate 			switch (size) {
2708*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
2709*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
2710*7c478bd9Sstevel@tonic-gate 
2711*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
2712*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_DECODE);
2713*7c478bd9Sstevel@tonic-gate 			}
2714*7c478bd9Sstevel@tonic-gate 		}
2715*7c478bd9Sstevel@tonic-gate 
2716*7c478bd9Sstevel@tonic-gate 		*tmp = ptr;
2717*7c478bd9Sstevel@tonic-gate 		ptr += size;
2718*7c478bd9Sstevel@tonic-gate 	}
2719*7c478bd9Sstevel@tonic-gate 
2720*7c478bd9Sstevel@tonic-gate 	/*
2721*7c478bd9Sstevel@tonic-gate 	 * String array is terminated by a NULL
2722*7c478bd9Sstevel@tonic-gate 	 */
2723*7c478bd9Sstevel@tonic-gate 	*tmp = NULL;
2724*7c478bd9Sstevel@tonic-gate 
2725*7c478bd9Sstevel@tonic-gate 	/*
2726*7c478bd9Sstevel@tonic-gate 	 * Finally, we can decode each string
2727*7c478bd9Sstevel@tonic-gate 	 */
2728*7c478bd9Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
2729*7c478bd9Sstevel@tonic-gate 	for (tmp = strs, n = 0; n < cnt; n++, tmp++) {
2730*7c478bd9Sstevel@tonic-gate 		i = DDI_PROP_STR(ph, DDI_PROP_CMD_DECODE, *tmp);
2731*7c478bd9Sstevel@tonic-gate 		if (i < DDI_PROP_RESULT_OK) {
2732*7c478bd9Sstevel@tonic-gate 			/*
2733*7c478bd9Sstevel@tonic-gate 			 * Free the space we just allocated
2734*7c478bd9Sstevel@tonic-gate 			 * and return an error
2735*7c478bd9Sstevel@tonic-gate 			 */
2736*7c478bd9Sstevel@tonic-gate 			ddi_prop_free(strs);
2737*7c478bd9Sstevel@tonic-gate 			switch (i) {
2738*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
2739*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
2740*7c478bd9Sstevel@tonic-gate 
2741*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
2742*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_DECODE);
2743*7c478bd9Sstevel@tonic-gate 			}
2744*7c478bd9Sstevel@tonic-gate 		}
2745*7c478bd9Sstevel@tonic-gate 	}
2746*7c478bd9Sstevel@tonic-gate 
2747*7c478bd9Sstevel@tonic-gate 	*(char ***)data = strs;
2748*7c478bd9Sstevel@tonic-gate 	*nelements = cnt;
2749*7c478bd9Sstevel@tonic-gate 
2750*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
2751*7c478bd9Sstevel@tonic-gate }
2752*7c478bd9Sstevel@tonic-gate 
2753*7c478bd9Sstevel@tonic-gate /*
2754*7c478bd9Sstevel@tonic-gate  * Encode a string.
2755*7c478bd9Sstevel@tonic-gate  */
2756*7c478bd9Sstevel@tonic-gate int
2757*7c478bd9Sstevel@tonic-gate ddi_prop_fm_encode_string(prop_handle_t *ph, void *data, uint_t nelements)
2758*7c478bd9Sstevel@tonic-gate {
2759*7c478bd9Sstevel@tonic-gate 	char		**tmp;
2760*7c478bd9Sstevel@tonic-gate 	int		size;
2761*7c478bd9Sstevel@tonic-gate 	int		i;
2762*7c478bd9Sstevel@tonic-gate 
2763*7c478bd9Sstevel@tonic-gate 	/*
2764*7c478bd9Sstevel@tonic-gate 	 * If there is no data, we cannot do anything
2765*7c478bd9Sstevel@tonic-gate 	 */
2766*7c478bd9Sstevel@tonic-gate 	if (nelements == 0)
2767*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_ENCODE);
2768*7c478bd9Sstevel@tonic-gate 
2769*7c478bd9Sstevel@tonic-gate 	/*
2770*7c478bd9Sstevel@tonic-gate 	 * Get the size of the encoded string.
2771*7c478bd9Sstevel@tonic-gate 	 */
2772*7c478bd9Sstevel@tonic-gate 	tmp = (char **)data;
2773*7c478bd9Sstevel@tonic-gate 	size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_ESIZE, *tmp);
2774*7c478bd9Sstevel@tonic-gate 	if (size < DDI_PROP_RESULT_OK) {
2775*7c478bd9Sstevel@tonic-gate 		switch (size) {
2776*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
2777*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
2778*7c478bd9Sstevel@tonic-gate 
2779*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
2780*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_ENCODE);
2781*7c478bd9Sstevel@tonic-gate 		}
2782*7c478bd9Sstevel@tonic-gate 	}
2783*7c478bd9Sstevel@tonic-gate 
2784*7c478bd9Sstevel@tonic-gate 	/*
2785*7c478bd9Sstevel@tonic-gate 	 * Allocate space in the handle to store the encoded string.
2786*7c478bd9Sstevel@tonic-gate 	 */
2787*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_encode_alloc(ph, size) != DDI_PROP_SUCCESS)
2788*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
2789*7c478bd9Sstevel@tonic-gate 
2790*7c478bd9Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
2791*7c478bd9Sstevel@tonic-gate 
2792*7c478bd9Sstevel@tonic-gate 	/*
2793*7c478bd9Sstevel@tonic-gate 	 * Encode the string.
2794*7c478bd9Sstevel@tonic-gate 	 */
2795*7c478bd9Sstevel@tonic-gate 	tmp = (char **)data;
2796*7c478bd9Sstevel@tonic-gate 	i = DDI_PROP_STR(ph, DDI_PROP_CMD_ENCODE, *tmp);
2797*7c478bd9Sstevel@tonic-gate 	if (i < DDI_PROP_RESULT_OK) {
2798*7c478bd9Sstevel@tonic-gate 		switch (i) {
2799*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
2800*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
2801*7c478bd9Sstevel@tonic-gate 
2802*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
2803*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_ENCODE);
2804*7c478bd9Sstevel@tonic-gate 		}
2805*7c478bd9Sstevel@tonic-gate 	}
2806*7c478bd9Sstevel@tonic-gate 
2807*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
2808*7c478bd9Sstevel@tonic-gate }
2809*7c478bd9Sstevel@tonic-gate 
2810*7c478bd9Sstevel@tonic-gate 
2811*7c478bd9Sstevel@tonic-gate /*
2812*7c478bd9Sstevel@tonic-gate  * Encode an array of strings.
2813*7c478bd9Sstevel@tonic-gate  */
2814*7c478bd9Sstevel@tonic-gate int
2815*7c478bd9Sstevel@tonic-gate ddi_prop_fm_encode_strings(prop_handle_t *ph, void *data, uint_t nelements)
2816*7c478bd9Sstevel@tonic-gate {
2817*7c478bd9Sstevel@tonic-gate 	int		cnt = 0;
2818*7c478bd9Sstevel@tonic-gate 	char		**tmp;
2819*7c478bd9Sstevel@tonic-gate 	int		size;
2820*7c478bd9Sstevel@tonic-gate 	uint_t		total_size;
2821*7c478bd9Sstevel@tonic-gate 	int		i;
2822*7c478bd9Sstevel@tonic-gate 
2823*7c478bd9Sstevel@tonic-gate 	/*
2824*7c478bd9Sstevel@tonic-gate 	 * If there is no data, we cannot do anything
2825*7c478bd9Sstevel@tonic-gate 	 */
2826*7c478bd9Sstevel@tonic-gate 	if (nelements == 0)
2827*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_ENCODE);
2828*7c478bd9Sstevel@tonic-gate 
2829*7c478bd9Sstevel@tonic-gate 	/*
2830*7c478bd9Sstevel@tonic-gate 	 * Get the total size required to encode all the strings.
2831*7c478bd9Sstevel@tonic-gate 	 */
2832*7c478bd9Sstevel@tonic-gate 	total_size = 0;
2833*7c478bd9Sstevel@tonic-gate 	tmp = (char **)data;
2834*7c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < nelements; cnt++, tmp++) {
2835*7c478bd9Sstevel@tonic-gate 		size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_ESIZE, *tmp);
2836*7c478bd9Sstevel@tonic-gate 		if (size < DDI_PROP_RESULT_OK) {
2837*7c478bd9Sstevel@tonic-gate 			switch (size) {
2838*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
2839*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
2840*7c478bd9Sstevel@tonic-gate 
2841*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
2842*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_ENCODE);
2843*7c478bd9Sstevel@tonic-gate 			}
2844*7c478bd9Sstevel@tonic-gate 		}
2845*7c478bd9Sstevel@tonic-gate 		total_size += (uint_t)size;
2846*7c478bd9Sstevel@tonic-gate 	}
2847*7c478bd9Sstevel@tonic-gate 
2848*7c478bd9Sstevel@tonic-gate 	/*
2849*7c478bd9Sstevel@tonic-gate 	 * Allocate space in the handle to store the encoded strings.
2850*7c478bd9Sstevel@tonic-gate 	 */
2851*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_encode_alloc(ph, total_size) != DDI_PROP_SUCCESS)
2852*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
2853*7c478bd9Sstevel@tonic-gate 
2854*7c478bd9Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
2855*7c478bd9Sstevel@tonic-gate 
2856*7c478bd9Sstevel@tonic-gate 	/*
2857*7c478bd9Sstevel@tonic-gate 	 * Encode the array of strings.
2858*7c478bd9Sstevel@tonic-gate 	 */
2859*7c478bd9Sstevel@tonic-gate 	tmp = (char **)data;
2860*7c478bd9Sstevel@tonic-gate 	for (cnt = 0; cnt < nelements; cnt++, tmp++) {
2861*7c478bd9Sstevel@tonic-gate 		i = DDI_PROP_STR(ph, DDI_PROP_CMD_ENCODE, *tmp);
2862*7c478bd9Sstevel@tonic-gate 		if (i < DDI_PROP_RESULT_OK) {
2863*7c478bd9Sstevel@tonic-gate 			switch (i) {
2864*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
2865*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
2866*7c478bd9Sstevel@tonic-gate 
2867*7c478bd9Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
2868*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_ENCODE);
2869*7c478bd9Sstevel@tonic-gate 			}
2870*7c478bd9Sstevel@tonic-gate 		}
2871*7c478bd9Sstevel@tonic-gate 	}
2872*7c478bd9Sstevel@tonic-gate 
2873*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
2874*7c478bd9Sstevel@tonic-gate }
2875*7c478bd9Sstevel@tonic-gate 
2876*7c478bd9Sstevel@tonic-gate 
2877*7c478bd9Sstevel@tonic-gate /*
2878*7c478bd9Sstevel@tonic-gate  * Decode an array of bytes.
2879*7c478bd9Sstevel@tonic-gate  */
2880*7c478bd9Sstevel@tonic-gate static int
2881*7c478bd9Sstevel@tonic-gate ddi_prop_fm_decode_bytes(prop_handle_t *ph, void *data, uint_t *nelements)
2882*7c478bd9Sstevel@tonic-gate {
2883*7c478bd9Sstevel@tonic-gate 	uchar_t		*tmp;
2884*7c478bd9Sstevel@tonic-gate 	int		nbytes;
2885*7c478bd9Sstevel@tonic-gate 	int		i;
2886*7c478bd9Sstevel@tonic-gate 
2887*7c478bd9Sstevel@tonic-gate 	/*
2888*7c478bd9Sstevel@tonic-gate 	 * If there are no elements return an error
2889*7c478bd9Sstevel@tonic-gate 	 */
2890*7c478bd9Sstevel@tonic-gate 	if (ph->ph_size == 0)
2891*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
2892*7c478bd9Sstevel@tonic-gate 
2893*7c478bd9Sstevel@tonic-gate 	/*
2894*7c478bd9Sstevel@tonic-gate 	 * Get the size of the encoded array of bytes.
2895*7c478bd9Sstevel@tonic-gate 	 */
2896*7c478bd9Sstevel@tonic-gate 	nbytes = DDI_PROP_BYTES(ph, DDI_PROP_CMD_GET_DSIZE,
2897*7c478bd9Sstevel@tonic-gate 		data, ph->ph_size);
2898*7c478bd9Sstevel@tonic-gate 	if (nbytes < DDI_PROP_RESULT_OK) {
2899*7c478bd9Sstevel@tonic-gate 		switch (nbytes) {
2900*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
2901*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
2902*7c478bd9Sstevel@tonic-gate 
2903*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
2904*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
2905*7c478bd9Sstevel@tonic-gate 		}
2906*7c478bd9Sstevel@tonic-gate 	}
2907*7c478bd9Sstevel@tonic-gate 
2908*7c478bd9Sstevel@tonic-gate 	/*
2909*7c478bd9Sstevel@tonic-gate 	 * Allocated memory to store the decoded value in.
2910*7c478bd9Sstevel@tonic-gate 	 */
2911*7c478bd9Sstevel@tonic-gate 	tmp = ddi_prop_decode_alloc(nbytes, ddi_prop_free_bytes);
2912*7c478bd9Sstevel@tonic-gate 
2913*7c478bd9Sstevel@tonic-gate 	/*
2914*7c478bd9Sstevel@tonic-gate 	 * Decode each element and place it in the space we just allocated
2915*7c478bd9Sstevel@tonic-gate 	 */
2916*7c478bd9Sstevel@tonic-gate 	i = DDI_PROP_BYTES(ph, DDI_PROP_CMD_DECODE, tmp, nbytes);
2917*7c478bd9Sstevel@tonic-gate 	if (i < DDI_PROP_RESULT_OK) {
2918*7c478bd9Sstevel@tonic-gate 		/*
2919*7c478bd9Sstevel@tonic-gate 		 * Free the space we just allocated
2920*7c478bd9Sstevel@tonic-gate 		 * and return an error
2921*7c478bd9Sstevel@tonic-gate 		 */
2922*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(tmp);
2923*7c478bd9Sstevel@tonic-gate 		switch (i) {
2924*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
2925*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
2926*7c478bd9Sstevel@tonic-gate 
2927*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
2928*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
2929*7c478bd9Sstevel@tonic-gate 		}
2930*7c478bd9Sstevel@tonic-gate 	}
2931*7c478bd9Sstevel@tonic-gate 
2932*7c478bd9Sstevel@tonic-gate 	*(uchar_t **)data = tmp;
2933*7c478bd9Sstevel@tonic-gate 	*nelements = nbytes;
2934*7c478bd9Sstevel@tonic-gate 
2935*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
2936*7c478bd9Sstevel@tonic-gate }
2937*7c478bd9Sstevel@tonic-gate 
2938*7c478bd9Sstevel@tonic-gate /*
2939*7c478bd9Sstevel@tonic-gate  * Encode an array of bytes.
2940*7c478bd9Sstevel@tonic-gate  */
2941*7c478bd9Sstevel@tonic-gate int
2942*7c478bd9Sstevel@tonic-gate ddi_prop_fm_encode_bytes(prop_handle_t *ph, void *data, uint_t nelements)
2943*7c478bd9Sstevel@tonic-gate {
2944*7c478bd9Sstevel@tonic-gate 	int		size;
2945*7c478bd9Sstevel@tonic-gate 	int		i;
2946*7c478bd9Sstevel@tonic-gate 
2947*7c478bd9Sstevel@tonic-gate 	/*
2948*7c478bd9Sstevel@tonic-gate 	 * If there are no elements, then this is a boolean property,
2949*7c478bd9Sstevel@tonic-gate 	 * so just create a property handle with no data and return.
2950*7c478bd9Sstevel@tonic-gate 	 */
2951*7c478bd9Sstevel@tonic-gate 	if (nelements == 0) {
2952*7c478bd9Sstevel@tonic-gate 		(void) ddi_prop_encode_alloc(ph, 0);
2953*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_SUCCESS);
2954*7c478bd9Sstevel@tonic-gate 	}
2955*7c478bd9Sstevel@tonic-gate 
2956*7c478bd9Sstevel@tonic-gate 	/*
2957*7c478bd9Sstevel@tonic-gate 	 * Get the size of the encoded array of bytes.
2958*7c478bd9Sstevel@tonic-gate 	 */
2959*7c478bd9Sstevel@tonic-gate 	size = DDI_PROP_BYTES(ph, DDI_PROP_CMD_GET_ESIZE, (uchar_t *)data,
2960*7c478bd9Sstevel@tonic-gate 		nelements);
2961*7c478bd9Sstevel@tonic-gate 	if (size < DDI_PROP_RESULT_OK) {
2962*7c478bd9Sstevel@tonic-gate 		switch (size) {
2963*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
2964*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
2965*7c478bd9Sstevel@tonic-gate 
2966*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
2967*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
2968*7c478bd9Sstevel@tonic-gate 		}
2969*7c478bd9Sstevel@tonic-gate 	}
2970*7c478bd9Sstevel@tonic-gate 
2971*7c478bd9Sstevel@tonic-gate 	/*
2972*7c478bd9Sstevel@tonic-gate 	 * Allocate space in the handle to store the encoded bytes.
2973*7c478bd9Sstevel@tonic-gate 	 */
2974*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_encode_alloc(ph, (uint_t)size) != DDI_PROP_SUCCESS)
2975*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
2976*7c478bd9Sstevel@tonic-gate 
2977*7c478bd9Sstevel@tonic-gate 	/*
2978*7c478bd9Sstevel@tonic-gate 	 * Encode the array of bytes.
2979*7c478bd9Sstevel@tonic-gate 	 */
2980*7c478bd9Sstevel@tonic-gate 	i = DDI_PROP_BYTES(ph, DDI_PROP_CMD_ENCODE, (uchar_t *)data,
2981*7c478bd9Sstevel@tonic-gate 		nelements);
2982*7c478bd9Sstevel@tonic-gate 	if (i < DDI_PROP_RESULT_OK) {
2983*7c478bd9Sstevel@tonic-gate 		switch (i) {
2984*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
2985*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
2986*7c478bd9Sstevel@tonic-gate 
2987*7c478bd9Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
2988*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_ENCODE);
2989*7c478bd9Sstevel@tonic-gate 		}
2990*7c478bd9Sstevel@tonic-gate 	}
2991*7c478bd9Sstevel@tonic-gate 
2992*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
2993*7c478bd9Sstevel@tonic-gate }
2994*7c478bd9Sstevel@tonic-gate 
2995*7c478bd9Sstevel@tonic-gate /*
2996*7c478bd9Sstevel@tonic-gate  * OBP 1275 integer, string and byte operators.
2997*7c478bd9Sstevel@tonic-gate  *
2998*7c478bd9Sstevel@tonic-gate  * DDI_PROP_CMD_DECODE:
2999*7c478bd9Sstevel@tonic-gate  *
3000*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_RESULT_ERROR:		cannot decode the data
3001*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_RESULT_EOF:		end of data
3002*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_OK:			data was decoded
3003*7c478bd9Sstevel@tonic-gate  *
3004*7c478bd9Sstevel@tonic-gate  * DDI_PROP_CMD_ENCODE:
3005*7c478bd9Sstevel@tonic-gate  *
3006*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_RESULT_ERROR:		cannot encode the data
3007*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_RESULT_EOF:		end of data
3008*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_OK:			data was encoded
3009*7c478bd9Sstevel@tonic-gate  *
3010*7c478bd9Sstevel@tonic-gate  * DDI_PROP_CMD_SKIP:
3011*7c478bd9Sstevel@tonic-gate  *
3012*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_RESULT_ERROR:		cannot skip the data
3013*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_RESULT_EOF:		end of data
3014*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_OK:			data was skipped
3015*7c478bd9Sstevel@tonic-gate  *
3016*7c478bd9Sstevel@tonic-gate  * DDI_PROP_CMD_GET_ESIZE:
3017*7c478bd9Sstevel@tonic-gate  *
3018*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_RESULT_ERROR:		cannot get encoded size
3019*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_RESULT_EOF:		end of data
3020*7c478bd9Sstevel@tonic-gate  *	> 0:				the encoded size
3021*7c478bd9Sstevel@tonic-gate  *
3022*7c478bd9Sstevel@tonic-gate  * DDI_PROP_CMD_GET_DSIZE:
3023*7c478bd9Sstevel@tonic-gate  *
3024*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_RESULT_ERROR:		cannot get decoded size
3025*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_RESULT_EOF:		end of data
3026*7c478bd9Sstevel@tonic-gate  *	> 0:				the decoded size
3027*7c478bd9Sstevel@tonic-gate  */
3028*7c478bd9Sstevel@tonic-gate 
3029*7c478bd9Sstevel@tonic-gate /*
3030*7c478bd9Sstevel@tonic-gate  * OBP 1275 integer operator
3031*7c478bd9Sstevel@tonic-gate  *
3032*7c478bd9Sstevel@tonic-gate  * OBP properties are a byte stream of data, so integers may not be
3033*7c478bd9Sstevel@tonic-gate  * properly aligned.  Therefore we need to copy them one byte at a time.
3034*7c478bd9Sstevel@tonic-gate  */
3035*7c478bd9Sstevel@tonic-gate int
3036*7c478bd9Sstevel@tonic-gate ddi_prop_1275_int(prop_handle_t *ph, uint_t cmd, int *data)
3037*7c478bd9Sstevel@tonic-gate {
3038*7c478bd9Sstevel@tonic-gate 	int	i;
3039*7c478bd9Sstevel@tonic-gate 
3040*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
3041*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_DECODE:
3042*7c478bd9Sstevel@tonic-gate 		/*
3043*7c478bd9Sstevel@tonic-gate 		 * Check that there is encoded data
3044*7c478bd9Sstevel@tonic-gate 		 */
3045*7c478bd9Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
3046*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3047*7c478bd9Sstevel@tonic-gate 		if (ph->ph_flags & PH_FROM_PROM) {
3048*7c478bd9Sstevel@tonic-gate 			i = MIN(ph->ph_size, PROP_1275_INT_SIZE);
3049*7c478bd9Sstevel@tonic-gate 			if ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
3050*7c478bd9Sstevel@tonic-gate 				ph->ph_size - i))
3051*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_RESULT_ERROR);
3052*7c478bd9Sstevel@tonic-gate 		} else {
3053*7c478bd9Sstevel@tonic-gate 			if (ph->ph_size < sizeof (int) ||
3054*7c478bd9Sstevel@tonic-gate 			((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
3055*7c478bd9Sstevel@tonic-gate 				ph->ph_size - sizeof (int))))
3056*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3057*7c478bd9Sstevel@tonic-gate 		}
3058*7c478bd9Sstevel@tonic-gate 
3059*7c478bd9Sstevel@tonic-gate 		/*
3060*7c478bd9Sstevel@tonic-gate 		 * Copy the integer, using the implementation-specific
3061*7c478bd9Sstevel@tonic-gate 		 * copy function if the property is coming from the PROM.
3062*7c478bd9Sstevel@tonic-gate 		 */
3063*7c478bd9Sstevel@tonic-gate 		if (ph->ph_flags & PH_FROM_PROM) {
3064*7c478bd9Sstevel@tonic-gate 			*data = impl_ddi_prop_int_from_prom(
3065*7c478bd9Sstevel@tonic-gate 				(uchar_t *)ph->ph_cur_pos,
3066*7c478bd9Sstevel@tonic-gate 				(ph->ph_size < PROP_1275_INT_SIZE) ?
3067*7c478bd9Sstevel@tonic-gate 				ph->ph_size : PROP_1275_INT_SIZE);
3068*7c478bd9Sstevel@tonic-gate 		} else {
3069*7c478bd9Sstevel@tonic-gate 			bcopy(ph->ph_cur_pos, data, sizeof (int));
3070*7c478bd9Sstevel@tonic-gate 		}
3071*7c478bd9Sstevel@tonic-gate 
3072*7c478bd9Sstevel@tonic-gate 		/*
3073*7c478bd9Sstevel@tonic-gate 		 * Move the current location to the start of the next
3074*7c478bd9Sstevel@tonic-gate 		 * bit of undecoded data.
3075*7c478bd9Sstevel@tonic-gate 		 */
3076*7c478bd9Sstevel@tonic-gate 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
3077*7c478bd9Sstevel@tonic-gate 			PROP_1275_INT_SIZE;
3078*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
3079*7c478bd9Sstevel@tonic-gate 
3080*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_ENCODE:
3081*7c478bd9Sstevel@tonic-gate 		/*
3082*7c478bd9Sstevel@tonic-gate 		 * Check that there is room to encoded the data
3083*7c478bd9Sstevel@tonic-gate 		 */
3084*7c478bd9Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3085*7c478bd9Sstevel@tonic-gate 			ph->ph_size < PROP_1275_INT_SIZE ||
3086*7c478bd9Sstevel@tonic-gate 			((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
3087*7c478bd9Sstevel@tonic-gate 				ph->ph_size - sizeof (int))))
3088*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3089*7c478bd9Sstevel@tonic-gate 
3090*7c478bd9Sstevel@tonic-gate 		/*
3091*7c478bd9Sstevel@tonic-gate 		 * Encode the integer into the byte stream one byte at a
3092*7c478bd9Sstevel@tonic-gate 		 * time.
3093*7c478bd9Sstevel@tonic-gate 		 */
3094*7c478bd9Sstevel@tonic-gate 		bcopy(data, ph->ph_cur_pos, sizeof (int));
3095*7c478bd9Sstevel@tonic-gate 
3096*7c478bd9Sstevel@tonic-gate 		/*
3097*7c478bd9Sstevel@tonic-gate 		 * Move the current location to the start of the next bit of
3098*7c478bd9Sstevel@tonic-gate 		 * space where we can store encoded data.
3099*7c478bd9Sstevel@tonic-gate 		 */
3100*7c478bd9Sstevel@tonic-gate 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
3101*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
3102*7c478bd9Sstevel@tonic-gate 
3103*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_SKIP:
3104*7c478bd9Sstevel@tonic-gate 		/*
3105*7c478bd9Sstevel@tonic-gate 		 * Check that there is encoded data
3106*7c478bd9Sstevel@tonic-gate 		 */
3107*7c478bd9Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3108*7c478bd9Sstevel@tonic-gate 				ph->ph_size < PROP_1275_INT_SIZE)
3109*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3110*7c478bd9Sstevel@tonic-gate 
3111*7c478bd9Sstevel@tonic-gate 
3112*7c478bd9Sstevel@tonic-gate 		if ((caddr_t)ph->ph_cur_pos ==
3113*7c478bd9Sstevel@tonic-gate 				(caddr_t)ph->ph_data + ph->ph_size) {
3114*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_EOF);
3115*7c478bd9Sstevel@tonic-gate 		} else if ((caddr_t)ph->ph_cur_pos >
3116*7c478bd9Sstevel@tonic-gate 				(caddr_t)ph->ph_data + ph->ph_size) {
3117*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_EOF);
3118*7c478bd9Sstevel@tonic-gate 		}
3119*7c478bd9Sstevel@tonic-gate 
3120*7c478bd9Sstevel@tonic-gate 		/*
3121*7c478bd9Sstevel@tonic-gate 		 * Move the current location to the start of the next bit of
3122*7c478bd9Sstevel@tonic-gate 		 * undecoded data.
3123*7c478bd9Sstevel@tonic-gate 		 */
3124*7c478bd9Sstevel@tonic-gate 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
3125*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
3126*7c478bd9Sstevel@tonic-gate 
3127*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_ESIZE:
3128*7c478bd9Sstevel@tonic-gate 		/*
3129*7c478bd9Sstevel@tonic-gate 		 * Return the size of an encoded integer on OBP
3130*7c478bd9Sstevel@tonic-gate 		 */
3131*7c478bd9Sstevel@tonic-gate 		return (PROP_1275_INT_SIZE);
3132*7c478bd9Sstevel@tonic-gate 
3133*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_DSIZE:
3134*7c478bd9Sstevel@tonic-gate 		/*
3135*7c478bd9Sstevel@tonic-gate 		 * Return the size of a decoded integer on the system.
3136*7c478bd9Sstevel@tonic-gate 		 */
3137*7c478bd9Sstevel@tonic-gate 		return (sizeof (int));
3138*7c478bd9Sstevel@tonic-gate 
3139*7c478bd9Sstevel@tonic-gate 	default:
3140*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
3141*7c478bd9Sstevel@tonic-gate 		panic("ddi_prop_1275_int: %x impossible", cmd);
3142*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3143*7c478bd9Sstevel@tonic-gate #else
3144*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_ERROR);
3145*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
3146*7c478bd9Sstevel@tonic-gate 	}
3147*7c478bd9Sstevel@tonic-gate }
3148*7c478bd9Sstevel@tonic-gate 
3149*7c478bd9Sstevel@tonic-gate /*
3150*7c478bd9Sstevel@tonic-gate  * 64 bit integer operator.
3151*7c478bd9Sstevel@tonic-gate  *
3152*7c478bd9Sstevel@tonic-gate  * This is an extension, defined by Sun, to the 1275 integer
3153*7c478bd9Sstevel@tonic-gate  * operator.  This routine handles the encoding/decoding of
3154*7c478bd9Sstevel@tonic-gate  * 64 bit integer properties.
3155*7c478bd9Sstevel@tonic-gate  */
3156*7c478bd9Sstevel@tonic-gate int
3157*7c478bd9Sstevel@tonic-gate ddi_prop_int64_op(prop_handle_t *ph, uint_t cmd, int64_t *data)
3158*7c478bd9Sstevel@tonic-gate {
3159*7c478bd9Sstevel@tonic-gate 
3160*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
3161*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_DECODE:
3162*7c478bd9Sstevel@tonic-gate 		/*
3163*7c478bd9Sstevel@tonic-gate 		 * Check that there is encoded data
3164*7c478bd9Sstevel@tonic-gate 		 */
3165*7c478bd9Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
3166*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3167*7c478bd9Sstevel@tonic-gate 		if (ph->ph_flags & PH_FROM_PROM) {
3168*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3169*7c478bd9Sstevel@tonic-gate 		} else {
3170*7c478bd9Sstevel@tonic-gate 			if (ph->ph_size < sizeof (int64_t) ||
3171*7c478bd9Sstevel@tonic-gate 			    ((int64_t *)ph->ph_cur_pos >
3172*7c478bd9Sstevel@tonic-gate 			    ((int64_t *)ph->ph_data +
3173*7c478bd9Sstevel@tonic-gate 			    ph->ph_size - sizeof (int64_t))))
3174*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_RESULT_ERROR);
3175*7c478bd9Sstevel@tonic-gate 		}
3176*7c478bd9Sstevel@tonic-gate 		/*
3177*7c478bd9Sstevel@tonic-gate 		 * Copy the integer, using the implementation-specific
3178*7c478bd9Sstevel@tonic-gate 		 * copy function if the property is coming from the PROM.
3179*7c478bd9Sstevel@tonic-gate 		 */
3180*7c478bd9Sstevel@tonic-gate 		if (ph->ph_flags & PH_FROM_PROM) {
3181*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3182*7c478bd9Sstevel@tonic-gate 		} else {
3183*7c478bd9Sstevel@tonic-gate 			bcopy(ph->ph_cur_pos, data, sizeof (int64_t));
3184*7c478bd9Sstevel@tonic-gate 		}
3185*7c478bd9Sstevel@tonic-gate 
3186*7c478bd9Sstevel@tonic-gate 		/*
3187*7c478bd9Sstevel@tonic-gate 		 * Move the current location to the start of the next
3188*7c478bd9Sstevel@tonic-gate 		 * bit of undecoded data.
3189*7c478bd9Sstevel@tonic-gate 		 */
3190*7c478bd9Sstevel@tonic-gate 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
3191*7c478bd9Sstevel@tonic-gate 		    sizeof (int64_t);
3192*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_OK);
3193*7c478bd9Sstevel@tonic-gate 
3194*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_ENCODE:
3195*7c478bd9Sstevel@tonic-gate 		/*
3196*7c478bd9Sstevel@tonic-gate 		 * Check that there is room to encoded the data
3197*7c478bd9Sstevel@tonic-gate 		 */
3198*7c478bd9Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3199*7c478bd9Sstevel@tonic-gate 		    ph->ph_size < sizeof (int64_t) ||
3200*7c478bd9Sstevel@tonic-gate 		    ((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data +
3201*7c478bd9Sstevel@tonic-gate 		    ph->ph_size - sizeof (int64_t))))
3202*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3203*7c478bd9Sstevel@tonic-gate 
3204*7c478bd9Sstevel@tonic-gate 		/*
3205*7c478bd9Sstevel@tonic-gate 		 * Encode the integer into the byte stream one byte at a
3206*7c478bd9Sstevel@tonic-gate 		 * time.
3207*7c478bd9Sstevel@tonic-gate 		 */
3208*7c478bd9Sstevel@tonic-gate 		bcopy(data, ph->ph_cur_pos, sizeof (int64_t));
3209*7c478bd9Sstevel@tonic-gate 
3210*7c478bd9Sstevel@tonic-gate 		/*
3211*7c478bd9Sstevel@tonic-gate 		 * Move the current location to the start of the next bit of
3212*7c478bd9Sstevel@tonic-gate 		 * space where we can store encoded data.
3213*7c478bd9Sstevel@tonic-gate 		 */
3214*7c478bd9Sstevel@tonic-gate 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
3215*7c478bd9Sstevel@tonic-gate 		    sizeof (int64_t);
3216*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
3217*7c478bd9Sstevel@tonic-gate 
3218*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_SKIP:
3219*7c478bd9Sstevel@tonic-gate 		/*
3220*7c478bd9Sstevel@tonic-gate 		 * Check that there is encoded data
3221*7c478bd9Sstevel@tonic-gate 		 */
3222*7c478bd9Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3223*7c478bd9Sstevel@tonic-gate 		    ph->ph_size < sizeof (int64_t))
3224*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3225*7c478bd9Sstevel@tonic-gate 
3226*7c478bd9Sstevel@tonic-gate 		if ((caddr_t)ph->ph_cur_pos ==
3227*7c478bd9Sstevel@tonic-gate 		    (caddr_t)ph->ph_data + ph->ph_size) {
3228*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_EOF);
3229*7c478bd9Sstevel@tonic-gate 		} else if ((caddr_t)ph->ph_cur_pos >
3230*7c478bd9Sstevel@tonic-gate 		    (caddr_t)ph->ph_data + ph->ph_size) {
3231*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_EOF);
3232*7c478bd9Sstevel@tonic-gate 		}
3233*7c478bd9Sstevel@tonic-gate 
3234*7c478bd9Sstevel@tonic-gate 		/*
3235*7c478bd9Sstevel@tonic-gate 		 * Move the current location to the start of
3236*7c478bd9Sstevel@tonic-gate 		 * the next bit of undecoded data.
3237*7c478bd9Sstevel@tonic-gate 		 */
3238*7c478bd9Sstevel@tonic-gate 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
3239*7c478bd9Sstevel@tonic-gate 		    sizeof (int64_t);
3240*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_OK);
3241*7c478bd9Sstevel@tonic-gate 
3242*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_ESIZE:
3243*7c478bd9Sstevel@tonic-gate 		/*
3244*7c478bd9Sstevel@tonic-gate 		 * Return the size of an encoded integer on OBP
3245*7c478bd9Sstevel@tonic-gate 		 */
3246*7c478bd9Sstevel@tonic-gate 		return (sizeof (int64_t));
3247*7c478bd9Sstevel@tonic-gate 
3248*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_DSIZE:
3249*7c478bd9Sstevel@tonic-gate 		/*
3250*7c478bd9Sstevel@tonic-gate 		 * Return the size of a decoded integer on the system.
3251*7c478bd9Sstevel@tonic-gate 		 */
3252*7c478bd9Sstevel@tonic-gate 		return (sizeof (int64_t));
3253*7c478bd9Sstevel@tonic-gate 
3254*7c478bd9Sstevel@tonic-gate 	default:
3255*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
3256*7c478bd9Sstevel@tonic-gate 		panic("ddi_prop_int64_op: %x impossible", cmd);
3257*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3258*7c478bd9Sstevel@tonic-gate #else
3259*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_ERROR);
3260*7c478bd9Sstevel@tonic-gate #endif  /* DEBUG */
3261*7c478bd9Sstevel@tonic-gate 	}
3262*7c478bd9Sstevel@tonic-gate }
3263*7c478bd9Sstevel@tonic-gate 
3264*7c478bd9Sstevel@tonic-gate /*
3265*7c478bd9Sstevel@tonic-gate  * OBP 1275 string operator.
3266*7c478bd9Sstevel@tonic-gate  *
3267*7c478bd9Sstevel@tonic-gate  * OBP strings are NULL terminated.
3268*7c478bd9Sstevel@tonic-gate  */
3269*7c478bd9Sstevel@tonic-gate int
3270*7c478bd9Sstevel@tonic-gate ddi_prop_1275_string(prop_handle_t *ph, uint_t cmd, char *data)
3271*7c478bd9Sstevel@tonic-gate {
3272*7c478bd9Sstevel@tonic-gate 	int	n;
3273*7c478bd9Sstevel@tonic-gate 	char	*p;
3274*7c478bd9Sstevel@tonic-gate 	char	*end;
3275*7c478bd9Sstevel@tonic-gate 
3276*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
3277*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_DECODE:
3278*7c478bd9Sstevel@tonic-gate 		/*
3279*7c478bd9Sstevel@tonic-gate 		 * Check that there is encoded data
3280*7c478bd9Sstevel@tonic-gate 		 */
3281*7c478bd9Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
3282*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3283*7c478bd9Sstevel@tonic-gate 		}
3284*7c478bd9Sstevel@tonic-gate 
3285*7c478bd9Sstevel@tonic-gate 		n = strlen((char *)ph->ph_cur_pos) + 1;
3286*7c478bd9Sstevel@tonic-gate 		if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
3287*7c478bd9Sstevel@tonic-gate 				ph->ph_size - n)) {
3288*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3289*7c478bd9Sstevel@tonic-gate 		}
3290*7c478bd9Sstevel@tonic-gate 
3291*7c478bd9Sstevel@tonic-gate 		/*
3292*7c478bd9Sstevel@tonic-gate 		 * Copy the NULL terminated string
3293*7c478bd9Sstevel@tonic-gate 		 */
3294*7c478bd9Sstevel@tonic-gate 		bcopy(ph->ph_cur_pos, data, n);
3295*7c478bd9Sstevel@tonic-gate 
3296*7c478bd9Sstevel@tonic-gate 		/*
3297*7c478bd9Sstevel@tonic-gate 		 * Move the current location to the start of the next bit of
3298*7c478bd9Sstevel@tonic-gate 		 * undecoded data.
3299*7c478bd9Sstevel@tonic-gate 		 */
3300*7c478bd9Sstevel@tonic-gate 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + n;
3301*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
3302*7c478bd9Sstevel@tonic-gate 
3303*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_ENCODE:
3304*7c478bd9Sstevel@tonic-gate 		/*
3305*7c478bd9Sstevel@tonic-gate 		 * Check that there is room to encoded the data
3306*7c478bd9Sstevel@tonic-gate 		 */
3307*7c478bd9Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
3308*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3309*7c478bd9Sstevel@tonic-gate 		}
3310*7c478bd9Sstevel@tonic-gate 
3311*7c478bd9Sstevel@tonic-gate 		n = strlen(data) + 1;
3312*7c478bd9Sstevel@tonic-gate 		if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
3313*7c478bd9Sstevel@tonic-gate 				ph->ph_size - n)) {
3314*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3315*7c478bd9Sstevel@tonic-gate 		}
3316*7c478bd9Sstevel@tonic-gate 
3317*7c478bd9Sstevel@tonic-gate 		/*
3318*7c478bd9Sstevel@tonic-gate 		 * Copy the NULL terminated string
3319*7c478bd9Sstevel@tonic-gate 		 */
3320*7c478bd9Sstevel@tonic-gate 		bcopy(data, ph->ph_cur_pos, n);
3321*7c478bd9Sstevel@tonic-gate 
3322*7c478bd9Sstevel@tonic-gate 		/*
3323*7c478bd9Sstevel@tonic-gate 		 * Move the current location to the start of the next bit of
3324*7c478bd9Sstevel@tonic-gate 		 * space where we can store encoded data.
3325*7c478bd9Sstevel@tonic-gate 		 */
3326*7c478bd9Sstevel@tonic-gate 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + n;
3327*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
3328*7c478bd9Sstevel@tonic-gate 
3329*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_SKIP:
3330*7c478bd9Sstevel@tonic-gate 		/*
3331*7c478bd9Sstevel@tonic-gate 		 * Check that there is encoded data
3332*7c478bd9Sstevel@tonic-gate 		 */
3333*7c478bd9Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
3334*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3335*7c478bd9Sstevel@tonic-gate 		}
3336*7c478bd9Sstevel@tonic-gate 
3337*7c478bd9Sstevel@tonic-gate 		/*
3338*7c478bd9Sstevel@tonic-gate 		 * Return the string length plus one for the NULL
3339*7c478bd9Sstevel@tonic-gate 		 * We know the size of the property, we need to
3340*7c478bd9Sstevel@tonic-gate 		 * ensure that the string is properly formatted,
3341*7c478bd9Sstevel@tonic-gate 		 * since we may be looking up random OBP data.
3342*7c478bd9Sstevel@tonic-gate 		 */
3343*7c478bd9Sstevel@tonic-gate 		p = (char *)ph->ph_cur_pos;
3344*7c478bd9Sstevel@tonic-gate 		end = (char *)ph->ph_data + ph->ph_size;
3345*7c478bd9Sstevel@tonic-gate 
3346*7c478bd9Sstevel@tonic-gate 		if (p == end) {
3347*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_EOF);
3348*7c478bd9Sstevel@tonic-gate 		}
3349*7c478bd9Sstevel@tonic-gate 
3350*7c478bd9Sstevel@tonic-gate 		for (n = 0; p < end; n++) {
3351*7c478bd9Sstevel@tonic-gate 			if (*p++ == 0) {
3352*7c478bd9Sstevel@tonic-gate 				ph->ph_cur_pos = p;
3353*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_RESULT_OK);
3354*7c478bd9Sstevel@tonic-gate 			}
3355*7c478bd9Sstevel@tonic-gate 		}
3356*7c478bd9Sstevel@tonic-gate 
3357*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_ERROR);
3358*7c478bd9Sstevel@tonic-gate 
3359*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_ESIZE:
3360*7c478bd9Sstevel@tonic-gate 		/*
3361*7c478bd9Sstevel@tonic-gate 		 * Return the size of the encoded string on OBP.
3362*7c478bd9Sstevel@tonic-gate 		 */
3363*7c478bd9Sstevel@tonic-gate 		return (strlen(data) + 1);
3364*7c478bd9Sstevel@tonic-gate 
3365*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_DSIZE:
3366*7c478bd9Sstevel@tonic-gate 		/*
3367*7c478bd9Sstevel@tonic-gate 		 * Return the string length plus one for the NULL
3368*7c478bd9Sstevel@tonic-gate 		 * We know the size of the property, we need to
3369*7c478bd9Sstevel@tonic-gate 		 * ensure that the string is properly formatted,
3370*7c478bd9Sstevel@tonic-gate 		 * since we may be looking up random OBP data.
3371*7c478bd9Sstevel@tonic-gate 		 */
3372*7c478bd9Sstevel@tonic-gate 		p = (char *)ph->ph_cur_pos;
3373*7c478bd9Sstevel@tonic-gate 		end = (char *)ph->ph_data + ph->ph_size;
3374*7c478bd9Sstevel@tonic-gate 		for (n = 0; p < end; n++) {
3375*7c478bd9Sstevel@tonic-gate 			if (*p++ == 0) {
3376*7c478bd9Sstevel@tonic-gate 				ph->ph_cur_pos = p;
3377*7c478bd9Sstevel@tonic-gate 				return (n+1);
3378*7c478bd9Sstevel@tonic-gate 			}
3379*7c478bd9Sstevel@tonic-gate 		}
3380*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_ERROR);
3381*7c478bd9Sstevel@tonic-gate 
3382*7c478bd9Sstevel@tonic-gate 	default:
3383*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
3384*7c478bd9Sstevel@tonic-gate 		panic("ddi_prop_1275_string: %x impossible", cmd);
3385*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3386*7c478bd9Sstevel@tonic-gate #else
3387*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_ERROR);
3388*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
3389*7c478bd9Sstevel@tonic-gate 	}
3390*7c478bd9Sstevel@tonic-gate }
3391*7c478bd9Sstevel@tonic-gate 
3392*7c478bd9Sstevel@tonic-gate /*
3393*7c478bd9Sstevel@tonic-gate  * OBP 1275 byte operator
3394*7c478bd9Sstevel@tonic-gate  *
3395*7c478bd9Sstevel@tonic-gate  * Caller must specify the number of bytes to get.  OBP encodes bytes
3396*7c478bd9Sstevel@tonic-gate  * as a byte so there is a 1-to-1 translation.
3397*7c478bd9Sstevel@tonic-gate  */
3398*7c478bd9Sstevel@tonic-gate int
3399*7c478bd9Sstevel@tonic-gate ddi_prop_1275_bytes(prop_handle_t *ph, uint_t cmd, uchar_t *data,
3400*7c478bd9Sstevel@tonic-gate 	uint_t nelements)
3401*7c478bd9Sstevel@tonic-gate {
3402*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
3403*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_DECODE:
3404*7c478bd9Sstevel@tonic-gate 		/*
3405*7c478bd9Sstevel@tonic-gate 		 * Check that there is encoded data
3406*7c478bd9Sstevel@tonic-gate 		 */
3407*7c478bd9Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3408*7c478bd9Sstevel@tonic-gate 			ph->ph_size < nelements ||
3409*7c478bd9Sstevel@tonic-gate 			((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
3410*7c478bd9Sstevel@tonic-gate 				ph->ph_size - nelements)))
3411*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3412*7c478bd9Sstevel@tonic-gate 
3413*7c478bd9Sstevel@tonic-gate 		/*
3414*7c478bd9Sstevel@tonic-gate 		 * Copy out the bytes
3415*7c478bd9Sstevel@tonic-gate 		 */
3416*7c478bd9Sstevel@tonic-gate 		bcopy(ph->ph_cur_pos, data, nelements);
3417*7c478bd9Sstevel@tonic-gate 
3418*7c478bd9Sstevel@tonic-gate 		/*
3419*7c478bd9Sstevel@tonic-gate 		 * Move the current location
3420*7c478bd9Sstevel@tonic-gate 		 */
3421*7c478bd9Sstevel@tonic-gate 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
3422*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
3423*7c478bd9Sstevel@tonic-gate 
3424*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_ENCODE:
3425*7c478bd9Sstevel@tonic-gate 		/*
3426*7c478bd9Sstevel@tonic-gate 		 * Check that there is room to encode the data
3427*7c478bd9Sstevel@tonic-gate 		 */
3428*7c478bd9Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3429*7c478bd9Sstevel@tonic-gate 			ph->ph_size < nelements ||
3430*7c478bd9Sstevel@tonic-gate 			((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
3431*7c478bd9Sstevel@tonic-gate 				ph->ph_size - nelements)))
3432*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3433*7c478bd9Sstevel@tonic-gate 
3434*7c478bd9Sstevel@tonic-gate 		/*
3435*7c478bd9Sstevel@tonic-gate 		 * Copy in the bytes
3436*7c478bd9Sstevel@tonic-gate 		 */
3437*7c478bd9Sstevel@tonic-gate 		bcopy(data, ph->ph_cur_pos, nelements);
3438*7c478bd9Sstevel@tonic-gate 
3439*7c478bd9Sstevel@tonic-gate 		/*
3440*7c478bd9Sstevel@tonic-gate 		 * Move the current location to the start of the next bit of
3441*7c478bd9Sstevel@tonic-gate 		 * space where we can store encoded data.
3442*7c478bd9Sstevel@tonic-gate 		 */
3443*7c478bd9Sstevel@tonic-gate 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
3444*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
3445*7c478bd9Sstevel@tonic-gate 
3446*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_SKIP:
3447*7c478bd9Sstevel@tonic-gate 		/*
3448*7c478bd9Sstevel@tonic-gate 		 * Check that there is encoded data
3449*7c478bd9Sstevel@tonic-gate 		 */
3450*7c478bd9Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
3451*7c478bd9Sstevel@tonic-gate 				ph->ph_size < nelements)
3452*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
3453*7c478bd9Sstevel@tonic-gate 
3454*7c478bd9Sstevel@tonic-gate 		if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
3455*7c478bd9Sstevel@tonic-gate 				ph->ph_size - nelements))
3456*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_RESULT_EOF);
3457*7c478bd9Sstevel@tonic-gate 
3458*7c478bd9Sstevel@tonic-gate 		/*
3459*7c478bd9Sstevel@tonic-gate 		 * Move the current location
3460*7c478bd9Sstevel@tonic-gate 		 */
3461*7c478bd9Sstevel@tonic-gate 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
3462*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
3463*7c478bd9Sstevel@tonic-gate 
3464*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_ESIZE:
3465*7c478bd9Sstevel@tonic-gate 		/*
3466*7c478bd9Sstevel@tonic-gate 		 * The size in bytes of the encoded size is the
3467*7c478bd9Sstevel@tonic-gate 		 * same as the decoded size provided by the caller.
3468*7c478bd9Sstevel@tonic-gate 		 */
3469*7c478bd9Sstevel@tonic-gate 		return (nelements);
3470*7c478bd9Sstevel@tonic-gate 
3471*7c478bd9Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_DSIZE:
3472*7c478bd9Sstevel@tonic-gate 		/*
3473*7c478bd9Sstevel@tonic-gate 		 * Just return the number of bytes specified by the caller.
3474*7c478bd9Sstevel@tonic-gate 		 */
3475*7c478bd9Sstevel@tonic-gate 		return (nelements);
3476*7c478bd9Sstevel@tonic-gate 
3477*7c478bd9Sstevel@tonic-gate 	default:
3478*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
3479*7c478bd9Sstevel@tonic-gate 		panic("ddi_prop_1275_bytes: %x impossible", cmd);
3480*7c478bd9Sstevel@tonic-gate 		/*NOTREACHED*/
3481*7c478bd9Sstevel@tonic-gate #else
3482*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_RESULT_ERROR);
3483*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
3484*7c478bd9Sstevel@tonic-gate 	}
3485*7c478bd9Sstevel@tonic-gate }
3486*7c478bd9Sstevel@tonic-gate 
3487*7c478bd9Sstevel@tonic-gate /*
3488*7c478bd9Sstevel@tonic-gate  * Used for properties that come from the OBP, hardware configuration files,
3489*7c478bd9Sstevel@tonic-gate  * or that are created by calls to ddi_prop_update(9F).
3490*7c478bd9Sstevel@tonic-gate  */
3491*7c478bd9Sstevel@tonic-gate static struct prop_handle_ops prop_1275_ops = {
3492*7c478bd9Sstevel@tonic-gate 	ddi_prop_1275_int,
3493*7c478bd9Sstevel@tonic-gate 	ddi_prop_1275_string,
3494*7c478bd9Sstevel@tonic-gate 	ddi_prop_1275_bytes,
3495*7c478bd9Sstevel@tonic-gate 	ddi_prop_int64_op
3496*7c478bd9Sstevel@tonic-gate };
3497*7c478bd9Sstevel@tonic-gate 
3498*7c478bd9Sstevel@tonic-gate 
3499*7c478bd9Sstevel@tonic-gate /*
3500*7c478bd9Sstevel@tonic-gate  * Interface to create/modify a managed property on child's behalf...
3501*7c478bd9Sstevel@tonic-gate  * Flags interpreted are:
3502*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_CANSLEEP:	Allow memory allocation to sleep.
3503*7c478bd9Sstevel@tonic-gate  *	DDI_PROP_SYSTEM_DEF:	Manipulate system list rather than driver list.
3504*7c478bd9Sstevel@tonic-gate  *
3505*7c478bd9Sstevel@tonic-gate  * Use same dev_t when modifying or undefining a property.
3506*7c478bd9Sstevel@tonic-gate  * Search for properties with DDI_DEV_T_ANY to match first named
3507*7c478bd9Sstevel@tonic-gate  * property on the list.
3508*7c478bd9Sstevel@tonic-gate  *
3509*7c478bd9Sstevel@tonic-gate  * Properties are stored LIFO and subsequently will match the first
3510*7c478bd9Sstevel@tonic-gate  * `matching' instance.
3511*7c478bd9Sstevel@tonic-gate  */
3512*7c478bd9Sstevel@tonic-gate 
3513*7c478bd9Sstevel@tonic-gate /*
3514*7c478bd9Sstevel@tonic-gate  * ddi_prop_add:	Add a software defined property
3515*7c478bd9Sstevel@tonic-gate  */
3516*7c478bd9Sstevel@tonic-gate 
3517*7c478bd9Sstevel@tonic-gate /*
3518*7c478bd9Sstevel@tonic-gate  * define to get a new ddi_prop_t.
3519*7c478bd9Sstevel@tonic-gate  * km_flags are KM_SLEEP or KM_NOSLEEP.
3520*7c478bd9Sstevel@tonic-gate  */
3521*7c478bd9Sstevel@tonic-gate 
3522*7c478bd9Sstevel@tonic-gate #define	DDI_NEW_PROP_T(km_flags)	\
3523*7c478bd9Sstevel@tonic-gate 	(kmem_zalloc(sizeof (ddi_prop_t), km_flags))
3524*7c478bd9Sstevel@tonic-gate 
3525*7c478bd9Sstevel@tonic-gate static int
3526*7c478bd9Sstevel@tonic-gate ddi_prop_add(dev_t dev, dev_info_t *dip, int flags,
3527*7c478bd9Sstevel@tonic-gate     char *name, caddr_t value, int length)
3528*7c478bd9Sstevel@tonic-gate {
3529*7c478bd9Sstevel@tonic-gate 	ddi_prop_t	*new_propp, *propp;
3530*7c478bd9Sstevel@tonic-gate 	ddi_prop_t	**list_head = &(DEVI(dip)->devi_drv_prop_ptr);
3531*7c478bd9Sstevel@tonic-gate 	int		km_flags = KM_NOSLEEP;
3532*7c478bd9Sstevel@tonic-gate 	int		name_buf_len;
3533*7c478bd9Sstevel@tonic-gate 
3534*7c478bd9Sstevel@tonic-gate 	/*
3535*7c478bd9Sstevel@tonic-gate 	 * If dev_t is DDI_DEV_T_ANY or name's length is zero return error.
3536*7c478bd9Sstevel@tonic-gate 	 */
3537*7c478bd9Sstevel@tonic-gate 
3538*7c478bd9Sstevel@tonic-gate 	if (dev == DDI_DEV_T_ANY || name == (char *)0 || strlen(name) == 0)
3539*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
3540*7c478bd9Sstevel@tonic-gate 
3541*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_CANSLEEP)
3542*7c478bd9Sstevel@tonic-gate 		km_flags = KM_SLEEP;
3543*7c478bd9Sstevel@tonic-gate 
3544*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_SYSTEM_DEF)
3545*7c478bd9Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_sys_prop_ptr);
3546*7c478bd9Sstevel@tonic-gate 	else if (flags & DDI_PROP_HW_DEF)
3547*7c478bd9Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_hw_prop_ptr);
3548*7c478bd9Sstevel@tonic-gate 
3549*7c478bd9Sstevel@tonic-gate 	if ((new_propp = DDI_NEW_PROP_T(km_flags)) == NULL)  {
3550*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, prop_no_mem_msg, name);
3551*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
3552*7c478bd9Sstevel@tonic-gate 	}
3553*7c478bd9Sstevel@tonic-gate 
3554*7c478bd9Sstevel@tonic-gate 	/*
3555*7c478bd9Sstevel@tonic-gate 	 * If dev is major number 0, then we need to do a ddi_name_to_major
3556*7c478bd9Sstevel@tonic-gate 	 * to get the real major number for the device.  This needs to be
3557*7c478bd9Sstevel@tonic-gate 	 * done because some drivers need to call ddi_prop_create in their
3558*7c478bd9Sstevel@tonic-gate 	 * attach routines but they don't have a dev.  By creating the dev
3559*7c478bd9Sstevel@tonic-gate 	 * ourself if the major number is 0, drivers will not have to know what
3560*7c478bd9Sstevel@tonic-gate 	 * their major number.	They can just create a dev with major number
3561*7c478bd9Sstevel@tonic-gate 	 * 0 and pass it in.  For device 0, we will be doing a little extra
3562*7c478bd9Sstevel@tonic-gate 	 * work by recreating the same dev that we already have, but its the
3563*7c478bd9Sstevel@tonic-gate 	 * price you pay :-).
3564*7c478bd9Sstevel@tonic-gate 	 *
3565*7c478bd9Sstevel@tonic-gate 	 * This fixes bug #1098060.
3566*7c478bd9Sstevel@tonic-gate 	 */
3567*7c478bd9Sstevel@tonic-gate 	if (getmajor(dev) == DDI_MAJOR_T_UNKNOWN) {
3568*7c478bd9Sstevel@tonic-gate 		new_propp->prop_dev =
3569*7c478bd9Sstevel@tonic-gate 		    makedevice(ddi_name_to_major(DEVI(dip)->devi_binding_name),
3570*7c478bd9Sstevel@tonic-gate 		    getminor(dev));
3571*7c478bd9Sstevel@tonic-gate 	} else
3572*7c478bd9Sstevel@tonic-gate 		new_propp->prop_dev = dev;
3573*7c478bd9Sstevel@tonic-gate 
3574*7c478bd9Sstevel@tonic-gate 	/*
3575*7c478bd9Sstevel@tonic-gate 	 * Allocate space for property name and copy it in...
3576*7c478bd9Sstevel@tonic-gate 	 */
3577*7c478bd9Sstevel@tonic-gate 
3578*7c478bd9Sstevel@tonic-gate 	name_buf_len = strlen(name) + 1;
3579*7c478bd9Sstevel@tonic-gate 	new_propp->prop_name = kmem_alloc(name_buf_len, km_flags);
3580*7c478bd9Sstevel@tonic-gate 	if (new_propp->prop_name == 0)	{
3581*7c478bd9Sstevel@tonic-gate 		kmem_free(new_propp, sizeof (ddi_prop_t));
3582*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, prop_no_mem_msg, name);
3583*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
3584*7c478bd9Sstevel@tonic-gate 	}
3585*7c478bd9Sstevel@tonic-gate 	bcopy(name, new_propp->prop_name, name_buf_len);
3586*7c478bd9Sstevel@tonic-gate 
3587*7c478bd9Sstevel@tonic-gate 	/*
3588*7c478bd9Sstevel@tonic-gate 	 * Set the property type
3589*7c478bd9Sstevel@tonic-gate 	 */
3590*7c478bd9Sstevel@tonic-gate 	new_propp->prop_flags = flags & DDI_PROP_TYPE_MASK;
3591*7c478bd9Sstevel@tonic-gate 
3592*7c478bd9Sstevel@tonic-gate 	/*
3593*7c478bd9Sstevel@tonic-gate 	 * Set length and value ONLY if not an explicit property undefine:
3594*7c478bd9Sstevel@tonic-gate 	 * NOTE: value and length are zero for explicit undefines.
3595*7c478bd9Sstevel@tonic-gate 	 */
3596*7c478bd9Sstevel@tonic-gate 
3597*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_UNDEF_IT) {
3598*7c478bd9Sstevel@tonic-gate 		new_propp->prop_flags |= DDI_PROP_UNDEF_IT;
3599*7c478bd9Sstevel@tonic-gate 	} else {
3600*7c478bd9Sstevel@tonic-gate 		if ((new_propp->prop_len = length) != 0) {
3601*7c478bd9Sstevel@tonic-gate 			new_propp->prop_val = kmem_alloc(length, km_flags);
3602*7c478bd9Sstevel@tonic-gate 			if (new_propp->prop_val == 0)  {
3603*7c478bd9Sstevel@tonic-gate 				kmem_free(new_propp->prop_name, name_buf_len);
3604*7c478bd9Sstevel@tonic-gate 				kmem_free(new_propp, sizeof (ddi_prop_t));
3605*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_CONT, prop_no_mem_msg, name);
3606*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_NO_MEMORY);
3607*7c478bd9Sstevel@tonic-gate 			}
3608*7c478bd9Sstevel@tonic-gate 			bcopy(value, new_propp->prop_val, length);
3609*7c478bd9Sstevel@tonic-gate 		}
3610*7c478bd9Sstevel@tonic-gate 	}
3611*7c478bd9Sstevel@tonic-gate 
3612*7c478bd9Sstevel@tonic-gate 	/*
3613*7c478bd9Sstevel@tonic-gate 	 * Link property into beginning of list. (Properties are LIFO order.)
3614*7c478bd9Sstevel@tonic-gate 	 */
3615*7c478bd9Sstevel@tonic-gate 
3616*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
3617*7c478bd9Sstevel@tonic-gate 	propp = *list_head;
3618*7c478bd9Sstevel@tonic-gate 	new_propp->prop_next = propp;
3619*7c478bd9Sstevel@tonic-gate 	*list_head = new_propp;
3620*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
3621*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
3622*7c478bd9Sstevel@tonic-gate }
3623*7c478bd9Sstevel@tonic-gate 
3624*7c478bd9Sstevel@tonic-gate 
3625*7c478bd9Sstevel@tonic-gate /*
3626*7c478bd9Sstevel@tonic-gate  * ddi_prop_change:	Modify a software managed property value
3627*7c478bd9Sstevel@tonic-gate  *
3628*7c478bd9Sstevel@tonic-gate  *			Set new length and value if found.
3629*7c478bd9Sstevel@tonic-gate  *			returns DDI_PROP_INVAL_ARG if dev is DDI_DEV_T_ANY or
3630*7c478bd9Sstevel@tonic-gate  *			input name is the NULL string.
3631*7c478bd9Sstevel@tonic-gate  *			returns DDI_PROP_NO_MEMORY if unable to allocate memory
3632*7c478bd9Sstevel@tonic-gate  *
3633*7c478bd9Sstevel@tonic-gate  *			Note: an undef can be modified to be a define,
3634*7c478bd9Sstevel@tonic-gate  *			(you can't go the other way.)
3635*7c478bd9Sstevel@tonic-gate  */
3636*7c478bd9Sstevel@tonic-gate 
3637*7c478bd9Sstevel@tonic-gate static int
3638*7c478bd9Sstevel@tonic-gate ddi_prop_change(dev_t dev, dev_info_t *dip, int flags,
3639*7c478bd9Sstevel@tonic-gate     char *name, caddr_t value, int length)
3640*7c478bd9Sstevel@tonic-gate {
3641*7c478bd9Sstevel@tonic-gate 	ddi_prop_t	*propp;
3642*7c478bd9Sstevel@tonic-gate 	int		km_flags = KM_NOSLEEP;
3643*7c478bd9Sstevel@tonic-gate 	caddr_t		p = NULL;
3644*7c478bd9Sstevel@tonic-gate 
3645*7c478bd9Sstevel@tonic-gate 	if (dev == DDI_DEV_T_ANY || name == (char *)0 || strlen(name) == 0)
3646*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
3647*7c478bd9Sstevel@tonic-gate 
3648*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_CANSLEEP)
3649*7c478bd9Sstevel@tonic-gate 		km_flags = KM_SLEEP;
3650*7c478bd9Sstevel@tonic-gate 
3651*7c478bd9Sstevel@tonic-gate 	/*
3652*7c478bd9Sstevel@tonic-gate 	 * Preallocate buffer, even if we don't need it...
3653*7c478bd9Sstevel@tonic-gate 	 */
3654*7c478bd9Sstevel@tonic-gate 	if (length != 0)  {
3655*7c478bd9Sstevel@tonic-gate 		p = kmem_alloc(length, km_flags);
3656*7c478bd9Sstevel@tonic-gate 		if (p == NULL)	{
3657*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, prop_no_mem_msg, name);
3658*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_NO_MEMORY);
3659*7c478bd9Sstevel@tonic-gate 		}
3660*7c478bd9Sstevel@tonic-gate 	}
3661*7c478bd9Sstevel@tonic-gate 
3662*7c478bd9Sstevel@tonic-gate 	/*
3663*7c478bd9Sstevel@tonic-gate 	 * Check to see if the property exists.  If so we modify it.
3664*7c478bd9Sstevel@tonic-gate 	 * Else we create it by calling ddi_prop_add().
3665*7c478bd9Sstevel@tonic-gate 	 */
3666*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
3667*7c478bd9Sstevel@tonic-gate 
3668*7c478bd9Sstevel@tonic-gate 	propp = DEVI(dip)->devi_drv_prop_ptr;
3669*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_SYSTEM_DEF)
3670*7c478bd9Sstevel@tonic-gate 		propp = DEVI(dip)->devi_sys_prop_ptr;
3671*7c478bd9Sstevel@tonic-gate 	else if (flags & DDI_PROP_HW_DEF)
3672*7c478bd9Sstevel@tonic-gate 		propp = DEVI(dip)->devi_hw_prop_ptr;
3673*7c478bd9Sstevel@tonic-gate 
3674*7c478bd9Sstevel@tonic-gate 	while (propp != NULL) {
3675*7c478bd9Sstevel@tonic-gate 		if (strcmp(name, propp->prop_name) == 0 &&
3676*7c478bd9Sstevel@tonic-gate 		    dev == propp->prop_dev) {
3677*7c478bd9Sstevel@tonic-gate 
3678*7c478bd9Sstevel@tonic-gate 			/*
3679*7c478bd9Sstevel@tonic-gate 			 * Need to reallocate buffer?  If so, do it
3680*7c478bd9Sstevel@tonic-gate 			 * (carefully). (Reuse same space if new prop
3681*7c478bd9Sstevel@tonic-gate 			 * is same size and non-NULL sized).
3682*7c478bd9Sstevel@tonic-gate 			 */
3683*7c478bd9Sstevel@tonic-gate 
3684*7c478bd9Sstevel@tonic-gate 			if (length != 0)
3685*7c478bd9Sstevel@tonic-gate 				bcopy(value, p, length);
3686*7c478bd9Sstevel@tonic-gate 
3687*7c478bd9Sstevel@tonic-gate 			if (propp->prop_len != 0)
3688*7c478bd9Sstevel@tonic-gate 				kmem_free(propp->prop_val, propp->prop_len);
3689*7c478bd9Sstevel@tonic-gate 
3690*7c478bd9Sstevel@tonic-gate 			propp->prop_len = length;
3691*7c478bd9Sstevel@tonic-gate 			propp->prop_val = p;
3692*7c478bd9Sstevel@tonic-gate 			propp->prop_flags &= ~DDI_PROP_UNDEF_IT;
3693*7c478bd9Sstevel@tonic-gate 			mutex_exit(&(DEVI(dip)->devi_lock));
3694*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_SUCCESS);
3695*7c478bd9Sstevel@tonic-gate 		}
3696*7c478bd9Sstevel@tonic-gate 		propp = propp->prop_next;
3697*7c478bd9Sstevel@tonic-gate 	}
3698*7c478bd9Sstevel@tonic-gate 
3699*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
3700*7c478bd9Sstevel@tonic-gate 	if (length != 0)
3701*7c478bd9Sstevel@tonic-gate 		kmem_free(p, length);
3702*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_add(dev, dip, flags, name, value, length));
3703*7c478bd9Sstevel@tonic-gate }
3704*7c478bd9Sstevel@tonic-gate 
3705*7c478bd9Sstevel@tonic-gate 
3706*7c478bd9Sstevel@tonic-gate 
3707*7c478bd9Sstevel@tonic-gate /*
3708*7c478bd9Sstevel@tonic-gate  * Common update routine used to update and encode a property.	Creates
3709*7c478bd9Sstevel@tonic-gate  * a property handle, calls the property encode routine, figures out if
3710*7c478bd9Sstevel@tonic-gate  * the property already exists and updates if it does.	Otherwise it
3711*7c478bd9Sstevel@tonic-gate  * creates if it does not exist.
3712*7c478bd9Sstevel@tonic-gate  */
3713*7c478bd9Sstevel@tonic-gate int
3714*7c478bd9Sstevel@tonic-gate ddi_prop_update_common(dev_t match_dev, dev_info_t *dip, int flags,
3715*7c478bd9Sstevel@tonic-gate     char *name, void *data, uint_t nelements,
3716*7c478bd9Sstevel@tonic-gate     int (*prop_create)(prop_handle_t *, void *data, uint_t nelements))
3717*7c478bd9Sstevel@tonic-gate {
3718*7c478bd9Sstevel@tonic-gate 	prop_handle_t	ph;
3719*7c478bd9Sstevel@tonic-gate 	int		rval;
3720*7c478bd9Sstevel@tonic-gate 	uint_t		ourflags;
3721*7c478bd9Sstevel@tonic-gate 
3722*7c478bd9Sstevel@tonic-gate 	/*
3723*7c478bd9Sstevel@tonic-gate 	 * If dev_t is DDI_DEV_T_ANY or name's length is zero,
3724*7c478bd9Sstevel@tonic-gate 	 * return error.
3725*7c478bd9Sstevel@tonic-gate 	 */
3726*7c478bd9Sstevel@tonic-gate 	if (match_dev == DDI_DEV_T_ANY || name == NULL || strlen(name) == 0)
3727*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
3728*7c478bd9Sstevel@tonic-gate 
3729*7c478bd9Sstevel@tonic-gate 	/*
3730*7c478bd9Sstevel@tonic-gate 	 * Create the handle
3731*7c478bd9Sstevel@tonic-gate 	 */
3732*7c478bd9Sstevel@tonic-gate 	ph.ph_data = NULL;
3733*7c478bd9Sstevel@tonic-gate 	ph.ph_cur_pos = NULL;
3734*7c478bd9Sstevel@tonic-gate 	ph.ph_save_pos = NULL;
3735*7c478bd9Sstevel@tonic-gate 	ph.ph_size = 0;
3736*7c478bd9Sstevel@tonic-gate 	ph.ph_ops = &prop_1275_ops;
3737*7c478bd9Sstevel@tonic-gate 
3738*7c478bd9Sstevel@tonic-gate 	/*
3739*7c478bd9Sstevel@tonic-gate 	 * ourflags:
3740*7c478bd9Sstevel@tonic-gate 	 * For compatibility with the old interfaces.  The old interfaces
3741*7c478bd9Sstevel@tonic-gate 	 * didn't sleep by default and slept when the flag was set.  These
3742*7c478bd9Sstevel@tonic-gate 	 * interfaces to the opposite.	So the old interfaces now set the
3743*7c478bd9Sstevel@tonic-gate 	 * DDI_PROP_DONTSLEEP flag by default which tells us not to sleep.
3744*7c478bd9Sstevel@tonic-gate 	 *
3745*7c478bd9Sstevel@tonic-gate 	 * ph.ph_flags:
3746*7c478bd9Sstevel@tonic-gate 	 * Blocked data or unblocked data allocation
3747*7c478bd9Sstevel@tonic-gate 	 * for ph.ph_data in ddi_prop_encode_alloc()
3748*7c478bd9Sstevel@tonic-gate 	 */
3749*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_DONTSLEEP) {
3750*7c478bd9Sstevel@tonic-gate 		ourflags = flags;
3751*7c478bd9Sstevel@tonic-gate 		ph.ph_flags = DDI_PROP_DONTSLEEP;
3752*7c478bd9Sstevel@tonic-gate 	} else {
3753*7c478bd9Sstevel@tonic-gate 		ourflags = flags | DDI_PROP_CANSLEEP;
3754*7c478bd9Sstevel@tonic-gate 		ph.ph_flags = DDI_PROP_CANSLEEP;
3755*7c478bd9Sstevel@tonic-gate 	}
3756*7c478bd9Sstevel@tonic-gate 
3757*7c478bd9Sstevel@tonic-gate 	/*
3758*7c478bd9Sstevel@tonic-gate 	 * Encode the data and store it in the property handle by
3759*7c478bd9Sstevel@tonic-gate 	 * calling the prop_encode routine.
3760*7c478bd9Sstevel@tonic-gate 	 */
3761*7c478bd9Sstevel@tonic-gate 	if ((rval = (*prop_create)(&ph, data, nelements)) !=
3762*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
3763*7c478bd9Sstevel@tonic-gate 		if (rval == DDI_PROP_NO_MEMORY)
3764*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT, prop_no_mem_msg, name);
3765*7c478bd9Sstevel@tonic-gate 		if (ph.ph_size != 0)
3766*7c478bd9Sstevel@tonic-gate 			kmem_free(ph.ph_data, ph.ph_size);
3767*7c478bd9Sstevel@tonic-gate 		return (rval);
3768*7c478bd9Sstevel@tonic-gate 	}
3769*7c478bd9Sstevel@tonic-gate 
3770*7c478bd9Sstevel@tonic-gate 	/*
3771*7c478bd9Sstevel@tonic-gate 	 * The old interfaces use a stacking approach to creating
3772*7c478bd9Sstevel@tonic-gate 	 * properties.	If we are being called from the old interfaces,
3773*7c478bd9Sstevel@tonic-gate 	 * the DDI_PROP_STACK_CREATE flag will be set, so we just do a
3774*7c478bd9Sstevel@tonic-gate 	 * create without checking.
3775*7c478bd9Sstevel@tonic-gate 	 */
3776*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_PROP_STACK_CREATE) {
3777*7c478bd9Sstevel@tonic-gate 		rval = ddi_prop_add(match_dev, dip,
3778*7c478bd9Sstevel@tonic-gate 		    ourflags, name, ph.ph_data, ph.ph_size);
3779*7c478bd9Sstevel@tonic-gate 	} else {
3780*7c478bd9Sstevel@tonic-gate 		rval = ddi_prop_change(match_dev, dip,
3781*7c478bd9Sstevel@tonic-gate 		    ourflags, name, ph.ph_data, ph.ph_size);
3782*7c478bd9Sstevel@tonic-gate 	}
3783*7c478bd9Sstevel@tonic-gate 
3784*7c478bd9Sstevel@tonic-gate 	/*
3785*7c478bd9Sstevel@tonic-gate 	 * Free the encoded data allocated in the prop_encode routine.
3786*7c478bd9Sstevel@tonic-gate 	 */
3787*7c478bd9Sstevel@tonic-gate 	if (ph.ph_size != 0)
3788*7c478bd9Sstevel@tonic-gate 		kmem_free(ph.ph_data, ph.ph_size);
3789*7c478bd9Sstevel@tonic-gate 
3790*7c478bd9Sstevel@tonic-gate 	return (rval);
3791*7c478bd9Sstevel@tonic-gate }
3792*7c478bd9Sstevel@tonic-gate 
3793*7c478bd9Sstevel@tonic-gate 
3794*7c478bd9Sstevel@tonic-gate /*
3795*7c478bd9Sstevel@tonic-gate  * ddi_prop_create:	Define a managed property:
3796*7c478bd9Sstevel@tonic-gate  *			See above for details.
3797*7c478bd9Sstevel@tonic-gate  */
3798*7c478bd9Sstevel@tonic-gate 
3799*7c478bd9Sstevel@tonic-gate int
3800*7c478bd9Sstevel@tonic-gate ddi_prop_create(dev_t dev, dev_info_t *dip, int flag,
3801*7c478bd9Sstevel@tonic-gate     char *name, caddr_t value, int length)
3802*7c478bd9Sstevel@tonic-gate {
3803*7c478bd9Sstevel@tonic-gate 	if (!(flag & DDI_PROP_CANSLEEP)) {
3804*7c478bd9Sstevel@tonic-gate 		flag |= DDI_PROP_DONTSLEEP;
3805*7c478bd9Sstevel@tonic-gate #ifdef DDI_PROP_DEBUG
3806*7c478bd9Sstevel@tonic-gate 		if (length != 0)
3807*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "!ddi_prop_create: interface obsolete,"
3808*7c478bd9Sstevel@tonic-gate 			    "use ddi_prop_update (prop = %s, node = %s%d)",
3809*7c478bd9Sstevel@tonic-gate 			    name, ddi_driver_name(dip), ddi_get_instance(dip));
3810*7c478bd9Sstevel@tonic-gate #endif /* DDI_PROP_DEBUG */
3811*7c478bd9Sstevel@tonic-gate 	}
3812*7c478bd9Sstevel@tonic-gate 	flag &= ~DDI_PROP_SYSTEM_DEF;
3813*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(dev, dip,
3814*7c478bd9Sstevel@tonic-gate 	    (flag | DDI_PROP_STACK_CREATE | DDI_PROP_TYPE_ANY), name,
3815*7c478bd9Sstevel@tonic-gate 	    value, length, ddi_prop_fm_encode_bytes));
3816*7c478bd9Sstevel@tonic-gate }
3817*7c478bd9Sstevel@tonic-gate 
3818*7c478bd9Sstevel@tonic-gate int
3819*7c478bd9Sstevel@tonic-gate e_ddi_prop_create(dev_t dev, dev_info_t *dip, int flag,
3820*7c478bd9Sstevel@tonic-gate     char *name, caddr_t value, int length)
3821*7c478bd9Sstevel@tonic-gate {
3822*7c478bd9Sstevel@tonic-gate 	if (!(flag & DDI_PROP_CANSLEEP))
3823*7c478bd9Sstevel@tonic-gate 		flag |= DDI_PROP_DONTSLEEP;
3824*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(dev, dip,
3825*7c478bd9Sstevel@tonic-gate 	    (flag | DDI_PROP_SYSTEM_DEF | DDI_PROP_STACK_CREATE |
3826*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_TYPE_ANY),
3827*7c478bd9Sstevel@tonic-gate 	    name, value, length, ddi_prop_fm_encode_bytes));
3828*7c478bd9Sstevel@tonic-gate }
3829*7c478bd9Sstevel@tonic-gate 
3830*7c478bd9Sstevel@tonic-gate int
3831*7c478bd9Sstevel@tonic-gate ddi_prop_modify(dev_t dev, dev_info_t *dip, int flag,
3832*7c478bd9Sstevel@tonic-gate     char *name, caddr_t value, int length)
3833*7c478bd9Sstevel@tonic-gate {
3834*7c478bd9Sstevel@tonic-gate 	ASSERT((flag & DDI_PROP_TYPE_MASK) == 0);
3835*7c478bd9Sstevel@tonic-gate 
3836*7c478bd9Sstevel@tonic-gate 	/*
3837*7c478bd9Sstevel@tonic-gate 	 * If dev_t is DDI_DEV_T_ANY or name's length is zero,
3838*7c478bd9Sstevel@tonic-gate 	 * return error.
3839*7c478bd9Sstevel@tonic-gate 	 */
3840*7c478bd9Sstevel@tonic-gate 	if (dev == DDI_DEV_T_ANY || name == NULL || strlen(name) == 0)
3841*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
3842*7c478bd9Sstevel@tonic-gate 
3843*7c478bd9Sstevel@tonic-gate 	if (!(flag & DDI_PROP_CANSLEEP))
3844*7c478bd9Sstevel@tonic-gate 		flag |= DDI_PROP_DONTSLEEP;
3845*7c478bd9Sstevel@tonic-gate 	flag &= ~DDI_PROP_SYSTEM_DEF;
3846*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_exists((dev == DDI_DEV_T_NONE) ? DDI_DEV_T_ANY : dev,
3847*7c478bd9Sstevel@tonic-gate 	    dip, (flag | DDI_PROP_NOTPROM), name) == 0)
3848*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
3849*7c478bd9Sstevel@tonic-gate 
3850*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(dev, dip,
3851*7c478bd9Sstevel@tonic-gate 	    (flag | DDI_PROP_TYPE_BYTE), name,
3852*7c478bd9Sstevel@tonic-gate 	    value, length, ddi_prop_fm_encode_bytes));
3853*7c478bd9Sstevel@tonic-gate }
3854*7c478bd9Sstevel@tonic-gate 
3855*7c478bd9Sstevel@tonic-gate int
3856*7c478bd9Sstevel@tonic-gate e_ddi_prop_modify(dev_t dev, dev_info_t *dip, int flag,
3857*7c478bd9Sstevel@tonic-gate     char *name, caddr_t value, int length)
3858*7c478bd9Sstevel@tonic-gate {
3859*7c478bd9Sstevel@tonic-gate 	ASSERT((flag & DDI_PROP_TYPE_MASK) == 0);
3860*7c478bd9Sstevel@tonic-gate 
3861*7c478bd9Sstevel@tonic-gate 	/*
3862*7c478bd9Sstevel@tonic-gate 	 * If dev_t is DDI_DEV_T_ANY or name's length is zero,
3863*7c478bd9Sstevel@tonic-gate 	 * return error.
3864*7c478bd9Sstevel@tonic-gate 	 */
3865*7c478bd9Sstevel@tonic-gate 	if (dev == DDI_DEV_T_ANY || name == NULL || strlen(name) == 0)
3866*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
3867*7c478bd9Sstevel@tonic-gate 
3868*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_exists((dev == DDI_DEV_T_NONE) ? DDI_DEV_T_ANY : dev,
3869*7c478bd9Sstevel@tonic-gate 	    dip, (flag | DDI_PROP_SYSTEM_DEF), name) == 0)
3870*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
3871*7c478bd9Sstevel@tonic-gate 
3872*7c478bd9Sstevel@tonic-gate 	if (!(flag & DDI_PROP_CANSLEEP))
3873*7c478bd9Sstevel@tonic-gate 		flag |= DDI_PROP_DONTSLEEP;
3874*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(dev, dip,
3875*7c478bd9Sstevel@tonic-gate 		(flag | DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_BYTE),
3876*7c478bd9Sstevel@tonic-gate 		name, value, length, ddi_prop_fm_encode_bytes));
3877*7c478bd9Sstevel@tonic-gate }
3878*7c478bd9Sstevel@tonic-gate 
3879*7c478bd9Sstevel@tonic-gate 
3880*7c478bd9Sstevel@tonic-gate /*
3881*7c478bd9Sstevel@tonic-gate  * Common lookup routine used to lookup and decode a property.
3882*7c478bd9Sstevel@tonic-gate  * Creates a property handle, searches for the raw encoded data,
3883*7c478bd9Sstevel@tonic-gate  * fills in the handle, and calls the property decode functions
3884*7c478bd9Sstevel@tonic-gate  * passed in.
3885*7c478bd9Sstevel@tonic-gate  *
3886*7c478bd9Sstevel@tonic-gate  * This routine is not static because ddi_bus_prop_op() which lives in
3887*7c478bd9Sstevel@tonic-gate  * ddi_impl.c calls it.  No driver should be calling this routine.
3888*7c478bd9Sstevel@tonic-gate  */
3889*7c478bd9Sstevel@tonic-gate int
3890*7c478bd9Sstevel@tonic-gate ddi_prop_lookup_common(dev_t match_dev, dev_info_t *dip,
3891*7c478bd9Sstevel@tonic-gate     uint_t flags, char *name, void *data, uint_t *nelements,
3892*7c478bd9Sstevel@tonic-gate     int (*prop_decoder)(prop_handle_t *, void *data, uint_t *nelements))
3893*7c478bd9Sstevel@tonic-gate {
3894*7c478bd9Sstevel@tonic-gate 	int		rval;
3895*7c478bd9Sstevel@tonic-gate 	uint_t		ourflags;
3896*7c478bd9Sstevel@tonic-gate 	prop_handle_t	ph;
3897*7c478bd9Sstevel@tonic-gate 
3898*7c478bd9Sstevel@tonic-gate 	if ((match_dev == DDI_DEV_T_NONE) ||
3899*7c478bd9Sstevel@tonic-gate 		(name == NULL) || (strlen(name) == 0))
3900*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
3901*7c478bd9Sstevel@tonic-gate 
3902*7c478bd9Sstevel@tonic-gate 	ourflags = (flags & DDI_PROP_DONTSLEEP) ? flags :
3903*7c478bd9Sstevel@tonic-gate 		flags | DDI_PROP_CANSLEEP;
3904*7c478bd9Sstevel@tonic-gate 
3905*7c478bd9Sstevel@tonic-gate 	/*
3906*7c478bd9Sstevel@tonic-gate 	 * Get the encoded data
3907*7c478bd9Sstevel@tonic-gate 	 */
3908*7c478bd9Sstevel@tonic-gate 	bzero(&ph, sizeof (prop_handle_t));
3909*7c478bd9Sstevel@tonic-gate 
3910*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_UNBND_DLPI2) {
3911*7c478bd9Sstevel@tonic-gate 		/*
3912*7c478bd9Sstevel@tonic-gate 		 * For unbound dlpi style-2 devices, index into
3913*7c478bd9Sstevel@tonic-gate 		 * the devnames' array and search the global
3914*7c478bd9Sstevel@tonic-gate 		 * property list.
3915*7c478bd9Sstevel@tonic-gate 		 */
3916*7c478bd9Sstevel@tonic-gate 		ourflags &= ~DDI_UNBND_DLPI2;
3917*7c478bd9Sstevel@tonic-gate 		rval = i_ddi_prop_search_global(match_dev,
3918*7c478bd9Sstevel@tonic-gate 		    ourflags, name, &ph.ph_data, &ph.ph_size);
3919*7c478bd9Sstevel@tonic-gate 	} else {
3920*7c478bd9Sstevel@tonic-gate 		rval = ddi_prop_search_common(match_dev, dip,
3921*7c478bd9Sstevel@tonic-gate 		    PROP_LEN_AND_VAL_ALLOC, ourflags, name,
3922*7c478bd9Sstevel@tonic-gate 		    &ph.ph_data, &ph.ph_size);
3923*7c478bd9Sstevel@tonic-gate 
3924*7c478bd9Sstevel@tonic-gate 	}
3925*7c478bd9Sstevel@tonic-gate 
3926*7c478bd9Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS && rval != DDI_PROP_FOUND_1275) {
3927*7c478bd9Sstevel@tonic-gate 		ASSERT(ph.ph_data == NULL);
3928*7c478bd9Sstevel@tonic-gate 		ASSERT(ph.ph_size == 0);
3929*7c478bd9Sstevel@tonic-gate 		return (rval);
3930*7c478bd9Sstevel@tonic-gate 	}
3931*7c478bd9Sstevel@tonic-gate 
3932*7c478bd9Sstevel@tonic-gate 	/*
3933*7c478bd9Sstevel@tonic-gate 	 * If the encoded data came from a OBP or software
3934*7c478bd9Sstevel@tonic-gate 	 * use the 1275 OBP decode/encode routines.
3935*7c478bd9Sstevel@tonic-gate 	 */
3936*7c478bd9Sstevel@tonic-gate 	ph.ph_cur_pos = ph.ph_data;
3937*7c478bd9Sstevel@tonic-gate 	ph.ph_save_pos = ph.ph_data;
3938*7c478bd9Sstevel@tonic-gate 	ph.ph_ops = &prop_1275_ops;
3939*7c478bd9Sstevel@tonic-gate 	ph.ph_flags = (rval == DDI_PROP_FOUND_1275) ? PH_FROM_PROM : 0;
3940*7c478bd9Sstevel@tonic-gate 
3941*7c478bd9Sstevel@tonic-gate 	rval = (*prop_decoder)(&ph, data, nelements);
3942*7c478bd9Sstevel@tonic-gate 
3943*7c478bd9Sstevel@tonic-gate 	/*
3944*7c478bd9Sstevel@tonic-gate 	 * Free the encoded data
3945*7c478bd9Sstevel@tonic-gate 	 */
3946*7c478bd9Sstevel@tonic-gate 	if (ph.ph_size != 0)
3947*7c478bd9Sstevel@tonic-gate 		kmem_free(ph.ph_data, ph.ph_size);
3948*7c478bd9Sstevel@tonic-gate 
3949*7c478bd9Sstevel@tonic-gate 	return (rval);
3950*7c478bd9Sstevel@tonic-gate }
3951*7c478bd9Sstevel@tonic-gate 
3952*7c478bd9Sstevel@tonic-gate /*
3953*7c478bd9Sstevel@tonic-gate  * Lookup and return an array of composite properties.  The driver must
3954*7c478bd9Sstevel@tonic-gate  * provide the decode routine.
3955*7c478bd9Sstevel@tonic-gate  */
3956*7c478bd9Sstevel@tonic-gate int
3957*7c478bd9Sstevel@tonic-gate ddi_prop_lookup(dev_t match_dev, dev_info_t *dip,
3958*7c478bd9Sstevel@tonic-gate     uint_t flags, char *name, void *data, uint_t *nelements,
3959*7c478bd9Sstevel@tonic-gate     int (*prop_decoder)(prop_handle_t *, void *data, uint_t *nelements))
3960*7c478bd9Sstevel@tonic-gate {
3961*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_lookup_common(match_dev, dip,
3962*7c478bd9Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_COMPOSITE), name,
3963*7c478bd9Sstevel@tonic-gate 	    data, nelements, prop_decoder));
3964*7c478bd9Sstevel@tonic-gate }
3965*7c478bd9Sstevel@tonic-gate 
3966*7c478bd9Sstevel@tonic-gate /*
3967*7c478bd9Sstevel@tonic-gate  * Return 1 if a property exists (no type checking done).
3968*7c478bd9Sstevel@tonic-gate  * Return 0 if it does not exist.
3969*7c478bd9Sstevel@tonic-gate  */
3970*7c478bd9Sstevel@tonic-gate int
3971*7c478bd9Sstevel@tonic-gate ddi_prop_exists(dev_t match_dev, dev_info_t *dip, uint_t flags, char *name)
3972*7c478bd9Sstevel@tonic-gate {
3973*7c478bd9Sstevel@tonic-gate 	int	i;
3974*7c478bd9Sstevel@tonic-gate 	uint_t	x = 0;
3975*7c478bd9Sstevel@tonic-gate 
3976*7c478bd9Sstevel@tonic-gate 	i = ddi_prop_search_common(match_dev, dip, PROP_EXISTS,
3977*7c478bd9Sstevel@tonic-gate 		flags | DDI_PROP_TYPE_MASK, name, NULL, &x);
3978*7c478bd9Sstevel@tonic-gate 	return (i == DDI_PROP_SUCCESS || i == DDI_PROP_FOUND_1275);
3979*7c478bd9Sstevel@tonic-gate }
3980*7c478bd9Sstevel@tonic-gate 
3981*7c478bd9Sstevel@tonic-gate 
3982*7c478bd9Sstevel@tonic-gate /*
3983*7c478bd9Sstevel@tonic-gate  * Update an array of composite properties.  The driver must
3984*7c478bd9Sstevel@tonic-gate  * provide the encode routine.
3985*7c478bd9Sstevel@tonic-gate  */
3986*7c478bd9Sstevel@tonic-gate int
3987*7c478bd9Sstevel@tonic-gate ddi_prop_update(dev_t match_dev, dev_info_t *dip,
3988*7c478bd9Sstevel@tonic-gate     char *name, void *data, uint_t nelements,
3989*7c478bd9Sstevel@tonic-gate     int (*prop_create)(prop_handle_t *, void *data, uint_t nelements))
3990*7c478bd9Sstevel@tonic-gate {
3991*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_COMPOSITE,
3992*7c478bd9Sstevel@tonic-gate 	    name, data, nelements, prop_create));
3993*7c478bd9Sstevel@tonic-gate }
3994*7c478bd9Sstevel@tonic-gate 
3995*7c478bd9Sstevel@tonic-gate /*
3996*7c478bd9Sstevel@tonic-gate  * Get a single integer or boolean property and return it.
3997*7c478bd9Sstevel@tonic-gate  * If the property does not exists, or cannot be decoded,
3998*7c478bd9Sstevel@tonic-gate  * then return the defvalue passed in.
3999*7c478bd9Sstevel@tonic-gate  *
4000*7c478bd9Sstevel@tonic-gate  * This routine always succeeds.
4001*7c478bd9Sstevel@tonic-gate  */
4002*7c478bd9Sstevel@tonic-gate int
4003*7c478bd9Sstevel@tonic-gate ddi_prop_get_int(dev_t match_dev, dev_info_t *dip, uint_t flags,
4004*7c478bd9Sstevel@tonic-gate     char *name, int defvalue)
4005*7c478bd9Sstevel@tonic-gate {
4006*7c478bd9Sstevel@tonic-gate 	int	data;
4007*7c478bd9Sstevel@tonic-gate 	uint_t	nelements;
4008*7c478bd9Sstevel@tonic-gate 	int	rval;
4009*7c478bd9Sstevel@tonic-gate 
4010*7c478bd9Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4011*7c478bd9Sstevel@tonic-gate 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
4012*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
4013*7c478bd9Sstevel@tonic-gate 		if (dip != NULL) {
4014*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "ddi_prop_get_int: invalid flag"
4015*7c478bd9Sstevel@tonic-gate 			    " 0x%x (prop = %s, node = %s%d)", flags,
4016*7c478bd9Sstevel@tonic-gate 			    name, ddi_driver_name(dip), ddi_get_instance(dip));
4017*7c478bd9Sstevel@tonic-gate 		}
4018*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4019*7c478bd9Sstevel@tonic-gate 		flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4020*7c478bd9Sstevel@tonic-gate 		    LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
4021*7c478bd9Sstevel@tonic-gate 	}
4022*7c478bd9Sstevel@tonic-gate 
4023*7c478bd9Sstevel@tonic-gate 	if ((rval = ddi_prop_lookup_common(match_dev, dip,
4024*7c478bd9Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_INT), name, &data, &nelements,
4025*7c478bd9Sstevel@tonic-gate 	    ddi_prop_fm_decode_int)) != DDI_PROP_SUCCESS) {
4026*7c478bd9Sstevel@tonic-gate 		if (rval == DDI_PROP_END_OF_DATA)
4027*7c478bd9Sstevel@tonic-gate 			data = 1;
4028*7c478bd9Sstevel@tonic-gate 		else
4029*7c478bd9Sstevel@tonic-gate 			data = defvalue;
4030*7c478bd9Sstevel@tonic-gate 	}
4031*7c478bd9Sstevel@tonic-gate 	return (data);
4032*7c478bd9Sstevel@tonic-gate }
4033*7c478bd9Sstevel@tonic-gate 
4034*7c478bd9Sstevel@tonic-gate /*
4035*7c478bd9Sstevel@tonic-gate  * Get a single 64 bit integer or boolean property and return it.
4036*7c478bd9Sstevel@tonic-gate  * If the property does not exists, or cannot be decoded,
4037*7c478bd9Sstevel@tonic-gate  * then return the defvalue passed in.
4038*7c478bd9Sstevel@tonic-gate  *
4039*7c478bd9Sstevel@tonic-gate  * This routine always succeeds.
4040*7c478bd9Sstevel@tonic-gate  */
4041*7c478bd9Sstevel@tonic-gate int64_t
4042*7c478bd9Sstevel@tonic-gate ddi_prop_get_int64(dev_t match_dev, dev_info_t *dip, uint_t flags,
4043*7c478bd9Sstevel@tonic-gate     char *name, int64_t defvalue)
4044*7c478bd9Sstevel@tonic-gate {
4045*7c478bd9Sstevel@tonic-gate 	int64_t	data;
4046*7c478bd9Sstevel@tonic-gate 	uint_t	nelements;
4047*7c478bd9Sstevel@tonic-gate 	int	rval;
4048*7c478bd9Sstevel@tonic-gate 
4049*7c478bd9Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4050*7c478bd9Sstevel@tonic-gate 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
4051*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
4052*7c478bd9Sstevel@tonic-gate 		if (dip != NULL) {
4053*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "ddi_prop_get_int64: invalid flag"
4054*7c478bd9Sstevel@tonic-gate 			    " 0x%x (prop = %s, node = %s%d)", flags,
4055*7c478bd9Sstevel@tonic-gate 			    name, ddi_driver_name(dip), ddi_get_instance(dip));
4056*7c478bd9Sstevel@tonic-gate 		}
4057*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4058*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
4059*7c478bd9Sstevel@tonic-gate 	}
4060*7c478bd9Sstevel@tonic-gate 
4061*7c478bd9Sstevel@tonic-gate 	if ((rval = ddi_prop_lookup_common(match_dev, dip,
4062*7c478bd9Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_INT64 | DDI_PROP_NOTPROM),
4063*7c478bd9Sstevel@tonic-gate 	    name, &data, &nelements, ddi_prop_fm_decode_int64))
4064*7c478bd9Sstevel@tonic-gate 	    != DDI_PROP_SUCCESS) {
4065*7c478bd9Sstevel@tonic-gate 		if (rval == DDI_PROP_END_OF_DATA)
4066*7c478bd9Sstevel@tonic-gate 			data = 1;
4067*7c478bd9Sstevel@tonic-gate 		else
4068*7c478bd9Sstevel@tonic-gate 			data = defvalue;
4069*7c478bd9Sstevel@tonic-gate 	}
4070*7c478bd9Sstevel@tonic-gate 	return (data);
4071*7c478bd9Sstevel@tonic-gate }
4072*7c478bd9Sstevel@tonic-gate 
4073*7c478bd9Sstevel@tonic-gate /*
4074*7c478bd9Sstevel@tonic-gate  * Get an array of integer property
4075*7c478bd9Sstevel@tonic-gate  */
4076*7c478bd9Sstevel@tonic-gate int
4077*7c478bd9Sstevel@tonic-gate ddi_prop_lookup_int_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
4078*7c478bd9Sstevel@tonic-gate     char *name, int **data, uint_t *nelements)
4079*7c478bd9Sstevel@tonic-gate {
4080*7c478bd9Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4081*7c478bd9Sstevel@tonic-gate 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
4082*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
4083*7c478bd9Sstevel@tonic-gate 		if (dip != NULL) {
4084*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "ddi_prop_lookup_int_array: "
4085*7c478bd9Sstevel@tonic-gate 			    "invalid flag 0x%x (prop = %s, node = %s%d)",
4086*7c478bd9Sstevel@tonic-gate 			    flags, name, ddi_driver_name(dip),
4087*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(dip));
4088*7c478bd9Sstevel@tonic-gate 		}
4089*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4090*7c478bd9Sstevel@tonic-gate 		flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4091*7c478bd9Sstevel@tonic-gate 		LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
4092*7c478bd9Sstevel@tonic-gate 	}
4093*7c478bd9Sstevel@tonic-gate 
4094*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_lookup_common(match_dev, dip,
4095*7c478bd9Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_INT), name, data,
4096*7c478bd9Sstevel@tonic-gate 	    nelements, ddi_prop_fm_decode_ints));
4097*7c478bd9Sstevel@tonic-gate }
4098*7c478bd9Sstevel@tonic-gate 
4099*7c478bd9Sstevel@tonic-gate /*
4100*7c478bd9Sstevel@tonic-gate  * Get an array of 64 bit integer properties
4101*7c478bd9Sstevel@tonic-gate  */
4102*7c478bd9Sstevel@tonic-gate int
4103*7c478bd9Sstevel@tonic-gate ddi_prop_lookup_int64_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
4104*7c478bd9Sstevel@tonic-gate     char *name, int64_t **data, uint_t *nelements)
4105*7c478bd9Sstevel@tonic-gate {
4106*7c478bd9Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4107*7c478bd9Sstevel@tonic-gate 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
4108*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
4109*7c478bd9Sstevel@tonic-gate 		if (dip != NULL) {
4110*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "ddi_prop_lookup_int64_array: "
4111*7c478bd9Sstevel@tonic-gate 			    "invalid flag 0x%x (prop = %s, node = %s%d)",
4112*7c478bd9Sstevel@tonic-gate 			    flags, name, ddi_driver_name(dip),
4113*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(dip));
4114*7c478bd9Sstevel@tonic-gate 		}
4115*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4116*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
4117*7c478bd9Sstevel@tonic-gate 	}
4118*7c478bd9Sstevel@tonic-gate 
4119*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_lookup_common(match_dev, dip,
4120*7c478bd9Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_INT64 | DDI_PROP_NOTPROM),
4121*7c478bd9Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_decode_int64_array));
4122*7c478bd9Sstevel@tonic-gate }
4123*7c478bd9Sstevel@tonic-gate 
4124*7c478bd9Sstevel@tonic-gate /*
4125*7c478bd9Sstevel@tonic-gate  * Update a single integer property.  If the property exists on the drivers
4126*7c478bd9Sstevel@tonic-gate  * property list it updates, else it creates it.
4127*7c478bd9Sstevel@tonic-gate  */
4128*7c478bd9Sstevel@tonic-gate int
4129*7c478bd9Sstevel@tonic-gate ddi_prop_update_int(dev_t match_dev, dev_info_t *dip,
4130*7c478bd9Sstevel@tonic-gate     char *name, int data)
4131*7c478bd9Sstevel@tonic-gate {
4132*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT,
4133*7c478bd9Sstevel@tonic-gate 	    name, &data, 1, ddi_prop_fm_encode_ints));
4134*7c478bd9Sstevel@tonic-gate }
4135*7c478bd9Sstevel@tonic-gate 
4136*7c478bd9Sstevel@tonic-gate /*
4137*7c478bd9Sstevel@tonic-gate  * Update a single 64 bit integer property.
4138*7c478bd9Sstevel@tonic-gate  * Update the driver property list if it exists, else create it.
4139*7c478bd9Sstevel@tonic-gate  */
4140*7c478bd9Sstevel@tonic-gate int
4141*7c478bd9Sstevel@tonic-gate ddi_prop_update_int64(dev_t match_dev, dev_info_t *dip,
4142*7c478bd9Sstevel@tonic-gate     char *name, int64_t data)
4143*7c478bd9Sstevel@tonic-gate {
4144*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT64,
4145*7c478bd9Sstevel@tonic-gate 	    name, &data, 1, ddi_prop_fm_encode_int64));
4146*7c478bd9Sstevel@tonic-gate }
4147*7c478bd9Sstevel@tonic-gate 
4148*7c478bd9Sstevel@tonic-gate int
4149*7c478bd9Sstevel@tonic-gate e_ddi_prop_update_int(dev_t match_dev, dev_info_t *dip,
4150*7c478bd9Sstevel@tonic-gate     char *name, int data)
4151*7c478bd9Sstevel@tonic-gate {
4152*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
4153*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT,
4154*7c478bd9Sstevel@tonic-gate 	    name, &data, 1, ddi_prop_fm_encode_ints));
4155*7c478bd9Sstevel@tonic-gate }
4156*7c478bd9Sstevel@tonic-gate 
4157*7c478bd9Sstevel@tonic-gate int
4158*7c478bd9Sstevel@tonic-gate e_ddi_prop_update_int64(dev_t match_dev, dev_info_t *dip,
4159*7c478bd9Sstevel@tonic-gate     char *name, int64_t data)
4160*7c478bd9Sstevel@tonic-gate {
4161*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
4162*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT64,
4163*7c478bd9Sstevel@tonic-gate 	    name, &data, 1, ddi_prop_fm_encode_int64));
4164*7c478bd9Sstevel@tonic-gate }
4165*7c478bd9Sstevel@tonic-gate 
4166*7c478bd9Sstevel@tonic-gate /*
4167*7c478bd9Sstevel@tonic-gate  * Update an array of integer property.  If the property exists on the drivers
4168*7c478bd9Sstevel@tonic-gate  * property list it updates, else it creates it.
4169*7c478bd9Sstevel@tonic-gate  */
4170*7c478bd9Sstevel@tonic-gate int
4171*7c478bd9Sstevel@tonic-gate ddi_prop_update_int_array(dev_t match_dev, dev_info_t *dip,
4172*7c478bd9Sstevel@tonic-gate     char *name, int *data, uint_t nelements)
4173*7c478bd9Sstevel@tonic-gate {
4174*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT,
4175*7c478bd9Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_encode_ints));
4176*7c478bd9Sstevel@tonic-gate }
4177*7c478bd9Sstevel@tonic-gate 
4178*7c478bd9Sstevel@tonic-gate /*
4179*7c478bd9Sstevel@tonic-gate  * Update an array of 64 bit integer properties.
4180*7c478bd9Sstevel@tonic-gate  * Update the driver property list if it exists, else create it.
4181*7c478bd9Sstevel@tonic-gate  */
4182*7c478bd9Sstevel@tonic-gate int
4183*7c478bd9Sstevel@tonic-gate ddi_prop_update_int64_array(dev_t match_dev, dev_info_t *dip,
4184*7c478bd9Sstevel@tonic-gate     char *name, int64_t *data, uint_t nelements)
4185*7c478bd9Sstevel@tonic-gate {
4186*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT64,
4187*7c478bd9Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_encode_int64));
4188*7c478bd9Sstevel@tonic-gate }
4189*7c478bd9Sstevel@tonic-gate 
4190*7c478bd9Sstevel@tonic-gate int
4191*7c478bd9Sstevel@tonic-gate e_ddi_prop_update_int64_array(dev_t match_dev, dev_info_t *dip,
4192*7c478bd9Sstevel@tonic-gate     char *name, int64_t *data, uint_t nelements)
4193*7c478bd9Sstevel@tonic-gate {
4194*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
4195*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT64,
4196*7c478bd9Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_encode_int64));
4197*7c478bd9Sstevel@tonic-gate }
4198*7c478bd9Sstevel@tonic-gate 
4199*7c478bd9Sstevel@tonic-gate int
4200*7c478bd9Sstevel@tonic-gate e_ddi_prop_update_int_array(dev_t match_dev, dev_info_t *dip,
4201*7c478bd9Sstevel@tonic-gate     char *name, int *data, uint_t nelements)
4202*7c478bd9Sstevel@tonic-gate {
4203*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
4204*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT,
4205*7c478bd9Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_encode_ints));
4206*7c478bd9Sstevel@tonic-gate }
4207*7c478bd9Sstevel@tonic-gate 
4208*7c478bd9Sstevel@tonic-gate /*
4209*7c478bd9Sstevel@tonic-gate  * Get a single string property.
4210*7c478bd9Sstevel@tonic-gate  */
4211*7c478bd9Sstevel@tonic-gate int
4212*7c478bd9Sstevel@tonic-gate ddi_prop_lookup_string(dev_t match_dev, dev_info_t *dip, uint_t flags,
4213*7c478bd9Sstevel@tonic-gate     char *name, char **data)
4214*7c478bd9Sstevel@tonic-gate {
4215*7c478bd9Sstevel@tonic-gate 	uint_t x;
4216*7c478bd9Sstevel@tonic-gate 
4217*7c478bd9Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4218*7c478bd9Sstevel@tonic-gate 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
4219*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
4220*7c478bd9Sstevel@tonic-gate 		if (dip != NULL) {
4221*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s: invalid flag 0x%x "
4222*7c478bd9Sstevel@tonic-gate 			    "(prop = %s, node = %s%d); invalid bits ignored",
4223*7c478bd9Sstevel@tonic-gate 			    "ddi_prop_lookup_string", flags, name,
4224*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip));
4225*7c478bd9Sstevel@tonic-gate 		}
4226*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4227*7c478bd9Sstevel@tonic-gate 		flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4228*7c478bd9Sstevel@tonic-gate 		    LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
4229*7c478bd9Sstevel@tonic-gate 	}
4230*7c478bd9Sstevel@tonic-gate 
4231*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_lookup_common(match_dev, dip,
4232*7c478bd9Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_STRING), name, data,
4233*7c478bd9Sstevel@tonic-gate 	    &x, ddi_prop_fm_decode_string));
4234*7c478bd9Sstevel@tonic-gate }
4235*7c478bd9Sstevel@tonic-gate 
4236*7c478bd9Sstevel@tonic-gate /*
4237*7c478bd9Sstevel@tonic-gate  * Get an array of strings property.
4238*7c478bd9Sstevel@tonic-gate  */
4239*7c478bd9Sstevel@tonic-gate int
4240*7c478bd9Sstevel@tonic-gate ddi_prop_lookup_string_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
4241*7c478bd9Sstevel@tonic-gate     char *name, char ***data, uint_t *nelements)
4242*7c478bd9Sstevel@tonic-gate {
4243*7c478bd9Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4244*7c478bd9Sstevel@tonic-gate 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
4245*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
4246*7c478bd9Sstevel@tonic-gate 		if (dip != NULL) {
4247*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "ddi_prop_lookup_string_array: "
4248*7c478bd9Sstevel@tonic-gate 			    "invalid flag 0x%x (prop = %s, node = %s%d)",
4249*7c478bd9Sstevel@tonic-gate 			    flags, name, ddi_driver_name(dip),
4250*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(dip));
4251*7c478bd9Sstevel@tonic-gate 		}
4252*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4253*7c478bd9Sstevel@tonic-gate 		flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4254*7c478bd9Sstevel@tonic-gate 		    LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
4255*7c478bd9Sstevel@tonic-gate 	}
4256*7c478bd9Sstevel@tonic-gate 
4257*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_lookup_common(match_dev, dip,
4258*7c478bd9Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_STRING), name, data,
4259*7c478bd9Sstevel@tonic-gate 	    nelements, ddi_prop_fm_decode_strings));
4260*7c478bd9Sstevel@tonic-gate }
4261*7c478bd9Sstevel@tonic-gate 
4262*7c478bd9Sstevel@tonic-gate /*
4263*7c478bd9Sstevel@tonic-gate  * Update a single string property.
4264*7c478bd9Sstevel@tonic-gate  */
4265*7c478bd9Sstevel@tonic-gate int
4266*7c478bd9Sstevel@tonic-gate ddi_prop_update_string(dev_t match_dev, dev_info_t *dip,
4267*7c478bd9Sstevel@tonic-gate     char *name, char *data)
4268*7c478bd9Sstevel@tonic-gate {
4269*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
4270*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_TYPE_STRING, name, &data, 1,
4271*7c478bd9Sstevel@tonic-gate 	    ddi_prop_fm_encode_string));
4272*7c478bd9Sstevel@tonic-gate }
4273*7c478bd9Sstevel@tonic-gate 
4274*7c478bd9Sstevel@tonic-gate int
4275*7c478bd9Sstevel@tonic-gate e_ddi_prop_update_string(dev_t match_dev, dev_info_t *dip,
4276*7c478bd9Sstevel@tonic-gate     char *name, char *data)
4277*7c478bd9Sstevel@tonic-gate {
4278*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
4279*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_STRING,
4280*7c478bd9Sstevel@tonic-gate 	    name, &data, 1, ddi_prop_fm_encode_string));
4281*7c478bd9Sstevel@tonic-gate }
4282*7c478bd9Sstevel@tonic-gate 
4283*7c478bd9Sstevel@tonic-gate 
4284*7c478bd9Sstevel@tonic-gate /*
4285*7c478bd9Sstevel@tonic-gate  * Update an array of strings property.
4286*7c478bd9Sstevel@tonic-gate  */
4287*7c478bd9Sstevel@tonic-gate int
4288*7c478bd9Sstevel@tonic-gate ddi_prop_update_string_array(dev_t match_dev, dev_info_t *dip,
4289*7c478bd9Sstevel@tonic-gate     char *name, char **data, uint_t nelements)
4290*7c478bd9Sstevel@tonic-gate {
4291*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
4292*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_TYPE_STRING, name, data, nelements,
4293*7c478bd9Sstevel@tonic-gate 	    ddi_prop_fm_encode_strings));
4294*7c478bd9Sstevel@tonic-gate }
4295*7c478bd9Sstevel@tonic-gate 
4296*7c478bd9Sstevel@tonic-gate int
4297*7c478bd9Sstevel@tonic-gate e_ddi_prop_update_string_array(dev_t match_dev, dev_info_t *dip,
4298*7c478bd9Sstevel@tonic-gate     char *name, char **data, uint_t nelements)
4299*7c478bd9Sstevel@tonic-gate {
4300*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
4301*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_STRING,
4302*7c478bd9Sstevel@tonic-gate 	    name, data, nelements,
4303*7c478bd9Sstevel@tonic-gate 	    ddi_prop_fm_encode_strings));
4304*7c478bd9Sstevel@tonic-gate }
4305*7c478bd9Sstevel@tonic-gate 
4306*7c478bd9Sstevel@tonic-gate 
4307*7c478bd9Sstevel@tonic-gate /*
4308*7c478bd9Sstevel@tonic-gate  * Get an array of bytes property.
4309*7c478bd9Sstevel@tonic-gate  */
4310*7c478bd9Sstevel@tonic-gate int
4311*7c478bd9Sstevel@tonic-gate ddi_prop_lookup_byte_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
4312*7c478bd9Sstevel@tonic-gate     char *name, uchar_t **data, uint_t *nelements)
4313*7c478bd9Sstevel@tonic-gate {
4314*7c478bd9Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4315*7c478bd9Sstevel@tonic-gate 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
4316*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
4317*7c478bd9Sstevel@tonic-gate 		if (dip != NULL) {
4318*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "ddi_prop_lookup_byte_array: "
4319*7c478bd9Sstevel@tonic-gate 			    " invalid flag 0x%x (prop = %s, node = %s%d)",
4320*7c478bd9Sstevel@tonic-gate 			    flags, name, ddi_driver_name(dip),
4321*7c478bd9Sstevel@tonic-gate 			    ddi_get_instance(dip));
4322*7c478bd9Sstevel@tonic-gate 		}
4323*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
4324*7c478bd9Sstevel@tonic-gate 		flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
4325*7c478bd9Sstevel@tonic-gate 		    LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
4326*7c478bd9Sstevel@tonic-gate 	}
4327*7c478bd9Sstevel@tonic-gate 
4328*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_lookup_common(match_dev, dip,
4329*7c478bd9Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_BYTE), name, data,
4330*7c478bd9Sstevel@tonic-gate 	    nelements, ddi_prop_fm_decode_bytes));
4331*7c478bd9Sstevel@tonic-gate }
4332*7c478bd9Sstevel@tonic-gate 
4333*7c478bd9Sstevel@tonic-gate /*
4334*7c478bd9Sstevel@tonic-gate  * Update an array of bytes property.
4335*7c478bd9Sstevel@tonic-gate  */
4336*7c478bd9Sstevel@tonic-gate int
4337*7c478bd9Sstevel@tonic-gate ddi_prop_update_byte_array(dev_t match_dev, dev_info_t *dip,
4338*7c478bd9Sstevel@tonic-gate     char *name, uchar_t *data, uint_t nelements)
4339*7c478bd9Sstevel@tonic-gate {
4340*7c478bd9Sstevel@tonic-gate 	if (nelements == 0)
4341*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
4342*7c478bd9Sstevel@tonic-gate 
4343*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_BYTE,
4344*7c478bd9Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_encode_bytes));
4345*7c478bd9Sstevel@tonic-gate }
4346*7c478bd9Sstevel@tonic-gate 
4347*7c478bd9Sstevel@tonic-gate 
4348*7c478bd9Sstevel@tonic-gate int
4349*7c478bd9Sstevel@tonic-gate e_ddi_prop_update_byte_array(dev_t match_dev, dev_info_t *dip,
4350*7c478bd9Sstevel@tonic-gate     char *name, uchar_t *data, uint_t nelements)
4351*7c478bd9Sstevel@tonic-gate {
4352*7c478bd9Sstevel@tonic-gate 	if (nelements == 0)
4353*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
4354*7c478bd9Sstevel@tonic-gate 
4355*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
4356*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_BYTE,
4357*7c478bd9Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_encode_bytes));
4358*7c478bd9Sstevel@tonic-gate }
4359*7c478bd9Sstevel@tonic-gate 
4360*7c478bd9Sstevel@tonic-gate 
4361*7c478bd9Sstevel@tonic-gate /*
4362*7c478bd9Sstevel@tonic-gate  * ddi_prop_remove_common:	Undefine a managed property:
4363*7c478bd9Sstevel@tonic-gate  *			Input dev_t must match dev_t when defined.
4364*7c478bd9Sstevel@tonic-gate  *			Returns DDI_PROP_NOT_FOUND, possibly.
4365*7c478bd9Sstevel@tonic-gate  *			DDI_PROP_INVAL_ARG is also possible if dev is
4366*7c478bd9Sstevel@tonic-gate  *			DDI_DEV_T_ANY or incoming name is the NULL string.
4367*7c478bd9Sstevel@tonic-gate  */
4368*7c478bd9Sstevel@tonic-gate int
4369*7c478bd9Sstevel@tonic-gate ddi_prop_remove_common(dev_t dev, dev_info_t *dip, char *name, int flag)
4370*7c478bd9Sstevel@tonic-gate {
4371*7c478bd9Sstevel@tonic-gate 	ddi_prop_t	**list_head = &(DEVI(dip)->devi_drv_prop_ptr);
4372*7c478bd9Sstevel@tonic-gate 	ddi_prop_t	*propp;
4373*7c478bd9Sstevel@tonic-gate 	ddi_prop_t	*lastpropp = NULL;
4374*7c478bd9Sstevel@tonic-gate 
4375*7c478bd9Sstevel@tonic-gate 	if ((dev == DDI_DEV_T_ANY) || (name == (char *)0) ||
4376*7c478bd9Sstevel@tonic-gate 	    (strlen(name) == 0)) {
4377*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
4378*7c478bd9Sstevel@tonic-gate 	}
4379*7c478bd9Sstevel@tonic-gate 
4380*7c478bd9Sstevel@tonic-gate 	if (flag & DDI_PROP_SYSTEM_DEF)
4381*7c478bd9Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_sys_prop_ptr);
4382*7c478bd9Sstevel@tonic-gate 	else if (flag & DDI_PROP_HW_DEF)
4383*7c478bd9Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_hw_prop_ptr);
4384*7c478bd9Sstevel@tonic-gate 
4385*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
4386*7c478bd9Sstevel@tonic-gate 
4387*7c478bd9Sstevel@tonic-gate 	for (propp = *list_head; propp != NULL; propp = propp->prop_next)  {
4388*7c478bd9Sstevel@tonic-gate 		if ((strcmp(name, propp->prop_name) == 0) &&
4389*7c478bd9Sstevel@tonic-gate 		    (dev == propp->prop_dev)) {
4390*7c478bd9Sstevel@tonic-gate 			/*
4391*7c478bd9Sstevel@tonic-gate 			 * Unlink this propp allowing for it to
4392*7c478bd9Sstevel@tonic-gate 			 * be first in the list:
4393*7c478bd9Sstevel@tonic-gate 			 */
4394*7c478bd9Sstevel@tonic-gate 
4395*7c478bd9Sstevel@tonic-gate 			if (lastpropp == NULL)
4396*7c478bd9Sstevel@tonic-gate 				*list_head = propp->prop_next;
4397*7c478bd9Sstevel@tonic-gate 			else
4398*7c478bd9Sstevel@tonic-gate 				lastpropp->prop_next = propp->prop_next;
4399*7c478bd9Sstevel@tonic-gate 
4400*7c478bd9Sstevel@tonic-gate 			mutex_exit(&(DEVI(dip)->devi_lock));
4401*7c478bd9Sstevel@tonic-gate 
4402*7c478bd9Sstevel@tonic-gate 			/*
4403*7c478bd9Sstevel@tonic-gate 			 * Free memory and return...
4404*7c478bd9Sstevel@tonic-gate 			 */
4405*7c478bd9Sstevel@tonic-gate 			kmem_free(propp->prop_name,
4406*7c478bd9Sstevel@tonic-gate 			    strlen(propp->prop_name) + 1);
4407*7c478bd9Sstevel@tonic-gate 			if (propp->prop_len != 0)
4408*7c478bd9Sstevel@tonic-gate 				kmem_free(propp->prop_val, propp->prop_len);
4409*7c478bd9Sstevel@tonic-gate 			kmem_free(propp, sizeof (ddi_prop_t));
4410*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_SUCCESS);
4411*7c478bd9Sstevel@tonic-gate 		}
4412*7c478bd9Sstevel@tonic-gate 		lastpropp = propp;
4413*7c478bd9Sstevel@tonic-gate 	}
4414*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
4415*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_NOT_FOUND);
4416*7c478bd9Sstevel@tonic-gate }
4417*7c478bd9Sstevel@tonic-gate 
4418*7c478bd9Sstevel@tonic-gate int
4419*7c478bd9Sstevel@tonic-gate ddi_prop_remove(dev_t dev, dev_info_t *dip, char *name)
4420*7c478bd9Sstevel@tonic-gate {
4421*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_remove_common(dev, dip, name, 0));
4422*7c478bd9Sstevel@tonic-gate }
4423*7c478bd9Sstevel@tonic-gate 
4424*7c478bd9Sstevel@tonic-gate int
4425*7c478bd9Sstevel@tonic-gate e_ddi_prop_remove(dev_t dev, dev_info_t *dip, char *name)
4426*7c478bd9Sstevel@tonic-gate {
4427*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_remove_common(dev, dip, name, DDI_PROP_SYSTEM_DEF));
4428*7c478bd9Sstevel@tonic-gate }
4429*7c478bd9Sstevel@tonic-gate 
4430*7c478bd9Sstevel@tonic-gate /*
4431*7c478bd9Sstevel@tonic-gate  * e_ddi_prop_list_delete: remove a list of properties
4432*7c478bd9Sstevel@tonic-gate  *	Note that the caller needs to provide the required protection
4433*7c478bd9Sstevel@tonic-gate  *	(eg. devi_lock if these properties are still attached to a devi)
4434*7c478bd9Sstevel@tonic-gate  */
4435*7c478bd9Sstevel@tonic-gate void
4436*7c478bd9Sstevel@tonic-gate e_ddi_prop_list_delete(ddi_prop_t *props)
4437*7c478bd9Sstevel@tonic-gate {
4438*7c478bd9Sstevel@tonic-gate 	i_ddi_prop_list_delete(props);
4439*7c478bd9Sstevel@tonic-gate }
4440*7c478bd9Sstevel@tonic-gate 
4441*7c478bd9Sstevel@tonic-gate /*
4442*7c478bd9Sstevel@tonic-gate  * ddi_prop_remove_all_common:
4443*7c478bd9Sstevel@tonic-gate  *	Used before unloading a driver to remove
4444*7c478bd9Sstevel@tonic-gate  *	all properties. (undefines all dev_t's props.)
4445*7c478bd9Sstevel@tonic-gate  *	Also removes `explicitly undefined' props.
4446*7c478bd9Sstevel@tonic-gate  *	No errors possible.
4447*7c478bd9Sstevel@tonic-gate  */
4448*7c478bd9Sstevel@tonic-gate void
4449*7c478bd9Sstevel@tonic-gate ddi_prop_remove_all_common(dev_info_t *dip, int flag)
4450*7c478bd9Sstevel@tonic-gate {
4451*7c478bd9Sstevel@tonic-gate 	ddi_prop_t	**list_head;
4452*7c478bd9Sstevel@tonic-gate 
4453*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
4454*7c478bd9Sstevel@tonic-gate 	if (flag & DDI_PROP_SYSTEM_DEF) {
4455*7c478bd9Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_sys_prop_ptr);
4456*7c478bd9Sstevel@tonic-gate 	} else if (flag & DDI_PROP_HW_DEF) {
4457*7c478bd9Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_hw_prop_ptr);
4458*7c478bd9Sstevel@tonic-gate 	} else {
4459*7c478bd9Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_drv_prop_ptr);
4460*7c478bd9Sstevel@tonic-gate 	}
4461*7c478bd9Sstevel@tonic-gate 	i_ddi_prop_list_delete(*list_head);
4462*7c478bd9Sstevel@tonic-gate 	*list_head = NULL;
4463*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
4464*7c478bd9Sstevel@tonic-gate }
4465*7c478bd9Sstevel@tonic-gate 
4466*7c478bd9Sstevel@tonic-gate 
4467*7c478bd9Sstevel@tonic-gate /*
4468*7c478bd9Sstevel@tonic-gate  * ddi_prop_remove_all:		Remove all driver prop definitions.
4469*7c478bd9Sstevel@tonic-gate  */
4470*7c478bd9Sstevel@tonic-gate 
4471*7c478bd9Sstevel@tonic-gate void
4472*7c478bd9Sstevel@tonic-gate ddi_prop_remove_all(dev_info_t *dip)
4473*7c478bd9Sstevel@tonic-gate {
4474*7c478bd9Sstevel@tonic-gate 	ddi_prop_remove_all_common(dip, 0);
4475*7c478bd9Sstevel@tonic-gate }
4476*7c478bd9Sstevel@tonic-gate 
4477*7c478bd9Sstevel@tonic-gate /*
4478*7c478bd9Sstevel@tonic-gate  * e_ddi_prop_remove_all:	Remove all system prop definitions.
4479*7c478bd9Sstevel@tonic-gate  */
4480*7c478bd9Sstevel@tonic-gate 
4481*7c478bd9Sstevel@tonic-gate void
4482*7c478bd9Sstevel@tonic-gate e_ddi_prop_remove_all(dev_info_t *dip)
4483*7c478bd9Sstevel@tonic-gate {
4484*7c478bd9Sstevel@tonic-gate 	ddi_prop_remove_all_common(dip, (int)DDI_PROP_SYSTEM_DEF);
4485*7c478bd9Sstevel@tonic-gate }
4486*7c478bd9Sstevel@tonic-gate 
4487*7c478bd9Sstevel@tonic-gate 
4488*7c478bd9Sstevel@tonic-gate /*
4489*7c478bd9Sstevel@tonic-gate  * ddi_prop_undefine:	Explicitly undefine a property.  Property
4490*7c478bd9Sstevel@tonic-gate  *			searches which match this property return
4491*7c478bd9Sstevel@tonic-gate  *			the error code DDI_PROP_UNDEFINED.
4492*7c478bd9Sstevel@tonic-gate  *
4493*7c478bd9Sstevel@tonic-gate  *			Use ddi_prop_remove to negate effect of
4494*7c478bd9Sstevel@tonic-gate  *			ddi_prop_undefine
4495*7c478bd9Sstevel@tonic-gate  *
4496*7c478bd9Sstevel@tonic-gate  *			See above for error returns.
4497*7c478bd9Sstevel@tonic-gate  */
4498*7c478bd9Sstevel@tonic-gate 
4499*7c478bd9Sstevel@tonic-gate int
4500*7c478bd9Sstevel@tonic-gate ddi_prop_undefine(dev_t dev, dev_info_t *dip, int flag, char *name)
4501*7c478bd9Sstevel@tonic-gate {
4502*7c478bd9Sstevel@tonic-gate 	if (!(flag & DDI_PROP_CANSLEEP))
4503*7c478bd9Sstevel@tonic-gate 		flag |= DDI_PROP_DONTSLEEP;
4504*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(dev, dip,
4505*7c478bd9Sstevel@tonic-gate 	    (flag | DDI_PROP_STACK_CREATE | DDI_PROP_UNDEF_IT |
4506*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_TYPE_ANY), name, NULL, 0, ddi_prop_fm_encode_bytes));
4507*7c478bd9Sstevel@tonic-gate }
4508*7c478bd9Sstevel@tonic-gate 
4509*7c478bd9Sstevel@tonic-gate int
4510*7c478bd9Sstevel@tonic-gate e_ddi_prop_undefine(dev_t dev, dev_info_t *dip, int flag, char *name)
4511*7c478bd9Sstevel@tonic-gate {
4512*7c478bd9Sstevel@tonic-gate 	if (!(flag & DDI_PROP_CANSLEEP))
4513*7c478bd9Sstevel@tonic-gate 		flag |= DDI_PROP_DONTSLEEP;
4514*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_update_common(dev, dip,
4515*7c478bd9Sstevel@tonic-gate 	    (flag | DDI_PROP_SYSTEM_DEF | DDI_PROP_STACK_CREATE |
4516*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_UNDEF_IT | DDI_PROP_TYPE_ANY),
4517*7c478bd9Sstevel@tonic-gate 	    name, NULL, 0, ddi_prop_fm_encode_bytes));
4518*7c478bd9Sstevel@tonic-gate }
4519*7c478bd9Sstevel@tonic-gate 
4520*7c478bd9Sstevel@tonic-gate /*
4521*7c478bd9Sstevel@tonic-gate  * Code to search hardware layer (PROM), if it exists, on behalf of child.
4522*7c478bd9Sstevel@tonic-gate  *
4523*7c478bd9Sstevel@tonic-gate  * if input dip != child_dip, then call is on behalf of child
4524*7c478bd9Sstevel@tonic-gate  * to search PROM, do it via ddi_prop_search_common() and ascend only
4525*7c478bd9Sstevel@tonic-gate  * if allowed.
4526*7c478bd9Sstevel@tonic-gate  *
4527*7c478bd9Sstevel@tonic-gate  * if input dip == ch_dip (child_dip), call is on behalf of root driver,
4528*7c478bd9Sstevel@tonic-gate  * to search for PROM defined props only.
4529*7c478bd9Sstevel@tonic-gate  *
4530*7c478bd9Sstevel@tonic-gate  * Note that the PROM search is done only if the requested dev
4531*7c478bd9Sstevel@tonic-gate  * is either DDI_DEV_T_ANY or DDI_DEV_T_NONE. PROM properties
4532*7c478bd9Sstevel@tonic-gate  * have no associated dev, thus are automatically associated with
4533*7c478bd9Sstevel@tonic-gate  * DDI_DEV_T_NONE.
4534*7c478bd9Sstevel@tonic-gate  *
4535*7c478bd9Sstevel@tonic-gate  * Modifying flag DDI_PROP_NOTPROM inhibits the search in the h/w layer.
4536*7c478bd9Sstevel@tonic-gate  *
4537*7c478bd9Sstevel@tonic-gate  * Returns DDI_PROP_FOUND_1275 if found to indicate to framework
4538*7c478bd9Sstevel@tonic-gate  * that the property resides in the prom.
4539*7c478bd9Sstevel@tonic-gate  */
4540*7c478bd9Sstevel@tonic-gate int
4541*7c478bd9Sstevel@tonic-gate impl_ddi_bus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
4542*7c478bd9Sstevel@tonic-gate     ddi_prop_op_t prop_op, int mod_flags,
4543*7c478bd9Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
4544*7c478bd9Sstevel@tonic-gate {
4545*7c478bd9Sstevel@tonic-gate 	int	len;
4546*7c478bd9Sstevel@tonic-gate 	caddr_t buffer;
4547*7c478bd9Sstevel@tonic-gate 
4548*7c478bd9Sstevel@tonic-gate 	/*
4549*7c478bd9Sstevel@tonic-gate 	 * If requested dev is DDI_DEV_T_NONE or DDI_DEV_T_ANY, then
4550*7c478bd9Sstevel@tonic-gate 	 * look in caller's PROM if it's a self identifying device...
4551*7c478bd9Sstevel@tonic-gate 	 *
4552*7c478bd9Sstevel@tonic-gate 	 * Note that this is very similar to ddi_prop_op, but we
4553*7c478bd9Sstevel@tonic-gate 	 * search the PROM instead of the s/w defined properties,
4554*7c478bd9Sstevel@tonic-gate 	 * and we are called on by the parent driver to do this for
4555*7c478bd9Sstevel@tonic-gate 	 * the child.
4556*7c478bd9Sstevel@tonic-gate 	 */
4557*7c478bd9Sstevel@tonic-gate 
4558*7c478bd9Sstevel@tonic-gate 	if (((dev == DDI_DEV_T_NONE) || (dev == DDI_DEV_T_ANY)) &&
4559*7c478bd9Sstevel@tonic-gate 	    ndi_dev_is_prom_node(ch_dip) &&
4560*7c478bd9Sstevel@tonic-gate 	    ((mod_flags & DDI_PROP_NOTPROM) == 0)) {
4561*7c478bd9Sstevel@tonic-gate 		len = prom_getproplen((dnode_t)DEVI(ch_dip)->devi_nodeid, name);
4562*7c478bd9Sstevel@tonic-gate 		if (len == -1) {
4563*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_NOT_FOUND);
4564*7c478bd9Sstevel@tonic-gate 		}
4565*7c478bd9Sstevel@tonic-gate 
4566*7c478bd9Sstevel@tonic-gate 		/*
4567*7c478bd9Sstevel@tonic-gate 		 * If exists only request, we're done
4568*7c478bd9Sstevel@tonic-gate 		 */
4569*7c478bd9Sstevel@tonic-gate 		if (prop_op == PROP_EXISTS) {
4570*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_FOUND_1275);
4571*7c478bd9Sstevel@tonic-gate 		}
4572*7c478bd9Sstevel@tonic-gate 
4573*7c478bd9Sstevel@tonic-gate 		/*
4574*7c478bd9Sstevel@tonic-gate 		 * If length only request or prop length == 0, get out
4575*7c478bd9Sstevel@tonic-gate 		 */
4576*7c478bd9Sstevel@tonic-gate 		if ((prop_op == PROP_LEN) || (len == 0)) {
4577*7c478bd9Sstevel@tonic-gate 			*lengthp = len;
4578*7c478bd9Sstevel@tonic-gate 			return (DDI_PROP_FOUND_1275);
4579*7c478bd9Sstevel@tonic-gate 		}
4580*7c478bd9Sstevel@tonic-gate 
4581*7c478bd9Sstevel@tonic-gate 		/*
4582*7c478bd9Sstevel@tonic-gate 		 * Allocate buffer if required... (either way `buffer'
4583*7c478bd9Sstevel@tonic-gate 		 * is receiving address).
4584*7c478bd9Sstevel@tonic-gate 		 */
4585*7c478bd9Sstevel@tonic-gate 
4586*7c478bd9Sstevel@tonic-gate 		switch (prop_op) {
4587*7c478bd9Sstevel@tonic-gate 
4588*7c478bd9Sstevel@tonic-gate 		case PROP_LEN_AND_VAL_ALLOC:
4589*7c478bd9Sstevel@tonic-gate 
4590*7c478bd9Sstevel@tonic-gate 			buffer = kmem_alloc((size_t)len,
4591*7c478bd9Sstevel@tonic-gate 			    mod_flags & DDI_PROP_CANSLEEP ?
4592*7c478bd9Sstevel@tonic-gate 			    KM_SLEEP : KM_NOSLEEP);
4593*7c478bd9Sstevel@tonic-gate 			if (buffer == NULL) {
4594*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_NO_MEMORY);
4595*7c478bd9Sstevel@tonic-gate 			}
4596*7c478bd9Sstevel@tonic-gate 			*(caddr_t *)valuep = buffer;
4597*7c478bd9Sstevel@tonic-gate 			break;
4598*7c478bd9Sstevel@tonic-gate 
4599*7c478bd9Sstevel@tonic-gate 		case PROP_LEN_AND_VAL_BUF:
4600*7c478bd9Sstevel@tonic-gate 
4601*7c478bd9Sstevel@tonic-gate 			if (len > (*lengthp)) {
4602*7c478bd9Sstevel@tonic-gate 				*lengthp = len;
4603*7c478bd9Sstevel@tonic-gate 				return (DDI_PROP_BUF_TOO_SMALL);
4604*7c478bd9Sstevel@tonic-gate 			}
4605*7c478bd9Sstevel@tonic-gate 
4606*7c478bd9Sstevel@tonic-gate 			buffer = valuep;
4607*7c478bd9Sstevel@tonic-gate 			break;
4608*7c478bd9Sstevel@tonic-gate 
4609*7c478bd9Sstevel@tonic-gate 		default:
4610*7c478bd9Sstevel@tonic-gate 			break;
4611*7c478bd9Sstevel@tonic-gate 		}
4612*7c478bd9Sstevel@tonic-gate 
4613*7c478bd9Sstevel@tonic-gate 		/*
4614*7c478bd9Sstevel@tonic-gate 		 * Call the PROM function to do the copy.
4615*7c478bd9Sstevel@tonic-gate 		 */
4616*7c478bd9Sstevel@tonic-gate 		(void) prom_getprop((dnode_t)DEVI(ch_dip)->devi_nodeid,
4617*7c478bd9Sstevel@tonic-gate 			name, buffer);
4618*7c478bd9Sstevel@tonic-gate 
4619*7c478bd9Sstevel@tonic-gate 		*lengthp = len; /* return the actual length to the caller */
4620*7c478bd9Sstevel@tonic-gate 		(void) impl_fix_props(dip, ch_dip, name, len, buffer);
4621*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_FOUND_1275);
4622*7c478bd9Sstevel@tonic-gate 	}
4623*7c478bd9Sstevel@tonic-gate 
4624*7c478bd9Sstevel@tonic-gate 	return (DDI_PROP_NOT_FOUND);
4625*7c478bd9Sstevel@tonic-gate }
4626*7c478bd9Sstevel@tonic-gate 
4627*7c478bd9Sstevel@tonic-gate /*
4628*7c478bd9Sstevel@tonic-gate  * The ddi_bus_prop_op default bus nexus prop op function.
4629*7c478bd9Sstevel@tonic-gate  *
4630*7c478bd9Sstevel@tonic-gate  * Code to search hardware layer (PROM), if it exists,
4631*7c478bd9Sstevel@tonic-gate  * on behalf of child, then, if appropriate, ascend and check
4632*7c478bd9Sstevel@tonic-gate  * my own software defined properties...
4633*7c478bd9Sstevel@tonic-gate  */
4634*7c478bd9Sstevel@tonic-gate int
4635*7c478bd9Sstevel@tonic-gate ddi_bus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
4636*7c478bd9Sstevel@tonic-gate     ddi_prop_op_t prop_op, int mod_flags,
4637*7c478bd9Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
4638*7c478bd9Sstevel@tonic-gate {
4639*7c478bd9Sstevel@tonic-gate 	int	error;
4640*7c478bd9Sstevel@tonic-gate 
4641*7c478bd9Sstevel@tonic-gate 	error = impl_ddi_bus_prop_op(dev, dip, ch_dip, prop_op, mod_flags,
4642*7c478bd9Sstevel@tonic-gate 				    name, valuep, lengthp);
4643*7c478bd9Sstevel@tonic-gate 
4644*7c478bd9Sstevel@tonic-gate 	if (error == DDI_PROP_SUCCESS || error == DDI_PROP_FOUND_1275 ||
4645*7c478bd9Sstevel@tonic-gate 	    error == DDI_PROP_BUF_TOO_SMALL)
4646*7c478bd9Sstevel@tonic-gate 		return (error);
4647*7c478bd9Sstevel@tonic-gate 
4648*7c478bd9Sstevel@tonic-gate 	if (error == DDI_PROP_NO_MEMORY) {
4649*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, prop_no_mem_msg, name);
4650*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
4651*7c478bd9Sstevel@tonic-gate 	}
4652*7c478bd9Sstevel@tonic-gate 
4653*7c478bd9Sstevel@tonic-gate 	/*
4654*7c478bd9Sstevel@tonic-gate 	 * Check the 'options' node as a last resort
4655*7c478bd9Sstevel@tonic-gate 	 */
4656*7c478bd9Sstevel@tonic-gate 	if ((mod_flags & DDI_PROP_DONTPASS) != 0)
4657*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
4658*7c478bd9Sstevel@tonic-gate 
4659*7c478bd9Sstevel@tonic-gate 	if (ch_dip == ddi_root_node())	{
4660*7c478bd9Sstevel@tonic-gate 		/*
4661*7c478bd9Sstevel@tonic-gate 		 * As a last resort, when we've reached
4662*7c478bd9Sstevel@tonic-gate 		 * the top and still haven't found the
4663*7c478bd9Sstevel@tonic-gate 		 * property, see if the desired property
4664*7c478bd9Sstevel@tonic-gate 		 * is attached to the options node.
4665*7c478bd9Sstevel@tonic-gate 		 *
4666*7c478bd9Sstevel@tonic-gate 		 * The options dip is attached right after boot.
4667*7c478bd9Sstevel@tonic-gate 		 */
4668*7c478bd9Sstevel@tonic-gate 		ASSERT(options_dip != NULL);
4669*7c478bd9Sstevel@tonic-gate 		/*
4670*7c478bd9Sstevel@tonic-gate 		 * Force the "don't pass" flag to *just* see
4671*7c478bd9Sstevel@tonic-gate 		 * what the options node has to offer.
4672*7c478bd9Sstevel@tonic-gate 		 */
4673*7c478bd9Sstevel@tonic-gate 		return (ddi_prop_search_common(dev, options_dip, prop_op,
4674*7c478bd9Sstevel@tonic-gate 		    mod_flags|DDI_PROP_DONTPASS, name, valuep,
4675*7c478bd9Sstevel@tonic-gate 		    (uint_t *)lengthp));
4676*7c478bd9Sstevel@tonic-gate 	}
4677*7c478bd9Sstevel@tonic-gate 
4678*7c478bd9Sstevel@tonic-gate 	/*
4679*7c478bd9Sstevel@tonic-gate 	 * Otherwise, continue search with parent's s/w defined properties...
4680*7c478bd9Sstevel@tonic-gate 	 * NOTE: Using `dip' in following call increments the level.
4681*7c478bd9Sstevel@tonic-gate 	 */
4682*7c478bd9Sstevel@tonic-gate 
4683*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_search_common(dev, dip, prop_op, mod_flags,
4684*7c478bd9Sstevel@tonic-gate 	    name, valuep, (uint_t *)lengthp));
4685*7c478bd9Sstevel@tonic-gate }
4686*7c478bd9Sstevel@tonic-gate 
4687*7c478bd9Sstevel@tonic-gate /*
4688*7c478bd9Sstevel@tonic-gate  * External property functions used by other parts of the kernel...
4689*7c478bd9Sstevel@tonic-gate  */
4690*7c478bd9Sstevel@tonic-gate 
4691*7c478bd9Sstevel@tonic-gate /*
4692*7c478bd9Sstevel@tonic-gate  * e_ddi_getlongprop: See comments for ddi_get_longprop.
4693*7c478bd9Sstevel@tonic-gate  */
4694*7c478bd9Sstevel@tonic-gate 
4695*7c478bd9Sstevel@tonic-gate int
4696*7c478bd9Sstevel@tonic-gate e_ddi_getlongprop(dev_t dev, vtype_t type, char *name, int flags,
4697*7c478bd9Sstevel@tonic-gate     caddr_t valuep, int *lengthp)
4698*7c478bd9Sstevel@tonic-gate {
4699*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(type))
4700*7c478bd9Sstevel@tonic-gate 	dev_info_t *devi;
4701*7c478bd9Sstevel@tonic-gate 	ddi_prop_op_t prop_op = PROP_LEN_AND_VAL_ALLOC;
4702*7c478bd9Sstevel@tonic-gate 	int error;
4703*7c478bd9Sstevel@tonic-gate 
4704*7c478bd9Sstevel@tonic-gate 	if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4705*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
4706*7c478bd9Sstevel@tonic-gate 
4707*7c478bd9Sstevel@tonic-gate 	error = cdev_prop_op(dev, devi, prop_op, flags, name, valuep, lengthp);
4708*7c478bd9Sstevel@tonic-gate 	ddi_release_devi(devi);
4709*7c478bd9Sstevel@tonic-gate 	return (error);
4710*7c478bd9Sstevel@tonic-gate }
4711*7c478bd9Sstevel@tonic-gate 
4712*7c478bd9Sstevel@tonic-gate /*
4713*7c478bd9Sstevel@tonic-gate  * e_ddi_getlongprop_buf:	See comments for ddi_getlongprop_buf.
4714*7c478bd9Sstevel@tonic-gate  */
4715*7c478bd9Sstevel@tonic-gate 
4716*7c478bd9Sstevel@tonic-gate int
4717*7c478bd9Sstevel@tonic-gate e_ddi_getlongprop_buf(dev_t dev, vtype_t type, char *name, int flags,
4718*7c478bd9Sstevel@tonic-gate     caddr_t valuep, int *lengthp)
4719*7c478bd9Sstevel@tonic-gate {
4720*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(type))
4721*7c478bd9Sstevel@tonic-gate 	dev_info_t *devi;
4722*7c478bd9Sstevel@tonic-gate 	ddi_prop_op_t prop_op = PROP_LEN_AND_VAL_BUF;
4723*7c478bd9Sstevel@tonic-gate 	int error;
4724*7c478bd9Sstevel@tonic-gate 
4725*7c478bd9Sstevel@tonic-gate 	if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4726*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
4727*7c478bd9Sstevel@tonic-gate 
4728*7c478bd9Sstevel@tonic-gate 	error = cdev_prop_op(dev, devi, prop_op, flags, name, valuep, lengthp);
4729*7c478bd9Sstevel@tonic-gate 	ddi_release_devi(devi);
4730*7c478bd9Sstevel@tonic-gate 	return (error);
4731*7c478bd9Sstevel@tonic-gate }
4732*7c478bd9Sstevel@tonic-gate 
4733*7c478bd9Sstevel@tonic-gate /*
4734*7c478bd9Sstevel@tonic-gate  * e_ddi_getprop:	See comments for ddi_getprop.
4735*7c478bd9Sstevel@tonic-gate  */
4736*7c478bd9Sstevel@tonic-gate int
4737*7c478bd9Sstevel@tonic-gate e_ddi_getprop(dev_t dev, vtype_t type, char *name, int flags, int defvalue)
4738*7c478bd9Sstevel@tonic-gate {
4739*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(type))
4740*7c478bd9Sstevel@tonic-gate 	dev_info_t *devi;
4741*7c478bd9Sstevel@tonic-gate 	ddi_prop_op_t prop_op = PROP_LEN_AND_VAL_BUF;
4742*7c478bd9Sstevel@tonic-gate 	int	propvalue = defvalue;
4743*7c478bd9Sstevel@tonic-gate 	int	proplength = sizeof (int);
4744*7c478bd9Sstevel@tonic-gate 	int	error;
4745*7c478bd9Sstevel@tonic-gate 
4746*7c478bd9Sstevel@tonic-gate 	if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4747*7c478bd9Sstevel@tonic-gate 		return (defvalue);
4748*7c478bd9Sstevel@tonic-gate 
4749*7c478bd9Sstevel@tonic-gate 	error = cdev_prop_op(dev, devi, prop_op,
4750*7c478bd9Sstevel@tonic-gate 	    flags, name, (caddr_t)&propvalue, &proplength);
4751*7c478bd9Sstevel@tonic-gate 	ddi_release_devi(devi);
4752*7c478bd9Sstevel@tonic-gate 
4753*7c478bd9Sstevel@tonic-gate 	if ((error == DDI_PROP_SUCCESS) && (proplength == 0))
4754*7c478bd9Sstevel@tonic-gate 		propvalue = 1;
4755*7c478bd9Sstevel@tonic-gate 
4756*7c478bd9Sstevel@tonic-gate 	return (propvalue);
4757*7c478bd9Sstevel@tonic-gate }
4758*7c478bd9Sstevel@tonic-gate 
4759*7c478bd9Sstevel@tonic-gate /*
4760*7c478bd9Sstevel@tonic-gate  * e_ddi_getprop_int64:
4761*7c478bd9Sstevel@tonic-gate  *
4762*7c478bd9Sstevel@tonic-gate  * This is a typed interfaces, but predates typed properties. With the
4763*7c478bd9Sstevel@tonic-gate  * introduction of typed properties the framework tries to ensure
4764*7c478bd9Sstevel@tonic-gate  * consistent use of typed interfaces. This is why TYPE_INT64 is not
4765*7c478bd9Sstevel@tonic-gate  * part of TYPE_ANY.  E_ddi_getprop_int64 is a special case where a
4766*7c478bd9Sstevel@tonic-gate  * typed interface invokes legacy (non-typed) interfaces:
4767*7c478bd9Sstevel@tonic-gate  * cdev_prop_op(), prop_op(9E), ddi_prop_op(9F)).  In this case the
4768*7c478bd9Sstevel@tonic-gate  * fact that TYPE_INT64 is not part of TYPE_ANY matters.  To support
4769*7c478bd9Sstevel@tonic-gate  * this type of lookup as a single operation we invoke the legacy
4770*7c478bd9Sstevel@tonic-gate  * non-typed interfaces with the special CONSUMER_TYPED bit set. The
4771*7c478bd9Sstevel@tonic-gate  * framework ddi_prop_op(9F) implementation is expected to check for
4772*7c478bd9Sstevel@tonic-gate  * CONSUMER_TYPED and, if set, expand type bits beyond TYPE_ANY
4773*7c478bd9Sstevel@tonic-gate  * (currently TYPE_INT64).
4774*7c478bd9Sstevel@tonic-gate  */
4775*7c478bd9Sstevel@tonic-gate int64_t
4776*7c478bd9Sstevel@tonic-gate e_ddi_getprop_int64(dev_t dev, vtype_t type, char *name,
4777*7c478bd9Sstevel@tonic-gate     int flags, int64_t defvalue)
4778*7c478bd9Sstevel@tonic-gate {
4779*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(type))
4780*7c478bd9Sstevel@tonic-gate 	dev_info_t	*devi;
4781*7c478bd9Sstevel@tonic-gate 	ddi_prop_op_t	prop_op = PROP_LEN_AND_VAL_BUF;
4782*7c478bd9Sstevel@tonic-gate 	int64_t		propvalue = defvalue;
4783*7c478bd9Sstevel@tonic-gate 	int		proplength = sizeof (propvalue);
4784*7c478bd9Sstevel@tonic-gate 	int		error;
4785*7c478bd9Sstevel@tonic-gate 
4786*7c478bd9Sstevel@tonic-gate 	if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4787*7c478bd9Sstevel@tonic-gate 		return (defvalue);
4788*7c478bd9Sstevel@tonic-gate 
4789*7c478bd9Sstevel@tonic-gate 	error = cdev_prop_op(dev, devi, prop_op, flags |
4790*7c478bd9Sstevel@tonic-gate 	    DDI_PROP_CONSUMER_TYPED, name, (caddr_t)&propvalue, &proplength);
4791*7c478bd9Sstevel@tonic-gate 	ddi_release_devi(devi);
4792*7c478bd9Sstevel@tonic-gate 
4793*7c478bd9Sstevel@tonic-gate 	if ((error == DDI_PROP_SUCCESS) && (proplength == 0))
4794*7c478bd9Sstevel@tonic-gate 		propvalue = 1;
4795*7c478bd9Sstevel@tonic-gate 
4796*7c478bd9Sstevel@tonic-gate 	return (propvalue);
4797*7c478bd9Sstevel@tonic-gate }
4798*7c478bd9Sstevel@tonic-gate 
4799*7c478bd9Sstevel@tonic-gate /*
4800*7c478bd9Sstevel@tonic-gate  * e_ddi_getproplen:	See comments for ddi_getproplen.
4801*7c478bd9Sstevel@tonic-gate  */
4802*7c478bd9Sstevel@tonic-gate int
4803*7c478bd9Sstevel@tonic-gate e_ddi_getproplen(dev_t dev, vtype_t type, char *name, int flags, int *lengthp)
4804*7c478bd9Sstevel@tonic-gate {
4805*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(type))
4806*7c478bd9Sstevel@tonic-gate 	dev_info_t *devi;
4807*7c478bd9Sstevel@tonic-gate 	ddi_prop_op_t prop_op = PROP_LEN;
4808*7c478bd9Sstevel@tonic-gate 	int error;
4809*7c478bd9Sstevel@tonic-gate 
4810*7c478bd9Sstevel@tonic-gate 	if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
4811*7c478bd9Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
4812*7c478bd9Sstevel@tonic-gate 
4813*7c478bd9Sstevel@tonic-gate 	error = cdev_prop_op(dev, devi, prop_op, flags, name, NULL, lengthp);
4814*7c478bd9Sstevel@tonic-gate 	ddi_release_devi(devi);
4815*7c478bd9Sstevel@tonic-gate 	return (error);
4816*7c478bd9Sstevel@tonic-gate }
4817*7c478bd9Sstevel@tonic-gate 
4818*7c478bd9Sstevel@tonic-gate /*
4819*7c478bd9Sstevel@tonic-gate  * Routines to get at elements of the dev_info structure
4820*7c478bd9Sstevel@tonic-gate  */
4821*7c478bd9Sstevel@tonic-gate 
4822*7c478bd9Sstevel@tonic-gate /*
4823*7c478bd9Sstevel@tonic-gate  * ddi_binding_name: Return the driver binding name of the devinfo node
4824*7c478bd9Sstevel@tonic-gate  *		This is the name the OS used to bind the node to a driver.
4825*7c478bd9Sstevel@tonic-gate  */
4826*7c478bd9Sstevel@tonic-gate char *
4827*7c478bd9Sstevel@tonic-gate ddi_binding_name(dev_info_t *dip)
4828*7c478bd9Sstevel@tonic-gate {
4829*7c478bd9Sstevel@tonic-gate 	return (DEVI(dip)->devi_binding_name);
4830*7c478bd9Sstevel@tonic-gate }
4831*7c478bd9Sstevel@tonic-gate 
4832*7c478bd9Sstevel@tonic-gate /*
4833*7c478bd9Sstevel@tonic-gate  * ddi_driver_major: Return the major number of the driver that
4834*7c478bd9Sstevel@tonic-gate  *		the supplied devinfo is bound to (-1 if none)
4835*7c478bd9Sstevel@tonic-gate  */
4836*7c478bd9Sstevel@tonic-gate major_t
4837*7c478bd9Sstevel@tonic-gate ddi_driver_major(dev_info_t *devi)
4838*7c478bd9Sstevel@tonic-gate {
4839*7c478bd9Sstevel@tonic-gate 	return (DEVI(devi)->devi_major);
4840*7c478bd9Sstevel@tonic-gate }
4841*7c478bd9Sstevel@tonic-gate 
4842*7c478bd9Sstevel@tonic-gate /*
4843*7c478bd9Sstevel@tonic-gate  * ddi_driver_name: Return the normalized driver name. this is the
4844*7c478bd9Sstevel@tonic-gate  *		actual driver name
4845*7c478bd9Sstevel@tonic-gate  */
4846*7c478bd9Sstevel@tonic-gate const char *
4847*7c478bd9Sstevel@tonic-gate ddi_driver_name(dev_info_t *devi)
4848*7c478bd9Sstevel@tonic-gate {
4849*7c478bd9Sstevel@tonic-gate 	major_t major;
4850*7c478bd9Sstevel@tonic-gate 
4851*7c478bd9Sstevel@tonic-gate 	if ((major = ddi_driver_major(devi)) != (major_t)-1)
4852*7c478bd9Sstevel@tonic-gate 		return (ddi_major_to_name(major));
4853*7c478bd9Sstevel@tonic-gate 
4854*7c478bd9Sstevel@tonic-gate 	return (ddi_node_name(devi));
4855*7c478bd9Sstevel@tonic-gate }
4856*7c478bd9Sstevel@tonic-gate 
4857*7c478bd9Sstevel@tonic-gate /*
4858*7c478bd9Sstevel@tonic-gate  * i_ddi_set_binding_name:	Set binding name.
4859*7c478bd9Sstevel@tonic-gate  *
4860*7c478bd9Sstevel@tonic-gate  *	Set the binding name to the given name.
4861*7c478bd9Sstevel@tonic-gate  *	This routine is for use by the ddi implementation, not by drivers.
4862*7c478bd9Sstevel@tonic-gate  */
4863*7c478bd9Sstevel@tonic-gate void
4864*7c478bd9Sstevel@tonic-gate i_ddi_set_binding_name(dev_info_t *dip, char *name)
4865*7c478bd9Sstevel@tonic-gate {
4866*7c478bd9Sstevel@tonic-gate 	DEVI(dip)->devi_binding_name = name;
4867*7c478bd9Sstevel@tonic-gate 
4868*7c478bd9Sstevel@tonic-gate }
4869*7c478bd9Sstevel@tonic-gate 
4870*7c478bd9Sstevel@tonic-gate /*
4871*7c478bd9Sstevel@tonic-gate  * ddi_get_name: A synonym of ddi_binding_name() ... returns a name
4872*7c478bd9Sstevel@tonic-gate  * the implementation has used to bind the node to a driver.
4873*7c478bd9Sstevel@tonic-gate  */
4874*7c478bd9Sstevel@tonic-gate char *
4875*7c478bd9Sstevel@tonic-gate ddi_get_name(dev_info_t *dip)
4876*7c478bd9Sstevel@tonic-gate {
4877*7c478bd9Sstevel@tonic-gate 	return (DEVI(dip)->devi_binding_name);
4878*7c478bd9Sstevel@tonic-gate }
4879*7c478bd9Sstevel@tonic-gate 
4880*7c478bd9Sstevel@tonic-gate /*
4881*7c478bd9Sstevel@tonic-gate  * ddi_node_name: Return the name property of the devinfo node
4882*7c478bd9Sstevel@tonic-gate  *		This may differ from ddi_binding_name if the node name
4883*7c478bd9Sstevel@tonic-gate  *		does not define a binding to a driver (i.e. generic names).
4884*7c478bd9Sstevel@tonic-gate  */
4885*7c478bd9Sstevel@tonic-gate char *
4886*7c478bd9Sstevel@tonic-gate ddi_node_name(dev_info_t *dip)
4887*7c478bd9Sstevel@tonic-gate {
4888*7c478bd9Sstevel@tonic-gate 	return (DEVI(dip)->devi_node_name);
4889*7c478bd9Sstevel@tonic-gate }
4890*7c478bd9Sstevel@tonic-gate 
4891*7c478bd9Sstevel@tonic-gate 
4892*7c478bd9Sstevel@tonic-gate /*
4893*7c478bd9Sstevel@tonic-gate  * ddi_get_nodeid:	Get nodeid stored in dev_info structure.
4894*7c478bd9Sstevel@tonic-gate  */
4895*7c478bd9Sstevel@tonic-gate int
4896*7c478bd9Sstevel@tonic-gate ddi_get_nodeid(dev_info_t *dip)
4897*7c478bd9Sstevel@tonic-gate {
4898*7c478bd9Sstevel@tonic-gate 	return (DEVI(dip)->devi_nodeid);
4899*7c478bd9Sstevel@tonic-gate }
4900*7c478bd9Sstevel@tonic-gate 
4901*7c478bd9Sstevel@tonic-gate int
4902*7c478bd9Sstevel@tonic-gate ddi_get_instance(dev_info_t *dip)
4903*7c478bd9Sstevel@tonic-gate {
4904*7c478bd9Sstevel@tonic-gate 	return (DEVI(dip)->devi_instance);
4905*7c478bd9Sstevel@tonic-gate }
4906*7c478bd9Sstevel@tonic-gate 
4907*7c478bd9Sstevel@tonic-gate struct dev_ops *
4908*7c478bd9Sstevel@tonic-gate ddi_get_driver(dev_info_t *dip)
4909*7c478bd9Sstevel@tonic-gate {
4910*7c478bd9Sstevel@tonic-gate 	return (DEVI(dip)->devi_ops);
4911*7c478bd9Sstevel@tonic-gate }
4912*7c478bd9Sstevel@tonic-gate 
4913*7c478bd9Sstevel@tonic-gate void
4914*7c478bd9Sstevel@tonic-gate ddi_set_driver(dev_info_t *dip, struct dev_ops *devo)
4915*7c478bd9Sstevel@tonic-gate {
4916*7c478bd9Sstevel@tonic-gate 	DEVI(dip)->devi_ops = devo;
4917*7c478bd9Sstevel@tonic-gate }
4918*7c478bd9Sstevel@tonic-gate 
4919*7c478bd9Sstevel@tonic-gate /*
4920*7c478bd9Sstevel@tonic-gate  * ddi_set_driver_private/ddi_get_driver_private:
4921*7c478bd9Sstevel@tonic-gate  * Get/set device driver private data in devinfo.
4922*7c478bd9Sstevel@tonic-gate  */
4923*7c478bd9Sstevel@tonic-gate void
4924*7c478bd9Sstevel@tonic-gate ddi_set_driver_private(dev_info_t *dip, void *data)
4925*7c478bd9Sstevel@tonic-gate {
4926*7c478bd9Sstevel@tonic-gate 	DEVI(dip)->devi_driver_data = data;
4927*7c478bd9Sstevel@tonic-gate }
4928*7c478bd9Sstevel@tonic-gate 
4929*7c478bd9Sstevel@tonic-gate void *
4930*7c478bd9Sstevel@tonic-gate ddi_get_driver_private(dev_info_t *dip)
4931*7c478bd9Sstevel@tonic-gate {
4932*7c478bd9Sstevel@tonic-gate 	return (DEVI(dip)->devi_driver_data);
4933*7c478bd9Sstevel@tonic-gate }
4934*7c478bd9Sstevel@tonic-gate 
4935*7c478bd9Sstevel@tonic-gate /*
4936*7c478bd9Sstevel@tonic-gate  * ddi_get_parent, ddi_get_child, ddi_get_next_sibling
4937*7c478bd9Sstevel@tonic-gate  */
4938*7c478bd9Sstevel@tonic-gate 
4939*7c478bd9Sstevel@tonic-gate dev_info_t *
4940*7c478bd9Sstevel@tonic-gate ddi_get_parent(dev_info_t *dip)
4941*7c478bd9Sstevel@tonic-gate {
4942*7c478bd9Sstevel@tonic-gate 	return ((dev_info_t *)DEVI(dip)->devi_parent);
4943*7c478bd9Sstevel@tonic-gate }
4944*7c478bd9Sstevel@tonic-gate 
4945*7c478bd9Sstevel@tonic-gate dev_info_t *
4946*7c478bd9Sstevel@tonic-gate ddi_get_child(dev_info_t *dip)
4947*7c478bd9Sstevel@tonic-gate {
4948*7c478bd9Sstevel@tonic-gate 	return ((dev_info_t *)DEVI(dip)->devi_child);
4949*7c478bd9Sstevel@tonic-gate }
4950*7c478bd9Sstevel@tonic-gate 
4951*7c478bd9Sstevel@tonic-gate dev_info_t *
4952*7c478bd9Sstevel@tonic-gate ddi_get_next_sibling(dev_info_t *dip)
4953*7c478bd9Sstevel@tonic-gate {
4954*7c478bd9Sstevel@tonic-gate 	return ((dev_info_t *)DEVI(dip)->devi_sibling);
4955*7c478bd9Sstevel@tonic-gate }
4956*7c478bd9Sstevel@tonic-gate 
4957*7c478bd9Sstevel@tonic-gate dev_info_t *
4958*7c478bd9Sstevel@tonic-gate ddi_get_next(dev_info_t *dip)
4959*7c478bd9Sstevel@tonic-gate {
4960*7c478bd9Sstevel@tonic-gate 	return ((dev_info_t *)DEVI(dip)->devi_next);
4961*7c478bd9Sstevel@tonic-gate }
4962*7c478bd9Sstevel@tonic-gate 
4963*7c478bd9Sstevel@tonic-gate void
4964*7c478bd9Sstevel@tonic-gate ddi_set_next(dev_info_t *dip, dev_info_t *nextdip)
4965*7c478bd9Sstevel@tonic-gate {
4966*7c478bd9Sstevel@tonic-gate 	DEVI(dip)->devi_next = DEVI(nextdip);
4967*7c478bd9Sstevel@tonic-gate }
4968*7c478bd9Sstevel@tonic-gate 
4969*7c478bd9Sstevel@tonic-gate /*
4970*7c478bd9Sstevel@tonic-gate  * ddi_root_node:		Return root node of devinfo tree
4971*7c478bd9Sstevel@tonic-gate  */
4972*7c478bd9Sstevel@tonic-gate 
4973*7c478bd9Sstevel@tonic-gate dev_info_t *
4974*7c478bd9Sstevel@tonic-gate ddi_root_node(void)
4975*7c478bd9Sstevel@tonic-gate {
4976*7c478bd9Sstevel@tonic-gate 	extern dev_info_t *top_devinfo;
4977*7c478bd9Sstevel@tonic-gate 
4978*7c478bd9Sstevel@tonic-gate 	return (top_devinfo);
4979*7c478bd9Sstevel@tonic-gate }
4980*7c478bd9Sstevel@tonic-gate 
4981*7c478bd9Sstevel@tonic-gate /*
4982*7c478bd9Sstevel@tonic-gate  * Miscellaneous functions:
4983*7c478bd9Sstevel@tonic-gate  */
4984*7c478bd9Sstevel@tonic-gate 
4985*7c478bd9Sstevel@tonic-gate /*
4986*7c478bd9Sstevel@tonic-gate  * Implementation specific hooks
4987*7c478bd9Sstevel@tonic-gate  */
4988*7c478bd9Sstevel@tonic-gate 
4989*7c478bd9Sstevel@tonic-gate void
4990*7c478bd9Sstevel@tonic-gate ddi_report_dev(dev_info_t *d)
4991*7c478bd9Sstevel@tonic-gate {
4992*7c478bd9Sstevel@tonic-gate 	char *b;
4993*7c478bd9Sstevel@tonic-gate 
4994*7c478bd9Sstevel@tonic-gate 	(void) ddi_ctlops(d, d, DDI_CTLOPS_REPORTDEV, (void *)0, (void *)0);
4995*7c478bd9Sstevel@tonic-gate 
4996*7c478bd9Sstevel@tonic-gate 	/*
4997*7c478bd9Sstevel@tonic-gate 	 * If this devinfo node has cb_ops, it's implicitly accessible from
4998*7c478bd9Sstevel@tonic-gate 	 * userland, so we print its full name together with the instance
4999*7c478bd9Sstevel@tonic-gate 	 * number 'abbreviation' that the driver may use internally.
5000*7c478bd9Sstevel@tonic-gate 	 */
5001*7c478bd9Sstevel@tonic-gate 	if (DEVI(d)->devi_ops->devo_cb_ops != (struct cb_ops *)0 &&
5002*7c478bd9Sstevel@tonic-gate 	    (b = kmem_zalloc(MAXPATHLEN, KM_NOSLEEP))) {
5003*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "?%s%d is %s\n",
5004*7c478bd9Sstevel@tonic-gate 		    ddi_driver_name(d), ddi_get_instance(d),
5005*7c478bd9Sstevel@tonic-gate 		    ddi_pathname(d, b));
5006*7c478bd9Sstevel@tonic-gate 		kmem_free(b, MAXPATHLEN);
5007*7c478bd9Sstevel@tonic-gate 	}
5008*7c478bd9Sstevel@tonic-gate }
5009*7c478bd9Sstevel@tonic-gate 
5010*7c478bd9Sstevel@tonic-gate /*
5011*7c478bd9Sstevel@tonic-gate  * ddi_ctlops() is described in the assembler not to buy a new register
5012*7c478bd9Sstevel@tonic-gate  * window when it's called and can reduce cost in climbing the device tree
5013*7c478bd9Sstevel@tonic-gate  * without using the tail call optimization.
5014*7c478bd9Sstevel@tonic-gate  */
5015*7c478bd9Sstevel@tonic-gate int
5016*7c478bd9Sstevel@tonic-gate ddi_dev_regsize(dev_info_t *dev, uint_t rnumber, off_t *result)
5017*7c478bd9Sstevel@tonic-gate {
5018*7c478bd9Sstevel@tonic-gate 	int ret;
5019*7c478bd9Sstevel@tonic-gate 
5020*7c478bd9Sstevel@tonic-gate 	ret = ddi_ctlops(dev, dev, DDI_CTLOPS_REGSIZE,
5021*7c478bd9Sstevel@tonic-gate 	    (void *)&rnumber, (void *)result);
5022*7c478bd9Sstevel@tonic-gate 
5023*7c478bd9Sstevel@tonic-gate 	return (ret == DDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
5024*7c478bd9Sstevel@tonic-gate }
5025*7c478bd9Sstevel@tonic-gate 
5026*7c478bd9Sstevel@tonic-gate int
5027*7c478bd9Sstevel@tonic-gate ddi_dev_nregs(dev_info_t *dev, int *result)
5028*7c478bd9Sstevel@tonic-gate {
5029*7c478bd9Sstevel@tonic-gate 	return (ddi_ctlops(dev, dev, DDI_CTLOPS_NREGS, 0, (void *)result));
5030*7c478bd9Sstevel@tonic-gate }
5031*7c478bd9Sstevel@tonic-gate 
5032*7c478bd9Sstevel@tonic-gate int
5033*7c478bd9Sstevel@tonic-gate ddi_dev_is_sid(dev_info_t *d)
5034*7c478bd9Sstevel@tonic-gate {
5035*7c478bd9Sstevel@tonic-gate 	return (ddi_ctlops(d, d, DDI_CTLOPS_SIDDEV, (void *)0, (void *)0));
5036*7c478bd9Sstevel@tonic-gate }
5037*7c478bd9Sstevel@tonic-gate 
5038*7c478bd9Sstevel@tonic-gate int
5039*7c478bd9Sstevel@tonic-gate ddi_slaveonly(dev_info_t *d)
5040*7c478bd9Sstevel@tonic-gate {
5041*7c478bd9Sstevel@tonic-gate 	return (ddi_ctlops(d, d, DDI_CTLOPS_SLAVEONLY, (void *)0, (void *)0));
5042*7c478bd9Sstevel@tonic-gate }
5043*7c478bd9Sstevel@tonic-gate 
5044*7c478bd9Sstevel@tonic-gate int
5045*7c478bd9Sstevel@tonic-gate ddi_dev_affinity(dev_info_t *a, dev_info_t *b)
5046*7c478bd9Sstevel@tonic-gate {
5047*7c478bd9Sstevel@tonic-gate 	return (ddi_ctlops(a, a, DDI_CTLOPS_AFFINITY, (void *)b, (void *)0));
5048*7c478bd9Sstevel@tonic-gate }
5049*7c478bd9Sstevel@tonic-gate 
5050*7c478bd9Sstevel@tonic-gate int
5051*7c478bd9Sstevel@tonic-gate ddi_streams_driver(dev_info_t *dip)
5052*7c478bd9Sstevel@tonic-gate {
5053*7c478bd9Sstevel@tonic-gate 	if ((i_ddi_node_state(dip) >= DS_ATTACHED) &&
5054*7c478bd9Sstevel@tonic-gate 	    (DEVI(dip)->devi_ops->devo_cb_ops != NULL) &&
5055*7c478bd9Sstevel@tonic-gate 	    (DEVI(dip)->devi_ops->devo_cb_ops->cb_str != NULL))
5056*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5057*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
5058*7c478bd9Sstevel@tonic-gate }
5059*7c478bd9Sstevel@tonic-gate 
5060*7c478bd9Sstevel@tonic-gate /*
5061*7c478bd9Sstevel@tonic-gate  * callback free list
5062*7c478bd9Sstevel@tonic-gate  */
5063*7c478bd9Sstevel@tonic-gate 
5064*7c478bd9Sstevel@tonic-gate static int ncallbacks;
5065*7c478bd9Sstevel@tonic-gate static int nc_low = 170;
5066*7c478bd9Sstevel@tonic-gate static int nc_med = 512;
5067*7c478bd9Sstevel@tonic-gate static int nc_high = 2048;
5068*7c478bd9Sstevel@tonic-gate static struct ddi_callback *callbackq;
5069*7c478bd9Sstevel@tonic-gate static struct ddi_callback *callbackqfree;
5070*7c478bd9Sstevel@tonic-gate 
5071*7c478bd9Sstevel@tonic-gate /*
5072*7c478bd9Sstevel@tonic-gate  * set/run callback lists
5073*7c478bd9Sstevel@tonic-gate  */
5074*7c478bd9Sstevel@tonic-gate struct	cbstats	{
5075*7c478bd9Sstevel@tonic-gate 	kstat_named_t	cb_asked;
5076*7c478bd9Sstevel@tonic-gate 	kstat_named_t	cb_new;
5077*7c478bd9Sstevel@tonic-gate 	kstat_named_t	cb_run;
5078*7c478bd9Sstevel@tonic-gate 	kstat_named_t	cb_delete;
5079*7c478bd9Sstevel@tonic-gate 	kstat_named_t	cb_maxreq;
5080*7c478bd9Sstevel@tonic-gate 	kstat_named_t	cb_maxlist;
5081*7c478bd9Sstevel@tonic-gate 	kstat_named_t	cb_alloc;
5082*7c478bd9Sstevel@tonic-gate 	kstat_named_t	cb_runouts;
5083*7c478bd9Sstevel@tonic-gate 	kstat_named_t	cb_L2;
5084*7c478bd9Sstevel@tonic-gate 	kstat_named_t	cb_grow;
5085*7c478bd9Sstevel@tonic-gate } cbstats = {
5086*7c478bd9Sstevel@tonic-gate 	{"asked",	KSTAT_DATA_UINT32},
5087*7c478bd9Sstevel@tonic-gate 	{"new",		KSTAT_DATA_UINT32},
5088*7c478bd9Sstevel@tonic-gate 	{"run",		KSTAT_DATA_UINT32},
5089*7c478bd9Sstevel@tonic-gate 	{"delete",	KSTAT_DATA_UINT32},
5090*7c478bd9Sstevel@tonic-gate 	{"maxreq",	KSTAT_DATA_UINT32},
5091*7c478bd9Sstevel@tonic-gate 	{"maxlist",	KSTAT_DATA_UINT32},
5092*7c478bd9Sstevel@tonic-gate 	{"alloc",	KSTAT_DATA_UINT32},
5093*7c478bd9Sstevel@tonic-gate 	{"runouts",	KSTAT_DATA_UINT32},
5094*7c478bd9Sstevel@tonic-gate 	{"L2",		KSTAT_DATA_UINT32},
5095*7c478bd9Sstevel@tonic-gate 	{"grow",	KSTAT_DATA_UINT32},
5096*7c478bd9Sstevel@tonic-gate };
5097*7c478bd9Sstevel@tonic-gate 
5098*7c478bd9Sstevel@tonic-gate #define	nc_asked	cb_asked.value.ui32
5099*7c478bd9Sstevel@tonic-gate #define	nc_new		cb_new.value.ui32
5100*7c478bd9Sstevel@tonic-gate #define	nc_run		cb_run.value.ui32
5101*7c478bd9Sstevel@tonic-gate #define	nc_delete	cb_delete.value.ui32
5102*7c478bd9Sstevel@tonic-gate #define	nc_maxreq	cb_maxreq.value.ui32
5103*7c478bd9Sstevel@tonic-gate #define	nc_maxlist	cb_maxlist.value.ui32
5104*7c478bd9Sstevel@tonic-gate #define	nc_alloc	cb_alloc.value.ui32
5105*7c478bd9Sstevel@tonic-gate #define	nc_runouts	cb_runouts.value.ui32
5106*7c478bd9Sstevel@tonic-gate #define	nc_L2		cb_L2.value.ui32
5107*7c478bd9Sstevel@tonic-gate #define	nc_grow		cb_grow.value.ui32
5108*7c478bd9Sstevel@tonic-gate 
5109*7c478bd9Sstevel@tonic-gate static kmutex_t ddi_callback_mutex;
5110*7c478bd9Sstevel@tonic-gate 
5111*7c478bd9Sstevel@tonic-gate /*
5112*7c478bd9Sstevel@tonic-gate  * callbacks are handled using a L1/L2 cache. The L1 cache
5113*7c478bd9Sstevel@tonic-gate  * comes out of kmem_cache_alloc and can expand/shrink dynamically. If
5114*7c478bd9Sstevel@tonic-gate  * we can't get callbacks from the L1 cache [because pageout is doing
5115*7c478bd9Sstevel@tonic-gate  * I/O at the time freemem is 0], we allocate callbacks out of the
5116*7c478bd9Sstevel@tonic-gate  * L2 cache. The L2 cache is static and depends on the memory size.
5117*7c478bd9Sstevel@tonic-gate  * [We might also count the number of devices at probe time and
5118*7c478bd9Sstevel@tonic-gate  * allocate one structure per device and adjust for deferred attach]
5119*7c478bd9Sstevel@tonic-gate  */
5120*7c478bd9Sstevel@tonic-gate void
5121*7c478bd9Sstevel@tonic-gate impl_ddi_callback_init(void)
5122*7c478bd9Sstevel@tonic-gate {
5123*7c478bd9Sstevel@tonic-gate 	int	i;
5124*7c478bd9Sstevel@tonic-gate 	uint_t	physmegs;
5125*7c478bd9Sstevel@tonic-gate 	kstat_t	*ksp;
5126*7c478bd9Sstevel@tonic-gate 
5127*7c478bd9Sstevel@tonic-gate 	physmegs = physmem >> (20 - PAGESHIFT);
5128*7c478bd9Sstevel@tonic-gate 	if (physmegs < 48) {
5129*7c478bd9Sstevel@tonic-gate 		ncallbacks = nc_low;
5130*7c478bd9Sstevel@tonic-gate 	} else if (physmegs < 128) {
5131*7c478bd9Sstevel@tonic-gate 		ncallbacks = nc_med;
5132*7c478bd9Sstevel@tonic-gate 	} else {
5133*7c478bd9Sstevel@tonic-gate 		ncallbacks = nc_high;
5134*7c478bd9Sstevel@tonic-gate 	}
5135*7c478bd9Sstevel@tonic-gate 
5136*7c478bd9Sstevel@tonic-gate 	/*
5137*7c478bd9Sstevel@tonic-gate 	 * init free list
5138*7c478bd9Sstevel@tonic-gate 	 */
5139*7c478bd9Sstevel@tonic-gate 	callbackq = kmem_zalloc(
5140*7c478bd9Sstevel@tonic-gate 	    ncallbacks * sizeof (struct ddi_callback), KM_SLEEP);
5141*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ncallbacks-1; i++)
5142*7c478bd9Sstevel@tonic-gate 		callbackq[i].c_nfree = &callbackq[i+1];
5143*7c478bd9Sstevel@tonic-gate 	callbackqfree = callbackq;
5144*7c478bd9Sstevel@tonic-gate 
5145*7c478bd9Sstevel@tonic-gate 	/* init kstats */
5146*7c478bd9Sstevel@tonic-gate 	if (ksp = kstat_create("unix", 0, "cbstats", "misc", KSTAT_TYPE_NAMED,
5147*7c478bd9Sstevel@tonic-gate 	    sizeof (cbstats) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL)) {
5148*7c478bd9Sstevel@tonic-gate 		ksp->ks_data = (void *) &cbstats;
5149*7c478bd9Sstevel@tonic-gate 		kstat_install(ksp);
5150*7c478bd9Sstevel@tonic-gate 	}
5151*7c478bd9Sstevel@tonic-gate 
5152*7c478bd9Sstevel@tonic-gate }
5153*7c478bd9Sstevel@tonic-gate 
5154*7c478bd9Sstevel@tonic-gate static void
5155*7c478bd9Sstevel@tonic-gate callback_insert(int (*funcp)(caddr_t), caddr_t arg, uintptr_t *listid,
5156*7c478bd9Sstevel@tonic-gate 	int count)
5157*7c478bd9Sstevel@tonic-gate {
5158*7c478bd9Sstevel@tonic-gate 	struct ddi_callback *list, *marker, *new;
5159*7c478bd9Sstevel@tonic-gate 	size_t size = sizeof (struct ddi_callback);
5160*7c478bd9Sstevel@tonic-gate 
5161*7c478bd9Sstevel@tonic-gate 	list = marker = (struct ddi_callback *)*listid;
5162*7c478bd9Sstevel@tonic-gate 	while (list != NULL) {
5163*7c478bd9Sstevel@tonic-gate 		if (list->c_call == funcp && list->c_arg == arg) {
5164*7c478bd9Sstevel@tonic-gate 			list->c_count += count;
5165*7c478bd9Sstevel@tonic-gate 			return;
5166*7c478bd9Sstevel@tonic-gate 		}
5167*7c478bd9Sstevel@tonic-gate 		marker = list;
5168*7c478bd9Sstevel@tonic-gate 		list = list->c_nlist;
5169*7c478bd9Sstevel@tonic-gate 	}
5170*7c478bd9Sstevel@tonic-gate 	new = kmem_alloc(size, KM_NOSLEEP);
5171*7c478bd9Sstevel@tonic-gate 	if (new == NULL) {
5172*7c478bd9Sstevel@tonic-gate 		new = callbackqfree;
5173*7c478bd9Sstevel@tonic-gate 		if (new == NULL) {
5174*7c478bd9Sstevel@tonic-gate 			new = kmem_alloc_tryhard(sizeof (struct ddi_callback),
5175*7c478bd9Sstevel@tonic-gate 			    &size, KM_NOSLEEP | KM_PANIC);
5176*7c478bd9Sstevel@tonic-gate 			cbstats.nc_grow++;
5177*7c478bd9Sstevel@tonic-gate 		} else {
5178*7c478bd9Sstevel@tonic-gate 			callbackqfree = new->c_nfree;
5179*7c478bd9Sstevel@tonic-gate 			cbstats.nc_L2++;
5180*7c478bd9Sstevel@tonic-gate 		}
5181*7c478bd9Sstevel@tonic-gate 	}
5182*7c478bd9Sstevel@tonic-gate 	if (marker != NULL) {
5183*7c478bd9Sstevel@tonic-gate 		marker->c_nlist = new;
5184*7c478bd9Sstevel@tonic-gate 	} else {
5185*7c478bd9Sstevel@tonic-gate 		*listid = (uintptr_t)new;
5186*7c478bd9Sstevel@tonic-gate 	}
5187*7c478bd9Sstevel@tonic-gate 	new->c_size = size;
5188*7c478bd9Sstevel@tonic-gate 	new->c_nlist = NULL;
5189*7c478bd9Sstevel@tonic-gate 	new->c_call = funcp;
5190*7c478bd9Sstevel@tonic-gate 	new->c_arg = arg;
5191*7c478bd9Sstevel@tonic-gate 	new->c_count = count;
5192*7c478bd9Sstevel@tonic-gate 	cbstats.nc_new++;
5193*7c478bd9Sstevel@tonic-gate 	cbstats.nc_alloc++;
5194*7c478bd9Sstevel@tonic-gate 	if (cbstats.nc_alloc > cbstats.nc_maxlist)
5195*7c478bd9Sstevel@tonic-gate 		cbstats.nc_maxlist = cbstats.nc_alloc;
5196*7c478bd9Sstevel@tonic-gate }
5197*7c478bd9Sstevel@tonic-gate 
5198*7c478bd9Sstevel@tonic-gate void
5199*7c478bd9Sstevel@tonic-gate ddi_set_callback(int (*funcp)(caddr_t), caddr_t arg, uintptr_t *listid)
5200*7c478bd9Sstevel@tonic-gate {
5201*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ddi_callback_mutex);
5202*7c478bd9Sstevel@tonic-gate 	cbstats.nc_asked++;
5203*7c478bd9Sstevel@tonic-gate 	if ((cbstats.nc_asked - cbstats.nc_run) > cbstats.nc_maxreq)
5204*7c478bd9Sstevel@tonic-gate 		cbstats.nc_maxreq = (cbstats.nc_asked - cbstats.nc_run);
5205*7c478bd9Sstevel@tonic-gate 	(void) callback_insert(funcp, arg, listid, 1);
5206*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ddi_callback_mutex);
5207*7c478bd9Sstevel@tonic-gate }
5208*7c478bd9Sstevel@tonic-gate 
5209*7c478bd9Sstevel@tonic-gate static void
5210*7c478bd9Sstevel@tonic-gate real_callback_run(void *Queue)
5211*7c478bd9Sstevel@tonic-gate {
5212*7c478bd9Sstevel@tonic-gate 	int (*funcp)(caddr_t);
5213*7c478bd9Sstevel@tonic-gate 	caddr_t arg;
5214*7c478bd9Sstevel@tonic-gate 	int count, rval;
5215*7c478bd9Sstevel@tonic-gate 	uintptr_t *listid;
5216*7c478bd9Sstevel@tonic-gate 	struct ddi_callback *list, *marker;
5217*7c478bd9Sstevel@tonic-gate 	int check_pending = 1;
5218*7c478bd9Sstevel@tonic-gate 	int pending = 0;
5219*7c478bd9Sstevel@tonic-gate 
5220*7c478bd9Sstevel@tonic-gate 	do {
5221*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ddi_callback_mutex);
5222*7c478bd9Sstevel@tonic-gate 		listid = Queue;
5223*7c478bd9Sstevel@tonic-gate 		list = (struct ddi_callback *)*listid;
5224*7c478bd9Sstevel@tonic-gate 		if (list == NULL) {
5225*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ddi_callback_mutex);
5226*7c478bd9Sstevel@tonic-gate 			return;
5227*7c478bd9Sstevel@tonic-gate 		}
5228*7c478bd9Sstevel@tonic-gate 		if (check_pending) {
5229*7c478bd9Sstevel@tonic-gate 			marker = list;
5230*7c478bd9Sstevel@tonic-gate 			while (marker != NULL) {
5231*7c478bd9Sstevel@tonic-gate 				pending += marker->c_count;
5232*7c478bd9Sstevel@tonic-gate 				marker = marker->c_nlist;
5233*7c478bd9Sstevel@tonic-gate 			}
5234*7c478bd9Sstevel@tonic-gate 			check_pending = 0;
5235*7c478bd9Sstevel@tonic-gate 		}
5236*7c478bd9Sstevel@tonic-gate 		ASSERT(pending > 0);
5237*7c478bd9Sstevel@tonic-gate 		ASSERT(list->c_count > 0);
5238*7c478bd9Sstevel@tonic-gate 		funcp = list->c_call;
5239*7c478bd9Sstevel@tonic-gate 		arg = list->c_arg;
5240*7c478bd9Sstevel@tonic-gate 		count = list->c_count;
5241*7c478bd9Sstevel@tonic-gate 		*(uintptr_t *)Queue = (uintptr_t)list->c_nlist;
5242*7c478bd9Sstevel@tonic-gate 		if (list >= &callbackq[0] &&
5243*7c478bd9Sstevel@tonic-gate 		    list <= &callbackq[ncallbacks-1]) {
5244*7c478bd9Sstevel@tonic-gate 			list->c_nfree = callbackqfree;
5245*7c478bd9Sstevel@tonic-gate 			callbackqfree = list;
5246*7c478bd9Sstevel@tonic-gate 		} else
5247*7c478bd9Sstevel@tonic-gate 			kmem_free(list, list->c_size);
5248*7c478bd9Sstevel@tonic-gate 
5249*7c478bd9Sstevel@tonic-gate 		cbstats.nc_delete++;
5250*7c478bd9Sstevel@tonic-gate 		cbstats.nc_alloc--;
5251*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ddi_callback_mutex);
5252*7c478bd9Sstevel@tonic-gate 
5253*7c478bd9Sstevel@tonic-gate 		do {
5254*7c478bd9Sstevel@tonic-gate 			if ((rval = (*funcp)(arg)) == 0) {
5255*7c478bd9Sstevel@tonic-gate 				pending -= count;
5256*7c478bd9Sstevel@tonic-gate 				mutex_enter(&ddi_callback_mutex);
5257*7c478bd9Sstevel@tonic-gate 				(void) callback_insert(funcp, arg, listid,
5258*7c478bd9Sstevel@tonic-gate 					count);
5259*7c478bd9Sstevel@tonic-gate 				cbstats.nc_runouts++;
5260*7c478bd9Sstevel@tonic-gate 			} else {
5261*7c478bd9Sstevel@tonic-gate 				pending--;
5262*7c478bd9Sstevel@tonic-gate 				mutex_enter(&ddi_callback_mutex);
5263*7c478bd9Sstevel@tonic-gate 				cbstats.nc_run++;
5264*7c478bd9Sstevel@tonic-gate 			}
5265*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ddi_callback_mutex);
5266*7c478bd9Sstevel@tonic-gate 		} while (rval != 0 && (--count > 0));
5267*7c478bd9Sstevel@tonic-gate 	} while (pending > 0);
5268*7c478bd9Sstevel@tonic-gate }
5269*7c478bd9Sstevel@tonic-gate 
5270*7c478bd9Sstevel@tonic-gate void
5271*7c478bd9Sstevel@tonic-gate ddi_run_callback(uintptr_t *listid)
5272*7c478bd9Sstevel@tonic-gate {
5273*7c478bd9Sstevel@tonic-gate 	softcall(real_callback_run, listid);
5274*7c478bd9Sstevel@tonic-gate }
5275*7c478bd9Sstevel@tonic-gate 
5276*7c478bd9Sstevel@tonic-gate dev_info_t *
5277*7c478bd9Sstevel@tonic-gate nodevinfo(dev_t dev, int otyp)
5278*7c478bd9Sstevel@tonic-gate {
5279*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dev, otyp))
5280*7c478bd9Sstevel@tonic-gate 	return ((dev_info_t *)0);
5281*7c478bd9Sstevel@tonic-gate }
5282*7c478bd9Sstevel@tonic-gate 
5283*7c478bd9Sstevel@tonic-gate /*
5284*7c478bd9Sstevel@tonic-gate  * A driver should support its own getinfo(9E) entry point. This function
5285*7c478bd9Sstevel@tonic-gate  * is provided as a convenience for ON drivers that don't expect their
5286*7c478bd9Sstevel@tonic-gate  * getinfo(9E) entry point to be called. A driver that uses this must not
5287*7c478bd9Sstevel@tonic-gate  * call ddi_create_minor_node.
5288*7c478bd9Sstevel@tonic-gate  */
5289*7c478bd9Sstevel@tonic-gate int
5290*7c478bd9Sstevel@tonic-gate ddi_no_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
5291*7c478bd9Sstevel@tonic-gate {
5292*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, infocmd, arg, result))
5293*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
5294*7c478bd9Sstevel@tonic-gate }
5295*7c478bd9Sstevel@tonic-gate 
5296*7c478bd9Sstevel@tonic-gate /*
5297*7c478bd9Sstevel@tonic-gate  * A driver should support its own getinfo(9E) entry point. This function
5298*7c478bd9Sstevel@tonic-gate  * is provided as a convenience for ON drivers that where the minor number
5299*7c478bd9Sstevel@tonic-gate  * is the instance. Drivers that do not have 1:1 mapping must implement
5300*7c478bd9Sstevel@tonic-gate  * their own getinfo(9E) function.
5301*7c478bd9Sstevel@tonic-gate  */
5302*7c478bd9Sstevel@tonic-gate int
5303*7c478bd9Sstevel@tonic-gate ddi_getinfo_1to1(dev_info_t *dip, ddi_info_cmd_t infocmd,
5304*7c478bd9Sstevel@tonic-gate     void *arg, void **result)
5305*7c478bd9Sstevel@tonic-gate {
5306*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip))
5307*7c478bd9Sstevel@tonic-gate 	int	instance;
5308*7c478bd9Sstevel@tonic-gate 
5309*7c478bd9Sstevel@tonic-gate 	if (infocmd != DDI_INFO_DEVT2INSTANCE)
5310*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5311*7c478bd9Sstevel@tonic-gate 
5312*7c478bd9Sstevel@tonic-gate 	instance = getminor((dev_t)(uintptr_t)arg);
5313*7c478bd9Sstevel@tonic-gate 	*result = (void *)(uintptr_t)instance;
5314*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5315*7c478bd9Sstevel@tonic-gate }
5316*7c478bd9Sstevel@tonic-gate 
5317*7c478bd9Sstevel@tonic-gate int
5318*7c478bd9Sstevel@tonic-gate ddifail(dev_info_t *devi, ddi_attach_cmd_t cmd)
5319*7c478bd9Sstevel@tonic-gate {
5320*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(devi, cmd))
5321*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
5322*7c478bd9Sstevel@tonic-gate }
5323*7c478bd9Sstevel@tonic-gate 
5324*7c478bd9Sstevel@tonic-gate int
5325*7c478bd9Sstevel@tonic-gate ddi_no_dma_map(dev_info_t *dip, dev_info_t *rdip,
5326*7c478bd9Sstevel@tonic-gate     struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
5327*7c478bd9Sstevel@tonic-gate {
5328*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, dmareqp, handlep))
5329*7c478bd9Sstevel@tonic-gate 	return (DDI_DMA_NOMAPPING);
5330*7c478bd9Sstevel@tonic-gate }
5331*7c478bd9Sstevel@tonic-gate 
5332*7c478bd9Sstevel@tonic-gate int
5333*7c478bd9Sstevel@tonic-gate ddi_no_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
5334*7c478bd9Sstevel@tonic-gate     int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
5335*7c478bd9Sstevel@tonic-gate {
5336*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, attr, waitfp, arg, handlep))
5337*7c478bd9Sstevel@tonic-gate 	return (DDI_DMA_BADATTR);
5338*7c478bd9Sstevel@tonic-gate }
5339*7c478bd9Sstevel@tonic-gate 
5340*7c478bd9Sstevel@tonic-gate int
5341*7c478bd9Sstevel@tonic-gate ddi_no_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
5342*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle)
5343*7c478bd9Sstevel@tonic-gate {
5344*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, handle))
5345*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
5346*7c478bd9Sstevel@tonic-gate }
5347*7c478bd9Sstevel@tonic-gate 
5348*7c478bd9Sstevel@tonic-gate int
5349*7c478bd9Sstevel@tonic-gate ddi_no_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
5350*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
5351*7c478bd9Sstevel@tonic-gate     ddi_dma_cookie_t *cp, uint_t *ccountp)
5352*7c478bd9Sstevel@tonic-gate {
5353*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, handle, dmareq, cp, ccountp))
5354*7c478bd9Sstevel@tonic-gate 	return (DDI_DMA_NOMAPPING);
5355*7c478bd9Sstevel@tonic-gate }
5356*7c478bd9Sstevel@tonic-gate 
5357*7c478bd9Sstevel@tonic-gate int
5358*7c478bd9Sstevel@tonic-gate ddi_no_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
5359*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle)
5360*7c478bd9Sstevel@tonic-gate {
5361*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, handle))
5362*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
5363*7c478bd9Sstevel@tonic-gate }
5364*7c478bd9Sstevel@tonic-gate 
5365*7c478bd9Sstevel@tonic-gate int
5366*7c478bd9Sstevel@tonic-gate ddi_no_dma_flush(dev_info_t *dip, dev_info_t *rdip,
5367*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle, off_t off, size_t len,
5368*7c478bd9Sstevel@tonic-gate     uint_t cache_flags)
5369*7c478bd9Sstevel@tonic-gate {
5370*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, handle, off, len, cache_flags))
5371*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
5372*7c478bd9Sstevel@tonic-gate }
5373*7c478bd9Sstevel@tonic-gate 
5374*7c478bd9Sstevel@tonic-gate int
5375*7c478bd9Sstevel@tonic-gate ddi_no_dma_win(dev_info_t *dip, dev_info_t *rdip,
5376*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle, uint_t win, off_t *offp,
5377*7c478bd9Sstevel@tonic-gate     size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
5378*7c478bd9Sstevel@tonic-gate {
5379*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, handle, win, offp, lenp, cookiep, ccountp))
5380*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
5381*7c478bd9Sstevel@tonic-gate }
5382*7c478bd9Sstevel@tonic-gate 
5383*7c478bd9Sstevel@tonic-gate int
5384*7c478bd9Sstevel@tonic-gate ddi_no_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
5385*7c478bd9Sstevel@tonic-gate     ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
5386*7c478bd9Sstevel@tonic-gate     off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags)
5387*7c478bd9Sstevel@tonic-gate {
5388*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, handle, request, offp, lenp, objp, flags))
5389*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
5390*7c478bd9Sstevel@tonic-gate }
5391*7c478bd9Sstevel@tonic-gate 
5392*7c478bd9Sstevel@tonic-gate void
5393*7c478bd9Sstevel@tonic-gate ddivoid(void)
5394*7c478bd9Sstevel@tonic-gate {}
5395*7c478bd9Sstevel@tonic-gate 
5396*7c478bd9Sstevel@tonic-gate int
5397*7c478bd9Sstevel@tonic-gate nochpoll(dev_t dev, short events, int anyyet, short *reventsp,
5398*7c478bd9Sstevel@tonic-gate     struct pollhead **pollhdrp)
5399*7c478bd9Sstevel@tonic-gate {
5400*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dev, events, anyyet, reventsp, pollhdrp))
5401*7c478bd9Sstevel@tonic-gate 	return (ENXIO);
5402*7c478bd9Sstevel@tonic-gate }
5403*7c478bd9Sstevel@tonic-gate 
5404*7c478bd9Sstevel@tonic-gate cred_t *
5405*7c478bd9Sstevel@tonic-gate ddi_get_cred(void)
5406*7c478bd9Sstevel@tonic-gate {
5407*7c478bd9Sstevel@tonic-gate 	return (CRED());
5408*7c478bd9Sstevel@tonic-gate }
5409*7c478bd9Sstevel@tonic-gate 
5410*7c478bd9Sstevel@tonic-gate clock_t
5411*7c478bd9Sstevel@tonic-gate ddi_get_lbolt(void)
5412*7c478bd9Sstevel@tonic-gate {
5413*7c478bd9Sstevel@tonic-gate 	return (lbolt);
5414*7c478bd9Sstevel@tonic-gate }
5415*7c478bd9Sstevel@tonic-gate 
5416*7c478bd9Sstevel@tonic-gate time_t
5417*7c478bd9Sstevel@tonic-gate ddi_get_time(void)
5418*7c478bd9Sstevel@tonic-gate {
5419*7c478bd9Sstevel@tonic-gate 	time_t	now;
5420*7c478bd9Sstevel@tonic-gate 
5421*7c478bd9Sstevel@tonic-gate 	if ((now = gethrestime_sec()) == 0) {
5422*7c478bd9Sstevel@tonic-gate 		timestruc_t ts;
5423*7c478bd9Sstevel@tonic-gate 		mutex_enter(&tod_lock);
5424*7c478bd9Sstevel@tonic-gate 		ts = tod_get();
5425*7c478bd9Sstevel@tonic-gate 		mutex_exit(&tod_lock);
5426*7c478bd9Sstevel@tonic-gate 		return (ts.tv_sec);
5427*7c478bd9Sstevel@tonic-gate 	} else {
5428*7c478bd9Sstevel@tonic-gate 		return (now);
5429*7c478bd9Sstevel@tonic-gate 	}
5430*7c478bd9Sstevel@tonic-gate }
5431*7c478bd9Sstevel@tonic-gate 
5432*7c478bd9Sstevel@tonic-gate pid_t
5433*7c478bd9Sstevel@tonic-gate ddi_get_pid(void)
5434*7c478bd9Sstevel@tonic-gate {
5435*7c478bd9Sstevel@tonic-gate 	return (ttoproc(curthread)->p_pid);
5436*7c478bd9Sstevel@tonic-gate }
5437*7c478bd9Sstevel@tonic-gate 
5438*7c478bd9Sstevel@tonic-gate kt_did_t
5439*7c478bd9Sstevel@tonic-gate ddi_get_kt_did(void)
5440*7c478bd9Sstevel@tonic-gate {
5441*7c478bd9Sstevel@tonic-gate 	return (curthread->t_did);
5442*7c478bd9Sstevel@tonic-gate }
5443*7c478bd9Sstevel@tonic-gate 
5444*7c478bd9Sstevel@tonic-gate /*
5445*7c478bd9Sstevel@tonic-gate  * This function returns B_TRUE if the caller can reasonably expect that a call
5446*7c478bd9Sstevel@tonic-gate  * to cv_wait_sig(9F), cv_timedwait_sig(9F), or qwait_sig(9F) could be awakened
5447*7c478bd9Sstevel@tonic-gate  * by user-level signal.  If it returns B_FALSE, then the caller should use
5448*7c478bd9Sstevel@tonic-gate  * other means to make certain that the wait will not hang "forever."
5449*7c478bd9Sstevel@tonic-gate  *
5450*7c478bd9Sstevel@tonic-gate  * It does not check the signal mask, nor for reception of any particular
5451*7c478bd9Sstevel@tonic-gate  * signal.
5452*7c478bd9Sstevel@tonic-gate  *
5453*7c478bd9Sstevel@tonic-gate  * Currently, a thread can receive a signal if it's not a kernel thread and it
5454*7c478bd9Sstevel@tonic-gate  * is not in the middle of exit(2) tear-down.  Threads that are in that
5455*7c478bd9Sstevel@tonic-gate  * tear-down effectively convert cv_wait_sig to cv_wait, cv_timedwait_sig to
5456*7c478bd9Sstevel@tonic-gate  * cv_timedwait, and qwait_sig to qwait.
5457*7c478bd9Sstevel@tonic-gate  */
5458*7c478bd9Sstevel@tonic-gate boolean_t
5459*7c478bd9Sstevel@tonic-gate ddi_can_receive_sig(void)
5460*7c478bd9Sstevel@tonic-gate {
5461*7c478bd9Sstevel@tonic-gate 	proc_t *pp;
5462*7c478bd9Sstevel@tonic-gate 
5463*7c478bd9Sstevel@tonic-gate 	if (curthread->t_proc_flag & TP_LWPEXIT)
5464*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
5465*7c478bd9Sstevel@tonic-gate 	if ((pp = ttoproc(curthread)) == NULL)
5466*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
5467*7c478bd9Sstevel@tonic-gate 	return (pp->p_as != &kas);
5468*7c478bd9Sstevel@tonic-gate }
5469*7c478bd9Sstevel@tonic-gate 
5470*7c478bd9Sstevel@tonic-gate /*
5471*7c478bd9Sstevel@tonic-gate  * Swap bytes in 16-bit [half-]words
5472*7c478bd9Sstevel@tonic-gate  */
5473*7c478bd9Sstevel@tonic-gate void
5474*7c478bd9Sstevel@tonic-gate swab(void *src, void *dst, size_t nbytes)
5475*7c478bd9Sstevel@tonic-gate {
5476*7c478bd9Sstevel@tonic-gate 	uchar_t *pf = (uchar_t *)src;
5477*7c478bd9Sstevel@tonic-gate 	uchar_t *pt = (uchar_t *)dst;
5478*7c478bd9Sstevel@tonic-gate 	uchar_t tmp;
5479*7c478bd9Sstevel@tonic-gate 	int nshorts;
5480*7c478bd9Sstevel@tonic-gate 
5481*7c478bd9Sstevel@tonic-gate 	nshorts = nbytes >> 1;
5482*7c478bd9Sstevel@tonic-gate 
5483*7c478bd9Sstevel@tonic-gate 	while (--nshorts >= 0) {
5484*7c478bd9Sstevel@tonic-gate 		tmp = *pf++;
5485*7c478bd9Sstevel@tonic-gate 		*pt++ = *pf++;
5486*7c478bd9Sstevel@tonic-gate 		*pt++ = tmp;
5487*7c478bd9Sstevel@tonic-gate 	}
5488*7c478bd9Sstevel@tonic-gate }
5489*7c478bd9Sstevel@tonic-gate 
5490*7c478bd9Sstevel@tonic-gate static void
5491*7c478bd9Sstevel@tonic-gate ddi_append_minor_node(dev_info_t *ddip, struct ddi_minor_data *dmdp)
5492*7c478bd9Sstevel@tonic-gate {
5493*7c478bd9Sstevel@tonic-gate 	struct ddi_minor_data *dp;
5494*7c478bd9Sstevel@tonic-gate 
5495*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(DEVI(ddip)->devi_lock));
5496*7c478bd9Sstevel@tonic-gate 	i_devi_enter(ddip, DEVI_S_MD_UPDATE, DEVI_S_MD_UPDATE, 1);
5497*7c478bd9Sstevel@tonic-gate 
5498*7c478bd9Sstevel@tonic-gate 	if ((dp = DEVI(ddip)->devi_minor) == (struct ddi_minor_data *)NULL) {
5499*7c478bd9Sstevel@tonic-gate 		DEVI(ddip)->devi_minor = dmdp;
5500*7c478bd9Sstevel@tonic-gate 	} else {
5501*7c478bd9Sstevel@tonic-gate 		while (dp->next != (struct ddi_minor_data *)NULL)
5502*7c478bd9Sstevel@tonic-gate 			dp = dp->next;
5503*7c478bd9Sstevel@tonic-gate 		dp->next = dmdp;
5504*7c478bd9Sstevel@tonic-gate 	}
5505*7c478bd9Sstevel@tonic-gate 
5506*7c478bd9Sstevel@tonic-gate 	i_devi_exit(ddip, DEVI_S_MD_UPDATE, 1);
5507*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(DEVI(ddip)->devi_lock));
5508*7c478bd9Sstevel@tonic-gate }
5509*7c478bd9Sstevel@tonic-gate 
5510*7c478bd9Sstevel@tonic-gate /*
5511*7c478bd9Sstevel@tonic-gate  * Part of the obsolete SunCluster DDI Hooks.
5512*7c478bd9Sstevel@tonic-gate  * Keep for binary compatibility
5513*7c478bd9Sstevel@tonic-gate  */
5514*7c478bd9Sstevel@tonic-gate minor_t
5515*7c478bd9Sstevel@tonic-gate ddi_getiminor(dev_t dev)
5516*7c478bd9Sstevel@tonic-gate {
5517*7c478bd9Sstevel@tonic-gate 	return (getminor(dev));
5518*7c478bd9Sstevel@tonic-gate }
5519*7c478bd9Sstevel@tonic-gate 
5520*7c478bd9Sstevel@tonic-gate static int
5521*7c478bd9Sstevel@tonic-gate i_log_devfs_minor_create(dev_info_t *dip, char *minor_name)
5522*7c478bd9Sstevel@tonic-gate {
5523*7c478bd9Sstevel@tonic-gate 	int se_flag;
5524*7c478bd9Sstevel@tonic-gate 	int kmem_flag;
5525*7c478bd9Sstevel@tonic-gate 	int se_err;
5526*7c478bd9Sstevel@tonic-gate 	char *pathname;
5527*7c478bd9Sstevel@tonic-gate 	sysevent_t *ev = NULL;
5528*7c478bd9Sstevel@tonic-gate 	sysevent_id_t eid;
5529*7c478bd9Sstevel@tonic-gate 	sysevent_value_t se_val;
5530*7c478bd9Sstevel@tonic-gate 	sysevent_attr_list_t *ev_attr_list = NULL;
5531*7c478bd9Sstevel@tonic-gate 
5532*7c478bd9Sstevel@tonic-gate 	/* determine interrupt context */
5533*7c478bd9Sstevel@tonic-gate 	se_flag = (servicing_interrupt()) ? SE_NOSLEEP : SE_SLEEP;
5534*7c478bd9Sstevel@tonic-gate 	kmem_flag = (se_flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
5535*7c478bd9Sstevel@tonic-gate 
5536*7c478bd9Sstevel@tonic-gate 	i_ddi_di_cache_invalidate(kmem_flag);
5537*7c478bd9Sstevel@tonic-gate 
5538*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
5539*7c478bd9Sstevel@tonic-gate 	if ((se_flag == SE_NOSLEEP) && sunddi_debug) {
5540*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "ddi_create_minor_node: called from "
5541*7c478bd9Sstevel@tonic-gate 		    "interrupt level by driver %s",
5542*7c478bd9Sstevel@tonic-gate 		    ddi_driver_name(dip));
5543*7c478bd9Sstevel@tonic-gate 	}
5544*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
5545*7c478bd9Sstevel@tonic-gate 
5546*7c478bd9Sstevel@tonic-gate 	ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_MINOR_CREATE, EP_DDI, se_flag);
5547*7c478bd9Sstevel@tonic-gate 	if (ev == NULL) {
5548*7c478bd9Sstevel@tonic-gate 		goto fail;
5549*7c478bd9Sstevel@tonic-gate 	}
5550*7c478bd9Sstevel@tonic-gate 
5551*7c478bd9Sstevel@tonic-gate 	pathname = kmem_alloc(MAXPATHLEN, kmem_flag);
5552*7c478bd9Sstevel@tonic-gate 	if (pathname == NULL) {
5553*7c478bd9Sstevel@tonic-gate 		sysevent_free(ev);
5554*7c478bd9Sstevel@tonic-gate 		goto fail;
5555*7c478bd9Sstevel@tonic-gate 	}
5556*7c478bd9Sstevel@tonic-gate 
5557*7c478bd9Sstevel@tonic-gate 	(void) ddi_pathname(dip, pathname);
5558*7c478bd9Sstevel@tonic-gate 	ASSERT(strlen(pathname));
5559*7c478bd9Sstevel@tonic-gate 	se_val.value_type = SE_DATA_TYPE_STRING;
5560*7c478bd9Sstevel@tonic-gate 	se_val.value.sv_string = pathname;
5561*7c478bd9Sstevel@tonic-gate 	if (sysevent_add_attr(&ev_attr_list, DEVFS_PATHNAME,
5562*7c478bd9Sstevel@tonic-gate 	    &se_val, se_flag) != 0) {
5563*7c478bd9Sstevel@tonic-gate 		kmem_free(pathname, MAXPATHLEN);
5564*7c478bd9Sstevel@tonic-gate 		sysevent_free(ev);
5565*7c478bd9Sstevel@tonic-gate 		goto fail;
5566*7c478bd9Sstevel@tonic-gate 	}
5567*7c478bd9Sstevel@tonic-gate 	kmem_free(pathname, MAXPATHLEN);
5568*7c478bd9Sstevel@tonic-gate 
5569*7c478bd9Sstevel@tonic-gate 	/*
5570*7c478bd9Sstevel@tonic-gate 	 * allow for NULL minor names
5571*7c478bd9Sstevel@tonic-gate 	 */
5572*7c478bd9Sstevel@tonic-gate 	if (minor_name != NULL) {
5573*7c478bd9Sstevel@tonic-gate 		se_val.value.sv_string = minor_name;
5574*7c478bd9Sstevel@tonic-gate 		if (sysevent_add_attr(&ev_attr_list, DEVFS_MINOR_NAME,
5575*7c478bd9Sstevel@tonic-gate 		    &se_val, se_flag) != 0) {
5576*7c478bd9Sstevel@tonic-gate 			sysevent_free_attr(ev_attr_list);
5577*7c478bd9Sstevel@tonic-gate 			sysevent_free(ev);
5578*7c478bd9Sstevel@tonic-gate 			goto fail;
5579*7c478bd9Sstevel@tonic-gate 		}
5580*7c478bd9Sstevel@tonic-gate 	}
5581*7c478bd9Sstevel@tonic-gate 
5582*7c478bd9Sstevel@tonic-gate 	if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
5583*7c478bd9Sstevel@tonic-gate 		sysevent_free_attr(ev_attr_list);
5584*7c478bd9Sstevel@tonic-gate 		sysevent_free(ev);
5585*7c478bd9Sstevel@tonic-gate 		goto fail;
5586*7c478bd9Sstevel@tonic-gate 	}
5587*7c478bd9Sstevel@tonic-gate 
5588*7c478bd9Sstevel@tonic-gate 	if ((se_err = log_sysevent(ev, se_flag, &eid)) != 0) {
5589*7c478bd9Sstevel@tonic-gate 		if (se_err == SE_NO_TRANSPORT) {
5590*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "/devices or /dev may not be current "
5591*7c478bd9Sstevel@tonic-gate 			    "for driver %s (%s). Run devfsadm -i %s",
5592*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip), "syseventd not responding",
5593*7c478bd9Sstevel@tonic-gate 			    ddi_driver_name(dip));
5594*7c478bd9Sstevel@tonic-gate 		} else {
5595*7c478bd9Sstevel@tonic-gate 			sysevent_free(ev);
5596*7c478bd9Sstevel@tonic-gate 			goto fail;
5597*7c478bd9Sstevel@tonic-gate 		}
5598*7c478bd9Sstevel@tonic-gate 	}
5599*7c478bd9Sstevel@tonic-gate 
5600*7c478bd9Sstevel@tonic-gate 	sysevent_free(ev);
5601*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5602*7c478bd9Sstevel@tonic-gate fail:
5603*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_WARN, "/devices or /dev may not be current "
5604*7c478bd9Sstevel@tonic-gate 	    "for driver %s. Run devfsadm -i %s",
5605*7c478bd9Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_driver_name(dip));
5606*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5607*7c478bd9Sstevel@tonic-gate }
5608*7c478bd9Sstevel@tonic-gate 
5609*7c478bd9Sstevel@tonic-gate /*
5610*7c478bd9Sstevel@tonic-gate  * failing to remove a minor node is not of interest
5611*7c478bd9Sstevel@tonic-gate  * therefore we do not generate an error message
5612*7c478bd9Sstevel@tonic-gate  */
5613*7c478bd9Sstevel@tonic-gate static int
5614*7c478bd9Sstevel@tonic-gate i_log_devfs_minor_remove(dev_info_t *dip, char *minor_name)
5615*7c478bd9Sstevel@tonic-gate {
5616*7c478bd9Sstevel@tonic-gate 	char *pathname;
5617*7c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
5618*7c478bd9Sstevel@tonic-gate 	sysevent_id_t eid;
5619*7c478bd9Sstevel@tonic-gate 	sysevent_value_t se_val;
5620*7c478bd9Sstevel@tonic-gate 	sysevent_attr_list_t *ev_attr_list = NULL;
5621*7c478bd9Sstevel@tonic-gate 
5622*7c478bd9Sstevel@tonic-gate 	/*
5623*7c478bd9Sstevel@tonic-gate 	 * only log ddi_remove_minor_node() calls outside the scope
5624*7c478bd9Sstevel@tonic-gate 	 * of attach/detach reconfigurations and when the dip is
5625*7c478bd9Sstevel@tonic-gate 	 * still initialized.
5626*7c478bd9Sstevel@tonic-gate 	 */
5627*7c478bd9Sstevel@tonic-gate 	if (DEVI_IS_ATTACHING(dip) || DEVI_IS_DETACHING(dip) ||
5628*7c478bd9Sstevel@tonic-gate 	    (i_ddi_node_state(dip) < DS_INITIALIZED)) {
5629*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5630*7c478bd9Sstevel@tonic-gate 	}
5631*7c478bd9Sstevel@tonic-gate 
5632*7c478bd9Sstevel@tonic-gate 	i_ddi_di_cache_invalidate(KM_SLEEP);
5633*7c478bd9Sstevel@tonic-gate 
5634*7c478bd9Sstevel@tonic-gate 	ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_MINOR_REMOVE, EP_DDI, SE_SLEEP);
5635*7c478bd9Sstevel@tonic-gate 	if (ev == NULL) {
5636*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5637*7c478bd9Sstevel@tonic-gate 	}
5638*7c478bd9Sstevel@tonic-gate 
5639*7c478bd9Sstevel@tonic-gate 	pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
5640*7c478bd9Sstevel@tonic-gate 	if (pathname == NULL) {
5641*7c478bd9Sstevel@tonic-gate 		sysevent_free(ev);
5642*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5643*7c478bd9Sstevel@tonic-gate 	}
5644*7c478bd9Sstevel@tonic-gate 
5645*7c478bd9Sstevel@tonic-gate 	(void) ddi_pathname(dip, pathname);
5646*7c478bd9Sstevel@tonic-gate 	ASSERT(strlen(pathname));
5647*7c478bd9Sstevel@tonic-gate 	se_val.value_type = SE_DATA_TYPE_STRING;
5648*7c478bd9Sstevel@tonic-gate 	se_val.value.sv_string = pathname;
5649*7c478bd9Sstevel@tonic-gate 	if (sysevent_add_attr(&ev_attr_list, DEVFS_PATHNAME,
5650*7c478bd9Sstevel@tonic-gate 	    &se_val, SE_SLEEP) != 0) {
5651*7c478bd9Sstevel@tonic-gate 		kmem_free(pathname, MAXPATHLEN);
5652*7c478bd9Sstevel@tonic-gate 		sysevent_free(ev);
5653*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
5654*7c478bd9Sstevel@tonic-gate 	}
5655*7c478bd9Sstevel@tonic-gate 
5656*7c478bd9Sstevel@tonic-gate 	kmem_free(pathname, MAXPATHLEN);
5657*7c478bd9Sstevel@tonic-gate 
5658*7c478bd9Sstevel@tonic-gate 	/*
5659*7c478bd9Sstevel@tonic-gate 	 * allow for NULL minor names
5660*7c478bd9Sstevel@tonic-gate 	 */
5661*7c478bd9Sstevel@tonic-gate 	if (minor_name != NULL) {
5662*7c478bd9Sstevel@tonic-gate 		se_val.value.sv_string = minor_name;
5663*7c478bd9Sstevel@tonic-gate 		if (sysevent_add_attr(&ev_attr_list, DEVFS_MINOR_NAME,
5664*7c478bd9Sstevel@tonic-gate 		    &se_val, SE_SLEEP) != 0) {
5665*7c478bd9Sstevel@tonic-gate 			sysevent_free_attr(ev_attr_list);
5666*7c478bd9Sstevel@tonic-gate 			goto fail;
5667*7c478bd9Sstevel@tonic-gate 		}
5668*7c478bd9Sstevel@tonic-gate 	}
5669*7c478bd9Sstevel@tonic-gate 
5670*7c478bd9Sstevel@tonic-gate 	if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
5671*7c478bd9Sstevel@tonic-gate 		sysevent_free_attr(ev_attr_list);
5672*7c478bd9Sstevel@tonic-gate 	} else {
5673*7c478bd9Sstevel@tonic-gate 		(void) log_sysevent(ev, SE_SLEEP, &eid);
5674*7c478bd9Sstevel@tonic-gate 	}
5675*7c478bd9Sstevel@tonic-gate fail:
5676*7c478bd9Sstevel@tonic-gate 	sysevent_free(ev);
5677*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5678*7c478bd9Sstevel@tonic-gate }
5679*7c478bd9Sstevel@tonic-gate 
5680*7c478bd9Sstevel@tonic-gate /*
5681*7c478bd9Sstevel@tonic-gate  * Derive the device class of the node.
5682*7c478bd9Sstevel@tonic-gate  * Device class names aren't defined yet. Until this is done we use
5683*7c478bd9Sstevel@tonic-gate  * devfs event subclass names as device class names.
5684*7c478bd9Sstevel@tonic-gate  */
5685*7c478bd9Sstevel@tonic-gate static int
5686*7c478bd9Sstevel@tonic-gate derive_devi_class(dev_info_t *dip, char *node_type, int flag)
5687*7c478bd9Sstevel@tonic-gate {
5688*7c478bd9Sstevel@tonic-gate 	int rv = DDI_SUCCESS;
5689*7c478bd9Sstevel@tonic-gate 
5690*7c478bd9Sstevel@tonic-gate 	if (i_ddi_devi_class(dip) == NULL) {
5691*7c478bd9Sstevel@tonic-gate 		if (strncmp(node_type, DDI_NT_BLOCK,
5692*7c478bd9Sstevel@tonic-gate 		    sizeof (DDI_NT_BLOCK) - 1) == 0 &&
5693*7c478bd9Sstevel@tonic-gate 		    (node_type[sizeof (DDI_NT_BLOCK) - 1] == '\0' ||
5694*7c478bd9Sstevel@tonic-gate 		    node_type[sizeof (DDI_NT_BLOCK) - 1] == ':') &&
5695*7c478bd9Sstevel@tonic-gate 		    strcmp(node_type, DDI_NT_FD) != 0) {
5696*7c478bd9Sstevel@tonic-gate 
5697*7c478bd9Sstevel@tonic-gate 			rv = i_ddi_set_devi_class(dip, ESC_DISK, flag);
5698*7c478bd9Sstevel@tonic-gate 
5699*7c478bd9Sstevel@tonic-gate 		} else if (strncmp(node_type, DDI_NT_NET,
5700*7c478bd9Sstevel@tonic-gate 		    sizeof (DDI_NT_NET) - 1) == 0 &&
5701*7c478bd9Sstevel@tonic-gate 		    (node_type[sizeof (DDI_NT_NET) - 1] == '\0' ||
5702*7c478bd9Sstevel@tonic-gate 		    node_type[sizeof (DDI_NT_NET) - 1] == ':')) {
5703*7c478bd9Sstevel@tonic-gate 
5704*7c478bd9Sstevel@tonic-gate 			rv = i_ddi_set_devi_class(dip, ESC_NETWORK, flag);
5705*7c478bd9Sstevel@tonic-gate 		}
5706*7c478bd9Sstevel@tonic-gate 	}
5707*7c478bd9Sstevel@tonic-gate 
5708*7c478bd9Sstevel@tonic-gate 	return (rv);
5709*7c478bd9Sstevel@tonic-gate }
5710*7c478bd9Sstevel@tonic-gate 
5711*7c478bd9Sstevel@tonic-gate /*
5712*7c478bd9Sstevel@tonic-gate  * Check compliance with PSARC 2003/375:
5713*7c478bd9Sstevel@tonic-gate  *
5714*7c478bd9Sstevel@tonic-gate  * The name must contain only characters a-z, A-Z, 0-9 or _ and it must not
5715*7c478bd9Sstevel@tonic-gate  * exceed IFNAMSIZ (16) characters in length.
5716*7c478bd9Sstevel@tonic-gate  */
5717*7c478bd9Sstevel@tonic-gate static boolean_t
5718*7c478bd9Sstevel@tonic-gate verify_name(char *name)
5719*7c478bd9Sstevel@tonic-gate {
5720*7c478bd9Sstevel@tonic-gate 	size_t	len = strlen(name);
5721*7c478bd9Sstevel@tonic-gate 	char	*cp;
5722*7c478bd9Sstevel@tonic-gate 
5723*7c478bd9Sstevel@tonic-gate 	if (len == 0 || len > IFNAMSIZ)
5724*7c478bd9Sstevel@tonic-gate 		return (B_FALSE);
5725*7c478bd9Sstevel@tonic-gate 
5726*7c478bd9Sstevel@tonic-gate 	for (cp = name; *cp != '\0'; cp++) {
5727*7c478bd9Sstevel@tonic-gate 		if (!isalnum(*cp) && *cp != '_')
5728*7c478bd9Sstevel@tonic-gate 			return (B_FALSE);
5729*7c478bd9Sstevel@tonic-gate 	}
5730*7c478bd9Sstevel@tonic-gate 
5731*7c478bd9Sstevel@tonic-gate 	return (B_TRUE);
5732*7c478bd9Sstevel@tonic-gate }
5733*7c478bd9Sstevel@tonic-gate 
5734*7c478bd9Sstevel@tonic-gate /*
5735*7c478bd9Sstevel@tonic-gate  * ddi_create_minor_common:	Create a  ddi_minor_data structure and
5736*7c478bd9Sstevel@tonic-gate  *				attach it to the given devinfo node.
5737*7c478bd9Sstevel@tonic-gate  */
5738*7c478bd9Sstevel@tonic-gate 
5739*7c478bd9Sstevel@tonic-gate int
5740*7c478bd9Sstevel@tonic-gate ddi_create_minor_common(dev_info_t *dip, char *name, int spec_type,
5741*7c478bd9Sstevel@tonic-gate     minor_t minor_num, char *node_type, int flag, ddi_minor_type mtype,
5742*7c478bd9Sstevel@tonic-gate     const char *read_priv, const char *write_priv, mode_t priv_mode)
5743*7c478bd9Sstevel@tonic-gate {
5744*7c478bd9Sstevel@tonic-gate 	struct ddi_minor_data *dmdp;
5745*7c478bd9Sstevel@tonic-gate 	major_t major;
5746*7c478bd9Sstevel@tonic-gate 
5747*7c478bd9Sstevel@tonic-gate 	if (spec_type != S_IFCHR && spec_type != S_IFBLK)
5748*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5749*7c478bd9Sstevel@tonic-gate 
5750*7c478bd9Sstevel@tonic-gate 	if (name == NULL)
5751*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5752*7c478bd9Sstevel@tonic-gate 
5753*7c478bd9Sstevel@tonic-gate 	/*
5754*7c478bd9Sstevel@tonic-gate 	 * Log a message if the minor number the driver is creating
5755*7c478bd9Sstevel@tonic-gate 	 * is not expressible on the on-disk filesystem (currently
5756*7c478bd9Sstevel@tonic-gate 	 * this is limited to 18 bits both by UFS). The device can
5757*7c478bd9Sstevel@tonic-gate 	 * be opened via devfs, but not by device special files created
5758*7c478bd9Sstevel@tonic-gate 	 * via mknod().
5759*7c478bd9Sstevel@tonic-gate 	 */
5760*7c478bd9Sstevel@tonic-gate 	if (minor_num > L_MAXMIN32) {
5761*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
5762*7c478bd9Sstevel@tonic-gate 		    "%s%d:%s minor 0x%x too big for 32-bit applications",
5763*7c478bd9Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip),
5764*7c478bd9Sstevel@tonic-gate 		    name, minor_num);
5765*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5766*7c478bd9Sstevel@tonic-gate 	}
5767*7c478bd9Sstevel@tonic-gate 
5768*7c478bd9Sstevel@tonic-gate 	/* dip must be bound and attached */
5769*7c478bd9Sstevel@tonic-gate 	major = ddi_driver_major(dip);
5770*7c478bd9Sstevel@tonic-gate 	ASSERT(major != (major_t)-1);
5771*7c478bd9Sstevel@tonic-gate 
5772*7c478bd9Sstevel@tonic-gate 	/*
5773*7c478bd9Sstevel@tonic-gate 	 * Default node_type to DDI_PSEUDO and issue notice in debug mode
5774*7c478bd9Sstevel@tonic-gate 	 */
5775*7c478bd9Sstevel@tonic-gate 	if (node_type == NULL) {
5776*7c478bd9Sstevel@tonic-gate 		node_type = DDI_PSEUDO;
5777*7c478bd9Sstevel@tonic-gate 		NDI_CONFIG_DEBUG((CE_NOTE, "!illegal node_type NULL for %s%d "
5778*7c478bd9Sstevel@tonic-gate 		    " minor node %s; default to DDI_PSEUDO",
5779*7c478bd9Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip), name));
5780*7c478bd9Sstevel@tonic-gate 	}
5781*7c478bd9Sstevel@tonic-gate 
5782*7c478bd9Sstevel@tonic-gate 	/*
5783*7c478bd9Sstevel@tonic-gate 	 * If the driver is a network driver, ensure that the name falls within
5784*7c478bd9Sstevel@tonic-gate 	 * the interface naming constraints specified by PSARC/2003/375.
5785*7c478bd9Sstevel@tonic-gate 	 */
5786*7c478bd9Sstevel@tonic-gate 	if (strcmp(node_type, DDI_NT_NET) == 0) {
5787*7c478bd9Sstevel@tonic-gate 		if (!verify_name(name))
5788*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5789*7c478bd9Sstevel@tonic-gate 
5790*7c478bd9Sstevel@tonic-gate 		if (mtype == DDM_MINOR) {
5791*7c478bd9Sstevel@tonic-gate 			struct devnames *dnp = &devnamesp[major];
5792*7c478bd9Sstevel@tonic-gate 
5793*7c478bd9Sstevel@tonic-gate 			/* Mark driver as a network driver */
5794*7c478bd9Sstevel@tonic-gate 			LOCK_DEV_OPS(&dnp->dn_lock);
5795*7c478bd9Sstevel@tonic-gate 			dnp->dn_flags |= DN_NETWORK_DRIVER;
5796*7c478bd9Sstevel@tonic-gate 			UNLOCK_DEV_OPS(&dnp->dn_lock);
5797*7c478bd9Sstevel@tonic-gate 		}
5798*7c478bd9Sstevel@tonic-gate 	}
5799*7c478bd9Sstevel@tonic-gate 
5800*7c478bd9Sstevel@tonic-gate 	if (mtype == DDM_MINOR) {
5801*7c478bd9Sstevel@tonic-gate 		if (derive_devi_class(dip,  node_type, KM_NOSLEEP) !=
5802*7c478bd9Sstevel@tonic-gate 		    DDI_SUCCESS)
5803*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5804*7c478bd9Sstevel@tonic-gate 	}
5805*7c478bd9Sstevel@tonic-gate 
5806*7c478bd9Sstevel@tonic-gate 	/*
5807*7c478bd9Sstevel@tonic-gate 	 * Take care of minor number information for the node.
5808*7c478bd9Sstevel@tonic-gate 	 */
5809*7c478bd9Sstevel@tonic-gate 
5810*7c478bd9Sstevel@tonic-gate 	if ((dmdp = kmem_zalloc(sizeof (struct ddi_minor_data),
5811*7c478bd9Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL) {
5812*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5813*7c478bd9Sstevel@tonic-gate 	}
5814*7c478bd9Sstevel@tonic-gate 	if ((dmdp->ddm_name = i_ddi_strdup(name, KM_NOSLEEP)) == NULL) {
5815*7c478bd9Sstevel@tonic-gate 		kmem_free(dmdp, sizeof (struct ddi_minor_data));
5816*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5817*7c478bd9Sstevel@tonic-gate 	}
5818*7c478bd9Sstevel@tonic-gate 	dmdp->dip = dip;
5819*7c478bd9Sstevel@tonic-gate 	dmdp->ddm_dev = makedevice(major, minor_num);
5820*7c478bd9Sstevel@tonic-gate 	dmdp->ddm_spec_type = spec_type;
5821*7c478bd9Sstevel@tonic-gate 	dmdp->ddm_node_type = node_type;
5822*7c478bd9Sstevel@tonic-gate 	dmdp->type = mtype;
5823*7c478bd9Sstevel@tonic-gate 	if (flag & CLONE_DEV) {
5824*7c478bd9Sstevel@tonic-gate 		dmdp->type = DDM_ALIAS;
5825*7c478bd9Sstevel@tonic-gate 		dmdp->ddm_dev = makedevice(ddi_driver_major(clone_dip), major);
5826*7c478bd9Sstevel@tonic-gate 	}
5827*7c478bd9Sstevel@tonic-gate 	if (flag & PRIVONLY_DEV) {
5828*7c478bd9Sstevel@tonic-gate 		dmdp->ddm_flags |= DM_NO_FSPERM;
5829*7c478bd9Sstevel@tonic-gate 	}
5830*7c478bd9Sstevel@tonic-gate 	if (read_priv || write_priv) {
5831*7c478bd9Sstevel@tonic-gate 		dmdp->ddm_node_priv =
5832*7c478bd9Sstevel@tonic-gate 		    devpolicy_priv_by_name(read_priv, write_priv);
5833*7c478bd9Sstevel@tonic-gate 	}
5834*7c478bd9Sstevel@tonic-gate 	dmdp->ddm_priv_mode = priv_mode;
5835*7c478bd9Sstevel@tonic-gate 
5836*7c478bd9Sstevel@tonic-gate 	ddi_append_minor_node(dip, dmdp);
5837*7c478bd9Sstevel@tonic-gate 
5838*7c478bd9Sstevel@tonic-gate 	/*
5839*7c478bd9Sstevel@tonic-gate 	 * only log ddi_create_minor_node() calls which occur
5840*7c478bd9Sstevel@tonic-gate 	 * outside the scope of attach(9e)/detach(9e) reconfigurations
5841*7c478bd9Sstevel@tonic-gate 	 */
5842*7c478bd9Sstevel@tonic-gate 	if (!(DEVI_IS_ATTACHING(dip) || DEVI_IS_DETACHING(dip))) {
5843*7c478bd9Sstevel@tonic-gate 		(void) i_log_devfs_minor_create(dip, name);
5844*7c478bd9Sstevel@tonic-gate 	}
5845*7c478bd9Sstevel@tonic-gate 
5846*7c478bd9Sstevel@tonic-gate 	/*
5847*7c478bd9Sstevel@tonic-gate 	 * Check if any dacf rules match the creation of this minor node
5848*7c478bd9Sstevel@tonic-gate 	 */
5849*7c478bd9Sstevel@tonic-gate 	dacfc_match_create_minor(name, node_type, dip, dmdp, flag);
5850*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
5851*7c478bd9Sstevel@tonic-gate }
5852*7c478bd9Sstevel@tonic-gate 
5853*7c478bd9Sstevel@tonic-gate int
5854*7c478bd9Sstevel@tonic-gate ddi_create_minor_node(dev_info_t *dip, char *name, int spec_type,
5855*7c478bd9Sstevel@tonic-gate     minor_t minor_num, char *node_type, int flag)
5856*7c478bd9Sstevel@tonic-gate {
5857*7c478bd9Sstevel@tonic-gate 	return (ddi_create_minor_common(dip, name, spec_type, minor_num,
5858*7c478bd9Sstevel@tonic-gate 	    node_type, flag, DDM_MINOR, NULL, NULL, 0));
5859*7c478bd9Sstevel@tonic-gate }
5860*7c478bd9Sstevel@tonic-gate 
5861*7c478bd9Sstevel@tonic-gate int
5862*7c478bd9Sstevel@tonic-gate ddi_create_priv_minor_node(dev_info_t *dip, char *name, int spec_type,
5863*7c478bd9Sstevel@tonic-gate     minor_t minor_num, char *node_type, int flag,
5864*7c478bd9Sstevel@tonic-gate     const char *rdpriv, const char *wrpriv, mode_t priv_mode)
5865*7c478bd9Sstevel@tonic-gate {
5866*7c478bd9Sstevel@tonic-gate 	return (ddi_create_minor_common(dip, name, spec_type, minor_num,
5867*7c478bd9Sstevel@tonic-gate 	    node_type, flag, DDM_MINOR, rdpriv, wrpriv, priv_mode));
5868*7c478bd9Sstevel@tonic-gate }
5869*7c478bd9Sstevel@tonic-gate 
5870*7c478bd9Sstevel@tonic-gate int
5871*7c478bd9Sstevel@tonic-gate ddi_create_default_minor_node(dev_info_t *dip, char *name, int spec_type,
5872*7c478bd9Sstevel@tonic-gate     minor_t minor_num, char *node_type, int flag)
5873*7c478bd9Sstevel@tonic-gate {
5874*7c478bd9Sstevel@tonic-gate 	return (ddi_create_minor_common(dip, name, spec_type, minor_num,
5875*7c478bd9Sstevel@tonic-gate 	    node_type, flag, DDM_DEFAULT, NULL, NULL, 0));
5876*7c478bd9Sstevel@tonic-gate }
5877*7c478bd9Sstevel@tonic-gate 
5878*7c478bd9Sstevel@tonic-gate /*
5879*7c478bd9Sstevel@tonic-gate  * Internal (non-ddi) routine for drivers to export names known
5880*7c478bd9Sstevel@tonic-gate  * to the kernel (especially ddi_pathname_to_dev_t and friends)
5881*7c478bd9Sstevel@tonic-gate  * but not exported externally to /dev
5882*7c478bd9Sstevel@tonic-gate  */
5883*7c478bd9Sstevel@tonic-gate int
5884*7c478bd9Sstevel@tonic-gate ddi_create_internal_pathname(dev_info_t *dip, char *name, int spec_type,
5885*7c478bd9Sstevel@tonic-gate     minor_t minor_num)
5886*7c478bd9Sstevel@tonic-gate {
5887*7c478bd9Sstevel@tonic-gate 	return (ddi_create_minor_common(dip, name, spec_type, minor_num,
5888*7c478bd9Sstevel@tonic-gate 	    "internal", 0, DDM_INTERNAL_PATH, NULL, NULL, 0));
5889*7c478bd9Sstevel@tonic-gate }
5890*7c478bd9Sstevel@tonic-gate 
5891*7c478bd9Sstevel@tonic-gate void
5892*7c478bd9Sstevel@tonic-gate ddi_remove_minor_node(dev_info_t *dip, char *name)
5893*7c478bd9Sstevel@tonic-gate {
5894*7c478bd9Sstevel@tonic-gate 	struct ddi_minor_data *dmdp, *dmdp1;
5895*7c478bd9Sstevel@tonic-gate 	struct ddi_minor_data **dmdp_prev;
5896*7c478bd9Sstevel@tonic-gate 
5897*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
5898*7c478bd9Sstevel@tonic-gate 	i_devi_enter(dip, DEVI_S_MD_UPDATE, DEVI_S_MD_UPDATE, 1);
5899*7c478bd9Sstevel@tonic-gate 
5900*7c478bd9Sstevel@tonic-gate 	dmdp_prev = &DEVI(dip)->devi_minor;
5901*7c478bd9Sstevel@tonic-gate 	dmdp = DEVI(dip)->devi_minor;
5902*7c478bd9Sstevel@tonic-gate 	while (dmdp != NULL) {
5903*7c478bd9Sstevel@tonic-gate 		dmdp1 = dmdp->next;
5904*7c478bd9Sstevel@tonic-gate 		if ((name == NULL || (dmdp->ddm_name != NULL &&
5905*7c478bd9Sstevel@tonic-gate 		    strcmp(name, dmdp->ddm_name) == 0))) {
5906*7c478bd9Sstevel@tonic-gate 			if (dmdp->ddm_name != NULL) {
5907*7c478bd9Sstevel@tonic-gate 				(void) i_log_devfs_minor_remove(dip,
5908*7c478bd9Sstevel@tonic-gate 				    dmdp->ddm_name);
5909*7c478bd9Sstevel@tonic-gate 				kmem_free(dmdp->ddm_name,
5910*7c478bd9Sstevel@tonic-gate 				    strlen(dmdp->ddm_name) + 1);
5911*7c478bd9Sstevel@tonic-gate 			}
5912*7c478bd9Sstevel@tonic-gate 			/*
5913*7c478bd9Sstevel@tonic-gate 			 * Release device privilege, if any.
5914*7c478bd9Sstevel@tonic-gate 			 * Release dacf client data associated with this minor
5915*7c478bd9Sstevel@tonic-gate 			 * node by storing NULL.
5916*7c478bd9Sstevel@tonic-gate 			 */
5917*7c478bd9Sstevel@tonic-gate 			if (dmdp->ddm_node_priv)
5918*7c478bd9Sstevel@tonic-gate 				dpfree(dmdp->ddm_node_priv);
5919*7c478bd9Sstevel@tonic-gate 			dacf_store_info((dacf_infohdl_t)dmdp, NULL);
5920*7c478bd9Sstevel@tonic-gate 			kmem_free(dmdp, sizeof (struct ddi_minor_data));
5921*7c478bd9Sstevel@tonic-gate 			*dmdp_prev = dmdp1;
5922*7c478bd9Sstevel@tonic-gate 			/*
5923*7c478bd9Sstevel@tonic-gate 			 * OK, we found it, so get out now -- if we drive on,
5924*7c478bd9Sstevel@tonic-gate 			 * we will strcmp against garbage.  See 1139209.
5925*7c478bd9Sstevel@tonic-gate 			 */
5926*7c478bd9Sstevel@tonic-gate 			if (name != NULL)
5927*7c478bd9Sstevel@tonic-gate 				break;
5928*7c478bd9Sstevel@tonic-gate 		} else {
5929*7c478bd9Sstevel@tonic-gate 			dmdp_prev = &dmdp->next;
5930*7c478bd9Sstevel@tonic-gate 		}
5931*7c478bd9Sstevel@tonic-gate 		dmdp = dmdp1;
5932*7c478bd9Sstevel@tonic-gate 	}
5933*7c478bd9Sstevel@tonic-gate 
5934*7c478bd9Sstevel@tonic-gate 	i_devi_exit(dip, DEVI_S_MD_UPDATE, 1);
5935*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
5936*7c478bd9Sstevel@tonic-gate }
5937*7c478bd9Sstevel@tonic-gate 
5938*7c478bd9Sstevel@tonic-gate 
5939*7c478bd9Sstevel@tonic-gate int
5940*7c478bd9Sstevel@tonic-gate ddi_in_panic()
5941*7c478bd9Sstevel@tonic-gate {
5942*7c478bd9Sstevel@tonic-gate 	return (panicstr != NULL);
5943*7c478bd9Sstevel@tonic-gate }
5944*7c478bd9Sstevel@tonic-gate 
5945*7c478bd9Sstevel@tonic-gate 
5946*7c478bd9Sstevel@tonic-gate /*
5947*7c478bd9Sstevel@tonic-gate  * Find first bit set in a mask (returned counting from 1 up)
5948*7c478bd9Sstevel@tonic-gate  */
5949*7c478bd9Sstevel@tonic-gate 
5950*7c478bd9Sstevel@tonic-gate int
5951*7c478bd9Sstevel@tonic-gate ddi_ffs(long mask)
5952*7c478bd9Sstevel@tonic-gate {
5953*7c478bd9Sstevel@tonic-gate 	extern int ffs(long mask);
5954*7c478bd9Sstevel@tonic-gate 	return (ffs(mask));
5955*7c478bd9Sstevel@tonic-gate }
5956*7c478bd9Sstevel@tonic-gate 
5957*7c478bd9Sstevel@tonic-gate /*
5958*7c478bd9Sstevel@tonic-gate  * Find last bit set. Take mask and clear
5959*7c478bd9Sstevel@tonic-gate  * all but the most significant bit, and
5960*7c478bd9Sstevel@tonic-gate  * then let ffs do the rest of the work.
5961*7c478bd9Sstevel@tonic-gate  *
5962*7c478bd9Sstevel@tonic-gate  * Algorithm courtesy of Steve Chessin.
5963*7c478bd9Sstevel@tonic-gate  */
5964*7c478bd9Sstevel@tonic-gate 
5965*7c478bd9Sstevel@tonic-gate int
5966*7c478bd9Sstevel@tonic-gate ddi_fls(long mask)
5967*7c478bd9Sstevel@tonic-gate {
5968*7c478bd9Sstevel@tonic-gate 	extern int ffs(long);
5969*7c478bd9Sstevel@tonic-gate 
5970*7c478bd9Sstevel@tonic-gate 	while (mask) {
5971*7c478bd9Sstevel@tonic-gate 		long nx;
5972*7c478bd9Sstevel@tonic-gate 
5973*7c478bd9Sstevel@tonic-gate 		if ((nx = (mask & (mask - 1))) == 0)
5974*7c478bd9Sstevel@tonic-gate 			break;
5975*7c478bd9Sstevel@tonic-gate 		mask = nx;
5976*7c478bd9Sstevel@tonic-gate 	}
5977*7c478bd9Sstevel@tonic-gate 	return (ffs(mask));
5978*7c478bd9Sstevel@tonic-gate }
5979*7c478bd9Sstevel@tonic-gate 
5980*7c478bd9Sstevel@tonic-gate /*
5981*7c478bd9Sstevel@tonic-gate  * The next five routines comprise generic storage management utilities
5982*7c478bd9Sstevel@tonic-gate  * for driver soft state structures (in "the old days," this was done
5983*7c478bd9Sstevel@tonic-gate  * with a statically sized array - big systems and dynamic loading
5984*7c478bd9Sstevel@tonic-gate  * and unloading make heap allocation more attractive)
5985*7c478bd9Sstevel@tonic-gate  */
5986*7c478bd9Sstevel@tonic-gate 
5987*7c478bd9Sstevel@tonic-gate /*
5988*7c478bd9Sstevel@tonic-gate  * Allocate a set of pointers to 'n_items' objects of size 'size'
5989*7c478bd9Sstevel@tonic-gate  * bytes.  Each pointer is initialized to nil.
5990*7c478bd9Sstevel@tonic-gate  *
5991*7c478bd9Sstevel@tonic-gate  * The 'size' and 'n_items' values are stashed in the opaque
5992*7c478bd9Sstevel@tonic-gate  * handle returned to the caller.
5993*7c478bd9Sstevel@tonic-gate  *
5994*7c478bd9Sstevel@tonic-gate  * This implementation interprets 'set of pointers' to mean 'array
5995*7c478bd9Sstevel@tonic-gate  * of pointers' but note that nothing in the interface definition
5996*7c478bd9Sstevel@tonic-gate  * precludes an implementation that uses, for example, a linked list.
5997*7c478bd9Sstevel@tonic-gate  * However there should be a small efficiency gain from using an array
5998*7c478bd9Sstevel@tonic-gate  * at lookup time.
5999*7c478bd9Sstevel@tonic-gate  *
6000*7c478bd9Sstevel@tonic-gate  * NOTE	As an optimization, we make our growable array allocations in
6001*7c478bd9Sstevel@tonic-gate  *	powers of two (bytes), since that's how much kmem_alloc (currently)
6002*7c478bd9Sstevel@tonic-gate  *	gives us anyway.  It should save us some free/realloc's ..
6003*7c478bd9Sstevel@tonic-gate  *
6004*7c478bd9Sstevel@tonic-gate  *	As a further optimization, we make the growable array start out
6005*7c478bd9Sstevel@tonic-gate  *	with MIN_N_ITEMS in it.
6006*7c478bd9Sstevel@tonic-gate  */
6007*7c478bd9Sstevel@tonic-gate 
6008*7c478bd9Sstevel@tonic-gate #define	MIN_N_ITEMS	8	/* 8 void *'s == 32 bytes */
6009*7c478bd9Sstevel@tonic-gate 
6010*7c478bd9Sstevel@tonic-gate int
6011*7c478bd9Sstevel@tonic-gate ddi_soft_state_init(void **state_p, size_t size, size_t n_items)
6012*7c478bd9Sstevel@tonic-gate {
6013*7c478bd9Sstevel@tonic-gate 	struct i_ddi_soft_state *ss;
6014*7c478bd9Sstevel@tonic-gate 
6015*7c478bd9Sstevel@tonic-gate 	if (state_p == NULL || *state_p != NULL || size == 0)
6016*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
6017*7c478bd9Sstevel@tonic-gate 
6018*7c478bd9Sstevel@tonic-gate 	ss = kmem_zalloc(sizeof (*ss), KM_SLEEP);
6019*7c478bd9Sstevel@tonic-gate 	mutex_init(&ss->lock, NULL, MUTEX_DRIVER, NULL);
6020*7c478bd9Sstevel@tonic-gate 	ss->size = size;
6021*7c478bd9Sstevel@tonic-gate 
6022*7c478bd9Sstevel@tonic-gate 	if (n_items < MIN_N_ITEMS)
6023*7c478bd9Sstevel@tonic-gate 		ss->n_items = MIN_N_ITEMS;
6024*7c478bd9Sstevel@tonic-gate 	else {
6025*7c478bd9Sstevel@tonic-gate 		int bitlog;
6026*7c478bd9Sstevel@tonic-gate 
6027*7c478bd9Sstevel@tonic-gate 		if ((bitlog = ddi_fls(n_items)) == ddi_ffs(n_items))
6028*7c478bd9Sstevel@tonic-gate 			bitlog--;
6029*7c478bd9Sstevel@tonic-gate 		ss->n_items = 1 << bitlog;
6030*7c478bd9Sstevel@tonic-gate 	}
6031*7c478bd9Sstevel@tonic-gate 
6032*7c478bd9Sstevel@tonic-gate 	ASSERT(ss->n_items >= n_items);
6033*7c478bd9Sstevel@tonic-gate 
6034*7c478bd9Sstevel@tonic-gate 	ss->array = kmem_zalloc(ss->n_items * sizeof (void *), KM_SLEEP);
6035*7c478bd9Sstevel@tonic-gate 
6036*7c478bd9Sstevel@tonic-gate 	*state_p = ss;
6037*7c478bd9Sstevel@tonic-gate 
6038*7c478bd9Sstevel@tonic-gate 	return (0);
6039*7c478bd9Sstevel@tonic-gate }
6040*7c478bd9Sstevel@tonic-gate 
6041*7c478bd9Sstevel@tonic-gate 
6042*7c478bd9Sstevel@tonic-gate /*
6043*7c478bd9Sstevel@tonic-gate  * Allocate a state structure of size 'size' to be associated
6044*7c478bd9Sstevel@tonic-gate  * with item 'item'.
6045*7c478bd9Sstevel@tonic-gate  *
6046*7c478bd9Sstevel@tonic-gate  * In this implementation, the array is extended to
6047*7c478bd9Sstevel@tonic-gate  * allow the requested offset, if needed.
6048*7c478bd9Sstevel@tonic-gate  */
6049*7c478bd9Sstevel@tonic-gate int
6050*7c478bd9Sstevel@tonic-gate ddi_soft_state_zalloc(void *state, int item)
6051*7c478bd9Sstevel@tonic-gate {
6052*7c478bd9Sstevel@tonic-gate 	struct i_ddi_soft_state *ss;
6053*7c478bd9Sstevel@tonic-gate 	void **array;
6054*7c478bd9Sstevel@tonic-gate 	void *new_element;
6055*7c478bd9Sstevel@tonic-gate 
6056*7c478bd9Sstevel@tonic-gate 	if ((ss = state) == NULL || item < 0)
6057*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6058*7c478bd9Sstevel@tonic-gate 
6059*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ss->lock);
6060*7c478bd9Sstevel@tonic-gate 	if (ss->size == 0) {
6061*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ss->lock);
6062*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "ddi_soft_state_zalloc: bad handle: %s",
6063*7c478bd9Sstevel@tonic-gate 		    mod_containing_pc(caller()));
6064*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6065*7c478bd9Sstevel@tonic-gate 	}
6066*7c478bd9Sstevel@tonic-gate 
6067*7c478bd9Sstevel@tonic-gate 	array = ss->array;	/* NULL if ss->n_items == 0 */
6068*7c478bd9Sstevel@tonic-gate 	ASSERT(ss->n_items != 0 && array != NULL);
6069*7c478bd9Sstevel@tonic-gate 
6070*7c478bd9Sstevel@tonic-gate 	/*
6071*7c478bd9Sstevel@tonic-gate 	 * refuse to tread on an existing element
6072*7c478bd9Sstevel@tonic-gate 	 */
6073*7c478bd9Sstevel@tonic-gate 	if (item < ss->n_items && array[item] != NULL) {
6074*7c478bd9Sstevel@tonic-gate 		mutex_exit(&ss->lock);
6075*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6076*7c478bd9Sstevel@tonic-gate 	}
6077*7c478bd9Sstevel@tonic-gate 
6078*7c478bd9Sstevel@tonic-gate 	/*
6079*7c478bd9Sstevel@tonic-gate 	 * Allocate a new element to plug in
6080*7c478bd9Sstevel@tonic-gate 	 */
6081*7c478bd9Sstevel@tonic-gate 	new_element = kmem_zalloc(ss->size, KM_SLEEP);
6082*7c478bd9Sstevel@tonic-gate 
6083*7c478bd9Sstevel@tonic-gate 	/*
6084*7c478bd9Sstevel@tonic-gate 	 * Check if the array is big enough, if not, grow it.
6085*7c478bd9Sstevel@tonic-gate 	 */
6086*7c478bd9Sstevel@tonic-gate 	if (item >= ss->n_items) {
6087*7c478bd9Sstevel@tonic-gate 		void	**new_array;
6088*7c478bd9Sstevel@tonic-gate 		size_t	new_n_items;
6089*7c478bd9Sstevel@tonic-gate 		struct i_ddi_soft_state *dirty;
6090*7c478bd9Sstevel@tonic-gate 
6091*7c478bd9Sstevel@tonic-gate 		/*
6092*7c478bd9Sstevel@tonic-gate 		 * Allocate a new array of the right length, copy
6093*7c478bd9Sstevel@tonic-gate 		 * all the old pointers to the new array, then
6094*7c478bd9Sstevel@tonic-gate 		 * if it exists at all, put the old array on the
6095*7c478bd9Sstevel@tonic-gate 		 * dirty list.
6096*7c478bd9Sstevel@tonic-gate 		 *
6097*7c478bd9Sstevel@tonic-gate 		 * Note that we can't kmem_free() the old array.
6098*7c478bd9Sstevel@tonic-gate 		 *
6099*7c478bd9Sstevel@tonic-gate 		 * Why -- well the 'get' operation is 'mutex-free', so we
6100*7c478bd9Sstevel@tonic-gate 		 * can't easily catch a suspended thread that is just about
6101*7c478bd9Sstevel@tonic-gate 		 * to dereference the array we just grew out of.  So we
6102*7c478bd9Sstevel@tonic-gate 		 * cons up a header and put it on a list of 'dirty'
6103*7c478bd9Sstevel@tonic-gate 		 * pointer arrays.  (Dirty in the sense that there may
6104*7c478bd9Sstevel@tonic-gate 		 * be suspended threads somewhere that are in the middle
6105*7c478bd9Sstevel@tonic-gate 		 * of referencing them).  Fortunately, we -can- garbage
6106*7c478bd9Sstevel@tonic-gate 		 * collect it all at ddi_soft_state_fini time.
6107*7c478bd9Sstevel@tonic-gate 		 */
6108*7c478bd9Sstevel@tonic-gate 		new_n_items = ss->n_items;
6109*7c478bd9Sstevel@tonic-gate 		while (new_n_items < (1 + item))
6110*7c478bd9Sstevel@tonic-gate 			new_n_items <<= 1;	/* double array size .. */
6111*7c478bd9Sstevel@tonic-gate 
6112*7c478bd9Sstevel@tonic-gate 		ASSERT(new_n_items >= (1 + item));	/* sanity check! */
6113*7c478bd9Sstevel@tonic-gate 
6114*7c478bd9Sstevel@tonic-gate 		new_array = kmem_zalloc(new_n_items * sizeof (void *),
6115*7c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
6116*7c478bd9Sstevel@tonic-gate 		/*
6117*7c478bd9Sstevel@tonic-gate 		 * Copy the pointers into the new array
6118*7c478bd9Sstevel@tonic-gate 		 */
6119*7c478bd9Sstevel@tonic-gate 		bcopy(array, new_array, ss->n_items * sizeof (void *));
6120*7c478bd9Sstevel@tonic-gate 
6121*7c478bd9Sstevel@tonic-gate 		/*
6122*7c478bd9Sstevel@tonic-gate 		 * Save the old array on the dirty list
6123*7c478bd9Sstevel@tonic-gate 		 */
6124*7c478bd9Sstevel@tonic-gate 		dirty = kmem_zalloc(sizeof (*dirty), KM_SLEEP);
6125*7c478bd9Sstevel@tonic-gate 		dirty->array = ss->array;
6126*7c478bd9Sstevel@tonic-gate 		dirty->n_items = ss->n_items;
6127*7c478bd9Sstevel@tonic-gate 		dirty->next = ss->next;
6128*7c478bd9Sstevel@tonic-gate 		ss->next = dirty;
6129*7c478bd9Sstevel@tonic-gate 
6130*7c478bd9Sstevel@tonic-gate 		ss->array = (array = new_array);
6131*7c478bd9Sstevel@tonic-gate 		ss->n_items = new_n_items;
6132*7c478bd9Sstevel@tonic-gate 	}
6133*7c478bd9Sstevel@tonic-gate 
6134*7c478bd9Sstevel@tonic-gate 	ASSERT(array != NULL && item < ss->n_items && array[item] == NULL);
6135*7c478bd9Sstevel@tonic-gate 
6136*7c478bd9Sstevel@tonic-gate 	array[item] = new_element;
6137*7c478bd9Sstevel@tonic-gate 
6138*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ss->lock);
6139*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6140*7c478bd9Sstevel@tonic-gate }
6141*7c478bd9Sstevel@tonic-gate 
6142*7c478bd9Sstevel@tonic-gate 
6143*7c478bd9Sstevel@tonic-gate /*
6144*7c478bd9Sstevel@tonic-gate  * Fetch a pointer to the allocated soft state structure.
6145*7c478bd9Sstevel@tonic-gate  *
6146*7c478bd9Sstevel@tonic-gate  * This is designed to be cheap.
6147*7c478bd9Sstevel@tonic-gate  *
6148*7c478bd9Sstevel@tonic-gate  * There's an argument that there should be more checking for
6149*7c478bd9Sstevel@tonic-gate  * nil pointers and out of bounds on the array.. but we do a lot
6150*7c478bd9Sstevel@tonic-gate  * of that in the alloc/free routines.
6151*7c478bd9Sstevel@tonic-gate  *
6152*7c478bd9Sstevel@tonic-gate  * An array has the convenience that we don't need to lock read-access
6153*7c478bd9Sstevel@tonic-gate  * to it c.f. a linked list.  However our "expanding array" strategy
6154*7c478bd9Sstevel@tonic-gate  * means that we should hold a readers lock on the i_ddi_soft_state
6155*7c478bd9Sstevel@tonic-gate  * structure.
6156*7c478bd9Sstevel@tonic-gate  *
6157*7c478bd9Sstevel@tonic-gate  * However, from a performance viewpoint, we need to do it without
6158*7c478bd9Sstevel@tonic-gate  * any locks at all -- this also makes it a leaf routine.  The algorithm
6159*7c478bd9Sstevel@tonic-gate  * is 'lock-free' because we only discard the pointer arrays at
6160*7c478bd9Sstevel@tonic-gate  * ddi_soft_state_fini() time.
6161*7c478bd9Sstevel@tonic-gate  */
6162*7c478bd9Sstevel@tonic-gate void *
6163*7c478bd9Sstevel@tonic-gate ddi_get_soft_state(void *state, int item)
6164*7c478bd9Sstevel@tonic-gate {
6165*7c478bd9Sstevel@tonic-gate 	struct i_ddi_soft_state *ss = state;
6166*7c478bd9Sstevel@tonic-gate 
6167*7c478bd9Sstevel@tonic-gate 	ASSERT(ss != NULL && item >= 0);
6168*7c478bd9Sstevel@tonic-gate 
6169*7c478bd9Sstevel@tonic-gate 	if (item < ss->n_items && ss->array != NULL)
6170*7c478bd9Sstevel@tonic-gate 		return (ss->array[item]);
6171*7c478bd9Sstevel@tonic-gate 	return (NULL);
6172*7c478bd9Sstevel@tonic-gate }
6173*7c478bd9Sstevel@tonic-gate 
6174*7c478bd9Sstevel@tonic-gate /*
6175*7c478bd9Sstevel@tonic-gate  * Free the state structure corresponding to 'item.'   Freeing an
6176*7c478bd9Sstevel@tonic-gate  * element that has either gone or was never allocated is not
6177*7c478bd9Sstevel@tonic-gate  * considered an error.  Note that we free the state structure, but
6178*7c478bd9Sstevel@tonic-gate  * we don't shrink our pointer array, or discard 'dirty' arrays,
6179*7c478bd9Sstevel@tonic-gate  * since even a few pointers don't really waste too much memory.
6180*7c478bd9Sstevel@tonic-gate  *
6181*7c478bd9Sstevel@tonic-gate  * Passing an item number that is out of bounds, or a null pointer will
6182*7c478bd9Sstevel@tonic-gate  * provoke an error message.
6183*7c478bd9Sstevel@tonic-gate  */
6184*7c478bd9Sstevel@tonic-gate void
6185*7c478bd9Sstevel@tonic-gate ddi_soft_state_free(void *state, int item)
6186*7c478bd9Sstevel@tonic-gate {
6187*7c478bd9Sstevel@tonic-gate 	struct i_ddi_soft_state *ss;
6188*7c478bd9Sstevel@tonic-gate 	void **array;
6189*7c478bd9Sstevel@tonic-gate 	void *element;
6190*7c478bd9Sstevel@tonic-gate 	static char msg[] = "ddi_soft_state_free:";
6191*7c478bd9Sstevel@tonic-gate 
6192*7c478bd9Sstevel@tonic-gate 	if ((ss = state) == NULL) {
6193*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s null handle: %s",
6194*7c478bd9Sstevel@tonic-gate 		    msg, mod_containing_pc(caller()));
6195*7c478bd9Sstevel@tonic-gate 		return;
6196*7c478bd9Sstevel@tonic-gate 	}
6197*7c478bd9Sstevel@tonic-gate 
6198*7c478bd9Sstevel@tonic-gate 	element = NULL;
6199*7c478bd9Sstevel@tonic-gate 
6200*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ss->lock);
6201*7c478bd9Sstevel@tonic-gate 
6202*7c478bd9Sstevel@tonic-gate 	if ((array = ss->array) == NULL || ss->size == 0) {
6203*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s bad handle: %s",
6204*7c478bd9Sstevel@tonic-gate 		    msg, mod_containing_pc(caller()));
6205*7c478bd9Sstevel@tonic-gate 	} else if (item < 0 || item >= ss->n_items) {
6206*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s item %d not in range [0..%lu]: %s",
6207*7c478bd9Sstevel@tonic-gate 		    msg, item, ss->n_items - 1, mod_containing_pc(caller()));
6208*7c478bd9Sstevel@tonic-gate 	} else if (array[item] != NULL) {
6209*7c478bd9Sstevel@tonic-gate 		element = array[item];
6210*7c478bd9Sstevel@tonic-gate 		array[item] = NULL;
6211*7c478bd9Sstevel@tonic-gate 	}
6212*7c478bd9Sstevel@tonic-gate 
6213*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ss->lock);
6214*7c478bd9Sstevel@tonic-gate 
6215*7c478bd9Sstevel@tonic-gate 	if (element)
6216*7c478bd9Sstevel@tonic-gate 		kmem_free(element, ss->size);
6217*7c478bd9Sstevel@tonic-gate }
6218*7c478bd9Sstevel@tonic-gate 
6219*7c478bd9Sstevel@tonic-gate 
6220*7c478bd9Sstevel@tonic-gate /*
6221*7c478bd9Sstevel@tonic-gate  * Free the entire set of pointers, and any
6222*7c478bd9Sstevel@tonic-gate  * soft state structures contained therein.
6223*7c478bd9Sstevel@tonic-gate  *
6224*7c478bd9Sstevel@tonic-gate  * Note that we don't grab the ss->lock mutex, even though
6225*7c478bd9Sstevel@tonic-gate  * we're inspecting the various fields of the data structure.
6226*7c478bd9Sstevel@tonic-gate  *
6227*7c478bd9Sstevel@tonic-gate  * There is an implicit assumption that this routine will
6228*7c478bd9Sstevel@tonic-gate  * never run concurrently with any of the above on this
6229*7c478bd9Sstevel@tonic-gate  * particular state structure i.e. by the time the driver
6230*7c478bd9Sstevel@tonic-gate  * calls this routine, there should be no other threads
6231*7c478bd9Sstevel@tonic-gate  * running in the driver.
6232*7c478bd9Sstevel@tonic-gate  */
6233*7c478bd9Sstevel@tonic-gate void
6234*7c478bd9Sstevel@tonic-gate ddi_soft_state_fini(void **state_p)
6235*7c478bd9Sstevel@tonic-gate {
6236*7c478bd9Sstevel@tonic-gate 	struct i_ddi_soft_state *ss, *dirty;
6237*7c478bd9Sstevel@tonic-gate 	int item;
6238*7c478bd9Sstevel@tonic-gate 	static char msg[] = "ddi_soft_state_fini:";
6239*7c478bd9Sstevel@tonic-gate 
6240*7c478bd9Sstevel@tonic-gate 	if (state_p == NULL || (ss = *state_p) == NULL) {
6241*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s null handle: %s",
6242*7c478bd9Sstevel@tonic-gate 		    msg, mod_containing_pc(caller()));
6243*7c478bd9Sstevel@tonic-gate 		return;
6244*7c478bd9Sstevel@tonic-gate 	}
6245*7c478bd9Sstevel@tonic-gate 
6246*7c478bd9Sstevel@tonic-gate 	if (ss->size == 0) {
6247*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s bad handle: %s",
6248*7c478bd9Sstevel@tonic-gate 		    msg, mod_containing_pc(caller()));
6249*7c478bd9Sstevel@tonic-gate 		return;
6250*7c478bd9Sstevel@tonic-gate 	}
6251*7c478bd9Sstevel@tonic-gate 
6252*7c478bd9Sstevel@tonic-gate 	if (ss->n_items > 0) {
6253*7c478bd9Sstevel@tonic-gate 		for (item = 0; item < ss->n_items; item++)
6254*7c478bd9Sstevel@tonic-gate 			ddi_soft_state_free(ss, item);
6255*7c478bd9Sstevel@tonic-gate 		kmem_free(ss->array, ss->n_items * sizeof (void *));
6256*7c478bd9Sstevel@tonic-gate 	}
6257*7c478bd9Sstevel@tonic-gate 
6258*7c478bd9Sstevel@tonic-gate 	/*
6259*7c478bd9Sstevel@tonic-gate 	 * Now delete any dirty arrays from previous 'grow' operations
6260*7c478bd9Sstevel@tonic-gate 	 */
6261*7c478bd9Sstevel@tonic-gate 	for (dirty = ss->next; dirty; dirty = ss->next) {
6262*7c478bd9Sstevel@tonic-gate 		ss->next = dirty->next;
6263*7c478bd9Sstevel@tonic-gate 		kmem_free(dirty->array, dirty->n_items * sizeof (void *));
6264*7c478bd9Sstevel@tonic-gate 		kmem_free(dirty, sizeof (*dirty));
6265*7c478bd9Sstevel@tonic-gate 	}
6266*7c478bd9Sstevel@tonic-gate 
6267*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&ss->lock);
6268*7c478bd9Sstevel@tonic-gate 	kmem_free(ss, sizeof (*ss));
6269*7c478bd9Sstevel@tonic-gate 
6270*7c478bd9Sstevel@tonic-gate 	*state_p = NULL;
6271*7c478bd9Sstevel@tonic-gate }
6272*7c478bd9Sstevel@tonic-gate 
6273*7c478bd9Sstevel@tonic-gate 
6274*7c478bd9Sstevel@tonic-gate /*
6275*7c478bd9Sstevel@tonic-gate  * This sets the devi_addr entry in the dev_info structure 'dip' to 'name'
6276*7c478bd9Sstevel@tonic-gate  * If name is NULL, this frees the devi_addr entry, if any.
6277*7c478bd9Sstevel@tonic-gate  */
6278*7c478bd9Sstevel@tonic-gate void
6279*7c478bd9Sstevel@tonic-gate ddi_set_name_addr(dev_info_t *dip, char *name)
6280*7c478bd9Sstevel@tonic-gate {
6281*7c478bd9Sstevel@tonic-gate 	char *oldname = DEVI(dip)->devi_addr;
6282*7c478bd9Sstevel@tonic-gate 
6283*7c478bd9Sstevel@tonic-gate 	DEVI(dip)->devi_addr = i_ddi_strdup(name, KM_SLEEP);
6284*7c478bd9Sstevel@tonic-gate 	if (oldname) {
6285*7c478bd9Sstevel@tonic-gate 		kmem_free(oldname, strlen(oldname) + 1);
6286*7c478bd9Sstevel@tonic-gate 	}
6287*7c478bd9Sstevel@tonic-gate }
6288*7c478bd9Sstevel@tonic-gate 
6289*7c478bd9Sstevel@tonic-gate char *
6290*7c478bd9Sstevel@tonic-gate ddi_get_name_addr(dev_info_t *dip)
6291*7c478bd9Sstevel@tonic-gate {
6292*7c478bd9Sstevel@tonic-gate 	return (DEVI(dip)->devi_addr);
6293*7c478bd9Sstevel@tonic-gate }
6294*7c478bd9Sstevel@tonic-gate 
6295*7c478bd9Sstevel@tonic-gate void
6296*7c478bd9Sstevel@tonic-gate ddi_set_parent_data(dev_info_t *dip, void *pd)
6297*7c478bd9Sstevel@tonic-gate {
6298*7c478bd9Sstevel@tonic-gate 	DEVI(dip)->devi_parent_data = pd;
6299*7c478bd9Sstevel@tonic-gate }
6300*7c478bd9Sstevel@tonic-gate 
6301*7c478bd9Sstevel@tonic-gate void *
6302*7c478bd9Sstevel@tonic-gate ddi_get_parent_data(dev_info_t *dip)
6303*7c478bd9Sstevel@tonic-gate {
6304*7c478bd9Sstevel@tonic-gate 	return (DEVI(dip)->devi_parent_data);
6305*7c478bd9Sstevel@tonic-gate }
6306*7c478bd9Sstevel@tonic-gate 
6307*7c478bd9Sstevel@tonic-gate /*
6308*7c478bd9Sstevel@tonic-gate  * ddi_name_to_major: Returns the major number of a module given its name.
6309*7c478bd9Sstevel@tonic-gate  */
6310*7c478bd9Sstevel@tonic-gate major_t
6311*7c478bd9Sstevel@tonic-gate ddi_name_to_major(char *name)
6312*7c478bd9Sstevel@tonic-gate {
6313*7c478bd9Sstevel@tonic-gate 	return (mod_name_to_major(name));
6314*7c478bd9Sstevel@tonic-gate }
6315*7c478bd9Sstevel@tonic-gate 
6316*7c478bd9Sstevel@tonic-gate /*
6317*7c478bd9Sstevel@tonic-gate  * ddi_major_to_name: Returns the module name bound to a major number.
6318*7c478bd9Sstevel@tonic-gate  */
6319*7c478bd9Sstevel@tonic-gate char *
6320*7c478bd9Sstevel@tonic-gate ddi_major_to_name(major_t major)
6321*7c478bd9Sstevel@tonic-gate {
6322*7c478bd9Sstevel@tonic-gate 	return (mod_major_to_name(major));
6323*7c478bd9Sstevel@tonic-gate }
6324*7c478bd9Sstevel@tonic-gate 
6325*7c478bd9Sstevel@tonic-gate /*
6326*7c478bd9Sstevel@tonic-gate  * Return the name of the devinfo node pointed at by 'dip' in the buffer
6327*7c478bd9Sstevel@tonic-gate  * pointed at by 'name.'  A devinfo node is named as a result of calling
6328*7c478bd9Sstevel@tonic-gate  * ddi_initchild().
6329*7c478bd9Sstevel@tonic-gate  *
6330*7c478bd9Sstevel@tonic-gate  * Note: the driver must be held before calling this function!
6331*7c478bd9Sstevel@tonic-gate  */
6332*7c478bd9Sstevel@tonic-gate char *
6333*7c478bd9Sstevel@tonic-gate ddi_deviname(dev_info_t *dip, char *name)
6334*7c478bd9Sstevel@tonic-gate {
6335*7c478bd9Sstevel@tonic-gate 	char *addrname;
6336*7c478bd9Sstevel@tonic-gate 	char none = '\0';
6337*7c478bd9Sstevel@tonic-gate 
6338*7c478bd9Sstevel@tonic-gate 	if (dip == ddi_root_node()) {
6339*7c478bd9Sstevel@tonic-gate 		*name = '\0';
6340*7c478bd9Sstevel@tonic-gate 		return (name);
6341*7c478bd9Sstevel@tonic-gate 	}
6342*7c478bd9Sstevel@tonic-gate 
6343*7c478bd9Sstevel@tonic-gate 	if (i_ddi_node_state(dip) < DS_INITIALIZED) {
6344*7c478bd9Sstevel@tonic-gate 		addrname = &none;
6345*7c478bd9Sstevel@tonic-gate 	} else {
6346*7c478bd9Sstevel@tonic-gate 		addrname = ddi_get_name_addr(dip);
6347*7c478bd9Sstevel@tonic-gate 	}
6348*7c478bd9Sstevel@tonic-gate 
6349*7c478bd9Sstevel@tonic-gate 	if (*addrname == '\0') {
6350*7c478bd9Sstevel@tonic-gate 		(void) sprintf(name, "/%s", ddi_node_name(dip));
6351*7c478bd9Sstevel@tonic-gate 	} else {
6352*7c478bd9Sstevel@tonic-gate 		(void) sprintf(name, "/%s@%s", ddi_node_name(dip), addrname);
6353*7c478bd9Sstevel@tonic-gate 	}
6354*7c478bd9Sstevel@tonic-gate 
6355*7c478bd9Sstevel@tonic-gate 	return (name);
6356*7c478bd9Sstevel@tonic-gate }
6357*7c478bd9Sstevel@tonic-gate 
6358*7c478bd9Sstevel@tonic-gate /*
6359*7c478bd9Sstevel@tonic-gate  * Spits out the name of device node, typically name@addr, for a given node,
6360*7c478bd9Sstevel@tonic-gate  * using the driver name, not the nodename.
6361*7c478bd9Sstevel@tonic-gate  *
6362*7c478bd9Sstevel@tonic-gate  * Used by match_parent. Not to be used elsewhere.
6363*7c478bd9Sstevel@tonic-gate  */
6364*7c478bd9Sstevel@tonic-gate char *
6365*7c478bd9Sstevel@tonic-gate i_ddi_parname(dev_info_t *dip, char *name)
6366*7c478bd9Sstevel@tonic-gate {
6367*7c478bd9Sstevel@tonic-gate 	char *addrname;
6368*7c478bd9Sstevel@tonic-gate 
6369*7c478bd9Sstevel@tonic-gate 	if (dip == ddi_root_node()) {
6370*7c478bd9Sstevel@tonic-gate 		*name = '\0';
6371*7c478bd9Sstevel@tonic-gate 		return (name);
6372*7c478bd9Sstevel@tonic-gate 	}
6373*7c478bd9Sstevel@tonic-gate 
6374*7c478bd9Sstevel@tonic-gate 	ASSERT(i_ddi_node_state(dip) >= DS_INITIALIZED);
6375*7c478bd9Sstevel@tonic-gate 
6376*7c478bd9Sstevel@tonic-gate 	if (*(addrname = ddi_get_name_addr(dip)) == '\0')
6377*7c478bd9Sstevel@tonic-gate 		(void) sprintf(name, "%s", ddi_binding_name(dip));
6378*7c478bd9Sstevel@tonic-gate 	else
6379*7c478bd9Sstevel@tonic-gate 		(void) sprintf(name, "%s@%s", ddi_binding_name(dip), addrname);
6380*7c478bd9Sstevel@tonic-gate 	return (name);
6381*7c478bd9Sstevel@tonic-gate }
6382*7c478bd9Sstevel@tonic-gate 
6383*7c478bd9Sstevel@tonic-gate static char *
6384*7c478bd9Sstevel@tonic-gate pathname_work(dev_info_t *dip, char *path)
6385*7c478bd9Sstevel@tonic-gate {
6386*7c478bd9Sstevel@tonic-gate 	char *bp;
6387*7c478bd9Sstevel@tonic-gate 
6388*7c478bd9Sstevel@tonic-gate 	if (dip == ddi_root_node()) {
6389*7c478bd9Sstevel@tonic-gate 		*path = '\0';
6390*7c478bd9Sstevel@tonic-gate 		return (path);
6391*7c478bd9Sstevel@tonic-gate 	}
6392*7c478bd9Sstevel@tonic-gate 	(void) pathname_work(ddi_get_parent(dip), path);
6393*7c478bd9Sstevel@tonic-gate 	bp = path + strlen(path);
6394*7c478bd9Sstevel@tonic-gate 	(void) ddi_deviname(dip, bp);
6395*7c478bd9Sstevel@tonic-gate 	return (path);
6396*7c478bd9Sstevel@tonic-gate }
6397*7c478bd9Sstevel@tonic-gate 
6398*7c478bd9Sstevel@tonic-gate char *
6399*7c478bd9Sstevel@tonic-gate ddi_pathname(dev_info_t *dip, char *path)
6400*7c478bd9Sstevel@tonic-gate {
6401*7c478bd9Sstevel@tonic-gate 	return (pathname_work(dip, path));
6402*7c478bd9Sstevel@tonic-gate }
6403*7c478bd9Sstevel@tonic-gate 
6404*7c478bd9Sstevel@tonic-gate /*
6405*7c478bd9Sstevel@tonic-gate  * Given a dev_t, return the pathname of the corresponding device in the
6406*7c478bd9Sstevel@tonic-gate  * buffer pointed at by "path."  The buffer is assumed to be large enough
6407*7c478bd9Sstevel@tonic-gate  * to hold the pathname of the device (MAXPATHLEN).
6408*7c478bd9Sstevel@tonic-gate  *
6409*7c478bd9Sstevel@tonic-gate  * The pathname of a device is the pathname of the devinfo node to which
6410*7c478bd9Sstevel@tonic-gate  * the device "belongs," concatenated with the character ':' and the name
6411*7c478bd9Sstevel@tonic-gate  * of the minor node corresponding to the dev_t.  If spec_type is 0 then
6412*7c478bd9Sstevel@tonic-gate  * just the pathname of the devinfo node is returned without driving attach
6413*7c478bd9Sstevel@tonic-gate  * of that node.  For a non-zero spec_type, an attach is performed and a
6414*7c478bd9Sstevel@tonic-gate  * search of the minor list occurs.
6415*7c478bd9Sstevel@tonic-gate  *
6416*7c478bd9Sstevel@tonic-gate  * It is possible that the path associated with the dev_t is not
6417*7c478bd9Sstevel@tonic-gate  * currently available in the devinfo tree.  In order to have a
6418*7c478bd9Sstevel@tonic-gate  * dev_t, a device must have been discovered before, which means
6419*7c478bd9Sstevel@tonic-gate  * that the path is always in the instance tree.  The one exception
6420*7c478bd9Sstevel@tonic-gate  * to this is if the dev_t is associated with a pseudo driver, in
6421*7c478bd9Sstevel@tonic-gate  * which case the device must exist on the pseudo branch of the
6422*7c478bd9Sstevel@tonic-gate  * devinfo tree as a result of parsing .conf files.
6423*7c478bd9Sstevel@tonic-gate  */
6424*7c478bd9Sstevel@tonic-gate int
6425*7c478bd9Sstevel@tonic-gate ddi_dev_pathname(dev_t devt, int spec_type, char *path)
6426*7c478bd9Sstevel@tonic-gate {
6427*7c478bd9Sstevel@tonic-gate 	major_t		major = getmajor(devt);
6428*7c478bd9Sstevel@tonic-gate 	int		instance;
6429*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
6430*7c478bd9Sstevel@tonic-gate 	char		*minorname;
6431*7c478bd9Sstevel@tonic-gate 	char		*drvname;
6432*7c478bd9Sstevel@tonic-gate 
6433*7c478bd9Sstevel@tonic-gate 	if (major >= devcnt)
6434*7c478bd9Sstevel@tonic-gate 		goto fail;
6435*7c478bd9Sstevel@tonic-gate 	if (major == clone_major) {
6436*7c478bd9Sstevel@tonic-gate 		/* clone has no minor nodes, manufacture the path here */
6437*7c478bd9Sstevel@tonic-gate 		if ((drvname = ddi_major_to_name(getminor(devt))) == NULL)
6438*7c478bd9Sstevel@tonic-gate 			goto fail;
6439*7c478bd9Sstevel@tonic-gate 
6440*7c478bd9Sstevel@tonic-gate 		(void) snprintf(path, MAXPATHLEN, "%s:%s", CLONE_PATH, drvname);
6441*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6442*7c478bd9Sstevel@tonic-gate 	}
6443*7c478bd9Sstevel@tonic-gate 
6444*7c478bd9Sstevel@tonic-gate 	/* extract instance from devt (getinfo(9E) DDI_INFO_DEVT2INSTANCE). */
6445*7c478bd9Sstevel@tonic-gate 	if ((instance = dev_to_instance(devt)) == -1)
6446*7c478bd9Sstevel@tonic-gate 		goto fail;
6447*7c478bd9Sstevel@tonic-gate 
6448*7c478bd9Sstevel@tonic-gate 	/* reconstruct the path given the major/instance */
6449*7c478bd9Sstevel@tonic-gate 	if (e_ddi_majorinstance_to_path(major, instance, path) != DDI_SUCCESS)
6450*7c478bd9Sstevel@tonic-gate 		goto fail;
6451*7c478bd9Sstevel@tonic-gate 
6452*7c478bd9Sstevel@tonic-gate 	/* if spec_type given we must drive attach and search minor nodes */
6453*7c478bd9Sstevel@tonic-gate 	if ((spec_type == S_IFCHR) || (spec_type == S_IFBLK)) {
6454*7c478bd9Sstevel@tonic-gate 		/* attach the path so we can search minors */
6455*7c478bd9Sstevel@tonic-gate 		if ((dip = e_ddi_hold_devi_by_path(path, 0)) == NULL)
6456*7c478bd9Sstevel@tonic-gate 			goto fail;
6457*7c478bd9Sstevel@tonic-gate 
6458*7c478bd9Sstevel@tonic-gate 		/* Add minorname to path. */
6459*7c478bd9Sstevel@tonic-gate 		mutex_enter(&(DEVI(dip)->devi_lock));
6460*7c478bd9Sstevel@tonic-gate 		minorname = i_ddi_devtspectype_to_minorname(dip,
6461*7c478bd9Sstevel@tonic-gate 		    devt, spec_type);
6462*7c478bd9Sstevel@tonic-gate 		if (minorname) {
6463*7c478bd9Sstevel@tonic-gate 			(void) strcat(path, ":");
6464*7c478bd9Sstevel@tonic-gate 			(void) strcat(path, minorname);
6465*7c478bd9Sstevel@tonic-gate 		}
6466*7c478bd9Sstevel@tonic-gate 		mutex_exit(&(DEVI(dip)->devi_lock));
6467*7c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
6468*7c478bd9Sstevel@tonic-gate 		if (minorname == NULL)
6469*7c478bd9Sstevel@tonic-gate 			goto fail;
6470*7c478bd9Sstevel@tonic-gate 	}
6471*7c478bd9Sstevel@tonic-gate 	ASSERT(strlen(path) < MAXPATHLEN);
6472*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6473*7c478bd9Sstevel@tonic-gate 
6474*7c478bd9Sstevel@tonic-gate fail:	*path = 0;
6475*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
6476*7c478bd9Sstevel@tonic-gate }
6477*7c478bd9Sstevel@tonic-gate 
6478*7c478bd9Sstevel@tonic-gate /*
6479*7c478bd9Sstevel@tonic-gate  * Given a major number and an instance, return the path.
6480*7c478bd9Sstevel@tonic-gate  * This interface does NOT drive attach.
6481*7c478bd9Sstevel@tonic-gate  */
6482*7c478bd9Sstevel@tonic-gate int
6483*7c478bd9Sstevel@tonic-gate e_ddi_majorinstance_to_path(major_t major, int instance, char *path)
6484*7c478bd9Sstevel@tonic-gate {
6485*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
6486*7c478bd9Sstevel@tonic-gate 
6487*7c478bd9Sstevel@tonic-gate 	/* look for the major/instance in the instance tree */
6488*7c478bd9Sstevel@tonic-gate 	if (e_ddi_instance_majorinstance_to_path(major, instance,
6489*7c478bd9Sstevel@tonic-gate 	    path) != DDI_SUCCESS) {
6490*7c478bd9Sstevel@tonic-gate 		/* not in instance tree, look in 'pseudo' branch */
6491*7c478bd9Sstevel@tonic-gate 		if ((dip = ddi_hold_devi_by_instance(major,
6492*7c478bd9Sstevel@tonic-gate 		    instance, E_DDI_HOLD_DEVI_NOATTACH)) == NULL) {
6493*7c478bd9Sstevel@tonic-gate 			*path = 0;
6494*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
6495*7c478bd9Sstevel@tonic-gate 		}
6496*7c478bd9Sstevel@tonic-gate 		(void) ddi_pathname(dip, path);
6497*7c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);
6498*7c478bd9Sstevel@tonic-gate 	}
6499*7c478bd9Sstevel@tonic-gate 	ASSERT(strlen(path) < MAXPATHLEN);
6500*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6501*7c478bd9Sstevel@tonic-gate }
6502*7c478bd9Sstevel@tonic-gate 
6503*7c478bd9Sstevel@tonic-gate 
6504*7c478bd9Sstevel@tonic-gate #define	GLD_DRIVER_PPA "SUNW,gld_v0_ppa"
6505*7c478bd9Sstevel@tonic-gate 
6506*7c478bd9Sstevel@tonic-gate /*
6507*7c478bd9Sstevel@tonic-gate  * Given the dip for a network interface return the ppa for that interface.
6508*7c478bd9Sstevel@tonic-gate  *
6509*7c478bd9Sstevel@tonic-gate  * In all cases except GLD v0 drivers, the ppa == instance.
6510*7c478bd9Sstevel@tonic-gate  * In the case of GLD v0 drivers, the ppa is equal to the attach order.
6511*7c478bd9Sstevel@tonic-gate  * So for these drivers when the attach routine calls gld_register(),
6512*7c478bd9Sstevel@tonic-gate  * the GLD framework creates an integer property called "gld_driver_ppa"
6513*7c478bd9Sstevel@tonic-gate  * that can be queried here.
6514*7c478bd9Sstevel@tonic-gate  *
6515*7c478bd9Sstevel@tonic-gate  * The only time this function is used is when a system is booting over nfs.
6516*7c478bd9Sstevel@tonic-gate  * In this case the system has to resolve the pathname of the boot device
6517*7c478bd9Sstevel@tonic-gate  * to it's ppa.
6518*7c478bd9Sstevel@tonic-gate  */
6519*7c478bd9Sstevel@tonic-gate int
6520*7c478bd9Sstevel@tonic-gate i_ddi_devi_get_ppa(dev_info_t *dip)
6521*7c478bd9Sstevel@tonic-gate {
6522*7c478bd9Sstevel@tonic-gate 	return (ddi_prop_get_int(DDI_DEV_T_ANY, dip,
6523*7c478bd9Sstevel@tonic-gate 			DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
6524*7c478bd9Sstevel@tonic-gate 			GLD_DRIVER_PPA, ddi_get_instance(dip)));
6525*7c478bd9Sstevel@tonic-gate }
6526*7c478bd9Sstevel@tonic-gate 
6527*7c478bd9Sstevel@tonic-gate /*
6528*7c478bd9Sstevel@tonic-gate  * i_ddi_devi_set_ppa() should only be called from gld_register()
6529*7c478bd9Sstevel@tonic-gate  * and only for GLD v0 drivers
6530*7c478bd9Sstevel@tonic-gate  */
6531*7c478bd9Sstevel@tonic-gate void
6532*7c478bd9Sstevel@tonic-gate i_ddi_devi_set_ppa(dev_info_t *dip, int ppa)
6533*7c478bd9Sstevel@tonic-gate {
6534*7c478bd9Sstevel@tonic-gate 	(void) e_ddi_prop_update_int(DDI_DEV_T_NONE, dip, GLD_DRIVER_PPA, ppa);
6535*7c478bd9Sstevel@tonic-gate }
6536*7c478bd9Sstevel@tonic-gate 
6537*7c478bd9Sstevel@tonic-gate 
6538*7c478bd9Sstevel@tonic-gate /*
6539*7c478bd9Sstevel@tonic-gate  * Private DDI Console bell functions.
6540*7c478bd9Sstevel@tonic-gate  */
6541*7c478bd9Sstevel@tonic-gate void
6542*7c478bd9Sstevel@tonic-gate ddi_ring_console_bell(clock_t duration)
6543*7c478bd9Sstevel@tonic-gate {
6544*7c478bd9Sstevel@tonic-gate 	if (ddi_console_bell_func != NULL)
6545*7c478bd9Sstevel@tonic-gate 		(*ddi_console_bell_func)(duration);
6546*7c478bd9Sstevel@tonic-gate }
6547*7c478bd9Sstevel@tonic-gate 
6548*7c478bd9Sstevel@tonic-gate void
6549*7c478bd9Sstevel@tonic-gate ddi_set_console_bell(void (*bellfunc)(clock_t duration))
6550*7c478bd9Sstevel@tonic-gate {
6551*7c478bd9Sstevel@tonic-gate 	ddi_console_bell_func = bellfunc;
6552*7c478bd9Sstevel@tonic-gate }
6553*7c478bd9Sstevel@tonic-gate 
6554*7c478bd9Sstevel@tonic-gate int
6555*7c478bd9Sstevel@tonic-gate ddi_dma_alloc_handle(dev_info_t *dip, ddi_dma_attr_t *attr,
6556*7c478bd9Sstevel@tonic-gate 	int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
6557*7c478bd9Sstevel@tonic-gate {
6558*7c478bd9Sstevel@tonic-gate 	int (*funcp)() = ddi_dma_allochdl;
6559*7c478bd9Sstevel@tonic-gate 	ddi_dma_attr_t dma_attr;
6560*7c478bd9Sstevel@tonic-gate 	struct bus_ops *bop;
6561*7c478bd9Sstevel@tonic-gate 
6562*7c478bd9Sstevel@tonic-gate 	if (attr == (ddi_dma_attr_t *)0)
6563*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_BADATTR);
6564*7c478bd9Sstevel@tonic-gate 
6565*7c478bd9Sstevel@tonic-gate 	dma_attr = *attr;
6566*7c478bd9Sstevel@tonic-gate 
6567*7c478bd9Sstevel@tonic-gate 	bop = DEVI(dip)->devi_ops->devo_bus_ops;
6568*7c478bd9Sstevel@tonic-gate 	if (bop && bop->bus_dma_allochdl)
6569*7c478bd9Sstevel@tonic-gate 		funcp = bop->bus_dma_allochdl;
6570*7c478bd9Sstevel@tonic-gate 
6571*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(dip, dip, &dma_attr, waitfp, arg, handlep));
6572*7c478bd9Sstevel@tonic-gate }
6573*7c478bd9Sstevel@tonic-gate 
6574*7c478bd9Sstevel@tonic-gate void
6575*7c478bd9Sstevel@tonic-gate ddi_dma_free_handle(ddi_dma_handle_t *handlep)
6576*7c478bd9Sstevel@tonic-gate {
6577*7c478bd9Sstevel@tonic-gate 	ddi_dma_handle_t h = *handlep;
6578*7c478bd9Sstevel@tonic-gate 	(void) ddi_dma_freehdl(HD, HD, h);
6579*7c478bd9Sstevel@tonic-gate }
6580*7c478bd9Sstevel@tonic-gate 
6581*7c478bd9Sstevel@tonic-gate static uintptr_t dma_mem_list_id = 0;
6582*7c478bd9Sstevel@tonic-gate 
6583*7c478bd9Sstevel@tonic-gate 
6584*7c478bd9Sstevel@tonic-gate int
6585*7c478bd9Sstevel@tonic-gate ddi_dma_mem_alloc(ddi_dma_handle_t handle, size_t length,
6586*7c478bd9Sstevel@tonic-gate 	ddi_device_acc_attr_t *accattrp, uint_t xfermodes,
6587*7c478bd9Sstevel@tonic-gate 	int (*waitfp)(caddr_t), caddr_t arg, caddr_t *kaddrp,
6588*7c478bd9Sstevel@tonic-gate 	size_t *real_length, ddi_acc_handle_t *handlep)
6589*7c478bd9Sstevel@tonic-gate {
6590*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
6591*7c478bd9Sstevel@tonic-gate 	dev_info_t *dip = hp->dmai_rdip;
6592*7c478bd9Sstevel@tonic-gate 	ddi_acc_hdl_t *ap;
6593*7c478bd9Sstevel@tonic-gate 	ddi_dma_attr_t *attrp = &hp->dmai_attr;
6594*7c478bd9Sstevel@tonic-gate 	uint_t sleepflag;
6595*7c478bd9Sstevel@tonic-gate 	int (*fp)(caddr_t);
6596*7c478bd9Sstevel@tonic-gate 	int rval;
6597*7c478bd9Sstevel@tonic-gate 
6598*7c478bd9Sstevel@tonic-gate 	if (waitfp == DDI_DMA_SLEEP)
6599*7c478bd9Sstevel@tonic-gate 		fp = (int (*)())KM_SLEEP;
6600*7c478bd9Sstevel@tonic-gate 	else if (waitfp == DDI_DMA_DONTWAIT)
6601*7c478bd9Sstevel@tonic-gate 		fp = (int (*)())KM_NOSLEEP;
6602*7c478bd9Sstevel@tonic-gate 	else
6603*7c478bd9Sstevel@tonic-gate 		fp = waitfp;
6604*7c478bd9Sstevel@tonic-gate 	*handlep = impl_acc_hdl_alloc(fp, arg);
6605*7c478bd9Sstevel@tonic-gate 	if (*handlep == NULL)
6606*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6607*7c478bd9Sstevel@tonic-gate 
6608*7c478bd9Sstevel@tonic-gate 	/*
6609*7c478bd9Sstevel@tonic-gate 	 * initialize the common elements of data access handle
6610*7c478bd9Sstevel@tonic-gate 	 */
6611*7c478bd9Sstevel@tonic-gate 	ap = impl_acc_hdl_get(*handlep);
6612*7c478bd9Sstevel@tonic-gate 	ap->ah_vers = VERS_ACCHDL;
6613*7c478bd9Sstevel@tonic-gate 	ap->ah_dip = dip;
6614*7c478bd9Sstevel@tonic-gate 	ap->ah_offset = 0;
6615*7c478bd9Sstevel@tonic-gate 	ap->ah_len = 0;
6616*7c478bd9Sstevel@tonic-gate 	ap->ah_xfermodes = xfermodes;
6617*7c478bd9Sstevel@tonic-gate 	ap->ah_acc = *accattrp;
6618*7c478bd9Sstevel@tonic-gate 
6619*7c478bd9Sstevel@tonic-gate 	sleepflag = ((waitfp == DDI_DMA_SLEEP) ? 1 : 0);
6620*7c478bd9Sstevel@tonic-gate 	if (xfermodes == DDI_DMA_CONSISTENT) {
6621*7c478bd9Sstevel@tonic-gate 		rval = i_ddi_mem_alloc(dip, attrp, length, sleepflag, 0,
6622*7c478bd9Sstevel@tonic-gate 			    accattrp, kaddrp, NULL, ap);
6623*7c478bd9Sstevel@tonic-gate 		*real_length = length;
6624*7c478bd9Sstevel@tonic-gate 	} else {
6625*7c478bd9Sstevel@tonic-gate 		rval = i_ddi_mem_alloc(dip, attrp, length, sleepflag, 1,
6626*7c478bd9Sstevel@tonic-gate 			    accattrp, kaddrp, real_length, ap);
6627*7c478bd9Sstevel@tonic-gate 	}
6628*7c478bd9Sstevel@tonic-gate 	if (rval == DDI_SUCCESS) {
6629*7c478bd9Sstevel@tonic-gate 		ap->ah_len = (off_t)(*real_length);
6630*7c478bd9Sstevel@tonic-gate 		ap->ah_addr = *kaddrp;
6631*7c478bd9Sstevel@tonic-gate 	} else {
6632*7c478bd9Sstevel@tonic-gate 		impl_acc_hdl_free(*handlep);
6633*7c478bd9Sstevel@tonic-gate 		*handlep = (ddi_acc_handle_t)NULL;
6634*7c478bd9Sstevel@tonic-gate 		if (waitfp != DDI_DMA_SLEEP && waitfp != DDI_DMA_DONTWAIT) {
6635*7c478bd9Sstevel@tonic-gate 			ddi_set_callback(waitfp, arg, &dma_mem_list_id);
6636*7c478bd9Sstevel@tonic-gate 		}
6637*7c478bd9Sstevel@tonic-gate 		rval = DDI_FAILURE;
6638*7c478bd9Sstevel@tonic-gate 	}
6639*7c478bd9Sstevel@tonic-gate 	return (rval);
6640*7c478bd9Sstevel@tonic-gate }
6641*7c478bd9Sstevel@tonic-gate 
6642*7c478bd9Sstevel@tonic-gate void
6643*7c478bd9Sstevel@tonic-gate ddi_dma_mem_free(ddi_acc_handle_t *handlep)
6644*7c478bd9Sstevel@tonic-gate {
6645*7c478bd9Sstevel@tonic-gate 	ddi_acc_hdl_t *ap;
6646*7c478bd9Sstevel@tonic-gate 
6647*7c478bd9Sstevel@tonic-gate 	ap = impl_acc_hdl_get(*handlep);
6648*7c478bd9Sstevel@tonic-gate 	ASSERT(ap);
6649*7c478bd9Sstevel@tonic-gate 
6650*7c478bd9Sstevel@tonic-gate 	if (ap->ah_xfermodes == DDI_DMA_CONSISTENT) {
6651*7c478bd9Sstevel@tonic-gate 		i_ddi_mem_free((caddr_t)ap->ah_addr, 0);
6652*7c478bd9Sstevel@tonic-gate 	} else {
6653*7c478bd9Sstevel@tonic-gate 		i_ddi_mem_free((caddr_t)ap->ah_addr, 1);
6654*7c478bd9Sstevel@tonic-gate 	}
6655*7c478bd9Sstevel@tonic-gate 
6656*7c478bd9Sstevel@tonic-gate 	/*
6657*7c478bd9Sstevel@tonic-gate 	 * free the handle
6658*7c478bd9Sstevel@tonic-gate 	 */
6659*7c478bd9Sstevel@tonic-gate 	impl_acc_hdl_free(*handlep);
6660*7c478bd9Sstevel@tonic-gate 	*handlep = (ddi_acc_handle_t)NULL;
6661*7c478bd9Sstevel@tonic-gate 
6662*7c478bd9Sstevel@tonic-gate 	if (dma_mem_list_id != 0) {
6663*7c478bd9Sstevel@tonic-gate 		ddi_run_callback(&dma_mem_list_id);
6664*7c478bd9Sstevel@tonic-gate 	}
6665*7c478bd9Sstevel@tonic-gate }
6666*7c478bd9Sstevel@tonic-gate 
6667*7c478bd9Sstevel@tonic-gate int
6668*7c478bd9Sstevel@tonic-gate ddi_dma_buf_bind_handle(ddi_dma_handle_t handle, struct buf *bp,
6669*7c478bd9Sstevel@tonic-gate 	uint_t flags, int (*waitfp)(caddr_t), caddr_t arg,
6670*7c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t *cookiep, uint_t *ccountp)
6671*7c478bd9Sstevel@tonic-gate {
6672*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
6673*7c478bd9Sstevel@tonic-gate 	dev_info_t *hdip, *dip;
6674*7c478bd9Sstevel@tonic-gate 	struct ddi_dma_req dmareq;
6675*7c478bd9Sstevel@tonic-gate 	int (*funcp)();
6676*7c478bd9Sstevel@tonic-gate 
6677*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_flags = flags;
6678*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_fp = waitfp;
6679*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_arg = arg;
6680*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_object.dmao_size = (uint_t)bp->b_bcount;
6681*7c478bd9Sstevel@tonic-gate 
6682*7c478bd9Sstevel@tonic-gate 	if ((bp->b_flags & (B_PAGEIO|B_REMAPPED)) == B_PAGEIO) {
6683*7c478bd9Sstevel@tonic-gate 		dmareq.dmar_object.dmao_type = DMA_OTYP_PAGES;
6684*7c478bd9Sstevel@tonic-gate 		dmareq.dmar_object.dmao_obj.pp_obj.pp_pp = bp->b_pages;
6685*7c478bd9Sstevel@tonic-gate 		dmareq.dmar_object.dmao_obj.pp_obj.pp_offset =
6686*7c478bd9Sstevel@tonic-gate 		    (uint_t)(((uintptr_t)bp->b_un.b_addr) & MMU_PAGEOFFSET);
6687*7c478bd9Sstevel@tonic-gate 	} else {
6688*7c478bd9Sstevel@tonic-gate 		dmareq.dmar_object.dmao_obj.virt_obj.v_addr = bp->b_un.b_addr;
6689*7c478bd9Sstevel@tonic-gate 		if ((bp->b_flags & (B_SHADOW|B_REMAPPED)) == B_SHADOW) {
6690*7c478bd9Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_priv =
6691*7c478bd9Sstevel@tonic-gate 							bp->b_shadow;
6692*7c478bd9Sstevel@tonic-gate 			dmareq.dmar_object.dmao_type = DMA_OTYP_BUFVADDR;
6693*7c478bd9Sstevel@tonic-gate 		} else {
6694*7c478bd9Sstevel@tonic-gate 			dmareq.dmar_object.dmao_type =
6695*7c478bd9Sstevel@tonic-gate 				(bp->b_flags & (B_PHYS | B_REMAPPED))?
6696*7c478bd9Sstevel@tonic-gate 				DMA_OTYP_BUFVADDR : DMA_OTYP_VADDR;
6697*7c478bd9Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
6698*7c478bd9Sstevel@tonic-gate 		}
6699*7c478bd9Sstevel@tonic-gate 
6700*7c478bd9Sstevel@tonic-gate 		/*
6701*7c478bd9Sstevel@tonic-gate 		 * If the buffer has no proc pointer, or the proc
6702*7c478bd9Sstevel@tonic-gate 		 * struct has the kernel address space, or the buffer has
6703*7c478bd9Sstevel@tonic-gate 		 * been marked B_REMAPPED (meaning that it is now
6704*7c478bd9Sstevel@tonic-gate 		 * mapped into the kernel's address space), then
6705*7c478bd9Sstevel@tonic-gate 		 * the address space is kas (kernel address space).
6706*7c478bd9Sstevel@tonic-gate 		 */
6707*7c478bd9Sstevel@tonic-gate 		if (bp->b_proc == NULL || bp->b_proc->p_as == &kas ||
6708*7c478bd9Sstevel@tonic-gate 		    (bp->b_flags & B_REMAPPED) != 0) {
6709*7c478bd9Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_as = 0;
6710*7c478bd9Sstevel@tonic-gate 		} else {
6711*7c478bd9Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_as =
6712*7c478bd9Sstevel@tonic-gate 			    bp->b_proc->p_as;
6713*7c478bd9Sstevel@tonic-gate 		}
6714*7c478bd9Sstevel@tonic-gate 	}
6715*7c478bd9Sstevel@tonic-gate 
6716*7c478bd9Sstevel@tonic-gate 	dip = hp->dmai_rdip;
6717*7c478bd9Sstevel@tonic-gate 	hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
6718*7c478bd9Sstevel@tonic-gate 	funcp = DEVI(dip)->devi_bus_dma_bindfunc;
6719*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(hdip, dip, handle, &dmareq, cookiep, ccountp));
6720*7c478bd9Sstevel@tonic-gate }
6721*7c478bd9Sstevel@tonic-gate 
6722*7c478bd9Sstevel@tonic-gate int
6723*7c478bd9Sstevel@tonic-gate ddi_dma_addr_bind_handle(ddi_dma_handle_t handle, struct as *as,
6724*7c478bd9Sstevel@tonic-gate 	caddr_t addr, size_t len, uint_t flags, int (*waitfp)(caddr_t),
6725*7c478bd9Sstevel@tonic-gate 	caddr_t arg, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
6726*7c478bd9Sstevel@tonic-gate {
6727*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
6728*7c478bd9Sstevel@tonic-gate 	dev_info_t *hdip, *dip;
6729*7c478bd9Sstevel@tonic-gate 	struct ddi_dma_req dmareq;
6730*7c478bd9Sstevel@tonic-gate 	int (*funcp)();
6731*7c478bd9Sstevel@tonic-gate 
6732*7c478bd9Sstevel@tonic-gate 	if (len == (uint_t)0) {
6733*7c478bd9Sstevel@tonic-gate 		return (DDI_DMA_NOMAPPING);
6734*7c478bd9Sstevel@tonic-gate 	}
6735*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_flags = flags;
6736*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_fp = waitfp;
6737*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_arg = arg;
6738*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_object.dmao_size = len;
6739*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR;
6740*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_object.dmao_obj.virt_obj.v_as = as;
6741*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_object.dmao_obj.virt_obj.v_addr = addr;
6742*7c478bd9Sstevel@tonic-gate 	dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
6743*7c478bd9Sstevel@tonic-gate 
6744*7c478bd9Sstevel@tonic-gate 	dip = hp->dmai_rdip;
6745*7c478bd9Sstevel@tonic-gate 	hdip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
6746*7c478bd9Sstevel@tonic-gate 	funcp = DEVI(dip)->devi_bus_dma_bindfunc;
6747*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(hdip, dip, handle, &dmareq, cookiep, ccountp));
6748*7c478bd9Sstevel@tonic-gate }
6749*7c478bd9Sstevel@tonic-gate 
6750*7c478bd9Sstevel@tonic-gate void
6751*7c478bd9Sstevel@tonic-gate ddi_dma_nextcookie(ddi_dma_handle_t handle, ddi_dma_cookie_t *cookiep)
6752*7c478bd9Sstevel@tonic-gate {
6753*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
6754*7c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t *cp;
6755*7c478bd9Sstevel@tonic-gate 
6756*7c478bd9Sstevel@tonic-gate 	cp = hp->dmai_cookie;
6757*7c478bd9Sstevel@tonic-gate 	ASSERT(cp);
6758*7c478bd9Sstevel@tonic-gate 
6759*7c478bd9Sstevel@tonic-gate 	cookiep->dmac_notused = cp->dmac_notused;
6760*7c478bd9Sstevel@tonic-gate 	cookiep->dmac_type = cp->dmac_type;
6761*7c478bd9Sstevel@tonic-gate 	cookiep->dmac_address = cp->dmac_address;
6762*7c478bd9Sstevel@tonic-gate 	cookiep->dmac_size = cp->dmac_size;
6763*7c478bd9Sstevel@tonic-gate 	hp->dmai_cookie++;
6764*7c478bd9Sstevel@tonic-gate }
6765*7c478bd9Sstevel@tonic-gate 
6766*7c478bd9Sstevel@tonic-gate int
6767*7c478bd9Sstevel@tonic-gate ddi_dma_numwin(ddi_dma_handle_t handle, uint_t *nwinp)
6768*7c478bd9Sstevel@tonic-gate {
6769*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
6770*7c478bd9Sstevel@tonic-gate 	if ((hp->dmai_rflags & DDI_DMA_PARTIAL) == 0) {
6771*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6772*7c478bd9Sstevel@tonic-gate 	} else {
6773*7c478bd9Sstevel@tonic-gate 		*nwinp = hp->dmai_nwin;
6774*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
6775*7c478bd9Sstevel@tonic-gate 	}
6776*7c478bd9Sstevel@tonic-gate }
6777*7c478bd9Sstevel@tonic-gate 
6778*7c478bd9Sstevel@tonic-gate int
6779*7c478bd9Sstevel@tonic-gate ddi_dma_getwin(ddi_dma_handle_t h, uint_t win, off_t *offp,
6780*7c478bd9Sstevel@tonic-gate 	size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
6781*7c478bd9Sstevel@tonic-gate {
6782*7c478bd9Sstevel@tonic-gate 	int (*funcp)() = ddi_dma_win;
6783*7c478bd9Sstevel@tonic-gate 	struct bus_ops *bop;
6784*7c478bd9Sstevel@tonic-gate 
6785*7c478bd9Sstevel@tonic-gate 	bop = DEVI(HD)->devi_ops->devo_bus_ops;
6786*7c478bd9Sstevel@tonic-gate 	if (bop && bop->bus_dma_win)
6787*7c478bd9Sstevel@tonic-gate 		funcp = bop->bus_dma_win;
6788*7c478bd9Sstevel@tonic-gate 
6789*7c478bd9Sstevel@tonic-gate 	return ((*funcp)(HD, HD, h, win, offp, lenp, cookiep, ccountp));
6790*7c478bd9Sstevel@tonic-gate }
6791*7c478bd9Sstevel@tonic-gate 
6792*7c478bd9Sstevel@tonic-gate int
6793*7c478bd9Sstevel@tonic-gate ddi_dma_set_sbus64(ddi_dma_handle_t h, ulong_t burstsizes)
6794*7c478bd9Sstevel@tonic-gate {
6795*7c478bd9Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_SET_SBUS64, 0,
6796*7c478bd9Sstevel@tonic-gate 		&burstsizes, 0, 0));
6797*7c478bd9Sstevel@tonic-gate }
6798*7c478bd9Sstevel@tonic-gate 
6799*7c478bd9Sstevel@tonic-gate int
6800*7c478bd9Sstevel@tonic-gate i_ddi_dma_fault_check(ddi_dma_impl_t *hp)
6801*7c478bd9Sstevel@tonic-gate {
6802*7c478bd9Sstevel@tonic-gate 	return (hp->dmai_fault);
6803*7c478bd9Sstevel@tonic-gate }
6804*7c478bd9Sstevel@tonic-gate 
6805*7c478bd9Sstevel@tonic-gate int
6806*7c478bd9Sstevel@tonic-gate ddi_check_dma_handle(ddi_dma_handle_t handle)
6807*7c478bd9Sstevel@tonic-gate {
6808*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
6809*7c478bd9Sstevel@tonic-gate 	int (*check)(ddi_dma_impl_t *);
6810*7c478bd9Sstevel@tonic-gate 
6811*7c478bd9Sstevel@tonic-gate 	if ((check = hp->dmai_fault_check) == NULL)
6812*7c478bd9Sstevel@tonic-gate 		check = i_ddi_dma_fault_check;
6813*7c478bd9Sstevel@tonic-gate 
6814*7c478bd9Sstevel@tonic-gate 	return (((*check)(hp) == DDI_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
6815*7c478bd9Sstevel@tonic-gate }
6816*7c478bd9Sstevel@tonic-gate 
6817*7c478bd9Sstevel@tonic-gate void
6818*7c478bd9Sstevel@tonic-gate i_ddi_dma_set_fault(ddi_dma_handle_t handle)
6819*7c478bd9Sstevel@tonic-gate {
6820*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
6821*7c478bd9Sstevel@tonic-gate 	void (*notify)(ddi_dma_impl_t *);
6822*7c478bd9Sstevel@tonic-gate 
6823*7c478bd9Sstevel@tonic-gate 	if (!hp->dmai_fault) {
6824*7c478bd9Sstevel@tonic-gate 		hp->dmai_fault = 1;
6825*7c478bd9Sstevel@tonic-gate 		if ((notify = hp->dmai_fault_notify) != NULL)
6826*7c478bd9Sstevel@tonic-gate 			(*notify)(hp);
6827*7c478bd9Sstevel@tonic-gate 	}
6828*7c478bd9Sstevel@tonic-gate }
6829*7c478bd9Sstevel@tonic-gate 
6830*7c478bd9Sstevel@tonic-gate void
6831*7c478bd9Sstevel@tonic-gate i_ddi_dma_clr_fault(ddi_dma_handle_t handle)
6832*7c478bd9Sstevel@tonic-gate {
6833*7c478bd9Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
6834*7c478bd9Sstevel@tonic-gate 	void (*notify)(ddi_dma_impl_t *);
6835*7c478bd9Sstevel@tonic-gate 
6836*7c478bd9Sstevel@tonic-gate 	if (hp->dmai_fault) {
6837*7c478bd9Sstevel@tonic-gate 		hp->dmai_fault = 0;
6838*7c478bd9Sstevel@tonic-gate 		if ((notify = hp->dmai_fault_notify) != NULL)
6839*7c478bd9Sstevel@tonic-gate 			(*notify)(hp);
6840*7c478bd9Sstevel@tonic-gate 	}
6841*7c478bd9Sstevel@tonic-gate }
6842*7c478bd9Sstevel@tonic-gate 
6843*7c478bd9Sstevel@tonic-gate /*
6844*7c478bd9Sstevel@tonic-gate  * register mapping routines.
6845*7c478bd9Sstevel@tonic-gate  */
6846*7c478bd9Sstevel@tonic-gate int
6847*7c478bd9Sstevel@tonic-gate ddi_regs_map_setup(dev_info_t *dip, uint_t rnumber, caddr_t *addrp,
6848*7c478bd9Sstevel@tonic-gate 	offset_t offset, offset_t len, ddi_device_acc_attr_t *accattrp,
6849*7c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t *handle)
6850*7c478bd9Sstevel@tonic-gate {
6851*7c478bd9Sstevel@tonic-gate 	ddi_map_req_t mr;
6852*7c478bd9Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
6853*7c478bd9Sstevel@tonic-gate 	int result;
6854*7c478bd9Sstevel@tonic-gate 
6855*7c478bd9Sstevel@tonic-gate 	/*
6856*7c478bd9Sstevel@tonic-gate 	 * Allocate and initialize the common elements of data access handle.
6857*7c478bd9Sstevel@tonic-gate 	 */
6858*7c478bd9Sstevel@tonic-gate 	*handle = impl_acc_hdl_alloc(KM_SLEEP, NULL);
6859*7c478bd9Sstevel@tonic-gate 	hp = impl_acc_hdl_get(*handle);
6860*7c478bd9Sstevel@tonic-gate 	hp->ah_vers = VERS_ACCHDL;
6861*7c478bd9Sstevel@tonic-gate 	hp->ah_dip = dip;
6862*7c478bd9Sstevel@tonic-gate 	hp->ah_rnumber = rnumber;
6863*7c478bd9Sstevel@tonic-gate 	hp->ah_offset = offset;
6864*7c478bd9Sstevel@tonic-gate 	hp->ah_len = len;
6865*7c478bd9Sstevel@tonic-gate 	hp->ah_acc = *accattrp;
6866*7c478bd9Sstevel@tonic-gate 
6867*7c478bd9Sstevel@tonic-gate 	/*
6868*7c478bd9Sstevel@tonic-gate 	 * Set up the mapping request and call to parent.
6869*7c478bd9Sstevel@tonic-gate 	 */
6870*7c478bd9Sstevel@tonic-gate 	mr.map_op = DDI_MO_MAP_LOCKED;
6871*7c478bd9Sstevel@tonic-gate 	mr.map_type = DDI_MT_RNUMBER;
6872*7c478bd9Sstevel@tonic-gate 	mr.map_obj.rnumber = rnumber;
6873*7c478bd9Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
6874*7c478bd9Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
6875*7c478bd9Sstevel@tonic-gate 	mr.map_handlep = hp;
6876*7c478bd9Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
6877*7c478bd9Sstevel@tonic-gate 	result = ddi_map(dip, &mr, offset, len, addrp);
6878*7c478bd9Sstevel@tonic-gate 
6879*7c478bd9Sstevel@tonic-gate 	/*
6880*7c478bd9Sstevel@tonic-gate 	 * check for end result
6881*7c478bd9Sstevel@tonic-gate 	 */
6882*7c478bd9Sstevel@tonic-gate 	if (result != DDI_SUCCESS) {
6883*7c478bd9Sstevel@tonic-gate 		impl_acc_hdl_free(*handle);
6884*7c478bd9Sstevel@tonic-gate 		*handle = (ddi_acc_handle_t)NULL;
6885*7c478bd9Sstevel@tonic-gate 	} else {
6886*7c478bd9Sstevel@tonic-gate 		hp->ah_addr = *addrp;
6887*7c478bd9Sstevel@tonic-gate 	}
6888*7c478bd9Sstevel@tonic-gate 
6889*7c478bd9Sstevel@tonic-gate 	return (result);
6890*7c478bd9Sstevel@tonic-gate }
6891*7c478bd9Sstevel@tonic-gate 
6892*7c478bd9Sstevel@tonic-gate void
6893*7c478bd9Sstevel@tonic-gate ddi_regs_map_free(ddi_acc_handle_t *handlep)
6894*7c478bd9Sstevel@tonic-gate {
6895*7c478bd9Sstevel@tonic-gate 	ddi_map_req_t mr;
6896*7c478bd9Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
6897*7c478bd9Sstevel@tonic-gate 
6898*7c478bd9Sstevel@tonic-gate 	hp = impl_acc_hdl_get(*handlep);
6899*7c478bd9Sstevel@tonic-gate 	ASSERT(hp);
6900*7c478bd9Sstevel@tonic-gate 
6901*7c478bd9Sstevel@tonic-gate 	mr.map_op = DDI_MO_UNMAP;
6902*7c478bd9Sstevel@tonic-gate 	mr.map_type = DDI_MT_RNUMBER;
6903*7c478bd9Sstevel@tonic-gate 	mr.map_obj.rnumber = hp->ah_rnumber;
6904*7c478bd9Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
6905*7c478bd9Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
6906*7c478bd9Sstevel@tonic-gate 	mr.map_handlep = hp;
6907*7c478bd9Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
6908*7c478bd9Sstevel@tonic-gate 
6909*7c478bd9Sstevel@tonic-gate 	/*
6910*7c478bd9Sstevel@tonic-gate 	 * Call my parent to unmap my regs.
6911*7c478bd9Sstevel@tonic-gate 	 */
6912*7c478bd9Sstevel@tonic-gate 	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
6913*7c478bd9Sstevel@tonic-gate 		hp->ah_len, &hp->ah_addr);
6914*7c478bd9Sstevel@tonic-gate 	/*
6915*7c478bd9Sstevel@tonic-gate 	 * free the handle
6916*7c478bd9Sstevel@tonic-gate 	 */
6917*7c478bd9Sstevel@tonic-gate 	impl_acc_hdl_free(*handlep);
6918*7c478bd9Sstevel@tonic-gate 	*handlep = (ddi_acc_handle_t)NULL;
6919*7c478bd9Sstevel@tonic-gate }
6920*7c478bd9Sstevel@tonic-gate 
6921*7c478bd9Sstevel@tonic-gate int
6922*7c478bd9Sstevel@tonic-gate ddi_device_zero(ddi_acc_handle_t handle, caddr_t dev_addr, size_t bytecount,
6923*7c478bd9Sstevel@tonic-gate 	ssize_t dev_advcnt, uint_t dev_datasz)
6924*7c478bd9Sstevel@tonic-gate {
6925*7c478bd9Sstevel@tonic-gate 	uint8_t *b;
6926*7c478bd9Sstevel@tonic-gate 	uint16_t *w;
6927*7c478bd9Sstevel@tonic-gate 	uint32_t *l;
6928*7c478bd9Sstevel@tonic-gate 	uint64_t *ll;
6929*7c478bd9Sstevel@tonic-gate 
6930*7c478bd9Sstevel@tonic-gate 	/* check for total byte count is multiple of data transfer size */
6931*7c478bd9Sstevel@tonic-gate 	if (bytecount != ((bytecount / dev_datasz) * dev_datasz))
6932*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6933*7c478bd9Sstevel@tonic-gate 
6934*7c478bd9Sstevel@tonic-gate 	switch (dev_datasz) {
6935*7c478bd9Sstevel@tonic-gate 	case DDI_DATA_SZ01_ACC:
6936*7c478bd9Sstevel@tonic-gate 		for (b = (uint8_t *)dev_addr;
6937*7c478bd9Sstevel@tonic-gate 			bytecount != 0; bytecount -= 1, b += dev_advcnt)
6938*7c478bd9Sstevel@tonic-gate 			ddi_put8(handle, b, 0);
6939*7c478bd9Sstevel@tonic-gate 		break;
6940*7c478bd9Sstevel@tonic-gate 	case DDI_DATA_SZ02_ACC:
6941*7c478bd9Sstevel@tonic-gate 		for (w = (uint16_t *)dev_addr;
6942*7c478bd9Sstevel@tonic-gate 			bytecount != 0; bytecount -= 2, w += dev_advcnt)
6943*7c478bd9Sstevel@tonic-gate 			ddi_put16(handle, w, 0);
6944*7c478bd9Sstevel@tonic-gate 		break;
6945*7c478bd9Sstevel@tonic-gate 	case DDI_DATA_SZ04_ACC:
6946*7c478bd9Sstevel@tonic-gate 		for (l = (uint32_t *)dev_addr;
6947*7c478bd9Sstevel@tonic-gate 			bytecount != 0; bytecount -= 4, l += dev_advcnt)
6948*7c478bd9Sstevel@tonic-gate 			ddi_put32(handle, l, 0);
6949*7c478bd9Sstevel@tonic-gate 		break;
6950*7c478bd9Sstevel@tonic-gate 	case DDI_DATA_SZ08_ACC:
6951*7c478bd9Sstevel@tonic-gate 		for (ll = (uint64_t *)dev_addr;
6952*7c478bd9Sstevel@tonic-gate 			bytecount != 0; bytecount -= 8, ll += dev_advcnt)
6953*7c478bd9Sstevel@tonic-gate 			ddi_put64(handle, ll, 0x0ll);
6954*7c478bd9Sstevel@tonic-gate 		break;
6955*7c478bd9Sstevel@tonic-gate 	default:
6956*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6957*7c478bd9Sstevel@tonic-gate 	}
6958*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
6959*7c478bd9Sstevel@tonic-gate }
6960*7c478bd9Sstevel@tonic-gate 
6961*7c478bd9Sstevel@tonic-gate int
6962*7c478bd9Sstevel@tonic-gate ddi_device_copy(
6963*7c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t src_handle, caddr_t src_addr, ssize_t src_advcnt,
6964*7c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t dest_handle, caddr_t dest_addr, ssize_t dest_advcnt,
6965*7c478bd9Sstevel@tonic-gate 	size_t bytecount, uint_t dev_datasz)
6966*7c478bd9Sstevel@tonic-gate {
6967*7c478bd9Sstevel@tonic-gate 	uint8_t *b_src, *b_dst;
6968*7c478bd9Sstevel@tonic-gate 	uint16_t *w_src, *w_dst;
6969*7c478bd9Sstevel@tonic-gate 	uint32_t *l_src, *l_dst;
6970*7c478bd9Sstevel@tonic-gate 	uint64_t *ll_src, *ll_dst;
6971*7c478bd9Sstevel@tonic-gate 
6972*7c478bd9Sstevel@tonic-gate 	/* check for total byte count is multiple of data transfer size */
6973*7c478bd9Sstevel@tonic-gate 	if (bytecount != ((bytecount / dev_datasz) * dev_datasz))
6974*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
6975*7c478bd9Sstevel@tonic-gate 
6976*7c478bd9Sstevel@tonic-gate 	switch (dev_datasz) {
6977*7c478bd9Sstevel@tonic-gate 	case DDI_DATA_SZ01_ACC:
6978*7c478bd9Sstevel@tonic-gate 		b_src = (uint8_t *)src_addr;
6979*7c478bd9Sstevel@tonic-gate 		b_dst = (uint8_t *)dest_addr;
6980*7c478bd9Sstevel@tonic-gate 
6981*7c478bd9Sstevel@tonic-gate 		for (; bytecount != 0; bytecount -= 1) {
6982*7c478bd9Sstevel@tonic-gate 			ddi_put8(dest_handle, b_dst,
6983*7c478bd9Sstevel@tonic-gate 				ddi_get8(src_handle, b_src));
6984*7c478bd9Sstevel@tonic-gate 			b_dst += dest_advcnt;
6985*7c478bd9Sstevel@tonic-gate 			b_src += src_advcnt;
6986*7c478bd9Sstevel@tonic-gate 		}
6987*7c478bd9Sstevel@tonic-gate 		break;
6988*7c478bd9Sstevel@tonic-gate 	case DDI_DATA_SZ02_ACC:
6989*7c478bd9Sstevel@tonic-gate 		w_src = (uint16_t *)src_addr;
6990*7c478bd9Sstevel@tonic-gate 		w_dst = (uint16_t *)dest_addr;
6991*7c478bd9Sstevel@tonic-gate 
6992*7c478bd9Sstevel@tonic-gate 		for (; bytecount != 0; bytecount -= 2) {
6993*7c478bd9Sstevel@tonic-gate 			ddi_put16(dest_handle, w_dst,
6994*7c478bd9Sstevel@tonic-gate 				ddi_get16(src_handle, w_src));
6995*7c478bd9Sstevel@tonic-gate 			w_dst += dest_advcnt;
6996*7c478bd9Sstevel@tonic-gate 			w_src += src_advcnt;
6997*7c478bd9Sstevel@tonic-gate 		}
6998*7c478bd9Sstevel@tonic-gate 		break;
6999*7c478bd9Sstevel@tonic-gate 	case DDI_DATA_SZ04_ACC:
7000*7c478bd9Sstevel@tonic-gate 		l_src = (uint32_t *)src_addr;
7001*7c478bd9Sstevel@tonic-gate 		l_dst = (uint32_t *)dest_addr;
7002*7c478bd9Sstevel@tonic-gate 
7003*7c478bd9Sstevel@tonic-gate 		for (; bytecount != 0; bytecount -= 4) {
7004*7c478bd9Sstevel@tonic-gate 			ddi_put32(dest_handle, l_dst,
7005*7c478bd9Sstevel@tonic-gate 				ddi_get32(src_handle, l_src));
7006*7c478bd9Sstevel@tonic-gate 			l_dst += dest_advcnt;
7007*7c478bd9Sstevel@tonic-gate 			l_src += src_advcnt;
7008*7c478bd9Sstevel@tonic-gate 		}
7009*7c478bd9Sstevel@tonic-gate 		break;
7010*7c478bd9Sstevel@tonic-gate 	case DDI_DATA_SZ08_ACC:
7011*7c478bd9Sstevel@tonic-gate 		ll_src = (uint64_t *)src_addr;
7012*7c478bd9Sstevel@tonic-gate 		ll_dst = (uint64_t *)dest_addr;
7013*7c478bd9Sstevel@tonic-gate 
7014*7c478bd9Sstevel@tonic-gate 		for (; bytecount != 0; bytecount -= 8) {
7015*7c478bd9Sstevel@tonic-gate 			ddi_put64(dest_handle, ll_dst,
7016*7c478bd9Sstevel@tonic-gate 				ddi_get64(src_handle, ll_src));
7017*7c478bd9Sstevel@tonic-gate 			ll_dst += dest_advcnt;
7018*7c478bd9Sstevel@tonic-gate 			ll_src += src_advcnt;
7019*7c478bd9Sstevel@tonic-gate 		}
7020*7c478bd9Sstevel@tonic-gate 		break;
7021*7c478bd9Sstevel@tonic-gate 	default:
7022*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7023*7c478bd9Sstevel@tonic-gate 	}
7024*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7025*7c478bd9Sstevel@tonic-gate }
7026*7c478bd9Sstevel@tonic-gate 
7027*7c478bd9Sstevel@tonic-gate #define	swap16(value)  \
7028*7c478bd9Sstevel@tonic-gate 	((((value) & 0xff) << 8) | ((value) >> 8))
7029*7c478bd9Sstevel@tonic-gate 
7030*7c478bd9Sstevel@tonic-gate #define	swap32(value)	\
7031*7c478bd9Sstevel@tonic-gate 	(((uint32_t)swap16((uint16_t)((value) & 0xffff)) << 16) | \
7032*7c478bd9Sstevel@tonic-gate 	(uint32_t)swap16((uint16_t)((value) >> 16)))
7033*7c478bd9Sstevel@tonic-gate 
7034*7c478bd9Sstevel@tonic-gate #define	swap64(value)	\
7035*7c478bd9Sstevel@tonic-gate 	(((uint64_t)swap32((uint32_t)((value) & 0xffffffff)) \
7036*7c478bd9Sstevel@tonic-gate 	    << 32) | \
7037*7c478bd9Sstevel@tonic-gate 	(uint64_t)swap32((uint32_t)((value) >> 32)))
7038*7c478bd9Sstevel@tonic-gate 
7039*7c478bd9Sstevel@tonic-gate uint16_t
7040*7c478bd9Sstevel@tonic-gate ddi_swap16(uint16_t value)
7041*7c478bd9Sstevel@tonic-gate {
7042*7c478bd9Sstevel@tonic-gate 	return (swap16(value));
7043*7c478bd9Sstevel@tonic-gate }
7044*7c478bd9Sstevel@tonic-gate 
7045*7c478bd9Sstevel@tonic-gate uint32_t
7046*7c478bd9Sstevel@tonic-gate ddi_swap32(uint32_t value)
7047*7c478bd9Sstevel@tonic-gate {
7048*7c478bd9Sstevel@tonic-gate 	return (swap32(value));
7049*7c478bd9Sstevel@tonic-gate }
7050*7c478bd9Sstevel@tonic-gate 
7051*7c478bd9Sstevel@tonic-gate uint64_t
7052*7c478bd9Sstevel@tonic-gate ddi_swap64(uint64_t value)
7053*7c478bd9Sstevel@tonic-gate {
7054*7c478bd9Sstevel@tonic-gate 	return (swap64(value));
7055*7c478bd9Sstevel@tonic-gate }
7056*7c478bd9Sstevel@tonic-gate 
7057*7c478bd9Sstevel@tonic-gate /*
7058*7c478bd9Sstevel@tonic-gate  * Convert a binding name to a driver name.
7059*7c478bd9Sstevel@tonic-gate  * A binding name is the name used to determine the driver for a
7060*7c478bd9Sstevel@tonic-gate  * device - it may be either an alias for the driver or the name
7061*7c478bd9Sstevel@tonic-gate  * of the driver itself.
7062*7c478bd9Sstevel@tonic-gate  */
7063*7c478bd9Sstevel@tonic-gate char *
7064*7c478bd9Sstevel@tonic-gate i_binding_to_drv_name(char *bname)
7065*7c478bd9Sstevel@tonic-gate {
7066*7c478bd9Sstevel@tonic-gate 	major_t major_no;
7067*7c478bd9Sstevel@tonic-gate 
7068*7c478bd9Sstevel@tonic-gate 	ASSERT(bname != NULL);
7069*7c478bd9Sstevel@tonic-gate 
7070*7c478bd9Sstevel@tonic-gate 	if ((major_no = ddi_name_to_major(bname)) == -1)
7071*7c478bd9Sstevel@tonic-gate 		return (NULL);
7072*7c478bd9Sstevel@tonic-gate 	return (ddi_major_to_name(major_no));
7073*7c478bd9Sstevel@tonic-gate }
7074*7c478bd9Sstevel@tonic-gate 
7075*7c478bd9Sstevel@tonic-gate /*
7076*7c478bd9Sstevel@tonic-gate  * Search for minor name that has specified dev_t and spec_type.
7077*7c478bd9Sstevel@tonic-gate  * If spec_type is zero then any dev_t match works.  Since we
7078*7c478bd9Sstevel@tonic-gate  * are returning a pointer to the minor name string, we require the
7079*7c478bd9Sstevel@tonic-gate  * caller to do the locking.
7080*7c478bd9Sstevel@tonic-gate  */
7081*7c478bd9Sstevel@tonic-gate char *
7082*7c478bd9Sstevel@tonic-gate i_ddi_devtspectype_to_minorname(dev_info_t *dip, dev_t dev, int spec_type)
7083*7c478bd9Sstevel@tonic-gate {
7084*7c478bd9Sstevel@tonic-gate 	struct ddi_minor_data	*dmdp;
7085*7c478bd9Sstevel@tonic-gate 
7086*7c478bd9Sstevel@tonic-gate 	/*
7087*7c478bd9Sstevel@tonic-gate 	 * The did layered driver currently intentionally returns a
7088*7c478bd9Sstevel@tonic-gate 	 * devinfo ptr for an underlying sd instance based on a did
7089*7c478bd9Sstevel@tonic-gate 	 * dev_t. In this case it is not an error.
7090*7c478bd9Sstevel@tonic-gate 	 *
7091*7c478bd9Sstevel@tonic-gate 	 * The did layered driver is associated with Sun Cluster.
7092*7c478bd9Sstevel@tonic-gate 	 */
7093*7c478bd9Sstevel@tonic-gate 	ASSERT((ddi_driver_major(dip) == getmajor(dev)) ||
7094*7c478bd9Sstevel@tonic-gate 		(strcmp(ddi_major_to_name(getmajor(dev)), "did") == 0));
7095*7c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&(DEVI(dip)->devi_lock)));
7096*7c478bd9Sstevel@tonic-gate 
7097*7c478bd9Sstevel@tonic-gate 	for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) {
7098*7c478bd9Sstevel@tonic-gate 		if (((dmdp->type == DDM_MINOR) ||
7099*7c478bd9Sstevel@tonic-gate 		    (dmdp->type == DDM_INTERNAL_PATH) ||
7100*7c478bd9Sstevel@tonic-gate 		    (dmdp->type == DDM_DEFAULT)) &&
7101*7c478bd9Sstevel@tonic-gate 		    (dmdp->ddm_dev == dev) &&
7102*7c478bd9Sstevel@tonic-gate 		    ((((spec_type & (S_IFCHR|S_IFBLK))) == 0) ||
7103*7c478bd9Sstevel@tonic-gate 		    (dmdp->ddm_spec_type == spec_type)))
7104*7c478bd9Sstevel@tonic-gate 			return (dmdp->ddm_name);
7105*7c478bd9Sstevel@tonic-gate 	}
7106*7c478bd9Sstevel@tonic-gate 
7107*7c478bd9Sstevel@tonic-gate 	return (NULL);
7108*7c478bd9Sstevel@tonic-gate }
7109*7c478bd9Sstevel@tonic-gate 
7110*7c478bd9Sstevel@tonic-gate /*
7111*7c478bd9Sstevel@tonic-gate  * Find the devt and spectype of the specified minor_name.
7112*7c478bd9Sstevel@tonic-gate  * Return DDI_FAILURE if minor_name not found. Since we are
7113*7c478bd9Sstevel@tonic-gate  * returning everything via arguments we can do the locking.
7114*7c478bd9Sstevel@tonic-gate  */
7115*7c478bd9Sstevel@tonic-gate int
7116*7c478bd9Sstevel@tonic-gate i_ddi_minorname_to_devtspectype(dev_info_t *dip, char *minor_name,
7117*7c478bd9Sstevel@tonic-gate 	dev_t *devtp, int *spectypep)
7118*7c478bd9Sstevel@tonic-gate {
7119*7c478bd9Sstevel@tonic-gate 	struct ddi_minor_data	*dmdp;
7120*7c478bd9Sstevel@tonic-gate 
7121*7c478bd9Sstevel@tonic-gate 	/* deal with clone minor nodes */
7122*7c478bd9Sstevel@tonic-gate 	if (dip == clone_dip) {
7123*7c478bd9Sstevel@tonic-gate 		major_t	major;
7124*7c478bd9Sstevel@tonic-gate 		/*
7125*7c478bd9Sstevel@tonic-gate 		 * Make sure minor_name is a STREAMS driver.
7126*7c478bd9Sstevel@tonic-gate 		 * We load the driver but don't attach to any instances.
7127*7c478bd9Sstevel@tonic-gate 		 */
7128*7c478bd9Sstevel@tonic-gate 
7129*7c478bd9Sstevel@tonic-gate 		major = ddi_name_to_major(minor_name);
7130*7c478bd9Sstevel@tonic-gate 		if (major == (major_t)-1)
7131*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7132*7c478bd9Sstevel@tonic-gate 
7133*7c478bd9Sstevel@tonic-gate 		if (ddi_hold_driver(major) == NULL)
7134*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7135*7c478bd9Sstevel@tonic-gate 
7136*7c478bd9Sstevel@tonic-gate 		if (STREAMSTAB(major) == NULL) {
7137*7c478bd9Sstevel@tonic-gate 			ddi_rele_driver(major);
7138*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7139*7c478bd9Sstevel@tonic-gate 		}
7140*7c478bd9Sstevel@tonic-gate 		ddi_rele_driver(major);
7141*7c478bd9Sstevel@tonic-gate 
7142*7c478bd9Sstevel@tonic-gate 		if (devtp)
7143*7c478bd9Sstevel@tonic-gate 			*devtp = makedevice(clone_major, (minor_t)major);
7144*7c478bd9Sstevel@tonic-gate 
7145*7c478bd9Sstevel@tonic-gate 		if (spectypep)
7146*7c478bd9Sstevel@tonic-gate 			*spectypep = S_IFCHR;
7147*7c478bd9Sstevel@tonic-gate 
7148*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
7149*7c478bd9Sstevel@tonic-gate 	}
7150*7c478bd9Sstevel@tonic-gate 
7151*7c478bd9Sstevel@tonic-gate 	ASSERT(!MUTEX_HELD(&(DEVI(dip)->devi_lock)));
7152*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
7153*7c478bd9Sstevel@tonic-gate 
7154*7c478bd9Sstevel@tonic-gate 	for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) {
7155*7c478bd9Sstevel@tonic-gate 		if (((dmdp->type != DDM_MINOR) &&
7156*7c478bd9Sstevel@tonic-gate 		    (dmdp->type != DDM_INTERNAL_PATH) &&
7157*7c478bd9Sstevel@tonic-gate 		    (dmdp->type != DDM_DEFAULT)) ||
7158*7c478bd9Sstevel@tonic-gate 		    strcmp(minor_name, dmdp->ddm_name))
7159*7c478bd9Sstevel@tonic-gate 			continue;
7160*7c478bd9Sstevel@tonic-gate 
7161*7c478bd9Sstevel@tonic-gate 		if (devtp)
7162*7c478bd9Sstevel@tonic-gate 			*devtp = dmdp->ddm_dev;
7163*7c478bd9Sstevel@tonic-gate 
7164*7c478bd9Sstevel@tonic-gate 		if (spectypep)
7165*7c478bd9Sstevel@tonic-gate 			*spectypep = dmdp->ddm_spec_type;
7166*7c478bd9Sstevel@tonic-gate 
7167*7c478bd9Sstevel@tonic-gate 		mutex_exit(&(DEVI(dip)->devi_lock));
7168*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
7169*7c478bd9Sstevel@tonic-gate 	}
7170*7c478bd9Sstevel@tonic-gate 
7171*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
7172*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
7173*7c478bd9Sstevel@tonic-gate }
7174*7c478bd9Sstevel@tonic-gate 
7175*7c478bd9Sstevel@tonic-gate extern char	hw_serial[];
7176*7c478bd9Sstevel@tonic-gate static kmutex_t devid_gen_mutex;
7177*7c478bd9Sstevel@tonic-gate static short	devid_gen_number;
7178*7c478bd9Sstevel@tonic-gate 
7179*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
7180*7c478bd9Sstevel@tonic-gate 
7181*7c478bd9Sstevel@tonic-gate static int	devid_register_corrupt = 0;
7182*7c478bd9Sstevel@tonic-gate static int	devid_register_corrupt_major = 0;
7183*7c478bd9Sstevel@tonic-gate static int	devid_register_corrupt_hint = 0;
7184*7c478bd9Sstevel@tonic-gate static int	devid_register_corrupt_hint_major = 0;
7185*7c478bd9Sstevel@tonic-gate 
7186*7c478bd9Sstevel@tonic-gate static int devid_lyr_debug = 0;
7187*7c478bd9Sstevel@tonic-gate 
7188*7c478bd9Sstevel@tonic-gate #define	DDI_DEBUG_DEVID_DEVTS(msg, ndevs, devs)		\
7189*7c478bd9Sstevel@tonic-gate 	if (devid_lyr_debug)					\
7190*7c478bd9Sstevel@tonic-gate 		ddi_debug_devid_devts(msg, ndevs, devs)
7191*7c478bd9Sstevel@tonic-gate 
7192*7c478bd9Sstevel@tonic-gate #else
7193*7c478bd9Sstevel@tonic-gate 
7194*7c478bd9Sstevel@tonic-gate #define	DDI_DEBUG_DEVID_DEVTS(msg, ndevs, devs)
7195*7c478bd9Sstevel@tonic-gate 
7196*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
7197*7c478bd9Sstevel@tonic-gate 
7198*7c478bd9Sstevel@tonic-gate 
7199*7c478bd9Sstevel@tonic-gate #ifdef	DEBUG
7200*7c478bd9Sstevel@tonic-gate 
7201*7c478bd9Sstevel@tonic-gate static void
7202*7c478bd9Sstevel@tonic-gate ddi_debug_devid_devts(char *msg, int ndevs, dev_t *devs)
7203*7c478bd9Sstevel@tonic-gate {
7204*7c478bd9Sstevel@tonic-gate 	int i;
7205*7c478bd9Sstevel@tonic-gate 
7206*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "%s:\n", msg);
7207*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ndevs; i++) {
7208*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "    0x%lx\n", devs[i]);
7209*7c478bd9Sstevel@tonic-gate 	}
7210*7c478bd9Sstevel@tonic-gate }
7211*7c478bd9Sstevel@tonic-gate 
7212*7c478bd9Sstevel@tonic-gate static void
7213*7c478bd9Sstevel@tonic-gate ddi_debug_devid_paths(char *msg, int npaths, char **paths)
7214*7c478bd9Sstevel@tonic-gate {
7215*7c478bd9Sstevel@tonic-gate 	int i;
7216*7c478bd9Sstevel@tonic-gate 
7217*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "%s:\n", msg);
7218*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < npaths; i++) {
7219*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "    %s\n", paths[i]);
7220*7c478bd9Sstevel@tonic-gate 	}
7221*7c478bd9Sstevel@tonic-gate }
7222*7c478bd9Sstevel@tonic-gate 
7223*7c478bd9Sstevel@tonic-gate static void
7224*7c478bd9Sstevel@tonic-gate ddi_debug_devid_devts_per_path(char *path, int ndevs, dev_t *devs)
7225*7c478bd9Sstevel@tonic-gate {
7226*7c478bd9Sstevel@tonic-gate 	int i;
7227*7c478bd9Sstevel@tonic-gate 
7228*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "dev_ts per path %s\n", path);
7229*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < ndevs; i++) {
7230*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "    0x%lx\n", devs[i]);
7231*7c478bd9Sstevel@tonic-gate 	}
7232*7c478bd9Sstevel@tonic-gate }
7233*7c478bd9Sstevel@tonic-gate 
7234*7c478bd9Sstevel@tonic-gate #endif	/* DEBUG */
7235*7c478bd9Sstevel@tonic-gate 
7236*7c478bd9Sstevel@tonic-gate /*
7237*7c478bd9Sstevel@tonic-gate  * Register device id into DDI framework.
7238*7c478bd9Sstevel@tonic-gate  * Must be called when device is attached.
7239*7c478bd9Sstevel@tonic-gate  */
7240*7c478bd9Sstevel@tonic-gate static int
7241*7c478bd9Sstevel@tonic-gate i_ddi_devid_register(dev_info_t *dip, ddi_devid_t devid)
7242*7c478bd9Sstevel@tonic-gate {
7243*7c478bd9Sstevel@tonic-gate 	impl_devid_t	*i_devid = (impl_devid_t *)devid;
7244*7c478bd9Sstevel@tonic-gate 	size_t		driver_len;
7245*7c478bd9Sstevel@tonic-gate 	const char	*driver_name;
7246*7c478bd9Sstevel@tonic-gate 	char		*devid_str;
7247*7c478bd9Sstevel@tonic-gate 	major_t		major;
7248*7c478bd9Sstevel@tonic-gate 
7249*7c478bd9Sstevel@tonic-gate 	if ((dip == NULL) ||
7250*7c478bd9Sstevel@tonic-gate 	    ((major = ddi_driver_major(dip)) == (major_t)-1))
7251*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7252*7c478bd9Sstevel@tonic-gate 
7253*7c478bd9Sstevel@tonic-gate 	/* verify that the devid is valid */
7254*7c478bd9Sstevel@tonic-gate 	if (ddi_devid_valid(devid) != DDI_SUCCESS)
7255*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7256*7c478bd9Sstevel@tonic-gate 
7257*7c478bd9Sstevel@tonic-gate 	/* Updating driver name hint in devid */
7258*7c478bd9Sstevel@tonic-gate 	driver_name = ddi_driver_name(dip);
7259*7c478bd9Sstevel@tonic-gate 	driver_len = strlen(driver_name);
7260*7c478bd9Sstevel@tonic-gate 	if (driver_len > DEVID_HINT_SIZE) {
7261*7c478bd9Sstevel@tonic-gate 		/* Pick up last four characters of driver name */
7262*7c478bd9Sstevel@tonic-gate 		driver_name += driver_len - DEVID_HINT_SIZE;
7263*7c478bd9Sstevel@tonic-gate 		driver_len = DEVID_HINT_SIZE;
7264*7c478bd9Sstevel@tonic-gate 	}
7265*7c478bd9Sstevel@tonic-gate 	bzero(i_devid->did_driver, DEVID_HINT_SIZE);
7266*7c478bd9Sstevel@tonic-gate 	bcopy(driver_name, i_devid->did_driver, driver_len);
7267*7c478bd9Sstevel@tonic-gate 
7268*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
7269*7c478bd9Sstevel@tonic-gate 	/* Corrupt the devid for testing. */
7270*7c478bd9Sstevel@tonic-gate 	if (devid_register_corrupt)
7271*7c478bd9Sstevel@tonic-gate 		i_devid->did_id[0] += devid_register_corrupt;
7272*7c478bd9Sstevel@tonic-gate 	if (devid_register_corrupt_major &&
7273*7c478bd9Sstevel@tonic-gate 	    (major == devid_register_corrupt_major))
7274*7c478bd9Sstevel@tonic-gate 		i_devid->did_id[0] += 1;
7275*7c478bd9Sstevel@tonic-gate 	if (devid_register_corrupt_hint)
7276*7c478bd9Sstevel@tonic-gate 		i_devid->did_driver[0] += devid_register_corrupt_hint;
7277*7c478bd9Sstevel@tonic-gate 	if (devid_register_corrupt_hint_major &&
7278*7c478bd9Sstevel@tonic-gate 	    (major == devid_register_corrupt_hint_major))
7279*7c478bd9Sstevel@tonic-gate 		i_devid->did_driver[0] += 1;
7280*7c478bd9Sstevel@tonic-gate #endif /* DEBUG */
7281*7c478bd9Sstevel@tonic-gate 
7282*7c478bd9Sstevel@tonic-gate 	/* encode the devid as a string */
7283*7c478bd9Sstevel@tonic-gate 	if ((devid_str = ddi_devid_str_encode(devid, NULL)) == NULL)
7284*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7285*7c478bd9Sstevel@tonic-gate 
7286*7c478bd9Sstevel@tonic-gate 	/* add string as a string property */
7287*7c478bd9Sstevel@tonic-gate 	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip,
7288*7c478bd9Sstevel@tonic-gate 	    DEVID_PROP_NAME, devid_str) != DDI_SUCCESS) {
7289*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: devid property update failed",
7290*7c478bd9Sstevel@tonic-gate 			ddi_driver_name(dip), ddi_get_instance(dip));
7291*7c478bd9Sstevel@tonic-gate 		ddi_devid_str_free(devid_str);
7292*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7293*7c478bd9Sstevel@tonic-gate 	}
7294*7c478bd9Sstevel@tonic-gate 
7295*7c478bd9Sstevel@tonic-gate 	ddi_devid_str_free(devid_str);
7296*7c478bd9Sstevel@tonic-gate 
7297*7c478bd9Sstevel@tonic-gate #ifdef	DEVID_COMPATIBILITY
7298*7c478bd9Sstevel@tonic-gate 	/*
7299*7c478bd9Sstevel@tonic-gate 	 * marker for devinfo snapshot compatibility.
7300*7c478bd9Sstevel@tonic-gate 	 * This code gets deleted when di_devid is gone from libdevid
7301*7c478bd9Sstevel@tonic-gate 	 */
7302*7c478bd9Sstevel@tonic-gate 	DEVI(dip)->devi_devid = DEVID_COMPATIBILITY;
7303*7c478bd9Sstevel@tonic-gate #endif	/* DEVID_COMPATIBILITY */
7304*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7305*7c478bd9Sstevel@tonic-gate }
7306*7c478bd9Sstevel@tonic-gate 
7307*7c478bd9Sstevel@tonic-gate int
7308*7c478bd9Sstevel@tonic-gate ddi_devid_register(dev_info_t *dip, ddi_devid_t devid)
7309*7c478bd9Sstevel@tonic-gate {
7310*7c478bd9Sstevel@tonic-gate 	int rval;
7311*7c478bd9Sstevel@tonic-gate 
7312*7c478bd9Sstevel@tonic-gate 	rval = i_ddi_devid_register(dip, devid);
7313*7c478bd9Sstevel@tonic-gate 	if (rval == DDI_SUCCESS) {
7314*7c478bd9Sstevel@tonic-gate 		/*
7315*7c478bd9Sstevel@tonic-gate 		 * Register devid in devid-to-path cache
7316*7c478bd9Sstevel@tonic-gate 		 */
7317*7c478bd9Sstevel@tonic-gate 		if (e_devid_cache_register(dip, devid) == DDI_SUCCESS) {
7318*7c478bd9Sstevel@tonic-gate 			mutex_enter(&DEVI(dip)->devi_lock);
7319*7c478bd9Sstevel@tonic-gate 			DEVI(dip)->devi_flags |= DEVI_REGISTERED_DEVID;
7320*7c478bd9Sstevel@tonic-gate 			mutex_exit(&DEVI(dip)->devi_lock);
7321*7c478bd9Sstevel@tonic-gate 		} else {
7322*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: failed to cache devid",
7323*7c478bd9Sstevel@tonic-gate 				ddi_driver_name(dip), ddi_get_instance(dip));
7324*7c478bd9Sstevel@tonic-gate 		}
7325*7c478bd9Sstevel@tonic-gate 	} else {
7326*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: failed to register devid",
7327*7c478bd9Sstevel@tonic-gate 			ddi_driver_name(dip), ddi_get_instance(dip));
7328*7c478bd9Sstevel@tonic-gate 	}
7329*7c478bd9Sstevel@tonic-gate 	return (rval);
7330*7c478bd9Sstevel@tonic-gate }
7331*7c478bd9Sstevel@tonic-gate 
7332*7c478bd9Sstevel@tonic-gate /*
7333*7c478bd9Sstevel@tonic-gate  * Remove (unregister) device id from DDI framework.
7334*7c478bd9Sstevel@tonic-gate  * Must be called when device is detached.
7335*7c478bd9Sstevel@tonic-gate  */
7336*7c478bd9Sstevel@tonic-gate static void
7337*7c478bd9Sstevel@tonic-gate i_ddi_devid_unregister(dev_info_t *dip)
7338*7c478bd9Sstevel@tonic-gate {
7339*7c478bd9Sstevel@tonic-gate #ifdef	DEVID_COMPATIBILITY
7340*7c478bd9Sstevel@tonic-gate 	/*
7341*7c478bd9Sstevel@tonic-gate 	 * marker for micro release devinfo snapshot compatibility.
7342*7c478bd9Sstevel@tonic-gate 	 * This code gets deleted for the minor release.
7343*7c478bd9Sstevel@tonic-gate 	 */
7344*7c478bd9Sstevel@tonic-gate 	DEVI(dip)->devi_devid = NULL;		/* unset DEVID_PROP */
7345*7c478bd9Sstevel@tonic-gate #endif	/* DEVID_COMPATIBILITY */
7346*7c478bd9Sstevel@tonic-gate 
7347*7c478bd9Sstevel@tonic-gate 	/* remove the devid property */
7348*7c478bd9Sstevel@tonic-gate 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, DEVID_PROP_NAME);
7349*7c478bd9Sstevel@tonic-gate }
7350*7c478bd9Sstevel@tonic-gate 
7351*7c478bd9Sstevel@tonic-gate void
7352*7c478bd9Sstevel@tonic-gate ddi_devid_unregister(dev_info_t *dip)
7353*7c478bd9Sstevel@tonic-gate {
7354*7c478bd9Sstevel@tonic-gate 	mutex_enter(&DEVI(dip)->devi_lock);
7355*7c478bd9Sstevel@tonic-gate 	DEVI(dip)->devi_flags &= ~DEVI_REGISTERED_DEVID;
7356*7c478bd9Sstevel@tonic-gate 	mutex_exit(&DEVI(dip)->devi_lock);
7357*7c478bd9Sstevel@tonic-gate 	e_devid_cache_unregister(dip);
7358*7c478bd9Sstevel@tonic-gate 	i_ddi_devid_unregister(dip);
7359*7c478bd9Sstevel@tonic-gate }
7360*7c478bd9Sstevel@tonic-gate 
7361*7c478bd9Sstevel@tonic-gate /*
7362*7c478bd9Sstevel@tonic-gate  * Allocate and initialize a device id.
7363*7c478bd9Sstevel@tonic-gate  */
7364*7c478bd9Sstevel@tonic-gate int
7365*7c478bd9Sstevel@tonic-gate ddi_devid_init(
7366*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip,
7367*7c478bd9Sstevel@tonic-gate 	ushort_t	devid_type,
7368*7c478bd9Sstevel@tonic-gate 	ushort_t	nbytes,
7369*7c478bd9Sstevel@tonic-gate 	void		*id,
7370*7c478bd9Sstevel@tonic-gate 	ddi_devid_t	*ret_devid)
7371*7c478bd9Sstevel@tonic-gate {
7372*7c478bd9Sstevel@tonic-gate 	impl_devid_t	*i_devid;
7373*7c478bd9Sstevel@tonic-gate 	int		sz = sizeof (*i_devid) + nbytes - sizeof (char);
7374*7c478bd9Sstevel@tonic-gate 	int		driver_len;
7375*7c478bd9Sstevel@tonic-gate 	const char	*driver_name;
7376*7c478bd9Sstevel@tonic-gate 
7377*7c478bd9Sstevel@tonic-gate 	switch (devid_type) {
7378*7c478bd9Sstevel@tonic-gate 	case DEVID_SCSI3_WWN:
7379*7c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
7380*7c478bd9Sstevel@tonic-gate 	case DEVID_SCSI_SERIAL:
7381*7c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
7382*7c478bd9Sstevel@tonic-gate 	case DEVID_ATA_SERIAL:
7383*7c478bd9Sstevel@tonic-gate 		/*FALLTHRU*/
7384*7c478bd9Sstevel@tonic-gate 	case DEVID_ENCAP:
7385*7c478bd9Sstevel@tonic-gate 		if (nbytes == 0)
7386*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7387*7c478bd9Sstevel@tonic-gate 		if (id == NULL)
7388*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7389*7c478bd9Sstevel@tonic-gate 		break;
7390*7c478bd9Sstevel@tonic-gate 	case DEVID_FAB:
7391*7c478bd9Sstevel@tonic-gate 		if (nbytes != 0)
7392*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7393*7c478bd9Sstevel@tonic-gate 		if (id != NULL)
7394*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
7395*7c478bd9Sstevel@tonic-gate 		nbytes = sizeof (int) +
7396*7c478bd9Sstevel@tonic-gate 		    sizeof (struct timeval32) + sizeof (short);
7397*7c478bd9Sstevel@tonic-gate 		sz += nbytes;
7398*7c478bd9Sstevel@tonic-gate 		break;
7399*7c478bd9Sstevel@tonic-gate 	default:
7400*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7401*7c478bd9Sstevel@tonic-gate 	}
7402*7c478bd9Sstevel@tonic-gate 
7403*7c478bd9Sstevel@tonic-gate 	if ((i_devid = kmem_zalloc(sz, KM_SLEEP)) == NULL)
7404*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7405*7c478bd9Sstevel@tonic-gate 
7406*7c478bd9Sstevel@tonic-gate 	i_devid->did_magic_hi = DEVID_MAGIC_MSB;
7407*7c478bd9Sstevel@tonic-gate 	i_devid->did_magic_lo = DEVID_MAGIC_LSB;
7408*7c478bd9Sstevel@tonic-gate 	i_devid->did_rev_hi = DEVID_REV_MSB;
7409*7c478bd9Sstevel@tonic-gate 	i_devid->did_rev_lo = DEVID_REV_LSB;
7410*7c478bd9Sstevel@tonic-gate 	DEVID_FORMTYPE(i_devid, devid_type);
7411*7c478bd9Sstevel@tonic-gate 	DEVID_FORMLEN(i_devid, nbytes);
7412*7c478bd9Sstevel@tonic-gate 
7413*7c478bd9Sstevel@tonic-gate 	/* Fill in driver name hint */
7414*7c478bd9Sstevel@tonic-gate 	driver_name = ddi_driver_name(dip);
7415*7c478bd9Sstevel@tonic-gate 	driver_len = strlen(driver_name);
7416*7c478bd9Sstevel@tonic-gate 	if (driver_len > DEVID_HINT_SIZE) {
7417*7c478bd9Sstevel@tonic-gate 		/* Pick up last four characters of driver name */
7418*7c478bd9Sstevel@tonic-gate 		driver_name += driver_len - DEVID_HINT_SIZE;
7419*7c478bd9Sstevel@tonic-gate 		driver_len = DEVID_HINT_SIZE;
7420*7c478bd9Sstevel@tonic-gate 	}
7421*7c478bd9Sstevel@tonic-gate 
7422*7c478bd9Sstevel@tonic-gate 	bcopy(driver_name, i_devid->did_driver, driver_len);
7423*7c478bd9Sstevel@tonic-gate 
7424*7c478bd9Sstevel@tonic-gate 	/* Fill in id field */
7425*7c478bd9Sstevel@tonic-gate 	if (devid_type == DEVID_FAB) {
7426*7c478bd9Sstevel@tonic-gate 		char		*cp;
7427*7c478bd9Sstevel@tonic-gate 		int		hostid;
7428*7c478bd9Sstevel@tonic-gate 		char		*hostid_cp = &hw_serial[0];
7429*7c478bd9Sstevel@tonic-gate 		struct timeval32 timestamp32;
7430*7c478bd9Sstevel@tonic-gate 		int		i;
7431*7c478bd9Sstevel@tonic-gate 		int		*ip;
7432*7c478bd9Sstevel@tonic-gate 		short		gen;
7433*7c478bd9Sstevel@tonic-gate 
7434*7c478bd9Sstevel@tonic-gate 		/* increase the generation number */
7435*7c478bd9Sstevel@tonic-gate 		mutex_enter(&devid_gen_mutex);
7436*7c478bd9Sstevel@tonic-gate 		gen = devid_gen_number++;
7437*7c478bd9Sstevel@tonic-gate 		mutex_exit(&devid_gen_mutex);
7438*7c478bd9Sstevel@tonic-gate 
7439*7c478bd9Sstevel@tonic-gate 		cp = i_devid->did_id;
7440*7c478bd9Sstevel@tonic-gate 
7441*7c478bd9Sstevel@tonic-gate 		/* Fill in host id (big-endian byte ordering) */
7442*7c478bd9Sstevel@tonic-gate 		hostid = stoi(&hostid_cp);
7443*7c478bd9Sstevel@tonic-gate 		*cp++ = hibyte(hiword(hostid));
7444*7c478bd9Sstevel@tonic-gate 		*cp++ = lobyte(hiword(hostid));
7445*7c478bd9Sstevel@tonic-gate 		*cp++ = hibyte(loword(hostid));
7446*7c478bd9Sstevel@tonic-gate 		*cp++ = lobyte(loword(hostid));
7447*7c478bd9Sstevel@tonic-gate 
7448*7c478bd9Sstevel@tonic-gate 		/*
7449*7c478bd9Sstevel@tonic-gate 		 * Fill in timestamp (big-endian byte ordering)
7450*7c478bd9Sstevel@tonic-gate 		 *
7451*7c478bd9Sstevel@tonic-gate 		 * (Note that the format may have to be changed
7452*7c478bd9Sstevel@tonic-gate 		 * before 2038 comes around, though it's arguably
7453*7c478bd9Sstevel@tonic-gate 		 * unique enough as it is..)
7454*7c478bd9Sstevel@tonic-gate 		 */
7455*7c478bd9Sstevel@tonic-gate 		uniqtime32(&timestamp32);
7456*7c478bd9Sstevel@tonic-gate 		ip = (int *)&timestamp32;
7457*7c478bd9Sstevel@tonic-gate 		for (i = 0;
7458*7c478bd9Sstevel@tonic-gate 		    i < sizeof (timestamp32) / sizeof (int); i++, ip++) {
7459*7c478bd9Sstevel@tonic-gate 			int	val;
7460*7c478bd9Sstevel@tonic-gate 			val = *ip;
7461*7c478bd9Sstevel@tonic-gate 			*cp++ = hibyte(hiword(val));
7462*7c478bd9Sstevel@tonic-gate 			*cp++ = lobyte(hiword(val));
7463*7c478bd9Sstevel@tonic-gate 			*cp++ = hibyte(loword(val));
7464*7c478bd9Sstevel@tonic-gate 			*cp++ = lobyte(loword(val));
7465*7c478bd9Sstevel@tonic-gate 		}
7466*7c478bd9Sstevel@tonic-gate 
7467*7c478bd9Sstevel@tonic-gate 		/* fill in the generation number */
7468*7c478bd9Sstevel@tonic-gate 		*cp++ = hibyte(gen);
7469*7c478bd9Sstevel@tonic-gate 		*cp++ = lobyte(gen);
7470*7c478bd9Sstevel@tonic-gate 	} else
7471*7c478bd9Sstevel@tonic-gate 		bcopy(id, i_devid->did_id, nbytes);
7472*7c478bd9Sstevel@tonic-gate 
7473*7c478bd9Sstevel@tonic-gate 	/* return device id */
7474*7c478bd9Sstevel@tonic-gate 	*ret_devid = (ddi_devid_t)i_devid;
7475*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7476*7c478bd9Sstevel@tonic-gate }
7477*7c478bd9Sstevel@tonic-gate 
7478*7c478bd9Sstevel@tonic-gate int
7479*7c478bd9Sstevel@tonic-gate i_ddi_devi_get_devid(dev_t dev, dev_info_t *dip, ddi_devid_t *ret_devid)
7480*7c478bd9Sstevel@tonic-gate {
7481*7c478bd9Sstevel@tonic-gate 	char		*devidstr;
7482*7c478bd9Sstevel@tonic-gate 
7483*7c478bd9Sstevel@tonic-gate 	ASSERT(dev != DDI_DEV_T_NONE);
7484*7c478bd9Sstevel@tonic-gate 
7485*7c478bd9Sstevel@tonic-gate 	/* look up the property, devt specific first */
7486*7c478bd9Sstevel@tonic-gate 	if (ddi_prop_lookup_string(dev, dip, DDI_PROP_DONTPASS,
7487*7c478bd9Sstevel@tonic-gate 	    DEVID_PROP_NAME, &devidstr) != DDI_PROP_SUCCESS) {
7488*7c478bd9Sstevel@tonic-gate 		if ((dev == DDI_DEV_T_ANY) ||
7489*7c478bd9Sstevel@tonic-gate 		    (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
7490*7c478bd9Sstevel@tonic-gate 			DDI_PROP_DONTPASS, DEVID_PROP_NAME, &devidstr) !=
7491*7c478bd9Sstevel@tonic-gate 			DDI_PROP_SUCCESS)) {
7492*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
7493*7c478bd9Sstevel@tonic-gate 		}
7494*7c478bd9Sstevel@tonic-gate 	}
7495*7c478bd9Sstevel@tonic-gate 
7496*7c478bd9Sstevel@tonic-gate 	/* convert to binary form */
7497*7c478bd9Sstevel@tonic-gate 	if (ddi_devid_str_decode(devidstr, ret_devid, NULL) == -1) {
7498*7c478bd9Sstevel@tonic-gate 		ddi_prop_free(devidstr);
7499*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7500*7c478bd9Sstevel@tonic-gate 	}
7501*7c478bd9Sstevel@tonic-gate 	ddi_prop_free(devidstr);
7502*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7503*7c478bd9Sstevel@tonic-gate }
7504*7c478bd9Sstevel@tonic-gate 
7505*7c478bd9Sstevel@tonic-gate /*
7506*7c478bd9Sstevel@tonic-gate  * Return a copy of the device id for dev_t
7507*7c478bd9Sstevel@tonic-gate  */
7508*7c478bd9Sstevel@tonic-gate int
7509*7c478bd9Sstevel@tonic-gate ddi_lyr_get_devid(dev_t dev, ddi_devid_t *ret_devid)
7510*7c478bd9Sstevel@tonic-gate {
7511*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
7512*7c478bd9Sstevel@tonic-gate 	int		rval;
7513*7c478bd9Sstevel@tonic-gate 
7514*7c478bd9Sstevel@tonic-gate 	/* get the dip */
7515*7c478bd9Sstevel@tonic-gate 	if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
7516*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7517*7c478bd9Sstevel@tonic-gate 
7518*7c478bd9Sstevel@tonic-gate 	rval = i_ddi_devi_get_devid(dev, dip, ret_devid);
7519*7c478bd9Sstevel@tonic-gate 
7520*7c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);		/* e_ddi_hold_devi_by_dev() */
7521*7c478bd9Sstevel@tonic-gate 	return (rval);
7522*7c478bd9Sstevel@tonic-gate }
7523*7c478bd9Sstevel@tonic-gate 
7524*7c478bd9Sstevel@tonic-gate /*
7525*7c478bd9Sstevel@tonic-gate  * Return a copy of the minor name for dev_t and spec_type
7526*7c478bd9Sstevel@tonic-gate  */
7527*7c478bd9Sstevel@tonic-gate int
7528*7c478bd9Sstevel@tonic-gate ddi_lyr_get_minor_name(dev_t dev, int spec_type, char **minor_name)
7529*7c478bd9Sstevel@tonic-gate {
7530*7c478bd9Sstevel@tonic-gate 	dev_info_t	*dip;
7531*7c478bd9Sstevel@tonic-gate 	char		*nm;
7532*7c478bd9Sstevel@tonic-gate 	size_t		alloc_sz, sz;
7533*7c478bd9Sstevel@tonic-gate 
7534*7c478bd9Sstevel@tonic-gate 	if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
7535*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7536*7c478bd9Sstevel@tonic-gate 
7537*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
7538*7c478bd9Sstevel@tonic-gate 
7539*7c478bd9Sstevel@tonic-gate 	if ((nm = i_ddi_devtspectype_to_minorname(dip,
7540*7c478bd9Sstevel@tonic-gate 	    dev, spec_type)) == NULL) {
7541*7c478bd9Sstevel@tonic-gate 		mutex_exit(&(DEVI(dip)->devi_lock));
7542*7c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);	/* e_ddi_hold_devi_by_dev() */
7543*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7544*7c478bd9Sstevel@tonic-gate 	}
7545*7c478bd9Sstevel@tonic-gate 
7546*7c478bd9Sstevel@tonic-gate 	/* make a copy */
7547*7c478bd9Sstevel@tonic-gate 	alloc_sz = strlen(nm) + 1;
7548*7c478bd9Sstevel@tonic-gate retry:
7549*7c478bd9Sstevel@tonic-gate 	/* drop lock to allocate memory */
7550*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
7551*7c478bd9Sstevel@tonic-gate 	*minor_name = kmem_alloc(alloc_sz, KM_SLEEP);
7552*7c478bd9Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
7553*7c478bd9Sstevel@tonic-gate 
7554*7c478bd9Sstevel@tonic-gate 	/* re-check things, since we dropped the lock */
7555*7c478bd9Sstevel@tonic-gate 	if ((nm = i_ddi_devtspectype_to_minorname(dip,
7556*7c478bd9Sstevel@tonic-gate 	    dev, spec_type)) == NULL) {
7557*7c478bd9Sstevel@tonic-gate 		mutex_exit(&(DEVI(dip)->devi_lock));
7558*7c478bd9Sstevel@tonic-gate 		kmem_free(*minor_name, alloc_sz);
7559*7c478bd9Sstevel@tonic-gate 		*minor_name = NULL;
7560*7c478bd9Sstevel@tonic-gate 		ddi_release_devi(dip);	/* e_ddi_hold_devi_by_dev() */
7561*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7562*7c478bd9Sstevel@tonic-gate 	}
7563*7c478bd9Sstevel@tonic-gate 
7564*7c478bd9Sstevel@tonic-gate 	/* verify size is the same */
7565*7c478bd9Sstevel@tonic-gate 	sz = strlen(nm) + 1;
7566*7c478bd9Sstevel@tonic-gate 	if (alloc_sz != sz) {
7567*7c478bd9Sstevel@tonic-gate 		kmem_free(*minor_name, alloc_sz);
7568*7c478bd9Sstevel@tonic-gate 		alloc_sz = sz;
7569*7c478bd9Sstevel@tonic-gate 		goto retry;
7570*7c478bd9Sstevel@tonic-gate 	}
7571*7c478bd9Sstevel@tonic-gate 
7572*7c478bd9Sstevel@tonic-gate 	/* sz == alloc_sz - make a copy */
7573*7c478bd9Sstevel@tonic-gate 	(void) strcpy(*minor_name, nm);
7574*7c478bd9Sstevel@tonic-gate 
7575*7c478bd9Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
7576*7c478bd9Sstevel@tonic-gate 	ddi_release_devi(dip);	/* e_ddi_hold_devi_by_dev() */
7577*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
7578*7c478bd9Sstevel@tonic-gate }
7579*7c478bd9Sstevel@tonic-gate 
7580*7c478bd9Sstevel@tonic-gate int
7581*7c478bd9Sstevel@tonic-gate ddi_lyr_devid_to_devlist(
7582*7c478bd9Sstevel@tonic-gate 	ddi_devid_t	devid,
7583*7c478bd9Sstevel@tonic-gate 	char		*minor_name,
7584*7c478bd9Sstevel@tonic-gate 	int		*retndevs,
7585*7c478bd9Sstevel@tonic-gate 	dev_t		**retdevs)
7586*7c478bd9Sstevel@tonic-gate {
7587*7c478bd9Sstevel@tonic-gate 	ASSERT(ddi_devid_valid(devid) == DDI_SUCCESS);
7588*7c478bd9Sstevel@tonic-gate 
7589*7c478bd9Sstevel@tonic-gate 	if (e_devid_cache_to_devt_list(devid, minor_name,
7590*7c478bd9Sstevel@tonic-gate 	    retndevs, retdevs) == DDI_SUCCESS) {
7591*7c478bd9Sstevel@tonic-gate 		ASSERT(*retndevs > 0);
7592*7c478bd9Sstevel@tonic-gate 		DDI_DEBUG_DEVID_DEVTS("ddi_lyr_devid_to_devlist",
7593*7c478bd9Sstevel@tonic-gate 			*retndevs, *retdevs);
7594*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
7595*7c478bd9Sstevel@tonic-gate 	}
7596*7c478bd9Sstevel@tonic-gate 
7597*7c478bd9Sstevel@tonic-gate 	if (e_ddi_devid_discovery(devid) == DDI_FAILURE) {
7598*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7599*7c478bd9Sstevel@tonic-gate 	}
7600*7c478bd9Sstevel@tonic-gate 
7601*7c478bd9Sstevel@tonic-gate 	if (e_devid_cache_to_devt_list(devid, minor_name,
7602*7c478bd9Sstevel@tonic-gate 	    retndevs, retdevs) == DDI_SUCCESS) {
7603*7c478bd9Sstevel@tonic-gate 		ASSERT(*retndevs > 0);
7604*7c478bd9Sstevel@tonic-gate 		DDI_DEBUG_DEVID_DEVTS("ddi_lyr_devid_to_devlist",
7605*7c478bd9Sstevel@tonic-gate 			*retndevs, *retdevs);
7606*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
7607*7c478bd9Sstevel@tonic-gate 	}
7608*7c478bd9Sstevel@tonic-gate 
7609*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
7610*7c478bd9Sstevel@tonic-gate }
7611*7c478bd9Sstevel@tonic-gate 
7612*7c478bd9Sstevel@tonic-gate void
7613*7c478bd9Sstevel@tonic-gate ddi_lyr_free_devlist(dev_t *devlist, int ndevs)
7614*7c478bd9Sstevel@tonic-gate {
7615*7c478bd9Sstevel@tonic-gate 	kmem_free(devlist, sizeof (dev_t) * ndevs);
7616*7c478bd9Sstevel@tonic-gate }
7617*7c478bd9Sstevel@tonic-gate 
7618*7c478bd9Sstevel@tonic-gate /*
7619*7c478bd9Sstevel@tonic-gate  * Note: This will need to be fixed if we ever allow processes to
7620*7c478bd9Sstevel@tonic-gate  * have more than one data model per exec.
7621*7c478bd9Sstevel@tonic-gate  */
7622*7c478bd9Sstevel@tonic-gate model_t
7623*7c478bd9Sstevel@tonic-gate ddi_mmap_get_model(void)
7624*7c478bd9Sstevel@tonic-gate {
7625*7c478bd9Sstevel@tonic-gate 	return (get_udatamodel());
7626*7c478bd9Sstevel@tonic-gate }
7627*7c478bd9Sstevel@tonic-gate 
7628*7c478bd9Sstevel@tonic-gate model_t
7629*7c478bd9Sstevel@tonic-gate ddi_model_convert_from(model_t model)
7630*7c478bd9Sstevel@tonic-gate {
7631*7c478bd9Sstevel@tonic-gate 	return ((model & DDI_MODEL_MASK) & ~DDI_MODEL_NATIVE);
7632*7c478bd9Sstevel@tonic-gate }
7633*7c478bd9Sstevel@tonic-gate 
7634*7c478bd9Sstevel@tonic-gate /*
7635*7c478bd9Sstevel@tonic-gate  * ddi interfaces managing storage and retrieval of eventcookies.
7636*7c478bd9Sstevel@tonic-gate  */
7637*7c478bd9Sstevel@tonic-gate 
7638*7c478bd9Sstevel@tonic-gate /*
7639*7c478bd9Sstevel@tonic-gate  * Invoke bus nexus driver's implementation of the
7640*7c478bd9Sstevel@tonic-gate  * (*bus_remove_eventcall)() interface to remove a registered
7641*7c478bd9Sstevel@tonic-gate  * callback handler for "event".
7642*7c478bd9Sstevel@tonic-gate  */
7643*7c478bd9Sstevel@tonic-gate int
7644*7c478bd9Sstevel@tonic-gate ddi_remove_event_handler(ddi_callback_id_t id)
7645*7c478bd9Sstevel@tonic-gate {
7646*7c478bd9Sstevel@tonic-gate 	ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)id;
7647*7c478bd9Sstevel@tonic-gate 	dev_info_t *ddip;
7648*7c478bd9Sstevel@tonic-gate 
7649*7c478bd9Sstevel@tonic-gate 	ASSERT(cb);
7650*7c478bd9Sstevel@tonic-gate 	if (!cb) {
7651*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
7652*7c478bd9Sstevel@tonic-gate 	}
7653*7c478bd9Sstevel@tonic-gate 
7654*7c478bd9Sstevel@tonic-gate 	ddip = NDI_EVENT_DDIP(cb->ndi_evtcb_cookie);
7655*7c478bd9Sstevel@tonic-gate 	return (ndi_busop_remove_eventcall(ddip, id));
7656*7c478bd9Sstevel@tonic-gate }
7657*7c478bd9Sstevel@tonic-gate 
7658*7c478bd9Sstevel@tonic-gate /*
7659*7c478bd9Sstevel@tonic-gate  * Invoke bus nexus driver's implementation of the
7660*7c478bd9Sstevel@tonic-gate  * (*bus_add_eventcall)() interface to register a callback handler
7661*7c478bd9Sstevel@tonic-gate  * for "event".
7662*7c478bd9Sstevel@tonic-gate  */
7663*7c478bd9Sstevel@tonic-gate int
7664*7c478bd9Sstevel@tonic-gate ddi_add_event_handler(dev_info_t *dip, ddi_eventcookie_t event,
7665*7c478bd9Sstevel@tonic-gate     void (*handler)(dev_info_t *, ddi_eventcookie_t, void *, void *),
7666*7c478bd9Sstevel@tonic-gate     void *arg, ddi_callback_id_t *id)
7667*7c478bd9Sstevel@tonic-gate {
7668*7c478bd9Sstevel@tonic-gate 	return (ndi_busop_add_eventcall(dip, dip, event, handler, arg, id));
7669*7c478bd9Sstevel@tonic-gate }
7670*7c478bd9Sstevel@tonic-gate 
7671*7c478bd9Sstevel@tonic-gate 
7672*7c478bd9Sstevel@tonic-gate /*
7673*7c478bd9Sstevel@tonic-gate  * Return a handle for event "name" by calling up the device tree
7674*7c478bd9Sstevel@tonic-gate  * hierarchy via  (*bus_get_eventcookie)() interface until claimed
7675*7c478bd9Sstevel@tonic-gate  * by a bus nexus or top of dev_info tree is reached.
7676*7c478bd9Sstevel@tonic-gate  */
7677*7c478bd9Sstevel@tonic-gate int
7678*7c478bd9Sstevel@tonic-gate ddi_get_eventcookie(dev_info_t *dip, char *name,
7679*7c478bd9Sstevel@tonic-gate     ddi_eventcookie_t *event_cookiep)
7680*7c478bd9Sstevel@tonic-gate {
7681*7c478bd9Sstevel@tonic-gate 	return (ndi_busop_get_eventcookie(dip, dip,
7682*7c478bd9Sstevel@tonic-gate 	    name, event_cookiep));
7683*7c478bd9Sstevel@tonic-gate }
7684*7c478bd9Sstevel@tonic-gate 
7685*7c478bd9Sstevel@tonic-gate /*
7686*7c478bd9Sstevel@tonic-gate  * single thread access to dev_info node and set state
7687*7c478bd9Sstevel@tonic-gate  */
7688*7c478bd9Sstevel@tonic-gate void
7689*7c478bd9Sstevel@tonic-gate i_devi_enter(dev_info_t *dip, uint_t s_mask, uint_t w_mask, int has_lock)
7690*7c478bd9Sstevel@tonic-gate {
7691*7c478bd9Sstevel@tonic-gate 	if (!has_lock)
7692*7c478bd9Sstevel@tonic-gate 		mutex_enter(&(DEVI(dip)->devi_lock));
7693*7c478bd9Sstevel@tonic-gate 
7694*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&(DEVI(dip)->devi_lock)));
7695*7c478bd9Sstevel@tonic-gate 
7696*7c478bd9Sstevel@tonic-gate 	/*
7697*7c478bd9Sstevel@tonic-gate 	 * wait until state(s) have been changed
7698*7c478bd9Sstevel@tonic-gate 	 */
7699*7c478bd9Sstevel@tonic-gate 	while ((DEVI(dip)->devi_state & w_mask) != 0) {
7700*7c478bd9Sstevel@tonic-gate 		cv_wait(&(DEVI(dip)->devi_cv), &(DEVI(dip)->devi_lock));
7701*7c478bd9Sstevel@tonic-gate 	}
7702*7c478bd9Sstevel@tonic-gate 	DEVI(dip)->devi_state |= s_mask;
7703*7c478bd9Sstevel@tonic-gate 
7704*7c478bd9Sstevel@tonic-gate 	if (!has_lock)
7705*7c478bd9Sstevel@tonic-gate 		mutex_exit(&(DEVI(dip)->devi_lock));
7706*7c478bd9Sstevel@tonic-gate }
7707*7c478bd9Sstevel@tonic-gate 
7708*7c478bd9Sstevel@tonic-gate void
7709*7c478bd9Sstevel@tonic-gate i_devi_exit(dev_info_t *dip, uint_t c_mask, int has_lock)
7710*7c478bd9Sstevel@tonic-gate {
7711*7c478bd9Sstevel@tonic-gate 	if (!has_lock)
7712*7c478bd9Sstevel@tonic-gate 		mutex_enter(&(DEVI(dip)->devi_lock));
7713*7c478bd9Sstevel@tonic-gate 
7714*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&(DEVI(dip)->devi_lock)));
7715*7c478bd9Sstevel@tonic-gate 
7716*7c478bd9Sstevel@tonic-gate 	/*
7717*7c478bd9Sstevel@tonic-gate 	 * clear the state(s) and wakeup any threads waiting
7718*7c478bd9Sstevel@tonic-gate 	 * for state change
7719*7c478bd9Sstevel@tonic-gate 	 */
7720*7c478bd9Sstevel@tonic-gate 	DEVI(dip)->devi_state &= ~c_mask;
7721*7c478bd9Sstevel@tonic-gate 	cv_broadcast(&(DEVI(dip)->devi_cv));
7722*7c478bd9Sstevel@tonic-gate 
7723*7c478bd9Sstevel@tonic-gate 	if (!has_lock)
7724*7c478bd9Sstevel@tonic-gate 		mutex_exit(&(DEVI(dip)->devi_lock));
7725*7c478bd9Sstevel@tonic-gate }
7726*7c478bd9Sstevel@tonic-gate 
7727*7c478bd9Sstevel@tonic-gate /*
7728*7c478bd9Sstevel@tonic-gate  * This procedure is provided as the general callback function when
7729*7c478bd9Sstevel@tonic-gate  * umem_lockmemory calls as_add_callback for long term memory locking.
7730*7c478bd9Sstevel@tonic-gate  * When as_unmap, as_setprot, or as_free encounter segments which have
7731*7c478bd9Sstevel@tonic-gate  * locked memory, this callback will be invoked.
7732*7c478bd9Sstevel@tonic-gate  */
7733*7c478bd9Sstevel@tonic-gate void
7734*7c478bd9Sstevel@tonic-gate umem_lock_undo(struct as *as, void *arg, uint_t event)
7735*7c478bd9Sstevel@tonic-gate {
7736*7c478bd9Sstevel@tonic-gate 	_NOTE(ARGUNUSED(as, event))
7737*7c478bd9Sstevel@tonic-gate 	struct ddi_umem_cookie *cp = (struct ddi_umem_cookie *)arg;
7738*7c478bd9Sstevel@tonic-gate 
7739*7c478bd9Sstevel@tonic-gate 	/*
7740*7c478bd9Sstevel@tonic-gate 	 * Call the cleanup function.  Decrement the cookie reference
7741*7c478bd9Sstevel@tonic-gate 	 * count, if it goes to zero, return the memory for the cookie.
7742*7c478bd9Sstevel@tonic-gate 	 * The i_ddi_umem_unlock for this cookie may or may not have been
7743*7c478bd9Sstevel@tonic-gate 	 * called already.  It is the responsibility of the caller of
7744*7c478bd9Sstevel@tonic-gate 	 * umem_lockmemory to handle the case of the cleanup routine
7745*7c478bd9Sstevel@tonic-gate 	 * being called after a ddi_umem_unlock for the cookie
7746*7c478bd9Sstevel@tonic-gate 	 * was called.
7747*7c478bd9Sstevel@tonic-gate 	 */
7748*7c478bd9Sstevel@tonic-gate 
7749*7c478bd9Sstevel@tonic-gate 	(*cp->callbacks.cbo_umem_lock_cleanup)((ddi_umem_cookie_t)cp);
7750*7c478bd9Sstevel@tonic-gate 
7751*7c478bd9Sstevel@tonic-gate 	/* remove the cookie if reference goes to zero */
7752*7c478bd9Sstevel@tonic-gate 	if (atomic_add_long_nv((ulong_t *)(&(cp->cook_refcnt)), -1) == 0) {
7753*7c478bd9Sstevel@tonic-gate 		kmem_free(cp, sizeof (struct ddi_umem_cookie));
7754*7c478bd9Sstevel@tonic-gate 	}
7755*7c478bd9Sstevel@tonic-gate }
7756*7c478bd9Sstevel@tonic-gate 
7757*7c478bd9Sstevel@tonic-gate /*
7758*7c478bd9Sstevel@tonic-gate  * The following two Consolidation Private routines provide generic
7759*7c478bd9Sstevel@tonic-gate  * interfaces to increase/decrease the amount of device-locked memory.
7760*7c478bd9Sstevel@tonic-gate  *
7761*7c478bd9Sstevel@tonic-gate  * To keep project_rele and project_hold consistent, i_ddi_decr_locked_memory()
7762*7c478bd9Sstevel@tonic-gate  * must be called every time i_ddi_incr_locked_memory() is called.
7763*7c478bd9Sstevel@tonic-gate  */
7764*7c478bd9Sstevel@tonic-gate int
7765*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
7766*7c478bd9Sstevel@tonic-gate i_ddi_incr_locked_memory(proc_t *procp, task_t *taskp,
7767*7c478bd9Sstevel@tonic-gate     kproject_t *projectp, zone_t *zonep, rctl_qty_t inc)
7768*7c478bd9Sstevel@tonic-gate {
7769*7c478bd9Sstevel@tonic-gate 	kproject_t *projp;
7770*7c478bd9Sstevel@tonic-gate 
7771*7c478bd9Sstevel@tonic-gate 	ASSERT(procp);
7772*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&procp->p_lock));
7773*7c478bd9Sstevel@tonic-gate 
7774*7c478bd9Sstevel@tonic-gate 	projp = procp->p_task->tk_proj;
7775*7c478bd9Sstevel@tonic-gate 	mutex_enter(&umem_devlockmem_rctl_lock);
7776*7c478bd9Sstevel@tonic-gate 	/*
7777*7c478bd9Sstevel@tonic-gate 	 * Test if the requested memory can be locked without exceeding the
7778*7c478bd9Sstevel@tonic-gate 	 * limits.
7779*7c478bd9Sstevel@tonic-gate 	 */
7780*7c478bd9Sstevel@tonic-gate 	if (rctl_test(rc_project_devlockmem, projp->kpj_rctls,
7781*7c478bd9Sstevel@tonic-gate 	    procp, inc, RCA_SAFE) & RCT_DENY) {
7782*7c478bd9Sstevel@tonic-gate 		mutex_exit(&umem_devlockmem_rctl_lock);
7783*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
7784*7c478bd9Sstevel@tonic-gate 	}
7785*7c478bd9Sstevel@tonic-gate 	projp->kpj_data.kpd_devlockmem += inc;
7786*7c478bd9Sstevel@tonic-gate 	mutex_exit(&umem_devlockmem_rctl_lock);
7787*7c478bd9Sstevel@tonic-gate 	/*
7788*7c478bd9Sstevel@tonic-gate 	 * Grab a hold on the project.
7789*7c478bd9Sstevel@tonic-gate 	 */
7790*7c478bd9Sstevel@tonic-gate 	(void) project_hold(projp);
7791*7c478bd9Sstevel@tonic-gate 
7792*7c478bd9Sstevel@tonic-gate 	return (0);
7793*7c478bd9Sstevel@tonic-gate }
7794*7c478bd9Sstevel@tonic-gate 
7795*7c478bd9Sstevel@tonic-gate /*
7796*7c478bd9Sstevel@tonic-gate  * To keep project_rele and project_hold consistent, i_ddi_incr_locked_memory()
7797*7c478bd9Sstevel@tonic-gate  * must be called every time i_ddi_decr_locked_memory() is called.
7798*7c478bd9Sstevel@tonic-gate  */
7799*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
7800*7c478bd9Sstevel@tonic-gate void
7801*7c478bd9Sstevel@tonic-gate i_ddi_decr_locked_memory(proc_t *procp, task_t *taskp,
7802*7c478bd9Sstevel@tonic-gate     kproject_t *projectp, zone_t *zonep, rctl_qty_t dec)
7803*7c478bd9Sstevel@tonic-gate {
7804*7c478bd9Sstevel@tonic-gate 	ASSERT(projectp);
7805*7c478bd9Sstevel@tonic-gate 
7806*7c478bd9Sstevel@tonic-gate 	mutex_enter(&umem_devlockmem_rctl_lock);
7807*7c478bd9Sstevel@tonic-gate 	projectp->kpj_data.kpd_devlockmem -= dec;
7808*7c478bd9Sstevel@tonic-gate 	mutex_exit(&umem_devlockmem_rctl_lock);
7809*7c478bd9Sstevel@tonic-gate 
7810*7c478bd9Sstevel@tonic-gate 	/*
7811*7c478bd9Sstevel@tonic-gate 	 * Release the project pointer reference accquired in
7812*7c478bd9Sstevel@tonic-gate 	 * i_ddi_incr_locked_memory().
7813*7c478bd9Sstevel@tonic-gate 	 */
7814*7c478bd9Sstevel@tonic-gate 	(void) project_rele(projectp);
7815*7c478bd9Sstevel@tonic-gate }
7816*7c478bd9Sstevel@tonic-gate 
7817*7c478bd9Sstevel@tonic-gate /*
7818*7c478bd9Sstevel@tonic-gate  * This routine checks if the max-device-locked-memory resource ctl is
7819*7c478bd9Sstevel@tonic-gate  * exceeded, if not increments it, grabs a hold on the project.
7820*7c478bd9Sstevel@tonic-gate  * Returns 0 if successful otherwise returns error code
7821*7c478bd9Sstevel@tonic-gate  */
7822*7c478bd9Sstevel@tonic-gate static int
7823*7c478bd9Sstevel@tonic-gate umem_incr_devlockmem(struct ddi_umem_cookie *cookie)
7824*7c478bd9Sstevel@tonic-gate {
7825*7c478bd9Sstevel@tonic-gate 	proc_t		*procp;
7826*7c478bd9Sstevel@tonic-gate 	int		ret;
7827*7c478bd9Sstevel@tonic-gate 
7828*7c478bd9Sstevel@tonic-gate 	ASSERT(cookie);
7829*7c478bd9Sstevel@tonic-gate 	procp = cookie->procp;
7830*7c478bd9Sstevel@tonic-gate 	ASSERT(procp);
7831*7c478bd9Sstevel@tonic-gate 
7832*7c478bd9Sstevel@tonic-gate 	mutex_enter(&procp->p_lock);
7833*7c478bd9Sstevel@tonic-gate 
7834*7c478bd9Sstevel@tonic-gate 	if ((ret = i_ddi_incr_locked_memory(procp, NULL,
7835*7c478bd9Sstevel@tonic-gate 		NULL, NULL, cookie->size)) != 0) {
7836*7c478bd9Sstevel@tonic-gate 		mutex_exit(&procp->p_lock);
7837*7c478bd9Sstevel@tonic-gate 		return (ret);
7838*7c478bd9Sstevel@tonic-gate 	}
7839*7c478bd9Sstevel@tonic-gate 
7840*7c478bd9Sstevel@tonic-gate 	/*
7841*7c478bd9Sstevel@tonic-gate 	 * save the project pointer in the
7842*7c478bd9Sstevel@tonic-gate 	 * umem cookie, project pointer already
7843*7c478bd9Sstevel@tonic-gate 	 * hold in i_ddi_incr_locked_memory
7844*7c478bd9Sstevel@tonic-gate 	 */
7845*7c478bd9Sstevel@tonic-gate 	cookie->lockmem_proj = (void *)procp->p_task->tk_proj;
7846*7c478bd9Sstevel@tonic-gate 	mutex_exit(&procp->p_lock);
7847*7c478bd9Sstevel@tonic-gate 
7848*7c478bd9Sstevel@tonic-gate 	return (0);
7849*7c478bd9Sstevel@tonic-gate }
7850*7c478bd9Sstevel@tonic-gate 
7851*7c478bd9Sstevel@tonic-gate /*
7852*7c478bd9Sstevel@tonic-gate  * Decrements the max-device-locked-memory resource ctl and releases
7853*7c478bd9Sstevel@tonic-gate  * the hold on the project that was acquired during umem_incr_devlockmem
7854*7c478bd9Sstevel@tonic-gate  */
7855*7c478bd9Sstevel@tonic-gate static void
7856*7c478bd9Sstevel@tonic-gate umem_decr_devlockmem(struct ddi_umem_cookie *cookie)
7857*7c478bd9Sstevel@tonic-gate {
7858*7c478bd9Sstevel@tonic-gate 	kproject_t	*projp;
7859*7c478bd9Sstevel@tonic-gate 
7860*7c478bd9Sstevel@tonic-gate 	if (!cookie->lockmem_proj)
7861*7c478bd9Sstevel@tonic-gate 		return;
7862*7c478bd9Sstevel@tonic-gate 
7863*7c478bd9Sstevel@tonic-gate 	projp = (kproject_t *)cookie->lockmem_proj;
7864*7c478bd9Sstevel@tonic-gate 	i_ddi_decr_locked_memory(NULL, NULL, projp, NULL, cookie->size);
7865*7c478bd9Sstevel@tonic-gate 
7866*7c478bd9Sstevel@tonic-gate 	cookie->lockmem_proj = NULL;
7867*7c478bd9Sstevel@tonic-gate }
7868*7c478bd9Sstevel@tonic-gate 
7869*7c478bd9Sstevel@tonic-gate /*
7870*7c478bd9Sstevel@tonic-gate  * A consolidation private function which is essentially equivalent to
7871*7c478bd9Sstevel@tonic-gate  * ddi_umem_lock but with the addition of arguments ops_vector and procp.
7872*7c478bd9Sstevel@tonic-gate  * A call to as_add_callback is done if DDI_UMEMLOCK_LONGTERM is set, and
7873*7c478bd9Sstevel@tonic-gate  * the ops_vector is valid.
7874*7c478bd9Sstevel@tonic-gate  *
7875*7c478bd9Sstevel@tonic-gate  * Lock the virtual address range in the current process and create a
7876*7c478bd9Sstevel@tonic-gate  * ddi_umem_cookie (of type UMEM_LOCKED). This can be used to pass to
7877*7c478bd9Sstevel@tonic-gate  * ddi_umem_iosetup to create a buf or do devmap_umem_setup/remap to export
7878*7c478bd9Sstevel@tonic-gate  * to user space.
7879*7c478bd9Sstevel@tonic-gate  *
7880*7c478bd9Sstevel@tonic-gate  * Note: The resource control accounting currently uses a full charge model
7881*7c478bd9Sstevel@tonic-gate  * in other words attempts to lock the same/overlapping areas of memory
7882*7c478bd9Sstevel@tonic-gate  * will deduct the full size of the buffer from the projects running
7883*7c478bd9Sstevel@tonic-gate  * counter for the device locked memory.
7884*7c478bd9Sstevel@tonic-gate  *
7885*7c478bd9Sstevel@tonic-gate  * addr, size should be PAGESIZE aligned
7886*7c478bd9Sstevel@tonic-gate  *
7887*7c478bd9Sstevel@tonic-gate  * flags - DDI_UMEMLOCK_READ, DDI_UMEMLOCK_WRITE or both
7888*7c478bd9Sstevel@tonic-gate  *	identifies whether the locked memory will be read or written or both
7889*7c478bd9Sstevel@tonic-gate  *      DDI_UMEMLOCK_LONGTERM  must be set when the locking will
7890*7c478bd9Sstevel@tonic-gate  * be maintained for an indefinitely long period (essentially permanent),
7891*7c478bd9Sstevel@tonic-gate  * rather than for what would be required for a typical I/O completion.
7892*7c478bd9Sstevel@tonic-gate  * When DDI_UMEMLOCK_LONGTERM is set, umem_lockmemory will return EFAULT
7893*7c478bd9Sstevel@tonic-gate  * if the memory pertains to a regular file which is mapped MAP_SHARED.
7894*7c478bd9Sstevel@tonic-gate  * This is to prevent a deadlock if a file truncation is attempted after
7895*7c478bd9Sstevel@tonic-gate  * after the locking is done.
7896*7c478bd9Sstevel@tonic-gate  *
7897*7c478bd9Sstevel@tonic-gate  * Returns 0 on success
7898*7c478bd9Sstevel@tonic-gate  *	EINVAL - for invalid parameters
7899*7c478bd9Sstevel@tonic-gate  *	EPERM, ENOMEM and other error codes returned by as_pagelock
7900*7c478bd9Sstevel@tonic-gate  *	ENOMEM - is returned if the current request to lock memory exceeds
7901*7c478bd9Sstevel@tonic-gate  *		project.max-device-locked-memory resource control value.
7902*7c478bd9Sstevel@tonic-gate  *      EFAULT - memory pertains to a regular file mapped shared and
7903*7c478bd9Sstevel@tonic-gate  *		and DDI_UMEMLOCK_LONGTERM flag is set
7904*7c478bd9Sstevel@tonic-gate  *	EAGAIN - could not start the ddi_umem_unlock list processing thread
7905*7c478bd9Sstevel@tonic-gate  */
7906*7c478bd9Sstevel@tonic-gate int
7907*7c478bd9Sstevel@tonic-gate umem_lockmemory(caddr_t addr, size_t len, int flags, ddi_umem_cookie_t *cookie,
7908*7c478bd9Sstevel@tonic-gate 		struct umem_callback_ops *ops_vector,
7909*7c478bd9Sstevel@tonic-gate 		proc_t *procp)
7910*7c478bd9Sstevel@tonic-gate {
7911*7c478bd9Sstevel@tonic-gate 	int	error;
7912*7c478bd9Sstevel@tonic-gate 	struct ddi_umem_cookie *p;
7913*7c478bd9Sstevel@tonic-gate 	void	(*driver_callback)() = NULL;
7914*7c478bd9Sstevel@tonic-gate 	struct as *as = procp->p_as;
7915*7c478bd9Sstevel@tonic-gate 	struct seg		*seg;
7916*7c478bd9Sstevel@tonic-gate 	vnode_t			*vp;
7917*7c478bd9Sstevel@tonic-gate 
7918*7c478bd9Sstevel@tonic-gate 	*cookie = NULL;		/* in case of any error return */
7919*7c478bd9Sstevel@tonic-gate 
7920*7c478bd9Sstevel@tonic-gate 	/* These are the only three valid flags */
7921*7c478bd9Sstevel@tonic-gate 	if ((flags & ~(DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE |
7922*7c478bd9Sstevel@tonic-gate 	    DDI_UMEMLOCK_LONGTERM)) != 0)
7923*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
7924*7c478bd9Sstevel@tonic-gate 
7925*7c478bd9Sstevel@tonic-gate 	/* At least one (can be both) of the two access flags must be set */
7926*7c478bd9Sstevel@tonic-gate 	if ((flags & (DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE)) == 0)
7927*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
7928*7c478bd9Sstevel@tonic-gate 
7929*7c478bd9Sstevel@tonic-gate 	/* addr and len must be page-aligned */
7930*7c478bd9Sstevel@tonic-gate 	if (((uintptr_t)addr & PAGEOFFSET) != 0)
7931*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
7932*7c478bd9Sstevel@tonic-gate 
7933*7c478bd9Sstevel@tonic-gate 	if ((len & PAGEOFFSET) != 0)
7934*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
7935*7c478bd9Sstevel@tonic-gate 
7936*7c478bd9Sstevel@tonic-gate 	/*
7937*7c478bd9Sstevel@tonic-gate 	 * For longterm locking a driver callback must be specified; if
7938*7c478bd9Sstevel@tonic-gate 	 * not longterm then a callback is optional.
7939*7c478bd9Sstevel@tonic-gate 	 */
7940*7c478bd9Sstevel@tonic-gate 	if (ops_vector != NULL) {
7941*7c478bd9Sstevel@tonic-gate 		if (ops_vector->cbo_umem_callback_version !=
7942*7c478bd9Sstevel@tonic-gate 		    UMEM_CALLBACK_VERSION)
7943*7c478bd9Sstevel@tonic-gate 			return (EINVAL);
7944*7c478bd9Sstevel@tonic-gate 		else
7945*7c478bd9Sstevel@tonic-gate 			driver_callback = ops_vector->cbo_umem_lock_cleanup;
7946*7c478bd9Sstevel@tonic-gate 	}
7947*7c478bd9Sstevel@tonic-gate 	if ((driver_callback == NULL) && (flags & DDI_UMEMLOCK_LONGTERM))
7948*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
7949*7c478bd9Sstevel@tonic-gate 
7950*7c478bd9Sstevel@tonic-gate 	/*
7951*7c478bd9Sstevel@tonic-gate 	 * Call i_ddi_umem_unlock_thread_start if necessary.  It will
7952*7c478bd9Sstevel@tonic-gate 	 * be called on first ddi_umem_lock or umem_lockmemory call.
7953*7c478bd9Sstevel@tonic-gate 	 */
7954*7c478bd9Sstevel@tonic-gate 	if (ddi_umem_unlock_thread == NULL)
7955*7c478bd9Sstevel@tonic-gate 		i_ddi_umem_unlock_thread_start();
7956*7c478bd9Sstevel@tonic-gate 
7957*7c478bd9Sstevel@tonic-gate 	/* Allocate memory for the cookie */
7958*7c478bd9Sstevel@tonic-gate 	p = kmem_zalloc(sizeof (struct ddi_umem_cookie), KM_SLEEP);
7959*7c478bd9Sstevel@tonic-gate 
7960*7c478bd9Sstevel@tonic-gate 	/* Convert the flags to seg_rw type */
7961*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_UMEMLOCK_WRITE) {
7962*7c478bd9Sstevel@tonic-gate 		p->s_flags = S_WRITE;
7963*7c478bd9Sstevel@tonic-gate 	} else {
7964*7c478bd9Sstevel@tonic-gate 		p->s_flags = S_READ;
7965*7c478bd9Sstevel@tonic-gate 	}
7966*7c478bd9Sstevel@tonic-gate 
7967*7c478bd9Sstevel@tonic-gate 	/* Store procp in cookie for later iosetup/unlock */
7968*7c478bd9Sstevel@tonic-gate 	p->procp = (void *)procp;
7969*7c478bd9Sstevel@tonic-gate 
7970*7c478bd9Sstevel@tonic-gate 	/*
7971*7c478bd9Sstevel@tonic-gate 	 * Store the struct as pointer in cookie for later use by
7972*7c478bd9Sstevel@tonic-gate 	 * ddi_umem_unlock.  The proc->p_as will be stale if ddi_umem_unlock
7973*7c478bd9Sstevel@tonic-gate 	 * is called after relvm is called.
7974*7c478bd9Sstevel@tonic-gate 	 */
7975*7c478bd9Sstevel@tonic-gate 	p->asp = as;
7976*7c478bd9Sstevel@tonic-gate 
7977*7c478bd9Sstevel@tonic-gate 	/*
7978*7c478bd9Sstevel@tonic-gate 	 * The size field is needed for lockmem accounting.
7979*7c478bd9Sstevel@tonic-gate 	 */
7980*7c478bd9Sstevel@tonic-gate 	p->size = len;
7981*7c478bd9Sstevel@tonic-gate 
7982*7c478bd9Sstevel@tonic-gate 	if (umem_incr_devlockmem(p) != 0) {
7983*7c478bd9Sstevel@tonic-gate 		/*
7984*7c478bd9Sstevel@tonic-gate 		 * The requested memory cannot be locked
7985*7c478bd9Sstevel@tonic-gate 		 */
7986*7c478bd9Sstevel@tonic-gate 		kmem_free(p, sizeof (struct ddi_umem_cookie));
7987*7c478bd9Sstevel@tonic-gate 		*cookie = (ddi_umem_cookie_t)NULL;
7988*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
7989*7c478bd9Sstevel@tonic-gate 	}
7990*7c478bd9Sstevel@tonic-gate 	/*
7991*7c478bd9Sstevel@tonic-gate 	 * umem_incr_devlockmem stashes the project ptr into the
7992*7c478bd9Sstevel@tonic-gate 	 * cookie. This is needed during unlock since that can
7993*7c478bd9Sstevel@tonic-gate 	 * happen in a non-USER context
7994*7c478bd9Sstevel@tonic-gate 	 */
7995*7c478bd9Sstevel@tonic-gate 	ASSERT(p->lockmem_proj);
7996*7c478bd9Sstevel@tonic-gate 
7997*7c478bd9Sstevel@tonic-gate 	/* Lock the pages corresponding to addr, len in memory */
7998*7c478bd9Sstevel@tonic-gate 	error = as_pagelock(as, &(p->pparray), addr, len, p->s_flags);
7999*7c478bd9Sstevel@tonic-gate 	if (error != 0) {
8000*7c478bd9Sstevel@tonic-gate 		umem_decr_devlockmem(p);
8001*7c478bd9Sstevel@tonic-gate 		kmem_free(p, sizeof (struct ddi_umem_cookie));
8002*7c478bd9Sstevel@tonic-gate 		*cookie = (ddi_umem_cookie_t)NULL;
8003*7c478bd9Sstevel@tonic-gate 		return (error);
8004*7c478bd9Sstevel@tonic-gate 	}
8005*7c478bd9Sstevel@tonic-gate 
8006*7c478bd9Sstevel@tonic-gate 	/*
8007*7c478bd9Sstevel@tonic-gate 	 * For longterm locking the addr must pertain to a seg_vn segment or
8008*7c478bd9Sstevel@tonic-gate 	 * or a seg_spt segment.
8009*7c478bd9Sstevel@tonic-gate 	 * If the segment pertains to a regular file, it cannot be
8010*7c478bd9Sstevel@tonic-gate 	 * mapped MAP_SHARED.
8011*7c478bd9Sstevel@tonic-gate 	 * This is to prevent a deadlock if a file truncation is attempted
8012*7c478bd9Sstevel@tonic-gate 	 * after the locking is done.
8013*7c478bd9Sstevel@tonic-gate 	 * Doing this after as_pagelock guarantees persistence of the as; if
8014*7c478bd9Sstevel@tonic-gate 	 * an unacceptable segment is found, the cleanup includes calling
8015*7c478bd9Sstevel@tonic-gate 	 * as_pageunlock before returning EFAULT.
8016*7c478bd9Sstevel@tonic-gate 	 */
8017*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_UMEMLOCK_LONGTERM) {
8018*7c478bd9Sstevel@tonic-gate 		extern  struct seg_ops segspt_shmops;
8019*7c478bd9Sstevel@tonic-gate 		AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
8020*7c478bd9Sstevel@tonic-gate 		for (seg = as_segat(as, addr); ; seg = AS_SEGNEXT(as, seg)) {
8021*7c478bd9Sstevel@tonic-gate 			if (seg == NULL || seg->s_base > addr + len)
8022*7c478bd9Sstevel@tonic-gate 				break;
8023*7c478bd9Sstevel@tonic-gate 			if (((seg->s_ops != &segvn_ops) &&
8024*7c478bd9Sstevel@tonic-gate 			    (seg->s_ops != &segspt_shmops)) ||
8025*7c478bd9Sstevel@tonic-gate 			    ((SEGOP_GETVP(seg, addr, &vp) == 0 &&
8026*7c478bd9Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG) &&
8027*7c478bd9Sstevel@tonic-gate 			    (SEGOP_GETTYPE(seg, addr) & MAP_SHARED))) {
8028*7c478bd9Sstevel@tonic-gate 				as_pageunlock(as, p->pparray,
8029*7c478bd9Sstevel@tonic-gate 						addr, len, p->s_flags);
8030*7c478bd9Sstevel@tonic-gate 				AS_LOCK_EXIT(as, &as->a_lock);
8031*7c478bd9Sstevel@tonic-gate 				umem_decr_devlockmem(p);
8032*7c478bd9Sstevel@tonic-gate 				kmem_free(p, sizeof (struct ddi_umem_cookie));
8033*7c478bd9Sstevel@tonic-gate 				*cookie = (ddi_umem_cookie_t)NULL;
8034*7c478bd9Sstevel@tonic-gate 				return (EFAULT);
8035*7c478bd9Sstevel@tonic-gate 			}
8036*7c478bd9Sstevel@tonic-gate 		}
8037*7c478bd9Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
8038*7c478bd9Sstevel@tonic-gate 	}
8039*7c478bd9Sstevel@tonic-gate 
8040*7c478bd9Sstevel@tonic-gate 
8041*7c478bd9Sstevel@tonic-gate 	/* Initialize the fields in the ddi_umem_cookie */
8042*7c478bd9Sstevel@tonic-gate 	p->cvaddr = addr;
8043*7c478bd9Sstevel@tonic-gate 	p->type = UMEM_LOCKED;
8044*7c478bd9Sstevel@tonic-gate 	if (driver_callback != NULL) {
8045*7c478bd9Sstevel@tonic-gate 		/* i_ddi_umem_unlock and umem_lock_undo may need the cookie */
8046*7c478bd9Sstevel@tonic-gate 		p->cook_refcnt = 2;
8047*7c478bd9Sstevel@tonic-gate 		p->callbacks = *ops_vector;
8048*7c478bd9Sstevel@tonic-gate 	} else {
8049*7c478bd9Sstevel@tonic-gate 		/* only i_ddi_umme_unlock needs the cookie */
8050*7c478bd9Sstevel@tonic-gate 		p->cook_refcnt = 1;
8051*7c478bd9Sstevel@tonic-gate 	}
8052*7c478bd9Sstevel@tonic-gate 
8053*7c478bd9Sstevel@tonic-gate 	*cookie = (ddi_umem_cookie_t)p;
8054*7c478bd9Sstevel@tonic-gate 
8055*7c478bd9Sstevel@tonic-gate 	/*
8056*7c478bd9Sstevel@tonic-gate 	 * If a driver callback was specified, add an entry to the
8057*7c478bd9Sstevel@tonic-gate 	 * as struct callback list. The as_pagelock above guarantees
8058*7c478bd9Sstevel@tonic-gate 	 * the persistence of as.
8059*7c478bd9Sstevel@tonic-gate 	 */
8060*7c478bd9Sstevel@tonic-gate 	if (driver_callback) {
8061*7c478bd9Sstevel@tonic-gate 		error = as_add_callback(as, umem_lock_undo, p, AS_ALL_EVENT,
8062*7c478bd9Sstevel@tonic-gate 						addr, len, KM_SLEEP);
8063*7c478bd9Sstevel@tonic-gate 		if (error != 0) {
8064*7c478bd9Sstevel@tonic-gate 			as_pageunlock(as, p->pparray,
8065*7c478bd9Sstevel@tonic-gate 					addr, len, p->s_flags);
8066*7c478bd9Sstevel@tonic-gate 			umem_decr_devlockmem(p);
8067*7c478bd9Sstevel@tonic-gate 			kmem_free(p, sizeof (struct ddi_umem_cookie));
8068*7c478bd9Sstevel@tonic-gate 			*cookie = (ddi_umem_cookie_t)NULL;
8069*7c478bd9Sstevel@tonic-gate 		}
8070*7c478bd9Sstevel@tonic-gate 	}
8071*7c478bd9Sstevel@tonic-gate 	return (error);
8072*7c478bd9Sstevel@tonic-gate }
8073*7c478bd9Sstevel@tonic-gate 
8074*7c478bd9Sstevel@tonic-gate /*
8075*7c478bd9Sstevel@tonic-gate  * Unlock the pages locked by ddi_umem_lock or umem_lockmemory and free
8076*7c478bd9Sstevel@tonic-gate  * the cookie.  Called from i_ddi_umem_unlock_thread.
8077*7c478bd9Sstevel@tonic-gate  */
8078*7c478bd9Sstevel@tonic-gate 
8079*7c478bd9Sstevel@tonic-gate static void
8080*7c478bd9Sstevel@tonic-gate i_ddi_umem_unlock(struct ddi_umem_cookie *p)
8081*7c478bd9Sstevel@tonic-gate {
8082*7c478bd9Sstevel@tonic-gate 	uint_t	rc;
8083*7c478bd9Sstevel@tonic-gate 
8084*7c478bd9Sstevel@tonic-gate 	/*
8085*7c478bd9Sstevel@tonic-gate 	 * There is no way to determine whether a callback to
8086*7c478bd9Sstevel@tonic-gate 	 * umem_lock_undo was registered via as_add_callback.
8087*7c478bd9Sstevel@tonic-gate 	 * (i.e. umem_lockmemory was called with DDI_MEMLOCK_LONGTERM and
8088*7c478bd9Sstevel@tonic-gate 	 * a valid callback function structure.)  as_delete_callback
8089*7c478bd9Sstevel@tonic-gate 	 * is called to delete a possible registered callback.  If the
8090*7c478bd9Sstevel@tonic-gate 	 * return from as_delete_callbacks is AS_CALLBACK_DELETED, it
8091*7c478bd9Sstevel@tonic-gate 	 * indicates that there was a callback registered, and that is was
8092*7c478bd9Sstevel@tonic-gate 	 * successfully deleted.  Thus, the cookie reference count
8093*7c478bd9Sstevel@tonic-gate 	 * will never be decremented by umem_lock_undo.  Just return the
8094*7c478bd9Sstevel@tonic-gate 	 * memory for the cookie, since both users of the cookie are done.
8095*7c478bd9Sstevel@tonic-gate 	 * A return of AS_CALLBACK_NOTFOUND indicates a callback was
8096*7c478bd9Sstevel@tonic-gate 	 * never registered.  A return of AS_CALLBACK_DELETE_DEFERRED
8097*7c478bd9Sstevel@tonic-gate 	 * indicates that callback processing is taking place and, and
8098*7c478bd9Sstevel@tonic-gate 	 * umem_lock_undo is, or will be, executing, and thus decrementing
8099*7c478bd9Sstevel@tonic-gate 	 * the cookie reference count when it is complete.
8100*7c478bd9Sstevel@tonic-gate 	 *
8101*7c478bd9Sstevel@tonic-gate 	 * This needs to be done before as_pageunlock so that the
8102*7c478bd9Sstevel@tonic-gate 	 * persistence of as is guaranteed because of the locked pages.
8103*7c478bd9Sstevel@tonic-gate 	 *
8104*7c478bd9Sstevel@tonic-gate 	 */
8105*7c478bd9Sstevel@tonic-gate 	rc = as_delete_callback(p->asp, p);
8106*7c478bd9Sstevel@tonic-gate 
8107*7c478bd9Sstevel@tonic-gate 
8108*7c478bd9Sstevel@tonic-gate 	/*
8109*7c478bd9Sstevel@tonic-gate 	 * The proc->p_as will be stale if i_ddi_umem_unlock is called
8110*7c478bd9Sstevel@tonic-gate 	 * after relvm is called so use p->asp.
8111*7c478bd9Sstevel@tonic-gate 	 */
8112*7c478bd9Sstevel@tonic-gate 	as_pageunlock(p->asp, p->pparray, p->cvaddr, p->size, p->s_flags);
8113*7c478bd9Sstevel@tonic-gate 
8114*7c478bd9Sstevel@tonic-gate 	/*
8115*7c478bd9Sstevel@tonic-gate 	 * Now that we have unlocked the memory decrement the
8116*7c478bd9Sstevel@tonic-gate 	 * max-device-locked-memory rctl
8117*7c478bd9Sstevel@tonic-gate 	 */
8118*7c478bd9Sstevel@tonic-gate 	umem_decr_devlockmem(p);
8119*7c478bd9Sstevel@tonic-gate 
8120*7c478bd9Sstevel@tonic-gate 	if (rc == AS_CALLBACK_DELETED) {
8121*7c478bd9Sstevel@tonic-gate 		/* umem_lock_undo will not happen, return the cookie memory */
8122*7c478bd9Sstevel@tonic-gate 		ASSERT(p->cook_refcnt == 2);
8123*7c478bd9Sstevel@tonic-gate 		kmem_free(p, sizeof (struct ddi_umem_cookie));
8124*7c478bd9Sstevel@tonic-gate 	} else {
8125*7c478bd9Sstevel@tonic-gate 		/*
8126*7c478bd9Sstevel@tonic-gate 		 * umem_undo_lock may happen if as_delete_callback returned
8127*7c478bd9Sstevel@tonic-gate 		 * AS_CALLBACK_DELETE_DEFERRED.  In that case, decrement the
8128*7c478bd9Sstevel@tonic-gate 		 * reference count, atomically, and return the cookie
8129*7c478bd9Sstevel@tonic-gate 		 * memory if the reference count goes to zero.  The only
8130*7c478bd9Sstevel@tonic-gate 		 * other value for rc is AS_CALLBACK_NOTFOUND.  In that
8131*7c478bd9Sstevel@tonic-gate 		 * case, just return the cookie memory.
8132*7c478bd9Sstevel@tonic-gate 		 */
8133*7c478bd9Sstevel@tonic-gate 		if ((rc != AS_CALLBACK_DELETE_DEFERRED) ||
8134*7c478bd9Sstevel@tonic-gate 		    (atomic_add_long_nv((ulong_t *)(&(p->cook_refcnt)), -1)
8135*7c478bd9Sstevel@tonic-gate 		    == 0)) {
8136*7c478bd9Sstevel@tonic-gate 			kmem_free(p, sizeof (struct ddi_umem_cookie));
8137*7c478bd9Sstevel@tonic-gate 		}
8138*7c478bd9Sstevel@tonic-gate 	}
8139*7c478bd9Sstevel@tonic-gate }
8140*7c478bd9Sstevel@tonic-gate 
8141*7c478bd9Sstevel@tonic-gate /*
8142*7c478bd9Sstevel@tonic-gate  * i_ddi_umem_unlock_thread - deferred ddi_umem_unlock list handler.
8143*7c478bd9Sstevel@tonic-gate  *
8144*7c478bd9Sstevel@tonic-gate  * Call i_ddi_umem_unlock for entries in the ddi_umem_unlock list
8145*7c478bd9Sstevel@tonic-gate  * until it is empty.  Then, wait for more to be added.  This thread is awoken
8146*7c478bd9Sstevel@tonic-gate  * via calls to ddi_umem_unlock.
8147*7c478bd9Sstevel@tonic-gate  */
8148*7c478bd9Sstevel@tonic-gate 
8149*7c478bd9Sstevel@tonic-gate static void
8150*7c478bd9Sstevel@tonic-gate i_ddi_umem_unlock_thread(void)
8151*7c478bd9Sstevel@tonic-gate {
8152*7c478bd9Sstevel@tonic-gate 	struct ddi_umem_cookie	*ret_cookie;
8153*7c478bd9Sstevel@tonic-gate 	callb_cpr_t	cprinfo;
8154*7c478bd9Sstevel@tonic-gate 
8155*7c478bd9Sstevel@tonic-gate 	/* process the ddi_umem_unlock list */
8156*7c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &ddi_umem_unlock_mutex,
8157*7c478bd9Sstevel@tonic-gate 	    callb_generic_cpr, "unlock_thread");
8158*7c478bd9Sstevel@tonic-gate 	for (;;) {
8159*7c478bd9Sstevel@tonic-gate 		mutex_enter(&ddi_umem_unlock_mutex);
8160*7c478bd9Sstevel@tonic-gate 		if (ddi_umem_unlock_head != NULL) {	/* list not empty */
8161*7c478bd9Sstevel@tonic-gate 			ret_cookie = ddi_umem_unlock_head;
8162*7c478bd9Sstevel@tonic-gate 			/* take if off the list */
8163*7c478bd9Sstevel@tonic-gate 			if ((ddi_umem_unlock_head =
8164*7c478bd9Sstevel@tonic-gate 			    ddi_umem_unlock_head->unl_forw) == NULL) {
8165*7c478bd9Sstevel@tonic-gate 				ddi_umem_unlock_tail = NULL;
8166*7c478bd9Sstevel@tonic-gate 			}
8167*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ddi_umem_unlock_mutex);
8168*7c478bd9Sstevel@tonic-gate 			/* unlock the pages in this cookie */
8169*7c478bd9Sstevel@tonic-gate 			(void) i_ddi_umem_unlock(ret_cookie);
8170*7c478bd9Sstevel@tonic-gate 		} else {   /* list is empty, wait for next ddi_umem_unlock */
8171*7c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
8172*7c478bd9Sstevel@tonic-gate 			cv_wait(&ddi_umem_unlock_cv, &ddi_umem_unlock_mutex);
8173*7c478bd9Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(&cprinfo, &ddi_umem_unlock_mutex);
8174*7c478bd9Sstevel@tonic-gate 			mutex_exit(&ddi_umem_unlock_mutex);
8175*7c478bd9Sstevel@tonic-gate 		}
8176*7c478bd9Sstevel@tonic-gate 	}
8177*7c478bd9Sstevel@tonic-gate 	/* ddi_umem_unlock_thread does not exit */
8178*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
8179*7c478bd9Sstevel@tonic-gate }
8180*7c478bd9Sstevel@tonic-gate 
8181*7c478bd9Sstevel@tonic-gate /*
8182*7c478bd9Sstevel@tonic-gate  * Start the thread that will process the ddi_umem_unlock list if it is
8183*7c478bd9Sstevel@tonic-gate  * not already started (i_ddi_umem_unlock_thread).
8184*7c478bd9Sstevel@tonic-gate  */
8185*7c478bd9Sstevel@tonic-gate static void
8186*7c478bd9Sstevel@tonic-gate i_ddi_umem_unlock_thread_start(void)
8187*7c478bd9Sstevel@tonic-gate {
8188*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ddi_umem_unlock_mutex);
8189*7c478bd9Sstevel@tonic-gate 	if (ddi_umem_unlock_thread == NULL) {
8190*7c478bd9Sstevel@tonic-gate 		ddi_umem_unlock_thread = thread_create(NULL, 0,
8191*7c478bd9Sstevel@tonic-gate 		    i_ddi_umem_unlock_thread, NULL, 0, &p0,
8192*7c478bd9Sstevel@tonic-gate 		    TS_RUN, minclsyspri);
8193*7c478bd9Sstevel@tonic-gate 	}
8194*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ddi_umem_unlock_mutex);
8195*7c478bd9Sstevel@tonic-gate }
8196*7c478bd9Sstevel@tonic-gate 
8197*7c478bd9Sstevel@tonic-gate /*
8198*7c478bd9Sstevel@tonic-gate  * Lock the virtual address range in the current process and create a
8199*7c478bd9Sstevel@tonic-gate  * ddi_umem_cookie (of type UMEM_LOCKED). This can be used to pass to
8200*7c478bd9Sstevel@tonic-gate  * ddi_umem_iosetup to create a buf or do devmap_umem_setup/remap to export
8201*7c478bd9Sstevel@tonic-gate  * to user space.
8202*7c478bd9Sstevel@tonic-gate  *
8203*7c478bd9Sstevel@tonic-gate  * Note: The resource control accounting currently uses a full charge model
8204*7c478bd9Sstevel@tonic-gate  * in other words attempts to lock the same/overlapping areas of memory
8205*7c478bd9Sstevel@tonic-gate  * will deduct the full size of the buffer from the projects running
8206*7c478bd9Sstevel@tonic-gate  * counter for the device locked memory. This applies to umem_lockmemory too.
8207*7c478bd9Sstevel@tonic-gate  *
8208*7c478bd9Sstevel@tonic-gate  * addr, size should be PAGESIZE aligned
8209*7c478bd9Sstevel@tonic-gate  * flags - DDI_UMEMLOCK_READ, DDI_UMEMLOCK_WRITE or both
8210*7c478bd9Sstevel@tonic-gate  *	identifies whether the locked memory will be read or written or both
8211*7c478bd9Sstevel@tonic-gate  *
8212*7c478bd9Sstevel@tonic-gate  * Returns 0 on success
8213*7c478bd9Sstevel@tonic-gate  *	EINVAL - for invalid parameters
8214*7c478bd9Sstevel@tonic-gate  *	EPERM, ENOMEM and other error codes returned by as_pagelock
8215*7c478bd9Sstevel@tonic-gate  *	ENOMEM - is returned if the current request to lock memory exceeds
8216*7c478bd9Sstevel@tonic-gate  *		project.max-device-locked-memory resource control value.
8217*7c478bd9Sstevel@tonic-gate  *	EAGAIN - could not start the ddi_umem_unlock list processing thread
8218*7c478bd9Sstevel@tonic-gate  */
8219*7c478bd9Sstevel@tonic-gate int
8220*7c478bd9Sstevel@tonic-gate ddi_umem_lock(caddr_t addr, size_t len, int flags, ddi_umem_cookie_t *cookie)
8221*7c478bd9Sstevel@tonic-gate {
8222*7c478bd9Sstevel@tonic-gate 	int	error;
8223*7c478bd9Sstevel@tonic-gate 	struct ddi_umem_cookie *p;
8224*7c478bd9Sstevel@tonic-gate 
8225*7c478bd9Sstevel@tonic-gate 	*cookie = NULL;		/* in case of any error return */
8226*7c478bd9Sstevel@tonic-gate 
8227*7c478bd9Sstevel@tonic-gate 	/* These are the only two valid flags */
8228*7c478bd9Sstevel@tonic-gate 	if ((flags & ~(DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE)) != 0) {
8229*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
8230*7c478bd9Sstevel@tonic-gate 	}
8231*7c478bd9Sstevel@tonic-gate 
8232*7c478bd9Sstevel@tonic-gate 	/* At least one of the two flags (or both) must be set */
8233*7c478bd9Sstevel@tonic-gate 	if ((flags & (DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE)) == 0) {
8234*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
8235*7c478bd9Sstevel@tonic-gate 	}
8236*7c478bd9Sstevel@tonic-gate 
8237*7c478bd9Sstevel@tonic-gate 	/* addr and len must be page-aligned */
8238*7c478bd9Sstevel@tonic-gate 	if (((uintptr_t)addr & PAGEOFFSET) != 0) {
8239*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
8240*7c478bd9Sstevel@tonic-gate 	}
8241*7c478bd9Sstevel@tonic-gate 
8242*7c478bd9Sstevel@tonic-gate 	if ((len & PAGEOFFSET) != 0) {
8243*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
8244*7c478bd9Sstevel@tonic-gate 	}
8245*7c478bd9Sstevel@tonic-gate 
8246*7c478bd9Sstevel@tonic-gate 	/*
8247*7c478bd9Sstevel@tonic-gate 	 * Call i_ddi_umem_unlock_thread_start if necessary.  It will
8248*7c478bd9Sstevel@tonic-gate 	 * be called on first ddi_umem_lock or umem_lockmemory call.
8249*7c478bd9Sstevel@tonic-gate 	 */
8250*7c478bd9Sstevel@tonic-gate 	if (ddi_umem_unlock_thread == NULL)
8251*7c478bd9Sstevel@tonic-gate 		i_ddi_umem_unlock_thread_start();
8252*7c478bd9Sstevel@tonic-gate 
8253*7c478bd9Sstevel@tonic-gate 	/* Allocate memory for the cookie */
8254*7c478bd9Sstevel@tonic-gate 	p = kmem_zalloc(sizeof (struct ddi_umem_cookie), KM_SLEEP);
8255*7c478bd9Sstevel@tonic-gate 
8256*7c478bd9Sstevel@tonic-gate 	/* Convert the flags to seg_rw type */
8257*7c478bd9Sstevel@tonic-gate 	if (flags & DDI_UMEMLOCK_WRITE) {
8258*7c478bd9Sstevel@tonic-gate 		p->s_flags = S_WRITE;
8259*7c478bd9Sstevel@tonic-gate 	} else {
8260*7c478bd9Sstevel@tonic-gate 		p->s_flags = S_READ;
8261*7c478bd9Sstevel@tonic-gate 	}
8262*7c478bd9Sstevel@tonic-gate 
8263*7c478bd9Sstevel@tonic-gate 	/* Store curproc in cookie for later iosetup/unlock */
8264*7c478bd9Sstevel@tonic-gate 	p->procp = (void *)curproc;
8265*7c478bd9Sstevel@tonic-gate 
8266*7c478bd9Sstevel@tonic-gate 	/*
8267*7c478bd9Sstevel@tonic-gate 	 * Store the struct as pointer in cookie for later use by
8268*7c478bd9Sstevel@tonic-gate 	 * ddi_umem_unlock.  The proc->p_as will be stale if ddi_umem_unlock
8269*7c478bd9Sstevel@tonic-gate 	 * is called after relvm is called.
8270*7c478bd9Sstevel@tonic-gate 	 */
8271*7c478bd9Sstevel@tonic-gate 	p->asp = curproc->p_as;
8272*7c478bd9Sstevel@tonic-gate 	/*
8273*7c478bd9Sstevel@tonic-gate 	 * The size field is needed for lockmem accounting.
8274*7c478bd9Sstevel@tonic-gate 	 */
8275*7c478bd9Sstevel@tonic-gate 	p->size = len;
8276*7c478bd9Sstevel@tonic-gate 
8277*7c478bd9Sstevel@tonic-gate 	if (umem_incr_devlockmem(p) != 0) {
8278*7c478bd9Sstevel@tonic-gate 		/*
8279*7c478bd9Sstevel@tonic-gate 		 * The requested memory cannot be locked
8280*7c478bd9Sstevel@tonic-gate 		 */
8281*7c478bd9Sstevel@tonic-gate 		kmem_free(p, sizeof (struct ddi_umem_cookie));
8282*7c478bd9Sstevel@tonic-gate 		*cookie = (ddi_umem_cookie_t)NULL;
8283*7c478bd9Sstevel@tonic-gate 		return (ENOMEM);
8284*7c478bd9Sstevel@tonic-gate 	}
8285*7c478bd9Sstevel@tonic-gate 	/*
8286*7c478bd9Sstevel@tonic-gate 	 * umem_incr_devlockmem stashes the project ptr into the
8287*7c478bd9Sstevel@tonic-gate 	 * cookie. This is needed during unlock since that can
8288*7c478bd9Sstevel@tonic-gate 	 * happen in a non-USER context
8289*7c478bd9Sstevel@tonic-gate 	 */
8290*7c478bd9Sstevel@tonic-gate 	ASSERT(p->lockmem_proj);
8291*7c478bd9Sstevel@tonic-gate 
8292*7c478bd9Sstevel@tonic-gate 	/* Lock the pages corresponding to addr, len in memory */
8293*7c478bd9Sstevel@tonic-gate 	error = as_pagelock(((proc_t *)p->procp)->p_as, &(p->pparray),
8294*7c478bd9Sstevel@tonic-gate 	    addr, len, p->s_flags);
8295*7c478bd9Sstevel@tonic-gate 	if (error != 0) {
8296*7c478bd9Sstevel@tonic-gate 		umem_decr_devlockmem(p);
8297*7c478bd9Sstevel@tonic-gate 		kmem_free(p, sizeof (struct ddi_umem_cookie));
8298*7c478bd9Sstevel@tonic-gate 		*cookie = (ddi_umem_cookie_t)NULL;
8299*7c478bd9Sstevel@tonic-gate 		return (error);
8300*7c478bd9Sstevel@tonic-gate 	}
8301*7c478bd9Sstevel@tonic-gate 
8302*7c478bd9Sstevel@tonic-gate 	/* Initialize the fields in the ddi_umem_cookie */
8303*7c478bd9Sstevel@tonic-gate 	p->cvaddr = addr;
8304*7c478bd9Sstevel@tonic-gate 	p->type = UMEM_LOCKED;
8305*7c478bd9Sstevel@tonic-gate 	p->cook_refcnt = 1;
8306*7c478bd9Sstevel@tonic-gate 
8307*7c478bd9Sstevel@tonic-gate 	*cookie = (ddi_umem_cookie_t)p;
8308*7c478bd9Sstevel@tonic-gate 	return (error);
8309*7c478bd9Sstevel@tonic-gate }
8310*7c478bd9Sstevel@tonic-gate 
8311*7c478bd9Sstevel@tonic-gate /*
8312*7c478bd9Sstevel@tonic-gate  * Add the cookie to the ddi_umem_unlock list.  Pages will be
8313*7c478bd9Sstevel@tonic-gate  * unlocked by i_ddi_umem_unlock_thread.
8314*7c478bd9Sstevel@tonic-gate  */
8315*7c478bd9Sstevel@tonic-gate 
8316*7c478bd9Sstevel@tonic-gate void
8317*7c478bd9Sstevel@tonic-gate ddi_umem_unlock(ddi_umem_cookie_t cookie)
8318*7c478bd9Sstevel@tonic-gate {
8319*7c478bd9Sstevel@tonic-gate 	struct ddi_umem_cookie	*p = (struct ddi_umem_cookie *)cookie;
8320*7c478bd9Sstevel@tonic-gate 
8321*7c478bd9Sstevel@tonic-gate 	ASSERT(p->type == UMEM_LOCKED);
8322*7c478bd9Sstevel@tonic-gate 	ASSERT(CPU_ON_INTR(CPU) == 0); /* cannot be high level */
8323*7c478bd9Sstevel@tonic-gate 	ASSERT(ddi_umem_unlock_thread != NULL);
8324*7c478bd9Sstevel@tonic-gate 
8325*7c478bd9Sstevel@tonic-gate 	p->unl_forw = (struct ddi_umem_cookie *)NULL;	/* end of list */
8326*7c478bd9Sstevel@tonic-gate 	mutex_enter(&ddi_umem_unlock_mutex);
8327*7c478bd9Sstevel@tonic-gate 	if (ddi_umem_unlock_head == NULL) {
8328*7c478bd9Sstevel@tonic-gate 		ddi_umem_unlock_head = ddi_umem_unlock_tail = p;
8329*7c478bd9Sstevel@tonic-gate 		cv_broadcast(&ddi_umem_unlock_cv);
8330*7c478bd9Sstevel@tonic-gate 	} else {
8331*7c478bd9Sstevel@tonic-gate 		ddi_umem_unlock_tail->unl_forw = p;
8332*7c478bd9Sstevel@tonic-gate 		ddi_umem_unlock_tail = p;
8333*7c478bd9Sstevel@tonic-gate 	}
8334*7c478bd9Sstevel@tonic-gate 	mutex_exit(&ddi_umem_unlock_mutex);
8335*7c478bd9Sstevel@tonic-gate }
8336*7c478bd9Sstevel@tonic-gate 
8337*7c478bd9Sstevel@tonic-gate /*
8338*7c478bd9Sstevel@tonic-gate  * Create a buf structure from a ddi_umem_cookie
8339*7c478bd9Sstevel@tonic-gate  * cookie - is a ddi_umem_cookie for from ddi_umem_lock and ddi_umem_alloc
8340*7c478bd9Sstevel@tonic-gate  *		(only UMEM_LOCKED & KMEM_NON_PAGEABLE types supported)
8341*7c478bd9Sstevel@tonic-gate  * off, len - identifies the portion of the memory represented by the cookie
8342*7c478bd9Sstevel@tonic-gate  *		that the buf points to.
8343*7c478bd9Sstevel@tonic-gate  *	NOTE: off, len need to follow the alignment/size restrictions of the
8344*7c478bd9Sstevel@tonic-gate  *		device (dev) that this buf will be passed to. Some devices
8345*7c478bd9Sstevel@tonic-gate  *		will accept unrestricted alignment/size, whereas others (such as
8346*7c478bd9Sstevel@tonic-gate  *		st) require some block-size alignment/size. It is the caller's
8347*7c478bd9Sstevel@tonic-gate  *		responsibility to ensure that the alignment/size restrictions
8348*7c478bd9Sstevel@tonic-gate  *		are met (we cannot assert as we do not know the restrictions)
8349*7c478bd9Sstevel@tonic-gate  *
8350*7c478bd9Sstevel@tonic-gate  * direction - is one of B_READ or B_WRITE and needs to be compatible with
8351*7c478bd9Sstevel@tonic-gate  *		the flags used in ddi_umem_lock
8352*7c478bd9Sstevel@tonic-gate  *
8353*7c478bd9Sstevel@tonic-gate  * The following three arguments are used to initialize fields in the
8354*7c478bd9Sstevel@tonic-gate  * buf structure and are uninterpreted by this routine.
8355*7c478bd9Sstevel@tonic-gate  *
8356*7c478bd9Sstevel@tonic-gate  * dev
8357*7c478bd9Sstevel@tonic-gate  * blkno
8358*7c478bd9Sstevel@tonic-gate  * iodone
8359*7c478bd9Sstevel@tonic-gate  *
8360*7c478bd9Sstevel@tonic-gate  * sleepflag - is one of DDI_UMEM_SLEEP or DDI_UMEM_NOSLEEP
8361*7c478bd9Sstevel@tonic-gate  *
8362*7c478bd9Sstevel@tonic-gate  * Returns a buf structure pointer on success (to be freed by freerbuf)
8363*7c478bd9Sstevel@tonic-gate  *	NULL on any parameter error or memory alloc failure
8364*7c478bd9Sstevel@tonic-gate  *
8365*7c478bd9Sstevel@tonic-gate  */
8366*7c478bd9Sstevel@tonic-gate struct buf *
8367*7c478bd9Sstevel@tonic-gate ddi_umem_iosetup(ddi_umem_cookie_t cookie, off_t off, size_t len,
8368*7c478bd9Sstevel@tonic-gate 	int direction, dev_t dev, daddr_t blkno,
8369*7c478bd9Sstevel@tonic-gate 	int (*iodone)(struct buf *), int sleepflag)
8370*7c478bd9Sstevel@tonic-gate {
8371*7c478bd9Sstevel@tonic-gate 	struct ddi_umem_cookie *p = (struct ddi_umem_cookie *)cookie;
8372*7c478bd9Sstevel@tonic-gate 	struct buf *bp;
8373*7c478bd9Sstevel@tonic-gate 
8374*7c478bd9Sstevel@tonic-gate 	/*
8375*7c478bd9Sstevel@tonic-gate 	 * check for valid cookie offset, len
8376*7c478bd9Sstevel@tonic-gate 	 */
8377*7c478bd9Sstevel@tonic-gate 	if ((off + len) > p->size) {
8378*7c478bd9Sstevel@tonic-gate 		return (NULL);
8379*7c478bd9Sstevel@tonic-gate 	}
8380*7c478bd9Sstevel@tonic-gate 
8381*7c478bd9Sstevel@tonic-gate 	if (len > p->size) {
8382*7c478bd9Sstevel@tonic-gate 		return (NULL);
8383*7c478bd9Sstevel@tonic-gate 	}
8384*7c478bd9Sstevel@tonic-gate 
8385*7c478bd9Sstevel@tonic-gate 	/* direction has to be one of B_READ or B_WRITE */
8386*7c478bd9Sstevel@tonic-gate 	if ((direction != B_READ) && (direction != B_WRITE)) {
8387*7c478bd9Sstevel@tonic-gate 		return (NULL);
8388*7c478bd9Sstevel@tonic-gate 	}
8389*7c478bd9Sstevel@tonic-gate 
8390*7c478bd9Sstevel@tonic-gate 	/* These are the only two valid sleepflags */
8391*7c478bd9Sstevel@tonic-gate 	if ((sleepflag != DDI_UMEM_SLEEP) && (sleepflag != DDI_UMEM_NOSLEEP)) {
8392*7c478bd9Sstevel@tonic-gate 		return (NULL);
8393*7c478bd9Sstevel@tonic-gate 	}
8394*7c478bd9Sstevel@tonic-gate 
8395*7c478bd9Sstevel@tonic-gate 	/*
8396*7c478bd9Sstevel@tonic-gate 	 * Only cookies of type UMEM_LOCKED and KMEM_NON_PAGEABLE are supported
8397*7c478bd9Sstevel@tonic-gate 	 */
8398*7c478bd9Sstevel@tonic-gate 	if ((p->type != UMEM_LOCKED) && (p->type != KMEM_NON_PAGEABLE)) {
8399*7c478bd9Sstevel@tonic-gate 		return (NULL);
8400*7c478bd9Sstevel@tonic-gate 	}
8401*7c478bd9Sstevel@tonic-gate 
8402*7c478bd9Sstevel@tonic-gate 	/* If type is KMEM_NON_PAGEABLE procp is NULL */
8403*7c478bd9Sstevel@tonic-gate 	ASSERT((p->type == KMEM_NON_PAGEABLE) ?
8404*7c478bd9Sstevel@tonic-gate 		(p->procp == NULL) : (p->procp != NULL));
8405*7c478bd9Sstevel@tonic-gate 
8406*7c478bd9Sstevel@tonic-gate 	bp = kmem_alloc(sizeof (struct buf), sleepflag);
8407*7c478bd9Sstevel@tonic-gate 	if (bp == NULL) {
8408*7c478bd9Sstevel@tonic-gate 		return (NULL);
8409*7c478bd9Sstevel@tonic-gate 	}
8410*7c478bd9Sstevel@tonic-gate 	bioinit(bp);
8411*7c478bd9Sstevel@tonic-gate 
8412*7c478bd9Sstevel@tonic-gate 	bp->b_flags = B_BUSY | B_PHYS | direction;
8413*7c478bd9Sstevel@tonic-gate 	bp->b_edev = dev;
8414*7c478bd9Sstevel@tonic-gate 	bp->b_lblkno = blkno;
8415*7c478bd9Sstevel@tonic-gate 	bp->b_iodone = iodone;
8416*7c478bd9Sstevel@tonic-gate 	bp->b_bcount = len;
8417*7c478bd9Sstevel@tonic-gate 	bp->b_proc = (proc_t *)p->procp;
8418*7c478bd9Sstevel@tonic-gate 	ASSERT(((uintptr_t)(p->cvaddr) & PAGEOFFSET) == 0);
8419*7c478bd9Sstevel@tonic-gate 	bp->b_un.b_addr = (caddr_t)((uintptr_t)(p->cvaddr) + off);
8420*7c478bd9Sstevel@tonic-gate 	if (p->pparray != NULL) {
8421*7c478bd9Sstevel@tonic-gate 		bp->b_flags |= B_SHADOW;
8422*7c478bd9Sstevel@tonic-gate 		ASSERT(((uintptr_t)(p->cvaddr) & PAGEOFFSET) == 0);
8423*7c478bd9Sstevel@tonic-gate 		bp->b_shadow = p->pparray + btop(off);
8424*7c478bd9Sstevel@tonic-gate 	}
8425*7c478bd9Sstevel@tonic-gate 	return (bp);
8426*7c478bd9Sstevel@tonic-gate }
8427*7c478bd9Sstevel@tonic-gate 
8428*7c478bd9Sstevel@tonic-gate /*
8429*7c478bd9Sstevel@tonic-gate  * Fault-handling and related routines
8430*7c478bd9Sstevel@tonic-gate  */
8431*7c478bd9Sstevel@tonic-gate 
8432*7c478bd9Sstevel@tonic-gate ddi_devstate_t
8433*7c478bd9Sstevel@tonic-gate ddi_get_devstate(dev_info_t *dip)
8434*7c478bd9Sstevel@tonic-gate {
8435*7c478bd9Sstevel@tonic-gate 	if (DEVI_IS_DEVICE_OFFLINE(dip))
8436*7c478bd9Sstevel@tonic-gate 		return (DDI_DEVSTATE_OFFLINE);
8437*7c478bd9Sstevel@tonic-gate 	else if (DEVI_IS_DEVICE_DOWN(dip) || DEVI_IS_BUS_DOWN(dip))
8438*7c478bd9Sstevel@tonic-gate 		return (DDI_DEVSTATE_DOWN);
8439*7c478bd9Sstevel@tonic-gate 	else if (DEVI_IS_BUS_QUIESCED(dip))
8440*7c478bd9Sstevel@tonic-gate 		return (DDI_DEVSTATE_QUIESCED);
8441*7c478bd9Sstevel@tonic-gate 	else if (DEVI_IS_DEVICE_DEGRADED(dip))
8442*7c478bd9Sstevel@tonic-gate 		return (DDI_DEVSTATE_DEGRADED);
8443*7c478bd9Sstevel@tonic-gate 	else
8444*7c478bd9Sstevel@tonic-gate 		return (DDI_DEVSTATE_UP);
8445*7c478bd9Sstevel@tonic-gate }
8446*7c478bd9Sstevel@tonic-gate 
8447*7c478bd9Sstevel@tonic-gate void
8448*7c478bd9Sstevel@tonic-gate ddi_dev_report_fault(dev_info_t *dip, ddi_fault_impact_t impact,
8449*7c478bd9Sstevel@tonic-gate 	ddi_fault_location_t location, const char *message)
8450*7c478bd9Sstevel@tonic-gate {
8451*7c478bd9Sstevel@tonic-gate 	struct ddi_fault_event_data fd;
8452*7c478bd9Sstevel@tonic-gate 	ddi_eventcookie_t ec;
8453*7c478bd9Sstevel@tonic-gate 
8454*7c478bd9Sstevel@tonic-gate 	/*
8455*7c478bd9Sstevel@tonic-gate 	 * Assemble all the information into a fault-event-data structure
8456*7c478bd9Sstevel@tonic-gate 	 */
8457*7c478bd9Sstevel@tonic-gate 	fd.f_dip = dip;
8458*7c478bd9Sstevel@tonic-gate 	fd.f_impact = impact;
8459*7c478bd9Sstevel@tonic-gate 	fd.f_location = location;
8460*7c478bd9Sstevel@tonic-gate 	fd.f_message = message;
8461*7c478bd9Sstevel@tonic-gate 	fd.f_oldstate = ddi_get_devstate(dip);
8462*7c478bd9Sstevel@tonic-gate 
8463*7c478bd9Sstevel@tonic-gate 	/*
8464*7c478bd9Sstevel@tonic-gate 	 * Get eventcookie from defining parent.
8465*7c478bd9Sstevel@tonic-gate 	 */
8466*7c478bd9Sstevel@tonic-gate 	if (ddi_get_eventcookie(dip, DDI_DEVI_FAULT_EVENT, &ec) !=
8467*7c478bd9Sstevel@tonic-gate 	    DDI_SUCCESS)
8468*7c478bd9Sstevel@tonic-gate 		return;
8469*7c478bd9Sstevel@tonic-gate 
8470*7c478bd9Sstevel@tonic-gate 	(void) ndi_post_event(dip, dip, ec, &fd);
8471*7c478bd9Sstevel@tonic-gate }
8472*7c478bd9Sstevel@tonic-gate 
8473*7c478bd9Sstevel@tonic-gate char *
8474*7c478bd9Sstevel@tonic-gate i_ddi_devi_class(dev_info_t *dip)
8475*7c478bd9Sstevel@tonic-gate {
8476*7c478bd9Sstevel@tonic-gate 	return (DEVI(dip)->devi_device_class);
8477*7c478bd9Sstevel@tonic-gate }
8478*7c478bd9Sstevel@tonic-gate 
8479*7c478bd9Sstevel@tonic-gate int
8480*7c478bd9Sstevel@tonic-gate i_ddi_set_devi_class(dev_info_t *dip, char *devi_class, int flag)
8481*7c478bd9Sstevel@tonic-gate {
8482*7c478bd9Sstevel@tonic-gate 	struct dev_info *devi = DEVI(dip);
8483*7c478bd9Sstevel@tonic-gate 
8484*7c478bd9Sstevel@tonic-gate 	mutex_enter(&devi->devi_lock);
8485*7c478bd9Sstevel@tonic-gate 
8486*7c478bd9Sstevel@tonic-gate 	if (devi->devi_device_class)
8487*7c478bd9Sstevel@tonic-gate 		kmem_free(devi->devi_device_class,
8488*7c478bd9Sstevel@tonic-gate 		    strlen(devi->devi_device_class) + 1);
8489*7c478bd9Sstevel@tonic-gate 
8490*7c478bd9Sstevel@tonic-gate 	if ((devi->devi_device_class = i_ddi_strdup(devi_class, flag))
8491*7c478bd9Sstevel@tonic-gate 	    != NULL) {
8492*7c478bd9Sstevel@tonic-gate 		mutex_exit(&devi->devi_lock);
8493*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
8494*7c478bd9Sstevel@tonic-gate 	}
8495*7c478bd9Sstevel@tonic-gate 
8496*7c478bd9Sstevel@tonic-gate 	mutex_exit(&devi->devi_lock);
8497*7c478bd9Sstevel@tonic-gate 
8498*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
8499*7c478bd9Sstevel@tonic-gate }
8500*7c478bd9Sstevel@tonic-gate 
8501*7c478bd9Sstevel@tonic-gate 
8502*7c478bd9Sstevel@tonic-gate /*
8503*7c478bd9Sstevel@tonic-gate  * Task Queues DDI interfaces.
8504*7c478bd9Sstevel@tonic-gate  */
8505*7c478bd9Sstevel@tonic-gate 
8506*7c478bd9Sstevel@tonic-gate /* ARGSUSED */
8507*7c478bd9Sstevel@tonic-gate ddi_taskq_t *
8508*7c478bd9Sstevel@tonic-gate ddi_taskq_create(dev_info_t *dip, const char *name, int nthreads,
8509*7c478bd9Sstevel@tonic-gate     pri_t pri, uint_t cflags)
8510*7c478bd9Sstevel@tonic-gate {
8511*7c478bd9Sstevel@tonic-gate 	char full_name[TASKQ_NAMELEN];
8512*7c478bd9Sstevel@tonic-gate 	const char *tq_name;
8513*7c478bd9Sstevel@tonic-gate 	int nodeid = 0;
8514*7c478bd9Sstevel@tonic-gate 
8515*7c478bd9Sstevel@tonic-gate 	if (dip == NULL)
8516*7c478bd9Sstevel@tonic-gate 		tq_name = name;
8517*7c478bd9Sstevel@tonic-gate 	else {
8518*7c478bd9Sstevel@tonic-gate 		nodeid = ddi_get_instance(dip);
8519*7c478bd9Sstevel@tonic-gate 
8520*7c478bd9Sstevel@tonic-gate 		if (name == NULL)
8521*7c478bd9Sstevel@tonic-gate 			name = "tq";
8522*7c478bd9Sstevel@tonic-gate 
8523*7c478bd9Sstevel@tonic-gate 		(void) snprintf(full_name, sizeof (full_name), "%s_%s",
8524*7c478bd9Sstevel@tonic-gate 		    ddi_driver_name(dip), name);
8525*7c478bd9Sstevel@tonic-gate 
8526*7c478bd9Sstevel@tonic-gate 		tq_name = full_name;
8527*7c478bd9Sstevel@tonic-gate 	}
8528*7c478bd9Sstevel@tonic-gate 
8529*7c478bd9Sstevel@tonic-gate 	return ((ddi_taskq_t *)taskq_create_instance(tq_name, nodeid, nthreads,
8530*7c478bd9Sstevel@tonic-gate 		    pri == TASKQ_DEFAULTPRI ? minclsyspri : pri,
8531*7c478bd9Sstevel@tonic-gate 		    nthreads, INT_MAX, TASKQ_PREPOPULATE));
8532*7c478bd9Sstevel@tonic-gate }
8533*7c478bd9Sstevel@tonic-gate 
8534*7c478bd9Sstevel@tonic-gate void
8535*7c478bd9Sstevel@tonic-gate ddi_taskq_destroy(ddi_taskq_t *tq)
8536*7c478bd9Sstevel@tonic-gate {
8537*7c478bd9Sstevel@tonic-gate 	taskq_destroy((taskq_t *)tq);
8538*7c478bd9Sstevel@tonic-gate }
8539*7c478bd9Sstevel@tonic-gate 
8540*7c478bd9Sstevel@tonic-gate int
8541*7c478bd9Sstevel@tonic-gate ddi_taskq_dispatch(ddi_taskq_t *tq, void (* func)(void *),
8542*7c478bd9Sstevel@tonic-gate     void *arg, uint_t dflags)
8543*7c478bd9Sstevel@tonic-gate {
8544*7c478bd9Sstevel@tonic-gate 	taskqid_t id = taskq_dispatch((taskq_t *)tq, func, arg,
8545*7c478bd9Sstevel@tonic-gate 	    dflags == DDI_SLEEP ? TQ_SLEEP : TQ_NOSLEEP);
8546*7c478bd9Sstevel@tonic-gate 
8547*7c478bd9Sstevel@tonic-gate 	return (id != 0 ? DDI_SUCCESS : DDI_FAILURE);
8548*7c478bd9Sstevel@tonic-gate }
8549*7c478bd9Sstevel@tonic-gate 
8550*7c478bd9Sstevel@tonic-gate void
8551*7c478bd9Sstevel@tonic-gate ddi_taskq_wait(ddi_taskq_t *tq)
8552*7c478bd9Sstevel@tonic-gate {
8553*7c478bd9Sstevel@tonic-gate 	taskq_wait((taskq_t *)tq);
8554*7c478bd9Sstevel@tonic-gate }
8555*7c478bd9Sstevel@tonic-gate 
8556*7c478bd9Sstevel@tonic-gate void
8557*7c478bd9Sstevel@tonic-gate ddi_taskq_suspend(ddi_taskq_t *tq)
8558*7c478bd9Sstevel@tonic-gate {
8559*7c478bd9Sstevel@tonic-gate 	taskq_suspend((taskq_t *)tq);
8560*7c478bd9Sstevel@tonic-gate }
8561*7c478bd9Sstevel@tonic-gate 
8562*7c478bd9Sstevel@tonic-gate boolean_t
8563*7c478bd9Sstevel@tonic-gate ddi_taskq_suspended(ddi_taskq_t *tq)
8564*7c478bd9Sstevel@tonic-gate {
8565*7c478bd9Sstevel@tonic-gate 	return (taskq_suspended((taskq_t *)tq));
8566*7c478bd9Sstevel@tonic-gate }
8567*7c478bd9Sstevel@tonic-gate 
8568*7c478bd9Sstevel@tonic-gate void
8569*7c478bd9Sstevel@tonic-gate ddi_taskq_resume(ddi_taskq_t *tq)
8570*7c478bd9Sstevel@tonic-gate {
8571*7c478bd9Sstevel@tonic-gate 	taskq_resume((taskq_t *)tq);
8572*7c478bd9Sstevel@tonic-gate }
8573*7c478bd9Sstevel@tonic-gate 
8574*7c478bd9Sstevel@tonic-gate int
8575*7c478bd9Sstevel@tonic-gate ddi_parse(
8576*7c478bd9Sstevel@tonic-gate 	const char	*ifname,
8577*7c478bd9Sstevel@tonic-gate 	char		*alnum,
8578*7c478bd9Sstevel@tonic-gate 	uint_t		*nump)
8579*7c478bd9Sstevel@tonic-gate {
8580*7c478bd9Sstevel@tonic-gate 	const char	*p;
8581*7c478bd9Sstevel@tonic-gate 	int		l;
8582*7c478bd9Sstevel@tonic-gate 	ulong_t		num;
8583*7c478bd9Sstevel@tonic-gate 	boolean_t	nonum = B_TRUE;
8584*7c478bd9Sstevel@tonic-gate 	char		c;
8585*7c478bd9Sstevel@tonic-gate 
8586*7c478bd9Sstevel@tonic-gate 	l = strlen(ifname);
8587*7c478bd9Sstevel@tonic-gate 	for (p = ifname + l; p != ifname; l--) {
8588*7c478bd9Sstevel@tonic-gate 		c = *--p;
8589*7c478bd9Sstevel@tonic-gate 		if (!isdigit(c)) {
8590*7c478bd9Sstevel@tonic-gate 			(void) strlcpy(alnum, ifname, l + 1);
8591*7c478bd9Sstevel@tonic-gate 			if (ddi_strtoul(p + 1, NULL, 10, &num) != 0)
8592*7c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
8593*7c478bd9Sstevel@tonic-gate 			break;
8594*7c478bd9Sstevel@tonic-gate 		}
8595*7c478bd9Sstevel@tonic-gate 		nonum = B_FALSE;
8596*7c478bd9Sstevel@tonic-gate 	}
8597*7c478bd9Sstevel@tonic-gate 	if (l == 0 || nonum)
8598*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8599*7c478bd9Sstevel@tonic-gate 
8600*7c478bd9Sstevel@tonic-gate 	*nump = num;
8601*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8602*7c478bd9Sstevel@tonic-gate }
8603