xref: /onnv-gate/usr/src/uts/common/os/sunddi.c (revision 13015:5664b86df7cd)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51106Smrj  * Common Development and Distribution License (the "License").
61106Smrj  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
211106Smrj 
220Sstevel@tonic-gate /*
2312121SReed.Liu@Sun.COM  * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #include <sys/note.h>
270Sstevel@tonic-gate #include <sys/types.h>
280Sstevel@tonic-gate #include <sys/param.h>
290Sstevel@tonic-gate #include <sys/systm.h>
300Sstevel@tonic-gate #include <sys/buf.h>
310Sstevel@tonic-gate #include <sys/uio.h>
320Sstevel@tonic-gate #include <sys/cred.h>
330Sstevel@tonic-gate #include <sys/poll.h>
340Sstevel@tonic-gate #include <sys/mman.h>
350Sstevel@tonic-gate #include <sys/kmem.h>
360Sstevel@tonic-gate #include <sys/model.h>
370Sstevel@tonic-gate #include <sys/file.h>
380Sstevel@tonic-gate #include <sys/proc.h>
390Sstevel@tonic-gate #include <sys/open.h>
400Sstevel@tonic-gate #include <sys/user.h>
410Sstevel@tonic-gate #include <sys/t_lock.h>
420Sstevel@tonic-gate #include <sys/vm.h>
430Sstevel@tonic-gate #include <sys/stat.h>
440Sstevel@tonic-gate #include <vm/hat.h>
450Sstevel@tonic-gate #include <vm/seg.h>
460Sstevel@tonic-gate #include <vm/seg_vn.h>
470Sstevel@tonic-gate #include <vm/seg_dev.h>
480Sstevel@tonic-gate #include <vm/as.h>
490Sstevel@tonic-gate #include <sys/cmn_err.h>
500Sstevel@tonic-gate #include <sys/cpuvar.h>
510Sstevel@tonic-gate #include <sys/debug.h>
520Sstevel@tonic-gate #include <sys/autoconf.h>
530Sstevel@tonic-gate #include <sys/sunddi.h>
540Sstevel@tonic-gate #include <sys/esunddi.h>
550Sstevel@tonic-gate #include <sys/sunndi.h>
560Sstevel@tonic-gate #include <sys/kstat.h>
570Sstevel@tonic-gate #include <sys/conf.h>
580Sstevel@tonic-gate #include <sys/ddi_impldefs.h>	/* include implementation structure defs */
590Sstevel@tonic-gate #include <sys/ndi_impldefs.h>	/* include prototypes */
605107Seota #include <sys/ddi_timer.h>
610Sstevel@tonic-gate #include <sys/hwconf.h>
620Sstevel@tonic-gate #include <sys/pathname.h>
630Sstevel@tonic-gate #include <sys/modctl.h>
640Sstevel@tonic-gate #include <sys/epm.h>
650Sstevel@tonic-gate #include <sys/devctl.h>
660Sstevel@tonic-gate #include <sys/callb.h>
670Sstevel@tonic-gate #include <sys/cladm.h>
680Sstevel@tonic-gate #include <sys/sysevent.h>
690Sstevel@tonic-gate #include <sys/dacf_impl.h>
700Sstevel@tonic-gate #include <sys/ddidevmap.h>
710Sstevel@tonic-gate #include <sys/bootconf.h>
720Sstevel@tonic-gate #include <sys/disp.h>
730Sstevel@tonic-gate #include <sys/atomic.h>
740Sstevel@tonic-gate #include <sys/promif.h>
750Sstevel@tonic-gate #include <sys/instance.h>
760Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
770Sstevel@tonic-gate #include <sys/task.h>
780Sstevel@tonic-gate #include <sys/project.h>
790Sstevel@tonic-gate #include <sys/taskq.h>
800Sstevel@tonic-gate #include <sys/devpolicy.h>
810Sstevel@tonic-gate #include <sys/ctype.h>
820Sstevel@tonic-gate #include <net/if.h>
832768Ssl108498 #include <sys/rctl.h>
848662SJordan.Vaughan@Sun.com #include <sys/zone.h>
8511066Srafael.vanoni@sun.com #include <sys/clock_impl.h>
8610696SDavid.Hollister@Sun.COM #include <sys/ddi.h>
8712004Sjiang.liu@intel.com #include <sys/modhash.h>
8812004Sjiang.liu@intel.com #include <sys/sunldi_impl.h>
8912004Sjiang.liu@intel.com #include <sys/fs/dv_node.h>
9012004Sjiang.liu@intel.com #include <sys/fs/snode.h>
910Sstevel@tonic-gate 
920Sstevel@tonic-gate extern	pri_t	minclsyspri;
930Sstevel@tonic-gate 
942768Ssl108498 extern	rctl_hndl_t rc_project_locked_mem;
952768Ssl108498 extern	rctl_hndl_t rc_zone_locked_mem;
960Sstevel@tonic-gate 
970Sstevel@tonic-gate #ifdef DEBUG
980Sstevel@tonic-gate static int sunddi_debug = 0;
990Sstevel@tonic-gate #endif /* DEBUG */
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate /* ddi_umem_unlock miscellaneous */
1020Sstevel@tonic-gate 
1030Sstevel@tonic-gate static	void	i_ddi_umem_unlock_thread_start(void);
1040Sstevel@tonic-gate 
1050Sstevel@tonic-gate static	kmutex_t	ddi_umem_unlock_mutex; /* unlock list mutex */
1060Sstevel@tonic-gate static	kcondvar_t	ddi_umem_unlock_cv; /* unlock list block/unblock */
1070Sstevel@tonic-gate static	kthread_t	*ddi_umem_unlock_thread;
1080Sstevel@tonic-gate /*
1090Sstevel@tonic-gate  * The ddi_umem_unlock FIFO list.  NULL head pointer indicates empty list.
1100Sstevel@tonic-gate  */
1110Sstevel@tonic-gate static	struct	ddi_umem_cookie *ddi_umem_unlock_head = NULL;
1120Sstevel@tonic-gate static	struct	ddi_umem_cookie *ddi_umem_unlock_tail = NULL;
1130Sstevel@tonic-gate 
1140Sstevel@tonic-gate /*
1150Sstevel@tonic-gate  * DDI(Sun) Function and flag definitions:
1160Sstevel@tonic-gate  */
1170Sstevel@tonic-gate 
1180Sstevel@tonic-gate #if defined(__x86)
1190Sstevel@tonic-gate /*
1200Sstevel@tonic-gate  * Used to indicate which entries were chosen from a range.
1210Sstevel@tonic-gate  */
1220Sstevel@tonic-gate char	*chosen_reg = "chosen-reg";
1230Sstevel@tonic-gate #endif
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate /*
1260Sstevel@tonic-gate  * Function used to ring system console bell
1270Sstevel@tonic-gate  */
1280Sstevel@tonic-gate void (*ddi_console_bell_func)(clock_t duration);
1290Sstevel@tonic-gate 
1300Sstevel@tonic-gate /*
1310Sstevel@tonic-gate  * Creating register mappings and handling interrupts:
1320Sstevel@tonic-gate  */
1330Sstevel@tonic-gate 
1340Sstevel@tonic-gate /*
1350Sstevel@tonic-gate  * Generic ddi_map: Call parent to fulfill request...
1360Sstevel@tonic-gate  */
1370Sstevel@tonic-gate 
1380Sstevel@tonic-gate int
ddi_map(dev_info_t * dp,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * addrp)1390Sstevel@tonic-gate ddi_map(dev_info_t *dp, ddi_map_req_t *mp, off_t offset,
1400Sstevel@tonic-gate     off_t len, caddr_t *addrp)
1410Sstevel@tonic-gate {
1420Sstevel@tonic-gate 	dev_info_t *pdip;
1430Sstevel@tonic-gate 
1440Sstevel@tonic-gate 	ASSERT(dp);
1450Sstevel@tonic-gate 	pdip = (dev_info_t *)DEVI(dp)->devi_parent;
1460Sstevel@tonic-gate 	return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)(pdip,
1470Sstevel@tonic-gate 	    dp, mp, offset, len, addrp));
1480Sstevel@tonic-gate }
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate /*
1510Sstevel@tonic-gate  * ddi_apply_range: (Called by nexi only.)
1520Sstevel@tonic-gate  * Apply ranges in parent node dp, to child regspec rp...
1530Sstevel@tonic-gate  */
1540Sstevel@tonic-gate 
1550Sstevel@tonic-gate int
ddi_apply_range(dev_info_t * dp,dev_info_t * rdip,struct regspec * rp)1560Sstevel@tonic-gate ddi_apply_range(dev_info_t *dp, dev_info_t *rdip, struct regspec *rp)
1570Sstevel@tonic-gate {
1580Sstevel@tonic-gate 	return (i_ddi_apply_range(dp, rdip, rp));
1590Sstevel@tonic-gate }
1600Sstevel@tonic-gate 
1610Sstevel@tonic-gate int
ddi_map_regs(dev_info_t * dip,uint_t rnumber,caddr_t * kaddrp,off_t offset,off_t len)1620Sstevel@tonic-gate ddi_map_regs(dev_info_t *dip, uint_t rnumber, caddr_t *kaddrp, off_t offset,
1630Sstevel@tonic-gate     off_t len)
1640Sstevel@tonic-gate {
1650Sstevel@tonic-gate 	ddi_map_req_t mr;
1660Sstevel@tonic-gate #if defined(__x86)
1670Sstevel@tonic-gate 	struct {
1680Sstevel@tonic-gate 		int	bus;
1690Sstevel@tonic-gate 		int	addr;
1700Sstevel@tonic-gate 		int	size;
1710Sstevel@tonic-gate 	} reg, *reglist;
1720Sstevel@tonic-gate 	uint_t	length;
1730Sstevel@tonic-gate 	int	rc;
1740Sstevel@tonic-gate 
1750Sstevel@tonic-gate 	/*
1760Sstevel@tonic-gate 	 * get the 'registers' or the 'reg' property.
1770Sstevel@tonic-gate 	 * We look up the reg property as an array of
1780Sstevel@tonic-gate 	 * int's.
1790Sstevel@tonic-gate 	 */
1800Sstevel@tonic-gate 	rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
1810Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "registers", (int **)&reglist, &length);
1820Sstevel@tonic-gate 	if (rc != DDI_PROP_SUCCESS)
1830Sstevel@tonic-gate 		rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
1840Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "reg", (int **)&reglist, &length);
1850Sstevel@tonic-gate 	if (rc == DDI_PROP_SUCCESS) {
1860Sstevel@tonic-gate 		/*
1870Sstevel@tonic-gate 		 * point to the required entry.
1880Sstevel@tonic-gate 		 */
1890Sstevel@tonic-gate 		reg = reglist[rnumber];
1900Sstevel@tonic-gate 		reg.addr += offset;
1910Sstevel@tonic-gate 		if (len != 0)
1920Sstevel@tonic-gate 			reg.size = len;
1930Sstevel@tonic-gate 		/*
1940Sstevel@tonic-gate 		 * make a new property containing ONLY the required tuple.
1950Sstevel@tonic-gate 		 */
1960Sstevel@tonic-gate 		if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1970Sstevel@tonic-gate 		    chosen_reg, (int *)&reg, (sizeof (reg)/sizeof (int)))
1980Sstevel@tonic-gate 		    != DDI_PROP_SUCCESS) {
1990Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: cannot create '%s' "
2000Sstevel@tonic-gate 			    "property", DEVI(dip)->devi_name,
2010Sstevel@tonic-gate 			    DEVI(dip)->devi_instance, chosen_reg);
2020Sstevel@tonic-gate 		}
2030Sstevel@tonic-gate 		/*
2040Sstevel@tonic-gate 		 * free the memory allocated by
2050Sstevel@tonic-gate 		 * ddi_prop_lookup_int_array ().
2060Sstevel@tonic-gate 		 */
2070Sstevel@tonic-gate 		ddi_prop_free((void *)reglist);
2080Sstevel@tonic-gate 	}
2090Sstevel@tonic-gate #endif
2100Sstevel@tonic-gate 	mr.map_op = DDI_MO_MAP_LOCKED;
2110Sstevel@tonic-gate 	mr.map_type = DDI_MT_RNUMBER;
2120Sstevel@tonic-gate 	mr.map_obj.rnumber = rnumber;
2130Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
2140Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
2150Sstevel@tonic-gate 	mr.map_handlep = NULL;
2160Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate 	/*
2190Sstevel@tonic-gate 	 * Call my parent to map in my regs.
2200Sstevel@tonic-gate 	 */
2210Sstevel@tonic-gate 
2220Sstevel@tonic-gate 	return (ddi_map(dip, &mr, offset, len, kaddrp));
2230Sstevel@tonic-gate }
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate void
ddi_unmap_regs(dev_info_t * dip,uint_t rnumber,caddr_t * kaddrp,off_t offset,off_t len)2260Sstevel@tonic-gate ddi_unmap_regs(dev_info_t *dip, uint_t rnumber, caddr_t *kaddrp, off_t offset,
2270Sstevel@tonic-gate     off_t len)
2280Sstevel@tonic-gate {
2290Sstevel@tonic-gate 	ddi_map_req_t mr;
2300Sstevel@tonic-gate 
2310Sstevel@tonic-gate 	mr.map_op = DDI_MO_UNMAP;
2320Sstevel@tonic-gate 	mr.map_type = DDI_MT_RNUMBER;
2330Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
2340Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;	/* who cares? */
2350Sstevel@tonic-gate 	mr.map_obj.rnumber = rnumber;
2360Sstevel@tonic-gate 	mr.map_handlep = NULL;
2370Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
2380Sstevel@tonic-gate 
2390Sstevel@tonic-gate 	/*
2400Sstevel@tonic-gate 	 * Call my parent to unmap my regs.
2410Sstevel@tonic-gate 	 */
2420Sstevel@tonic-gate 
2430Sstevel@tonic-gate 	(void) ddi_map(dip, &mr, offset, len, kaddrp);
2440Sstevel@tonic-gate 	*kaddrp = (caddr_t)0;
2450Sstevel@tonic-gate #if defined(__x86)
2460Sstevel@tonic-gate 	(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, chosen_reg);
2470Sstevel@tonic-gate #endif
2480Sstevel@tonic-gate }
2490Sstevel@tonic-gate 
2500Sstevel@tonic-gate int
ddi_bus_map(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * vaddrp)2510Sstevel@tonic-gate ddi_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
2520Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *vaddrp)
2530Sstevel@tonic-gate {
2540Sstevel@tonic-gate 	return (i_ddi_bus_map(dip, rdip, mp, offset, len, vaddrp));
2550Sstevel@tonic-gate }
2560Sstevel@tonic-gate 
2570Sstevel@tonic-gate /*
2580Sstevel@tonic-gate  * nullbusmap:	The/DDI default bus_map entry point for nexi
2590Sstevel@tonic-gate  *		not conforming to the reg/range paradigm (i.e. scsi, etc.)
2600Sstevel@tonic-gate  *		with no HAT/MMU layer to be programmed at this level.
2610Sstevel@tonic-gate  *
2620Sstevel@tonic-gate  *		If the call is to map by rnumber, return an error,
2630Sstevel@tonic-gate  *		otherwise pass anything else up the tree to my parent.
2640Sstevel@tonic-gate  */
2650Sstevel@tonic-gate int
nullbusmap(dev_info_t * dip,dev_info_t * rdip,ddi_map_req_t * mp,off_t offset,off_t len,caddr_t * vaddrp)2660Sstevel@tonic-gate nullbusmap(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
2670Sstevel@tonic-gate 	off_t offset, off_t len, caddr_t *vaddrp)
2680Sstevel@tonic-gate {
2690Sstevel@tonic-gate 	_NOTE(ARGUNUSED(rdip))
2700Sstevel@tonic-gate 	if (mp->map_type == DDI_MT_RNUMBER)
2710Sstevel@tonic-gate 		return (DDI_ME_UNSUPPORTED);
2720Sstevel@tonic-gate 
2730Sstevel@tonic-gate 	return (ddi_map(dip, mp, offset, len, vaddrp));
2740Sstevel@tonic-gate }
2750Sstevel@tonic-gate 
2760Sstevel@tonic-gate /*
2770Sstevel@tonic-gate  * ddi_rnumber_to_regspec: Not for use by leaf drivers.
2780Sstevel@tonic-gate  *			   Only for use by nexi using the reg/range paradigm.
2790Sstevel@tonic-gate  */
2800Sstevel@tonic-gate struct regspec *
ddi_rnumber_to_regspec(dev_info_t * dip,int rnumber)2810Sstevel@tonic-gate ddi_rnumber_to_regspec(dev_info_t *dip, int rnumber)
2820Sstevel@tonic-gate {
2830Sstevel@tonic-gate 	return (i_ddi_rnumber_to_regspec(dip, rnumber));
2840Sstevel@tonic-gate }
2850Sstevel@tonic-gate 
2860Sstevel@tonic-gate 
2870Sstevel@tonic-gate /*
2880Sstevel@tonic-gate  * Note that we allow the dip to be nil because we may be called
2890Sstevel@tonic-gate  * prior even to the instantiation of the devinfo tree itself - all
2900Sstevel@tonic-gate  * regular leaf and nexus drivers should always use a non-nil dip!
2910Sstevel@tonic-gate  *
2920Sstevel@tonic-gate  * We treat peek in a somewhat cavalier fashion .. assuming that we'll
2930Sstevel@tonic-gate  * simply get a synchronous fault as soon as we touch a missing address.
2940Sstevel@tonic-gate  *
2950Sstevel@tonic-gate  * Poke is rather more carefully handled because we might poke to a write
2960Sstevel@tonic-gate  * buffer, "succeed", then only find some time later that we got an
2970Sstevel@tonic-gate  * asynchronous fault that indicated that the address we were writing to
2980Sstevel@tonic-gate  * was not really backed by hardware.
2990Sstevel@tonic-gate  */
3000Sstevel@tonic-gate 
3010Sstevel@tonic-gate static int
i_ddi_peekpoke(dev_info_t * devi,ddi_ctl_enum_t cmd,size_t size,void * addr,void * value_p)3020Sstevel@tonic-gate i_ddi_peekpoke(dev_info_t *devi, ddi_ctl_enum_t cmd, size_t size,
3030Sstevel@tonic-gate     void *addr, void *value_p)
3040Sstevel@tonic-gate {
3050Sstevel@tonic-gate 	union {
3060Sstevel@tonic-gate 		uint64_t	u64;
3070Sstevel@tonic-gate 		uint32_t	u32;
3080Sstevel@tonic-gate 		uint16_t	u16;
3090Sstevel@tonic-gate 		uint8_t		u8;
3100Sstevel@tonic-gate 	} peekpoke_value;
3110Sstevel@tonic-gate 
3120Sstevel@tonic-gate 	peekpoke_ctlops_t peekpoke_args;
3130Sstevel@tonic-gate 	uint64_t dummy_result;
3140Sstevel@tonic-gate 	int rval;
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate 	/* Note: size is assumed to be correct;  it is not checked. */
3170Sstevel@tonic-gate 	peekpoke_args.size = size;
31842Sagiri 	peekpoke_args.dev_addr = (uintptr_t)addr;
3190Sstevel@tonic-gate 	peekpoke_args.handle = NULL;
3200Sstevel@tonic-gate 	peekpoke_args.repcount = 1;
3210Sstevel@tonic-gate 	peekpoke_args.flags = 0;
3220Sstevel@tonic-gate 
3230Sstevel@tonic-gate 	if (cmd == DDI_CTLOPS_POKE) {
3240Sstevel@tonic-gate 		switch (size) {
3250Sstevel@tonic-gate 		case sizeof (uint8_t):
3260Sstevel@tonic-gate 			peekpoke_value.u8 = *(uint8_t *)value_p;
3270Sstevel@tonic-gate 			break;
3280Sstevel@tonic-gate 		case sizeof (uint16_t):
3290Sstevel@tonic-gate 			peekpoke_value.u16 = *(uint16_t *)value_p;
3300Sstevel@tonic-gate 			break;
3310Sstevel@tonic-gate 		case sizeof (uint32_t):
3320Sstevel@tonic-gate 			peekpoke_value.u32 = *(uint32_t *)value_p;
3330Sstevel@tonic-gate 			break;
3340Sstevel@tonic-gate 		case sizeof (uint64_t):
3350Sstevel@tonic-gate 			peekpoke_value.u64 = *(uint64_t *)value_p;
3360Sstevel@tonic-gate 			break;
3370Sstevel@tonic-gate 		}
3380Sstevel@tonic-gate 	}
3390Sstevel@tonic-gate 
34042Sagiri 	peekpoke_args.host_addr = (uintptr_t)&peekpoke_value.u64;
3410Sstevel@tonic-gate 
3420Sstevel@tonic-gate 	if (devi != NULL)
3430Sstevel@tonic-gate 		rval = ddi_ctlops(devi, devi, cmd, &peekpoke_args,
3440Sstevel@tonic-gate 		    &dummy_result);
3450Sstevel@tonic-gate 	else
3460Sstevel@tonic-gate 		rval = peekpoke_mem(cmd, &peekpoke_args);
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	/*
3490Sstevel@tonic-gate 	 * A NULL value_p is permitted by ddi_peek(9F); discard the result.
3500Sstevel@tonic-gate 	 */
3510Sstevel@tonic-gate 	if ((cmd == DDI_CTLOPS_PEEK) & (value_p != NULL)) {
3520Sstevel@tonic-gate 		switch (size) {
3530Sstevel@tonic-gate 		case sizeof (uint8_t):
3540Sstevel@tonic-gate 			*(uint8_t *)value_p = peekpoke_value.u8;
3550Sstevel@tonic-gate 			break;
3560Sstevel@tonic-gate 		case sizeof (uint16_t):
3570Sstevel@tonic-gate 			*(uint16_t *)value_p = peekpoke_value.u16;
3580Sstevel@tonic-gate 			break;
3590Sstevel@tonic-gate 		case sizeof (uint32_t):
3600Sstevel@tonic-gate 			*(uint32_t *)value_p = peekpoke_value.u32;
3610Sstevel@tonic-gate 			break;
3620Sstevel@tonic-gate 		case sizeof (uint64_t):
3630Sstevel@tonic-gate 			*(uint64_t *)value_p = peekpoke_value.u64;
3640Sstevel@tonic-gate 			break;
3650Sstevel@tonic-gate 		}
3660Sstevel@tonic-gate 	}
3670Sstevel@tonic-gate 
3680Sstevel@tonic-gate 	return (rval);
3690Sstevel@tonic-gate }
3700Sstevel@tonic-gate 
3710Sstevel@tonic-gate /*
3720Sstevel@tonic-gate  * Keep ddi_peek() and ddi_poke() in case 3rd parties are calling this.
3730Sstevel@tonic-gate  * they shouldn't be, but the 9f manpage kind of pseudo exposes it.
3740Sstevel@tonic-gate  */
3750Sstevel@tonic-gate int
ddi_peek(dev_info_t * devi,size_t size,void * addr,void * value_p)3760Sstevel@tonic-gate ddi_peek(dev_info_t *devi, size_t size, void *addr, void *value_p)
3770Sstevel@tonic-gate {
3780Sstevel@tonic-gate 	switch (size) {
3790Sstevel@tonic-gate 	case sizeof (uint8_t):
3800Sstevel@tonic-gate 	case sizeof (uint16_t):
3810Sstevel@tonic-gate 	case sizeof (uint32_t):
3820Sstevel@tonic-gate 	case sizeof (uint64_t):
3830Sstevel@tonic-gate 		break;
3840Sstevel@tonic-gate 	default:
3850Sstevel@tonic-gate 		return (DDI_FAILURE);
3860Sstevel@tonic-gate 	}
3870Sstevel@tonic-gate 
3880Sstevel@tonic-gate 	return (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, size, addr, value_p));
3890Sstevel@tonic-gate }
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate int
ddi_poke(dev_info_t * devi,size_t size,void * addr,void * value_p)3920Sstevel@tonic-gate ddi_poke(dev_info_t *devi, size_t size, void *addr, void *value_p)
3930Sstevel@tonic-gate {
3940Sstevel@tonic-gate 	switch (size) {
3950Sstevel@tonic-gate 	case sizeof (uint8_t):
3960Sstevel@tonic-gate 	case sizeof (uint16_t):
3970Sstevel@tonic-gate 	case sizeof (uint32_t):
3980Sstevel@tonic-gate 	case sizeof (uint64_t):
3990Sstevel@tonic-gate 		break;
4000Sstevel@tonic-gate 	default:
4010Sstevel@tonic-gate 		return (DDI_FAILURE);
4020Sstevel@tonic-gate 	}
4030Sstevel@tonic-gate 
4040Sstevel@tonic-gate 	return (i_ddi_peekpoke(devi, DDI_CTLOPS_POKE, size, addr, value_p));
4050Sstevel@tonic-gate }
4060Sstevel@tonic-gate 
4070Sstevel@tonic-gate int
ddi_peek8(dev_info_t * dip,int8_t * addr,int8_t * val_p)4080Sstevel@tonic-gate ddi_peek8(dev_info_t *dip, int8_t *addr, int8_t *val_p)
4091106Smrj {
4101106Smrj 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4111106Smrj 	    val_p));
4121106Smrj }
4131106Smrj 
4141106Smrj int
ddi_peek16(dev_info_t * dip,int16_t * addr,int16_t * val_p)4151106Smrj ddi_peek16(dev_info_t *dip, int16_t *addr, int16_t *val_p)
4160Sstevel@tonic-gate {
4170Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4180Sstevel@tonic-gate 	    val_p));
4190Sstevel@tonic-gate }
4200Sstevel@tonic-gate 
4211106Smrj int
ddi_peek32(dev_info_t * dip,int32_t * addr,int32_t * val_p)4221106Smrj ddi_peek32(dev_info_t *dip, int32_t *addr, int32_t *val_p)
4231106Smrj {
4241106Smrj 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4251106Smrj 	    val_p));
4261106Smrj }
4271106Smrj 
4281106Smrj int
ddi_peek64(dev_info_t * dip,int64_t * addr,int64_t * val_p)4291106Smrj ddi_peek64(dev_info_t *dip, int64_t *addr, int64_t *val_p)
4300Sstevel@tonic-gate {
4310Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4320Sstevel@tonic-gate 	    val_p));
4330Sstevel@tonic-gate }
4340Sstevel@tonic-gate 
4351106Smrj 
4361106Smrj /*
4371106Smrj  * We need to separate the old interfaces from the new ones and leave them
4381106Smrj  * in here for a while. Previous versions of the OS defined the new interfaces
4391106Smrj  * to the old interfaces. This way we can fix things up so that we can
4401106Smrj  * eventually remove these interfaces.
4411106Smrj  * e.g. A 3rd party module/driver using ddi_peek8 and built against S10
4421106Smrj  * or earlier will actually have a reference to ddi_peekc in the binary.
4431106Smrj  */
4441106Smrj #ifdef _ILP32
4451106Smrj int
ddi_peekc(dev_info_t * dip,int8_t * addr,int8_t * val_p)4461106Smrj ddi_peekc(dev_info_t *dip, int8_t *addr, int8_t *val_p)
4470Sstevel@tonic-gate {
4480Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4490Sstevel@tonic-gate 	    val_p));
4500Sstevel@tonic-gate }
4510Sstevel@tonic-gate 
4521106Smrj int
ddi_peeks(dev_info_t * dip,int16_t * addr,int16_t * val_p)4531106Smrj ddi_peeks(dev_info_t *dip, int16_t *addr, int16_t *val_p)
4541106Smrj {
4551106Smrj 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4561106Smrj 	    val_p));
4571106Smrj }
4581106Smrj 
4591106Smrj int
ddi_peekl(dev_info_t * dip,int32_t * addr,int32_t * val_p)4601106Smrj ddi_peekl(dev_info_t *dip, int32_t *addr, int32_t *val_p)
4610Sstevel@tonic-gate {
4620Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4630Sstevel@tonic-gate 	    val_p));
4640Sstevel@tonic-gate }
4650Sstevel@tonic-gate 
4661106Smrj int
ddi_peekd(dev_info_t * dip,int64_t * addr,int64_t * val_p)4671106Smrj ddi_peekd(dev_info_t *dip, int64_t *addr, int64_t *val_p)
4681106Smrj {
4691106Smrj 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4701106Smrj 	    val_p));
4711106Smrj }
4721106Smrj #endif /* _ILP32 */
4731106Smrj 
4740Sstevel@tonic-gate int
ddi_poke8(dev_info_t * dip,int8_t * addr,int8_t val)4750Sstevel@tonic-gate ddi_poke8(dev_info_t *dip, int8_t *addr, int8_t val)
4760Sstevel@tonic-gate {
4770Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
4780Sstevel@tonic-gate }
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate int
ddi_poke16(dev_info_t * dip,int16_t * addr,int16_t val)4810Sstevel@tonic-gate ddi_poke16(dev_info_t *dip, int16_t *addr, int16_t val)
4821106Smrj {
4831106Smrj 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
4841106Smrj }
4851106Smrj 
4861106Smrj int
ddi_poke32(dev_info_t * dip,int32_t * addr,int32_t val)4871106Smrj ddi_poke32(dev_info_t *dip, int32_t *addr, int32_t val)
4881106Smrj {
4891106Smrj 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
4901106Smrj }
4911106Smrj 
4921106Smrj int
ddi_poke64(dev_info_t * dip,int64_t * addr,int64_t val)4931106Smrj ddi_poke64(dev_info_t *dip, int64_t *addr, int64_t val)
4940Sstevel@tonic-gate {
4950Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
4960Sstevel@tonic-gate }
4970Sstevel@tonic-gate 
4981106Smrj /*
4991106Smrj  * We need to separate the old interfaces from the new ones and leave them
5001106Smrj  * in here for a while. Previous versions of the OS defined the new interfaces
5011106Smrj  * to the old interfaces. This way we can fix things up so that we can
5021106Smrj  * eventually remove these interfaces.
5031106Smrj  * e.g. A 3rd party module/driver using ddi_poke8 and built against S10
5041106Smrj  * or earlier will actually have a reference to ddi_pokec in the binary.
5051106Smrj  */
5061106Smrj #ifdef _ILP32
5071106Smrj int
ddi_pokec(dev_info_t * dip,int8_t * addr,int8_t val)5081106Smrj ddi_pokec(dev_info_t *dip, int8_t *addr, int8_t val)
5090Sstevel@tonic-gate {
5100Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
5110Sstevel@tonic-gate }
5120Sstevel@tonic-gate 
5131106Smrj int
ddi_pokes(dev_info_t * dip,int16_t * addr,int16_t val)5141106Smrj ddi_pokes(dev_info_t *dip, int16_t *addr, int16_t val)
5151106Smrj {
5161106Smrj 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
5171106Smrj }
5181106Smrj 
5191106Smrj int
ddi_pokel(dev_info_t * dip,int32_t * addr,int32_t val)5201106Smrj ddi_pokel(dev_info_t *dip, int32_t *addr, int32_t val)
5211106Smrj {
5221106Smrj 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
5231106Smrj }
5241106Smrj 
5250Sstevel@tonic-gate int
ddi_poked(dev_info_t * dip,int64_t * addr,int64_t val)5260Sstevel@tonic-gate ddi_poked(dev_info_t *dip, int64_t *addr, int64_t val)
5270Sstevel@tonic-gate {
5280Sstevel@tonic-gate 	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
5290Sstevel@tonic-gate }
5301106Smrj #endif /* _ILP32 */
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate /*
5330Sstevel@tonic-gate  * ddi_peekpokeio() is used primarily by the mem drivers for moving
5340Sstevel@tonic-gate  * data to and from uio structures via peek and poke.  Note that we
5350Sstevel@tonic-gate  * use "internal" routines ddi_peek and ddi_poke to make this go
5360Sstevel@tonic-gate  * slightly faster, avoiding the call overhead ..
5370Sstevel@tonic-gate  */
5380Sstevel@tonic-gate int
ddi_peekpokeio(dev_info_t * devi,struct uio * uio,enum uio_rw rw,caddr_t addr,size_t len,uint_t xfersize)5390Sstevel@tonic-gate ddi_peekpokeio(dev_info_t *devi, struct uio *uio, enum uio_rw rw,
5400Sstevel@tonic-gate     caddr_t addr, size_t len, uint_t xfersize)
5410Sstevel@tonic-gate {
5420Sstevel@tonic-gate 	int64_t	ibuffer;
5430Sstevel@tonic-gate 	int8_t w8;
5440Sstevel@tonic-gate 	size_t sz;
5450Sstevel@tonic-gate 	int o;
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	if (xfersize > sizeof (long))
5480Sstevel@tonic-gate 		xfersize = sizeof (long);
5490Sstevel@tonic-gate 
5500Sstevel@tonic-gate 	while (len != 0) {
5510Sstevel@tonic-gate 		if ((len | (uintptr_t)addr) & 1) {
5520Sstevel@tonic-gate 			sz = sizeof (int8_t);
5530Sstevel@tonic-gate 			if (rw == UIO_WRITE) {
5540Sstevel@tonic-gate 				if ((o = uwritec(uio)) == -1)
5550Sstevel@tonic-gate 					return (DDI_FAILURE);
5560Sstevel@tonic-gate 				if (ddi_poke8(devi, (int8_t *)addr,
5570Sstevel@tonic-gate 				    (int8_t)o) != DDI_SUCCESS)
5580Sstevel@tonic-gate 					return (DDI_FAILURE);
5590Sstevel@tonic-gate 			} else {
5600Sstevel@tonic-gate 				if (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, sz,
5610Sstevel@tonic-gate 				    (int8_t *)addr, &w8) != DDI_SUCCESS)
5620Sstevel@tonic-gate 					return (DDI_FAILURE);
5630Sstevel@tonic-gate 				if (ureadc(w8, uio))
5640Sstevel@tonic-gate 					return (DDI_FAILURE);
5650Sstevel@tonic-gate 			}
5660Sstevel@tonic-gate 		} else {
5670Sstevel@tonic-gate 			switch (xfersize) {
5680Sstevel@tonic-gate 			case sizeof (int64_t):
5690Sstevel@tonic-gate 				if (((len | (uintptr_t)addr) &
5700Sstevel@tonic-gate 				    (sizeof (int64_t) - 1)) == 0) {
5710Sstevel@tonic-gate 					sz = xfersize;
5720Sstevel@tonic-gate 					break;
5730Sstevel@tonic-gate 				}
5740Sstevel@tonic-gate 				/*FALLTHROUGH*/
5750Sstevel@tonic-gate 			case sizeof (int32_t):
5760Sstevel@tonic-gate 				if (((len | (uintptr_t)addr) &
5770Sstevel@tonic-gate 				    (sizeof (int32_t) - 1)) == 0) {
5780Sstevel@tonic-gate 					sz = xfersize;
5790Sstevel@tonic-gate 					break;
5800Sstevel@tonic-gate 				}
5810Sstevel@tonic-gate 				/*FALLTHROUGH*/
5820Sstevel@tonic-gate 			default:
5830Sstevel@tonic-gate 				/*
5840Sstevel@tonic-gate 				 * This still assumes that we might have an
5850Sstevel@tonic-gate 				 * I/O bus out there that permits 16-bit
5860Sstevel@tonic-gate 				 * transfers (and that it would be upset by
5870Sstevel@tonic-gate 				 * 32-bit transfers from such locations).
5880Sstevel@tonic-gate 				 */
5890Sstevel@tonic-gate 				sz = sizeof (int16_t);
5900Sstevel@tonic-gate 				break;
5910Sstevel@tonic-gate 			}
5920Sstevel@tonic-gate 
5930Sstevel@tonic-gate 			if (rw == UIO_READ) {
5940Sstevel@tonic-gate 				if (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, sz,
5950Sstevel@tonic-gate 				    addr, &ibuffer) != DDI_SUCCESS)
5960Sstevel@tonic-gate 					return (DDI_FAILURE);
5970Sstevel@tonic-gate 			}
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 			if (uiomove(&ibuffer, sz, rw, uio))
6000Sstevel@tonic-gate 				return (DDI_FAILURE);
6010Sstevel@tonic-gate 
6020Sstevel@tonic-gate 			if (rw == UIO_WRITE) {
6030Sstevel@tonic-gate 				if (i_ddi_peekpoke(devi, DDI_CTLOPS_POKE, sz,
6040Sstevel@tonic-gate 				    addr, &ibuffer) != DDI_SUCCESS)
6050Sstevel@tonic-gate 					return (DDI_FAILURE);
6060Sstevel@tonic-gate 			}
6070Sstevel@tonic-gate 		}
6080Sstevel@tonic-gate 		addr += sz;
6090Sstevel@tonic-gate 		len -= sz;
6100Sstevel@tonic-gate 	}
6110Sstevel@tonic-gate 	return (DDI_SUCCESS);
6120Sstevel@tonic-gate }
6130Sstevel@tonic-gate 
6140Sstevel@tonic-gate /*
6150Sstevel@tonic-gate  * These routines are used by drivers that do layered ioctls
6160Sstevel@tonic-gate  * On sparc, they're implemented in assembler to avoid spilling
6170Sstevel@tonic-gate  * register windows in the common (copyin) case ..
6180Sstevel@tonic-gate  */
6190Sstevel@tonic-gate #if !defined(__sparc)
6200Sstevel@tonic-gate int
ddi_copyin(const void * buf,void * kernbuf,size_t size,int flags)6210Sstevel@tonic-gate ddi_copyin(const void *buf, void *kernbuf, size_t size, int flags)
6220Sstevel@tonic-gate {
6230Sstevel@tonic-gate 	if (flags & FKIOCTL)
6240Sstevel@tonic-gate 		return (kcopy(buf, kernbuf, size) ? -1 : 0);
6250Sstevel@tonic-gate 	return (copyin(buf, kernbuf, size));
6260Sstevel@tonic-gate }
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate int
ddi_copyout(const void * buf,void * kernbuf,size_t size,int flags)6290Sstevel@tonic-gate ddi_copyout(const void *buf, void *kernbuf, size_t size, int flags)
6300Sstevel@tonic-gate {
6310Sstevel@tonic-gate 	if (flags & FKIOCTL)
6320Sstevel@tonic-gate 		return (kcopy(buf, kernbuf, size) ? -1 : 0);
6330Sstevel@tonic-gate 	return (copyout(buf, kernbuf, size));
6340Sstevel@tonic-gate }
6350Sstevel@tonic-gate #endif	/* !__sparc */
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate /*
6380Sstevel@tonic-gate  * Conversions in nexus pagesize units.  We don't duplicate the
6390Sstevel@tonic-gate  * 'nil dip' semantics of peek/poke because btopr/btop/ptob are DDI/DKI
6400Sstevel@tonic-gate  * routines anyway.
6410Sstevel@tonic-gate  */
6420Sstevel@tonic-gate unsigned long
ddi_btop(dev_info_t * dip,unsigned long bytes)6430Sstevel@tonic-gate ddi_btop(dev_info_t *dip, unsigned long bytes)
6440Sstevel@tonic-gate {
6450Sstevel@tonic-gate 	unsigned long pages;
6460Sstevel@tonic-gate 
6470Sstevel@tonic-gate 	(void) ddi_ctlops(dip, dip, DDI_CTLOPS_BTOP, &bytes, &pages);
6480Sstevel@tonic-gate 	return (pages);
6490Sstevel@tonic-gate }
6500Sstevel@tonic-gate 
6510Sstevel@tonic-gate unsigned long
ddi_btopr(dev_info_t * dip,unsigned long bytes)6520Sstevel@tonic-gate ddi_btopr(dev_info_t *dip, unsigned long bytes)
6530Sstevel@tonic-gate {
6540Sstevel@tonic-gate 	unsigned long pages;
6550Sstevel@tonic-gate 
6560Sstevel@tonic-gate 	(void) ddi_ctlops(dip, dip, DDI_CTLOPS_BTOPR, &bytes, &pages);
6570Sstevel@tonic-gate 	return (pages);
6580Sstevel@tonic-gate }
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate unsigned long
ddi_ptob(dev_info_t * dip,unsigned long pages)6610Sstevel@tonic-gate ddi_ptob(dev_info_t *dip, unsigned long pages)
6620Sstevel@tonic-gate {
6630Sstevel@tonic-gate 	unsigned long bytes;
6640Sstevel@tonic-gate 
6650Sstevel@tonic-gate 	(void) ddi_ctlops(dip, dip, DDI_CTLOPS_PTOB, &pages, &bytes);
6660Sstevel@tonic-gate 	return (bytes);
6670Sstevel@tonic-gate }
6680Sstevel@tonic-gate 
6690Sstevel@tonic-gate unsigned int
ddi_enter_critical(void)6700Sstevel@tonic-gate ddi_enter_critical(void)
6710Sstevel@tonic-gate {
6720Sstevel@tonic-gate 	return ((uint_t)spl7());
6730Sstevel@tonic-gate }
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate void
ddi_exit_critical(unsigned int spl)6760Sstevel@tonic-gate ddi_exit_critical(unsigned int spl)
6770Sstevel@tonic-gate {
6780Sstevel@tonic-gate 	splx((int)spl);
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate 
6810Sstevel@tonic-gate /*
6820Sstevel@tonic-gate  * Nexus ctlops punter
6830Sstevel@tonic-gate  */
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate #if !defined(__sparc)
6860Sstevel@tonic-gate /*
6870Sstevel@tonic-gate  * Request bus_ctl parent to handle a bus_ctl request
6880Sstevel@tonic-gate  *
6890Sstevel@tonic-gate  * (The sparc version is in sparc_ddi.s)
6900Sstevel@tonic-gate  */
6910Sstevel@tonic-gate int
ddi_ctlops(dev_info_t * d,dev_info_t * r,ddi_ctl_enum_t op,void * a,void * v)6920Sstevel@tonic-gate ddi_ctlops(dev_info_t *d, dev_info_t *r, ddi_ctl_enum_t op, void *a, void *v)
6930Sstevel@tonic-gate {
6940Sstevel@tonic-gate 	int (*fp)();
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	if (!d || !r)
6970Sstevel@tonic-gate 		return (DDI_FAILURE);
6980Sstevel@tonic-gate 
6990Sstevel@tonic-gate 	if ((d = (dev_info_t *)DEVI(d)->devi_bus_ctl) == NULL)
7000Sstevel@tonic-gate 		return (DDI_FAILURE);
7010Sstevel@tonic-gate 
7020Sstevel@tonic-gate 	fp = DEVI(d)->devi_ops->devo_bus_ops->bus_ctl;
7030Sstevel@tonic-gate 	return ((*fp)(d, r, op, a, v));
7040Sstevel@tonic-gate }
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate #endif
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate /*
7090Sstevel@tonic-gate  * DMA/DVMA setup
7100Sstevel@tonic-gate  */
7110Sstevel@tonic-gate 
7120Sstevel@tonic-gate #if defined(__sparc)
7130Sstevel@tonic-gate static ddi_dma_lim_t standard_limits = {
7140Sstevel@tonic-gate 	(uint_t)0,	/* addr_t dlim_addr_lo */
7150Sstevel@tonic-gate 	(uint_t)-1,	/* addr_t dlim_addr_hi */
7160Sstevel@tonic-gate 	(uint_t)-1,	/* uint_t dlim_cntr_max */
7170Sstevel@tonic-gate 	(uint_t)1,	/* uint_t dlim_burstsizes */
7180Sstevel@tonic-gate 	(uint_t)1,	/* uint_t dlim_minxfer */
7190Sstevel@tonic-gate 	0		/* uint_t dlim_dmaspeed */
7200Sstevel@tonic-gate };
7210Sstevel@tonic-gate #elif defined(__x86)
7220Sstevel@tonic-gate static ddi_dma_lim_t standard_limits = {
7230Sstevel@tonic-gate 	(uint_t)0,		/* addr_t dlim_addr_lo */
7240Sstevel@tonic-gate 	(uint_t)0xffffff,	/* addr_t dlim_addr_hi */
7250Sstevel@tonic-gate 	(uint_t)0,		/* uint_t dlim_cntr_max */
7260Sstevel@tonic-gate 	(uint_t)0x00000001,	/* uint_t dlim_burstsizes */
7270Sstevel@tonic-gate 	(uint_t)DMA_UNIT_8,	/* uint_t dlim_minxfer */
7280Sstevel@tonic-gate 	(uint_t)0,		/* uint_t dlim_dmaspeed */
7290Sstevel@tonic-gate 	(uint_t)0x86<<24+0,	/* uint_t dlim_version */
7300Sstevel@tonic-gate 	(uint_t)0xffff,		/* uint_t dlim_adreg_max */
7310Sstevel@tonic-gate 	(uint_t)0xffff,		/* uint_t dlim_ctreg_max */
7320Sstevel@tonic-gate 	(uint_t)512,		/* uint_t dlim_granular */
7330Sstevel@tonic-gate 	(int)1,			/* int dlim_sgllen */
7340Sstevel@tonic-gate 	(uint_t)0xffffffff	/* uint_t dlim_reqsizes */
7350Sstevel@tonic-gate };
7360Sstevel@tonic-gate 
7370Sstevel@tonic-gate #endif
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate int
ddi_dma_setup(dev_info_t * dip,struct ddi_dma_req * dmareqp,ddi_dma_handle_t * handlep)7400Sstevel@tonic-gate ddi_dma_setup(dev_info_t *dip, struct ddi_dma_req *dmareqp,
7410Sstevel@tonic-gate     ddi_dma_handle_t *handlep)
7420Sstevel@tonic-gate {
7430Sstevel@tonic-gate 	int (*funcp)() = ddi_dma_map;
7440Sstevel@tonic-gate 	struct bus_ops *bop;
7450Sstevel@tonic-gate #if defined(__sparc)
7460Sstevel@tonic-gate 	auto ddi_dma_lim_t dma_lim;
7470Sstevel@tonic-gate 
7480Sstevel@tonic-gate 	if (dmareqp->dmar_limits == (ddi_dma_lim_t *)0) {
7490Sstevel@tonic-gate 		dma_lim = standard_limits;
7500Sstevel@tonic-gate 	} else {
7510Sstevel@tonic-gate 		dma_lim = *dmareqp->dmar_limits;
7520Sstevel@tonic-gate 	}
7530Sstevel@tonic-gate 	dmareqp->dmar_limits = &dma_lim;
7540Sstevel@tonic-gate #endif
7550Sstevel@tonic-gate #if defined(__x86)
7560Sstevel@tonic-gate 	if (dmareqp->dmar_limits == (ddi_dma_lim_t *)0)
7570Sstevel@tonic-gate 		return (DDI_FAILURE);
7580Sstevel@tonic-gate #endif
7590Sstevel@tonic-gate 
7600Sstevel@tonic-gate 	/*
7610Sstevel@tonic-gate 	 * Handle the case that the requester is both a leaf
7620Sstevel@tonic-gate 	 * and a nexus driver simultaneously by calling the
7630Sstevel@tonic-gate 	 * requester's bus_dma_map function directly instead
7640Sstevel@tonic-gate 	 * of ddi_dma_map.
7650Sstevel@tonic-gate 	 */
7660Sstevel@tonic-gate 	bop = DEVI(dip)->devi_ops->devo_bus_ops;
7670Sstevel@tonic-gate 	if (bop && bop->bus_dma_map)
7680Sstevel@tonic-gate 		funcp = bop->bus_dma_map;
7690Sstevel@tonic-gate 	return ((*funcp)(dip, dip, dmareqp, handlep));
7700Sstevel@tonic-gate }
7710Sstevel@tonic-gate 
7720Sstevel@tonic-gate int
ddi_dma_addr_setup(dev_info_t * dip,struct as * as,caddr_t addr,size_t len,uint_t flags,int (* waitfp)(),caddr_t arg,ddi_dma_lim_t * limits,ddi_dma_handle_t * handlep)7730Sstevel@tonic-gate ddi_dma_addr_setup(dev_info_t *dip, struct as *as, caddr_t addr, size_t len,
7740Sstevel@tonic-gate     uint_t flags, int (*waitfp)(), caddr_t arg,
7750Sstevel@tonic-gate     ddi_dma_lim_t *limits, ddi_dma_handle_t *handlep)
7760Sstevel@tonic-gate {
7770Sstevel@tonic-gate 	int (*funcp)() = ddi_dma_map;
7780Sstevel@tonic-gate 	ddi_dma_lim_t dma_lim;
7790Sstevel@tonic-gate 	struct ddi_dma_req dmareq;
7800Sstevel@tonic-gate 	struct bus_ops *bop;
7810Sstevel@tonic-gate 
7820Sstevel@tonic-gate 	if (len == 0) {
7830Sstevel@tonic-gate 		return (DDI_DMA_NOMAPPING);
7840Sstevel@tonic-gate 	}
7850Sstevel@tonic-gate 	if (limits == (ddi_dma_lim_t *)0) {
7860Sstevel@tonic-gate 		dma_lim = standard_limits;
7870Sstevel@tonic-gate 	} else {
7880Sstevel@tonic-gate 		dma_lim = *limits;
7890Sstevel@tonic-gate 	}
7900Sstevel@tonic-gate 	dmareq.dmar_limits = &dma_lim;
7910Sstevel@tonic-gate 	dmareq.dmar_flags = flags;
7920Sstevel@tonic-gate 	dmareq.dmar_fp = waitfp;
7930Sstevel@tonic-gate 	dmareq.dmar_arg = arg;
7940Sstevel@tonic-gate 	dmareq.dmar_object.dmao_size = len;
7950Sstevel@tonic-gate 	dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR;
7960Sstevel@tonic-gate 	dmareq.dmar_object.dmao_obj.virt_obj.v_as = as;
7970Sstevel@tonic-gate 	dmareq.dmar_object.dmao_obj.virt_obj.v_addr = addr;
7980Sstevel@tonic-gate 	dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
7990Sstevel@tonic-gate 
8000Sstevel@tonic-gate 	/*
8010Sstevel@tonic-gate 	 * Handle the case that the requester is both a leaf
8020Sstevel@tonic-gate 	 * and a nexus driver simultaneously by calling the
8030Sstevel@tonic-gate 	 * requester's bus_dma_map function directly instead
8040Sstevel@tonic-gate 	 * of ddi_dma_map.
8050Sstevel@tonic-gate 	 */
8060Sstevel@tonic-gate 	bop = DEVI(dip)->devi_ops->devo_bus_ops;
8070Sstevel@tonic-gate 	if (bop && bop->bus_dma_map)
8080Sstevel@tonic-gate 		funcp = bop->bus_dma_map;
8090Sstevel@tonic-gate 
8100Sstevel@tonic-gate 	return ((*funcp)(dip, dip, &dmareq, handlep));
8110Sstevel@tonic-gate }
8120Sstevel@tonic-gate 
8130Sstevel@tonic-gate int
ddi_dma_buf_setup(dev_info_t * dip,struct buf * bp,uint_t flags,int (* waitfp)(),caddr_t arg,ddi_dma_lim_t * limits,ddi_dma_handle_t * handlep)8140Sstevel@tonic-gate ddi_dma_buf_setup(dev_info_t *dip, struct buf *bp, uint_t flags,
8150Sstevel@tonic-gate     int (*waitfp)(), caddr_t arg, ddi_dma_lim_t *limits,
8160Sstevel@tonic-gate     ddi_dma_handle_t *handlep)
8170Sstevel@tonic-gate {
8180Sstevel@tonic-gate 	int (*funcp)() = ddi_dma_map;
8190Sstevel@tonic-gate 	ddi_dma_lim_t dma_lim;
8200Sstevel@tonic-gate 	struct ddi_dma_req dmareq;
8210Sstevel@tonic-gate 	struct bus_ops *bop;
8220Sstevel@tonic-gate 
8230Sstevel@tonic-gate 	if (limits == (ddi_dma_lim_t *)0) {
8240Sstevel@tonic-gate 		dma_lim = standard_limits;
8250Sstevel@tonic-gate 	} else {
8260Sstevel@tonic-gate 		dma_lim = *limits;
8270Sstevel@tonic-gate 	}
8280Sstevel@tonic-gate 	dmareq.dmar_limits = &dma_lim;
8290Sstevel@tonic-gate 	dmareq.dmar_flags = flags;
8300Sstevel@tonic-gate 	dmareq.dmar_fp = waitfp;
8310Sstevel@tonic-gate 	dmareq.dmar_arg = arg;
8320Sstevel@tonic-gate 	dmareq.dmar_object.dmao_size = (uint_t)bp->b_bcount;
8330Sstevel@tonic-gate 
8341299Scth 	if (bp->b_flags & B_PAGEIO) {
8350Sstevel@tonic-gate 		dmareq.dmar_object.dmao_type = DMA_OTYP_PAGES;
8360Sstevel@tonic-gate 		dmareq.dmar_object.dmao_obj.pp_obj.pp_pp = bp->b_pages;
8370Sstevel@tonic-gate 		dmareq.dmar_object.dmao_obj.pp_obj.pp_offset =
8380Sstevel@tonic-gate 		    (uint_t)(((uintptr_t)bp->b_un.b_addr) & MMU_PAGEOFFSET);
8390Sstevel@tonic-gate 	} else {
8400Sstevel@tonic-gate 		dmareq.dmar_object.dmao_type = DMA_OTYP_BUFVADDR;
8410Sstevel@tonic-gate 		dmareq.dmar_object.dmao_obj.virt_obj.v_addr = bp->b_un.b_addr;
8421299Scth 		if (bp->b_flags & B_SHADOW) {
8430Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_priv =
8444582Scth 			    bp->b_shadow;
8450Sstevel@tonic-gate 		} else {
8460Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
8470Sstevel@tonic-gate 		}
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate 		/*
8500Sstevel@tonic-gate 		 * If the buffer has no proc pointer, or the proc
8510Sstevel@tonic-gate 		 * struct has the kernel address space, or the buffer has
8520Sstevel@tonic-gate 		 * been marked B_REMAPPED (meaning that it is now
8530Sstevel@tonic-gate 		 * mapped into the kernel's address space), then
8540Sstevel@tonic-gate 		 * the address space is kas (kernel address space).
8550Sstevel@tonic-gate 		 */
8561299Scth 		if ((bp->b_proc == NULL) || (bp->b_proc->p_as == &kas) ||
8571299Scth 		    (bp->b_flags & B_REMAPPED)) {
8580Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_as = 0;
8590Sstevel@tonic-gate 		} else {
8600Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_as =
8610Sstevel@tonic-gate 			    bp->b_proc->p_as;
8620Sstevel@tonic-gate 		}
8630Sstevel@tonic-gate 	}
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 	/*
8660Sstevel@tonic-gate 	 * Handle the case that the requester is both a leaf
8670Sstevel@tonic-gate 	 * and a nexus driver simultaneously by calling the
8680Sstevel@tonic-gate 	 * requester's bus_dma_map function directly instead
8690Sstevel@tonic-gate 	 * of ddi_dma_map.
8700Sstevel@tonic-gate 	 */
8710Sstevel@tonic-gate 	bop = DEVI(dip)->devi_ops->devo_bus_ops;
8720Sstevel@tonic-gate 	if (bop && bop->bus_dma_map)
8730Sstevel@tonic-gate 		funcp = bop->bus_dma_map;
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 	return ((*funcp)(dip, dip, &dmareq, handlep));
8760Sstevel@tonic-gate }
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate #if !defined(__sparc)
8790Sstevel@tonic-gate /*
8800Sstevel@tonic-gate  * Request bus_dma_ctl parent to fiddle with a dma request.
8810Sstevel@tonic-gate  *
8820Sstevel@tonic-gate  * (The sparc version is in sparc_subr.s)
8830Sstevel@tonic-gate  */
8840Sstevel@tonic-gate int
ddi_dma_mctl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,enum ddi_dma_ctlops request,off_t * offp,size_t * lenp,caddr_t * objp,uint_t flags)8850Sstevel@tonic-gate ddi_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
8860Sstevel@tonic-gate     ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
8870Sstevel@tonic-gate     off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags)
8880Sstevel@tonic-gate {
8890Sstevel@tonic-gate 	int (*fp)();
8900Sstevel@tonic-gate 
89110216SVikram.Hegde@Sun.COM 	if (dip != ddi_root_node())
89210216SVikram.Hegde@Sun.COM 		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_ctl;
8930Sstevel@tonic-gate 	fp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_ctl;
8940Sstevel@tonic-gate 	return ((*fp) (dip, rdip, handle, request, offp, lenp, objp, flags));
8950Sstevel@tonic-gate }
8960Sstevel@tonic-gate #endif
8970Sstevel@tonic-gate 
8980Sstevel@tonic-gate /*
8990Sstevel@tonic-gate  * For all DMA control functions, call the DMA control
9000Sstevel@tonic-gate  * routine and return status.
9010Sstevel@tonic-gate  *
9020Sstevel@tonic-gate  * Just plain assume that the parent is to be called.
9030Sstevel@tonic-gate  * If a nexus driver or a thread outside the framework
9040Sstevel@tonic-gate  * of a nexus driver or a leaf driver calls these functions,
9050Sstevel@tonic-gate  * it is up to them to deal with the fact that the parent's
9060Sstevel@tonic-gate  * bus_dma_ctl function will be the first one called.
9070Sstevel@tonic-gate  */
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate #define	HD	((ddi_dma_impl_t *)h)->dmai_rdip
9100Sstevel@tonic-gate 
9110Sstevel@tonic-gate int
ddi_dma_kvaddrp(ddi_dma_handle_t h,off_t off,size_t len,caddr_t * kp)9120Sstevel@tonic-gate ddi_dma_kvaddrp(ddi_dma_handle_t h, off_t off, size_t len, caddr_t *kp)
9130Sstevel@tonic-gate {
9140Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_KVADDR, &off, &len, kp, 0));
9150Sstevel@tonic-gate }
9160Sstevel@tonic-gate 
9170Sstevel@tonic-gate int
ddi_dma_htoc(ddi_dma_handle_t h,off_t o,ddi_dma_cookie_t * c)9180Sstevel@tonic-gate ddi_dma_htoc(ddi_dma_handle_t h, off_t o, ddi_dma_cookie_t *c)
9190Sstevel@tonic-gate {
9200Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_HTOC, &o, 0, (caddr_t *)c, 0));
9210Sstevel@tonic-gate }
9220Sstevel@tonic-gate 
9230Sstevel@tonic-gate int
ddi_dma_coff(ddi_dma_handle_t h,ddi_dma_cookie_t * c,off_t * o)9240Sstevel@tonic-gate ddi_dma_coff(ddi_dma_handle_t h, ddi_dma_cookie_t *c, off_t *o)
9250Sstevel@tonic-gate {
9260Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_COFF,
9270Sstevel@tonic-gate 	    (off_t *)c, 0, (caddr_t *)o, 0));
9280Sstevel@tonic-gate }
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate int
ddi_dma_movwin(ddi_dma_handle_t h,off_t * o,size_t * l,ddi_dma_cookie_t * c)9310Sstevel@tonic-gate ddi_dma_movwin(ddi_dma_handle_t h, off_t *o, size_t *l, ddi_dma_cookie_t *c)
9320Sstevel@tonic-gate {
9330Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_MOVWIN, o,
9340Sstevel@tonic-gate 	    l, (caddr_t *)c, 0));
9350Sstevel@tonic-gate }
9360Sstevel@tonic-gate 
9370Sstevel@tonic-gate int
ddi_dma_curwin(ddi_dma_handle_t h,off_t * o,size_t * l)9380Sstevel@tonic-gate ddi_dma_curwin(ddi_dma_handle_t h, off_t *o, size_t *l)
9390Sstevel@tonic-gate {
9400Sstevel@tonic-gate 	if ((((ddi_dma_impl_t *)h)->dmai_rflags & DDI_DMA_PARTIAL) == 0)
9410Sstevel@tonic-gate 		return (DDI_FAILURE);
9420Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_REPWIN, o, l, 0, 0));
9430Sstevel@tonic-gate }
9440Sstevel@tonic-gate 
9450Sstevel@tonic-gate int
ddi_dma_nextwin(ddi_dma_handle_t h,ddi_dma_win_t win,ddi_dma_win_t * nwin)9460Sstevel@tonic-gate ddi_dma_nextwin(ddi_dma_handle_t h, ddi_dma_win_t win,
9470Sstevel@tonic-gate     ddi_dma_win_t *nwin)
9480Sstevel@tonic-gate {
9490Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_NEXTWIN, (off_t *)&win, 0,
9500Sstevel@tonic-gate 	    (caddr_t *)nwin, 0));
9510Sstevel@tonic-gate }
9520Sstevel@tonic-gate 
9530Sstevel@tonic-gate int
ddi_dma_nextseg(ddi_dma_win_t win,ddi_dma_seg_t seg,ddi_dma_seg_t * nseg)9540Sstevel@tonic-gate ddi_dma_nextseg(ddi_dma_win_t win, ddi_dma_seg_t seg, ddi_dma_seg_t *nseg)
9550Sstevel@tonic-gate {
9560Sstevel@tonic-gate 	ddi_dma_handle_t h = (ddi_dma_handle_t)win;
9570Sstevel@tonic-gate 
9580Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_NEXTSEG, (off_t *)&win,
9590Sstevel@tonic-gate 	    (size_t *)&seg, (caddr_t *)nseg, 0));
9600Sstevel@tonic-gate }
9610Sstevel@tonic-gate 
9620Sstevel@tonic-gate #if (defined(__i386) && !defined(__amd64)) || defined(__sparc)
9630Sstevel@tonic-gate /*
9640Sstevel@tonic-gate  * This routine is Obsolete and should be removed from ALL architectures
9650Sstevel@tonic-gate  * in a future release of Solaris.
9660Sstevel@tonic-gate  *
9670Sstevel@tonic-gate  * It is deliberately NOT ported to amd64; please fix the code that
9680Sstevel@tonic-gate  * depends on this routine to use ddi_dma_nextcookie(9F).
969509Smrj  *
970509Smrj  * NOTE: even though we fixed the pointer through a 32-bit param issue (the fix
971509Smrj  * is a side effect to some other cleanup), we're still not going to support
972509Smrj  * this interface on x64.
9730Sstevel@tonic-gate  */
9740Sstevel@tonic-gate int
ddi_dma_segtocookie(ddi_dma_seg_t seg,off_t * o,off_t * l,ddi_dma_cookie_t * cookiep)9750Sstevel@tonic-gate ddi_dma_segtocookie(ddi_dma_seg_t seg, off_t *o, off_t *l,
9760Sstevel@tonic-gate     ddi_dma_cookie_t *cookiep)
9770Sstevel@tonic-gate {
9780Sstevel@tonic-gate 	ddi_dma_handle_t h = (ddi_dma_handle_t)seg;
9790Sstevel@tonic-gate 
9800Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_SEGTOC, o, (size_t *)l,
9810Sstevel@tonic-gate 	    (caddr_t *)cookiep, 0));
9820Sstevel@tonic-gate }
9830Sstevel@tonic-gate #endif	/* (__i386 && !__amd64) || __sparc */
9840Sstevel@tonic-gate 
9850Sstevel@tonic-gate #if !defined(__sparc)
9860Sstevel@tonic-gate 
9870Sstevel@tonic-gate /*
9880Sstevel@tonic-gate  * The SPARC versions of these routines are done in assembler to
9890Sstevel@tonic-gate  * save register windows, so they're in sparc_subr.s.
9900Sstevel@tonic-gate  */
9910Sstevel@tonic-gate 
9920Sstevel@tonic-gate int
ddi_dma_map(dev_info_t * dip,dev_info_t * rdip,struct ddi_dma_req * dmareqp,ddi_dma_handle_t * handlep)9930Sstevel@tonic-gate ddi_dma_map(dev_info_t *dip, dev_info_t *rdip,
9940Sstevel@tonic-gate 	struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
9950Sstevel@tonic-gate {
9960Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, struct ddi_dma_req *,
9970Sstevel@tonic-gate 	    ddi_dma_handle_t *);
9980Sstevel@tonic-gate 
99910216SVikram.Hegde@Sun.COM 	if (dip != ddi_root_node())
100010216SVikram.Hegde@Sun.COM 		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_map;
100110216SVikram.Hegde@Sun.COM 
100210216SVikram.Hegde@Sun.COM 	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_map;
100310216SVikram.Hegde@Sun.COM 	return ((*funcp)(dip, rdip, dmareqp, handlep));
10040Sstevel@tonic-gate }
10050Sstevel@tonic-gate 
10060Sstevel@tonic-gate int
ddi_dma_allochdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_attr_t * attr,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_handle_t * handlep)10070Sstevel@tonic-gate ddi_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
10080Sstevel@tonic-gate     int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
10090Sstevel@tonic-gate {
10100Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_attr_t *,
10110Sstevel@tonic-gate 	    int (*)(caddr_t), caddr_t, ddi_dma_handle_t *);
10120Sstevel@tonic-gate 
101310216SVikram.Hegde@Sun.COM 	if (dip != ddi_root_node())
101410216SVikram.Hegde@Sun.COM 		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_allochdl;
101510216SVikram.Hegde@Sun.COM 
101610216SVikram.Hegde@Sun.COM 	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_allochdl;
101710216SVikram.Hegde@Sun.COM 	return ((*funcp)(dip, rdip, attr, waitfp, arg, handlep));
10180Sstevel@tonic-gate }
10190Sstevel@tonic-gate 
10200Sstevel@tonic-gate int
ddi_dma_freehdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handlep)10210Sstevel@tonic-gate ddi_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handlep)
10220Sstevel@tonic-gate {
10230Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
10240Sstevel@tonic-gate 
102510216SVikram.Hegde@Sun.COM 	if (dip != ddi_root_node())
102610216SVikram.Hegde@Sun.COM 		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_allochdl;
102710216SVikram.Hegde@Sun.COM 
102810216SVikram.Hegde@Sun.COM 	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_freehdl;
102910216SVikram.Hegde@Sun.COM 	return ((*funcp)(dip, rdip, handlep));
10300Sstevel@tonic-gate }
10310Sstevel@tonic-gate 
10320Sstevel@tonic-gate int
ddi_dma_bindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,struct ddi_dma_req * dmareq,ddi_dma_cookie_t * cp,uint_t * ccountp)10330Sstevel@tonic-gate ddi_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
10340Sstevel@tonic-gate     ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
10350Sstevel@tonic-gate     ddi_dma_cookie_t *cp, uint_t *ccountp)
10360Sstevel@tonic-gate {
10370Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
10380Sstevel@tonic-gate 	    struct ddi_dma_req *, ddi_dma_cookie_t *, uint_t *);
10390Sstevel@tonic-gate 
104010216SVikram.Hegde@Sun.COM 	if (dip != ddi_root_node())
104110216SVikram.Hegde@Sun.COM 		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
104210216SVikram.Hegde@Sun.COM 
104310216SVikram.Hegde@Sun.COM 	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_bindhdl;
104410216SVikram.Hegde@Sun.COM 	return ((*funcp)(dip, rdip, handle, dmareq, cp, ccountp));
10450Sstevel@tonic-gate }
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate int
ddi_dma_unbindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)10480Sstevel@tonic-gate ddi_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
10490Sstevel@tonic-gate     ddi_dma_handle_t handle)
10500Sstevel@tonic-gate {
10510Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
10520Sstevel@tonic-gate 
105310216SVikram.Hegde@Sun.COM 	if (dip != ddi_root_node())
105410216SVikram.Hegde@Sun.COM 		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
105510216SVikram.Hegde@Sun.COM 
105610216SVikram.Hegde@Sun.COM 	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl;
105710216SVikram.Hegde@Sun.COM 	return ((*funcp)(dip, rdip, handle));
10580Sstevel@tonic-gate }
10590Sstevel@tonic-gate 
10600Sstevel@tonic-gate 
10610Sstevel@tonic-gate int
ddi_dma_flush(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,off_t off,size_t len,uint_t cache_flags)10620Sstevel@tonic-gate ddi_dma_flush(dev_info_t *dip, dev_info_t *rdip,
10630Sstevel@tonic-gate     ddi_dma_handle_t handle, off_t off, size_t len,
10640Sstevel@tonic-gate     uint_t cache_flags)
10650Sstevel@tonic-gate {
10660Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
10670Sstevel@tonic-gate 	    off_t, size_t, uint_t);
10680Sstevel@tonic-gate 
106910216SVikram.Hegde@Sun.COM 	if (dip != ddi_root_node())
107010216SVikram.Hegde@Sun.COM 		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_flush;
107110216SVikram.Hegde@Sun.COM 
107210216SVikram.Hegde@Sun.COM 	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_flush;
107310216SVikram.Hegde@Sun.COM 	return ((*funcp)(dip, rdip, handle, off, len, cache_flags));
10740Sstevel@tonic-gate }
10750Sstevel@tonic-gate 
10760Sstevel@tonic-gate int
ddi_dma_win(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,uint_t win,off_t * offp,size_t * lenp,ddi_dma_cookie_t * cookiep,uint_t * ccountp)10770Sstevel@tonic-gate ddi_dma_win(dev_info_t *dip, dev_info_t *rdip,
10780Sstevel@tonic-gate     ddi_dma_handle_t handle, uint_t win, off_t *offp,
10790Sstevel@tonic-gate     size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
10800Sstevel@tonic-gate {
10810Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
10820Sstevel@tonic-gate 	    uint_t, off_t *, size_t *, ddi_dma_cookie_t *, uint_t *);
10830Sstevel@tonic-gate 
108410216SVikram.Hegde@Sun.COM 	if (dip != ddi_root_node())
108510216SVikram.Hegde@Sun.COM 		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_win;
108610216SVikram.Hegde@Sun.COM 
108710216SVikram.Hegde@Sun.COM 	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_win;
108810216SVikram.Hegde@Sun.COM 	return ((*funcp)(dip, rdip, handle, win, offp, lenp,
10890Sstevel@tonic-gate 	    cookiep, ccountp));
10900Sstevel@tonic-gate }
10910Sstevel@tonic-gate 
10920Sstevel@tonic-gate int
ddi_dma_sync(ddi_dma_handle_t h,off_t o,size_t l,uint_t whom)10930Sstevel@tonic-gate ddi_dma_sync(ddi_dma_handle_t h, off_t o, size_t l, uint_t whom)
10940Sstevel@tonic-gate {
10950Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)h;
109610216SVikram.Hegde@Sun.COM 	dev_info_t *dip, *rdip;
10970Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t, off_t,
10984582Scth 	    size_t, uint_t);
10990Sstevel@tonic-gate 
11000Sstevel@tonic-gate 	/*
11010Sstevel@tonic-gate 	 * the DMA nexus driver will set DMP_NOSYNC if the
11020Sstevel@tonic-gate 	 * platform does not require any sync operation. For
11030Sstevel@tonic-gate 	 * example if the memory is uncached or consistent
11040Sstevel@tonic-gate 	 * and without any I/O write buffers involved.
11050Sstevel@tonic-gate 	 */
11060Sstevel@tonic-gate 	if ((hp->dmai_rflags & DMP_NOSYNC) == DMP_NOSYNC)
11070Sstevel@tonic-gate 		return (DDI_SUCCESS);
11080Sstevel@tonic-gate 
110910216SVikram.Hegde@Sun.COM 	dip = rdip = hp->dmai_rdip;
111010216SVikram.Hegde@Sun.COM 	if (dip != ddi_root_node())
111110216SVikram.Hegde@Sun.COM 		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_flush;
111210216SVikram.Hegde@Sun.COM 	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_flush;
111310216SVikram.Hegde@Sun.COM 	return ((*funcp)(dip, rdip, h, o, l, whom));
11140Sstevel@tonic-gate }
11150Sstevel@tonic-gate 
11160Sstevel@tonic-gate int
ddi_dma_unbind_handle(ddi_dma_handle_t h)11170Sstevel@tonic-gate ddi_dma_unbind_handle(ddi_dma_handle_t h)
11180Sstevel@tonic-gate {
11190Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)h;
112010216SVikram.Hegde@Sun.COM 	dev_info_t *dip, *rdip;
11210Sstevel@tonic-gate 	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
11220Sstevel@tonic-gate 
112310216SVikram.Hegde@Sun.COM 	dip = rdip = hp->dmai_rdip;
112410216SVikram.Hegde@Sun.COM 	if (dip != ddi_root_node())
112510216SVikram.Hegde@Sun.COM 		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
112610216SVikram.Hegde@Sun.COM 	funcp = DEVI(rdip)->devi_bus_dma_unbindfunc;
112710216SVikram.Hegde@Sun.COM 	return ((*funcp)(dip, rdip, h));
11280Sstevel@tonic-gate }
11290Sstevel@tonic-gate 
11300Sstevel@tonic-gate #endif	/* !__sparc */
11310Sstevel@tonic-gate 
11320Sstevel@tonic-gate int
ddi_dma_free(ddi_dma_handle_t h)11330Sstevel@tonic-gate ddi_dma_free(ddi_dma_handle_t h)
11340Sstevel@tonic-gate {
11350Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_FREE, 0, 0, 0, 0));
11360Sstevel@tonic-gate }
11370Sstevel@tonic-gate 
11380Sstevel@tonic-gate int
ddi_iopb_alloc(dev_info_t * dip,ddi_dma_lim_t * limp,uint_t len,caddr_t * iopbp)11390Sstevel@tonic-gate ddi_iopb_alloc(dev_info_t *dip, ddi_dma_lim_t *limp, uint_t len, caddr_t *iopbp)
11400Sstevel@tonic-gate {
11410Sstevel@tonic-gate 	ddi_dma_lim_t defalt;
11420Sstevel@tonic-gate 	size_t size = len;
11430Sstevel@tonic-gate 
11440Sstevel@tonic-gate 	if (!limp) {
11450Sstevel@tonic-gate 		defalt = standard_limits;
11460Sstevel@tonic-gate 		limp = &defalt;
11470Sstevel@tonic-gate 	}
11480Sstevel@tonic-gate 	return (i_ddi_mem_alloc_lim(dip, limp, size, 0, 0, 0,
11490Sstevel@tonic-gate 	    iopbp, NULL, NULL));
11500Sstevel@tonic-gate }
11510Sstevel@tonic-gate 
11520Sstevel@tonic-gate void
ddi_iopb_free(caddr_t iopb)11530Sstevel@tonic-gate ddi_iopb_free(caddr_t iopb)
11540Sstevel@tonic-gate {
11551900Seota 	i_ddi_mem_free(iopb, NULL);
11560Sstevel@tonic-gate }
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate int
ddi_mem_alloc(dev_info_t * dip,ddi_dma_lim_t * limits,uint_t length,uint_t flags,caddr_t * kaddrp,uint_t * real_length)11590Sstevel@tonic-gate ddi_mem_alloc(dev_info_t *dip, ddi_dma_lim_t *limits, uint_t length,
11600Sstevel@tonic-gate 	uint_t flags, caddr_t *kaddrp, uint_t *real_length)
11610Sstevel@tonic-gate {
11620Sstevel@tonic-gate 	ddi_dma_lim_t defalt;
11630Sstevel@tonic-gate 	size_t size = length;
11640Sstevel@tonic-gate 
11650Sstevel@tonic-gate 	if (!limits) {
11660Sstevel@tonic-gate 		defalt = standard_limits;
11670Sstevel@tonic-gate 		limits = &defalt;
11680Sstevel@tonic-gate 	}
11690Sstevel@tonic-gate 	return (i_ddi_mem_alloc_lim(dip, limits, size, flags & 0x1,
11700Sstevel@tonic-gate 	    1, 0, kaddrp, real_length, NULL));
11710Sstevel@tonic-gate }
11720Sstevel@tonic-gate 
11730Sstevel@tonic-gate void
ddi_mem_free(caddr_t kaddr)11740Sstevel@tonic-gate ddi_mem_free(caddr_t kaddr)
11750Sstevel@tonic-gate {
11761900Seota 	i_ddi_mem_free(kaddr, NULL);
11770Sstevel@tonic-gate }
11780Sstevel@tonic-gate 
11790Sstevel@tonic-gate /*
11800Sstevel@tonic-gate  * DMA attributes, alignment, burst sizes, and transfer minimums
11810Sstevel@tonic-gate  */
11820Sstevel@tonic-gate int
ddi_dma_get_attr(ddi_dma_handle_t handle,ddi_dma_attr_t * attrp)11830Sstevel@tonic-gate ddi_dma_get_attr(ddi_dma_handle_t handle, ddi_dma_attr_t *attrp)
11840Sstevel@tonic-gate {
11850Sstevel@tonic-gate 	ddi_dma_impl_t *dimp = (ddi_dma_impl_t *)handle;
11860Sstevel@tonic-gate 
11870Sstevel@tonic-gate 	if (attrp == NULL)
11880Sstevel@tonic-gate 		return (DDI_FAILURE);
11890Sstevel@tonic-gate 	*attrp = dimp->dmai_attr;
11900Sstevel@tonic-gate 	return (DDI_SUCCESS);
11910Sstevel@tonic-gate }
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate int
ddi_dma_burstsizes(ddi_dma_handle_t handle)11940Sstevel@tonic-gate ddi_dma_burstsizes(ddi_dma_handle_t handle)
11950Sstevel@tonic-gate {
11960Sstevel@tonic-gate 	ddi_dma_impl_t *dimp = (ddi_dma_impl_t *)handle;
11970Sstevel@tonic-gate 
11980Sstevel@tonic-gate 	if (!dimp)
11990Sstevel@tonic-gate 		return (0);
12000Sstevel@tonic-gate 	else
12010Sstevel@tonic-gate 		return (dimp->dmai_burstsizes);
12020Sstevel@tonic-gate }
12030Sstevel@tonic-gate 
12040Sstevel@tonic-gate int
ddi_dma_devalign(ddi_dma_handle_t handle,uint_t * alignment,uint_t * mineffect)12050Sstevel@tonic-gate ddi_dma_devalign(ddi_dma_handle_t handle, uint_t *alignment, uint_t *mineffect)
12060Sstevel@tonic-gate {
12070Sstevel@tonic-gate 	ddi_dma_impl_t *dimp = (ddi_dma_impl_t *)handle;
12080Sstevel@tonic-gate 
12090Sstevel@tonic-gate 	if (!dimp || !alignment || !mineffect)
12100Sstevel@tonic-gate 		return (DDI_FAILURE);
12110Sstevel@tonic-gate 	if (!(dimp->dmai_rflags & DDI_DMA_SBUS_64BIT)) {
12120Sstevel@tonic-gate 		*alignment = 1 << ddi_ffs(dimp->dmai_burstsizes);
12130Sstevel@tonic-gate 	} else {
12140Sstevel@tonic-gate 		if (dimp->dmai_burstsizes & 0xff0000) {
12150Sstevel@tonic-gate 			*alignment = 1 << ddi_ffs(dimp->dmai_burstsizes >> 16);
12160Sstevel@tonic-gate 		} else {
12170Sstevel@tonic-gate 			*alignment = 1 << ddi_ffs(dimp->dmai_burstsizes);
12180Sstevel@tonic-gate 		}
12190Sstevel@tonic-gate 	}
12200Sstevel@tonic-gate 	*mineffect = dimp->dmai_minxfer;
12210Sstevel@tonic-gate 	return (DDI_SUCCESS);
12220Sstevel@tonic-gate }
12230Sstevel@tonic-gate 
12240Sstevel@tonic-gate int
ddi_iomin(dev_info_t * a,int i,int stream)12250Sstevel@tonic-gate ddi_iomin(dev_info_t *a, int i, int stream)
12260Sstevel@tonic-gate {
12270Sstevel@tonic-gate 	int r;
12280Sstevel@tonic-gate 
12290Sstevel@tonic-gate 	/*
12300Sstevel@tonic-gate 	 * Make sure that the initial value is sane
12310Sstevel@tonic-gate 	 */
12320Sstevel@tonic-gate 	if (i & (i - 1))
12330Sstevel@tonic-gate 		return (0);
12340Sstevel@tonic-gate 	if (i == 0)
12350Sstevel@tonic-gate 		i = (stream) ? 4 : 1;
12360Sstevel@tonic-gate 
12370Sstevel@tonic-gate 	r = ddi_ctlops(a, a,
12380Sstevel@tonic-gate 	    DDI_CTLOPS_IOMIN, (void *)(uintptr_t)stream, (void *)&i);
12390Sstevel@tonic-gate 	if (r != DDI_SUCCESS || (i & (i - 1)))
12400Sstevel@tonic-gate 		return (0);
12410Sstevel@tonic-gate 	return (i);
12420Sstevel@tonic-gate }
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate /*
12450Sstevel@tonic-gate  * Given two DMA attribute structures, apply the attributes
12460Sstevel@tonic-gate  * of one to the other, following the rules of attributes
12470Sstevel@tonic-gate  * and the wishes of the caller.
12480Sstevel@tonic-gate  *
12490Sstevel@tonic-gate  * The rules of DMA attribute structures are that you cannot
12500Sstevel@tonic-gate  * make things *less* restrictive as you apply one set
12510Sstevel@tonic-gate  * of attributes to another.
12520Sstevel@tonic-gate  *
12530Sstevel@tonic-gate  */
12540Sstevel@tonic-gate void
ddi_dma_attr_merge(ddi_dma_attr_t * attr,ddi_dma_attr_t * mod)12550Sstevel@tonic-gate ddi_dma_attr_merge(ddi_dma_attr_t *attr, ddi_dma_attr_t *mod)
12560Sstevel@tonic-gate {
12570Sstevel@tonic-gate 	attr->dma_attr_addr_lo =
12580Sstevel@tonic-gate 	    MAX(attr->dma_attr_addr_lo, mod->dma_attr_addr_lo);
12590Sstevel@tonic-gate 	attr->dma_attr_addr_hi =
12600Sstevel@tonic-gate 	    MIN(attr->dma_attr_addr_hi, mod->dma_attr_addr_hi);
12610Sstevel@tonic-gate 	attr->dma_attr_count_max =
12620Sstevel@tonic-gate 	    MIN(attr->dma_attr_count_max, mod->dma_attr_count_max);
12630Sstevel@tonic-gate 	attr->dma_attr_align =
12640Sstevel@tonic-gate 	    MAX(attr->dma_attr_align,  mod->dma_attr_align);
12650Sstevel@tonic-gate 	attr->dma_attr_burstsizes =
12660Sstevel@tonic-gate 	    (uint_t)(attr->dma_attr_burstsizes & mod->dma_attr_burstsizes);
12670Sstevel@tonic-gate 	attr->dma_attr_minxfer =
12680Sstevel@tonic-gate 	    maxbit(attr->dma_attr_minxfer, mod->dma_attr_minxfer);
12690Sstevel@tonic-gate 	attr->dma_attr_maxxfer =
12700Sstevel@tonic-gate 	    MIN(attr->dma_attr_maxxfer, mod->dma_attr_maxxfer);
12710Sstevel@tonic-gate 	attr->dma_attr_seg = MIN(attr->dma_attr_seg, mod->dma_attr_seg);
12720Sstevel@tonic-gate 	attr->dma_attr_sgllen = MIN((uint_t)attr->dma_attr_sgllen,
12730Sstevel@tonic-gate 	    (uint_t)mod->dma_attr_sgllen);
12740Sstevel@tonic-gate 	attr->dma_attr_granular =
12750Sstevel@tonic-gate 	    MAX(attr->dma_attr_granular, mod->dma_attr_granular);
12760Sstevel@tonic-gate }
12770Sstevel@tonic-gate 
12780Sstevel@tonic-gate /*
12790Sstevel@tonic-gate  * mmap/segmap interface:
12800Sstevel@tonic-gate  */
12810Sstevel@tonic-gate 
12820Sstevel@tonic-gate /*
12830Sstevel@tonic-gate  * ddi_segmap:		setup the default segment driver. Calls the drivers
12840Sstevel@tonic-gate  *			XXmmap routine to validate the range to be mapped.
12850Sstevel@tonic-gate  *			Return ENXIO of the range is not valid.  Create
12860Sstevel@tonic-gate  *			a seg_dev segment that contains all of the
12870Sstevel@tonic-gate  *			necessary information and will reference the
12880Sstevel@tonic-gate  *			default segment driver routines. It returns zero
12890Sstevel@tonic-gate  *			on success or non-zero on failure.
12900Sstevel@tonic-gate  */
12910Sstevel@tonic-gate int
ddi_segmap(dev_t dev,off_t offset,struct as * asp,caddr_t * addrp,off_t len,uint_t prot,uint_t maxprot,uint_t flags,cred_t * credp)12920Sstevel@tonic-gate ddi_segmap(dev_t dev, off_t offset, struct as *asp, caddr_t *addrp, off_t len,
12930Sstevel@tonic-gate     uint_t prot, uint_t maxprot, uint_t flags, cred_t *credp)
12940Sstevel@tonic-gate {
12950Sstevel@tonic-gate 	extern int spec_segmap(dev_t, off_t, struct as *, caddr_t *,
12960Sstevel@tonic-gate 	    off_t, uint_t, uint_t, uint_t, struct cred *);
12970Sstevel@tonic-gate 
12980Sstevel@tonic-gate 	return (spec_segmap(dev, offset, asp, addrp, len,
12990Sstevel@tonic-gate 	    prot, maxprot, flags, credp));
13000Sstevel@tonic-gate }
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate /*
13030Sstevel@tonic-gate  * ddi_map_fault:	Resolve mappings at fault time.  Used by segment
13040Sstevel@tonic-gate  *			drivers. Allows each successive parent to resolve
13050Sstevel@tonic-gate  *			address translations and add its mappings to the
13060Sstevel@tonic-gate  *			mapping list supplied in the page structure. It
13070Sstevel@tonic-gate  *			returns zero on success	or non-zero on failure.
13080Sstevel@tonic-gate  */
13090Sstevel@tonic-gate 
13100Sstevel@tonic-gate int
ddi_map_fault(dev_info_t * dip,struct hat * hat,struct seg * seg,caddr_t addr,struct devpage * dp,pfn_t pfn,uint_t prot,uint_t lock)13110Sstevel@tonic-gate ddi_map_fault(dev_info_t *dip, struct hat *hat, struct seg *seg,
13120Sstevel@tonic-gate     caddr_t addr, struct devpage *dp, pfn_t pfn, uint_t prot, uint_t lock)
13130Sstevel@tonic-gate {
13140Sstevel@tonic-gate 	return (i_ddi_map_fault(dip, dip, hat, seg, addr, dp, pfn, prot, lock));
13150Sstevel@tonic-gate }
13160Sstevel@tonic-gate 
13170Sstevel@tonic-gate /*
13180Sstevel@tonic-gate  * ddi_device_mapping_check:	Called from ddi_segmap_setup.
13190Sstevel@tonic-gate  *	Invokes platform specific DDI to determine whether attributes specified
13200Sstevel@tonic-gate  *	in attr(9s) are	valid for the region of memory that will be made
13210Sstevel@tonic-gate  *	available for direct access to user process via the mmap(2) system call.
13220Sstevel@tonic-gate  */
13230Sstevel@tonic-gate int
ddi_device_mapping_check(dev_t dev,ddi_device_acc_attr_t * accattrp,uint_t rnumber,uint_t * hat_flags)13240Sstevel@tonic-gate ddi_device_mapping_check(dev_t dev, ddi_device_acc_attr_t *accattrp,
13250Sstevel@tonic-gate     uint_t rnumber, uint_t *hat_flags)
13260Sstevel@tonic-gate {
13270Sstevel@tonic-gate 	ddi_acc_handle_t handle;
13280Sstevel@tonic-gate 	ddi_map_req_t mr;
13290Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
13300Sstevel@tonic-gate 	int result;
13310Sstevel@tonic-gate 	dev_info_t *dip;
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 	/*
13340Sstevel@tonic-gate 	 * we use e_ddi_hold_devi_by_dev to search for the devi.  We
13350Sstevel@tonic-gate 	 * release it immediately since it should already be held by
13360Sstevel@tonic-gate 	 * a devfs vnode.
13370Sstevel@tonic-gate 	 */
13380Sstevel@tonic-gate 	if ((dip =
13390Sstevel@tonic-gate 	    e_ddi_hold_devi_by_dev(dev, E_DDI_HOLD_DEVI_NOATTACH)) == NULL)
13400Sstevel@tonic-gate 		return (-1);
13410Sstevel@tonic-gate 	ddi_release_devi(dip);		/* for e_ddi_hold_devi_by_dev() */
13420Sstevel@tonic-gate 
13430Sstevel@tonic-gate 	/*
13440Sstevel@tonic-gate 	 * Allocate and initialize the common elements of data
13450Sstevel@tonic-gate 	 * access handle.
13460Sstevel@tonic-gate 	 */
13470Sstevel@tonic-gate 	handle = impl_acc_hdl_alloc(KM_SLEEP, NULL);
13480Sstevel@tonic-gate 	if (handle == NULL)
13490Sstevel@tonic-gate 		return (-1);
13500Sstevel@tonic-gate 
13510Sstevel@tonic-gate 	hp = impl_acc_hdl_get(handle);
13520Sstevel@tonic-gate 	hp->ah_vers = VERS_ACCHDL;
13530Sstevel@tonic-gate 	hp->ah_dip = dip;
13540Sstevel@tonic-gate 	hp->ah_rnumber = rnumber;
13550Sstevel@tonic-gate 	hp->ah_offset = 0;
13560Sstevel@tonic-gate 	hp->ah_len = 0;
13570Sstevel@tonic-gate 	hp->ah_acc = *accattrp;
13580Sstevel@tonic-gate 
13590Sstevel@tonic-gate 	/*
13600Sstevel@tonic-gate 	 * Set up the mapping request and call to parent.
13610Sstevel@tonic-gate 	 */
13620Sstevel@tonic-gate 	mr.map_op = DDI_MO_MAP_HANDLE;
13630Sstevel@tonic-gate 	mr.map_type = DDI_MT_RNUMBER;
13640Sstevel@tonic-gate 	mr.map_obj.rnumber = rnumber;
13650Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
13660Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
13670Sstevel@tonic-gate 	mr.map_handlep = hp;
13680Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
13690Sstevel@tonic-gate 	result = ddi_map(dip, &mr, 0, 0, NULL);
13700Sstevel@tonic-gate 
13710Sstevel@tonic-gate 	/*
13720Sstevel@tonic-gate 	 * Region must be mappable, pick up flags from the framework.
13730Sstevel@tonic-gate 	 */
13740Sstevel@tonic-gate 	*hat_flags = hp->ah_hat_flags;
13750Sstevel@tonic-gate 
13760Sstevel@tonic-gate 	impl_acc_hdl_free(handle);
13770Sstevel@tonic-gate 
13780Sstevel@tonic-gate 	/*
13790Sstevel@tonic-gate 	 * check for end result.
13800Sstevel@tonic-gate 	 */
13810Sstevel@tonic-gate 	if (result != DDI_SUCCESS)
13820Sstevel@tonic-gate 		return (-1);
13830Sstevel@tonic-gate 	return (0);
13840Sstevel@tonic-gate }
13850Sstevel@tonic-gate 
13860Sstevel@tonic-gate 
13870Sstevel@tonic-gate /*
13880Sstevel@tonic-gate  * Property functions:	 See also, ddipropdefs.h.
13890Sstevel@tonic-gate  *
13900Sstevel@tonic-gate  * These functions are the framework for the property functions,
13910Sstevel@tonic-gate  * i.e. they support software defined properties.  All implementation
13920Sstevel@tonic-gate  * specific property handling (i.e.: self-identifying devices and
13930Sstevel@tonic-gate  * PROM defined properties are handled in the implementation specific
13940Sstevel@tonic-gate  * functions (defined in ddi_implfuncs.h).
13950Sstevel@tonic-gate  */
13960Sstevel@tonic-gate 
13970Sstevel@tonic-gate /*
13980Sstevel@tonic-gate  * nopropop:	Shouldn't be called, right?
13990Sstevel@tonic-gate  */
14000Sstevel@tonic-gate int
nopropop(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)14010Sstevel@tonic-gate nopropop(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
14020Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
14030Sstevel@tonic-gate {
14040Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dev, dip, prop_op, mod_flags, name, valuep, lengthp))
14050Sstevel@tonic-gate 	return (DDI_PROP_NOT_FOUND);
14060Sstevel@tonic-gate }
14070Sstevel@tonic-gate 
14080Sstevel@tonic-gate #ifdef	DDI_PROP_DEBUG
14090Sstevel@tonic-gate int ddi_prop_debug_flag = 0;
14100Sstevel@tonic-gate 
14110Sstevel@tonic-gate int
ddi_prop_debug(int enable)14120Sstevel@tonic-gate ddi_prop_debug(int enable)
14130Sstevel@tonic-gate {
14140Sstevel@tonic-gate 	int prev = ddi_prop_debug_flag;
14150Sstevel@tonic-gate 
14160Sstevel@tonic-gate 	if ((enable != 0) || (prev != 0))
14170Sstevel@tonic-gate 		printf("ddi_prop_debug: debugging %s\n",
14180Sstevel@tonic-gate 		    enable ? "enabled" : "disabled");
14190Sstevel@tonic-gate 	ddi_prop_debug_flag = enable;
14200Sstevel@tonic-gate 	return (prev);
14210Sstevel@tonic-gate }
14220Sstevel@tonic-gate 
14230Sstevel@tonic-gate #endif	/* DDI_PROP_DEBUG */
14240Sstevel@tonic-gate 
14250Sstevel@tonic-gate /*
14260Sstevel@tonic-gate  * Search a property list for a match, if found return pointer
14270Sstevel@tonic-gate  * to matching prop struct, else return NULL.
14280Sstevel@tonic-gate  */
14290Sstevel@tonic-gate 
14300Sstevel@tonic-gate ddi_prop_t *
i_ddi_prop_search(dev_t dev,char * name,uint_t flags,ddi_prop_t ** list_head)14310Sstevel@tonic-gate i_ddi_prop_search(dev_t dev, char *name, uint_t flags, ddi_prop_t **list_head)
14320Sstevel@tonic-gate {
14330Sstevel@tonic-gate 	ddi_prop_t	*propp;
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	/*
14360Sstevel@tonic-gate 	 * find the property in child's devinfo:
1437168Scth 	 * Search order defined by this search function is first matching
1438168Scth 	 * property with input dev == DDI_DEV_T_ANY matching any dev or
1439168Scth 	 * dev == propp->prop_dev, name == propp->name, and the correct
1440168Scth 	 * data type as specified in the flags.  If a DDI_DEV_T_NONE dev
1441168Scth 	 * value made it this far then it implies a DDI_DEV_T_ANY search.
1442168Scth 	 */
1443168Scth 	if (dev == DDI_DEV_T_NONE)
1444168Scth 		dev = DDI_DEV_T_ANY;
14450Sstevel@tonic-gate 
14460Sstevel@tonic-gate 	for (propp = *list_head; propp != NULL; propp = propp->prop_next)  {
14470Sstevel@tonic-gate 
1448164Scth 		if (!DDI_STRSAME(propp->prop_name, name))
14490Sstevel@tonic-gate 			continue;
14500Sstevel@tonic-gate 
14510Sstevel@tonic-gate 		if ((dev != DDI_DEV_T_ANY) && (propp->prop_dev != dev))
14520Sstevel@tonic-gate 			continue;
14530Sstevel@tonic-gate 
14540Sstevel@tonic-gate 		if (((propp->prop_flags & flags) & DDI_PROP_TYPE_MASK) == 0)
14550Sstevel@tonic-gate 			continue;
14560Sstevel@tonic-gate 
14570Sstevel@tonic-gate 		return (propp);
14580Sstevel@tonic-gate 	}
14590Sstevel@tonic-gate 
14600Sstevel@tonic-gate 	return ((ddi_prop_t *)0);
14610Sstevel@tonic-gate }
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate /*
14640Sstevel@tonic-gate  * Search for property within devnames structures
14650Sstevel@tonic-gate  */
14660Sstevel@tonic-gate ddi_prop_t *
i_ddi_search_global_prop(dev_t dev,char * name,uint_t flags)14670Sstevel@tonic-gate i_ddi_search_global_prop(dev_t dev, char *name, uint_t flags)
14680Sstevel@tonic-gate {
14690Sstevel@tonic-gate 	major_t		major;
14700Sstevel@tonic-gate 	struct devnames	*dnp;
14710Sstevel@tonic-gate 	ddi_prop_t	*propp;
14720Sstevel@tonic-gate 
14730Sstevel@tonic-gate 	/*
14740Sstevel@tonic-gate 	 * Valid dev_t value is needed to index into the
14750Sstevel@tonic-gate 	 * correct devnames entry, therefore a dev_t
14760Sstevel@tonic-gate 	 * value of DDI_DEV_T_ANY is not appropriate.
14770Sstevel@tonic-gate 	 */
14780Sstevel@tonic-gate 	ASSERT(dev != DDI_DEV_T_ANY);
14790Sstevel@tonic-gate 	if (dev == DDI_DEV_T_ANY) {
14800Sstevel@tonic-gate 		return ((ddi_prop_t *)0);
14810Sstevel@tonic-gate 	}
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	major = getmajor(dev);
14840Sstevel@tonic-gate 	dnp = &(devnamesp[major]);
14850Sstevel@tonic-gate 
14860Sstevel@tonic-gate 	if (dnp->dn_global_prop_ptr == NULL)
14870Sstevel@tonic-gate 		return ((ddi_prop_t *)0);
14880Sstevel@tonic-gate 
14890Sstevel@tonic-gate 	LOCK_DEV_OPS(&dnp->dn_lock);
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate 	for (propp = dnp->dn_global_prop_ptr->prop_list;
14920Sstevel@tonic-gate 	    propp != NULL;
14930Sstevel@tonic-gate 	    propp = (ddi_prop_t *)propp->prop_next) {
14940Sstevel@tonic-gate 
1495164Scth 		if (!DDI_STRSAME(propp->prop_name, name))
14960Sstevel@tonic-gate 			continue;
14970Sstevel@tonic-gate 
14988371SVikram.Hegde@Sun.COM 		if ((!(flags & DDI_PROP_ROOTNEX_GLOBAL)) &&
14998371SVikram.Hegde@Sun.COM 		    (!(flags & LDI_DEV_T_ANY)) && (propp->prop_dev != dev))
15000Sstevel@tonic-gate 			continue;
15010Sstevel@tonic-gate 
15020Sstevel@tonic-gate 		if (((propp->prop_flags & flags) & DDI_PROP_TYPE_MASK) == 0)
15030Sstevel@tonic-gate 			continue;
15040Sstevel@tonic-gate 
15050Sstevel@tonic-gate 		/* Property found, return it */
15060Sstevel@tonic-gate 		UNLOCK_DEV_OPS(&dnp->dn_lock);
15070Sstevel@tonic-gate 		return (propp);
15080Sstevel@tonic-gate 	}
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	UNLOCK_DEV_OPS(&dnp->dn_lock);
15110Sstevel@tonic-gate 	return ((ddi_prop_t *)0);
15120Sstevel@tonic-gate }
15130Sstevel@tonic-gate 
15140Sstevel@tonic-gate static char prop_no_mem_msg[] = "can't allocate memory for ddi property <%s>";
15150Sstevel@tonic-gate 
15160Sstevel@tonic-gate /*
15170Sstevel@tonic-gate  * ddi_prop_search_global:
15180Sstevel@tonic-gate  *	Search the global property list within devnames
15190Sstevel@tonic-gate  *	for the named property.  Return the encoded value.
15200Sstevel@tonic-gate  */
15210Sstevel@tonic-gate static int
i_ddi_prop_search_global(dev_t dev,uint_t flags,char * name,void * valuep,uint_t * lengthp)15220Sstevel@tonic-gate i_ddi_prop_search_global(dev_t dev, uint_t flags, char *name,
15230Sstevel@tonic-gate     void *valuep, uint_t *lengthp)
15240Sstevel@tonic-gate {
15250Sstevel@tonic-gate 	ddi_prop_t	*propp;
15260Sstevel@tonic-gate 	caddr_t		buffer;
15270Sstevel@tonic-gate 
15280Sstevel@tonic-gate 	propp =  i_ddi_search_global_prop(dev, name, flags);
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 	/* Property NOT found, bail */
15310Sstevel@tonic-gate 	if (propp == (ddi_prop_t *)0)
15320Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
15330Sstevel@tonic-gate 
15340Sstevel@tonic-gate 	if (propp->prop_flags & DDI_PROP_UNDEF_IT)
15350Sstevel@tonic-gate 		return (DDI_PROP_UNDEFINED);
15360Sstevel@tonic-gate 
1537497Scth 	if ((buffer = kmem_alloc(propp->prop_len,
1538497Scth 	    (flags & DDI_PROP_CANSLEEP) ? KM_SLEEP : KM_NOSLEEP)) == NULL) {
15390Sstevel@tonic-gate 		cmn_err(CE_CONT, prop_no_mem_msg, name);
15400Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
15410Sstevel@tonic-gate 	}
15420Sstevel@tonic-gate 
15430Sstevel@tonic-gate 	/*
15440Sstevel@tonic-gate 	 * Return the encoded data
15450Sstevel@tonic-gate 	 */
15460Sstevel@tonic-gate 	*(caddr_t *)valuep = buffer;
15470Sstevel@tonic-gate 	*lengthp = propp->prop_len;
15480Sstevel@tonic-gate 	bcopy(propp->prop_val, buffer, propp->prop_len);
15490Sstevel@tonic-gate 
15500Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
15510Sstevel@tonic-gate }
15520Sstevel@tonic-gate 
15530Sstevel@tonic-gate /*
15540Sstevel@tonic-gate  * ddi_prop_search_common:	Lookup and return the encoded value
15550Sstevel@tonic-gate  */
15560Sstevel@tonic-gate int
ddi_prop_search_common(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,uint_t flags,char * name,void * valuep,uint_t * lengthp)15570Sstevel@tonic-gate ddi_prop_search_common(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
15580Sstevel@tonic-gate     uint_t flags, char *name, void *valuep, uint_t *lengthp)
15590Sstevel@tonic-gate {
15600Sstevel@tonic-gate 	ddi_prop_t	*propp;
15610Sstevel@tonic-gate 	int		i;
15620Sstevel@tonic-gate 	caddr_t		buffer;
15630Sstevel@tonic-gate 	caddr_t		prealloc = NULL;
15640Sstevel@tonic-gate 	int		plength = 0;
15650Sstevel@tonic-gate 	dev_info_t	*pdip;
15660Sstevel@tonic-gate 	int		(*bop)();
15670Sstevel@tonic-gate 
15680Sstevel@tonic-gate 	/*CONSTANTCONDITION*/
15690Sstevel@tonic-gate 	while (1)  {
15700Sstevel@tonic-gate 
15710Sstevel@tonic-gate 		mutex_enter(&(DEVI(dip)->devi_lock));
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 
15740Sstevel@tonic-gate 		/*
15750Sstevel@tonic-gate 		 * find the property in child's devinfo:
15760Sstevel@tonic-gate 		 * Search order is:
15770Sstevel@tonic-gate 		 *	1. driver defined properties
15780Sstevel@tonic-gate 		 *	2. system defined properties
15790Sstevel@tonic-gate 		 *	3. driver global properties
15800Sstevel@tonic-gate 		 *	4. boot defined properties
15810Sstevel@tonic-gate 		 */
15820Sstevel@tonic-gate 
15830Sstevel@tonic-gate 		propp = i_ddi_prop_search(dev, name, flags,
15840Sstevel@tonic-gate 		    &(DEVI(dip)->devi_drv_prop_ptr));
15850Sstevel@tonic-gate 		if (propp == NULL)  {
15860Sstevel@tonic-gate 			propp = i_ddi_prop_search(dev, name, flags,
15870Sstevel@tonic-gate 			    &(DEVI(dip)->devi_sys_prop_ptr));
15880Sstevel@tonic-gate 		}
15890Sstevel@tonic-gate 		if ((propp == NULL) && DEVI(dip)->devi_global_prop_list) {
15900Sstevel@tonic-gate 			propp = i_ddi_prop_search(dev, name, flags,
15910Sstevel@tonic-gate 			    &DEVI(dip)->devi_global_prop_list->prop_list);
15920Sstevel@tonic-gate 		}
15930Sstevel@tonic-gate 
15940Sstevel@tonic-gate 		if (propp == NULL)  {
15950Sstevel@tonic-gate 			propp = i_ddi_prop_search(dev, name, flags,
15960Sstevel@tonic-gate 			    &(DEVI(dip)->devi_hw_prop_ptr));
15970Sstevel@tonic-gate 		}
15980Sstevel@tonic-gate 
15990Sstevel@tonic-gate 		/*
16000Sstevel@tonic-gate 		 * Software property found?
16010Sstevel@tonic-gate 		 */
16020Sstevel@tonic-gate 		if (propp != (ddi_prop_t *)0)	{
16030Sstevel@tonic-gate 
16040Sstevel@tonic-gate 			/*
16050Sstevel@tonic-gate 			 * If explicit undefine, return now.
16060Sstevel@tonic-gate 			 */
16070Sstevel@tonic-gate 			if (propp->prop_flags & DDI_PROP_UNDEF_IT) {
16080Sstevel@tonic-gate 				mutex_exit(&(DEVI(dip)->devi_lock));
16090Sstevel@tonic-gate 				if (prealloc)
16100Sstevel@tonic-gate 					kmem_free(prealloc, plength);
16110Sstevel@tonic-gate 				return (DDI_PROP_UNDEFINED);
16120Sstevel@tonic-gate 			}
16130Sstevel@tonic-gate 
16140Sstevel@tonic-gate 			/*
16150Sstevel@tonic-gate 			 * If we only want to know if it exists, return now
16160Sstevel@tonic-gate 			 */
16170Sstevel@tonic-gate 			if (prop_op == PROP_EXISTS) {
16180Sstevel@tonic-gate 				mutex_exit(&(DEVI(dip)->devi_lock));
16190Sstevel@tonic-gate 				ASSERT(prealloc == NULL);
16200Sstevel@tonic-gate 				return (DDI_PROP_SUCCESS);
16210Sstevel@tonic-gate 			}
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate 			/*
16240Sstevel@tonic-gate 			 * If length only request or prop length == 0,
16250Sstevel@tonic-gate 			 * service request and return now.
16260Sstevel@tonic-gate 			 */
16270Sstevel@tonic-gate 			if ((prop_op == PROP_LEN) ||(propp->prop_len == 0)) {
16280Sstevel@tonic-gate 				*lengthp = propp->prop_len;
16290Sstevel@tonic-gate 
16300Sstevel@tonic-gate 				/*
16310Sstevel@tonic-gate 				 * if prop_op is PROP_LEN_AND_VAL_ALLOC
16320Sstevel@tonic-gate 				 * that means prop_len is 0, so set valuep
16330Sstevel@tonic-gate 				 * also to NULL
16340Sstevel@tonic-gate 				 */
16350Sstevel@tonic-gate 				if (prop_op == PROP_LEN_AND_VAL_ALLOC)
16360Sstevel@tonic-gate 					*(caddr_t *)valuep = NULL;
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate 				mutex_exit(&(DEVI(dip)->devi_lock));
16390Sstevel@tonic-gate 				if (prealloc)
16400Sstevel@tonic-gate 					kmem_free(prealloc, plength);
16410Sstevel@tonic-gate 				return (DDI_PROP_SUCCESS);
16420Sstevel@tonic-gate 			}
16430Sstevel@tonic-gate 
16440Sstevel@tonic-gate 			/*
16450Sstevel@tonic-gate 			 * If LEN_AND_VAL_ALLOC and the request can sleep,
16460Sstevel@tonic-gate 			 * drop the mutex, allocate the buffer, and go
16470Sstevel@tonic-gate 			 * through the loop again.  If we already allocated
16480Sstevel@tonic-gate 			 * the buffer, and the size of the property changed,
16490Sstevel@tonic-gate 			 * keep trying...
16500Sstevel@tonic-gate 			 */
16510Sstevel@tonic-gate 			if ((prop_op == PROP_LEN_AND_VAL_ALLOC) &&
16520Sstevel@tonic-gate 			    (flags & DDI_PROP_CANSLEEP))  {
16530Sstevel@tonic-gate 				if (prealloc && (propp->prop_len != plength)) {
16540Sstevel@tonic-gate 					kmem_free(prealloc, plength);
16550Sstevel@tonic-gate 					prealloc = NULL;
16560Sstevel@tonic-gate 				}
16570Sstevel@tonic-gate 				if (prealloc == NULL)  {
16580Sstevel@tonic-gate 					plength = propp->prop_len;
16590Sstevel@tonic-gate 					mutex_exit(&(DEVI(dip)->devi_lock));
16600Sstevel@tonic-gate 					prealloc = kmem_alloc(plength,
16610Sstevel@tonic-gate 					    KM_SLEEP);
16620Sstevel@tonic-gate 					continue;
16630Sstevel@tonic-gate 				}
16640Sstevel@tonic-gate 			}
16650Sstevel@tonic-gate 
16660Sstevel@tonic-gate 			/*
16670Sstevel@tonic-gate 			 * Allocate buffer, if required.  Either way,
16680Sstevel@tonic-gate 			 * set `buffer' variable.
16690Sstevel@tonic-gate 			 */
16700Sstevel@tonic-gate 			i = *lengthp;			/* Get callers length */
16710Sstevel@tonic-gate 			*lengthp = propp->prop_len;	/* Set callers length */
16720Sstevel@tonic-gate 
16730Sstevel@tonic-gate 			switch (prop_op) {
16740Sstevel@tonic-gate 
16750Sstevel@tonic-gate 			case PROP_LEN_AND_VAL_ALLOC:
16760Sstevel@tonic-gate 
16770Sstevel@tonic-gate 				if (prealloc == NULL) {
16780Sstevel@tonic-gate 					buffer = kmem_alloc(propp->prop_len,
16790Sstevel@tonic-gate 					    KM_NOSLEEP);
16800Sstevel@tonic-gate 				} else {
16810Sstevel@tonic-gate 					buffer = prealloc;
16820Sstevel@tonic-gate 				}
16830Sstevel@tonic-gate 
16840Sstevel@tonic-gate 				if (buffer == NULL)  {
16850Sstevel@tonic-gate 					mutex_exit(&(DEVI(dip)->devi_lock));
16860Sstevel@tonic-gate 					cmn_err(CE_CONT, prop_no_mem_msg, name);
16870Sstevel@tonic-gate 					return (DDI_PROP_NO_MEMORY);
16880Sstevel@tonic-gate 				}
16890Sstevel@tonic-gate 				/* Set callers buf ptr */
16900Sstevel@tonic-gate 				*(caddr_t *)valuep = buffer;
16910Sstevel@tonic-gate 				break;
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate 			case PROP_LEN_AND_VAL_BUF:
16940Sstevel@tonic-gate 
16950Sstevel@tonic-gate 				if (propp->prop_len > (i)) {
16960Sstevel@tonic-gate 					mutex_exit(&(DEVI(dip)->devi_lock));
16970Sstevel@tonic-gate 					return (DDI_PROP_BUF_TOO_SMALL);
16980Sstevel@tonic-gate 				}
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate 				buffer = valuep;  /* Get callers buf ptr */
17010Sstevel@tonic-gate 				break;
17020Sstevel@tonic-gate 
17030Sstevel@tonic-gate 			default:
17040Sstevel@tonic-gate 				break;
17050Sstevel@tonic-gate 			}
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate 			/*
17080Sstevel@tonic-gate 			 * Do the copy.
17090Sstevel@tonic-gate 			 */
17100Sstevel@tonic-gate 			bcopy(propp->prop_val, buffer, propp->prop_len);
17110Sstevel@tonic-gate 			mutex_exit(&(DEVI(dip)->devi_lock));
17120Sstevel@tonic-gate 			return (DDI_PROP_SUCCESS);
17130Sstevel@tonic-gate 		}
17140Sstevel@tonic-gate 
17150Sstevel@tonic-gate 		mutex_exit(&(DEVI(dip)->devi_lock));
17160Sstevel@tonic-gate 		if (prealloc)
17170Sstevel@tonic-gate 			kmem_free(prealloc, plength);
17180Sstevel@tonic-gate 		prealloc = NULL;
17190Sstevel@tonic-gate 
17200Sstevel@tonic-gate 		/*
17210Sstevel@tonic-gate 		 * Prop not found, call parent bus_ops to deal with possible
17220Sstevel@tonic-gate 		 * h/w layer (possible PROM defined props, etc.) and to
17230Sstevel@tonic-gate 		 * possibly ascend the hierarchy, if allowed by flags.
17240Sstevel@tonic-gate 		 */
17250Sstevel@tonic-gate 		pdip = (dev_info_t *)DEVI(dip)->devi_parent;
17260Sstevel@tonic-gate 
17270Sstevel@tonic-gate 		/*
17280Sstevel@tonic-gate 		 * One last call for the root driver PROM props?
17290Sstevel@tonic-gate 		 */
17300Sstevel@tonic-gate 		if (dip == ddi_root_node())  {
17310Sstevel@tonic-gate 			return (ddi_bus_prop_op(dev, dip, dip, prop_op,
17320Sstevel@tonic-gate 			    flags, name, valuep, (int *)lengthp));
17330Sstevel@tonic-gate 		}
17340Sstevel@tonic-gate 
17350Sstevel@tonic-gate 		/*
17360Sstevel@tonic-gate 		 * We may have been called to check for properties
17370Sstevel@tonic-gate 		 * within a single devinfo node that has no parent -
17380Sstevel@tonic-gate 		 * see make_prop()
17390Sstevel@tonic-gate 		 */
17400Sstevel@tonic-gate 		if (pdip == NULL) {
17410Sstevel@tonic-gate 			ASSERT((flags &
17420Sstevel@tonic-gate 			    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM)) ==
17430Sstevel@tonic-gate 			    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM));
17440Sstevel@tonic-gate 			return (DDI_PROP_NOT_FOUND);
17450Sstevel@tonic-gate 		}
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 		/*
17480Sstevel@tonic-gate 		 * Instead of recursing, we do iterative calls up the tree.
17490Sstevel@tonic-gate 		 * As a bit of optimization, skip the bus_op level if the
17500Sstevel@tonic-gate 		 * node is a s/w node and if the parent's bus_prop_op function
17510Sstevel@tonic-gate 		 * is `ddi_bus_prop_op', because we know that in this case,
17520Sstevel@tonic-gate 		 * this function does nothing.
17530Sstevel@tonic-gate 		 *
17540Sstevel@tonic-gate 		 * 4225415: If the parent isn't attached, or the child
17550Sstevel@tonic-gate 		 * hasn't been named by the parent yet, use the default
17560Sstevel@tonic-gate 		 * ddi_bus_prop_op as a proxy for the parent.  This
17570Sstevel@tonic-gate 		 * allows property lookups in any child/parent state to
17580Sstevel@tonic-gate 		 * include 'prom' and inherited properties, even when
17590Sstevel@tonic-gate 		 * there are no drivers attached to the child or parent.
17600Sstevel@tonic-gate 		 */
17610Sstevel@tonic-gate 
17620Sstevel@tonic-gate 		bop = ddi_bus_prop_op;
17631333Scth 		if (i_ddi_devi_attached(pdip) &&
17640Sstevel@tonic-gate 		    (i_ddi_node_state(dip) >= DS_INITIALIZED))
17650Sstevel@tonic-gate 			bop = DEVI(pdip)->devi_ops->devo_bus_ops->bus_prop_op;
17660Sstevel@tonic-gate 
17670Sstevel@tonic-gate 		i = DDI_PROP_NOT_FOUND;
17680Sstevel@tonic-gate 
17690Sstevel@tonic-gate 		if ((bop != ddi_bus_prop_op) || ndi_dev_is_prom_node(dip)) {
17700Sstevel@tonic-gate 			i = (*bop)(dev, pdip, dip, prop_op,
17710Sstevel@tonic-gate 			    flags | DDI_PROP_DONTPASS,
17720Sstevel@tonic-gate 			    name, valuep, lengthp);
17730Sstevel@tonic-gate 		}
17740Sstevel@tonic-gate 
17750Sstevel@tonic-gate 		if ((flags & DDI_PROP_DONTPASS) ||
17760Sstevel@tonic-gate 		    (i != DDI_PROP_NOT_FOUND))
17770Sstevel@tonic-gate 			return (i);
17780Sstevel@tonic-gate 
17790Sstevel@tonic-gate 		dip = pdip;
17800Sstevel@tonic-gate 	}
17810Sstevel@tonic-gate 	/*NOTREACHED*/
17820Sstevel@tonic-gate }
17830Sstevel@tonic-gate 
17840Sstevel@tonic-gate 
17850Sstevel@tonic-gate /*
17860Sstevel@tonic-gate  * ddi_prop_op: The basic property operator for drivers.
17870Sstevel@tonic-gate  *
17880Sstevel@tonic-gate  * In ddi_prop_op, the type of valuep is interpreted based on prop_op:
17890Sstevel@tonic-gate  *
17900Sstevel@tonic-gate  *	prop_op			valuep
17910Sstevel@tonic-gate  *	------			------
17920Sstevel@tonic-gate  *
17930Sstevel@tonic-gate  *	PROP_LEN		<unused>
17940Sstevel@tonic-gate  *
17950Sstevel@tonic-gate  *	PROP_LEN_AND_VAL_BUF	Pointer to callers buffer
17960Sstevel@tonic-gate  *
17970Sstevel@tonic-gate  *	PROP_LEN_AND_VAL_ALLOC	Address of callers pointer (will be set to
17980Sstevel@tonic-gate  *				address of allocated buffer, if successful)
17990Sstevel@tonic-gate  */
18000Sstevel@tonic-gate int
ddi_prop_op(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)18010Sstevel@tonic-gate ddi_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
18020Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
18030Sstevel@tonic-gate {
18040Sstevel@tonic-gate 	int	i;
18050Sstevel@tonic-gate 
18060Sstevel@tonic-gate 	ASSERT((mod_flags & DDI_PROP_TYPE_MASK) == 0);
18070Sstevel@tonic-gate 
18080Sstevel@tonic-gate 	/*
18090Sstevel@tonic-gate 	 * If this was originally an LDI prop lookup then we bail here.
18100Sstevel@tonic-gate 	 * The reason is that the LDI property lookup interfaces first call
18110Sstevel@tonic-gate 	 * a drivers prop_op() entry point to allow it to override
18120Sstevel@tonic-gate 	 * properties.  But if we've made it here, then the driver hasn't
18130Sstevel@tonic-gate 	 * overriden any properties.  We don't want to continue with the
18140Sstevel@tonic-gate 	 * property search here because we don't have any type inforamtion.
18150Sstevel@tonic-gate 	 * When we return failure, the LDI interfaces will then proceed to
18160Sstevel@tonic-gate 	 * call the typed property interfaces to look up the property.
18170Sstevel@tonic-gate 	 */
18180Sstevel@tonic-gate 	if (mod_flags & DDI_PROP_DYNAMIC)
18190Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
18200Sstevel@tonic-gate 
18210Sstevel@tonic-gate 	/*
18220Sstevel@tonic-gate 	 * check for pre-typed property consumer asking for typed property:
18230Sstevel@tonic-gate 	 * see e_ddi_getprop_int64.
18240Sstevel@tonic-gate 	 */
18250Sstevel@tonic-gate 	if (mod_flags & DDI_PROP_CONSUMER_TYPED)
18260Sstevel@tonic-gate 		mod_flags |= DDI_PROP_TYPE_INT64;
18270Sstevel@tonic-gate 	mod_flags |= DDI_PROP_TYPE_ANY;
18280Sstevel@tonic-gate 
18290Sstevel@tonic-gate 	i = ddi_prop_search_common(dev, dip, prop_op,
18304582Scth 	    mod_flags, name, valuep, (uint_t *)lengthp);
18310Sstevel@tonic-gate 	if (i == DDI_PROP_FOUND_1275)
18320Sstevel@tonic-gate 		return (DDI_PROP_SUCCESS);
18330Sstevel@tonic-gate 	return (i);
18340Sstevel@tonic-gate }
18350Sstevel@tonic-gate 
18360Sstevel@tonic-gate /*
18374582Scth  * ddi_prop_op_nblocks_blksize: The basic property operator for drivers that
18384582Scth  * maintain size in number of blksize blocks.  Provides a dynamic property
18394582Scth  * implementation for size oriented properties based on nblocks64 and blksize
18404582Scth  * values passed in by the driver.  Fallback to ddi_prop_op if the nblocks64
18414582Scth  * is too large.  This interface should not be used with a nblocks64 that
18424582Scth  * represents the driver's idea of how to represent unknown, if nblocks is
18434582Scth  * unknown use ddi_prop_op.
18444582Scth  */
18454582Scth int
ddi_prop_op_nblocks_blksize(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp,uint64_t nblocks64,uint_t blksize)18464582Scth ddi_prop_op_nblocks_blksize(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
18474582Scth     int mod_flags, char *name, caddr_t valuep, int *lengthp,
18484582Scth     uint64_t nblocks64, uint_t blksize)
18494582Scth {
18504582Scth 	uint64_t size64;
18514582Scth 	int	blkshift;
18524582Scth 
18534582Scth 	/* convert block size to shift value */
18544582Scth 	ASSERT(BIT_ONLYONESET(blksize));
18554582Scth 	blkshift = highbit(blksize) - 1;
18564582Scth 
18574582Scth 	/*
18584582Scth 	 * There is no point in supporting nblocks64 values that don't have
18594582Scth 	 * an accurate uint64_t byte count representation.
18604582Scth 	 */
18614582Scth 	if (nblocks64 >= (UINT64_MAX >> blkshift))
18624582Scth 		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
18634582Scth 		    name, valuep, lengthp));
18644582Scth 
18654582Scth 	size64 = nblocks64 << blkshift;
18664582Scth 	return (ddi_prop_op_size_blksize(dev, dip, prop_op, mod_flags,
18674582Scth 	    name, valuep, lengthp, size64, blksize));
18684582Scth }
18694582Scth 
18704582Scth /*
18714582Scth  * ddi_prop_op_nblocks: ddi_prop_op_nblocks_blksize with DEV_BSIZE blksize.
18720Sstevel@tonic-gate  */
18730Sstevel@tonic-gate int
ddi_prop_op_nblocks(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp,uint64_t nblocks64)18740Sstevel@tonic-gate ddi_prop_op_nblocks(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
18750Sstevel@tonic-gate     int mod_flags, char *name, caddr_t valuep, int *lengthp, uint64_t nblocks64)
18760Sstevel@tonic-gate {
18774582Scth 	return (ddi_prop_op_nblocks_blksize(dev, dip, prop_op,
18784582Scth 	    mod_flags, name, valuep, lengthp, nblocks64, DEV_BSIZE));
18794582Scth }
18804582Scth 
18814582Scth /*
18824582Scth  * ddi_prop_op_size_blksize: The basic property operator for block drivers that
18834582Scth  * maintain size in bytes. Provides a of dynamic property implementation for
18844582Scth  * size oriented properties based on size64 value and blksize passed in by the
18854582Scth  * driver.  Fallback to ddi_prop_op if the size64 is too large. This interface
18864582Scth  * should not be used with a size64 that represents the driver's idea of how
18874582Scth  * to represent unknown, if size is unknown use ddi_prop_op.
18880Sstevel@tonic-gate  *
18890Sstevel@tonic-gate  * NOTE: the legacy "nblocks"/"size" properties are treated as 32-bit unsigned
18900Sstevel@tonic-gate  * integers. While the most likely interface to request them ([bc]devi_size)
18910Sstevel@tonic-gate  * is declared int (signed) there is no enforcement of this, which means we
18920Sstevel@tonic-gate  * can't enforce limitations here without risking regression.
18930Sstevel@tonic-gate  */
18940Sstevel@tonic-gate int
ddi_prop_op_size_blksize(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp,uint64_t size64,uint_t blksize)18954582Scth ddi_prop_op_size_blksize(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
18964582Scth     int mod_flags, char *name, caddr_t valuep, int *lengthp, uint64_t size64,
18974582Scth     uint_t blksize)
18980Sstevel@tonic-gate {
18990Sstevel@tonic-gate 	uint64_t nblocks64;
19000Sstevel@tonic-gate 	int	callers_length;
19010Sstevel@tonic-gate 	caddr_t	buffer;
19024582Scth 	int	blkshift;
19034582Scth 
19047224Scth 	/*
19057224Scth 	 * This is a kludge to support capture of size(9P) pure dynamic
19067224Scth 	 * properties in snapshots for non-cmlb code (without exposing
19077224Scth 	 * i_ddi_prop_dyn changes). When everyone uses cmlb, this code
19087224Scth 	 * should be removed.
19097224Scth 	 */
19107224Scth 	if (i_ddi_prop_dyn_driver_get(dip) == NULL) {
19117224Scth 		static i_ddi_prop_dyn_t prop_dyn_size[] = {
19127224Scth 		    {"Size",		DDI_PROP_TYPE_INT64,	S_IFCHR},
19137224Scth 		    {"Nblocks",		DDI_PROP_TYPE_INT64,	S_IFBLK},
19147224Scth 		    {NULL}
19157224Scth 		};
19167224Scth 		i_ddi_prop_dyn_driver_set(dip, prop_dyn_size);
19177224Scth 	}
19187224Scth 
19194582Scth 	/* convert block size to shift value */
19204582Scth 	ASSERT(BIT_ONLYONESET(blksize));
19214582Scth 	blkshift = highbit(blksize) - 1;
19220Sstevel@tonic-gate 
19230Sstevel@tonic-gate 	/* compute DEV_BSIZE nblocks value */
19244582Scth 	nblocks64 = size64 >> blkshift;
19250Sstevel@tonic-gate 
19260Sstevel@tonic-gate 	/* get callers length, establish length of our dynamic properties */
19270Sstevel@tonic-gate 	callers_length = *lengthp;
19280Sstevel@tonic-gate 
19290Sstevel@tonic-gate 	if (strcmp(name, "Nblocks") == 0)
19300Sstevel@tonic-gate 		*lengthp = sizeof (uint64_t);
19310Sstevel@tonic-gate 	else if (strcmp(name, "Size") == 0)
19320Sstevel@tonic-gate 		*lengthp = sizeof (uint64_t);
19330Sstevel@tonic-gate 	else if ((strcmp(name, "nblocks") == 0) && (nblocks64 < UINT_MAX))
19340Sstevel@tonic-gate 		*lengthp = sizeof (uint32_t);
19350Sstevel@tonic-gate 	else if ((strcmp(name, "size") == 0) && (size64 < UINT_MAX))
19360Sstevel@tonic-gate 		*lengthp = sizeof (uint32_t);
19374582Scth 	else if ((strcmp(name, "blksize") == 0) && (blksize < UINT_MAX))
19384582Scth 		*lengthp = sizeof (uint32_t);
19390Sstevel@tonic-gate 	else {
19400Sstevel@tonic-gate 		/* fallback to ddi_prop_op */
19410Sstevel@tonic-gate 		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
19420Sstevel@tonic-gate 		    name, valuep, lengthp));
19430Sstevel@tonic-gate 	}
19440Sstevel@tonic-gate 
19450Sstevel@tonic-gate 	/* service request for the length of the property */
19460Sstevel@tonic-gate 	if (prop_op == PROP_LEN)
19470Sstevel@tonic-gate 		return (DDI_PROP_SUCCESS);
19480Sstevel@tonic-gate 
19490Sstevel@tonic-gate 	switch (prop_op) {
19500Sstevel@tonic-gate 	case PROP_LEN_AND_VAL_ALLOC:
19510Sstevel@tonic-gate 		if ((buffer = kmem_alloc(*lengthp,
19520Sstevel@tonic-gate 		    (mod_flags & DDI_PROP_CANSLEEP) ?
19530Sstevel@tonic-gate 		    KM_SLEEP : KM_NOSLEEP)) == NULL)
19540Sstevel@tonic-gate 			return (DDI_PROP_NO_MEMORY);
19550Sstevel@tonic-gate 
19560Sstevel@tonic-gate 		*(caddr_t *)valuep = buffer;	/* set callers buf ptr */
19570Sstevel@tonic-gate 		break;
19580Sstevel@tonic-gate 
19590Sstevel@tonic-gate 	case PROP_LEN_AND_VAL_BUF:
19607224Scth 		/* the length of the property and the request must match */
19617224Scth 		if (callers_length != *lengthp)
19627224Scth 			return (DDI_PROP_INVAL_ARG);
19637224Scth 
19640Sstevel@tonic-gate 		buffer = valuep;		/* get callers buf ptr */
19650Sstevel@tonic-gate 		break;
19660Sstevel@tonic-gate 
19670Sstevel@tonic-gate 	default:
19680Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
19690Sstevel@tonic-gate 	}
19700Sstevel@tonic-gate 
19710Sstevel@tonic-gate 	/* transfer the value into the buffer */
19720Sstevel@tonic-gate 	if (strcmp(name, "Nblocks") == 0)
19730Sstevel@tonic-gate 		*((uint64_t *)buffer) = nblocks64;
19740Sstevel@tonic-gate 	else if (strcmp(name, "Size") == 0)
19750Sstevel@tonic-gate 		*((uint64_t *)buffer) = size64;
19760Sstevel@tonic-gate 	else if (strcmp(name, "nblocks") == 0)
19770Sstevel@tonic-gate 		*((uint32_t *)buffer) = (uint32_t)nblocks64;
19780Sstevel@tonic-gate 	else if (strcmp(name, "size") == 0)
19790Sstevel@tonic-gate 		*((uint32_t *)buffer) = (uint32_t)size64;
19804582Scth 	else if (strcmp(name, "blksize") == 0)
19814582Scth 		*((uint32_t *)buffer) = (uint32_t)blksize;
19820Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
19830Sstevel@tonic-gate }
19840Sstevel@tonic-gate 
19850Sstevel@tonic-gate /*
19864582Scth  * ddi_prop_op_size: ddi_prop_op_size_blksize with DEV_BSIZE block size.
19874582Scth  */
19884582Scth int
ddi_prop_op_size(dev_t dev,dev_info_t * dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp,uint64_t size64)19894582Scth ddi_prop_op_size(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
19904582Scth     int mod_flags, char *name, caddr_t valuep, int *lengthp, uint64_t size64)
19914582Scth {
19924582Scth 	return (ddi_prop_op_size_blksize(dev, dip, prop_op,
19934582Scth 	    mod_flags, name, valuep, lengthp, size64, DEV_BSIZE));
19944582Scth }
19954582Scth 
19964582Scth /*
19970Sstevel@tonic-gate  * Variable length props...
19980Sstevel@tonic-gate  */
19990Sstevel@tonic-gate 
20000Sstevel@tonic-gate /*
20010Sstevel@tonic-gate  * ddi_getlongprop:	Get variable length property len+val into a buffer
20020Sstevel@tonic-gate  *		allocated by property provider via kmem_alloc. Requester
20030Sstevel@tonic-gate  *		is responsible for freeing returned property via kmem_free.
20040Sstevel@tonic-gate  *
20050Sstevel@tonic-gate  *	Arguments:
20060Sstevel@tonic-gate  *
20070Sstevel@tonic-gate  *	dev_t:	Input:	dev_t of property.
20080Sstevel@tonic-gate  *	dip:	Input:	dev_info_t pointer of child.
20090Sstevel@tonic-gate  *	flags:	Input:	Possible flag modifiers are:
20100Sstevel@tonic-gate  *		DDI_PROP_DONTPASS:	Don't pass to parent if prop not found.
20110Sstevel@tonic-gate  *		DDI_PROP_CANSLEEP:	Memory allocation may sleep.
20120Sstevel@tonic-gate  *	name:	Input:	name of property.
20130Sstevel@tonic-gate  *	valuep:	Output:	Addr of callers buffer pointer.
20140Sstevel@tonic-gate  *	lengthp:Output:	*lengthp will contain prop length on exit.
20150Sstevel@tonic-gate  *
20160Sstevel@tonic-gate  *	Possible Returns:
20170Sstevel@tonic-gate  *
20180Sstevel@tonic-gate  *		DDI_PROP_SUCCESS:	Prop found and returned.
20190Sstevel@tonic-gate  *		DDI_PROP_NOT_FOUND:	Prop not found
20200Sstevel@tonic-gate  *		DDI_PROP_UNDEFINED:	Prop explicitly undefined.
20210Sstevel@tonic-gate  *		DDI_PROP_NO_MEMORY:	Prop found, but unable to alloc mem.
20220Sstevel@tonic-gate  */
20230Sstevel@tonic-gate 
20240Sstevel@tonic-gate int
ddi_getlongprop(dev_t dev,dev_info_t * dip,int flags,char * name,caddr_t valuep,int * lengthp)20250Sstevel@tonic-gate ddi_getlongprop(dev_t dev, dev_info_t *dip, int flags,
20260Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
20270Sstevel@tonic-gate {
20280Sstevel@tonic-gate 	return (ddi_prop_op(dev, dip, PROP_LEN_AND_VAL_ALLOC,
20290Sstevel@tonic-gate 	    flags, name, valuep, lengthp));
20300Sstevel@tonic-gate }
20310Sstevel@tonic-gate 
20320Sstevel@tonic-gate /*
20330Sstevel@tonic-gate  *
20340Sstevel@tonic-gate  * ddi_getlongprop_buf:		Get long prop into pre-allocated callers
20350Sstevel@tonic-gate  *				buffer. (no memory allocation by provider).
20360Sstevel@tonic-gate  *
20370Sstevel@tonic-gate  *	dev_t:	Input:	dev_t of property.
20380Sstevel@tonic-gate  *	dip:	Input:	dev_info_t pointer of child.
20390Sstevel@tonic-gate  *	flags:	Input:	DDI_PROP_DONTPASS or NULL
20400Sstevel@tonic-gate  *	name:	Input:	name of property
20410Sstevel@tonic-gate  *	valuep:	Input:	ptr to callers buffer.
20420Sstevel@tonic-gate  *	lengthp:I/O:	ptr to length of callers buffer on entry,
20430Sstevel@tonic-gate  *			actual length of property on exit.
20440Sstevel@tonic-gate  *
20450Sstevel@tonic-gate  *	Possible returns:
20460Sstevel@tonic-gate  *
20470Sstevel@tonic-gate  *		DDI_PROP_SUCCESS	Prop found and returned
20480Sstevel@tonic-gate  *		DDI_PROP_NOT_FOUND	Prop not found
20490Sstevel@tonic-gate  *		DDI_PROP_UNDEFINED	Prop explicitly undefined.
20500Sstevel@tonic-gate  *		DDI_PROP_BUF_TOO_SMALL	Prop found, callers buf too small,
20510Sstevel@tonic-gate  *					no value returned, but actual prop
20520Sstevel@tonic-gate  *					length returned in *lengthp
20530Sstevel@tonic-gate  *
20540Sstevel@tonic-gate  */
20550Sstevel@tonic-gate 
20560Sstevel@tonic-gate int
ddi_getlongprop_buf(dev_t dev,dev_info_t * dip,int flags,char * name,caddr_t valuep,int * lengthp)20570Sstevel@tonic-gate ddi_getlongprop_buf(dev_t dev, dev_info_t *dip, int flags,
20580Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
20590Sstevel@tonic-gate {
20600Sstevel@tonic-gate 	return (ddi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
20610Sstevel@tonic-gate 	    flags, name, valuep, lengthp));
20620Sstevel@tonic-gate }
20630Sstevel@tonic-gate 
20640Sstevel@tonic-gate /*
20650Sstevel@tonic-gate  * Integer/boolean sized props.
20660Sstevel@tonic-gate  *
20670Sstevel@tonic-gate  * Call is value only... returns found boolean or int sized prop value or
20680Sstevel@tonic-gate  * defvalue if prop not found or is wrong length or is explicitly undefined.
20690Sstevel@tonic-gate  * Only flag is DDI_PROP_DONTPASS...
20700Sstevel@tonic-gate  *
20710Sstevel@tonic-gate  * By convention, this interface returns boolean (0) sized properties
20720Sstevel@tonic-gate  * as value (int)1.
20730Sstevel@tonic-gate  *
20740Sstevel@tonic-gate  * This never returns an error, if property not found or specifically
20750Sstevel@tonic-gate  * undefined, the input `defvalue' is returned.
20760Sstevel@tonic-gate  */
20770Sstevel@tonic-gate 
20780Sstevel@tonic-gate int
ddi_getprop(dev_t dev,dev_info_t * dip,int flags,char * name,int defvalue)20790Sstevel@tonic-gate ddi_getprop(dev_t dev, dev_info_t *dip, int flags, char *name, int defvalue)
20800Sstevel@tonic-gate {
20810Sstevel@tonic-gate 	int	propvalue = defvalue;
20820Sstevel@tonic-gate 	int	proplength = sizeof (int);
20830Sstevel@tonic-gate 	int	error;
20840Sstevel@tonic-gate 
20850Sstevel@tonic-gate 	error = ddi_prop_op(dev, dip, PROP_LEN_AND_VAL_BUF,
20860Sstevel@tonic-gate 	    flags, name, (caddr_t)&propvalue, &proplength);
20870Sstevel@tonic-gate 
20880Sstevel@tonic-gate 	if ((error == DDI_PROP_SUCCESS) && (proplength == 0))
20890Sstevel@tonic-gate 		propvalue = 1;
20900Sstevel@tonic-gate 
20910Sstevel@tonic-gate 	return (propvalue);
20920Sstevel@tonic-gate }
20930Sstevel@tonic-gate 
20940Sstevel@tonic-gate /*
20950Sstevel@tonic-gate  * Get prop length interface: flags are 0 or DDI_PROP_DONTPASS
20960Sstevel@tonic-gate  * if returns DDI_PROP_SUCCESS, length returned in *lengthp.
20970Sstevel@tonic-gate  */
20980Sstevel@tonic-gate 
20990Sstevel@tonic-gate int
ddi_getproplen(dev_t dev,dev_info_t * dip,int flags,char * name,int * lengthp)21000Sstevel@tonic-gate ddi_getproplen(dev_t dev, dev_info_t *dip, int flags, char *name, int *lengthp)
21010Sstevel@tonic-gate {
21020Sstevel@tonic-gate 	return (ddi_prop_op(dev, dip, PROP_LEN, flags, name, NULL, lengthp));
21030Sstevel@tonic-gate }
21040Sstevel@tonic-gate 
21050Sstevel@tonic-gate /*
21060Sstevel@tonic-gate  * Allocate a struct prop_driver_data, along with 'size' bytes
21070Sstevel@tonic-gate  * for decoded property data.  This structure is freed by
21080Sstevel@tonic-gate  * calling ddi_prop_free(9F).
21090Sstevel@tonic-gate  */
21100Sstevel@tonic-gate static void *
ddi_prop_decode_alloc(size_t size,void (* prop_free)(struct prop_driver_data *))21110Sstevel@tonic-gate ddi_prop_decode_alloc(size_t size, void (*prop_free)(struct prop_driver_data *))
21120Sstevel@tonic-gate {
21130Sstevel@tonic-gate 	struct prop_driver_data *pdd;
21140Sstevel@tonic-gate 
21150Sstevel@tonic-gate 	/*
21160Sstevel@tonic-gate 	 * Allocate a structure with enough memory to store the decoded data.
21170Sstevel@tonic-gate 	 */
21180Sstevel@tonic-gate 	pdd = kmem_zalloc(sizeof (struct prop_driver_data) + size, KM_SLEEP);
21190Sstevel@tonic-gate 	pdd->pdd_size = (sizeof (struct prop_driver_data) + size);
21200Sstevel@tonic-gate 	pdd->pdd_prop_free = prop_free;
21210Sstevel@tonic-gate 
21220Sstevel@tonic-gate 	/*
21230Sstevel@tonic-gate 	 * Return a pointer to the location to put the decoded data.
21240Sstevel@tonic-gate 	 */
21250Sstevel@tonic-gate 	return ((void *)((caddr_t)pdd + sizeof (struct prop_driver_data)));
21260Sstevel@tonic-gate }
21270Sstevel@tonic-gate 
21280Sstevel@tonic-gate /*
21290Sstevel@tonic-gate  * Allocated the memory needed to store the encoded data in the property
21300Sstevel@tonic-gate  * handle.
21310Sstevel@tonic-gate  */
21320Sstevel@tonic-gate static int
ddi_prop_encode_alloc(prop_handle_t * ph,size_t size)21330Sstevel@tonic-gate ddi_prop_encode_alloc(prop_handle_t *ph, size_t size)
21340Sstevel@tonic-gate {
21350Sstevel@tonic-gate 	/*
21360Sstevel@tonic-gate 	 * If size is zero, then set data to NULL and size to 0.  This
21370Sstevel@tonic-gate 	 * is a boolean property.
21380Sstevel@tonic-gate 	 */
21390Sstevel@tonic-gate 	if (size == 0) {
21400Sstevel@tonic-gate 		ph->ph_size = 0;
21410Sstevel@tonic-gate 		ph->ph_data = NULL;
21420Sstevel@tonic-gate 		ph->ph_cur_pos = NULL;
21430Sstevel@tonic-gate 		ph->ph_save_pos = NULL;
21440Sstevel@tonic-gate 	} else {
21450Sstevel@tonic-gate 		if (ph->ph_flags == DDI_PROP_DONTSLEEP) {
21460Sstevel@tonic-gate 			ph->ph_data = kmem_zalloc(size, KM_NOSLEEP);
21470Sstevel@tonic-gate 			if (ph->ph_data == NULL)
21480Sstevel@tonic-gate 				return (DDI_PROP_NO_MEMORY);
21490Sstevel@tonic-gate 		} else
21500Sstevel@tonic-gate 			ph->ph_data = kmem_zalloc(size, KM_SLEEP);
21510Sstevel@tonic-gate 		ph->ph_size = size;
21520Sstevel@tonic-gate 		ph->ph_cur_pos = ph->ph_data;
21530Sstevel@tonic-gate 		ph->ph_save_pos = ph->ph_data;
21540Sstevel@tonic-gate 	}
21550Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
21560Sstevel@tonic-gate }
21570Sstevel@tonic-gate 
21580Sstevel@tonic-gate /*
21590Sstevel@tonic-gate  * Free the space allocated by the lookup routines.  Each lookup routine
21600Sstevel@tonic-gate  * returns a pointer to the decoded data to the driver.  The driver then
21610Sstevel@tonic-gate  * passes this pointer back to us.  This data actually lives in a struct
21620Sstevel@tonic-gate  * prop_driver_data.  We use negative indexing to find the beginning of
21630Sstevel@tonic-gate  * the structure and then free the entire structure using the size and
21640Sstevel@tonic-gate  * the free routine stored in the structure.
21650Sstevel@tonic-gate  */
21660Sstevel@tonic-gate void
ddi_prop_free(void * datap)21670Sstevel@tonic-gate ddi_prop_free(void *datap)
21680Sstevel@tonic-gate {
21690Sstevel@tonic-gate 	struct prop_driver_data *pdd;
21700Sstevel@tonic-gate 
21710Sstevel@tonic-gate 	/*
21720Sstevel@tonic-gate 	 * Get the structure
21730Sstevel@tonic-gate 	 */
21740Sstevel@tonic-gate 	pdd = (struct prop_driver_data *)
21754582Scth 	    ((caddr_t)datap - sizeof (struct prop_driver_data));
21760Sstevel@tonic-gate 	/*
21770Sstevel@tonic-gate 	 * Call the free routine to free it
21780Sstevel@tonic-gate 	 */
21790Sstevel@tonic-gate 	(*pdd->pdd_prop_free)(pdd);
21800Sstevel@tonic-gate }
21810Sstevel@tonic-gate 
21820Sstevel@tonic-gate /*
21830Sstevel@tonic-gate  * Free the data associated with an array of ints,
21840Sstevel@tonic-gate  * allocated with ddi_prop_decode_alloc().
21850Sstevel@tonic-gate  */
21860Sstevel@tonic-gate static void
ddi_prop_free_ints(struct prop_driver_data * pdd)21870Sstevel@tonic-gate ddi_prop_free_ints(struct prop_driver_data *pdd)
21880Sstevel@tonic-gate {
21890Sstevel@tonic-gate 	kmem_free(pdd, pdd->pdd_size);
21900Sstevel@tonic-gate }
21910Sstevel@tonic-gate 
21920Sstevel@tonic-gate /*
21930Sstevel@tonic-gate  * Free a single string property or a single string contained within
21940Sstevel@tonic-gate  * the argv style return value of an array of strings.
21950Sstevel@tonic-gate  */
21960Sstevel@tonic-gate static void
ddi_prop_free_string(struct prop_driver_data * pdd)21970Sstevel@tonic-gate ddi_prop_free_string(struct prop_driver_data *pdd)
21980Sstevel@tonic-gate {
21990Sstevel@tonic-gate 	kmem_free(pdd, pdd->pdd_size);
22000Sstevel@tonic-gate 
22010Sstevel@tonic-gate }
22020Sstevel@tonic-gate 
22030Sstevel@tonic-gate /*
22040Sstevel@tonic-gate  * Free an array of strings.
22050Sstevel@tonic-gate  */
22060Sstevel@tonic-gate static void
ddi_prop_free_strings(struct prop_driver_data * pdd)22070Sstevel@tonic-gate ddi_prop_free_strings(struct prop_driver_data *pdd)
22080Sstevel@tonic-gate {
22090Sstevel@tonic-gate 	kmem_free(pdd, pdd->pdd_size);
22100Sstevel@tonic-gate }
22110Sstevel@tonic-gate 
22120Sstevel@tonic-gate /*
22130Sstevel@tonic-gate  * Free the data associated with an array of bytes.
22140Sstevel@tonic-gate  */
22150Sstevel@tonic-gate static void
ddi_prop_free_bytes(struct prop_driver_data * pdd)22160Sstevel@tonic-gate ddi_prop_free_bytes(struct prop_driver_data *pdd)
22170Sstevel@tonic-gate {
22180Sstevel@tonic-gate 	kmem_free(pdd, pdd->pdd_size);
22190Sstevel@tonic-gate }
22200Sstevel@tonic-gate 
22210Sstevel@tonic-gate /*
22220Sstevel@tonic-gate  * Reset the current location pointer in the property handle to the
22230Sstevel@tonic-gate  * beginning of the data.
22240Sstevel@tonic-gate  */
22250Sstevel@tonic-gate void
ddi_prop_reset_pos(prop_handle_t * ph)22260Sstevel@tonic-gate ddi_prop_reset_pos(prop_handle_t *ph)
22270Sstevel@tonic-gate {
22280Sstevel@tonic-gate 	ph->ph_cur_pos = ph->ph_data;
22290Sstevel@tonic-gate 	ph->ph_save_pos = ph->ph_data;
22300Sstevel@tonic-gate }
22310Sstevel@tonic-gate 
22320Sstevel@tonic-gate /*
22330Sstevel@tonic-gate  * Restore the current location pointer in the property handle to the
22340Sstevel@tonic-gate  * saved position.
22350Sstevel@tonic-gate  */
22360Sstevel@tonic-gate void
ddi_prop_save_pos(prop_handle_t * ph)22370Sstevel@tonic-gate ddi_prop_save_pos(prop_handle_t *ph)
22380Sstevel@tonic-gate {
22390Sstevel@tonic-gate 	ph->ph_save_pos = ph->ph_cur_pos;
22400Sstevel@tonic-gate }
22410Sstevel@tonic-gate 
22420Sstevel@tonic-gate /*
22430Sstevel@tonic-gate  * Save the location that the current location pointer is pointing to..
22440Sstevel@tonic-gate  */
22450Sstevel@tonic-gate void
ddi_prop_restore_pos(prop_handle_t * ph)22460Sstevel@tonic-gate ddi_prop_restore_pos(prop_handle_t *ph)
22470Sstevel@tonic-gate {
22480Sstevel@tonic-gate 	ph->ph_cur_pos = ph->ph_save_pos;
22490Sstevel@tonic-gate }
22500Sstevel@tonic-gate 
22510Sstevel@tonic-gate /*
22520Sstevel@tonic-gate  * Property encode/decode functions
22530Sstevel@tonic-gate  */
22540Sstevel@tonic-gate 
22550Sstevel@tonic-gate /*
22560Sstevel@tonic-gate  * Decode a single integer property
22570Sstevel@tonic-gate  */
22580Sstevel@tonic-gate static int
ddi_prop_fm_decode_int(prop_handle_t * ph,void * data,uint_t * nelements)22590Sstevel@tonic-gate ddi_prop_fm_decode_int(prop_handle_t *ph, void *data, uint_t *nelements)
22600Sstevel@tonic-gate {
22610Sstevel@tonic-gate 	int	i;
22620Sstevel@tonic-gate 	int	tmp;
22630Sstevel@tonic-gate 
22640Sstevel@tonic-gate 	/*
22650Sstevel@tonic-gate 	 * If there is nothing to decode return an error
22660Sstevel@tonic-gate 	 */
22670Sstevel@tonic-gate 	if (ph->ph_size == 0)
22680Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
22690Sstevel@tonic-gate 
22700Sstevel@tonic-gate 	/*
22710Sstevel@tonic-gate 	 * Decode the property as a single integer and return it
22720Sstevel@tonic-gate 	 * in data if we were able to decode it.
22730Sstevel@tonic-gate 	 */
22740Sstevel@tonic-gate 	i = DDI_PROP_INT(ph, DDI_PROP_CMD_DECODE, &tmp);
22750Sstevel@tonic-gate 	if (i < DDI_PROP_RESULT_OK) {
22760Sstevel@tonic-gate 		switch (i) {
22770Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
22780Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
22790Sstevel@tonic-gate 
22800Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
22810Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
22820Sstevel@tonic-gate 		}
22830Sstevel@tonic-gate 	}
22840Sstevel@tonic-gate 
22850Sstevel@tonic-gate 	*(int *)data = tmp;
22860Sstevel@tonic-gate 	*nelements = 1;
22870Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
22880Sstevel@tonic-gate }
22890Sstevel@tonic-gate 
22900Sstevel@tonic-gate /*
22910Sstevel@tonic-gate  * Decode a single 64 bit integer property
22920Sstevel@tonic-gate  */
22930Sstevel@tonic-gate static int
ddi_prop_fm_decode_int64(prop_handle_t * ph,void * data,uint_t * nelements)22940Sstevel@tonic-gate ddi_prop_fm_decode_int64(prop_handle_t *ph, void *data, uint_t *nelements)
22950Sstevel@tonic-gate {
22960Sstevel@tonic-gate 	int	i;
22970Sstevel@tonic-gate 	int64_t	tmp;
22980Sstevel@tonic-gate 
22990Sstevel@tonic-gate 	/*
23000Sstevel@tonic-gate 	 * If there is nothing to decode return an error
23010Sstevel@tonic-gate 	 */
23020Sstevel@tonic-gate 	if (ph->ph_size == 0)
23030Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
23040Sstevel@tonic-gate 
23050Sstevel@tonic-gate 	/*
23060Sstevel@tonic-gate 	 * Decode the property as a single integer and return it
23070Sstevel@tonic-gate 	 * in data if we were able to decode it.
23080Sstevel@tonic-gate 	 */
23090Sstevel@tonic-gate 	i = DDI_PROP_INT64(ph, DDI_PROP_CMD_DECODE, &tmp);
23100Sstevel@tonic-gate 	if (i < DDI_PROP_RESULT_OK) {
23110Sstevel@tonic-gate 		switch (i) {
23120Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
23130Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
23140Sstevel@tonic-gate 
23150Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
23160Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
23170Sstevel@tonic-gate 		}
23180Sstevel@tonic-gate 	}
23190Sstevel@tonic-gate 
23200Sstevel@tonic-gate 	*(int64_t *)data = tmp;
23210Sstevel@tonic-gate 	*nelements = 1;
23220Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
23230Sstevel@tonic-gate }
23240Sstevel@tonic-gate 
23250Sstevel@tonic-gate /*
23260Sstevel@tonic-gate  * Decode an array of integers property
23270Sstevel@tonic-gate  */
23280Sstevel@tonic-gate static int
ddi_prop_fm_decode_ints(prop_handle_t * ph,void * data,uint_t * nelements)23290Sstevel@tonic-gate ddi_prop_fm_decode_ints(prop_handle_t *ph, void *data, uint_t *nelements)
23300Sstevel@tonic-gate {
23310Sstevel@tonic-gate 	int	i;
23320Sstevel@tonic-gate 	int	cnt = 0;
23330Sstevel@tonic-gate 	int	*tmp;
23340Sstevel@tonic-gate 	int	*intp;
23350Sstevel@tonic-gate 	int	n;
23360Sstevel@tonic-gate 
23370Sstevel@tonic-gate 	/*
23380Sstevel@tonic-gate 	 * Figure out how many array elements there are by going through the
23390Sstevel@tonic-gate 	 * data without decoding it first and counting.
23400Sstevel@tonic-gate 	 */
23410Sstevel@tonic-gate 	for (;;) {
23420Sstevel@tonic-gate 		i = DDI_PROP_INT(ph, DDI_PROP_CMD_SKIP, NULL);
23430Sstevel@tonic-gate 		if (i < 0)
23440Sstevel@tonic-gate 			break;
23450Sstevel@tonic-gate 		cnt++;
23460Sstevel@tonic-gate 	}
23470Sstevel@tonic-gate 
23480Sstevel@tonic-gate 	/*
23490Sstevel@tonic-gate 	 * If there are no elements return an error
23500Sstevel@tonic-gate 	 */
23510Sstevel@tonic-gate 	if (cnt == 0)
23520Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
23530Sstevel@tonic-gate 
23540Sstevel@tonic-gate 	/*
23550Sstevel@tonic-gate 	 * If we cannot skip through the data, we cannot decode it
23560Sstevel@tonic-gate 	 */
23570Sstevel@tonic-gate 	if (i == DDI_PROP_RESULT_ERROR)
23580Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_DECODE);
23590Sstevel@tonic-gate 
23600Sstevel@tonic-gate 	/*
23610Sstevel@tonic-gate 	 * Reset the data pointer to the beginning of the encoded data
23620Sstevel@tonic-gate 	 */
23630Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
23640Sstevel@tonic-gate 
23650Sstevel@tonic-gate 	/*
23660Sstevel@tonic-gate 	 * Allocated memory to store the decoded value in.
23670Sstevel@tonic-gate 	 */
23680Sstevel@tonic-gate 	intp = ddi_prop_decode_alloc((cnt * sizeof (int)),
23694582Scth 	    ddi_prop_free_ints);
23700Sstevel@tonic-gate 
23710Sstevel@tonic-gate 	/*
23720Sstevel@tonic-gate 	 * Decode each element and place it in the space we just allocated
23730Sstevel@tonic-gate 	 */
23740Sstevel@tonic-gate 	tmp = intp;
23750Sstevel@tonic-gate 	for (n = 0; n < cnt; n++, tmp++) {
23760Sstevel@tonic-gate 		i = DDI_PROP_INT(ph, DDI_PROP_CMD_DECODE, tmp);
23770Sstevel@tonic-gate 		if (i < DDI_PROP_RESULT_OK) {
23780Sstevel@tonic-gate 			/*
23790Sstevel@tonic-gate 			 * Free the space we just allocated
23800Sstevel@tonic-gate 			 * and return an error.
23810Sstevel@tonic-gate 			 */
23820Sstevel@tonic-gate 			ddi_prop_free(intp);
23830Sstevel@tonic-gate 			switch (i) {
23840Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
23850Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
23860Sstevel@tonic-gate 
23870Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
23880Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_DECODE);
23890Sstevel@tonic-gate 			}
23900Sstevel@tonic-gate 		}
23910Sstevel@tonic-gate 	}
23920Sstevel@tonic-gate 
23930Sstevel@tonic-gate 	*nelements = cnt;
23940Sstevel@tonic-gate 	*(int **)data = intp;
23950Sstevel@tonic-gate 
23960Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
23970Sstevel@tonic-gate }
23980Sstevel@tonic-gate 
23990Sstevel@tonic-gate /*
24000Sstevel@tonic-gate  * Decode a 64 bit integer array property
24010Sstevel@tonic-gate  */
24020Sstevel@tonic-gate static int
ddi_prop_fm_decode_int64_array(prop_handle_t * ph,void * data,uint_t * nelements)24030Sstevel@tonic-gate ddi_prop_fm_decode_int64_array(prop_handle_t *ph, void *data, uint_t *nelements)
24040Sstevel@tonic-gate {
24050Sstevel@tonic-gate 	int	i;
24060Sstevel@tonic-gate 	int	n;
24070Sstevel@tonic-gate 	int	cnt = 0;
24080Sstevel@tonic-gate 	int64_t	*tmp;
24090Sstevel@tonic-gate 	int64_t	*intp;
24100Sstevel@tonic-gate 
24110Sstevel@tonic-gate 	/*
24120Sstevel@tonic-gate 	 * Count the number of array elements by going
24130Sstevel@tonic-gate 	 * through the data without decoding it.
24140Sstevel@tonic-gate 	 */
24150Sstevel@tonic-gate 	for (;;) {
24160Sstevel@tonic-gate 		i = DDI_PROP_INT64(ph, DDI_PROP_CMD_SKIP, NULL);
24170Sstevel@tonic-gate 		if (i < 0)
24180Sstevel@tonic-gate 			break;
24190Sstevel@tonic-gate 		cnt++;
24200Sstevel@tonic-gate 	}
24210Sstevel@tonic-gate 
24220Sstevel@tonic-gate 	/*
24230Sstevel@tonic-gate 	 * If there are no elements return an error
24240Sstevel@tonic-gate 	 */
24250Sstevel@tonic-gate 	if (cnt == 0)
24260Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
24270Sstevel@tonic-gate 
24280Sstevel@tonic-gate 	/*
24290Sstevel@tonic-gate 	 * If we cannot skip through the data, we cannot decode it
24300Sstevel@tonic-gate 	 */
24310Sstevel@tonic-gate 	if (i == DDI_PROP_RESULT_ERROR)
24320Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_DECODE);
24330Sstevel@tonic-gate 
24340Sstevel@tonic-gate 	/*
24350Sstevel@tonic-gate 	 * Reset the data pointer to the beginning of the encoded data
24360Sstevel@tonic-gate 	 */
24370Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
24380Sstevel@tonic-gate 
24390Sstevel@tonic-gate 	/*
24400Sstevel@tonic-gate 	 * Allocate memory to store the decoded value.
24410Sstevel@tonic-gate 	 */
24420Sstevel@tonic-gate 	intp = ddi_prop_decode_alloc((cnt * sizeof (int64_t)),
24434582Scth 	    ddi_prop_free_ints);
24440Sstevel@tonic-gate 
24450Sstevel@tonic-gate 	/*
24460Sstevel@tonic-gate 	 * Decode each element and place it in the space allocated
24470Sstevel@tonic-gate 	 */
24480Sstevel@tonic-gate 	tmp = intp;
24490Sstevel@tonic-gate 	for (n = 0; n < cnt; n++, tmp++) {
24500Sstevel@tonic-gate 		i = DDI_PROP_INT64(ph, DDI_PROP_CMD_DECODE, tmp);
24510Sstevel@tonic-gate 		if (i < DDI_PROP_RESULT_OK) {
24520Sstevel@tonic-gate 			/*
24530Sstevel@tonic-gate 			 * Free the space we just allocated
24540Sstevel@tonic-gate 			 * and return an error.
24550Sstevel@tonic-gate 			 */
24560Sstevel@tonic-gate 			ddi_prop_free(intp);
24570Sstevel@tonic-gate 			switch (i) {
24580Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
24590Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
24600Sstevel@tonic-gate 
24610Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
24620Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_DECODE);
24630Sstevel@tonic-gate 			}
24640Sstevel@tonic-gate 		}
24650Sstevel@tonic-gate 	}
24660Sstevel@tonic-gate 
24670Sstevel@tonic-gate 	*nelements = cnt;
24680Sstevel@tonic-gate 	*(int64_t **)data = intp;
24690Sstevel@tonic-gate 
24700Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
24710Sstevel@tonic-gate }
24720Sstevel@tonic-gate 
24730Sstevel@tonic-gate /*
24740Sstevel@tonic-gate  * Encode an array of integers property (Can be one element)
24750Sstevel@tonic-gate  */
24760Sstevel@tonic-gate int
ddi_prop_fm_encode_ints(prop_handle_t * ph,void * data,uint_t nelements)24770Sstevel@tonic-gate ddi_prop_fm_encode_ints(prop_handle_t *ph, void *data, uint_t nelements)
24780Sstevel@tonic-gate {
24790Sstevel@tonic-gate 	int	i;
24800Sstevel@tonic-gate 	int	*tmp;
24810Sstevel@tonic-gate 	int	cnt;
24820Sstevel@tonic-gate 	int	size;
24830Sstevel@tonic-gate 
24840Sstevel@tonic-gate 	/*
24850Sstevel@tonic-gate 	 * If there is no data, we cannot do anything
24860Sstevel@tonic-gate 	 */
24870Sstevel@tonic-gate 	if (nelements == 0)
24880Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_ENCODE);
24890Sstevel@tonic-gate 
24900Sstevel@tonic-gate 	/*
24910Sstevel@tonic-gate 	 * Get the size of an encoded int.
24920Sstevel@tonic-gate 	 */
24930Sstevel@tonic-gate 	size = DDI_PROP_INT(ph, DDI_PROP_CMD_GET_ESIZE, NULL);
24940Sstevel@tonic-gate 
24950Sstevel@tonic-gate 	if (size < DDI_PROP_RESULT_OK) {
24960Sstevel@tonic-gate 		switch (size) {
24970Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
24980Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
24990Sstevel@tonic-gate 
25000Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
25010Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_ENCODE);
25020Sstevel@tonic-gate 		}
25030Sstevel@tonic-gate 	}
25040Sstevel@tonic-gate 
25050Sstevel@tonic-gate 	/*
25060Sstevel@tonic-gate 	 * Allocate space in the handle to store the encoded int.
25070Sstevel@tonic-gate 	 */
25080Sstevel@tonic-gate 	if (ddi_prop_encode_alloc(ph, size * nelements) !=
25094582Scth 	    DDI_PROP_SUCCESS)
25100Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
25110Sstevel@tonic-gate 
25120Sstevel@tonic-gate 	/*
25130Sstevel@tonic-gate 	 * Encode the array of ints.
25140Sstevel@tonic-gate 	 */
25150Sstevel@tonic-gate 	tmp = (int *)data;
25160Sstevel@tonic-gate 	for (cnt = 0; cnt < nelements; cnt++, tmp++) {
25170Sstevel@tonic-gate 		i = DDI_PROP_INT(ph, DDI_PROP_CMD_ENCODE, tmp);
25180Sstevel@tonic-gate 		if (i < DDI_PROP_RESULT_OK) {
25190Sstevel@tonic-gate 			switch (i) {
25200Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
25210Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
25220Sstevel@tonic-gate 
25230Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
25240Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_ENCODE);
25250Sstevel@tonic-gate 			}
25260Sstevel@tonic-gate 		}
25270Sstevel@tonic-gate 	}
25280Sstevel@tonic-gate 
25290Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
25300Sstevel@tonic-gate }
25310Sstevel@tonic-gate 
25320Sstevel@tonic-gate 
25330Sstevel@tonic-gate /*
25340Sstevel@tonic-gate  * Encode a 64 bit integer array property
25350Sstevel@tonic-gate  */
25360Sstevel@tonic-gate int
ddi_prop_fm_encode_int64(prop_handle_t * ph,void * data,uint_t nelements)25370Sstevel@tonic-gate ddi_prop_fm_encode_int64(prop_handle_t *ph, void *data, uint_t nelements)
25380Sstevel@tonic-gate {
25390Sstevel@tonic-gate 	int i;
25400Sstevel@tonic-gate 	int cnt;
25410Sstevel@tonic-gate 	int size;
25420Sstevel@tonic-gate 	int64_t *tmp;
25430Sstevel@tonic-gate 
25440Sstevel@tonic-gate 	/*
25450Sstevel@tonic-gate 	 * If there is no data, we cannot do anything
25460Sstevel@tonic-gate 	 */
25470Sstevel@tonic-gate 	if (nelements == 0)
25480Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_ENCODE);
25490Sstevel@tonic-gate 
25500Sstevel@tonic-gate 	/*
25510Sstevel@tonic-gate 	 * Get the size of an encoded 64 bit int.
25520Sstevel@tonic-gate 	 */
25530Sstevel@tonic-gate 	size = DDI_PROP_INT64(ph, DDI_PROP_CMD_GET_ESIZE, NULL);
25540Sstevel@tonic-gate 
25550Sstevel@tonic-gate 	if (size < DDI_PROP_RESULT_OK) {
25560Sstevel@tonic-gate 		switch (size) {
25570Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
25580Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
25590Sstevel@tonic-gate 
25600Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
25610Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_ENCODE);
25620Sstevel@tonic-gate 		}
25630Sstevel@tonic-gate 	}
25640Sstevel@tonic-gate 
25650Sstevel@tonic-gate 	/*
25660Sstevel@tonic-gate 	 * Allocate space in the handle to store the encoded int.
25670Sstevel@tonic-gate 	 */
25680Sstevel@tonic-gate 	if (ddi_prop_encode_alloc(ph, size * nelements) !=
25690Sstevel@tonic-gate 	    DDI_PROP_SUCCESS)
25700Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
25710Sstevel@tonic-gate 
25720Sstevel@tonic-gate 	/*
25730Sstevel@tonic-gate 	 * Encode the array of ints.
25740Sstevel@tonic-gate 	 */
25750Sstevel@tonic-gate 	tmp = (int64_t *)data;
25760Sstevel@tonic-gate 	for (cnt = 0; cnt < nelements; cnt++, tmp++) {
25770Sstevel@tonic-gate 		i = DDI_PROP_INT64(ph, DDI_PROP_CMD_ENCODE, tmp);
25780Sstevel@tonic-gate 		if (i < DDI_PROP_RESULT_OK) {
25790Sstevel@tonic-gate 			switch (i) {
25800Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
25810Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
25820Sstevel@tonic-gate 
25830Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
25840Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_ENCODE);
25850Sstevel@tonic-gate 			}
25860Sstevel@tonic-gate 		}
25870Sstevel@tonic-gate 	}
25880Sstevel@tonic-gate 
25890Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
25900Sstevel@tonic-gate }
25910Sstevel@tonic-gate 
25920Sstevel@tonic-gate /*
25930Sstevel@tonic-gate  * Decode a single string property
25940Sstevel@tonic-gate  */
25950Sstevel@tonic-gate static int
ddi_prop_fm_decode_string(prop_handle_t * ph,void * data,uint_t * nelements)25960Sstevel@tonic-gate ddi_prop_fm_decode_string(prop_handle_t *ph, void *data, uint_t *nelements)
25970Sstevel@tonic-gate {
25980Sstevel@tonic-gate 	char		*tmp;
25990Sstevel@tonic-gate 	char		*str;
26000Sstevel@tonic-gate 	int		i;
26010Sstevel@tonic-gate 	int		size;
26020Sstevel@tonic-gate 
26030Sstevel@tonic-gate 	/*
26040Sstevel@tonic-gate 	 * If there is nothing to decode return an error
26050Sstevel@tonic-gate 	 */
26060Sstevel@tonic-gate 	if (ph->ph_size == 0)
26070Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
26080Sstevel@tonic-gate 
26090Sstevel@tonic-gate 	/*
26100Sstevel@tonic-gate 	 * Get the decoded size of the encoded string.
26110Sstevel@tonic-gate 	 */
26120Sstevel@tonic-gate 	size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
26130Sstevel@tonic-gate 	if (size < DDI_PROP_RESULT_OK) {
26140Sstevel@tonic-gate 		switch (size) {
26150Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
26160Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
26170Sstevel@tonic-gate 
26180Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
26190Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
26200Sstevel@tonic-gate 		}
26210Sstevel@tonic-gate 	}
26220Sstevel@tonic-gate 
26230Sstevel@tonic-gate 	/*
26240Sstevel@tonic-gate 	 * Allocated memory to store the decoded value in.
26250Sstevel@tonic-gate 	 */
26260Sstevel@tonic-gate 	str = ddi_prop_decode_alloc((size_t)size, ddi_prop_free_string);
26270Sstevel@tonic-gate 
26280Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
26290Sstevel@tonic-gate 
26300Sstevel@tonic-gate 	/*
26310Sstevel@tonic-gate 	 * Decode the str and place it in the space we just allocated
26320Sstevel@tonic-gate 	 */
26330Sstevel@tonic-gate 	tmp = str;
26340Sstevel@tonic-gate 	i = DDI_PROP_STR(ph, DDI_PROP_CMD_DECODE, tmp);
26350Sstevel@tonic-gate 	if (i < DDI_PROP_RESULT_OK) {
26360Sstevel@tonic-gate 		/*
26370Sstevel@tonic-gate 		 * Free the space we just allocated
26380Sstevel@tonic-gate 		 * and return an error.
26390Sstevel@tonic-gate 		 */
26400Sstevel@tonic-gate 		ddi_prop_free(str);
26410Sstevel@tonic-gate 		switch (i) {
26420Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
26430Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
26440Sstevel@tonic-gate 
26450Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
26460Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
26470Sstevel@tonic-gate 		}
26480Sstevel@tonic-gate 	}
26490Sstevel@tonic-gate 
26500Sstevel@tonic-gate 	*(char **)data = str;
26510Sstevel@tonic-gate 	*nelements = 1;
26520Sstevel@tonic-gate 
26530Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
26540Sstevel@tonic-gate }
26550Sstevel@tonic-gate 
26560Sstevel@tonic-gate /*
26570Sstevel@tonic-gate  * Decode an array of strings.
26580Sstevel@tonic-gate  */
26590Sstevel@tonic-gate int
ddi_prop_fm_decode_strings(prop_handle_t * ph,void * data,uint_t * nelements)26600Sstevel@tonic-gate ddi_prop_fm_decode_strings(prop_handle_t *ph, void *data, uint_t *nelements)
26610Sstevel@tonic-gate {
26620Sstevel@tonic-gate 	int		cnt = 0;
26630Sstevel@tonic-gate 	char		**strs;
26640Sstevel@tonic-gate 	char		**tmp;
26650Sstevel@tonic-gate 	char		*ptr;
26660Sstevel@tonic-gate 	int		i;
26670Sstevel@tonic-gate 	int		n;
26680Sstevel@tonic-gate 	int		size;
26690Sstevel@tonic-gate 	size_t		nbytes;
26700Sstevel@tonic-gate 
26710Sstevel@tonic-gate 	/*
26720Sstevel@tonic-gate 	 * Figure out how many array elements there are by going through the
26730Sstevel@tonic-gate 	 * data without decoding it first and counting.
26740Sstevel@tonic-gate 	 */
26750Sstevel@tonic-gate 	for (;;) {
26760Sstevel@tonic-gate 		i = DDI_PROP_STR(ph, DDI_PROP_CMD_SKIP, NULL);
26770Sstevel@tonic-gate 		if (i < 0)
26780Sstevel@tonic-gate 			break;
26790Sstevel@tonic-gate 		cnt++;
26800Sstevel@tonic-gate 	}
26810Sstevel@tonic-gate 
26820Sstevel@tonic-gate 	/*
26830Sstevel@tonic-gate 	 * If there are no elements return an error
26840Sstevel@tonic-gate 	 */
26850Sstevel@tonic-gate 	if (cnt == 0)
26860Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
26870Sstevel@tonic-gate 
26880Sstevel@tonic-gate 	/*
26890Sstevel@tonic-gate 	 * If we cannot skip through the data, we cannot decode it
26900Sstevel@tonic-gate 	 */
26910Sstevel@tonic-gate 	if (i == DDI_PROP_RESULT_ERROR)
26920Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_DECODE);
26930Sstevel@tonic-gate 
26940Sstevel@tonic-gate 	/*
26950Sstevel@tonic-gate 	 * Reset the data pointer to the beginning of the encoded data
26960Sstevel@tonic-gate 	 */
26970Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
26980Sstevel@tonic-gate 
26990Sstevel@tonic-gate 	/*
27000Sstevel@tonic-gate 	 * Figure out how much memory we need for the sum total
27010Sstevel@tonic-gate 	 */
27020Sstevel@tonic-gate 	nbytes = (cnt + 1) * sizeof (char *);
27030Sstevel@tonic-gate 
27040Sstevel@tonic-gate 	for (n = 0; n < cnt; n++) {
27050Sstevel@tonic-gate 		/*
27060Sstevel@tonic-gate 		 * Get the decoded size of the current encoded string.
27070Sstevel@tonic-gate 		 */
27080Sstevel@tonic-gate 		size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
27090Sstevel@tonic-gate 		if (size < DDI_PROP_RESULT_OK) {
27100Sstevel@tonic-gate 			switch (size) {
27110Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
27120Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
27130Sstevel@tonic-gate 
27140Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
27150Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_DECODE);
27160Sstevel@tonic-gate 			}
27170Sstevel@tonic-gate 		}
27180Sstevel@tonic-gate 
27190Sstevel@tonic-gate 		nbytes += size;
27200Sstevel@tonic-gate 	}
27210Sstevel@tonic-gate 
27220Sstevel@tonic-gate 	/*
27230Sstevel@tonic-gate 	 * Allocate memory in which to store the decoded strings.
27240Sstevel@tonic-gate 	 */
27250Sstevel@tonic-gate 	strs = ddi_prop_decode_alloc(nbytes, ddi_prop_free_strings);
27260Sstevel@tonic-gate 
27270Sstevel@tonic-gate 	/*
27280Sstevel@tonic-gate 	 * Set up pointers for each string by figuring out yet
27290Sstevel@tonic-gate 	 * again how long each string is.
27300Sstevel@tonic-gate 	 */
27310Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
27320Sstevel@tonic-gate 	ptr = (caddr_t)strs + ((cnt + 1) * sizeof (char *));
27330Sstevel@tonic-gate 	for (tmp = strs, n = 0; n < cnt; n++, tmp++) {
27340Sstevel@tonic-gate 		/*
27350Sstevel@tonic-gate 		 * Get the decoded size of the current encoded string.
27360Sstevel@tonic-gate 		 */
27370Sstevel@tonic-gate 		size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_DSIZE, NULL);
27380Sstevel@tonic-gate 		if (size < DDI_PROP_RESULT_OK) {
27390Sstevel@tonic-gate 			ddi_prop_free(strs);
27400Sstevel@tonic-gate 			switch (size) {
27410Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
27420Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
27430Sstevel@tonic-gate 
27440Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
27450Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_DECODE);
27460Sstevel@tonic-gate 			}
27470Sstevel@tonic-gate 		}
27480Sstevel@tonic-gate 
27490Sstevel@tonic-gate 		*tmp = ptr;
27500Sstevel@tonic-gate 		ptr += size;
27510Sstevel@tonic-gate 	}
27520Sstevel@tonic-gate 
27530Sstevel@tonic-gate 	/*
27540Sstevel@tonic-gate 	 * String array is terminated by a NULL
27550Sstevel@tonic-gate 	 */
27560Sstevel@tonic-gate 	*tmp = NULL;
27570Sstevel@tonic-gate 
27580Sstevel@tonic-gate 	/*
27590Sstevel@tonic-gate 	 * Finally, we can decode each string
27600Sstevel@tonic-gate 	 */
27610Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
27620Sstevel@tonic-gate 	for (tmp = strs, n = 0; n < cnt; n++, tmp++) {
27630Sstevel@tonic-gate 		i = DDI_PROP_STR(ph, DDI_PROP_CMD_DECODE, *tmp);
27640Sstevel@tonic-gate 		if (i < DDI_PROP_RESULT_OK) {
27650Sstevel@tonic-gate 			/*
27660Sstevel@tonic-gate 			 * Free the space we just allocated
27670Sstevel@tonic-gate 			 * and return an error
27680Sstevel@tonic-gate 			 */
27690Sstevel@tonic-gate 			ddi_prop_free(strs);
27700Sstevel@tonic-gate 			switch (i) {
27710Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
27720Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
27730Sstevel@tonic-gate 
27740Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
27750Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_DECODE);
27760Sstevel@tonic-gate 			}
27770Sstevel@tonic-gate 		}
27780Sstevel@tonic-gate 	}
27790Sstevel@tonic-gate 
27800Sstevel@tonic-gate 	*(char ***)data = strs;
27810Sstevel@tonic-gate 	*nelements = cnt;
27820Sstevel@tonic-gate 
27830Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
27840Sstevel@tonic-gate }
27850Sstevel@tonic-gate 
27860Sstevel@tonic-gate /*
27870Sstevel@tonic-gate  * Encode a string.
27880Sstevel@tonic-gate  */
27890Sstevel@tonic-gate int
ddi_prop_fm_encode_string(prop_handle_t * ph,void * data,uint_t nelements)27900Sstevel@tonic-gate ddi_prop_fm_encode_string(prop_handle_t *ph, void *data, uint_t nelements)
27910Sstevel@tonic-gate {
27920Sstevel@tonic-gate 	char		**tmp;
27930Sstevel@tonic-gate 	int		size;
27940Sstevel@tonic-gate 	int		i;
27950Sstevel@tonic-gate 
27960Sstevel@tonic-gate 	/*
27970Sstevel@tonic-gate 	 * If there is no data, we cannot do anything
27980Sstevel@tonic-gate 	 */
27990Sstevel@tonic-gate 	if (nelements == 0)
28000Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_ENCODE);
28010Sstevel@tonic-gate 
28020Sstevel@tonic-gate 	/*
28030Sstevel@tonic-gate 	 * Get the size of the encoded string.
28040Sstevel@tonic-gate 	 */
28050Sstevel@tonic-gate 	tmp = (char **)data;
28060Sstevel@tonic-gate 	size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_ESIZE, *tmp);
28070Sstevel@tonic-gate 	if (size < DDI_PROP_RESULT_OK) {
28080Sstevel@tonic-gate 		switch (size) {
28090Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
28100Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
28110Sstevel@tonic-gate 
28120Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
28130Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_ENCODE);
28140Sstevel@tonic-gate 		}
28150Sstevel@tonic-gate 	}
28160Sstevel@tonic-gate 
28170Sstevel@tonic-gate 	/*
28180Sstevel@tonic-gate 	 * Allocate space in the handle to store the encoded string.
28190Sstevel@tonic-gate 	 */
28200Sstevel@tonic-gate 	if (ddi_prop_encode_alloc(ph, size) != DDI_PROP_SUCCESS)
28210Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
28220Sstevel@tonic-gate 
28230Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
28240Sstevel@tonic-gate 
28250Sstevel@tonic-gate 	/*
28260Sstevel@tonic-gate 	 * Encode the string.
28270Sstevel@tonic-gate 	 */
28280Sstevel@tonic-gate 	tmp = (char **)data;
28290Sstevel@tonic-gate 	i = DDI_PROP_STR(ph, DDI_PROP_CMD_ENCODE, *tmp);
28300Sstevel@tonic-gate 	if (i < DDI_PROP_RESULT_OK) {
28310Sstevel@tonic-gate 		switch (i) {
28320Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
28330Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
28340Sstevel@tonic-gate 
28350Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
28360Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_ENCODE);
28370Sstevel@tonic-gate 		}
28380Sstevel@tonic-gate 	}
28390Sstevel@tonic-gate 
28400Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
28410Sstevel@tonic-gate }
28420Sstevel@tonic-gate 
28430Sstevel@tonic-gate 
28440Sstevel@tonic-gate /*
28450Sstevel@tonic-gate  * Encode an array of strings.
28460Sstevel@tonic-gate  */
28470Sstevel@tonic-gate int
ddi_prop_fm_encode_strings(prop_handle_t * ph,void * data,uint_t nelements)28480Sstevel@tonic-gate ddi_prop_fm_encode_strings(prop_handle_t *ph, void *data, uint_t nelements)
28490Sstevel@tonic-gate {
28500Sstevel@tonic-gate 	int		cnt = 0;
28510Sstevel@tonic-gate 	char		**tmp;
28520Sstevel@tonic-gate 	int		size;
28530Sstevel@tonic-gate 	uint_t		total_size;
28540Sstevel@tonic-gate 	int		i;
28550Sstevel@tonic-gate 
28560Sstevel@tonic-gate 	/*
28570Sstevel@tonic-gate 	 * If there is no data, we cannot do anything
28580Sstevel@tonic-gate 	 */
28590Sstevel@tonic-gate 	if (nelements == 0)
28600Sstevel@tonic-gate 		return (DDI_PROP_CANNOT_ENCODE);
28610Sstevel@tonic-gate 
28620Sstevel@tonic-gate 	/*
28630Sstevel@tonic-gate 	 * Get the total size required to encode all the strings.
28640Sstevel@tonic-gate 	 */
28650Sstevel@tonic-gate 	total_size = 0;
28660Sstevel@tonic-gate 	tmp = (char **)data;
28670Sstevel@tonic-gate 	for (cnt = 0; cnt < nelements; cnt++, tmp++) {
28680Sstevel@tonic-gate 		size = DDI_PROP_STR(ph, DDI_PROP_CMD_GET_ESIZE, *tmp);
28690Sstevel@tonic-gate 		if (size < DDI_PROP_RESULT_OK) {
28700Sstevel@tonic-gate 			switch (size) {
28710Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
28720Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
28730Sstevel@tonic-gate 
28740Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
28750Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_ENCODE);
28760Sstevel@tonic-gate 			}
28770Sstevel@tonic-gate 		}
28780Sstevel@tonic-gate 		total_size += (uint_t)size;
28790Sstevel@tonic-gate 	}
28800Sstevel@tonic-gate 
28810Sstevel@tonic-gate 	/*
28820Sstevel@tonic-gate 	 * Allocate space in the handle to store the encoded strings.
28830Sstevel@tonic-gate 	 */
28840Sstevel@tonic-gate 	if (ddi_prop_encode_alloc(ph, total_size) != DDI_PROP_SUCCESS)
28850Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
28860Sstevel@tonic-gate 
28870Sstevel@tonic-gate 	ddi_prop_reset_pos(ph);
28880Sstevel@tonic-gate 
28890Sstevel@tonic-gate 	/*
28900Sstevel@tonic-gate 	 * Encode the array of strings.
28910Sstevel@tonic-gate 	 */
28920Sstevel@tonic-gate 	tmp = (char **)data;
28930Sstevel@tonic-gate 	for (cnt = 0; cnt < nelements; cnt++, tmp++) {
28940Sstevel@tonic-gate 		i = DDI_PROP_STR(ph, DDI_PROP_CMD_ENCODE, *tmp);
28950Sstevel@tonic-gate 		if (i < DDI_PROP_RESULT_OK) {
28960Sstevel@tonic-gate 			switch (i) {
28970Sstevel@tonic-gate 			case DDI_PROP_RESULT_EOF:
28980Sstevel@tonic-gate 				return (DDI_PROP_END_OF_DATA);
28990Sstevel@tonic-gate 
29000Sstevel@tonic-gate 			case DDI_PROP_RESULT_ERROR:
29010Sstevel@tonic-gate 				return (DDI_PROP_CANNOT_ENCODE);
29020Sstevel@tonic-gate 			}
29030Sstevel@tonic-gate 		}
29040Sstevel@tonic-gate 	}
29050Sstevel@tonic-gate 
29060Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
29070Sstevel@tonic-gate }
29080Sstevel@tonic-gate 
29090Sstevel@tonic-gate 
29100Sstevel@tonic-gate /*
29110Sstevel@tonic-gate  * Decode an array of bytes.
29120Sstevel@tonic-gate  */
29130Sstevel@tonic-gate static int
ddi_prop_fm_decode_bytes(prop_handle_t * ph,void * data,uint_t * nelements)29140Sstevel@tonic-gate ddi_prop_fm_decode_bytes(prop_handle_t *ph, void *data, uint_t *nelements)
29150Sstevel@tonic-gate {
29160Sstevel@tonic-gate 	uchar_t		*tmp;
29170Sstevel@tonic-gate 	int		nbytes;
29180Sstevel@tonic-gate 	int		i;
29190Sstevel@tonic-gate 
29200Sstevel@tonic-gate 	/*
29210Sstevel@tonic-gate 	 * If there are no elements return an error
29220Sstevel@tonic-gate 	 */
29230Sstevel@tonic-gate 	if (ph->ph_size == 0)
29240Sstevel@tonic-gate 		return (DDI_PROP_END_OF_DATA);
29250Sstevel@tonic-gate 
29260Sstevel@tonic-gate 	/*
29270Sstevel@tonic-gate 	 * Get the size of the encoded array of bytes.
29280Sstevel@tonic-gate 	 */
29290Sstevel@tonic-gate 	nbytes = DDI_PROP_BYTES(ph, DDI_PROP_CMD_GET_DSIZE,
29304582Scth 	    data, ph->ph_size);
29310Sstevel@tonic-gate 	if (nbytes < DDI_PROP_RESULT_OK) {
29320Sstevel@tonic-gate 		switch (nbytes) {
29330Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
29340Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
29350Sstevel@tonic-gate 
29360Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
29370Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
29380Sstevel@tonic-gate 		}
29390Sstevel@tonic-gate 	}
29400Sstevel@tonic-gate 
29410Sstevel@tonic-gate 	/*
29420Sstevel@tonic-gate 	 * Allocated memory to store the decoded value in.
29430Sstevel@tonic-gate 	 */
29440Sstevel@tonic-gate 	tmp = ddi_prop_decode_alloc(nbytes, ddi_prop_free_bytes);
29450Sstevel@tonic-gate 
29460Sstevel@tonic-gate 	/*
29470Sstevel@tonic-gate 	 * Decode each element and place it in the space we just allocated
29480Sstevel@tonic-gate 	 */
29490Sstevel@tonic-gate 	i = DDI_PROP_BYTES(ph, DDI_PROP_CMD_DECODE, tmp, nbytes);
29500Sstevel@tonic-gate 	if (i < DDI_PROP_RESULT_OK) {
29510Sstevel@tonic-gate 		/*
29520Sstevel@tonic-gate 		 * Free the space we just allocated
29530Sstevel@tonic-gate 		 * and return an error
29540Sstevel@tonic-gate 		 */
29550Sstevel@tonic-gate 		ddi_prop_free(tmp);
29560Sstevel@tonic-gate 		switch (i) {
29570Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
29580Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
29590Sstevel@tonic-gate 
29600Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
29610Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
29620Sstevel@tonic-gate 		}
29630Sstevel@tonic-gate 	}
29640Sstevel@tonic-gate 
29650Sstevel@tonic-gate 	*(uchar_t **)data = tmp;
29660Sstevel@tonic-gate 	*nelements = nbytes;
29670Sstevel@tonic-gate 
29680Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
29690Sstevel@tonic-gate }
29700Sstevel@tonic-gate 
29710Sstevel@tonic-gate /*
29720Sstevel@tonic-gate  * Encode an array of bytes.
29730Sstevel@tonic-gate  */
29740Sstevel@tonic-gate int
ddi_prop_fm_encode_bytes(prop_handle_t * ph,void * data,uint_t nelements)29750Sstevel@tonic-gate ddi_prop_fm_encode_bytes(prop_handle_t *ph, void *data, uint_t nelements)
29760Sstevel@tonic-gate {
29770Sstevel@tonic-gate 	int		size;
29780Sstevel@tonic-gate 	int		i;
29790Sstevel@tonic-gate 
29800Sstevel@tonic-gate 	/*
29810Sstevel@tonic-gate 	 * If there are no elements, then this is a boolean property,
29820Sstevel@tonic-gate 	 * so just create a property handle with no data and return.
29830Sstevel@tonic-gate 	 */
29840Sstevel@tonic-gate 	if (nelements == 0) {
29850Sstevel@tonic-gate 		(void) ddi_prop_encode_alloc(ph, 0);
29860Sstevel@tonic-gate 		return (DDI_PROP_SUCCESS);
29870Sstevel@tonic-gate 	}
29880Sstevel@tonic-gate 
29890Sstevel@tonic-gate 	/*
29900Sstevel@tonic-gate 	 * Get the size of the encoded array of bytes.
29910Sstevel@tonic-gate 	 */
29920Sstevel@tonic-gate 	size = DDI_PROP_BYTES(ph, DDI_PROP_CMD_GET_ESIZE, (uchar_t *)data,
29934582Scth 	    nelements);
29940Sstevel@tonic-gate 	if (size < DDI_PROP_RESULT_OK) {
29950Sstevel@tonic-gate 		switch (size) {
29960Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
29970Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
29980Sstevel@tonic-gate 
29990Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
30000Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_DECODE);
30010Sstevel@tonic-gate 		}
30020Sstevel@tonic-gate 	}
30030Sstevel@tonic-gate 
30040Sstevel@tonic-gate 	/*
30050Sstevel@tonic-gate 	 * Allocate space in the handle to store the encoded bytes.
30060Sstevel@tonic-gate 	 */
30070Sstevel@tonic-gate 	if (ddi_prop_encode_alloc(ph, (uint_t)size) != DDI_PROP_SUCCESS)
30080Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
30090Sstevel@tonic-gate 
30100Sstevel@tonic-gate 	/*
30110Sstevel@tonic-gate 	 * Encode the array of bytes.
30120Sstevel@tonic-gate 	 */
30130Sstevel@tonic-gate 	i = DDI_PROP_BYTES(ph, DDI_PROP_CMD_ENCODE, (uchar_t *)data,
30144582Scth 	    nelements);
30150Sstevel@tonic-gate 	if (i < DDI_PROP_RESULT_OK) {
30160Sstevel@tonic-gate 		switch (i) {
30170Sstevel@tonic-gate 		case DDI_PROP_RESULT_EOF:
30180Sstevel@tonic-gate 			return (DDI_PROP_END_OF_DATA);
30190Sstevel@tonic-gate 
30200Sstevel@tonic-gate 		case DDI_PROP_RESULT_ERROR:
30210Sstevel@tonic-gate 			return (DDI_PROP_CANNOT_ENCODE);
30220Sstevel@tonic-gate 		}
30230Sstevel@tonic-gate 	}
30240Sstevel@tonic-gate 
30250Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
30260Sstevel@tonic-gate }
30270Sstevel@tonic-gate 
30280Sstevel@tonic-gate /*
30290Sstevel@tonic-gate  * OBP 1275 integer, string and byte operators.
30300Sstevel@tonic-gate  *
30310Sstevel@tonic-gate  * DDI_PROP_CMD_DECODE:
30320Sstevel@tonic-gate  *
30330Sstevel@tonic-gate  *	DDI_PROP_RESULT_ERROR:		cannot decode the data
30340Sstevel@tonic-gate  *	DDI_PROP_RESULT_EOF:		end of data
30350Sstevel@tonic-gate  *	DDI_PROP_OK:			data was decoded
30360Sstevel@tonic-gate  *
30370Sstevel@tonic-gate  * DDI_PROP_CMD_ENCODE:
30380Sstevel@tonic-gate  *
30390Sstevel@tonic-gate  *	DDI_PROP_RESULT_ERROR:		cannot encode the data
30400Sstevel@tonic-gate  *	DDI_PROP_RESULT_EOF:		end of data
30410Sstevel@tonic-gate  *	DDI_PROP_OK:			data was encoded
30420Sstevel@tonic-gate  *
30430Sstevel@tonic-gate  * DDI_PROP_CMD_SKIP:
30440Sstevel@tonic-gate  *
30450Sstevel@tonic-gate  *	DDI_PROP_RESULT_ERROR:		cannot skip the data
30460Sstevel@tonic-gate  *	DDI_PROP_RESULT_EOF:		end of data
30470Sstevel@tonic-gate  *	DDI_PROP_OK:			data was skipped
30480Sstevel@tonic-gate  *
30490Sstevel@tonic-gate  * DDI_PROP_CMD_GET_ESIZE:
30500Sstevel@tonic-gate  *
30510Sstevel@tonic-gate  *	DDI_PROP_RESULT_ERROR:		cannot get encoded size
30520Sstevel@tonic-gate  *	DDI_PROP_RESULT_EOF:		end of data
30530Sstevel@tonic-gate  *	> 0:				the encoded size
30540Sstevel@tonic-gate  *
30550Sstevel@tonic-gate  * DDI_PROP_CMD_GET_DSIZE:
30560Sstevel@tonic-gate  *
30570Sstevel@tonic-gate  *	DDI_PROP_RESULT_ERROR:		cannot get decoded size
30580Sstevel@tonic-gate  *	DDI_PROP_RESULT_EOF:		end of data
30590Sstevel@tonic-gate  *	> 0:				the decoded size
30600Sstevel@tonic-gate  */
30610Sstevel@tonic-gate 
30620Sstevel@tonic-gate /*
30630Sstevel@tonic-gate  * OBP 1275 integer operator
30640Sstevel@tonic-gate  *
30650Sstevel@tonic-gate  * OBP properties are a byte stream of data, so integers may not be
30660Sstevel@tonic-gate  * properly aligned.  Therefore we need to copy them one byte at a time.
30670Sstevel@tonic-gate  */
30680Sstevel@tonic-gate int
ddi_prop_1275_int(prop_handle_t * ph,uint_t cmd,int * data)30690Sstevel@tonic-gate ddi_prop_1275_int(prop_handle_t *ph, uint_t cmd, int *data)
30700Sstevel@tonic-gate {
30710Sstevel@tonic-gate 	int	i;
30720Sstevel@tonic-gate 
30730Sstevel@tonic-gate 	switch (cmd) {
30740Sstevel@tonic-gate 	case DDI_PROP_CMD_DECODE:
30750Sstevel@tonic-gate 		/*
30760Sstevel@tonic-gate 		 * Check that there is encoded data
30770Sstevel@tonic-gate 		 */
30780Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
30790Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
30800Sstevel@tonic-gate 		if (ph->ph_flags & PH_FROM_PROM) {
30810Sstevel@tonic-gate 			i = MIN(ph->ph_size, PROP_1275_INT_SIZE);
30820Sstevel@tonic-gate 			if ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
30834582Scth 			    ph->ph_size - i))
30840Sstevel@tonic-gate 				return (DDI_PROP_RESULT_ERROR);
30850Sstevel@tonic-gate 		} else {
30860Sstevel@tonic-gate 			if (ph->ph_size < sizeof (int) ||
30874582Scth 			    ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
30884582Scth 			    ph->ph_size - sizeof (int))))
30894582Scth 				return (DDI_PROP_RESULT_ERROR);
30900Sstevel@tonic-gate 		}
30910Sstevel@tonic-gate 
30920Sstevel@tonic-gate 		/*
30930Sstevel@tonic-gate 		 * Copy the integer, using the implementation-specific
30940Sstevel@tonic-gate 		 * copy function if the property is coming from the PROM.
30950Sstevel@tonic-gate 		 */
30960Sstevel@tonic-gate 		if (ph->ph_flags & PH_FROM_PROM) {
30970Sstevel@tonic-gate 			*data = impl_ddi_prop_int_from_prom(
30984582Scth 			    (uchar_t *)ph->ph_cur_pos,
30994582Scth 			    (ph->ph_size < PROP_1275_INT_SIZE) ?
31004582Scth 			    ph->ph_size : PROP_1275_INT_SIZE);
31010Sstevel@tonic-gate 		} else {
31020Sstevel@tonic-gate 			bcopy(ph->ph_cur_pos, data, sizeof (int));
31030Sstevel@tonic-gate 		}
31040Sstevel@tonic-gate 
31050Sstevel@tonic-gate 		/*
31060Sstevel@tonic-gate 		 * Move the current location to the start of the next
31070Sstevel@tonic-gate 		 * bit of undecoded data.
31080Sstevel@tonic-gate 		 */
31090Sstevel@tonic-gate 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
31104582Scth 		    PROP_1275_INT_SIZE;
31110Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
31120Sstevel@tonic-gate 
31130Sstevel@tonic-gate 	case DDI_PROP_CMD_ENCODE:
31140Sstevel@tonic-gate 		/*
31150Sstevel@tonic-gate 		 * Check that there is room to encoded the data
31160Sstevel@tonic-gate 		 */
31170Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
31184582Scth 		    ph->ph_size < PROP_1275_INT_SIZE ||
31194582Scth 		    ((int *)ph->ph_cur_pos > ((int *)ph->ph_data +
31204582Scth 		    ph->ph_size - sizeof (int))))
31210Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
31220Sstevel@tonic-gate 
31230Sstevel@tonic-gate 		/*
31240Sstevel@tonic-gate 		 * Encode the integer into the byte stream one byte at a
31250Sstevel@tonic-gate 		 * time.
31260Sstevel@tonic-gate 		 */
31270Sstevel@tonic-gate 		bcopy(data, ph->ph_cur_pos, sizeof (int));
31280Sstevel@tonic-gate 
31290Sstevel@tonic-gate 		/*
31300Sstevel@tonic-gate 		 * Move the current location to the start of the next bit of
31310Sstevel@tonic-gate 		 * space where we can store encoded data.
31320Sstevel@tonic-gate 		 */
31330Sstevel@tonic-gate 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
31340Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
31350Sstevel@tonic-gate 
31360Sstevel@tonic-gate 	case DDI_PROP_CMD_SKIP:
31370Sstevel@tonic-gate 		/*
31380Sstevel@tonic-gate 		 * Check that there is encoded data
31390Sstevel@tonic-gate 		 */
31400Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
31414582Scth 		    ph->ph_size < PROP_1275_INT_SIZE)
31420Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
31430Sstevel@tonic-gate 
31440Sstevel@tonic-gate 
31450Sstevel@tonic-gate 		if ((caddr_t)ph->ph_cur_pos ==
31464582Scth 		    (caddr_t)ph->ph_data + ph->ph_size) {
31470Sstevel@tonic-gate 			return (DDI_PROP_RESULT_EOF);
31480Sstevel@tonic-gate 		} else if ((caddr_t)ph->ph_cur_pos >
31494582Scth 		    (caddr_t)ph->ph_data + ph->ph_size) {
31500Sstevel@tonic-gate 			return (DDI_PROP_RESULT_EOF);
31510Sstevel@tonic-gate 		}
31520Sstevel@tonic-gate 
31530Sstevel@tonic-gate 		/*
31540Sstevel@tonic-gate 		 * Move the current location to the start of the next bit of
31550Sstevel@tonic-gate 		 * undecoded data.
31560Sstevel@tonic-gate 		 */
31570Sstevel@tonic-gate 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos + PROP_1275_INT_SIZE;
31580Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
31590Sstevel@tonic-gate 
31600Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_ESIZE:
31610Sstevel@tonic-gate 		/*
31620Sstevel@tonic-gate 		 * Return the size of an encoded integer on OBP
31630Sstevel@tonic-gate 		 */
31640Sstevel@tonic-gate 		return (PROP_1275_INT_SIZE);
31650Sstevel@tonic-gate 
31660Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_DSIZE:
31670Sstevel@tonic-gate 		/*
31680Sstevel@tonic-gate 		 * Return the size of a decoded integer on the system.
31690Sstevel@tonic-gate 		 */
31700Sstevel@tonic-gate 		return (sizeof (int));
31710Sstevel@tonic-gate 
31720Sstevel@tonic-gate 	default:
31730Sstevel@tonic-gate #ifdef DEBUG
31740Sstevel@tonic-gate 		panic("ddi_prop_1275_int: %x impossible", cmd);
31750Sstevel@tonic-gate 		/*NOTREACHED*/
31760Sstevel@tonic-gate #else
31770Sstevel@tonic-gate 		return (DDI_PROP_RESULT_ERROR);
31780Sstevel@tonic-gate #endif	/* DEBUG */
31790Sstevel@tonic-gate 	}
31800Sstevel@tonic-gate }
31810Sstevel@tonic-gate 
31820Sstevel@tonic-gate /*
31830Sstevel@tonic-gate  * 64 bit integer operator.
31840Sstevel@tonic-gate  *
31850Sstevel@tonic-gate  * This is an extension, defined by Sun, to the 1275 integer
31860Sstevel@tonic-gate  * operator.  This routine handles the encoding/decoding of
31870Sstevel@tonic-gate  * 64 bit integer properties.
31880Sstevel@tonic-gate  */
31890Sstevel@tonic-gate int
ddi_prop_int64_op(prop_handle_t * ph,uint_t cmd,int64_t * data)31900Sstevel@tonic-gate ddi_prop_int64_op(prop_handle_t *ph, uint_t cmd, int64_t *data)
31910Sstevel@tonic-gate {
31920Sstevel@tonic-gate 
31930Sstevel@tonic-gate 	switch (cmd) {
31940Sstevel@tonic-gate 	case DDI_PROP_CMD_DECODE:
31950Sstevel@tonic-gate 		/*
31960Sstevel@tonic-gate 		 * Check that there is encoded data
31970Sstevel@tonic-gate 		 */
31980Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0)
31990Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
32000Sstevel@tonic-gate 		if (ph->ph_flags & PH_FROM_PROM) {
32010Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
32020Sstevel@tonic-gate 		} else {
32030Sstevel@tonic-gate 			if (ph->ph_size < sizeof (int64_t) ||
32040Sstevel@tonic-gate 			    ((int64_t *)ph->ph_cur_pos >
32050Sstevel@tonic-gate 			    ((int64_t *)ph->ph_data +
32060Sstevel@tonic-gate 			    ph->ph_size - sizeof (int64_t))))
32070Sstevel@tonic-gate 				return (DDI_PROP_RESULT_ERROR);
32080Sstevel@tonic-gate 		}
32090Sstevel@tonic-gate 		/*
32100Sstevel@tonic-gate 		 * Copy the integer, using the implementation-specific
32110Sstevel@tonic-gate 		 * copy function if the property is coming from the PROM.
32120Sstevel@tonic-gate 		 */
32130Sstevel@tonic-gate 		if (ph->ph_flags & PH_FROM_PROM) {
32140Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
32150Sstevel@tonic-gate 		} else {
32160Sstevel@tonic-gate 			bcopy(ph->ph_cur_pos, data, sizeof (int64_t));
32170Sstevel@tonic-gate 		}
32180Sstevel@tonic-gate 
32190Sstevel@tonic-gate 		/*
32200Sstevel@tonic-gate 		 * Move the current location to the start of the next
32210Sstevel@tonic-gate 		 * bit of undecoded data.
32220Sstevel@tonic-gate 		 */
32230Sstevel@tonic-gate 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
32240Sstevel@tonic-gate 		    sizeof (int64_t);
32250Sstevel@tonic-gate 			return (DDI_PROP_RESULT_OK);
32260Sstevel@tonic-gate 
32270Sstevel@tonic-gate 	case DDI_PROP_CMD_ENCODE:
32280Sstevel@tonic-gate 		/*
32290Sstevel@tonic-gate 		 * Check that there is room to encoded the data
32300Sstevel@tonic-gate 		 */
32310Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
32320Sstevel@tonic-gate 		    ph->ph_size < sizeof (int64_t) ||
32330Sstevel@tonic-gate 		    ((int64_t *)ph->ph_cur_pos > ((int64_t *)ph->ph_data +
32340Sstevel@tonic-gate 		    ph->ph_size - sizeof (int64_t))))
32350Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
32360Sstevel@tonic-gate 
32370Sstevel@tonic-gate 		/*
32380Sstevel@tonic-gate 		 * Encode the integer into the byte stream one byte at a
32390Sstevel@tonic-gate 		 * time.
32400Sstevel@tonic-gate 		 */
32410Sstevel@tonic-gate 		bcopy(data, ph->ph_cur_pos, sizeof (int64_t));
32420Sstevel@tonic-gate 
32430Sstevel@tonic-gate 		/*
32440Sstevel@tonic-gate 		 * Move the current location to the start of the next bit of
32450Sstevel@tonic-gate 		 * space where we can store encoded data.
32460Sstevel@tonic-gate 		 */
32470Sstevel@tonic-gate 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
32480Sstevel@tonic-gate 		    sizeof (int64_t);
32490Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
32500Sstevel@tonic-gate 
32510Sstevel@tonic-gate 	case DDI_PROP_CMD_SKIP:
32520Sstevel@tonic-gate 		/*
32530Sstevel@tonic-gate 		 * Check that there is encoded data
32540Sstevel@tonic-gate 		 */
32550Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
32560Sstevel@tonic-gate 		    ph->ph_size < sizeof (int64_t))
32570Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
32580Sstevel@tonic-gate 
32590Sstevel@tonic-gate 		if ((caddr_t)ph->ph_cur_pos ==
32600Sstevel@tonic-gate 		    (caddr_t)ph->ph_data + ph->ph_size) {
32610Sstevel@tonic-gate 			return (DDI_PROP_RESULT_EOF);
32620Sstevel@tonic-gate 		} else if ((caddr_t)ph->ph_cur_pos >
32630Sstevel@tonic-gate 		    (caddr_t)ph->ph_data + ph->ph_size) {
32640Sstevel@tonic-gate 			return (DDI_PROP_RESULT_EOF);
32650Sstevel@tonic-gate 		}
32660Sstevel@tonic-gate 
32670Sstevel@tonic-gate 		/*
32680Sstevel@tonic-gate 		 * Move the current location to the start of
32690Sstevel@tonic-gate 		 * the next bit of undecoded data.
32700Sstevel@tonic-gate 		 */
32710Sstevel@tonic-gate 		ph->ph_cur_pos = (uchar_t *)ph->ph_cur_pos +
32720Sstevel@tonic-gate 		    sizeof (int64_t);
32730Sstevel@tonic-gate 			return (DDI_PROP_RESULT_OK);
32740Sstevel@tonic-gate 
32750Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_ESIZE:
32760Sstevel@tonic-gate 		/*
32770Sstevel@tonic-gate 		 * Return the size of an encoded integer on OBP
32780Sstevel@tonic-gate 		 */
32790Sstevel@tonic-gate 		return (sizeof (int64_t));
32800Sstevel@tonic-gate 
32810Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_DSIZE:
32820Sstevel@tonic-gate 		/*
32830Sstevel@tonic-gate 		 * Return the size of a decoded integer on the system.
32840Sstevel@tonic-gate 		 */
32850Sstevel@tonic-gate 		return (sizeof (int64_t));
32860Sstevel@tonic-gate 
32870Sstevel@tonic-gate 	default:
32880Sstevel@tonic-gate #ifdef DEBUG
32890Sstevel@tonic-gate 		panic("ddi_prop_int64_op: %x impossible", cmd);
32900Sstevel@tonic-gate 		/*NOTREACHED*/
32910Sstevel@tonic-gate #else
32920Sstevel@tonic-gate 		return (DDI_PROP_RESULT_ERROR);
32930Sstevel@tonic-gate #endif  /* DEBUG */
32940Sstevel@tonic-gate 	}
32950Sstevel@tonic-gate }
32960Sstevel@tonic-gate 
32970Sstevel@tonic-gate /*
32980Sstevel@tonic-gate  * OBP 1275 string operator.
32990Sstevel@tonic-gate  *
33000Sstevel@tonic-gate  * OBP strings are NULL terminated.
33010Sstevel@tonic-gate  */
33020Sstevel@tonic-gate int
ddi_prop_1275_string(prop_handle_t * ph,uint_t cmd,char * data)33030Sstevel@tonic-gate ddi_prop_1275_string(prop_handle_t *ph, uint_t cmd, char *data)
33040Sstevel@tonic-gate {
33050Sstevel@tonic-gate 	int	n;
33060Sstevel@tonic-gate 	char	*p;
33070Sstevel@tonic-gate 	char	*end;
33080Sstevel@tonic-gate 
33090Sstevel@tonic-gate 	switch (cmd) {
33100Sstevel@tonic-gate 	case DDI_PROP_CMD_DECODE:
33110Sstevel@tonic-gate 		/*
33120Sstevel@tonic-gate 		 * Check that there is encoded data
33130Sstevel@tonic-gate 		 */
33140Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
33150Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
33160Sstevel@tonic-gate 		}
33170Sstevel@tonic-gate 
33181313Scth 		/*
33191313Scth 		 * Match DDI_PROP_CMD_GET_DSIZE logic for when to stop and
33201313Scth 		 * how to NULL terminate result.
33211313Scth 		 */
33221313Scth 		p = (char *)ph->ph_cur_pos;
33231313Scth 		end = (char *)ph->ph_data + ph->ph_size;
33241313Scth 		if (p >= end)
33251313Scth 			return (DDI_PROP_RESULT_EOF);
33261313Scth 
33271313Scth 		while (p < end) {
33281313Scth 			*data++ = *p;
33291313Scth 			if (*p++ == 0) {	/* NULL from OBP */
33301313Scth 				ph->ph_cur_pos = p;
33311313Scth 				return (DDI_PROP_RESULT_OK);
33321313Scth 			}
33330Sstevel@tonic-gate 		}
33340Sstevel@tonic-gate 
33350Sstevel@tonic-gate 		/*
33361313Scth 		 * If OBP did not NULL terminate string, which happens
33371313Scth 		 * (at least) for 'true'/'false' boolean values, account for
33381313Scth 		 * the space and store null termination on decode.
33390Sstevel@tonic-gate 		 */
33401313Scth 		ph->ph_cur_pos = p;
33411313Scth 		*data = 0;
33420Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
33430Sstevel@tonic-gate 
33440Sstevel@tonic-gate 	case DDI_PROP_CMD_ENCODE:
33450Sstevel@tonic-gate 		/*
33460Sstevel@tonic-gate 		 * Check that there is room to encoded the data
33470Sstevel@tonic-gate 		 */
33480Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
33490Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
33500Sstevel@tonic-gate 		}
33510Sstevel@tonic-gate 
33520Sstevel@tonic-gate 		n = strlen(data) + 1;
33530Sstevel@tonic-gate 		if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
33544582Scth 		    ph->ph_size - n)) {
33550Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
33560Sstevel@tonic-gate 		}
33570Sstevel@tonic-gate 
33580Sstevel@tonic-gate 		/*
33590Sstevel@tonic-gate 		 * Copy the NULL terminated string
33600Sstevel@tonic-gate 		 */
33610Sstevel@tonic-gate 		bcopy(data, ph->ph_cur_pos, n);
33620Sstevel@tonic-gate 
33630Sstevel@tonic-gate 		/*
33640Sstevel@tonic-gate 		 * Move the current location to the start of the next bit of
33650Sstevel@tonic-gate 		 * space where we can store encoded data.
33660Sstevel@tonic-gate 		 */
33670Sstevel@tonic-gate 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + n;
33680Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
33690Sstevel@tonic-gate 
33700Sstevel@tonic-gate 	case DDI_PROP_CMD_SKIP:
33710Sstevel@tonic-gate 		/*
33720Sstevel@tonic-gate 		 * Check that there is encoded data
33730Sstevel@tonic-gate 		 */
33740Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0) {
33750Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
33760Sstevel@tonic-gate 		}
33770Sstevel@tonic-gate 
33780Sstevel@tonic-gate 		/*
33790Sstevel@tonic-gate 		 * Return the string length plus one for the NULL
33800Sstevel@tonic-gate 		 * We know the size of the property, we need to
33810Sstevel@tonic-gate 		 * ensure that the string is properly formatted,
33820Sstevel@tonic-gate 		 * since we may be looking up random OBP data.
33830Sstevel@tonic-gate 		 */
33840Sstevel@tonic-gate 		p = (char *)ph->ph_cur_pos;
33850Sstevel@tonic-gate 		end = (char *)ph->ph_data + ph->ph_size;
33861313Scth 		if (p >= end)
33870Sstevel@tonic-gate 			return (DDI_PROP_RESULT_EOF);
33881313Scth 
33891313Scth 		while (p < end) {
33901313Scth 			if (*p++ == 0) {	/* NULL from OBP */
33910Sstevel@tonic-gate 				ph->ph_cur_pos = p;
33920Sstevel@tonic-gate 				return (DDI_PROP_RESULT_OK);
33930Sstevel@tonic-gate 			}
33940Sstevel@tonic-gate 		}
33950Sstevel@tonic-gate 
33961313Scth 		/*
33971313Scth 		 * Accommodate the fact that OBP does not always NULL
33981313Scth 		 * terminate strings.
33991313Scth 		 */
34001313Scth 		ph->ph_cur_pos = p;
34011313Scth 		return (DDI_PROP_RESULT_OK);
34020Sstevel@tonic-gate 
34030Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_ESIZE:
34040Sstevel@tonic-gate 		/*
34050Sstevel@tonic-gate 		 * Return the size of the encoded string on OBP.
34060Sstevel@tonic-gate 		 */
34070Sstevel@tonic-gate 		return (strlen(data) + 1);
34080Sstevel@tonic-gate 
34090Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_DSIZE:
34100Sstevel@tonic-gate 		/*
34111313Scth 		 * Return the string length plus one for the NULL.
34120Sstevel@tonic-gate 		 * We know the size of the property, we need to
34130Sstevel@tonic-gate 		 * ensure that the string is properly formatted,
34140Sstevel@tonic-gate 		 * since we may be looking up random OBP data.
34150Sstevel@tonic-gate 		 */
34160Sstevel@tonic-gate 		p = (char *)ph->ph_cur_pos;
34170Sstevel@tonic-gate 		end = (char *)ph->ph_data + ph->ph_size;
34181313Scth 		if (p >= end)
34191313Scth 			return (DDI_PROP_RESULT_EOF);
34201313Scth 
34210Sstevel@tonic-gate 		for (n = 0; p < end; n++) {
34221313Scth 			if (*p++ == 0) {	/* NULL from OBP */
34230Sstevel@tonic-gate 				ph->ph_cur_pos = p;
34241313Scth 				return (n + 1);
34250Sstevel@tonic-gate 			}
34260Sstevel@tonic-gate 		}
34271313Scth 
34281313Scth 		/*
34291313Scth 		 * If OBP did not NULL terminate string, which happens for
34301313Scth 		 * 'true'/'false' boolean values, account for the space
34311313Scth 		 * to store null termination here.
34321313Scth 		 */
34331313Scth 		ph->ph_cur_pos = p;
34341313Scth 		return (n + 1);
34350Sstevel@tonic-gate 
34360Sstevel@tonic-gate 	default:
34370Sstevel@tonic-gate #ifdef DEBUG
34380Sstevel@tonic-gate 		panic("ddi_prop_1275_string: %x impossible", cmd);
34390Sstevel@tonic-gate 		/*NOTREACHED*/
34400Sstevel@tonic-gate #else
34410Sstevel@tonic-gate 		return (DDI_PROP_RESULT_ERROR);
34420Sstevel@tonic-gate #endif	/* DEBUG */
34430Sstevel@tonic-gate 	}
34440Sstevel@tonic-gate }
34450Sstevel@tonic-gate 
34460Sstevel@tonic-gate /*
34470Sstevel@tonic-gate  * OBP 1275 byte operator
34480Sstevel@tonic-gate  *
34490Sstevel@tonic-gate  * Caller must specify the number of bytes to get.  OBP encodes bytes
34500Sstevel@tonic-gate  * as a byte so there is a 1-to-1 translation.
34510Sstevel@tonic-gate  */
34520Sstevel@tonic-gate int
ddi_prop_1275_bytes(prop_handle_t * ph,uint_t cmd,uchar_t * data,uint_t nelements)34530Sstevel@tonic-gate ddi_prop_1275_bytes(prop_handle_t *ph, uint_t cmd, uchar_t *data,
34540Sstevel@tonic-gate 	uint_t nelements)
34550Sstevel@tonic-gate {
34560Sstevel@tonic-gate 	switch (cmd) {
34570Sstevel@tonic-gate 	case DDI_PROP_CMD_DECODE:
34580Sstevel@tonic-gate 		/*
34590Sstevel@tonic-gate 		 * Check that there is encoded data
34600Sstevel@tonic-gate 		 */
34610Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
34624582Scth 		    ph->ph_size < nelements ||
34634582Scth 		    ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
34644582Scth 		    ph->ph_size - nelements)))
34650Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
34660Sstevel@tonic-gate 
34670Sstevel@tonic-gate 		/*
34680Sstevel@tonic-gate 		 * Copy out the bytes
34690Sstevel@tonic-gate 		 */
34700Sstevel@tonic-gate 		bcopy(ph->ph_cur_pos, data, nelements);
34710Sstevel@tonic-gate 
34720Sstevel@tonic-gate 		/*
34730Sstevel@tonic-gate 		 * Move the current location
34740Sstevel@tonic-gate 		 */
34750Sstevel@tonic-gate 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
34760Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
34770Sstevel@tonic-gate 
34780Sstevel@tonic-gate 	case DDI_PROP_CMD_ENCODE:
34790Sstevel@tonic-gate 		/*
34800Sstevel@tonic-gate 		 * Check that there is room to encode the data
34810Sstevel@tonic-gate 		 */
34820Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
34834582Scth 		    ph->ph_size < nelements ||
34844582Scth 		    ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
34854582Scth 		    ph->ph_size - nelements)))
34860Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
34870Sstevel@tonic-gate 
34880Sstevel@tonic-gate 		/*
34890Sstevel@tonic-gate 		 * Copy in the bytes
34900Sstevel@tonic-gate 		 */
34910Sstevel@tonic-gate 		bcopy(data, ph->ph_cur_pos, nelements);
34920Sstevel@tonic-gate 
34930Sstevel@tonic-gate 		/*
34940Sstevel@tonic-gate 		 * Move the current location to the start of the next bit of
34950Sstevel@tonic-gate 		 * space where we can store encoded data.
34960Sstevel@tonic-gate 		 */
34970Sstevel@tonic-gate 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
34980Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
34990Sstevel@tonic-gate 
35000Sstevel@tonic-gate 	case DDI_PROP_CMD_SKIP:
35010Sstevel@tonic-gate 		/*
35020Sstevel@tonic-gate 		 * Check that there is encoded data
35030Sstevel@tonic-gate 		 */
35040Sstevel@tonic-gate 		if (ph->ph_cur_pos == NULL || ph->ph_size == 0 ||
35054582Scth 		    ph->ph_size < nelements)
35060Sstevel@tonic-gate 			return (DDI_PROP_RESULT_ERROR);
35070Sstevel@tonic-gate 
35080Sstevel@tonic-gate 		if ((char *)ph->ph_cur_pos > ((char *)ph->ph_data +
35094582Scth 		    ph->ph_size - nelements))
35100Sstevel@tonic-gate 			return (DDI_PROP_RESULT_EOF);
35110Sstevel@tonic-gate 
35120Sstevel@tonic-gate 		/*
35130Sstevel@tonic-gate 		 * Move the current location
35140Sstevel@tonic-gate 		 */
35150Sstevel@tonic-gate 		ph->ph_cur_pos = (char *)ph->ph_cur_pos + nelements;
35160Sstevel@tonic-gate 		return (DDI_PROP_RESULT_OK);
35170Sstevel@tonic-gate 
35180Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_ESIZE:
35190Sstevel@tonic-gate 		/*
35200Sstevel@tonic-gate 		 * The size in bytes of the encoded size is the
35210Sstevel@tonic-gate 		 * same as the decoded size provided by the caller.
35220Sstevel@tonic-gate 		 */
35230Sstevel@tonic-gate 		return (nelements);
35240Sstevel@tonic-gate 
35250Sstevel@tonic-gate 	case DDI_PROP_CMD_GET_DSIZE:
35260Sstevel@tonic-gate 		/*
35270Sstevel@tonic-gate 		 * Just return the number of bytes specified by the caller.
35280Sstevel@tonic-gate 		 */
35290Sstevel@tonic-gate 		return (nelements);
35300Sstevel@tonic-gate 
35310Sstevel@tonic-gate 	default:
35320Sstevel@tonic-gate #ifdef DEBUG
35330Sstevel@tonic-gate 		panic("ddi_prop_1275_bytes: %x impossible", cmd);
35340Sstevel@tonic-gate 		/*NOTREACHED*/
35350Sstevel@tonic-gate #else
35360Sstevel@tonic-gate 		return (DDI_PROP_RESULT_ERROR);
35370Sstevel@tonic-gate #endif	/* DEBUG */
35380Sstevel@tonic-gate 	}
35390Sstevel@tonic-gate }
35400Sstevel@tonic-gate 
35410Sstevel@tonic-gate /*
35420Sstevel@tonic-gate  * Used for properties that come from the OBP, hardware configuration files,
35430Sstevel@tonic-gate  * or that are created by calls to ddi_prop_update(9F).
35440Sstevel@tonic-gate  */
35450Sstevel@tonic-gate static struct prop_handle_ops prop_1275_ops = {
35460Sstevel@tonic-gate 	ddi_prop_1275_int,
35470Sstevel@tonic-gate 	ddi_prop_1275_string,
35480Sstevel@tonic-gate 	ddi_prop_1275_bytes,
35490Sstevel@tonic-gate 	ddi_prop_int64_op
35500Sstevel@tonic-gate };
35510Sstevel@tonic-gate 
35520Sstevel@tonic-gate 
35530Sstevel@tonic-gate /*
35540Sstevel@tonic-gate  * Interface to create/modify a managed property on child's behalf...
35550Sstevel@tonic-gate  * Flags interpreted are:
35560Sstevel@tonic-gate  *	DDI_PROP_CANSLEEP:	Allow memory allocation to sleep.
35570Sstevel@tonic-gate  *	DDI_PROP_SYSTEM_DEF:	Manipulate system list rather than driver list.
35580Sstevel@tonic-gate  *
35590Sstevel@tonic-gate  * Use same dev_t when modifying or undefining a property.
35600Sstevel@tonic-gate  * Search for properties with DDI_DEV_T_ANY to match first named
35610Sstevel@tonic-gate  * property on the list.
35620Sstevel@tonic-gate  *
35630Sstevel@tonic-gate  * Properties are stored LIFO and subsequently will match the first
35640Sstevel@tonic-gate  * `matching' instance.
35650Sstevel@tonic-gate  */
35660Sstevel@tonic-gate 
35670Sstevel@tonic-gate /*
35680Sstevel@tonic-gate  * ddi_prop_add:	Add a software defined property
35690Sstevel@tonic-gate  */
35700Sstevel@tonic-gate 
35710Sstevel@tonic-gate /*
35720Sstevel@tonic-gate  * define to get a new ddi_prop_t.
35730Sstevel@tonic-gate  * km_flags are KM_SLEEP or KM_NOSLEEP.
35740Sstevel@tonic-gate  */
35750Sstevel@tonic-gate 
35760Sstevel@tonic-gate #define	DDI_NEW_PROP_T(km_flags)	\
35770Sstevel@tonic-gate 	(kmem_zalloc(sizeof (ddi_prop_t), km_flags))
35780Sstevel@tonic-gate 
35790Sstevel@tonic-gate static int
ddi_prop_add(dev_t dev,dev_info_t * dip,int flags,char * name,caddr_t value,int length)35800Sstevel@tonic-gate ddi_prop_add(dev_t dev, dev_info_t *dip, int flags,
35810Sstevel@tonic-gate     char *name, caddr_t value, int length)
35820Sstevel@tonic-gate {
35830Sstevel@tonic-gate 	ddi_prop_t	*new_propp, *propp;
35840Sstevel@tonic-gate 	ddi_prop_t	**list_head = &(DEVI(dip)->devi_drv_prop_ptr);
35850Sstevel@tonic-gate 	int		km_flags = KM_NOSLEEP;
35860Sstevel@tonic-gate 	int		name_buf_len;
35870Sstevel@tonic-gate 
35880Sstevel@tonic-gate 	/*
35890Sstevel@tonic-gate 	 * If dev_t is DDI_DEV_T_ANY or name's length is zero return error.
35900Sstevel@tonic-gate 	 */
35910Sstevel@tonic-gate 
35920Sstevel@tonic-gate 	if (dev == DDI_DEV_T_ANY || name == (char *)0 || strlen(name) == 0)
35930Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
35940Sstevel@tonic-gate 
35950Sstevel@tonic-gate 	if (flags & DDI_PROP_CANSLEEP)
35960Sstevel@tonic-gate 		km_flags = KM_SLEEP;
35970Sstevel@tonic-gate 
35980Sstevel@tonic-gate 	if (flags & DDI_PROP_SYSTEM_DEF)
35990Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_sys_prop_ptr);
36000Sstevel@tonic-gate 	else if (flags & DDI_PROP_HW_DEF)
36010Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_hw_prop_ptr);
36020Sstevel@tonic-gate 
36030Sstevel@tonic-gate 	if ((new_propp = DDI_NEW_PROP_T(km_flags)) == NULL)  {
36040Sstevel@tonic-gate 		cmn_err(CE_CONT, prop_no_mem_msg, name);
36050Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
36060Sstevel@tonic-gate 	}
36070Sstevel@tonic-gate 
36080Sstevel@tonic-gate 	/*
36090Sstevel@tonic-gate 	 * If dev is major number 0, then we need to do a ddi_name_to_major
36100Sstevel@tonic-gate 	 * to get the real major number for the device.  This needs to be
36110Sstevel@tonic-gate 	 * done because some drivers need to call ddi_prop_create in their
36120Sstevel@tonic-gate 	 * attach routines but they don't have a dev.  By creating the dev
36130Sstevel@tonic-gate 	 * ourself if the major number is 0, drivers will not have to know what
36140Sstevel@tonic-gate 	 * their major number.	They can just create a dev with major number
36150Sstevel@tonic-gate 	 * 0 and pass it in.  For device 0, we will be doing a little extra
36160Sstevel@tonic-gate 	 * work by recreating the same dev that we already have, but its the
36170Sstevel@tonic-gate 	 * price you pay :-).
36180Sstevel@tonic-gate 	 *
36190Sstevel@tonic-gate 	 * This fixes bug #1098060.
36200Sstevel@tonic-gate 	 */
36210Sstevel@tonic-gate 	if (getmajor(dev) == DDI_MAJOR_T_UNKNOWN) {
36220Sstevel@tonic-gate 		new_propp->prop_dev =
36230Sstevel@tonic-gate 		    makedevice(ddi_name_to_major(DEVI(dip)->devi_binding_name),
36240Sstevel@tonic-gate 		    getminor(dev));
36250Sstevel@tonic-gate 	} else
36260Sstevel@tonic-gate 		new_propp->prop_dev = dev;
36270Sstevel@tonic-gate 
36280Sstevel@tonic-gate 	/*
36290Sstevel@tonic-gate 	 * Allocate space for property name and copy it in...
36300Sstevel@tonic-gate 	 */
36310Sstevel@tonic-gate 
36320Sstevel@tonic-gate 	name_buf_len = strlen(name) + 1;
36330Sstevel@tonic-gate 	new_propp->prop_name = kmem_alloc(name_buf_len, km_flags);
36340Sstevel@tonic-gate 	if (new_propp->prop_name == 0)	{
36350Sstevel@tonic-gate 		kmem_free(new_propp, sizeof (ddi_prop_t));
36360Sstevel@tonic-gate 		cmn_err(CE_CONT, prop_no_mem_msg, name);
36370Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
36380Sstevel@tonic-gate 	}
36390Sstevel@tonic-gate 	bcopy(name, new_propp->prop_name, name_buf_len);
36400Sstevel@tonic-gate 
36410Sstevel@tonic-gate 	/*
36420Sstevel@tonic-gate 	 * Set the property type
36430Sstevel@tonic-gate 	 */
36440Sstevel@tonic-gate 	new_propp->prop_flags = flags & DDI_PROP_TYPE_MASK;
36450Sstevel@tonic-gate 
36460Sstevel@tonic-gate 	/*
36470Sstevel@tonic-gate 	 * Set length and value ONLY if not an explicit property undefine:
36480Sstevel@tonic-gate 	 * NOTE: value and length are zero for explicit undefines.
36490Sstevel@tonic-gate 	 */
36500Sstevel@tonic-gate 
36510Sstevel@tonic-gate 	if (flags & DDI_PROP_UNDEF_IT) {
36520Sstevel@tonic-gate 		new_propp->prop_flags |= DDI_PROP_UNDEF_IT;
36530Sstevel@tonic-gate 	} else {
36540Sstevel@tonic-gate 		if ((new_propp->prop_len = length) != 0) {
36550Sstevel@tonic-gate 			new_propp->prop_val = kmem_alloc(length, km_flags);
36560Sstevel@tonic-gate 			if (new_propp->prop_val == 0)  {
36570Sstevel@tonic-gate 				kmem_free(new_propp->prop_name, name_buf_len);
36580Sstevel@tonic-gate 				kmem_free(new_propp, sizeof (ddi_prop_t));
36590Sstevel@tonic-gate 				cmn_err(CE_CONT, prop_no_mem_msg, name);
36600Sstevel@tonic-gate 				return (DDI_PROP_NO_MEMORY);
36610Sstevel@tonic-gate 			}
36620Sstevel@tonic-gate 			bcopy(value, new_propp->prop_val, length);
36630Sstevel@tonic-gate 		}
36640Sstevel@tonic-gate 	}
36650Sstevel@tonic-gate 
36660Sstevel@tonic-gate 	/*
36670Sstevel@tonic-gate 	 * Link property into beginning of list. (Properties are LIFO order.)
36680Sstevel@tonic-gate 	 */
36690Sstevel@tonic-gate 
36700Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
36710Sstevel@tonic-gate 	propp = *list_head;
36720Sstevel@tonic-gate 	new_propp->prop_next = propp;
36730Sstevel@tonic-gate 	*list_head = new_propp;
36740Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
36750Sstevel@tonic-gate 	return (DDI_PROP_SUCCESS);
36760Sstevel@tonic-gate }
36770Sstevel@tonic-gate 
36780Sstevel@tonic-gate 
36790Sstevel@tonic-gate /*
36800Sstevel@tonic-gate  * ddi_prop_change:	Modify a software managed property value
36810Sstevel@tonic-gate  *
36820Sstevel@tonic-gate  *			Set new length and value if found.
36830Sstevel@tonic-gate  *			returns DDI_PROP_INVAL_ARG if dev is DDI_DEV_T_ANY or
36840Sstevel@tonic-gate  *			input name is the NULL string.
36850Sstevel@tonic-gate  *			returns DDI_PROP_NO_MEMORY if unable to allocate memory
36860Sstevel@tonic-gate  *
36870Sstevel@tonic-gate  *			Note: an undef can be modified to be a define,
36880Sstevel@tonic-gate  *			(you can't go the other way.)
36890Sstevel@tonic-gate  */
36900Sstevel@tonic-gate 
36910Sstevel@tonic-gate static int
ddi_prop_change(dev_t dev,dev_info_t * dip,int flags,char * name,caddr_t value,int length)36920Sstevel@tonic-gate ddi_prop_change(dev_t dev, dev_info_t *dip, int flags,
36930Sstevel@tonic-gate     char *name, caddr_t value, int length)
36940Sstevel@tonic-gate {
36950Sstevel@tonic-gate 	ddi_prop_t	*propp;
3696168Scth 	ddi_prop_t	**ppropp;
36970Sstevel@tonic-gate 	caddr_t		p = NULL;
36980Sstevel@tonic-gate 
3699168Scth 	if ((dev == DDI_DEV_T_ANY) || (name == NULL) || (strlen(name) == 0))
37000Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
37010Sstevel@tonic-gate 
37020Sstevel@tonic-gate 	/*
37030Sstevel@tonic-gate 	 * Preallocate buffer, even if we don't need it...
37040Sstevel@tonic-gate 	 */
37050Sstevel@tonic-gate 	if (length != 0)  {
3706168Scth 		p = kmem_alloc(length, (flags & DDI_PROP_CANSLEEP) ?
3707168Scth 		    KM_SLEEP : KM_NOSLEEP);
37080Sstevel@tonic-gate 		if (p == NULL)	{
37090Sstevel@tonic-gate 			cmn_err(CE_CONT, prop_no_mem_msg, name);
37100Sstevel@tonic-gate 			return (DDI_PROP_NO_MEMORY);
37110Sstevel@tonic-gate 		}
37120Sstevel@tonic-gate 	}
37130Sstevel@tonic-gate 
37140Sstevel@tonic-gate 	/*
3715168Scth 	 * If the dev_t value contains DDI_MAJOR_T_UNKNOWN for the major
3716168Scth 	 * number, a real dev_t value should be created based upon the dip's
3717168Scth 	 * binding driver.  See ddi_prop_add...
3718168Scth 	 */
3719168Scth 	if (getmajor(dev) == DDI_MAJOR_T_UNKNOWN)
3720168Scth 		dev = makedevice(
3721168Scth 		    ddi_name_to_major(DEVI(dip)->devi_binding_name),
3722168Scth 		    getminor(dev));
3723168Scth 
3724168Scth 	/*
37250Sstevel@tonic-gate 	 * Check to see if the property exists.  If so we modify it.
37260Sstevel@tonic-gate 	 * Else we create it by calling ddi_prop_add().
37270Sstevel@tonic-gate 	 */
37280Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
3729168Scth 	ppropp = &DEVI(dip)->devi_drv_prop_ptr;
37300Sstevel@tonic-gate 	if (flags & DDI_PROP_SYSTEM_DEF)
3731168Scth 		ppropp = &DEVI(dip)->devi_sys_prop_ptr;
37320Sstevel@tonic-gate 	else if (flags & DDI_PROP_HW_DEF)
3733168Scth 		ppropp = &DEVI(dip)->devi_hw_prop_ptr;
3734168Scth 
3735168Scth 	if ((propp = i_ddi_prop_search(dev, name, flags, ppropp)) != NULL) {
3736168Scth 		/*
3737168Scth 		 * Need to reallocate buffer?  If so, do it
3738168Scth 		 * carefully (reuse same space if new prop
3739168Scth 		 * is same size and non-NULL sized).
3740168Scth 		 */
3741168Scth 		if (length != 0)
3742168Scth 			bcopy(value, p, length);
3743168Scth 
3744168Scth 		if (propp->prop_len != 0)
3745168Scth 			kmem_free(propp->prop_val, propp->prop_len);
3746168Scth 
3747168Scth 		propp->prop_len = length;
3748168Scth 		propp->prop_val = p;
3749168Scth 		propp->prop_flags &= ~DDI_PROP_UNDEF_IT;
3750168Scth 		mutex_exit(&(DEVI(dip)->devi_lock));
3751168Scth 		return (DDI_PROP_SUCCESS);
37520Sstevel@tonic-gate 	}
37530Sstevel@tonic-gate 
37540Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
37550Sstevel@tonic-gate 	if (length != 0)
37560Sstevel@tonic-gate 		kmem_free(p, length);
3757168Scth 
37580Sstevel@tonic-gate 	return (ddi_prop_add(dev, dip, flags, name, value, length));
37590Sstevel@tonic-gate }
37600Sstevel@tonic-gate 
37610Sstevel@tonic-gate /*
37620Sstevel@tonic-gate  * Common update routine used to update and encode a property.	Creates
37630Sstevel@tonic-gate  * a property handle, calls the property encode routine, figures out if
37640Sstevel@tonic-gate  * the property already exists and updates if it does.	Otherwise it
37650Sstevel@tonic-gate  * creates if it does not exist.
37660Sstevel@tonic-gate  */
37670Sstevel@tonic-gate int
ddi_prop_update_common(dev_t match_dev,dev_info_t * dip,int flags,char * name,void * data,uint_t nelements,int (* prop_create)(prop_handle_t *,void * data,uint_t nelements))37680Sstevel@tonic-gate ddi_prop_update_common(dev_t match_dev, dev_info_t *dip, int flags,
37690Sstevel@tonic-gate     char *name, void *data, uint_t nelements,
37700Sstevel@tonic-gate     int (*prop_create)(prop_handle_t *, void *data, uint_t nelements))
37710Sstevel@tonic-gate {
37720Sstevel@tonic-gate 	prop_handle_t	ph;
37730Sstevel@tonic-gate 	int		rval;
37740Sstevel@tonic-gate 	uint_t		ourflags;
37750Sstevel@tonic-gate 
37760Sstevel@tonic-gate 	/*
37770Sstevel@tonic-gate 	 * If dev_t is DDI_DEV_T_ANY or name's length is zero,
37780Sstevel@tonic-gate 	 * return error.
37790Sstevel@tonic-gate 	 */
37800Sstevel@tonic-gate 	if (match_dev == DDI_DEV_T_ANY || name == NULL || strlen(name) == 0)
37810Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
37820Sstevel@tonic-gate 
37830Sstevel@tonic-gate 	/*
37840Sstevel@tonic-gate 	 * Create the handle
37850Sstevel@tonic-gate 	 */
37860Sstevel@tonic-gate 	ph.ph_data = NULL;
37870Sstevel@tonic-gate 	ph.ph_cur_pos = NULL;
37880Sstevel@tonic-gate 	ph.ph_save_pos = NULL;
37890Sstevel@tonic-gate 	ph.ph_size = 0;
37900Sstevel@tonic-gate 	ph.ph_ops = &prop_1275_ops;
37910Sstevel@tonic-gate 
37920Sstevel@tonic-gate 	/*
37930Sstevel@tonic-gate 	 * ourflags:
37940Sstevel@tonic-gate 	 * For compatibility with the old interfaces.  The old interfaces
37950Sstevel@tonic-gate 	 * didn't sleep by default and slept when the flag was set.  These
37960Sstevel@tonic-gate 	 * interfaces to the opposite.	So the old interfaces now set the
37970Sstevel@tonic-gate 	 * DDI_PROP_DONTSLEEP flag by default which tells us not to sleep.
37980Sstevel@tonic-gate 	 *
37990Sstevel@tonic-gate 	 * ph.ph_flags:
38000Sstevel@tonic-gate 	 * Blocked data or unblocked data allocation
38010Sstevel@tonic-gate 	 * for ph.ph_data in ddi_prop_encode_alloc()
38020Sstevel@tonic-gate 	 */
38030Sstevel@tonic-gate 	if (flags & DDI_PROP_DONTSLEEP) {
38040Sstevel@tonic-gate 		ourflags = flags;
38050Sstevel@tonic-gate 		ph.ph_flags = DDI_PROP_DONTSLEEP;
38060Sstevel@tonic-gate 	} else {
38070Sstevel@tonic-gate 		ourflags = flags | DDI_PROP_CANSLEEP;
38080Sstevel@tonic-gate 		ph.ph_flags = DDI_PROP_CANSLEEP;
38090Sstevel@tonic-gate 	}
38100Sstevel@tonic-gate 
38110Sstevel@tonic-gate 	/*
38120Sstevel@tonic-gate 	 * Encode the data and store it in the property handle by
38130Sstevel@tonic-gate 	 * calling the prop_encode routine.
38140Sstevel@tonic-gate 	 */
38150Sstevel@tonic-gate 	if ((rval = (*prop_create)(&ph, data, nelements)) !=
38160Sstevel@tonic-gate 	    DDI_PROP_SUCCESS) {
38170Sstevel@tonic-gate 		if (rval == DDI_PROP_NO_MEMORY)
38180Sstevel@tonic-gate 			cmn_err(CE_CONT, prop_no_mem_msg, name);
38190Sstevel@tonic-gate 		if (ph.ph_size != 0)
38200Sstevel@tonic-gate 			kmem_free(ph.ph_data, ph.ph_size);
38210Sstevel@tonic-gate 		return (rval);
38220Sstevel@tonic-gate 	}
38230Sstevel@tonic-gate 
38240Sstevel@tonic-gate 	/*
38250Sstevel@tonic-gate 	 * The old interfaces use a stacking approach to creating
38260Sstevel@tonic-gate 	 * properties.	If we are being called from the old interfaces,
38270Sstevel@tonic-gate 	 * the DDI_PROP_STACK_CREATE flag will be set, so we just do a
38280Sstevel@tonic-gate 	 * create without checking.
38290Sstevel@tonic-gate 	 */
38300Sstevel@tonic-gate 	if (flags & DDI_PROP_STACK_CREATE) {
38310Sstevel@tonic-gate 		rval = ddi_prop_add(match_dev, dip,
38320Sstevel@tonic-gate 		    ourflags, name, ph.ph_data, ph.ph_size);
38330Sstevel@tonic-gate 	} else {
38340Sstevel@tonic-gate 		rval = ddi_prop_change(match_dev, dip,
38350Sstevel@tonic-gate 		    ourflags, name, ph.ph_data, ph.ph_size);
38360Sstevel@tonic-gate 	}
38370Sstevel@tonic-gate 
38380Sstevel@tonic-gate 	/*
38390Sstevel@tonic-gate 	 * Free the encoded data allocated in the prop_encode routine.
38400Sstevel@tonic-gate 	 */
38410Sstevel@tonic-gate 	if (ph.ph_size != 0)
38420Sstevel@tonic-gate 		kmem_free(ph.ph_data, ph.ph_size);
38430Sstevel@tonic-gate 
38440Sstevel@tonic-gate 	return (rval);
38450Sstevel@tonic-gate }
38460Sstevel@tonic-gate 
38470Sstevel@tonic-gate 
38480Sstevel@tonic-gate /*
38490Sstevel@tonic-gate  * ddi_prop_create:	Define a managed property:
38500Sstevel@tonic-gate  *			See above for details.
38510Sstevel@tonic-gate  */
38520Sstevel@tonic-gate 
38530Sstevel@tonic-gate int
ddi_prop_create(dev_t dev,dev_info_t * dip,int flag,char * name,caddr_t value,int length)38540Sstevel@tonic-gate ddi_prop_create(dev_t dev, dev_info_t *dip, int flag,
38550Sstevel@tonic-gate     char *name, caddr_t value, int length)
38560Sstevel@tonic-gate {
38570Sstevel@tonic-gate 	if (!(flag & DDI_PROP_CANSLEEP)) {
38580Sstevel@tonic-gate 		flag |= DDI_PROP_DONTSLEEP;
38590Sstevel@tonic-gate #ifdef DDI_PROP_DEBUG
38600Sstevel@tonic-gate 		if (length != 0)
38610Sstevel@tonic-gate 			cmn_err(CE_NOTE, "!ddi_prop_create: interface obsolete,"
38620Sstevel@tonic-gate 			    "use ddi_prop_update (prop = %s, node = %s%d)",
38630Sstevel@tonic-gate 			    name, ddi_driver_name(dip), ddi_get_instance(dip));
38640Sstevel@tonic-gate #endif /* DDI_PROP_DEBUG */
38650Sstevel@tonic-gate 	}
38660Sstevel@tonic-gate 	flag &= ~DDI_PROP_SYSTEM_DEF;
38677224Scth 	flag |= DDI_PROP_STACK_CREATE | DDI_PROP_TYPE_ANY;
38687224Scth 	return (ddi_prop_update_common(dev, dip, flag, name,
38690Sstevel@tonic-gate 	    value, length, ddi_prop_fm_encode_bytes));
38700Sstevel@tonic-gate }
38710Sstevel@tonic-gate 
38720Sstevel@tonic-gate int
e_ddi_prop_create(dev_t dev,dev_info_t * dip,int flag,char * name,caddr_t value,int length)38730Sstevel@tonic-gate e_ddi_prop_create(dev_t dev, dev_info_t *dip, int flag,
38740Sstevel@tonic-gate     char *name, caddr_t value, int length)
38750Sstevel@tonic-gate {
38760Sstevel@tonic-gate 	if (!(flag & DDI_PROP_CANSLEEP))
38770Sstevel@tonic-gate 		flag |= DDI_PROP_DONTSLEEP;
38787224Scth 	flag |= DDI_PROP_SYSTEM_DEF | DDI_PROP_STACK_CREATE | DDI_PROP_TYPE_ANY;
38797224Scth 	return (ddi_prop_update_common(dev, dip, flag,
38800Sstevel@tonic-gate 	    name, value, length, ddi_prop_fm_encode_bytes));
38810Sstevel@tonic-gate }
38820Sstevel@tonic-gate 
38830Sstevel@tonic-gate int
ddi_prop_modify(dev_t dev,dev_info_t * dip,int flag,char * name,caddr_t value,int length)38840Sstevel@tonic-gate ddi_prop_modify(dev_t dev, dev_info_t *dip, int flag,
38850Sstevel@tonic-gate     char *name, caddr_t value, int length)
38860Sstevel@tonic-gate {
38870Sstevel@tonic-gate 	ASSERT((flag & DDI_PROP_TYPE_MASK) == 0);
38880Sstevel@tonic-gate 
38890Sstevel@tonic-gate 	/*
38900Sstevel@tonic-gate 	 * If dev_t is DDI_DEV_T_ANY or name's length is zero,
38910Sstevel@tonic-gate 	 * return error.
38920Sstevel@tonic-gate 	 */
38930Sstevel@tonic-gate 	if (dev == DDI_DEV_T_ANY || name == NULL || strlen(name) == 0)
38940Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
38950Sstevel@tonic-gate 
38960Sstevel@tonic-gate 	if (!(flag & DDI_PROP_CANSLEEP))
38970Sstevel@tonic-gate 		flag |= DDI_PROP_DONTSLEEP;
38980Sstevel@tonic-gate 	flag &= ~DDI_PROP_SYSTEM_DEF;
3899168Scth 	if (ddi_prop_exists(dev, dip, (flag | DDI_PROP_NOTPROM), name) == 0)
39000Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
39010Sstevel@tonic-gate 
39020Sstevel@tonic-gate 	return (ddi_prop_update_common(dev, dip,
39030Sstevel@tonic-gate 	    (flag | DDI_PROP_TYPE_BYTE), name,
39040Sstevel@tonic-gate 	    value, length, ddi_prop_fm_encode_bytes));
39050Sstevel@tonic-gate }
39060Sstevel@tonic-gate 
39070Sstevel@tonic-gate int
e_ddi_prop_modify(dev_t dev,dev_info_t * dip,int flag,char * name,caddr_t value,int length)39080Sstevel@tonic-gate e_ddi_prop_modify(dev_t dev, dev_info_t *dip, int flag,
39090Sstevel@tonic-gate     char *name, caddr_t value, int length)
39100Sstevel@tonic-gate {
39110Sstevel@tonic-gate 	ASSERT((flag & DDI_PROP_TYPE_MASK) == 0);
39120Sstevel@tonic-gate 
39130Sstevel@tonic-gate 	/*
39140Sstevel@tonic-gate 	 * If dev_t is DDI_DEV_T_ANY or name's length is zero,
39150Sstevel@tonic-gate 	 * return error.
39160Sstevel@tonic-gate 	 */
39170Sstevel@tonic-gate 	if (dev == DDI_DEV_T_ANY || name == NULL || strlen(name) == 0)
39180Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
39190Sstevel@tonic-gate 
3920168Scth 	if (ddi_prop_exists(dev, dip, (flag | DDI_PROP_SYSTEM_DEF), name) == 0)
39210Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
39220Sstevel@tonic-gate 
39230Sstevel@tonic-gate 	if (!(flag & DDI_PROP_CANSLEEP))
39240Sstevel@tonic-gate 		flag |= DDI_PROP_DONTSLEEP;
39250Sstevel@tonic-gate 	return (ddi_prop_update_common(dev, dip,
39264582Scth 	    (flag | DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_BYTE),
39274582Scth 	    name, value, length, ddi_prop_fm_encode_bytes));
39280Sstevel@tonic-gate }
39290Sstevel@tonic-gate 
39300Sstevel@tonic-gate 
39310Sstevel@tonic-gate /*
39320Sstevel@tonic-gate  * Common lookup routine used to lookup and decode a property.
39330Sstevel@tonic-gate  * Creates a property handle, searches for the raw encoded data,
39340Sstevel@tonic-gate  * fills in the handle, and calls the property decode functions
39350Sstevel@tonic-gate  * passed in.
39360Sstevel@tonic-gate  *
39370Sstevel@tonic-gate  * This routine is not static because ddi_bus_prop_op() which lives in
39380Sstevel@tonic-gate  * ddi_impl.c calls it.  No driver should be calling this routine.
39390Sstevel@tonic-gate  */
39400Sstevel@tonic-gate int
ddi_prop_lookup_common(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,void * data,uint_t * nelements,int (* prop_decoder)(prop_handle_t *,void * data,uint_t * nelements))39410Sstevel@tonic-gate ddi_prop_lookup_common(dev_t match_dev, dev_info_t *dip,
39420Sstevel@tonic-gate     uint_t flags, char *name, void *data, uint_t *nelements,
39430Sstevel@tonic-gate     int (*prop_decoder)(prop_handle_t *, void *data, uint_t *nelements))
39440Sstevel@tonic-gate {
39450Sstevel@tonic-gate 	int		rval;
39460Sstevel@tonic-gate 	uint_t		ourflags;
39470Sstevel@tonic-gate 	prop_handle_t	ph;
39480Sstevel@tonic-gate 
39490Sstevel@tonic-gate 	if ((match_dev == DDI_DEV_T_NONE) ||
3950168Scth 	    (name == NULL) || (strlen(name) == 0))
39510Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
39520Sstevel@tonic-gate 
39530Sstevel@tonic-gate 	ourflags = (flags & DDI_PROP_DONTSLEEP) ? flags :
39544582Scth 	    flags | DDI_PROP_CANSLEEP;
39550Sstevel@tonic-gate 
39560Sstevel@tonic-gate 	/*
39570Sstevel@tonic-gate 	 * Get the encoded data
39580Sstevel@tonic-gate 	 */
39590Sstevel@tonic-gate 	bzero(&ph, sizeof (prop_handle_t));
39600Sstevel@tonic-gate 
39618371SVikram.Hegde@Sun.COM 	if ((flags & DDI_UNBND_DLPI2) || (flags & DDI_PROP_ROOTNEX_GLOBAL)) {
39620Sstevel@tonic-gate 		/*
39638371SVikram.Hegde@Sun.COM 		 * For rootnex and unbound dlpi style-2 devices, index into
39640Sstevel@tonic-gate 		 * the devnames' array and search the global
39650Sstevel@tonic-gate 		 * property list.
39660Sstevel@tonic-gate 		 */
39670Sstevel@tonic-gate 		ourflags &= ~DDI_UNBND_DLPI2;
39680Sstevel@tonic-gate 		rval = i_ddi_prop_search_global(match_dev,
39690Sstevel@tonic-gate 		    ourflags, name, &ph.ph_data, &ph.ph_size);
39700Sstevel@tonic-gate 	} else {
39710Sstevel@tonic-gate 		rval = ddi_prop_search_common(match_dev, dip,
39720Sstevel@tonic-gate 		    PROP_LEN_AND_VAL_ALLOC, ourflags, name,
39730Sstevel@tonic-gate 		    &ph.ph_data, &ph.ph_size);
39740Sstevel@tonic-gate 
39750Sstevel@tonic-gate 	}
39760Sstevel@tonic-gate 
39770Sstevel@tonic-gate 	if (rval != DDI_PROP_SUCCESS && rval != DDI_PROP_FOUND_1275) {
39780Sstevel@tonic-gate 		ASSERT(ph.ph_data == NULL);
39790Sstevel@tonic-gate 		ASSERT(ph.ph_size == 0);
39800Sstevel@tonic-gate 		return (rval);
39810Sstevel@tonic-gate 	}
39820Sstevel@tonic-gate 
39830Sstevel@tonic-gate 	/*
39840Sstevel@tonic-gate 	 * If the encoded data came from a OBP or software
39850Sstevel@tonic-gate 	 * use the 1275 OBP decode/encode routines.
39860Sstevel@tonic-gate 	 */
39870Sstevel@tonic-gate 	ph.ph_cur_pos = ph.ph_data;
39880Sstevel@tonic-gate 	ph.ph_save_pos = ph.ph_data;
39890Sstevel@tonic-gate 	ph.ph_ops = &prop_1275_ops;
39900Sstevel@tonic-gate 	ph.ph_flags = (rval == DDI_PROP_FOUND_1275) ? PH_FROM_PROM : 0;
39910Sstevel@tonic-gate 
39920Sstevel@tonic-gate 	rval = (*prop_decoder)(&ph, data, nelements);
39930Sstevel@tonic-gate 
39940Sstevel@tonic-gate 	/*
39950Sstevel@tonic-gate 	 * Free the encoded data
39960Sstevel@tonic-gate 	 */
39970Sstevel@tonic-gate 	if (ph.ph_size != 0)
39980Sstevel@tonic-gate 		kmem_free(ph.ph_data, ph.ph_size);
39990Sstevel@tonic-gate 
40000Sstevel@tonic-gate 	return (rval);
40010Sstevel@tonic-gate }
40020Sstevel@tonic-gate 
40030Sstevel@tonic-gate /*
40040Sstevel@tonic-gate  * Lookup and return an array of composite properties.  The driver must
40050Sstevel@tonic-gate  * provide the decode routine.
40060Sstevel@tonic-gate  */
40070Sstevel@tonic-gate int
ddi_prop_lookup(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,void * data,uint_t * nelements,int (* prop_decoder)(prop_handle_t *,void * data,uint_t * nelements))40080Sstevel@tonic-gate ddi_prop_lookup(dev_t match_dev, dev_info_t *dip,
40090Sstevel@tonic-gate     uint_t flags, char *name, void *data, uint_t *nelements,
40100Sstevel@tonic-gate     int (*prop_decoder)(prop_handle_t *, void *data, uint_t *nelements))
40110Sstevel@tonic-gate {
40120Sstevel@tonic-gate 	return (ddi_prop_lookup_common(match_dev, dip,
40130Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_COMPOSITE), name,
40140Sstevel@tonic-gate 	    data, nelements, prop_decoder));
40150Sstevel@tonic-gate }
40160Sstevel@tonic-gate 
40170Sstevel@tonic-gate /*
40180Sstevel@tonic-gate  * Return 1 if a property exists (no type checking done).
40190Sstevel@tonic-gate  * Return 0 if it does not exist.
40200Sstevel@tonic-gate  */
40210Sstevel@tonic-gate int
ddi_prop_exists(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name)40220Sstevel@tonic-gate ddi_prop_exists(dev_t match_dev, dev_info_t *dip, uint_t flags, char *name)
40230Sstevel@tonic-gate {
40240Sstevel@tonic-gate 	int	i;
40250Sstevel@tonic-gate 	uint_t	x = 0;
40260Sstevel@tonic-gate 
40270Sstevel@tonic-gate 	i = ddi_prop_search_common(match_dev, dip, PROP_EXISTS,
40284582Scth 	    flags | DDI_PROP_TYPE_MASK, name, NULL, &x);
40290Sstevel@tonic-gate 	return (i == DDI_PROP_SUCCESS || i == DDI_PROP_FOUND_1275);
40300Sstevel@tonic-gate }
40310Sstevel@tonic-gate 
40320Sstevel@tonic-gate 
40330Sstevel@tonic-gate /*
40340Sstevel@tonic-gate  * Update an array of composite properties.  The driver must
40350Sstevel@tonic-gate  * provide the encode routine.
40360Sstevel@tonic-gate  */
40370Sstevel@tonic-gate int
ddi_prop_update(dev_t match_dev,dev_info_t * dip,char * name,void * data,uint_t nelements,int (* prop_create)(prop_handle_t *,void * data,uint_t nelements))40380Sstevel@tonic-gate ddi_prop_update(dev_t match_dev, dev_info_t *dip,
40390Sstevel@tonic-gate     char *name, void *data, uint_t nelements,
40400Sstevel@tonic-gate     int (*prop_create)(prop_handle_t *, void *data, uint_t nelements))
40410Sstevel@tonic-gate {
40420Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_COMPOSITE,
40430Sstevel@tonic-gate 	    name, data, nelements, prop_create));
40440Sstevel@tonic-gate }
40450Sstevel@tonic-gate 
40460Sstevel@tonic-gate /*
40470Sstevel@tonic-gate  * Get a single integer or boolean property and return it.
40480Sstevel@tonic-gate  * If the property does not exists, or cannot be decoded,
40490Sstevel@tonic-gate  * then return the defvalue passed in.
40500Sstevel@tonic-gate  *
40510Sstevel@tonic-gate  * This routine always succeeds.
40520Sstevel@tonic-gate  */
40530Sstevel@tonic-gate int
ddi_prop_get_int(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,int defvalue)40540Sstevel@tonic-gate ddi_prop_get_int(dev_t match_dev, dev_info_t *dip, uint_t flags,
40550Sstevel@tonic-gate     char *name, int defvalue)
40560Sstevel@tonic-gate {
40570Sstevel@tonic-gate 	int	data;
40580Sstevel@tonic-gate 	uint_t	nelements;
40590Sstevel@tonic-gate 	int	rval;
40600Sstevel@tonic-gate 
40610Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
40628371SVikram.Hegde@Sun.COM 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
40630Sstevel@tonic-gate #ifdef DEBUG
40640Sstevel@tonic-gate 		if (dip != NULL) {
40650Sstevel@tonic-gate 			cmn_err(CE_WARN, "ddi_prop_get_int: invalid flag"
40660Sstevel@tonic-gate 			    " 0x%x (prop = %s, node = %s%d)", flags,
40670Sstevel@tonic-gate 			    name, ddi_driver_name(dip), ddi_get_instance(dip));
40680Sstevel@tonic-gate 		}
40690Sstevel@tonic-gate #endif /* DEBUG */
40700Sstevel@tonic-gate 		flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
40710Sstevel@tonic-gate 		    LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
40720Sstevel@tonic-gate 	}
40730Sstevel@tonic-gate 
40740Sstevel@tonic-gate 	if ((rval = ddi_prop_lookup_common(match_dev, dip,
40750Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_INT), name, &data, &nelements,
40760Sstevel@tonic-gate 	    ddi_prop_fm_decode_int)) != DDI_PROP_SUCCESS) {
40770Sstevel@tonic-gate 		if (rval == DDI_PROP_END_OF_DATA)
40780Sstevel@tonic-gate 			data = 1;
40790Sstevel@tonic-gate 		else
40800Sstevel@tonic-gate 			data = defvalue;
40810Sstevel@tonic-gate 	}
40820Sstevel@tonic-gate 	return (data);
40830Sstevel@tonic-gate }
40840Sstevel@tonic-gate 
40850Sstevel@tonic-gate /*
40860Sstevel@tonic-gate  * Get a single 64 bit integer or boolean property and return it.
40870Sstevel@tonic-gate  * If the property does not exists, or cannot be decoded,
40880Sstevel@tonic-gate  * then return the defvalue passed in.
40890Sstevel@tonic-gate  *
40900Sstevel@tonic-gate  * This routine always succeeds.
40910Sstevel@tonic-gate  */
40920Sstevel@tonic-gate int64_t
ddi_prop_get_int64(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,int64_t defvalue)40930Sstevel@tonic-gate ddi_prop_get_int64(dev_t match_dev, dev_info_t *dip, uint_t flags,
40940Sstevel@tonic-gate     char *name, int64_t defvalue)
40950Sstevel@tonic-gate {
40960Sstevel@tonic-gate 	int64_t	data;
40970Sstevel@tonic-gate 	uint_t	nelements;
40980Sstevel@tonic-gate 	int	rval;
40990Sstevel@tonic-gate 
41000Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
41018371SVikram.Hegde@Sun.COM 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
41020Sstevel@tonic-gate #ifdef DEBUG
41030Sstevel@tonic-gate 		if (dip != NULL) {
41040Sstevel@tonic-gate 			cmn_err(CE_WARN, "ddi_prop_get_int64: invalid flag"
41050Sstevel@tonic-gate 			    " 0x%x (prop = %s, node = %s%d)", flags,
41060Sstevel@tonic-gate 			    name, ddi_driver_name(dip), ddi_get_instance(dip));
41070Sstevel@tonic-gate 		}
41080Sstevel@tonic-gate #endif /* DEBUG */
41090Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
41100Sstevel@tonic-gate 	}
41110Sstevel@tonic-gate 
41120Sstevel@tonic-gate 	if ((rval = ddi_prop_lookup_common(match_dev, dip,
41130Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_INT64 | DDI_PROP_NOTPROM),
41140Sstevel@tonic-gate 	    name, &data, &nelements, ddi_prop_fm_decode_int64))
41150Sstevel@tonic-gate 	    != DDI_PROP_SUCCESS) {
41160Sstevel@tonic-gate 		if (rval == DDI_PROP_END_OF_DATA)
41170Sstevel@tonic-gate 			data = 1;
41180Sstevel@tonic-gate 		else
41190Sstevel@tonic-gate 			data = defvalue;
41200Sstevel@tonic-gate 	}
41210Sstevel@tonic-gate 	return (data);
41220Sstevel@tonic-gate }
41230Sstevel@tonic-gate 
41240Sstevel@tonic-gate /*
41250Sstevel@tonic-gate  * Get an array of integer property
41260Sstevel@tonic-gate  */
41270Sstevel@tonic-gate int
ddi_prop_lookup_int_array(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,int ** data,uint_t * nelements)41280Sstevel@tonic-gate ddi_prop_lookup_int_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
41290Sstevel@tonic-gate     char *name, int **data, uint_t *nelements)
41300Sstevel@tonic-gate {
41310Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
41328371SVikram.Hegde@Sun.COM 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
41330Sstevel@tonic-gate #ifdef DEBUG
41340Sstevel@tonic-gate 		if (dip != NULL) {
41350Sstevel@tonic-gate 			cmn_err(CE_WARN, "ddi_prop_lookup_int_array: "
41360Sstevel@tonic-gate 			    "invalid flag 0x%x (prop = %s, node = %s%d)",
41370Sstevel@tonic-gate 			    flags, name, ddi_driver_name(dip),
41380Sstevel@tonic-gate 			    ddi_get_instance(dip));
41390Sstevel@tonic-gate 		}
41400Sstevel@tonic-gate #endif /* DEBUG */
41410Sstevel@tonic-gate 		flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
41424582Scth 		    LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
41430Sstevel@tonic-gate 	}
41440Sstevel@tonic-gate 
41450Sstevel@tonic-gate 	return (ddi_prop_lookup_common(match_dev, dip,
41460Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_INT), name, data,
41470Sstevel@tonic-gate 	    nelements, ddi_prop_fm_decode_ints));
41480Sstevel@tonic-gate }
41490Sstevel@tonic-gate 
41500Sstevel@tonic-gate /*
41510Sstevel@tonic-gate  * Get an array of 64 bit integer properties
41520Sstevel@tonic-gate  */
41530Sstevel@tonic-gate int
ddi_prop_lookup_int64_array(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,int64_t ** data,uint_t * nelements)41540Sstevel@tonic-gate ddi_prop_lookup_int64_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
41550Sstevel@tonic-gate     char *name, int64_t **data, uint_t *nelements)
41560Sstevel@tonic-gate {
41570Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
41588371SVikram.Hegde@Sun.COM 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
41590Sstevel@tonic-gate #ifdef DEBUG
41600Sstevel@tonic-gate 		if (dip != NULL) {
41610Sstevel@tonic-gate 			cmn_err(CE_WARN, "ddi_prop_lookup_int64_array: "
41620Sstevel@tonic-gate 			    "invalid flag 0x%x (prop = %s, node = %s%d)",
41630Sstevel@tonic-gate 			    flags, name, ddi_driver_name(dip),
41640Sstevel@tonic-gate 			    ddi_get_instance(dip));
41650Sstevel@tonic-gate 		}
41660Sstevel@tonic-gate #endif /* DEBUG */
41670Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
41680Sstevel@tonic-gate 	}
41690Sstevel@tonic-gate 
41700Sstevel@tonic-gate 	return (ddi_prop_lookup_common(match_dev, dip,
41710Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_INT64 | DDI_PROP_NOTPROM),
41720Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_decode_int64_array));
41730Sstevel@tonic-gate }
41740Sstevel@tonic-gate 
41750Sstevel@tonic-gate /*
41760Sstevel@tonic-gate  * Update a single integer property.  If the property exists on the drivers
41770Sstevel@tonic-gate  * property list it updates, else it creates it.
41780Sstevel@tonic-gate  */
41790Sstevel@tonic-gate int
ddi_prop_update_int(dev_t match_dev,dev_info_t * dip,char * name,int data)41800Sstevel@tonic-gate ddi_prop_update_int(dev_t match_dev, dev_info_t *dip,
41810Sstevel@tonic-gate     char *name, int data)
41820Sstevel@tonic-gate {
41830Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT,
41840Sstevel@tonic-gate 	    name, &data, 1, ddi_prop_fm_encode_ints));
41850Sstevel@tonic-gate }
41860Sstevel@tonic-gate 
41870Sstevel@tonic-gate /*
41880Sstevel@tonic-gate  * Update a single 64 bit integer property.
41890Sstevel@tonic-gate  * Update the driver property list if it exists, else create it.
41900Sstevel@tonic-gate  */
41910Sstevel@tonic-gate int
ddi_prop_update_int64(dev_t match_dev,dev_info_t * dip,char * name,int64_t data)41920Sstevel@tonic-gate ddi_prop_update_int64(dev_t match_dev, dev_info_t *dip,
41930Sstevel@tonic-gate     char *name, int64_t data)
41940Sstevel@tonic-gate {
41950Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT64,
41960Sstevel@tonic-gate 	    name, &data, 1, ddi_prop_fm_encode_int64));
41970Sstevel@tonic-gate }
41980Sstevel@tonic-gate 
41990Sstevel@tonic-gate int
e_ddi_prop_update_int(dev_t match_dev,dev_info_t * dip,char * name,int data)42000Sstevel@tonic-gate e_ddi_prop_update_int(dev_t match_dev, dev_info_t *dip,
42010Sstevel@tonic-gate     char *name, int data)
42020Sstevel@tonic-gate {
42030Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
42040Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT,
42050Sstevel@tonic-gate 	    name, &data, 1, ddi_prop_fm_encode_ints));
42060Sstevel@tonic-gate }
42070Sstevel@tonic-gate 
42080Sstevel@tonic-gate int
e_ddi_prop_update_int64(dev_t match_dev,dev_info_t * dip,char * name,int64_t data)42090Sstevel@tonic-gate e_ddi_prop_update_int64(dev_t match_dev, dev_info_t *dip,
42100Sstevel@tonic-gate     char *name, int64_t data)
42110Sstevel@tonic-gate {
42120Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
42130Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT64,
42140Sstevel@tonic-gate 	    name, &data, 1, ddi_prop_fm_encode_int64));
42150Sstevel@tonic-gate }
42160Sstevel@tonic-gate 
42170Sstevel@tonic-gate /*
42180Sstevel@tonic-gate  * Update an array of integer property.  If the property exists on the drivers
42190Sstevel@tonic-gate  * property list it updates, else it creates it.
42200Sstevel@tonic-gate  */
42210Sstevel@tonic-gate int
ddi_prop_update_int_array(dev_t match_dev,dev_info_t * dip,char * name,int * data,uint_t nelements)42220Sstevel@tonic-gate ddi_prop_update_int_array(dev_t match_dev, dev_info_t *dip,
42230Sstevel@tonic-gate     char *name, int *data, uint_t nelements)
42240Sstevel@tonic-gate {
42250Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT,
42260Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_encode_ints));
42270Sstevel@tonic-gate }
42280Sstevel@tonic-gate 
42290Sstevel@tonic-gate /*
42300Sstevel@tonic-gate  * Update an array of 64 bit integer properties.
42310Sstevel@tonic-gate  * Update the driver property list if it exists, else create it.
42320Sstevel@tonic-gate  */
42330Sstevel@tonic-gate int
ddi_prop_update_int64_array(dev_t match_dev,dev_info_t * dip,char * name,int64_t * data,uint_t nelements)42340Sstevel@tonic-gate ddi_prop_update_int64_array(dev_t match_dev, dev_info_t *dip,
42350Sstevel@tonic-gate     char *name, int64_t *data, uint_t nelements)
42360Sstevel@tonic-gate {
42370Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_INT64,
42380Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_encode_int64));
42390Sstevel@tonic-gate }
42400Sstevel@tonic-gate 
42410Sstevel@tonic-gate int
e_ddi_prop_update_int64_array(dev_t match_dev,dev_info_t * dip,char * name,int64_t * data,uint_t nelements)42420Sstevel@tonic-gate e_ddi_prop_update_int64_array(dev_t match_dev, dev_info_t *dip,
42430Sstevel@tonic-gate     char *name, int64_t *data, uint_t nelements)
42440Sstevel@tonic-gate {
42450Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
42460Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT64,
42470Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_encode_int64));
42480Sstevel@tonic-gate }
42490Sstevel@tonic-gate 
42500Sstevel@tonic-gate int
e_ddi_prop_update_int_array(dev_t match_dev,dev_info_t * dip,char * name,int * data,uint_t nelements)42510Sstevel@tonic-gate e_ddi_prop_update_int_array(dev_t match_dev, dev_info_t *dip,
42520Sstevel@tonic-gate     char *name, int *data, uint_t nelements)
42530Sstevel@tonic-gate {
42540Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
42550Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_INT,
42560Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_encode_ints));
42570Sstevel@tonic-gate }
42580Sstevel@tonic-gate 
42590Sstevel@tonic-gate /*
42600Sstevel@tonic-gate  * Get a single string property.
42610Sstevel@tonic-gate  */
42620Sstevel@tonic-gate int
ddi_prop_lookup_string(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,char ** data)42630Sstevel@tonic-gate ddi_prop_lookup_string(dev_t match_dev, dev_info_t *dip, uint_t flags,
42640Sstevel@tonic-gate     char *name, char **data)
42650Sstevel@tonic-gate {
42660Sstevel@tonic-gate 	uint_t x;
42670Sstevel@tonic-gate 
42680Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
42698371SVikram.Hegde@Sun.COM 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
42700Sstevel@tonic-gate #ifdef DEBUG
42710Sstevel@tonic-gate 		if (dip != NULL) {
42720Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s: invalid flag 0x%x "
42730Sstevel@tonic-gate 			    "(prop = %s, node = %s%d); invalid bits ignored",
42740Sstevel@tonic-gate 			    "ddi_prop_lookup_string", flags, name,
42750Sstevel@tonic-gate 			    ddi_driver_name(dip), ddi_get_instance(dip));
42760Sstevel@tonic-gate 		}
42770Sstevel@tonic-gate #endif /* DEBUG */
42780Sstevel@tonic-gate 		flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
42790Sstevel@tonic-gate 		    LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
42800Sstevel@tonic-gate 	}
42810Sstevel@tonic-gate 
42820Sstevel@tonic-gate 	return (ddi_prop_lookup_common(match_dev, dip,
42830Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_STRING), name, data,
42840Sstevel@tonic-gate 	    &x, ddi_prop_fm_decode_string));
42850Sstevel@tonic-gate }
42860Sstevel@tonic-gate 
42870Sstevel@tonic-gate /*
42880Sstevel@tonic-gate  * Get an array of strings property.
42890Sstevel@tonic-gate  */
42900Sstevel@tonic-gate int
ddi_prop_lookup_string_array(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,char *** data,uint_t * nelements)42910Sstevel@tonic-gate ddi_prop_lookup_string_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
42920Sstevel@tonic-gate     char *name, char ***data, uint_t *nelements)
42930Sstevel@tonic-gate {
42940Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
42958371SVikram.Hegde@Sun.COM 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
42960Sstevel@tonic-gate #ifdef DEBUG
42970Sstevel@tonic-gate 		if (dip != NULL) {
42980Sstevel@tonic-gate 			cmn_err(CE_WARN, "ddi_prop_lookup_string_array: "
42990Sstevel@tonic-gate 			    "invalid flag 0x%x (prop = %s, node = %s%d)",
43000Sstevel@tonic-gate 			    flags, name, ddi_driver_name(dip),
43010Sstevel@tonic-gate 			    ddi_get_instance(dip));
43020Sstevel@tonic-gate 		}
43030Sstevel@tonic-gate #endif /* DEBUG */
43040Sstevel@tonic-gate 		flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
43050Sstevel@tonic-gate 		    LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
43060Sstevel@tonic-gate 	}
43070Sstevel@tonic-gate 
43080Sstevel@tonic-gate 	return (ddi_prop_lookup_common(match_dev, dip,
43090Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_STRING), name, data,
43100Sstevel@tonic-gate 	    nelements, ddi_prop_fm_decode_strings));
43110Sstevel@tonic-gate }
43120Sstevel@tonic-gate 
43130Sstevel@tonic-gate /*
43140Sstevel@tonic-gate  * Update a single string property.
43150Sstevel@tonic-gate  */
43160Sstevel@tonic-gate int
ddi_prop_update_string(dev_t match_dev,dev_info_t * dip,char * name,char * data)43170Sstevel@tonic-gate ddi_prop_update_string(dev_t match_dev, dev_info_t *dip,
43180Sstevel@tonic-gate     char *name, char *data)
43190Sstevel@tonic-gate {
43200Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
43210Sstevel@tonic-gate 	    DDI_PROP_TYPE_STRING, name, &data, 1,
43220Sstevel@tonic-gate 	    ddi_prop_fm_encode_string));
43230Sstevel@tonic-gate }
43240Sstevel@tonic-gate 
43250Sstevel@tonic-gate int
e_ddi_prop_update_string(dev_t match_dev,dev_info_t * dip,char * name,char * data)43260Sstevel@tonic-gate e_ddi_prop_update_string(dev_t match_dev, dev_info_t *dip,
43270Sstevel@tonic-gate     char *name, char *data)
43280Sstevel@tonic-gate {
43290Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
43300Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_STRING,
43310Sstevel@tonic-gate 	    name, &data, 1, ddi_prop_fm_encode_string));
43320Sstevel@tonic-gate }
43330Sstevel@tonic-gate 
43340Sstevel@tonic-gate 
43350Sstevel@tonic-gate /*
43360Sstevel@tonic-gate  * Update an array of strings property.
43370Sstevel@tonic-gate  */
43380Sstevel@tonic-gate int
ddi_prop_update_string_array(dev_t match_dev,dev_info_t * dip,char * name,char ** data,uint_t nelements)43390Sstevel@tonic-gate ddi_prop_update_string_array(dev_t match_dev, dev_info_t *dip,
43400Sstevel@tonic-gate     char *name, char **data, uint_t nelements)
43410Sstevel@tonic-gate {
43420Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
43430Sstevel@tonic-gate 	    DDI_PROP_TYPE_STRING, name, data, nelements,
43440Sstevel@tonic-gate 	    ddi_prop_fm_encode_strings));
43450Sstevel@tonic-gate }
43460Sstevel@tonic-gate 
43470Sstevel@tonic-gate int
e_ddi_prop_update_string_array(dev_t match_dev,dev_info_t * dip,char * name,char ** data,uint_t nelements)43480Sstevel@tonic-gate e_ddi_prop_update_string_array(dev_t match_dev, dev_info_t *dip,
43490Sstevel@tonic-gate     char *name, char **data, uint_t nelements)
43500Sstevel@tonic-gate {
43510Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
43520Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_STRING,
43530Sstevel@tonic-gate 	    name, data, nelements,
43540Sstevel@tonic-gate 	    ddi_prop_fm_encode_strings));
43550Sstevel@tonic-gate }
43560Sstevel@tonic-gate 
43570Sstevel@tonic-gate 
43580Sstevel@tonic-gate /*
43590Sstevel@tonic-gate  * Get an array of bytes property.
43600Sstevel@tonic-gate  */
43610Sstevel@tonic-gate int
ddi_prop_lookup_byte_array(dev_t match_dev,dev_info_t * dip,uint_t flags,char * name,uchar_t ** data,uint_t * nelements)43620Sstevel@tonic-gate ddi_prop_lookup_byte_array(dev_t match_dev, dev_info_t *dip, uint_t flags,
43630Sstevel@tonic-gate     char *name, uchar_t **data, uint_t *nelements)
43640Sstevel@tonic-gate {
43650Sstevel@tonic-gate 	if (flags & ~(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
43668371SVikram.Hegde@Sun.COM 	    LDI_DEV_T_ANY | DDI_UNBND_DLPI2 | DDI_PROP_ROOTNEX_GLOBAL)) {
43670Sstevel@tonic-gate #ifdef DEBUG
43680Sstevel@tonic-gate 		if (dip != NULL) {
43690Sstevel@tonic-gate 			cmn_err(CE_WARN, "ddi_prop_lookup_byte_array: "
43700Sstevel@tonic-gate 			    " invalid flag 0x%x (prop = %s, node = %s%d)",
43710Sstevel@tonic-gate 			    flags, name, ddi_driver_name(dip),
43720Sstevel@tonic-gate 			    ddi_get_instance(dip));
43730Sstevel@tonic-gate 		}
43740Sstevel@tonic-gate #endif /* DEBUG */
43750Sstevel@tonic-gate 		flags &= DDI_PROP_DONTPASS | DDI_PROP_NOTPROM |
43760Sstevel@tonic-gate 		    LDI_DEV_T_ANY | DDI_UNBND_DLPI2;
43770Sstevel@tonic-gate 	}
43780Sstevel@tonic-gate 
43790Sstevel@tonic-gate 	return (ddi_prop_lookup_common(match_dev, dip,
43800Sstevel@tonic-gate 	    (flags | DDI_PROP_TYPE_BYTE), name, data,
43810Sstevel@tonic-gate 	    nelements, ddi_prop_fm_decode_bytes));
43820Sstevel@tonic-gate }
43830Sstevel@tonic-gate 
43840Sstevel@tonic-gate /*
43850Sstevel@tonic-gate  * Update an array of bytes property.
43860Sstevel@tonic-gate  */
43870Sstevel@tonic-gate int
ddi_prop_update_byte_array(dev_t match_dev,dev_info_t * dip,char * name,uchar_t * data,uint_t nelements)43880Sstevel@tonic-gate ddi_prop_update_byte_array(dev_t match_dev, dev_info_t *dip,
43890Sstevel@tonic-gate     char *name, uchar_t *data, uint_t nelements)
43900Sstevel@tonic-gate {
43910Sstevel@tonic-gate 	if (nelements == 0)
43920Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
43930Sstevel@tonic-gate 
43940Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip, DDI_PROP_TYPE_BYTE,
43950Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_encode_bytes));
43960Sstevel@tonic-gate }
43970Sstevel@tonic-gate 
43980Sstevel@tonic-gate 
43990Sstevel@tonic-gate int
e_ddi_prop_update_byte_array(dev_t match_dev,dev_info_t * dip,char * name,uchar_t * data,uint_t nelements)44000Sstevel@tonic-gate e_ddi_prop_update_byte_array(dev_t match_dev, dev_info_t *dip,
44010Sstevel@tonic-gate     char *name, uchar_t *data, uint_t nelements)
44020Sstevel@tonic-gate {
44030Sstevel@tonic-gate 	if (nelements == 0)
44040Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
44050Sstevel@tonic-gate 
44060Sstevel@tonic-gate 	return (ddi_prop_update_common(match_dev, dip,
44070Sstevel@tonic-gate 	    DDI_PROP_SYSTEM_DEF | DDI_PROP_TYPE_BYTE,
44080Sstevel@tonic-gate 	    name, data, nelements, ddi_prop_fm_encode_bytes));
44090Sstevel@tonic-gate }
44100Sstevel@tonic-gate 
44110Sstevel@tonic-gate 
44120Sstevel@tonic-gate /*
44130Sstevel@tonic-gate  * ddi_prop_remove_common:	Undefine a managed property:
44140Sstevel@tonic-gate  *			Input dev_t must match dev_t when defined.
44150Sstevel@tonic-gate  *			Returns DDI_PROP_NOT_FOUND, possibly.
44160Sstevel@tonic-gate  *			DDI_PROP_INVAL_ARG is also possible if dev is
44170Sstevel@tonic-gate  *			DDI_DEV_T_ANY or incoming name is the NULL string.
44180Sstevel@tonic-gate  */
44190Sstevel@tonic-gate int
ddi_prop_remove_common(dev_t dev,dev_info_t * dip,char * name,int flag)44200Sstevel@tonic-gate ddi_prop_remove_common(dev_t dev, dev_info_t *dip, char *name, int flag)
44210Sstevel@tonic-gate {
44220Sstevel@tonic-gate 	ddi_prop_t	**list_head = &(DEVI(dip)->devi_drv_prop_ptr);
44230Sstevel@tonic-gate 	ddi_prop_t	*propp;
44240Sstevel@tonic-gate 	ddi_prop_t	*lastpropp = NULL;
44250Sstevel@tonic-gate 
44260Sstevel@tonic-gate 	if ((dev == DDI_DEV_T_ANY) || (name == (char *)0) ||
44270Sstevel@tonic-gate 	    (strlen(name) == 0)) {
44280Sstevel@tonic-gate 		return (DDI_PROP_INVAL_ARG);
44290Sstevel@tonic-gate 	}
44300Sstevel@tonic-gate 
44310Sstevel@tonic-gate 	if (flag & DDI_PROP_SYSTEM_DEF)
44320Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_sys_prop_ptr);
44330Sstevel@tonic-gate 	else if (flag & DDI_PROP_HW_DEF)
44340Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_hw_prop_ptr);
44350Sstevel@tonic-gate 
44360Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
44370Sstevel@tonic-gate 
44380Sstevel@tonic-gate 	for (propp = *list_head; propp != NULL; propp = propp->prop_next)  {
4439164Scth 		if (DDI_STRSAME(propp->prop_name, name) &&
44400Sstevel@tonic-gate 		    (dev == propp->prop_dev)) {
44410Sstevel@tonic-gate 			/*
44420Sstevel@tonic-gate 			 * Unlink this propp allowing for it to
44430Sstevel@tonic-gate 			 * be first in the list:
44440Sstevel@tonic-gate 			 */
44450Sstevel@tonic-gate 
44460Sstevel@tonic-gate 			if (lastpropp == NULL)
44470Sstevel@tonic-gate 				*list_head = propp->prop_next;
44480Sstevel@tonic-gate 			else
44490Sstevel@tonic-gate 				lastpropp->prop_next = propp->prop_next;
44500Sstevel@tonic-gate 
44510Sstevel@tonic-gate 			mutex_exit(&(DEVI(dip)->devi_lock));
44520Sstevel@tonic-gate 
44530Sstevel@tonic-gate 			/*
44540Sstevel@tonic-gate 			 * Free memory and return...
44550Sstevel@tonic-gate 			 */
44560Sstevel@tonic-gate 			kmem_free(propp->prop_name,
44570Sstevel@tonic-gate 			    strlen(propp->prop_name) + 1);
44580Sstevel@tonic-gate 			if (propp->prop_len != 0)
44590Sstevel@tonic-gate 				kmem_free(propp->prop_val, propp->prop_len);
44600Sstevel@tonic-gate 			kmem_free(propp, sizeof (ddi_prop_t));
44610Sstevel@tonic-gate 			return (DDI_PROP_SUCCESS);
44620Sstevel@tonic-gate 		}
44630Sstevel@tonic-gate 		lastpropp = propp;
44640Sstevel@tonic-gate 	}
44650Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
44660Sstevel@tonic-gate 	return (DDI_PROP_NOT_FOUND);
44670Sstevel@tonic-gate }
44680Sstevel@tonic-gate 
44690Sstevel@tonic-gate int
ddi_prop_remove(dev_t dev,dev_info_t * dip,char * name)44700Sstevel@tonic-gate ddi_prop_remove(dev_t dev, dev_info_t *dip, char *name)
44710Sstevel@tonic-gate {
44720Sstevel@tonic-gate 	return (ddi_prop_remove_common(dev, dip, name, 0));
44730Sstevel@tonic-gate }
44740Sstevel@tonic-gate 
44750Sstevel@tonic-gate int
e_ddi_prop_remove(dev_t dev,dev_info_t * dip,char * name)44760Sstevel@tonic-gate e_ddi_prop_remove(dev_t dev, dev_info_t *dip, char *name)
44770Sstevel@tonic-gate {
44780Sstevel@tonic-gate 	return (ddi_prop_remove_common(dev, dip, name, DDI_PROP_SYSTEM_DEF));
44790Sstevel@tonic-gate }
44800Sstevel@tonic-gate 
44810Sstevel@tonic-gate /*
44820Sstevel@tonic-gate  * e_ddi_prop_list_delete: remove a list of properties
44830Sstevel@tonic-gate  *	Note that the caller needs to provide the required protection
44840Sstevel@tonic-gate  *	(eg. devi_lock if these properties are still attached to a devi)
44850Sstevel@tonic-gate  */
44860Sstevel@tonic-gate void
e_ddi_prop_list_delete(ddi_prop_t * props)44870Sstevel@tonic-gate e_ddi_prop_list_delete(ddi_prop_t *props)
44880Sstevel@tonic-gate {
44890Sstevel@tonic-gate 	i_ddi_prop_list_delete(props);
44900Sstevel@tonic-gate }
44910Sstevel@tonic-gate 
44920Sstevel@tonic-gate /*
44930Sstevel@tonic-gate  * ddi_prop_remove_all_common:
44940Sstevel@tonic-gate  *	Used before unloading a driver to remove
44950Sstevel@tonic-gate  *	all properties. (undefines all dev_t's props.)
44960Sstevel@tonic-gate  *	Also removes `explicitly undefined' props.
44970Sstevel@tonic-gate  *	No errors possible.
44980Sstevel@tonic-gate  */
44990Sstevel@tonic-gate void
ddi_prop_remove_all_common(dev_info_t * dip,int flag)45000Sstevel@tonic-gate ddi_prop_remove_all_common(dev_info_t *dip, int flag)
45010Sstevel@tonic-gate {
45020Sstevel@tonic-gate 	ddi_prop_t	**list_head;
45030Sstevel@tonic-gate 
45040Sstevel@tonic-gate 	mutex_enter(&(DEVI(dip)->devi_lock));
45050Sstevel@tonic-gate 	if (flag & DDI_PROP_SYSTEM_DEF) {
45060Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_sys_prop_ptr);
45070Sstevel@tonic-gate 	} else if (flag & DDI_PROP_HW_DEF) {
45080Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_hw_prop_ptr);
45090Sstevel@tonic-gate 	} else {
45100Sstevel@tonic-gate 		list_head = &(DEVI(dip)->devi_drv_prop_ptr);
45110Sstevel@tonic-gate 	}
45120Sstevel@tonic-gate 	i_ddi_prop_list_delete(*list_head);
45130Sstevel@tonic-gate 	*list_head = NULL;
45140Sstevel@tonic-gate 	mutex_exit(&(DEVI(dip)->devi_lock));
45150Sstevel@tonic-gate }
45160Sstevel@tonic-gate 
45170Sstevel@tonic-gate 
45180Sstevel@tonic-gate /*
45190Sstevel@tonic-gate  * ddi_prop_remove_all:		Remove all driver prop definitions.
45200Sstevel@tonic-gate  */
45210Sstevel@tonic-gate 
45220Sstevel@tonic-gate void
ddi_prop_remove_all(dev_info_t * dip)45230Sstevel@tonic-gate ddi_prop_remove_all(dev_info_t *dip)
45240Sstevel@tonic-gate {
45257224Scth 	i_ddi_prop_dyn_driver_set(dip, NULL);
45260Sstevel@tonic-gate 	ddi_prop_remove_all_common(dip, 0);
45270Sstevel@tonic-gate }
45280Sstevel@tonic-gate 
45290Sstevel@tonic-gate /*
45300Sstevel@tonic-gate  * e_ddi_prop_remove_all:	Remove all system prop definitions.
45310Sstevel@tonic-gate  */
45320Sstevel@tonic-gate 
45330Sstevel@tonic-gate void
e_ddi_prop_remove_all(dev_info_t * dip)45340Sstevel@tonic-gate e_ddi_prop_remove_all(dev_info_t *dip)
45350Sstevel@tonic-gate {
45360Sstevel@tonic-gate 	ddi_prop_remove_all_common(dip, (int)DDI_PROP_SYSTEM_DEF);
45370Sstevel@tonic-gate }
45380Sstevel@tonic-gate 
45390Sstevel@tonic-gate 
45400Sstevel@tonic-gate /*
45410Sstevel@tonic-gate  * ddi_prop_undefine:	Explicitly undefine a property.  Property
45420Sstevel@tonic-gate  *			searches which match this property return
45430Sstevel@tonic-gate  *			the error code DDI_PROP_UNDEFINED.
45440Sstevel@tonic-gate  *
45450Sstevel@tonic-gate  *			Use ddi_prop_remove to negate effect of
45460Sstevel@tonic-gate  *			ddi_prop_undefine
45470Sstevel@tonic-gate  *
45480Sstevel@tonic-gate  *			See above for error returns.
45490Sstevel@tonic-gate  */
45500Sstevel@tonic-gate 
45510Sstevel@tonic-gate int
ddi_prop_undefine(dev_t dev,dev_info_t * dip,int flag,char * name)45520Sstevel@tonic-gate ddi_prop_undefine(dev_t dev, dev_info_t *dip, int flag, char *name)
45530Sstevel@tonic-gate {
45540Sstevel@tonic-gate 	if (!(flag & DDI_PROP_CANSLEEP))
45550Sstevel@tonic-gate 		flag |= DDI_PROP_DONTSLEEP;
45567224Scth 	flag |= DDI_PROP_STACK_CREATE | DDI_PROP_UNDEF_IT | DDI_PROP_TYPE_ANY;
45577224Scth 	return (ddi_prop_update_common(dev, dip, flag,
45587224Scth 	    name, NULL, 0, ddi_prop_fm_encode_bytes));
45590Sstevel@tonic-gate }
45600Sstevel@tonic-gate 
45610Sstevel@tonic-gate int
e_ddi_prop_undefine(dev_t dev,dev_info_t * dip,int flag,char * name)45620Sstevel@tonic-gate e_ddi_prop_undefine(dev_t dev, dev_info_t *dip, int flag, char *name)
45630Sstevel@tonic-gate {
45640Sstevel@tonic-gate 	if (!(flag & DDI_PROP_CANSLEEP))
45650Sstevel@tonic-gate 		flag |= DDI_PROP_DONTSLEEP;
45667224Scth 	flag |= DDI_PROP_SYSTEM_DEF | DDI_PROP_STACK_CREATE |
45677224Scth 	    DDI_PROP_UNDEF_IT | DDI_PROP_TYPE_ANY;
45687224Scth 	return (ddi_prop_update_common(dev, dip, flag,
45690Sstevel@tonic-gate 	    name, NULL, 0, ddi_prop_fm_encode_bytes));
45700Sstevel@tonic-gate }
45710Sstevel@tonic-gate 
45720Sstevel@tonic-gate /*
45737224Scth  * Support for gathering dynamic properties in devinfo snapshot.
45747224Scth  */
45757224Scth void
i_ddi_prop_dyn_driver_set(dev_info_t * dip,i_ddi_prop_dyn_t * dp)45767224Scth i_ddi_prop_dyn_driver_set(dev_info_t *dip, i_ddi_prop_dyn_t *dp)
45777224Scth {
45787224Scth 	DEVI(dip)->devi_prop_dyn_driver = dp;
45797224Scth }
45807224Scth 
45817224Scth i_ddi_prop_dyn_t *
i_ddi_prop_dyn_driver_get(dev_info_t * dip)45827224Scth i_ddi_prop_dyn_driver_get(dev_info_t *dip)
45837224Scth {
45847224Scth 	return (DEVI(dip)->devi_prop_dyn_driver);
45857224Scth }
45867224Scth 
45877224Scth void
i_ddi_prop_dyn_parent_set(dev_info_t * dip,i_ddi_prop_dyn_t * dp)45887224Scth i_ddi_prop_dyn_parent_set(dev_info_t *dip, i_ddi_prop_dyn_t *dp)
45897224Scth {
45907224Scth 	DEVI(dip)->devi_prop_dyn_parent = dp;
45917224Scth }
45927224Scth 
45937224Scth i_ddi_prop_dyn_t *
i_ddi_prop_dyn_parent_get(dev_info_t * dip)45947224Scth i_ddi_prop_dyn_parent_get(dev_info_t *dip)
45957224Scth {
45967224Scth 	return (DEVI(dip)->devi_prop_dyn_parent);
45977224Scth }
45987224Scth 
45997224Scth void
i_ddi_prop_dyn_cache_invalidate(dev_info_t * dip,i_ddi_prop_dyn_t * dp)46007224Scth i_ddi_prop_dyn_cache_invalidate(dev_info_t *dip, i_ddi_prop_dyn_t *dp)
46017224Scth {
46027224Scth 	/* for now we invalidate the entire cached snapshot */
46037224Scth 	if (dip && dp)
460410696SDavid.Hollister@Sun.COM 		i_ddi_di_cache_invalidate();
46057224Scth }
46067224Scth 
46077224Scth /* ARGSUSED */
46087224Scth void
ddi_prop_cache_invalidate(dev_t dev,dev_info_t * dip,char * name,int flags)46097224Scth ddi_prop_cache_invalidate(dev_t dev, dev_info_t *dip, char *name, int flags)
46107224Scth {
46117224Scth 	/* for now we invalidate the entire cached snapshot */
461210696SDavid.Hollister@Sun.COM 	i_ddi_di_cache_invalidate();
46137224Scth }
46147224Scth 
46157224Scth 
46167224Scth /*
46170Sstevel@tonic-gate  * Code to search hardware layer (PROM), if it exists, on behalf of child.
46180Sstevel@tonic-gate  *
46190Sstevel@tonic-gate  * if input dip != child_dip, then call is on behalf of child
46200Sstevel@tonic-gate  * to search PROM, do it via ddi_prop_search_common() and ascend only
46210Sstevel@tonic-gate  * if allowed.
46220Sstevel@tonic-gate  *
46230Sstevel@tonic-gate  * if input dip == ch_dip (child_dip), call is on behalf of root driver,
46240Sstevel@tonic-gate  * to search for PROM defined props only.
46250Sstevel@tonic-gate  *
46260Sstevel@tonic-gate  * Note that the PROM search is done only if the requested dev
46270Sstevel@tonic-gate  * is either DDI_DEV_T_ANY or DDI_DEV_T_NONE. PROM properties
46280Sstevel@tonic-gate  * have no associated dev, thus are automatically associated with
46290Sstevel@tonic-gate  * DDI_DEV_T_NONE.
46300Sstevel@tonic-gate  *
46310Sstevel@tonic-gate  * Modifying flag DDI_PROP_NOTPROM inhibits the search in the h/w layer.
46320Sstevel@tonic-gate  *
46330Sstevel@tonic-gate  * Returns DDI_PROP_FOUND_1275 if found to indicate to framework
46340Sstevel@tonic-gate  * that the property resides in the prom.
46350Sstevel@tonic-gate  */
46360Sstevel@tonic-gate int
impl_ddi_bus_prop_op(dev_t dev,dev_info_t * dip,dev_info_t * ch_dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)46370Sstevel@tonic-gate impl_ddi_bus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
46380Sstevel@tonic-gate     ddi_prop_op_t prop_op, int mod_flags,
46390Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
46400Sstevel@tonic-gate {
46410Sstevel@tonic-gate 	int	len;
46420Sstevel@tonic-gate 	caddr_t buffer;
46430Sstevel@tonic-gate 
46440Sstevel@tonic-gate 	/*
46450Sstevel@tonic-gate 	 * If requested dev is DDI_DEV_T_NONE or DDI_DEV_T_ANY, then
46460Sstevel@tonic-gate 	 * look in caller's PROM if it's a self identifying device...
46470Sstevel@tonic-gate 	 *
46480Sstevel@tonic-gate 	 * Note that this is very similar to ddi_prop_op, but we
46490Sstevel@tonic-gate 	 * search the PROM instead of the s/w defined properties,
46500Sstevel@tonic-gate 	 * and we are called on by the parent driver to do this for
46510Sstevel@tonic-gate 	 * the child.
46520Sstevel@tonic-gate 	 */
46530Sstevel@tonic-gate 
46540Sstevel@tonic-gate 	if (((dev == DDI_DEV_T_NONE) || (dev == DDI_DEV_T_ANY)) &&
46550Sstevel@tonic-gate 	    ndi_dev_is_prom_node(ch_dip) &&
46560Sstevel@tonic-gate 	    ((mod_flags & DDI_PROP_NOTPROM) == 0)) {
4657789Sahrens 		len = prom_getproplen((pnode_t)DEVI(ch_dip)->devi_nodeid, name);
46580Sstevel@tonic-gate 		if (len == -1) {
46590Sstevel@tonic-gate 			return (DDI_PROP_NOT_FOUND);
46600Sstevel@tonic-gate 		}
46610Sstevel@tonic-gate 
46620Sstevel@tonic-gate 		/*
46630Sstevel@tonic-gate 		 * If exists only request, we're done
46640Sstevel@tonic-gate 		 */
46650Sstevel@tonic-gate 		if (prop_op == PROP_EXISTS) {
46660Sstevel@tonic-gate 			return (DDI_PROP_FOUND_1275);
46670Sstevel@tonic-gate 		}
46680Sstevel@tonic-gate 
46690Sstevel@tonic-gate 		/*
46700Sstevel@tonic-gate 		 * If length only request or prop length == 0, get out
46710Sstevel@tonic-gate 		 */
46720Sstevel@tonic-gate 		if ((prop_op == PROP_LEN) || (len == 0)) {
46730Sstevel@tonic-gate 			*lengthp = len;
46740Sstevel@tonic-gate 			return (DDI_PROP_FOUND_1275);
46750Sstevel@tonic-gate 		}
46760Sstevel@tonic-gate 
46770Sstevel@tonic-gate 		/*
46780Sstevel@tonic-gate 		 * Allocate buffer if required... (either way `buffer'
46790Sstevel@tonic-gate 		 * is receiving address).
46800Sstevel@tonic-gate 		 */
46810Sstevel@tonic-gate 
46820Sstevel@tonic-gate 		switch (prop_op) {
46830Sstevel@tonic-gate 
46840Sstevel@tonic-gate 		case PROP_LEN_AND_VAL_ALLOC:
46850Sstevel@tonic-gate 
46860Sstevel@tonic-gate 			buffer = kmem_alloc((size_t)len,
46870Sstevel@tonic-gate 			    mod_flags & DDI_PROP_CANSLEEP ?
46880Sstevel@tonic-gate 			    KM_SLEEP : KM_NOSLEEP);
46890Sstevel@tonic-gate 			if (buffer == NULL) {
46900Sstevel@tonic-gate 				return (DDI_PROP_NO_MEMORY);
46910Sstevel@tonic-gate 			}
46920Sstevel@tonic-gate 			*(caddr_t *)valuep = buffer;
46930Sstevel@tonic-gate 			break;
46940Sstevel@tonic-gate 
46950Sstevel@tonic-gate 		case PROP_LEN_AND_VAL_BUF:
46960Sstevel@tonic-gate 
46970Sstevel@tonic-gate 			if (len > (*lengthp)) {
46980Sstevel@tonic-gate 				*lengthp = len;
46990Sstevel@tonic-gate 				return (DDI_PROP_BUF_TOO_SMALL);
47000Sstevel@tonic-gate 			}
47010Sstevel@tonic-gate 
47020Sstevel@tonic-gate 			buffer = valuep;
47030Sstevel@tonic-gate 			break;
47040Sstevel@tonic-gate 
47050Sstevel@tonic-gate 		default:
47060Sstevel@tonic-gate 			break;
47070Sstevel@tonic-gate 		}
47080Sstevel@tonic-gate 
47090Sstevel@tonic-gate 		/*
47100Sstevel@tonic-gate 		 * Call the PROM function to do the copy.
47110Sstevel@tonic-gate 		 */
4712789Sahrens 		(void) prom_getprop((pnode_t)DEVI(ch_dip)->devi_nodeid,
47134582Scth 		    name, buffer);
47140Sstevel@tonic-gate 
47150Sstevel@tonic-gate 		*lengthp = len; /* return the actual length to the caller */
47160Sstevel@tonic-gate 		(void) impl_fix_props(dip, ch_dip, name, len, buffer);
47170Sstevel@tonic-gate 		return (DDI_PROP_FOUND_1275);
47180Sstevel@tonic-gate 	}
47190Sstevel@tonic-gate 
47200Sstevel@tonic-gate 	return (DDI_PROP_NOT_FOUND);
47210Sstevel@tonic-gate }
47220Sstevel@tonic-gate 
47230Sstevel@tonic-gate /*
47240Sstevel@tonic-gate  * The ddi_bus_prop_op default bus nexus prop op function.
47250Sstevel@tonic-gate  *
47260Sstevel@tonic-gate  * Code to search hardware layer (PROM), if it exists,
47270Sstevel@tonic-gate  * on behalf of child, then, if appropriate, ascend and check
47280Sstevel@tonic-gate  * my own software defined properties...
47290Sstevel@tonic-gate  */
47300Sstevel@tonic-gate int
ddi_bus_prop_op(dev_t dev,dev_info_t * dip,dev_info_t * ch_dip,ddi_prop_op_t prop_op,int mod_flags,char * name,caddr_t valuep,int * lengthp)47310Sstevel@tonic-gate ddi_bus_prop_op(dev_t dev, dev_info_t *dip, dev_info_t *ch_dip,
47320Sstevel@tonic-gate     ddi_prop_op_t prop_op, int mod_flags,
47330Sstevel@tonic-gate     char *name, caddr_t valuep, int *lengthp)
47340Sstevel@tonic-gate {
47350Sstevel@tonic-gate 	int	error;
47360Sstevel@tonic-gate 
47370Sstevel@tonic-gate 	error = impl_ddi_bus_prop_op(dev, dip, ch_dip, prop_op, mod_flags,
47384582Scth 	    name, valuep, lengthp);
47390Sstevel@tonic-gate 
47400Sstevel@tonic-gate 	if (error == DDI_PROP_SUCCESS || error == DDI_PROP_FOUND_1275 ||
47410Sstevel@tonic-gate 	    error == DDI_PROP_BUF_TOO_SMALL)
47420Sstevel@tonic-gate 		return (error);
47430Sstevel@tonic-gate 
47440Sstevel@tonic-gate 	if (error == DDI_PROP_NO_MEMORY) {
47450Sstevel@tonic-gate 		cmn_err(CE_CONT, prop_no_mem_msg, name);
47460Sstevel@tonic-gate 		return (DDI_PROP_NO_MEMORY);
47470Sstevel@tonic-gate 	}
47480Sstevel@tonic-gate 
47490Sstevel@tonic-gate 	/*
47500Sstevel@tonic-gate 	 * Check the 'options' node as a last resort
47510Sstevel@tonic-gate 	 */
47520Sstevel@tonic-gate 	if ((mod_flags & DDI_PROP_DONTPASS) != 0)
47530Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
47540Sstevel@tonic-gate 
47550Sstevel@tonic-gate 	if (ch_dip == ddi_root_node())	{
47560Sstevel@tonic-gate 		/*
47570Sstevel@tonic-gate 		 * As a last resort, when we've reached
47580Sstevel@tonic-gate 		 * the top and still haven't found the
47590Sstevel@tonic-gate 		 * property, see if the desired property
47600Sstevel@tonic-gate 		 * is attached to the options node.
47610Sstevel@tonic-gate 		 *
47620Sstevel@tonic-gate 		 * The options dip is attached right after boot.
47630Sstevel@tonic-gate 		 */
47640Sstevel@tonic-gate 		ASSERT(options_dip != NULL);
47650Sstevel@tonic-gate 		/*
47660Sstevel@tonic-gate 		 * Force the "don't pass" flag to *just* see
47670Sstevel@tonic-gate 		 * what the options node has to offer.
47680Sstevel@tonic-gate 		 */
47690Sstevel@tonic-gate 		return (ddi_prop_search_common(dev, options_dip, prop_op,
47700Sstevel@tonic-gate 		    mod_flags|DDI_PROP_DONTPASS, name, valuep,
47710Sstevel@tonic-gate 		    (uint_t *)lengthp));
47720Sstevel@tonic-gate 	}
47730Sstevel@tonic-gate 
47740Sstevel@tonic-gate 	/*
47750Sstevel@tonic-gate 	 * Otherwise, continue search with parent's s/w defined properties...
47760Sstevel@tonic-gate 	 * NOTE: Using `dip' in following call increments the level.
47770Sstevel@tonic-gate 	 */
47780Sstevel@tonic-gate 
47790Sstevel@tonic-gate 	return (ddi_prop_search_common(dev, dip, prop_op, mod_flags,
47800Sstevel@tonic-gate 	    name, valuep, (uint_t *)lengthp));
47810Sstevel@tonic-gate }
47820Sstevel@tonic-gate 
47830Sstevel@tonic-gate /*
47840Sstevel@tonic-gate  * External property functions used by other parts of the kernel...
47850Sstevel@tonic-gate  */
47860Sstevel@tonic-gate 
47870Sstevel@tonic-gate /*
47880Sstevel@tonic-gate  * e_ddi_getlongprop: See comments for ddi_get_longprop.
47890Sstevel@tonic-gate  */
47900Sstevel@tonic-gate 
47910Sstevel@tonic-gate int
e_ddi_getlongprop(dev_t dev,vtype_t type,char * name,int flags,caddr_t valuep,int * lengthp)47920Sstevel@tonic-gate e_ddi_getlongprop(dev_t dev, vtype_t type, char *name, int flags,
47930Sstevel@tonic-gate     caddr_t valuep, int *lengthp)
47940Sstevel@tonic-gate {
47950Sstevel@tonic-gate 	_NOTE(ARGUNUSED(type))
47960Sstevel@tonic-gate 	dev_info_t *devi;
47970Sstevel@tonic-gate 	ddi_prop_op_t prop_op = PROP_LEN_AND_VAL_ALLOC;
47980Sstevel@tonic-gate 	int error;
47990Sstevel@tonic-gate 
48000Sstevel@tonic-gate 	if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
48010Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
48020Sstevel@tonic-gate 
48030Sstevel@tonic-gate 	error = cdev_prop_op(dev, devi, prop_op, flags, name, valuep, lengthp);
48040Sstevel@tonic-gate 	ddi_release_devi(devi);
48050Sstevel@tonic-gate 	return (error);
48060Sstevel@tonic-gate }
48070Sstevel@tonic-gate 
48080Sstevel@tonic-gate /*
48090Sstevel@tonic-gate  * e_ddi_getlongprop_buf:	See comments for ddi_getlongprop_buf.
48100Sstevel@tonic-gate  */
48110Sstevel@tonic-gate 
48120Sstevel@tonic-gate int
e_ddi_getlongprop_buf(dev_t dev,vtype_t type,char * name,int flags,caddr_t valuep,int * lengthp)48130Sstevel@tonic-gate e_ddi_getlongprop_buf(dev_t dev, vtype_t type, char *name, int flags,
48140Sstevel@tonic-gate     caddr_t valuep, int *lengthp)
48150Sstevel@tonic-gate {
48160Sstevel@tonic-gate 	_NOTE(ARGUNUSED(type))
48170Sstevel@tonic-gate 	dev_info_t *devi;
48180Sstevel@tonic-gate 	ddi_prop_op_t prop_op = PROP_LEN_AND_VAL_BUF;
48190Sstevel@tonic-gate 	int error;
48200Sstevel@tonic-gate 
48210Sstevel@tonic-gate 	if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
48220Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
48230Sstevel@tonic-gate 
48240Sstevel@tonic-gate 	error = cdev_prop_op(dev, devi, prop_op, flags, name, valuep, lengthp);
48250Sstevel@tonic-gate 	ddi_release_devi(devi);
48260Sstevel@tonic-gate 	return (error);
48270Sstevel@tonic-gate }
48280Sstevel@tonic-gate 
48290Sstevel@tonic-gate /*
48300Sstevel@tonic-gate  * e_ddi_getprop:	See comments for ddi_getprop.
48310Sstevel@tonic-gate  */
48320Sstevel@tonic-gate int
e_ddi_getprop(dev_t dev,vtype_t type,char * name,int flags,int defvalue)48330Sstevel@tonic-gate e_ddi_getprop(dev_t dev, vtype_t type, char *name, int flags, int defvalue)
48340Sstevel@tonic-gate {
48350Sstevel@tonic-gate 	_NOTE(ARGUNUSED(type))
48360Sstevel@tonic-gate 	dev_info_t *devi;
48370Sstevel@tonic-gate 	ddi_prop_op_t prop_op = PROP_LEN_AND_VAL_BUF;
48380Sstevel@tonic-gate 	int	propvalue = defvalue;
48390Sstevel@tonic-gate 	int	proplength = sizeof (int);
48400Sstevel@tonic-gate 	int	error;
48410Sstevel@tonic-gate 
48420Sstevel@tonic-gate 	if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
48430Sstevel@tonic-gate 		return (defvalue);
48440Sstevel@tonic-gate 
48450Sstevel@tonic-gate 	error = cdev_prop_op(dev, devi, prop_op,
48460Sstevel@tonic-gate 	    flags, name, (caddr_t)&propvalue, &proplength);
48470Sstevel@tonic-gate 	ddi_release_devi(devi);
48480Sstevel@tonic-gate 
48490Sstevel@tonic-gate 	if ((error == DDI_PROP_SUCCESS) && (proplength == 0))
48500Sstevel@tonic-gate 		propvalue = 1;
48510Sstevel@tonic-gate 
48520Sstevel@tonic-gate 	return (propvalue);
48530Sstevel@tonic-gate }
48540Sstevel@tonic-gate 
48550Sstevel@tonic-gate /*
48560Sstevel@tonic-gate  * e_ddi_getprop_int64:
48570Sstevel@tonic-gate  *
48580Sstevel@tonic-gate  * This is a typed interfaces, but predates typed properties. With the
48590Sstevel@tonic-gate  * introduction of typed properties the framework tries to ensure
48600Sstevel@tonic-gate  * consistent use of typed interfaces. This is why TYPE_INT64 is not
48610Sstevel@tonic-gate  * part of TYPE_ANY.  E_ddi_getprop_int64 is a special case where a
48620Sstevel@tonic-gate  * typed interface invokes legacy (non-typed) interfaces:
48630Sstevel@tonic-gate  * cdev_prop_op(), prop_op(9E), ddi_prop_op(9F)).  In this case the
48640Sstevel@tonic-gate  * fact that TYPE_INT64 is not part of TYPE_ANY matters.  To support
48650Sstevel@tonic-gate  * this type of lookup as a single operation we invoke the legacy
48660Sstevel@tonic-gate  * non-typed interfaces with the special CONSUMER_TYPED bit set. The
48670Sstevel@tonic-gate  * framework ddi_prop_op(9F) implementation is expected to check for
48680Sstevel@tonic-gate  * CONSUMER_TYPED and, if set, expand type bits beyond TYPE_ANY
48690Sstevel@tonic-gate  * (currently TYPE_INT64).
48700Sstevel@tonic-gate  */
48710Sstevel@tonic-gate int64_t
e_ddi_getprop_int64(dev_t dev,vtype_t type,char * name,int flags,int64_t defvalue)48720Sstevel@tonic-gate e_ddi_getprop_int64(dev_t dev, vtype_t type, char *name,
48730Sstevel@tonic-gate     int flags, int64_t defvalue)
48740Sstevel@tonic-gate {
48750Sstevel@tonic-gate 	_NOTE(ARGUNUSED(type))
48760Sstevel@tonic-gate 	dev_info_t	*devi;
48770Sstevel@tonic-gate 	ddi_prop_op_t	prop_op = PROP_LEN_AND_VAL_BUF;
48780Sstevel@tonic-gate 	int64_t		propvalue = defvalue;
48790Sstevel@tonic-gate 	int		proplength = sizeof (propvalue);
48800Sstevel@tonic-gate 	int		error;
48810Sstevel@tonic-gate 
48820Sstevel@tonic-gate 	if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
48830Sstevel@tonic-gate 		return (defvalue);
48840Sstevel@tonic-gate 
48850Sstevel@tonic-gate 	error = cdev_prop_op(dev, devi, prop_op, flags |
48860Sstevel@tonic-gate 	    DDI_PROP_CONSUMER_TYPED, name, (caddr_t)&propvalue, &proplength);
48870Sstevel@tonic-gate 	ddi_release_devi(devi);
48880Sstevel@tonic-gate 
48890Sstevel@tonic-gate 	if ((error == DDI_PROP_SUCCESS) && (proplength == 0))
48900Sstevel@tonic-gate 		propvalue = 1;
48910Sstevel@tonic-gate 
48920Sstevel@tonic-gate 	return (propvalue);
48930Sstevel@tonic-gate }
48940Sstevel@tonic-gate 
48950Sstevel@tonic-gate /*
48960Sstevel@tonic-gate  * e_ddi_getproplen:	See comments for ddi_getproplen.
48970Sstevel@tonic-gate  */
48980Sstevel@tonic-gate int
e_ddi_getproplen(dev_t dev,vtype_t type,char * name,int flags,int * lengthp)48990Sstevel@tonic-gate e_ddi_getproplen(dev_t dev, vtype_t type, char *name, int flags, int *lengthp)
49000Sstevel@tonic-gate {
49010Sstevel@tonic-gate 	_NOTE(ARGUNUSED(type))
49020Sstevel@tonic-gate 	dev_info_t *devi;
49030Sstevel@tonic-gate 	ddi_prop_op_t prop_op = PROP_LEN;
49040Sstevel@tonic-gate 	int error;
49050Sstevel@tonic-gate 
49060Sstevel@tonic-gate 	if ((devi = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
49070Sstevel@tonic-gate 		return (DDI_PROP_NOT_FOUND);
49080Sstevel@tonic-gate 
49090Sstevel@tonic-gate 	error = cdev_prop_op(dev, devi, prop_op, flags, name, NULL, lengthp);
49100Sstevel@tonic-gate 	ddi_release_devi(devi);
49110Sstevel@tonic-gate 	return (error);
49120Sstevel@tonic-gate }
49130Sstevel@tonic-gate 
49140Sstevel@tonic-gate /*
49150Sstevel@tonic-gate  * Routines to get at elements of the dev_info structure
49160Sstevel@tonic-gate  */
49170Sstevel@tonic-gate 
49180Sstevel@tonic-gate /*
49190Sstevel@tonic-gate  * ddi_binding_name: Return the driver binding name of the devinfo node
49200Sstevel@tonic-gate  *		This is the name the OS used to bind the node to a driver.
49210Sstevel@tonic-gate  */
49220Sstevel@tonic-gate char *
ddi_binding_name(dev_info_t * dip)49230Sstevel@tonic-gate ddi_binding_name(dev_info_t *dip)
49240Sstevel@tonic-gate {
49250Sstevel@tonic-gate 	return (DEVI(dip)->devi_binding_name);
49260Sstevel@tonic-gate }
49270Sstevel@tonic-gate 
49280Sstevel@tonic-gate /*
49290Sstevel@tonic-gate  * ddi_driver_major: Return the major number of the driver that
49308459SJerry.Gilliam@Sun.COM  *	the supplied devinfo is bound to.  If not yet bound,
49318459SJerry.Gilliam@Sun.COM  *	DDI_MAJOR_T_NONE.
49328459SJerry.Gilliam@Sun.COM  *
49338459SJerry.Gilliam@Sun.COM  * When used by the driver bound to 'devi', this
49348459SJerry.Gilliam@Sun.COM  * function will reliably return the driver major number.
49358459SJerry.Gilliam@Sun.COM  * Other ways of determining the driver major number, such as
49368459SJerry.Gilliam@Sun.COM  *	major = ddi_name_to_major(ddi_get_name(devi));
49378459SJerry.Gilliam@Sun.COM  *	major = ddi_name_to_major(ddi_binding_name(devi));
49388459SJerry.Gilliam@Sun.COM  * can return a different result as the driver/alias binding
49398459SJerry.Gilliam@Sun.COM  * can change dynamically, and thus should be avoided.
49400Sstevel@tonic-gate  */
49410Sstevel@tonic-gate major_t
ddi_driver_major(dev_info_t * devi)49420Sstevel@tonic-gate ddi_driver_major(dev_info_t *devi)
49430Sstevel@tonic-gate {
49440Sstevel@tonic-gate 	return (DEVI(devi)->devi_major);
49450Sstevel@tonic-gate }
49460Sstevel@tonic-gate 
49470Sstevel@tonic-gate /*
49480Sstevel@tonic-gate  * ddi_driver_name: Return the normalized driver name. this is the
49490Sstevel@tonic-gate  *		actual driver name
49500Sstevel@tonic-gate  */
49510Sstevel@tonic-gate const char *
ddi_driver_name(dev_info_t * devi)49520Sstevel@tonic-gate ddi_driver_name(dev_info_t *devi)
49530Sstevel@tonic-gate {
49540Sstevel@tonic-gate 	major_t major;
49550Sstevel@tonic-gate 
49567009Scth 	if ((major = ddi_driver_major(devi)) != DDI_MAJOR_T_NONE)
49570Sstevel@tonic-gate 		return (ddi_major_to_name(major));
49580Sstevel@tonic-gate 
49590Sstevel@tonic-gate 	return (ddi_node_name(devi));
49600Sstevel@tonic-gate }
49610Sstevel@tonic-gate 
49620Sstevel@tonic-gate /*
49630Sstevel@tonic-gate  * i_ddi_set_binding_name:	Set binding name.
49640Sstevel@tonic-gate  *
49650Sstevel@tonic-gate  *	Set the binding name to the given name.
49660Sstevel@tonic-gate  *	This routine is for use by the ddi implementation, not by drivers.
49670Sstevel@tonic-gate  */
49680Sstevel@tonic-gate void
i_ddi_set_binding_name(dev_info_t * dip,char * name)49690Sstevel@tonic-gate i_ddi_set_binding_name(dev_info_t *dip, char *name)
49700Sstevel@tonic-gate {
49710Sstevel@tonic-gate 	DEVI(dip)->devi_binding_name = name;
49720Sstevel@tonic-gate 
49730Sstevel@tonic-gate }
49740Sstevel@tonic-gate 
49750Sstevel@tonic-gate /*
49760Sstevel@tonic-gate  * ddi_get_name: A synonym of ddi_binding_name() ... returns a name
49770Sstevel@tonic-gate  * the implementation has used to bind the node to a driver.
49780Sstevel@tonic-gate  */
49790Sstevel@tonic-gate char *
ddi_get_name(dev_info_t * dip)49800Sstevel@tonic-gate ddi_get_name(dev_info_t *dip)
49810Sstevel@tonic-gate {
49820Sstevel@tonic-gate 	return (DEVI(dip)->devi_binding_name);
49830Sstevel@tonic-gate }
49840Sstevel@tonic-gate 
49850Sstevel@tonic-gate /*
49860Sstevel@tonic-gate  * ddi_node_name: Return the name property of the devinfo node
49870Sstevel@tonic-gate  *		This may differ from ddi_binding_name if the node name
49880Sstevel@tonic-gate  *		does not define a binding to a driver (i.e. generic names).
49890Sstevel@tonic-gate  */
49900Sstevel@tonic-gate char *
ddi_node_name(dev_info_t * dip)49910Sstevel@tonic-gate ddi_node_name(dev_info_t *dip)
49920Sstevel@tonic-gate {
49930Sstevel@tonic-gate 	return (DEVI(dip)->devi_node_name);
49940Sstevel@tonic-gate }
49950Sstevel@tonic-gate 
49960Sstevel@tonic-gate 
49970Sstevel@tonic-gate /*
49980Sstevel@tonic-gate  * ddi_get_nodeid:	Get nodeid stored in dev_info structure.
49990Sstevel@tonic-gate  */
50000Sstevel@tonic-gate int
ddi_get_nodeid(dev_info_t * dip)50010Sstevel@tonic-gate ddi_get_nodeid(dev_info_t *dip)
50020Sstevel@tonic-gate {
50030Sstevel@tonic-gate 	return (DEVI(dip)->devi_nodeid);
50040Sstevel@tonic-gate }
50050Sstevel@tonic-gate 
50060Sstevel@tonic-gate int
ddi_get_instance(dev_info_t * dip)50070Sstevel@tonic-gate ddi_get_instance(dev_info_t *dip)
50080Sstevel@tonic-gate {
50090Sstevel@tonic-gate 	return (DEVI(dip)->devi_instance);
50100Sstevel@tonic-gate }
50110Sstevel@tonic-gate 
50120Sstevel@tonic-gate struct dev_ops *
ddi_get_driver(dev_info_t * dip)50130Sstevel@tonic-gate ddi_get_driver(dev_info_t *dip)
50140Sstevel@tonic-gate {
50150Sstevel@tonic-gate 	return (DEVI(dip)->devi_ops);
50160Sstevel@tonic-gate }
50170Sstevel@tonic-gate 
50180Sstevel@tonic-gate void
ddi_set_driver(dev_info_t * dip,struct dev_ops * devo)50190Sstevel@tonic-gate ddi_set_driver(dev_info_t *dip, struct dev_ops *devo)
50200Sstevel@tonic-gate {
50210Sstevel@tonic-gate 	DEVI(dip)->devi_ops = devo;
50220Sstevel@tonic-gate }
50230Sstevel@tonic-gate 
50240Sstevel@tonic-gate /*
50250Sstevel@tonic-gate  * ddi_set_driver_private/ddi_get_driver_private:
50260Sstevel@tonic-gate  * Get/set device driver private data in devinfo.
50270Sstevel@tonic-gate  */
50280Sstevel@tonic-gate void
ddi_set_driver_private(dev_info_t * dip,void * data)50290Sstevel@tonic-gate ddi_set_driver_private(dev_info_t *dip, void *data)
50300Sstevel@tonic-gate {
50310Sstevel@tonic-gate 	DEVI(dip)->devi_driver_data = data;
50320Sstevel@tonic-gate }
50330Sstevel@tonic-gate 
50340Sstevel@tonic-gate void *
ddi_get_driver_private(dev_info_t * dip)50350Sstevel@tonic-gate ddi_get_driver_private(dev_info_t *dip)
50360Sstevel@tonic-gate {
50370Sstevel@tonic-gate 	return (DEVI(dip)->devi_driver_data);
50380Sstevel@tonic-gate }
50390Sstevel@tonic-gate 
50400Sstevel@tonic-gate /*
50410Sstevel@tonic-gate  * ddi_get_parent, ddi_get_child, ddi_get_next_sibling
50420Sstevel@tonic-gate  */
50430Sstevel@tonic-gate 
50440Sstevel@tonic-gate dev_info_t *
ddi_get_parent(dev_info_t * dip)50450Sstevel@tonic-gate ddi_get_parent(dev_info_t *dip)
50460Sstevel@tonic-gate {
50470Sstevel@tonic-gate 	return ((dev_info_t *)DEVI(dip)->devi_parent);
50480Sstevel@tonic-gate }
50490Sstevel@tonic-gate 
50500Sstevel@tonic-gate dev_info_t *
ddi_get_child(dev_info_t * dip)50510Sstevel@tonic-gate ddi_get_child(dev_info_t *dip)
50520Sstevel@tonic-gate {
50530Sstevel@tonic-gate 	return ((dev_info_t *)DEVI(dip)->devi_child);
50540Sstevel@tonic-gate }
50550Sstevel@tonic-gate 
50560Sstevel@tonic-gate dev_info_t *
ddi_get_next_sibling(dev_info_t * dip)50570Sstevel@tonic-gate ddi_get_next_sibling(dev_info_t *dip)
50580Sstevel@tonic-gate {
50590Sstevel@tonic-gate 	return ((dev_info_t *)DEVI(dip)->devi_sibling);
50600Sstevel@tonic-gate }
50610Sstevel@tonic-gate 
50620Sstevel@tonic-gate dev_info_t *
ddi_get_next(dev_info_t * dip)50630Sstevel@tonic-gate ddi_get_next(dev_info_t *dip)
50640Sstevel@tonic-gate {
50650Sstevel@tonic-gate 	return ((dev_info_t *)DEVI(dip)->devi_next);
50660Sstevel@tonic-gate }
50670Sstevel@tonic-gate 
50680Sstevel@tonic-gate void
ddi_set_next(dev_info_t * dip,dev_info_t * nextdip)50690Sstevel@tonic-gate ddi_set_next(dev_info_t *dip, dev_info_t *nextdip)
50700Sstevel@tonic-gate {
50710Sstevel@tonic-gate 	DEVI(dip)->devi_next = DEVI(nextdip);
50720Sstevel@tonic-gate }
50730Sstevel@tonic-gate 
50740Sstevel@tonic-gate /*
50750Sstevel@tonic-gate  * ddi_root_node:		Return root node of devinfo tree
50760Sstevel@tonic-gate  */
50770Sstevel@tonic-gate 
50780Sstevel@tonic-gate dev_info_t *
ddi_root_node(void)50790Sstevel@tonic-gate ddi_root_node(void)
50800Sstevel@tonic-gate {
50810Sstevel@tonic-gate 	extern dev_info_t *top_devinfo;
50820Sstevel@tonic-gate 
50830Sstevel@tonic-gate 	return (top_devinfo);
50840Sstevel@tonic-gate }
50850Sstevel@tonic-gate 
50860Sstevel@tonic-gate /*
50870Sstevel@tonic-gate  * Miscellaneous functions:
50880Sstevel@tonic-gate  */
50890Sstevel@tonic-gate 
50900Sstevel@tonic-gate /*
50910Sstevel@tonic-gate  * Implementation specific hooks
50920Sstevel@tonic-gate  */
50930Sstevel@tonic-gate 
50940Sstevel@tonic-gate void
ddi_report_dev(dev_info_t * d)50950Sstevel@tonic-gate ddi_report_dev(dev_info_t *d)
50960Sstevel@tonic-gate {
50970Sstevel@tonic-gate 	char *b;
50980Sstevel@tonic-gate 
50990Sstevel@tonic-gate 	(void) ddi_ctlops(d, d, DDI_CTLOPS_REPORTDEV, (void *)0, (void *)0);
51000Sstevel@tonic-gate 
51010Sstevel@tonic-gate 	/*
51020Sstevel@tonic-gate 	 * If this devinfo node has cb_ops, it's implicitly accessible from
51030Sstevel@tonic-gate 	 * userland, so we print its full name together with the instance
51040Sstevel@tonic-gate 	 * number 'abbreviation' that the driver may use internally.
51050Sstevel@tonic-gate 	 */
51060Sstevel@tonic-gate 	if (DEVI(d)->devi_ops->devo_cb_ops != (struct cb_ops *)0 &&
51070Sstevel@tonic-gate 	    (b = kmem_zalloc(MAXPATHLEN, KM_NOSLEEP))) {
51080Sstevel@tonic-gate 		cmn_err(CE_CONT, "?%s%d is %s\n",
51090Sstevel@tonic-gate 		    ddi_driver_name(d), ddi_get_instance(d),
51100Sstevel@tonic-gate 		    ddi_pathname(d, b));
51110Sstevel@tonic-gate 		kmem_free(b, MAXPATHLEN);
51120Sstevel@tonic-gate 	}
51130Sstevel@tonic-gate }
51140Sstevel@tonic-gate 
51150Sstevel@tonic-gate /*
51160Sstevel@tonic-gate  * ddi_ctlops() is described in the assembler not to buy a new register
51170Sstevel@tonic-gate  * window when it's called and can reduce cost in climbing the device tree
51180Sstevel@tonic-gate  * without using the tail call optimization.
51190Sstevel@tonic-gate  */
51200Sstevel@tonic-gate int
ddi_dev_regsize(dev_info_t * dev,uint_t rnumber,off_t * result)51210Sstevel@tonic-gate ddi_dev_regsize(dev_info_t *dev, uint_t rnumber, off_t *result)
51220Sstevel@tonic-gate {
51230Sstevel@tonic-gate 	int ret;
51240Sstevel@tonic-gate 
51250Sstevel@tonic-gate 	ret = ddi_ctlops(dev, dev, DDI_CTLOPS_REGSIZE,
51260Sstevel@tonic-gate 	    (void *)&rnumber, (void *)result);
51270Sstevel@tonic-gate 
51280Sstevel@tonic-gate 	return (ret == DDI_SUCCESS ? DDI_SUCCESS : DDI_FAILURE);
51290Sstevel@tonic-gate }
51300Sstevel@tonic-gate 
51310Sstevel@tonic-gate int
ddi_dev_nregs(dev_info_t * dev,int * result)51320Sstevel@tonic-gate ddi_dev_nregs(dev_info_t *dev, int *result)
51330Sstevel@tonic-gate {
51340Sstevel@tonic-gate 	return (ddi_ctlops(dev, dev, DDI_CTLOPS_NREGS, 0, (void *)result));
51350Sstevel@tonic-gate }
51360Sstevel@tonic-gate 
51370Sstevel@tonic-gate int
ddi_dev_is_sid(dev_info_t * d)51380Sstevel@tonic-gate ddi_dev_is_sid(dev_info_t *d)
51390Sstevel@tonic-gate {
51400Sstevel@tonic-gate 	return (ddi_ctlops(d, d, DDI_CTLOPS_SIDDEV, (void *)0, (void *)0));
51410Sstevel@tonic-gate }
51420Sstevel@tonic-gate 
51430Sstevel@tonic-gate int
ddi_slaveonly(dev_info_t * d)51440Sstevel@tonic-gate ddi_slaveonly(dev_info_t *d)
51450Sstevel@tonic-gate {
51460Sstevel@tonic-gate 	return (ddi_ctlops(d, d, DDI_CTLOPS_SLAVEONLY, (void *)0, (void *)0));
51470Sstevel@tonic-gate }
51480Sstevel@tonic-gate 
51490Sstevel@tonic-gate int
ddi_dev_affinity(dev_info_t * a,dev_info_t * b)51500Sstevel@tonic-gate ddi_dev_affinity(dev_info_t *a, dev_info_t *b)
51510Sstevel@tonic-gate {
51520Sstevel@tonic-gate 	return (ddi_ctlops(a, a, DDI_CTLOPS_AFFINITY, (void *)b, (void *)0));
51530Sstevel@tonic-gate }
51540Sstevel@tonic-gate 
51550Sstevel@tonic-gate int
ddi_streams_driver(dev_info_t * dip)51560Sstevel@tonic-gate ddi_streams_driver(dev_info_t *dip)
51570Sstevel@tonic-gate {
51581333Scth 	if (i_ddi_devi_attached(dip) &&
51590Sstevel@tonic-gate 	    (DEVI(dip)->devi_ops->devo_cb_ops != NULL) &&
51600Sstevel@tonic-gate 	    (DEVI(dip)->devi_ops->devo_cb_ops->cb_str != NULL))
51610Sstevel@tonic-gate 		return (DDI_SUCCESS);
51620Sstevel@tonic-gate 	return (DDI_FAILURE);
51630Sstevel@tonic-gate }
51640Sstevel@tonic-gate 
51650Sstevel@tonic-gate /*
51660Sstevel@tonic-gate  * callback free list
51670Sstevel@tonic-gate  */
51680Sstevel@tonic-gate 
51690Sstevel@tonic-gate static int ncallbacks;
51700Sstevel@tonic-gate static int nc_low = 170;
51710Sstevel@tonic-gate static int nc_med = 512;
51720Sstevel@tonic-gate static int nc_high = 2048;
51730Sstevel@tonic-gate static struct ddi_callback *callbackq;
51740Sstevel@tonic-gate static struct ddi_callback *callbackqfree;
51750Sstevel@tonic-gate 
51760Sstevel@tonic-gate /*
51770Sstevel@tonic-gate  * set/run callback lists
51780Sstevel@tonic-gate  */
51790Sstevel@tonic-gate struct	cbstats	{
51800Sstevel@tonic-gate 	kstat_named_t	cb_asked;
51810Sstevel@tonic-gate 	kstat_named_t	cb_new;
51820Sstevel@tonic-gate 	kstat_named_t	cb_run;
51830Sstevel@tonic-gate 	kstat_named_t	cb_delete;
51840Sstevel@tonic-gate 	kstat_named_t	cb_maxreq;
51850Sstevel@tonic-gate 	kstat_named_t	cb_maxlist;
51860Sstevel@tonic-gate 	kstat_named_t	cb_alloc;
51870Sstevel@tonic-gate 	kstat_named_t	cb_runouts;
51880Sstevel@tonic-gate 	kstat_named_t	cb_L2;
51890Sstevel@tonic-gate 	kstat_named_t	cb_grow;
51900Sstevel@tonic-gate } cbstats = {
51910Sstevel@tonic-gate 	{"asked",	KSTAT_DATA_UINT32},
51920Sstevel@tonic-gate 	{"new",		KSTAT_DATA_UINT32},
51930Sstevel@tonic-gate 	{"run",		KSTAT_DATA_UINT32},
51940Sstevel@tonic-gate 	{"delete",	KSTAT_DATA_UINT32},
51950Sstevel@tonic-gate 	{"maxreq",	KSTAT_DATA_UINT32},
51960Sstevel@tonic-gate 	{"maxlist",	KSTAT_DATA_UINT32},
51970Sstevel@tonic-gate 	{"alloc",	KSTAT_DATA_UINT32},
51980Sstevel@tonic-gate 	{"runouts",	KSTAT_DATA_UINT32},
51990Sstevel@tonic-gate 	{"L2",		KSTAT_DATA_UINT32},
52000Sstevel@tonic-gate 	{"grow",	KSTAT_DATA_UINT32},
52010Sstevel@tonic-gate };
52020Sstevel@tonic-gate 
52030Sstevel@tonic-gate #define	nc_asked	cb_asked.value.ui32
52040Sstevel@tonic-gate #define	nc_new		cb_new.value.ui32
52050Sstevel@tonic-gate #define	nc_run		cb_run.value.ui32
52060Sstevel@tonic-gate #define	nc_delete	cb_delete.value.ui32
52070Sstevel@tonic-gate #define	nc_maxreq	cb_maxreq.value.ui32
52080Sstevel@tonic-gate #define	nc_maxlist	cb_maxlist.value.ui32
52090Sstevel@tonic-gate #define	nc_alloc	cb_alloc.value.ui32
52100Sstevel@tonic-gate #define	nc_runouts	cb_runouts.value.ui32
52110Sstevel@tonic-gate #define	nc_L2		cb_L2.value.ui32
52120Sstevel@tonic-gate #define	nc_grow		cb_grow.value.ui32
52130Sstevel@tonic-gate 
52140Sstevel@tonic-gate static kmutex_t ddi_callback_mutex;
52150Sstevel@tonic-gate 
52160Sstevel@tonic-gate /*
52170Sstevel@tonic-gate  * callbacks are handled using a L1/L2 cache. The L1 cache
52180Sstevel@tonic-gate  * comes out of kmem_cache_alloc and can expand/shrink dynamically. If
52190Sstevel@tonic-gate  * we can't get callbacks from the L1 cache [because pageout is doing
52200Sstevel@tonic-gate  * I/O at the time freemem is 0], we allocate callbacks out of the
52210Sstevel@tonic-gate  * L2 cache. The L2 cache is static and depends on the memory size.
52220Sstevel@tonic-gate  * [We might also count the number of devices at probe time and
52230Sstevel@tonic-gate  * allocate one structure per device and adjust for deferred attach]
52240Sstevel@tonic-gate  */
52250Sstevel@tonic-gate void
impl_ddi_callback_init(void)52260Sstevel@tonic-gate impl_ddi_callback_init(void)
52270Sstevel@tonic-gate {
52280Sstevel@tonic-gate 	int	i;
52290Sstevel@tonic-gate 	uint_t	physmegs;
52300Sstevel@tonic-gate 	kstat_t	*ksp;
52310Sstevel@tonic-gate 
52320Sstevel@tonic-gate 	physmegs = physmem >> (20 - PAGESHIFT);
52330Sstevel@tonic-gate 	if (physmegs < 48) {
52340Sstevel@tonic-gate 		ncallbacks = nc_low;
52350Sstevel@tonic-gate 	} else if (physmegs < 128) {
52360Sstevel@tonic-gate 		ncallbacks = nc_med;
52370Sstevel@tonic-gate 	} else {
52380Sstevel@tonic-gate 		ncallbacks = nc_high;
52390Sstevel@tonic-gate 	}
52400Sstevel@tonic-gate 
52410Sstevel@tonic-gate 	/*
52420Sstevel@tonic-gate 	 * init free list
52430Sstevel@tonic-gate 	 */
52440Sstevel@tonic-gate 	callbackq = kmem_zalloc(
52450Sstevel@tonic-gate 	    ncallbacks * sizeof (struct ddi_callback), KM_SLEEP);
52460Sstevel@tonic-gate 	for (i = 0; i < ncallbacks-1; i++)
52470Sstevel@tonic-gate 		callbackq[i].c_nfree = &callbackq[i+1];
52480Sstevel@tonic-gate 	callbackqfree = callbackq;
52490Sstevel@tonic-gate 
52500Sstevel@tonic-gate 	/* init kstats */
52510Sstevel@tonic-gate 	if (ksp = kstat_create("unix", 0, "cbstats", "misc", KSTAT_TYPE_NAMED,
52520Sstevel@tonic-gate 	    sizeof (cbstats) / sizeof (kstat_named_t), KSTAT_FLAG_VIRTUAL)) {
52530Sstevel@tonic-gate 		ksp->ks_data = (void *) &cbstats;
52540Sstevel@tonic-gate 		kstat_install(ksp);
52550Sstevel@tonic-gate 	}
52560Sstevel@tonic-gate 
52570Sstevel@tonic-gate }
52580Sstevel@tonic-gate 
52590Sstevel@tonic-gate static void
callback_insert(int (* funcp)(caddr_t),caddr_t arg,uintptr_t * listid,int count)52600Sstevel@tonic-gate callback_insert(int (*funcp)(caddr_t), caddr_t arg, uintptr_t *listid,
52610Sstevel@tonic-gate 	int count)
52620Sstevel@tonic-gate {
52630Sstevel@tonic-gate 	struct ddi_callback *list, *marker, *new;
52640Sstevel@tonic-gate 	size_t size = sizeof (struct ddi_callback);
52650Sstevel@tonic-gate 
52660Sstevel@tonic-gate 	list = marker = (struct ddi_callback *)*listid;
52670Sstevel@tonic-gate 	while (list != NULL) {
52680Sstevel@tonic-gate 		if (list->c_call == funcp && list->c_arg == arg) {
52690Sstevel@tonic-gate 			list->c_count += count;
52700Sstevel@tonic-gate 			return;
52710Sstevel@tonic-gate 		}
52720Sstevel@tonic-gate 		marker = list;
52730Sstevel@tonic-gate 		list = list->c_nlist;
52740Sstevel@tonic-gate 	}
52750Sstevel@tonic-gate 	new = kmem_alloc(size, KM_NOSLEEP);
52760Sstevel@tonic-gate 	if (new == NULL) {
52770Sstevel@tonic-gate 		new = callbackqfree;
52780Sstevel@tonic-gate 		if (new == NULL) {
52790Sstevel@tonic-gate 			new = kmem_alloc_tryhard(sizeof (struct ddi_callback),
52800Sstevel@tonic-gate 			    &size, KM_NOSLEEP | KM_PANIC);
52810Sstevel@tonic-gate 			cbstats.nc_grow++;
52820Sstevel@tonic-gate 		} else {
52830Sstevel@tonic-gate 			callbackqfree = new->c_nfree;
52840Sstevel@tonic-gate 			cbstats.nc_L2++;
52850Sstevel@tonic-gate 		}
52860Sstevel@tonic-gate 	}
52870Sstevel@tonic-gate 	if (marker != NULL) {
52880Sstevel@tonic-gate 		marker->c_nlist = new;
52890Sstevel@tonic-gate 	} else {
52900Sstevel@tonic-gate 		*listid = (uintptr_t)new;
52910Sstevel@tonic-gate 	}
52920Sstevel@tonic-gate 	new->c_size = size;
52930Sstevel@tonic-gate 	new->c_nlist = NULL;
52940Sstevel@tonic-gate 	new->c_call = funcp;
52950Sstevel@tonic-gate 	new->c_arg = arg;
52960Sstevel@tonic-gate 	new->c_count = count;
52970Sstevel@tonic-gate 	cbstats.nc_new++;
52980Sstevel@tonic-gate 	cbstats.nc_alloc++;
52990Sstevel@tonic-gate 	if (cbstats.nc_alloc > cbstats.nc_maxlist)
53000Sstevel@tonic-gate 		cbstats.nc_maxlist = cbstats.nc_alloc;
53010Sstevel@tonic-gate }
53020Sstevel@tonic-gate 
53030Sstevel@tonic-gate void
ddi_set_callback(int (* funcp)(caddr_t),caddr_t arg,uintptr_t * listid)53040Sstevel@tonic-gate ddi_set_callback(int (*funcp)(caddr_t), caddr_t arg, uintptr_t *listid)
53050Sstevel@tonic-gate {
53060Sstevel@tonic-gate 	mutex_enter(&ddi_callback_mutex);
53070Sstevel@tonic-gate 	cbstats.nc_asked++;
53080Sstevel@tonic-gate 	if ((cbstats.nc_asked - cbstats.nc_run) > cbstats.nc_maxreq)
53090Sstevel@tonic-gate 		cbstats.nc_maxreq = (cbstats.nc_asked - cbstats.nc_run);
53100Sstevel@tonic-gate 	(void) callback_insert(funcp, arg, listid, 1);
53110Sstevel@tonic-gate 	mutex_exit(&ddi_callback_mutex);
53120Sstevel@tonic-gate }
53130Sstevel@tonic-gate 
53140Sstevel@tonic-gate static void
real_callback_run(void * Queue)53150Sstevel@tonic-gate real_callback_run(void *Queue)
53160Sstevel@tonic-gate {
53170Sstevel@tonic-gate 	int (*funcp)(caddr_t);
53180Sstevel@tonic-gate 	caddr_t arg;
53190Sstevel@tonic-gate 	int count, rval;
53200Sstevel@tonic-gate 	uintptr_t *listid;
53210Sstevel@tonic-gate 	struct ddi_callback *list, *marker;
53220Sstevel@tonic-gate 	int check_pending = 1;
53230Sstevel@tonic-gate 	int pending = 0;
53240Sstevel@tonic-gate 
53250Sstevel@tonic-gate 	do {
53260Sstevel@tonic-gate 		mutex_enter(&ddi_callback_mutex);
53270Sstevel@tonic-gate 		listid = Queue;
53280Sstevel@tonic-gate 		list = (struct ddi_callback *)*listid;
53290Sstevel@tonic-gate 		if (list == NULL) {
53300Sstevel@tonic-gate 			mutex_exit(&ddi_callback_mutex);
53310Sstevel@tonic-gate 			return;
53320Sstevel@tonic-gate 		}
53330Sstevel@tonic-gate 		if (check_pending) {
53340Sstevel@tonic-gate 			marker = list;
53350Sstevel@tonic-gate 			while (marker != NULL) {
53360Sstevel@tonic-gate 				pending += marker->c_count;
53370Sstevel@tonic-gate 				marker = marker->c_nlist;
53380Sstevel@tonic-gate 			}
53390Sstevel@tonic-gate 			check_pending = 0;
53400Sstevel@tonic-gate 		}
53410Sstevel@tonic-gate 		ASSERT(pending > 0);
53420Sstevel@tonic-gate 		ASSERT(list->c_count > 0);
53430Sstevel@tonic-gate 		funcp = list->c_call;
53440Sstevel@tonic-gate 		arg = list->c_arg;
53450Sstevel@tonic-gate 		count = list->c_count;
53460Sstevel@tonic-gate 		*(uintptr_t *)Queue = (uintptr_t)list->c_nlist;
53470Sstevel@tonic-gate 		if (list >= &callbackq[0] &&
53480Sstevel@tonic-gate 		    list <= &callbackq[ncallbacks-1]) {
53490Sstevel@tonic-gate 			list->c_nfree = callbackqfree;
53500Sstevel@tonic-gate 			callbackqfree = list;
53510Sstevel@tonic-gate 		} else
53520Sstevel@tonic-gate 			kmem_free(list, list->c_size);
53530Sstevel@tonic-gate 
53540Sstevel@tonic-gate 		cbstats.nc_delete++;
53550Sstevel@tonic-gate 		cbstats.nc_alloc--;
53560Sstevel@tonic-gate 		mutex_exit(&ddi_callback_mutex);
53570Sstevel@tonic-gate 
53580Sstevel@tonic-gate 		do {
53590Sstevel@tonic-gate 			if ((rval = (*funcp)(arg)) == 0) {
53600Sstevel@tonic-gate 				pending -= count;
53610Sstevel@tonic-gate 				mutex_enter(&ddi_callback_mutex);
53620Sstevel@tonic-gate 				(void) callback_insert(funcp, arg, listid,
53634582Scth 				    count);
53640Sstevel@tonic-gate 				cbstats.nc_runouts++;
53650Sstevel@tonic-gate 			} else {
53660Sstevel@tonic-gate 				pending--;
53670Sstevel@tonic-gate 				mutex_enter(&ddi_callback_mutex);
53680Sstevel@tonic-gate 				cbstats.nc_run++;
53690Sstevel@tonic-gate 			}
53700Sstevel@tonic-gate 			mutex_exit(&ddi_callback_mutex);
53710Sstevel@tonic-gate 		} while (rval != 0 && (--count > 0));
53720Sstevel@tonic-gate 	} while (pending > 0);
53730Sstevel@tonic-gate }
53740Sstevel@tonic-gate 
53750Sstevel@tonic-gate void
ddi_run_callback(uintptr_t * listid)53760Sstevel@tonic-gate ddi_run_callback(uintptr_t *listid)
53770Sstevel@tonic-gate {
53780Sstevel@tonic-gate 	softcall(real_callback_run, listid);
53790Sstevel@tonic-gate }
53800Sstevel@tonic-gate 
53815107Seota /*
53825107Seota  * ddi_periodic_t
53835107Seota  * ddi_periodic_add(void (*func)(void *), void *arg, hrtime_t interval,
53845107Seota  *     int level)
53855107Seota  *
53865107Seota  * INTERFACE LEVEL
53875107Seota  *      Solaris DDI specific (Solaris DDI)
53885107Seota  *
53895107Seota  * PARAMETERS
53905107Seota  *      func: the callback function
53915107Seota  *
53925107Seota  *            The callback function will be invoked. The function is invoked
53935107Seota  *            in kernel context if the argument level passed is the zero.
53945107Seota  *            Otherwise it's invoked in interrupt context at the specified
53955107Seota  *            level.
53965107Seota  *
53975107Seota  *       arg: the argument passed to the callback function
53985107Seota  *
53995107Seota  *  interval: interval time
54005107Seota  *
54015107Seota  *    level : callback interrupt level
54025107Seota  *
54035107Seota  *            If the value is the zero, the callback function is invoked
54045107Seota  *            in kernel context. If the value is more than the zero, but
54055107Seota  *            less than or equal to ten, the callback function is invoked in
54065107Seota  *            interrupt context at the specified interrupt level, which may
54075107Seota  *            be used for real time applications.
54085107Seota  *
54095107Seota  *            This value must be in range of 0-10, which can be a numeric
54105107Seota  *            number or a pre-defined macro (DDI_IPL_0, ... , DDI_IPL_10).
54115107Seota  *
54125107Seota  * DESCRIPTION
54135107Seota  *      ddi_periodic_add(9F) schedules the specified function to be
54145107Seota  *      periodically invoked in the interval time.
54155107Seota  *
54165107Seota  *      As well as timeout(9F), the exact time interval over which the function
54175107Seota  *      takes effect cannot be guaranteed, but the value given is a close
54185107Seota  *      approximation.
54195107Seota  *
54205107Seota  *      Drivers waiting on behalf of processes with real-time constraints must
54215107Seota  *      pass non-zero value with the level argument to ddi_periodic_add(9F).
54225107Seota  *
54235107Seota  * RETURN VALUES
54245107Seota  *      ddi_periodic_add(9F) returns a non-zero opaque value (ddi_periodic_t),
54255107Seota  *      which must be used for ddi_periodic_delete(9F) to specify the request.
54265107Seota  *
54275107Seota  * CONTEXT
54285107Seota  *      ddi_periodic_add(9F) can be called in user or kernel context, but
54295107Seota  *      it cannot be called in interrupt context, which is different from
54305107Seota  *      timeout(9F).
54315107Seota  */
54325107Seota ddi_periodic_t
ddi_periodic_add(void (* func)(void *),void * arg,hrtime_t interval,int level)54335107Seota ddi_periodic_add(void (*func)(void *), void *arg, hrtime_t interval, int level)
54345107Seota {
54355107Seota 	/*
54365107Seota 	 * Sanity check of the argument level.
54375107Seota 	 */
54385107Seota 	if (level < DDI_IPL_0 || level > DDI_IPL_10)
54395107Seota 		cmn_err(CE_PANIC,
54405107Seota 		    "ddi_periodic_add: invalid interrupt level (%d).", level);
54415107Seota 
54425107Seota 	/*
54435107Seota 	 * Sanity check of the context. ddi_periodic_add() cannot be
54445107Seota 	 * called in either interrupt context or high interrupt context.
54455107Seota 	 */
54465107Seota 	if (servicing_interrupt())
54475107Seota 		cmn_err(CE_PANIC,
54485107Seota 		    "ddi_periodic_add: called in (high) interrupt context.");
54495107Seota 
54505107Seota 	return ((ddi_periodic_t)i_timeout(func, arg, interval, level));
54515107Seota }
54525107Seota 
54535107Seota /*
54545107Seota  * void
54555107Seota  * ddi_periodic_delete(ddi_periodic_t req)
54565107Seota  *
54575107Seota  * INTERFACE LEVEL
54585107Seota  *     Solaris DDI specific (Solaris DDI)
54595107Seota  *
54605107Seota  * PARAMETERS
54615107Seota  *     req: ddi_periodic_t opaque value ddi_periodic_add(9F) returned
54625107Seota  *     previously.
54635107Seota  *
54645107Seota  * DESCRIPTION
54655107Seota  *     ddi_periodic_delete(9F) cancels the ddi_periodic_add(9F) request
54665107Seota  *     previously requested.
54675107Seota  *
54685107Seota  *     ddi_periodic_delete(9F) will not return until the pending request
54695107Seota  *     is canceled or executed.
54705107Seota  *
54715107Seota  *     As well as untimeout(9F), calling ddi_periodic_delete(9F) for a
54725107Seota  *     timeout which is either running on another CPU, or has already
54735107Seota  *     completed causes no problems. However, unlike untimeout(9F), there is
54745107Seota  *     no restrictions on the lock which might be held across the call to
54755107Seota  *     ddi_periodic_delete(9F).
54765107Seota  *
54775107Seota  *     Drivers should be structured with the understanding that the arrival of
54785107Seota  *     both an interrupt and a timeout for that interrupt can occasionally
54795107Seota  *     occur, in either order.
54805107Seota  *
54815107Seota  * CONTEXT
54825107Seota  *     ddi_periodic_delete(9F) can be called in user or kernel context, but
54835107Seota  *     it cannot be called in interrupt context, which is different from
54845107Seota  *     untimeout(9F).
54855107Seota  */
54865107Seota void
ddi_periodic_delete(ddi_periodic_t req)54875107Seota ddi_periodic_delete(ddi_periodic_t req)
54885107Seota {
54895107Seota 	/*
54905107Seota 	 * Sanity check of the context. ddi_periodic_delete() cannot be
54915107Seota 	 * called in either interrupt context or high interrupt context.
54925107Seota 	 */
54935107Seota 	if (servicing_interrupt())
54945107Seota 		cmn_err(CE_PANIC,
54955107Seota 		    "ddi_periodic_delete: called in (high) interrupt context.");
54965107Seota 
54975107Seota 	i_untimeout((timeout_t)req);
54985107Seota }
54995107Seota 
55000Sstevel@tonic-gate dev_info_t *
nodevinfo(dev_t dev,int otyp)55010Sstevel@tonic-gate nodevinfo(dev_t dev, int otyp)
55020Sstevel@tonic-gate {
55030Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dev, otyp))
55040Sstevel@tonic-gate 	return ((dev_info_t *)0);
55050Sstevel@tonic-gate }
55060Sstevel@tonic-gate 
55070Sstevel@tonic-gate /*
55080Sstevel@tonic-gate  * A driver should support its own getinfo(9E) entry point. This function
55090Sstevel@tonic-gate  * is provided as a convenience for ON drivers that don't expect their
55100Sstevel@tonic-gate  * getinfo(9E) entry point to be called. A driver that uses this must not
55110Sstevel@tonic-gate  * call ddi_create_minor_node.
55120Sstevel@tonic-gate  */
55130Sstevel@tonic-gate int
ddi_no_info(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)55140Sstevel@tonic-gate ddi_no_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
55150Sstevel@tonic-gate {
55160Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, infocmd, arg, result))
55170Sstevel@tonic-gate 	return (DDI_FAILURE);
55180Sstevel@tonic-gate }
55190Sstevel@tonic-gate 
55200Sstevel@tonic-gate /*
55210Sstevel@tonic-gate  * A driver should support its own getinfo(9E) entry point. This function
55220Sstevel@tonic-gate  * is provided as a convenience for ON drivers that where the minor number
55230Sstevel@tonic-gate  * is the instance. Drivers that do not have 1:1 mapping must implement
55240Sstevel@tonic-gate  * their own getinfo(9E) function.
55250Sstevel@tonic-gate  */
55260Sstevel@tonic-gate int
ddi_getinfo_1to1(dev_info_t * dip,ddi_info_cmd_t infocmd,void * arg,void ** result)55270Sstevel@tonic-gate ddi_getinfo_1to1(dev_info_t *dip, ddi_info_cmd_t infocmd,
55280Sstevel@tonic-gate     void *arg, void **result)
55290Sstevel@tonic-gate {
55300Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip))
55310Sstevel@tonic-gate 	int	instance;
55320Sstevel@tonic-gate 
55330Sstevel@tonic-gate 	if (infocmd != DDI_INFO_DEVT2INSTANCE)
55340Sstevel@tonic-gate 		return (DDI_FAILURE);
55350Sstevel@tonic-gate 
55360Sstevel@tonic-gate 	instance = getminor((dev_t)(uintptr_t)arg);
55370Sstevel@tonic-gate 	*result = (void *)(uintptr_t)instance;
55380Sstevel@tonic-gate 	return (DDI_SUCCESS);
55390Sstevel@tonic-gate }
55400Sstevel@tonic-gate 
55410Sstevel@tonic-gate int
ddifail(dev_info_t * devi,ddi_attach_cmd_t cmd)55420Sstevel@tonic-gate ddifail(dev_info_t *devi, ddi_attach_cmd_t cmd)
55430Sstevel@tonic-gate {
55440Sstevel@tonic-gate 	_NOTE(ARGUNUSED(devi, cmd))
55450Sstevel@tonic-gate 	return (DDI_FAILURE);
55460Sstevel@tonic-gate }
55470Sstevel@tonic-gate 
55480Sstevel@tonic-gate int
ddi_no_dma_map(dev_info_t * dip,dev_info_t * rdip,struct ddi_dma_req * dmareqp,ddi_dma_handle_t * handlep)55490Sstevel@tonic-gate ddi_no_dma_map(dev_info_t *dip, dev_info_t *rdip,
55500Sstevel@tonic-gate     struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
55510Sstevel@tonic-gate {
55520Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, dmareqp, handlep))
55530Sstevel@tonic-gate 	return (DDI_DMA_NOMAPPING);
55540Sstevel@tonic-gate }
55550Sstevel@tonic-gate 
55560Sstevel@tonic-gate int
ddi_no_dma_allochdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_attr_t * attr,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_handle_t * handlep)55570Sstevel@tonic-gate ddi_no_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
55580Sstevel@tonic-gate     int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
55590Sstevel@tonic-gate {
55600Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, attr, waitfp, arg, handlep))
55610Sstevel@tonic-gate 	return (DDI_DMA_BADATTR);
55620Sstevel@tonic-gate }
55630Sstevel@tonic-gate 
55640Sstevel@tonic-gate int
ddi_no_dma_freehdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)55650Sstevel@tonic-gate ddi_no_dma_freehdl(dev_info_t *dip, dev_info_t *rdip,
55660Sstevel@tonic-gate     ddi_dma_handle_t handle)
55670Sstevel@tonic-gate {
55680Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, handle))
55690Sstevel@tonic-gate 	return (DDI_FAILURE);
55700Sstevel@tonic-gate }
55710Sstevel@tonic-gate 
55720Sstevel@tonic-gate int
ddi_no_dma_bindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,struct ddi_dma_req * dmareq,ddi_dma_cookie_t * cp,uint_t * ccountp)55730Sstevel@tonic-gate ddi_no_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
55740Sstevel@tonic-gate     ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
55750Sstevel@tonic-gate     ddi_dma_cookie_t *cp, uint_t *ccountp)
55760Sstevel@tonic-gate {
55770Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, handle, dmareq, cp, ccountp))
55780Sstevel@tonic-gate 	return (DDI_DMA_NOMAPPING);
55790Sstevel@tonic-gate }
55800Sstevel@tonic-gate 
55810Sstevel@tonic-gate int
ddi_no_dma_unbindhdl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle)55820Sstevel@tonic-gate ddi_no_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
55830Sstevel@tonic-gate     ddi_dma_handle_t handle)
55840Sstevel@tonic-gate {
55850Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, handle))
55860Sstevel@tonic-gate 	return (DDI_FAILURE);
55870Sstevel@tonic-gate }
55880Sstevel@tonic-gate 
55890Sstevel@tonic-gate int
ddi_no_dma_flush(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,off_t off,size_t len,uint_t cache_flags)55900Sstevel@tonic-gate ddi_no_dma_flush(dev_info_t *dip, dev_info_t *rdip,
55910Sstevel@tonic-gate     ddi_dma_handle_t handle, off_t off, size_t len,
55920Sstevel@tonic-gate     uint_t cache_flags)
55930Sstevel@tonic-gate {
55940Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, handle, off, len, cache_flags))
55950Sstevel@tonic-gate 	return (DDI_FAILURE);
55960Sstevel@tonic-gate }
55970Sstevel@tonic-gate 
55980Sstevel@tonic-gate int
ddi_no_dma_win(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,uint_t win,off_t * offp,size_t * lenp,ddi_dma_cookie_t * cookiep,uint_t * ccountp)55990Sstevel@tonic-gate ddi_no_dma_win(dev_info_t *dip, dev_info_t *rdip,
56000Sstevel@tonic-gate     ddi_dma_handle_t handle, uint_t win, off_t *offp,
56010Sstevel@tonic-gate     size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
56020Sstevel@tonic-gate {
56030Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, handle, win, offp, lenp, cookiep, ccountp))
56040Sstevel@tonic-gate 	return (DDI_FAILURE);
56050Sstevel@tonic-gate }
56060Sstevel@tonic-gate 
56070Sstevel@tonic-gate int
ddi_no_dma_mctl(dev_info_t * dip,dev_info_t * rdip,ddi_dma_handle_t handle,enum ddi_dma_ctlops request,off_t * offp,size_t * lenp,caddr_t * objp,uint_t flags)56080Sstevel@tonic-gate ddi_no_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
56090Sstevel@tonic-gate     ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
56100Sstevel@tonic-gate     off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags)
56110Sstevel@tonic-gate {
56120Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dip, rdip, handle, request, offp, lenp, objp, flags))
56130Sstevel@tonic-gate 	return (DDI_FAILURE);
56140Sstevel@tonic-gate }
56150Sstevel@tonic-gate 
56160Sstevel@tonic-gate void
ddivoid(void)56170Sstevel@tonic-gate ddivoid(void)
56180Sstevel@tonic-gate {}
56190Sstevel@tonic-gate 
56200Sstevel@tonic-gate int
nochpoll(dev_t dev,short events,int anyyet,short * reventsp,struct pollhead ** pollhdrp)56210Sstevel@tonic-gate nochpoll(dev_t dev, short events, int anyyet, short *reventsp,
56220Sstevel@tonic-gate     struct pollhead **pollhdrp)
56230Sstevel@tonic-gate {
56240Sstevel@tonic-gate 	_NOTE(ARGUNUSED(dev, events, anyyet, reventsp, pollhdrp))
56250Sstevel@tonic-gate 	return (ENXIO);
56260Sstevel@tonic-gate }
56270Sstevel@tonic-gate 
56280Sstevel@tonic-gate cred_t *
ddi_get_cred(void)56290Sstevel@tonic-gate ddi_get_cred(void)
56300Sstevel@tonic-gate {
56310Sstevel@tonic-gate 	return (CRED());
56320Sstevel@tonic-gate }
56330Sstevel@tonic-gate 
56340Sstevel@tonic-gate clock_t
ddi_get_lbolt(void)56350Sstevel@tonic-gate ddi_get_lbolt(void)
56360Sstevel@tonic-gate {
563711066Srafael.vanoni@sun.com 	return ((clock_t)lbolt_hybrid());
563811066Srafael.vanoni@sun.com }
563911066Srafael.vanoni@sun.com 
564011066Srafael.vanoni@sun.com int64_t
ddi_get_lbolt64(void)564111066Srafael.vanoni@sun.com ddi_get_lbolt64(void)
564211066Srafael.vanoni@sun.com {
564311066Srafael.vanoni@sun.com 	return (lbolt_hybrid());
56440Sstevel@tonic-gate }
56450Sstevel@tonic-gate 
56460Sstevel@tonic-gate time_t
ddi_get_time(void)56470Sstevel@tonic-gate ddi_get_time(void)
56480Sstevel@tonic-gate {
56490Sstevel@tonic-gate 	time_t	now;
56500Sstevel@tonic-gate 
56510Sstevel@tonic-gate 	if ((now = gethrestime_sec()) == 0) {
56520Sstevel@tonic-gate 		timestruc_t ts;
56530Sstevel@tonic-gate 		mutex_enter(&tod_lock);
56540Sstevel@tonic-gate 		ts = tod_get();
56550Sstevel@tonic-gate 		mutex_exit(&tod_lock);
56560Sstevel@tonic-gate 		return (ts.tv_sec);
56570Sstevel@tonic-gate 	} else {
56580Sstevel@tonic-gate 		return (now);
56590Sstevel@tonic-gate 	}
56600Sstevel@tonic-gate }
56610Sstevel@tonic-gate 
56620Sstevel@tonic-gate pid_t
ddi_get_pid(void)56630Sstevel@tonic-gate ddi_get_pid(void)
56640Sstevel@tonic-gate {
56650Sstevel@tonic-gate 	return (ttoproc(curthread)->p_pid);
56660Sstevel@tonic-gate }
56670Sstevel@tonic-gate 
56680Sstevel@tonic-gate kt_did_t
ddi_get_kt_did(void)56690Sstevel@tonic-gate ddi_get_kt_did(void)
56700Sstevel@tonic-gate {
56710Sstevel@tonic-gate 	return (curthread->t_did);
56720Sstevel@tonic-gate }
56730Sstevel@tonic-gate 
56740Sstevel@tonic-gate /*
56750Sstevel@tonic-gate  * This function returns B_TRUE if the caller can reasonably expect that a call
56760Sstevel@tonic-gate  * to cv_wait_sig(9F), cv_timedwait_sig(9F), or qwait_sig(9F) could be awakened
56770Sstevel@tonic-gate  * by user-level signal.  If it returns B_FALSE, then the caller should use
56780Sstevel@tonic-gate  * other means to make certain that the wait will not hang "forever."
56790Sstevel@tonic-gate  *
56800Sstevel@tonic-gate  * It does not check the signal mask, nor for reception of any particular
56810Sstevel@tonic-gate  * signal.
56820Sstevel@tonic-gate  *
56830Sstevel@tonic-gate  * Currently, a thread can receive a signal if it's not a kernel thread and it
56840Sstevel@tonic-gate  * is not in the middle of exit(2) tear-down.  Threads that are in that
56850Sstevel@tonic-gate  * tear-down effectively convert cv_wait_sig to cv_wait, cv_timedwait_sig to
56860Sstevel@tonic-gate  * cv_timedwait, and qwait_sig to qwait.
56870Sstevel@tonic-gate  */
56880Sstevel@tonic-gate boolean_t
ddi_can_receive_sig(void)56890Sstevel@tonic-gate ddi_can_receive_sig(void)
56900Sstevel@tonic-gate {
56910Sstevel@tonic-gate 	proc_t *pp;
56920Sstevel@tonic-gate 
56930Sstevel@tonic-gate 	if (curthread->t_proc_flag & TP_LWPEXIT)
56940Sstevel@tonic-gate 		return (B_FALSE);
56950Sstevel@tonic-gate 	if ((pp = ttoproc(curthread)) == NULL)
56960Sstevel@tonic-gate 		return (B_FALSE);
56970Sstevel@tonic-gate 	return (pp->p_as != &kas);
56980Sstevel@tonic-gate }
56990Sstevel@tonic-gate 
57000Sstevel@tonic-gate /*
57010Sstevel@tonic-gate  * Swap bytes in 16-bit [half-]words
57020Sstevel@tonic-gate  */
57030Sstevel@tonic-gate void
swab(void * src,void * dst,size_t nbytes)57040Sstevel@tonic-gate swab(void *src, void *dst, size_t nbytes)
57050Sstevel@tonic-gate {
57060Sstevel@tonic-gate 	uchar_t *pf = (uchar_t *)src;
57070Sstevel@tonic-gate 	uchar_t *pt = (uchar_t *)dst;
57080Sstevel@tonic-gate 	uchar_t tmp;
57090Sstevel@tonic-gate 	int nshorts;
57100Sstevel@tonic-gate 
57110Sstevel@tonic-gate 	nshorts = nbytes >> 1;
57120Sstevel@tonic-gate 
57130Sstevel@tonic-gate 	while (--nshorts >= 0) {
57140Sstevel@tonic-gate 		tmp = *pf++;
57150Sstevel@tonic-gate 		*pt++ = *pf++;
57160Sstevel@tonic-gate 		*pt++ = tmp;
57170Sstevel@tonic-gate 	}
57180Sstevel@tonic-gate }
57190Sstevel@tonic-gate 
57200Sstevel@tonic-gate static void
ddi_append_minor_node(dev_info_t * ddip,struct ddi_minor_data * dmdp)57210Sstevel@tonic-gate ddi_append_minor_node(dev_info_t *ddip, struct ddi_minor_data *dmdp)
57220Sstevel@tonic-gate {
57237224Scth 	int			circ;
57247224Scth 	struct ddi_minor_data	*dp;
57257224Scth 
57267224Scth 	ndi_devi_enter(ddip, &circ);
57270Sstevel@tonic-gate 	if ((dp = DEVI(ddip)->devi_minor) == (struct ddi_minor_data *)NULL) {
57280Sstevel@tonic-gate 		DEVI(ddip)->devi_minor = dmdp;
57290Sstevel@tonic-gate 	} else {
57300Sstevel@tonic-gate 		while (dp->next != (struct ddi_minor_data *)NULL)
57310Sstevel@tonic-gate 			dp = dp->next;
57320Sstevel@tonic-gate 		dp->next = dmdp;
57330Sstevel@tonic-gate 	}
57347224Scth 	ndi_devi_exit(ddip, circ);
57350Sstevel@tonic-gate }
57360Sstevel@tonic-gate 
57370Sstevel@tonic-gate /*
57380Sstevel@tonic-gate  * Part of the obsolete SunCluster DDI Hooks.
57390Sstevel@tonic-gate  * Keep for binary compatibility
57400Sstevel@tonic-gate  */
57410Sstevel@tonic-gate minor_t
ddi_getiminor(dev_t dev)57420Sstevel@tonic-gate ddi_getiminor(dev_t dev)
57430Sstevel@tonic-gate {
57440Sstevel@tonic-gate 	return (getminor(dev));
57450Sstevel@tonic-gate }
57460Sstevel@tonic-gate 
57470Sstevel@tonic-gate static int
i_log_devfs_minor_create(dev_info_t * dip,char * minor_name)57480Sstevel@tonic-gate i_log_devfs_minor_create(dev_info_t *dip, char *minor_name)
57490Sstevel@tonic-gate {
57500Sstevel@tonic-gate 	int se_flag;
57510Sstevel@tonic-gate 	int kmem_flag;
57520Sstevel@tonic-gate 	int se_err;
57534211Sphitran 	char *pathname, *class_name;
57540Sstevel@tonic-gate 	sysevent_t *ev = NULL;
57550Sstevel@tonic-gate 	sysevent_id_t eid;
57560Sstevel@tonic-gate 	sysevent_value_t se_val;
57570Sstevel@tonic-gate 	sysevent_attr_list_t *ev_attr_list = NULL;
57580Sstevel@tonic-gate 
57590Sstevel@tonic-gate 	/* determine interrupt context */
57600Sstevel@tonic-gate 	se_flag = (servicing_interrupt()) ? SE_NOSLEEP : SE_SLEEP;
57610Sstevel@tonic-gate 	kmem_flag = (se_flag == SE_SLEEP) ? KM_SLEEP : KM_NOSLEEP;
57620Sstevel@tonic-gate 
576310696SDavid.Hollister@Sun.COM 	i_ddi_di_cache_invalidate();
57640Sstevel@tonic-gate 
57650Sstevel@tonic-gate #ifdef DEBUG
57660Sstevel@tonic-gate 	if ((se_flag == SE_NOSLEEP) && sunddi_debug) {
57670Sstevel@tonic-gate 		cmn_err(CE_CONT, "ddi_create_minor_node: called from "
57680Sstevel@tonic-gate 		    "interrupt level by driver %s",
57690Sstevel@tonic-gate 		    ddi_driver_name(dip));
57700Sstevel@tonic-gate 	}
57710Sstevel@tonic-gate #endif /* DEBUG */
57720Sstevel@tonic-gate 
57730Sstevel@tonic-gate 	ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_MINOR_CREATE, EP_DDI, se_flag);
57740Sstevel@tonic-gate 	if (ev == NULL) {
57750Sstevel@tonic-gate 		goto fail;
57760Sstevel@tonic-gate 	}
57770Sstevel@tonic-gate 
57780Sstevel@tonic-gate 	pathname = kmem_alloc(MAXPATHLEN, kmem_flag);
57790Sstevel@tonic-gate 	if (pathname == NULL) {
57800Sstevel@tonic-gate 		sysevent_free(ev);
57810Sstevel@tonic-gate 		goto fail;
57820Sstevel@tonic-gate 	}
57830Sstevel@tonic-gate 
57840Sstevel@tonic-gate 	(void) ddi_pathname(dip, pathname);
57850Sstevel@tonic-gate 	ASSERT(strlen(pathname));
57860Sstevel@tonic-gate 	se_val.value_type = SE_DATA_TYPE_STRING;
57870Sstevel@tonic-gate 	se_val.value.sv_string = pathname;
57880Sstevel@tonic-gate 	if (sysevent_add_attr(&ev_attr_list, DEVFS_PATHNAME,
57890Sstevel@tonic-gate 	    &se_val, se_flag) != 0) {
57900Sstevel@tonic-gate 		kmem_free(pathname, MAXPATHLEN);
57910Sstevel@tonic-gate 		sysevent_free(ev);
57920Sstevel@tonic-gate 		goto fail;
57930Sstevel@tonic-gate 	}
57940Sstevel@tonic-gate 	kmem_free(pathname, MAXPATHLEN);
57950Sstevel@tonic-gate 
57964211Sphitran 	/* add the device class attribute */
57974211Sphitran 	if ((class_name = i_ddi_devi_class(dip)) != NULL) {
57984211Sphitran 		se_val.value_type = SE_DATA_TYPE_STRING;
57994211Sphitran 		se_val.value.sv_string = class_name;
58004211Sphitran 		if (sysevent_add_attr(&ev_attr_list,
58014211Sphitran 		    DEVFS_DEVI_CLASS, &se_val, SE_SLEEP) != 0) {
58024211Sphitran 			sysevent_free_attr(ev_attr_list);
58034211Sphitran 			goto fail;
58044211Sphitran 		}
58054211Sphitran 	}
58064211Sphitran 
58070Sstevel@tonic-gate 	/*
58080Sstevel@tonic-gate 	 * allow for NULL minor names
58090Sstevel@tonic-gate 	 */
58100Sstevel@tonic-gate 	if (minor_name != NULL) {
58110Sstevel@tonic-gate 		se_val.value.sv_string = minor_name;
58120Sstevel@tonic-gate 		if (sysevent_add_attr(&ev_attr_list, DEVFS_MINOR_NAME,
58130Sstevel@tonic-gate 		    &se_val, se_flag) != 0) {
58140Sstevel@tonic-gate 			sysevent_free_attr(ev_attr_list);
58150Sstevel@tonic-gate 			sysevent_free(ev);
58160Sstevel@tonic-gate 			goto fail;
58170Sstevel@tonic-gate 		}
58180Sstevel@tonic-gate 	}
58190Sstevel@tonic-gate 
58200Sstevel@tonic-gate 	if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
58210Sstevel@tonic-gate 		sysevent_free_attr(ev_attr_list);
58220Sstevel@tonic-gate 		sysevent_free(ev);
58230Sstevel@tonic-gate 		goto fail;
58240Sstevel@tonic-gate 	}
58250Sstevel@tonic-gate 
58260Sstevel@tonic-gate 	if ((se_err = log_sysevent(ev, se_flag, &eid)) != 0) {
58270Sstevel@tonic-gate 		if (se_err == SE_NO_TRANSPORT) {
58280Sstevel@tonic-gate 			cmn_err(CE_WARN, "/devices or /dev may not be current "
58290Sstevel@tonic-gate 			    "for driver %s (%s). Run devfsadm -i %s",
58300Sstevel@tonic-gate 			    ddi_driver_name(dip), "syseventd not responding",
58310Sstevel@tonic-gate 			    ddi_driver_name(dip));
58320Sstevel@tonic-gate 		} else {
58330Sstevel@tonic-gate 			sysevent_free(ev);
58340Sstevel@tonic-gate 			goto fail;
58350Sstevel@tonic-gate 		}
58360Sstevel@tonic-gate 	}
58370Sstevel@tonic-gate 
58380Sstevel@tonic-gate 	sysevent_free(ev);
58390Sstevel@tonic-gate 	return (DDI_SUCCESS);
58400Sstevel@tonic-gate fail:
58410Sstevel@tonic-gate 	cmn_err(CE_WARN, "/devices or /dev may not be current "
58420Sstevel@tonic-gate 	    "for driver %s. Run devfsadm -i %s",
58430Sstevel@tonic-gate 	    ddi_driver_name(dip), ddi_driver_name(dip));
58440Sstevel@tonic-gate 	return (DDI_SUCCESS);
58450Sstevel@tonic-gate }
58460Sstevel@tonic-gate 
58470Sstevel@tonic-gate /*
58480Sstevel@tonic-gate  * failing to remove a minor node is not of interest
58490Sstevel@tonic-gate  * therefore we do not generate an error message
58500Sstevel@tonic-gate  */
58510Sstevel@tonic-gate static int
i_log_devfs_minor_remove(dev_info_t * dip,char * minor_name)58520Sstevel@tonic-gate i_log_devfs_minor_remove(dev_info_t *dip, char *minor_name)
58530Sstevel@tonic-gate {
58544211Sphitran 	char *pathname, *class_name;
58550Sstevel@tonic-gate 	sysevent_t *ev;
58560Sstevel@tonic-gate 	sysevent_id_t eid;
58570Sstevel@tonic-gate 	sysevent_value_t se_val;
58580Sstevel@tonic-gate 	sysevent_attr_list_t *ev_attr_list = NULL;
58590Sstevel@tonic-gate 
58600Sstevel@tonic-gate 	/*
58610Sstevel@tonic-gate 	 * only log ddi_remove_minor_node() calls outside the scope
58620Sstevel@tonic-gate 	 * of attach/detach reconfigurations and when the dip is
58630Sstevel@tonic-gate 	 * still initialized.
58640Sstevel@tonic-gate 	 */
58650Sstevel@tonic-gate 	if (DEVI_IS_ATTACHING(dip) || DEVI_IS_DETACHING(dip) ||
58660Sstevel@tonic-gate 	    (i_ddi_node_state(dip) < DS_INITIALIZED)) {
58670Sstevel@tonic-gate 		return (DDI_SUCCESS);
58680Sstevel@tonic-gate 	}
58690Sstevel@tonic-gate 
587010696SDavid.Hollister@Sun.COM 	i_ddi_di_cache_invalidate();
58710Sstevel@tonic-gate 
58720Sstevel@tonic-gate 	ev = sysevent_alloc(EC_DEVFS, ESC_DEVFS_MINOR_REMOVE, EP_DDI, SE_SLEEP);
58730Sstevel@tonic-gate 	if (ev == NULL) {
58740Sstevel@tonic-gate 		return (DDI_SUCCESS);
58750Sstevel@tonic-gate 	}
58760Sstevel@tonic-gate 
58770Sstevel@tonic-gate 	pathname = kmem_alloc(MAXPATHLEN, KM_SLEEP);
58780Sstevel@tonic-gate 	if (pathname == NULL) {
58790Sstevel@tonic-gate 		sysevent_free(ev);
58800Sstevel@tonic-gate 		return (DDI_SUCCESS);
58810Sstevel@tonic-gate 	}
58820Sstevel@tonic-gate 
58830Sstevel@tonic-gate 	(void) ddi_pathname(dip, pathname);
58840Sstevel@tonic-gate 	ASSERT(strlen(pathname));
58850Sstevel@tonic-gate 	se_val.value_type = SE_DATA_TYPE_STRING;
58860Sstevel@tonic-gate 	se_val.value.sv_string = pathname;
58870Sstevel@tonic-gate 	if (sysevent_add_attr(&ev_attr_list, DEVFS_PATHNAME,
58880Sstevel@tonic-gate 	    &se_val, SE_SLEEP) != 0) {
58890Sstevel@tonic-gate 		kmem_free(pathname, MAXPATHLEN);
58900Sstevel@tonic-gate 		sysevent_free(ev);
58910Sstevel@tonic-gate 		return (DDI_SUCCESS);
58920Sstevel@tonic-gate 	}
58930Sstevel@tonic-gate 
58940Sstevel@tonic-gate 	kmem_free(pathname, MAXPATHLEN);
58950Sstevel@tonic-gate 
58960Sstevel@tonic-gate 	/*
58970Sstevel@tonic-gate 	 * allow for NULL minor names
58980Sstevel@tonic-gate 	 */
58990Sstevel@tonic-gate 	if (minor_name != NULL) {
59000Sstevel@tonic-gate 		se_val.value.sv_string = minor_name;
59010Sstevel@tonic-gate 		if (sysevent_add_attr(&ev_attr_list, DEVFS_MINOR_NAME,
59020Sstevel@tonic-gate 		    &se_val, SE_SLEEP) != 0) {
59030Sstevel@tonic-gate 			sysevent_free_attr(ev_attr_list);
59040Sstevel@tonic-gate 			goto fail;
59050Sstevel@tonic-gate 		}
59060Sstevel@tonic-gate 	}
59070Sstevel@tonic-gate 
59084211Sphitran 	if ((class_name = i_ddi_devi_class(dip)) != NULL) {
59094211Sphitran 		/* add the device class, driver name and instance attributes */
59104211Sphitran 
59114211Sphitran 		se_val.value_type = SE_DATA_TYPE_STRING;
59124211Sphitran 		se_val.value.sv_string = class_name;
59134211Sphitran 		if (sysevent_add_attr(&ev_attr_list,
59144211Sphitran 		    DEVFS_DEVI_CLASS, &se_val, SE_SLEEP) != 0) {
59154211Sphitran 			sysevent_free_attr(ev_attr_list);
59164211Sphitran 			goto fail;
59174211Sphitran 		}
59184211Sphitran 
59194211Sphitran 		se_val.value_type = SE_DATA_TYPE_STRING;
59204211Sphitran 		se_val.value.sv_string = (char *)ddi_driver_name(dip);
59214211Sphitran 		if (sysevent_add_attr(&ev_attr_list,
59224211Sphitran 		    DEVFS_DRIVER_NAME, &se_val, SE_SLEEP) != 0) {
59234211Sphitran 			sysevent_free_attr(ev_attr_list);
59244211Sphitran 			goto fail;
59254211Sphitran 		}
59264211Sphitran 
59274211Sphitran 		se_val.value_type = SE_DATA_TYPE_INT32;
59284211Sphitran 		se_val.value.sv_int32 = ddi_get_instance(dip);
59294211Sphitran 		if (sysevent_add_attr(&ev_attr_list,
59304211Sphitran 		    DEVFS_INSTANCE, &se_val, SE_SLEEP) != 0) {
59314211Sphitran 			sysevent_free_attr(ev_attr_list);
59324211Sphitran 			goto fail;
59334211Sphitran 		}
59344211Sphitran 
59354211Sphitran 	}
59364211Sphitran 
59370Sstevel@tonic-gate 	if (sysevent_attach_attributes(ev, ev_attr_list) != 0) {
59380Sstevel@tonic-gate 		sysevent_free_attr(ev_attr_list);
59390Sstevel@tonic-gate 	} else {
59400Sstevel@tonic-gate 		(void) log_sysevent(ev, SE_SLEEP, &eid);
59410Sstevel@tonic-gate 	}
59420Sstevel@tonic-gate fail:
59430Sstevel@tonic-gate 	sysevent_free(ev);
59440Sstevel@tonic-gate 	return (DDI_SUCCESS);
59450Sstevel@tonic-gate }
59460Sstevel@tonic-gate 
59470Sstevel@tonic-gate /*
59480Sstevel@tonic-gate  * Derive the device class of the node.
59490Sstevel@tonic-gate  * Device class names aren't defined yet. Until this is done we use
59500Sstevel@tonic-gate  * devfs event subclass names as device class names.
59510Sstevel@tonic-gate  */
59520Sstevel@tonic-gate static int
derive_devi_class(dev_info_t * dip,char * node_type,int flag)59530Sstevel@tonic-gate derive_devi_class(dev_info_t *dip, char *node_type, int flag)
59540Sstevel@tonic-gate {
59550Sstevel@tonic-gate 	int rv = DDI_SUCCESS;
59560Sstevel@tonic-gate 
59570Sstevel@tonic-gate 	if (i_ddi_devi_class(dip) == NULL) {
59580Sstevel@tonic-gate 		if (strncmp(node_type, DDI_NT_BLOCK,
59590Sstevel@tonic-gate 		    sizeof (DDI_NT_BLOCK) - 1) == 0 &&
59600Sstevel@tonic-gate 		    (node_type[sizeof (DDI_NT_BLOCK) - 1] == '\0' ||
59610Sstevel@tonic-gate 		    node_type[sizeof (DDI_NT_BLOCK) - 1] == ':') &&
59620Sstevel@tonic-gate 		    strcmp(node_type, DDI_NT_FD) != 0) {
59630Sstevel@tonic-gate 
59640Sstevel@tonic-gate 			rv = i_ddi_set_devi_class(dip, ESC_DISK, flag);
59650Sstevel@tonic-gate 
59660Sstevel@tonic-gate 		} else if (strncmp(node_type, DDI_NT_NET,
59670Sstevel@tonic-gate 		    sizeof (DDI_NT_NET) - 1) == 0 &&
59680Sstevel@tonic-gate 		    (node_type[sizeof (DDI_NT_NET) - 1] == '\0' ||
59690Sstevel@tonic-gate 		    node_type[sizeof (DDI_NT_NET) - 1] == ':')) {
59700Sstevel@tonic-gate 
59710Sstevel@tonic-gate 			rv = i_ddi_set_devi_class(dip, ESC_NETWORK, flag);
59722441Sjacobs 
59732441Sjacobs 		} else if (strncmp(node_type, DDI_NT_PRINTER,
59742441Sjacobs 		    sizeof (DDI_NT_PRINTER) - 1) == 0 &&
59752441Sjacobs 		    (node_type[sizeof (DDI_NT_PRINTER) - 1] == '\0' ||
59762441Sjacobs 		    node_type[sizeof (DDI_NT_PRINTER) - 1] == ':')) {
59772441Sjacobs 
59782441Sjacobs 			rv = i_ddi_set_devi_class(dip, ESC_PRINTER, flag);
59794211Sphitran 
59804211Sphitran 		} else if (strncmp(node_type, DDI_PSEUDO,
59814211Sphitran 		    sizeof (DDI_PSEUDO) -1) == 0 &&
59824211Sphitran 		    (strncmp(ESC_LOFI, ddi_node_name(dip),
59834211Sphitran 		    sizeof (ESC_LOFI) -1) == 0)) {
59844211Sphitran 			rv = i_ddi_set_devi_class(dip, ESC_LOFI, flag);
59850Sstevel@tonic-gate 		}
59860Sstevel@tonic-gate 	}
59870Sstevel@tonic-gate 
59880Sstevel@tonic-gate 	return (rv);
59890Sstevel@tonic-gate }
59900Sstevel@tonic-gate 
59910Sstevel@tonic-gate /*
59920Sstevel@tonic-gate  * Check compliance with PSARC 2003/375:
59930Sstevel@tonic-gate  *
59940Sstevel@tonic-gate  * The name must contain only characters a-z, A-Z, 0-9 or _ and it must not
59950Sstevel@tonic-gate  * exceed IFNAMSIZ (16) characters in length.
59960Sstevel@tonic-gate  */
59970Sstevel@tonic-gate static boolean_t
verify_name(char * name)59980Sstevel@tonic-gate verify_name(char *name)
59990Sstevel@tonic-gate {
60000Sstevel@tonic-gate 	size_t	len = strlen(name);
60010Sstevel@tonic-gate 	char	*cp;
60020Sstevel@tonic-gate 
60030Sstevel@tonic-gate 	if (len == 0 || len > IFNAMSIZ)
60040Sstevel@tonic-gate 		return (B_FALSE);
60050Sstevel@tonic-gate 
60060Sstevel@tonic-gate 	for (cp = name; *cp != '\0'; cp++) {
60070Sstevel@tonic-gate 		if (!isalnum(*cp) && *cp != '_')
60080Sstevel@tonic-gate 			return (B_FALSE);
60090Sstevel@tonic-gate 	}
60100Sstevel@tonic-gate 
60110Sstevel@tonic-gate 	return (B_TRUE);
60120Sstevel@tonic-gate }
60130Sstevel@tonic-gate 
60140Sstevel@tonic-gate /*
60150Sstevel@tonic-gate  * ddi_create_minor_common:	Create a  ddi_minor_data structure and
60160Sstevel@tonic-gate  *				attach it to the given devinfo node.
60170Sstevel@tonic-gate  */
60180Sstevel@tonic-gate 
60190Sstevel@tonic-gate int
ddi_create_minor_common(dev_info_t * dip,char * name,int spec_type,minor_t minor_num,char * node_type,int flag,ddi_minor_type mtype,const char * read_priv,const char * write_priv,mode_t priv_mode)60200Sstevel@tonic-gate ddi_create_minor_common(dev_info_t *dip, char *name, int spec_type,
60210Sstevel@tonic-gate     minor_t minor_num, char *node_type, int flag, ddi_minor_type mtype,
60220Sstevel@tonic-gate     const char *read_priv, const char *write_priv, mode_t priv_mode)
60230Sstevel@tonic-gate {
60240Sstevel@tonic-gate 	struct ddi_minor_data *dmdp;
60250Sstevel@tonic-gate 	major_t major;
60260Sstevel@tonic-gate 
60270Sstevel@tonic-gate 	if (spec_type != S_IFCHR && spec_type != S_IFBLK)
60280Sstevel@tonic-gate 		return (DDI_FAILURE);
60290Sstevel@tonic-gate 
60300Sstevel@tonic-gate 	if (name == NULL)
60310Sstevel@tonic-gate 		return (DDI_FAILURE);
60320Sstevel@tonic-gate 
60330Sstevel@tonic-gate 	/*
60340Sstevel@tonic-gate 	 * Log a message if the minor number the driver is creating
60350Sstevel@tonic-gate 	 * is not expressible on the on-disk filesystem (currently
60360Sstevel@tonic-gate 	 * this is limited to 18 bits both by UFS). The device can
60370Sstevel@tonic-gate 	 * be opened via devfs, but not by device special files created
60380Sstevel@tonic-gate 	 * via mknod().
60390Sstevel@tonic-gate 	 */
60400Sstevel@tonic-gate 	if (minor_num > L_MAXMIN32) {
60410Sstevel@tonic-gate 		cmn_err(CE_WARN,
60420Sstevel@tonic-gate 		    "%s%d:%s minor 0x%x too big for 32-bit applications",
60430Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip),
60440Sstevel@tonic-gate 		    name, minor_num);
60450Sstevel@tonic-gate 		return (DDI_FAILURE);
60460Sstevel@tonic-gate 	}
60470Sstevel@tonic-gate 
60480Sstevel@tonic-gate 	/* dip must be bound and attached */
60490Sstevel@tonic-gate 	major = ddi_driver_major(dip);
60507009Scth 	ASSERT(major != DDI_MAJOR_T_NONE);
60510Sstevel@tonic-gate 
60520Sstevel@tonic-gate 	/*
60530Sstevel@tonic-gate 	 * Default node_type to DDI_PSEUDO and issue notice in debug mode
60540Sstevel@tonic-gate 	 */
60550Sstevel@tonic-gate 	if (node_type == NULL) {
60560Sstevel@tonic-gate 		node_type = DDI_PSEUDO;
60570Sstevel@tonic-gate 		NDI_CONFIG_DEBUG((CE_NOTE, "!illegal node_type NULL for %s%d "
60580Sstevel@tonic-gate 		    " minor node %s; default to DDI_PSEUDO",
60590Sstevel@tonic-gate 		    ddi_driver_name(dip), ddi_get_instance(dip), name));
60600Sstevel@tonic-gate 	}
60610Sstevel@tonic-gate 
60620Sstevel@tonic-gate 	/*
60630Sstevel@tonic-gate 	 * If the driver is a network driver, ensure that the name falls within
60640Sstevel@tonic-gate 	 * the interface naming constraints specified by PSARC/2003/375.
60650Sstevel@tonic-gate 	 */
60660Sstevel@tonic-gate 	if (strcmp(node_type, DDI_NT_NET) == 0) {
60670Sstevel@tonic-gate 		if (!verify_name(name))
60680Sstevel@tonic-gate 			return (DDI_FAILURE);
60690Sstevel@tonic-gate 
60700Sstevel@tonic-gate 		if (mtype == DDM_MINOR) {
60710Sstevel@tonic-gate 			struct devnames *dnp = &devnamesp[major];
60720Sstevel@tonic-gate 
60730Sstevel@tonic-gate 			/* Mark driver as a network driver */
60740Sstevel@tonic-gate 			LOCK_DEV_OPS(&dnp->dn_lock);
60750Sstevel@tonic-gate 			dnp->dn_flags |= DN_NETWORK_DRIVER;
607610788SCathy.Zhou@Sun.COM 
607710788SCathy.Zhou@Sun.COM 			/*
607810788SCathy.Zhou@Sun.COM 			 * If this minor node is created during the device
607910788SCathy.Zhou@Sun.COM 			 * attachment, this is a physical network device.
608010788SCathy.Zhou@Sun.COM 			 * Mark the driver as a physical network driver.
608110788SCathy.Zhou@Sun.COM 			 */
608210788SCathy.Zhou@Sun.COM 			if (DEVI_IS_ATTACHING(dip))
608310788SCathy.Zhou@Sun.COM 				dnp->dn_flags |= DN_NETWORK_PHYSDRIVER;
60840Sstevel@tonic-gate 			UNLOCK_DEV_OPS(&dnp->dn_lock);
60850Sstevel@tonic-gate 		}
60860Sstevel@tonic-gate 	}
60870Sstevel@tonic-gate 
60880Sstevel@tonic-gate 	if (mtype == DDM_MINOR) {
60890Sstevel@tonic-gate 		if (derive_devi_class(dip,  node_type, KM_NOSLEEP) !=
60900Sstevel@tonic-gate 		    DDI_SUCCESS)
60910Sstevel@tonic-gate 			return (DDI_FAILURE);
60920Sstevel@tonic-gate 	}
60930Sstevel@tonic-gate 
60940Sstevel@tonic-gate 	/*
60950Sstevel@tonic-gate 	 * Take care of minor number information for the node.
60960Sstevel@tonic-gate 	 */
60970Sstevel@tonic-gate 
60980Sstevel@tonic-gate 	if ((dmdp = kmem_zalloc(sizeof (struct ddi_minor_data),
60990Sstevel@tonic-gate 	    KM_NOSLEEP)) == NULL) {
61000Sstevel@tonic-gate 		return (DDI_FAILURE);
61010Sstevel@tonic-gate 	}
61020Sstevel@tonic-gate 	if ((dmdp->ddm_name = i_ddi_strdup(name, KM_NOSLEEP)) == NULL) {
61030Sstevel@tonic-gate 		kmem_free(dmdp, sizeof (struct ddi_minor_data));
61040Sstevel@tonic-gate 		return (DDI_FAILURE);
61050Sstevel@tonic-gate 	}
61060Sstevel@tonic-gate 	dmdp->dip = dip;
61070Sstevel@tonic-gate 	dmdp->ddm_dev = makedevice(major, minor_num);
61080Sstevel@tonic-gate 	dmdp->ddm_spec_type = spec_type;
61090Sstevel@tonic-gate 	dmdp->ddm_node_type = node_type;
61100Sstevel@tonic-gate 	dmdp->type = mtype;
61110Sstevel@tonic-gate 	if (flag & CLONE_DEV) {
61120Sstevel@tonic-gate 		dmdp->type = DDM_ALIAS;
61130Sstevel@tonic-gate 		dmdp->ddm_dev = makedevice(ddi_driver_major(clone_dip), major);
61140Sstevel@tonic-gate 	}
61150Sstevel@tonic-gate 	if (flag & PRIVONLY_DEV) {
61160Sstevel@tonic-gate 		dmdp->ddm_flags |= DM_NO_FSPERM;
61170Sstevel@tonic-gate 	}
61180Sstevel@tonic-gate 	if (read_priv || write_priv) {
61190Sstevel@tonic-gate 		dmdp->ddm_node_priv =
61200Sstevel@tonic-gate 		    devpolicy_priv_by_name(read_priv, write_priv);
61210Sstevel@tonic-gate 	}
61220Sstevel@tonic-gate 	dmdp->ddm_priv_mode = priv_mode;
61230Sstevel@tonic-gate 
61240Sstevel@tonic-gate 	ddi_append_minor_node(dip, dmdp);
61250Sstevel@tonic-gate 
61260Sstevel@tonic-gate 	/*
61270Sstevel@tonic-gate 	 * only log ddi_create_minor_node() calls which occur
61280Sstevel@tonic-gate 	 * outside the scope of attach(9e)/detach(9e) reconfigurations
61290Sstevel@tonic-gate 	 */
61302123Sszhou 	if (!(DEVI_IS_ATTACHING(dip) || DEVI_IS_DETACHING(dip)) &&
61312123Sszhou 	    mtype != DDM_INTERNAL_PATH) {
61320Sstevel@tonic-gate 		(void) i_log_devfs_minor_create(dip, name);
61330Sstevel@tonic-gate 	}
61340Sstevel@tonic-gate 
61350Sstevel@tonic-gate 	/*
61360Sstevel@tonic-gate 	 * Check if any dacf rules match the creation of this minor node
61370Sstevel@tonic-gate 	 */
61380Sstevel@tonic-gate 	dacfc_match_create_minor(name, node_type, dip, dmdp, flag);
61390Sstevel@tonic-gate 	return (DDI_SUCCESS);
61400Sstevel@tonic-gate }
61410Sstevel@tonic-gate 
61420Sstevel@tonic-gate int
ddi_create_minor_node(dev_info_t * dip,char * name,int spec_type,minor_t minor_num,char * node_type,int flag)61430Sstevel@tonic-gate ddi_create_minor_node(dev_info_t *dip, char *name, int spec_type,
61440Sstevel@tonic-gate     minor_t minor_num, char *node_type, int flag)
61450Sstevel@tonic-gate {
61460Sstevel@tonic-gate 	return (ddi_create_minor_common(dip, name, spec_type, minor_num,
61470Sstevel@tonic-gate 	    node_type, flag, DDM_MINOR, NULL, NULL, 0));
61480Sstevel@tonic-gate }
61490Sstevel@tonic-gate 
61500Sstevel@tonic-gate int
ddi_create_priv_minor_node(dev_info_t * dip,char * name,int spec_type,minor_t minor_num,char * node_type,int flag,const char * rdpriv,const char * wrpriv,mode_t priv_mode)61510Sstevel@tonic-gate ddi_create_priv_minor_node(dev_info_t *dip, char *name, int spec_type,
61520Sstevel@tonic-gate     minor_t minor_num, char *node_type, int flag,
61530Sstevel@tonic-gate     const char *rdpriv, const char *wrpriv, mode_t priv_mode)
61540Sstevel@tonic-gate {
61550Sstevel@tonic-gate 	return (ddi_create_minor_common(dip, name, spec_type, minor_num,
61560Sstevel@tonic-gate 	    node_type, flag, DDM_MINOR, rdpriv, wrpriv, priv_mode));
61570Sstevel@tonic-gate }
61580Sstevel@tonic-gate 
61590Sstevel@tonic-gate int
ddi_create_default_minor_node(dev_info_t * dip,char * name,int spec_type,minor_t minor_num,char * node_type,int flag)61600Sstevel@tonic-gate ddi_create_default_minor_node(dev_info_t *dip, char *name, int spec_type,
61610Sstevel@tonic-gate     minor_t minor_num, char *node_type, int flag)
61620Sstevel@tonic-gate {
61630Sstevel@tonic-gate 	return (ddi_create_minor_common(dip, name, spec_type, minor_num,
61640Sstevel@tonic-gate 	    node_type, flag, DDM_DEFAULT, NULL, NULL, 0));
61650Sstevel@tonic-gate }
61660Sstevel@tonic-gate 
61670Sstevel@tonic-gate /*
61680Sstevel@tonic-gate  * Internal (non-ddi) routine for drivers to export names known
61690Sstevel@tonic-gate  * to the kernel (especially ddi_pathname_to_dev_t and friends)
61700Sstevel@tonic-gate  * but not exported externally to /dev
61710Sstevel@tonic-gate  */
61720Sstevel@tonic-gate int
ddi_create_internal_pathname(dev_info_t * dip,char * name,int spec_type,minor_t minor_num)61730Sstevel@tonic-gate ddi_create_internal_pathname(dev_info_t *dip, char *name, int spec_type,
61740Sstevel@tonic-gate     minor_t minor_num)
61750Sstevel@tonic-gate {
61760Sstevel@tonic-gate 	return (ddi_create_minor_common(dip, name, spec_type, minor_num,
61770Sstevel@tonic-gate 	    "internal", 0, DDM_INTERNAL_PATH, NULL, NULL, 0));
61780Sstevel@tonic-gate }
61790Sstevel@tonic-gate 
61800Sstevel@tonic-gate void
ddi_remove_minor_node(dev_info_t * dip,char * name)61810Sstevel@tonic-gate ddi_remove_minor_node(dev_info_t *dip, char *name)
61820Sstevel@tonic-gate {
61837224Scth 	int			circ;
61847224Scth 	struct ddi_minor_data	*dmdp, *dmdp1;
61857224Scth 	struct ddi_minor_data	**dmdp_prev;
61867224Scth 
61877224Scth 	ndi_devi_enter(dip, &circ);
61880Sstevel@tonic-gate 	dmdp_prev = &DEVI(dip)->devi_minor;
61890Sstevel@tonic-gate 	dmdp = DEVI(dip)->devi_minor;
61900Sstevel@tonic-gate 	while (dmdp != NULL) {
61910Sstevel@tonic-gate 		dmdp1 = dmdp->next;
61920Sstevel@tonic-gate 		if ((name == NULL || (dmdp->ddm_name != NULL &&
61930Sstevel@tonic-gate 		    strcmp(name, dmdp->ddm_name) == 0))) {
61940Sstevel@tonic-gate 			if (dmdp->ddm_name != NULL) {
61952123Sszhou 				if (dmdp->type != DDM_INTERNAL_PATH)
61962123Sszhou 					(void) i_log_devfs_minor_remove(dip,
61972123Sszhou 					    dmdp->ddm_name);
61980Sstevel@tonic-gate 				kmem_free(dmdp->ddm_name,
61990Sstevel@tonic-gate 				    strlen(dmdp->ddm_name) + 1);
62000Sstevel@tonic-gate 			}
62010Sstevel@tonic-gate 			/*
62020Sstevel@tonic-gate 			 * Release device privilege, if any.
62030Sstevel@tonic-gate 			 * Release dacf client data associated with this minor
62040Sstevel@tonic-gate 			 * node by storing NULL.
62050Sstevel@tonic-gate 			 */
62060Sstevel@tonic-gate 			if (dmdp->ddm_node_priv)
62070Sstevel@tonic-gate 				dpfree(dmdp->ddm_node_priv);
62080Sstevel@tonic-gate 			dacf_store_info((dacf_infohdl_t)dmdp, NULL);
62090Sstevel@tonic-gate 			kmem_free(dmdp, sizeof (struct ddi_minor_data));
62100Sstevel@tonic-gate 			*dmdp_prev = dmdp1;
62110Sstevel@tonic-gate 			/*
62120Sstevel@tonic-gate 			 * OK, we found it, so get out now -- if we drive on,
62130Sstevel@tonic-gate 			 * we will strcmp against garbage.  See 1139209.
62140Sstevel@tonic-gate 			 */
62150Sstevel@tonic-gate 			if (name != NULL)
62160Sstevel@tonic-gate 				break;
62170Sstevel@tonic-gate 		} else {
62180Sstevel@tonic-gate 			dmdp_prev = &dmdp->next;
62190Sstevel@tonic-gate 		}
62200Sstevel@tonic-gate 		dmdp = dmdp1;
62210Sstevel@tonic-gate 	}
62227224Scth 	ndi_devi_exit(dip, circ);
62230Sstevel@tonic-gate }
62240Sstevel@tonic-gate 
62250Sstevel@tonic-gate 
62260Sstevel@tonic-gate int
ddi_in_panic()62270Sstevel@tonic-gate ddi_in_panic()
62280Sstevel@tonic-gate {
62290Sstevel@tonic-gate 	return (panicstr != NULL);
62300Sstevel@tonic-gate }
62310Sstevel@tonic-gate 
62320Sstevel@tonic-gate 
62330Sstevel@tonic-gate /*
62340Sstevel@tonic-gate  * Find first bit set in a mask (returned counting from 1 up)
62350Sstevel@tonic-gate  */
62360Sstevel@tonic-gate 
62370Sstevel@tonic-gate int
ddi_ffs(long mask)62380Sstevel@tonic-gate ddi_ffs(long mask)
62390Sstevel@tonic-gate {
62400Sstevel@tonic-gate 	return (ffs(mask));
62410Sstevel@tonic-gate }
62420Sstevel@tonic-gate 
62430Sstevel@tonic-gate /*
62440Sstevel@tonic-gate  * Find last bit set. Take mask and clear
62450Sstevel@tonic-gate  * all but the most significant bit, and
62460Sstevel@tonic-gate  * then let ffs do the rest of the work.
62470Sstevel@tonic-gate  *
62480Sstevel@tonic-gate  * Algorithm courtesy of Steve Chessin.
62490Sstevel@tonic-gate  */
62500Sstevel@tonic-gate 
62510Sstevel@tonic-gate int
ddi_fls(long mask)62520Sstevel@tonic-gate ddi_fls(long mask)
62530Sstevel@tonic-gate {
62540Sstevel@tonic-gate 	while (mask) {
62550Sstevel@tonic-gate 		long nx;
62560Sstevel@tonic-gate 
62570Sstevel@tonic-gate 		if ((nx = (mask & (mask - 1))) == 0)
62580Sstevel@tonic-gate 			break;
62590Sstevel@tonic-gate 		mask = nx;
62600Sstevel@tonic-gate 	}
62610Sstevel@tonic-gate 	return (ffs(mask));
62620Sstevel@tonic-gate }
62630Sstevel@tonic-gate 
62640Sstevel@tonic-gate /*
626510696SDavid.Hollister@Sun.COM  * The ddi_soft_state_* routines comprise generic storage management utilities
626610696SDavid.Hollister@Sun.COM  * for driver soft state structures (in "the old days," this was done with
626710696SDavid.Hollister@Sun.COM  * statically sized array - big systems and dynamic loading and unloading
626810696SDavid.Hollister@Sun.COM  * make heap allocation more attractive).
62690Sstevel@tonic-gate  */
62700Sstevel@tonic-gate 
62710Sstevel@tonic-gate /*
62720Sstevel@tonic-gate  * Allocate a set of pointers to 'n_items' objects of size 'size'
62730Sstevel@tonic-gate  * bytes.  Each pointer is initialized to nil.
62740Sstevel@tonic-gate  *
62750Sstevel@tonic-gate  * The 'size' and 'n_items' values are stashed in the opaque
62760Sstevel@tonic-gate  * handle returned to the caller.
62770Sstevel@tonic-gate  *
62780Sstevel@tonic-gate  * This implementation interprets 'set of pointers' to mean 'array
62790Sstevel@tonic-gate  * of pointers' but note that nothing in the interface definition
62800Sstevel@tonic-gate  * precludes an implementation that uses, for example, a linked list.
62810Sstevel@tonic-gate  * However there should be a small efficiency gain from using an array
62820Sstevel@tonic-gate  * at lookup time.
62830Sstevel@tonic-gate  *
62840Sstevel@tonic-gate  * NOTE	As an optimization, we make our growable array allocations in
62850Sstevel@tonic-gate  *	powers of two (bytes), since that's how much kmem_alloc (currently)
62860Sstevel@tonic-gate  *	gives us anyway.  It should save us some free/realloc's ..
62870Sstevel@tonic-gate  *
62880Sstevel@tonic-gate  *	As a further optimization, we make the growable array start out
62890Sstevel@tonic-gate  *	with MIN_N_ITEMS in it.
62900Sstevel@tonic-gate  */
62910Sstevel@tonic-gate 
62920Sstevel@tonic-gate #define	MIN_N_ITEMS	8	/* 8 void *'s == 32 bytes */
62930Sstevel@tonic-gate 
62940Sstevel@tonic-gate int
ddi_soft_state_init(void ** state_p,size_t size,size_t n_items)62950Sstevel@tonic-gate ddi_soft_state_init(void **state_p, size_t size, size_t n_items)
62960Sstevel@tonic-gate {
629710696SDavid.Hollister@Sun.COM 	i_ddi_soft_state	*ss;
629810696SDavid.Hollister@Sun.COM 
629910696SDavid.Hollister@Sun.COM 	if (state_p == NULL || size == 0)
63000Sstevel@tonic-gate 		return (EINVAL);
63010Sstevel@tonic-gate 
63020Sstevel@tonic-gate 	ss = kmem_zalloc(sizeof (*ss), KM_SLEEP);
63030Sstevel@tonic-gate 	mutex_init(&ss->lock, NULL, MUTEX_DRIVER, NULL);
63040Sstevel@tonic-gate 	ss->size = size;
63050Sstevel@tonic-gate 
63060Sstevel@tonic-gate 	if (n_items < MIN_N_ITEMS)
63070Sstevel@tonic-gate 		ss->n_items = MIN_N_ITEMS;
63080Sstevel@tonic-gate 	else {
63090Sstevel@tonic-gate 		int bitlog;
63100Sstevel@tonic-gate 
63110Sstevel@tonic-gate 		if ((bitlog = ddi_fls(n_items)) == ddi_ffs(n_items))
63120Sstevel@tonic-gate 			bitlog--;
63130Sstevel@tonic-gate 		ss->n_items = 1 << bitlog;
63140Sstevel@tonic-gate 	}
63150Sstevel@tonic-gate 
63160Sstevel@tonic-gate 	ASSERT(ss->n_items >= n_items);
63170Sstevel@tonic-gate 
63180Sstevel@tonic-gate 	ss->array = kmem_zalloc(ss->n_items * sizeof (void *), KM_SLEEP);
63190Sstevel@tonic-gate 
63200Sstevel@tonic-gate 	*state_p = ss;
63210Sstevel@tonic-gate 	return (0);
63220Sstevel@tonic-gate }
63230Sstevel@tonic-gate 
63240Sstevel@tonic-gate /*
63250Sstevel@tonic-gate  * Allocate a state structure of size 'size' to be associated
63260Sstevel@tonic-gate  * with item 'item'.
63270Sstevel@tonic-gate  *
63280Sstevel@tonic-gate  * In this implementation, the array is extended to
63290Sstevel@tonic-gate  * allow the requested offset, if needed.
63300Sstevel@tonic-gate  */
63310Sstevel@tonic-gate int
ddi_soft_state_zalloc(void * state,int item)63320Sstevel@tonic-gate ddi_soft_state_zalloc(void *state, int item)
63330Sstevel@tonic-gate {
633410696SDavid.Hollister@Sun.COM 	i_ddi_soft_state	*ss = (i_ddi_soft_state *)state;
633510696SDavid.Hollister@Sun.COM 	void			**array;
633610696SDavid.Hollister@Sun.COM 	void			*new_element;
633710696SDavid.Hollister@Sun.COM 
633810696SDavid.Hollister@Sun.COM 	if ((state == NULL) || (item < 0))
63390Sstevel@tonic-gate 		return (DDI_FAILURE);
63400Sstevel@tonic-gate 
63410Sstevel@tonic-gate 	mutex_enter(&ss->lock);
63420Sstevel@tonic-gate 	if (ss->size == 0) {
63430Sstevel@tonic-gate 		mutex_exit(&ss->lock);
63440Sstevel@tonic-gate 		cmn_err(CE_WARN, "ddi_soft_state_zalloc: bad handle: %s",
63450Sstevel@tonic-gate 		    mod_containing_pc(caller()));
63460Sstevel@tonic-gate 		return (DDI_FAILURE);
63470Sstevel@tonic-gate 	}
63480Sstevel@tonic-gate 
63490Sstevel@tonic-gate 	array = ss->array;	/* NULL if ss->n_items == 0 */
63500Sstevel@tonic-gate 	ASSERT(ss->n_items != 0 && array != NULL);
63510Sstevel@tonic-gate 
63520Sstevel@tonic-gate 	/*
63530Sstevel@tonic-gate 	 * refuse to tread on an existing element
63540Sstevel@tonic-gate 	 */
63550Sstevel@tonic-gate 	if (item < ss->n_items && array[item] != NULL) {
63560Sstevel@tonic-gate 		mutex_exit(&ss->lock);
63570Sstevel@tonic-gate 		return (DDI_FAILURE);
63580Sstevel@tonic-gate 	}
63590Sstevel@tonic-gate 
63600Sstevel@tonic-gate 	/*
63610Sstevel@tonic-gate 	 * Allocate a new element to plug in
63620Sstevel@tonic-gate 	 */
63630Sstevel@tonic-gate 	new_element = kmem_zalloc(ss->size, KM_SLEEP);
63640Sstevel@tonic-gate 
63650Sstevel@tonic-gate 	/*
63660Sstevel@tonic-gate 	 * Check if the array is big enough, if not, grow it.
63670Sstevel@tonic-gate 	 */
63680Sstevel@tonic-gate 	if (item >= ss->n_items) {
636910696SDavid.Hollister@Sun.COM 		void			**new_array;
637010696SDavid.Hollister@Sun.COM 		size_t			new_n_items;
637110696SDavid.Hollister@Sun.COM 		struct i_ddi_soft_state	*dirty;
63720Sstevel@tonic-gate 
63730Sstevel@tonic-gate 		/*
63740Sstevel@tonic-gate 		 * Allocate a new array of the right length, copy
63750Sstevel@tonic-gate 		 * all the old pointers to the new array, then
63760Sstevel@tonic-gate 		 * if it exists at all, put the old array on the
63770Sstevel@tonic-gate 		 * dirty list.
63780Sstevel@tonic-gate 		 *
63790Sstevel@tonic-gate 		 * Note that we can't kmem_free() the old array.
63800Sstevel@tonic-gate 		 *
63810Sstevel@tonic-gate 		 * Why -- well the 'get' operation is 'mutex-free', so we
63820Sstevel@tonic-gate 		 * can't easily catch a suspended thread that is just about
63830Sstevel@tonic-gate 		 * to dereference the array we just grew out of.  So we
63840Sstevel@tonic-gate 		 * cons up a header and put it on a list of 'dirty'
63850Sstevel@tonic-gate 		 * pointer arrays.  (Dirty in the sense that there may
63860Sstevel@tonic-gate 		 * be suspended threads somewhere that are in the middle
63870Sstevel@tonic-gate 		 * of referencing them).  Fortunately, we -can- garbage
63880Sstevel@tonic-gate 		 * collect it all at ddi_soft_state_fini time.
63890Sstevel@tonic-gate 		 */
63900Sstevel@tonic-gate 		new_n_items = ss->n_items;
63910Sstevel@tonic-gate 		while (new_n_items < (1 + item))
63920Sstevel@tonic-gate 			new_n_items <<= 1;	/* double array size .. */
63930Sstevel@tonic-gate 
63940Sstevel@tonic-gate 		ASSERT(new_n_items >= (1 + item));	/* sanity check! */
63950Sstevel@tonic-gate 
63960Sstevel@tonic-gate 		new_array = kmem_zalloc(new_n_items * sizeof (void *),
63970Sstevel@tonic-gate 		    KM_SLEEP);
63980Sstevel@tonic-gate 		/*
63990Sstevel@tonic-gate 		 * Copy the pointers into the new array
64000Sstevel@tonic-gate 		 */
64010Sstevel@tonic-gate 		bcopy(array, new_array, ss->n_items * sizeof (void *));
64020Sstevel@tonic-gate 
64030Sstevel@tonic-gate 		/*
64040Sstevel@tonic-gate 		 * Save the old array on the dirty list
64050Sstevel@tonic-gate 		 */
64060Sstevel@tonic-gate 		dirty = kmem_zalloc(sizeof (*dirty), KM_SLEEP);
64070Sstevel@tonic-gate 		dirty->array = ss->array;
64080Sstevel@tonic-gate 		dirty->n_items = ss->n_items;
64090Sstevel@tonic-gate 		dirty->next = ss->next;
64100Sstevel@tonic-gate 		ss->next = dirty;
64110Sstevel@tonic-gate 
64120Sstevel@tonic-gate 		ss->array = (array = new_array);
64130Sstevel@tonic-gate 		ss->n_items = new_n_items;
64140Sstevel@tonic-gate 	}
64150Sstevel@tonic-gate 
64160Sstevel@tonic-gate 	ASSERT(array != NULL && item < ss->n_items && array[item] == NULL);
64170Sstevel@tonic-gate 
64180Sstevel@tonic-gate 	array[item] = new_element;
64190Sstevel@tonic-gate 
64200Sstevel@tonic-gate 	mutex_exit(&ss->lock);
64210Sstevel@tonic-gate 	return (DDI_SUCCESS);
64220Sstevel@tonic-gate }
64230Sstevel@tonic-gate 
64240Sstevel@tonic-gate /*
64250Sstevel@tonic-gate  * Fetch a pointer to the allocated soft state structure.
64260Sstevel@tonic-gate  *
64270Sstevel@tonic-gate  * This is designed to be cheap.
64280Sstevel@tonic-gate  *
64290Sstevel@tonic-gate  * There's an argument that there should be more checking for
64300Sstevel@tonic-gate  * nil pointers and out of bounds on the array.. but we do a lot
64310Sstevel@tonic-gate  * of that in the alloc/free routines.
64320Sstevel@tonic-gate  *
64330Sstevel@tonic-gate  * An array has the convenience that we don't need to lock read-access
64340Sstevel@tonic-gate  * to it c.f. a linked list.  However our "expanding array" strategy
64350Sstevel@tonic-gate  * means that we should hold a readers lock on the i_ddi_soft_state
64360Sstevel@tonic-gate  * structure.
64370Sstevel@tonic-gate  *
64380Sstevel@tonic-gate  * However, from a performance viewpoint, we need to do it without
64390Sstevel@tonic-gate  * any locks at all -- this also makes it a leaf routine.  The algorithm
64400Sstevel@tonic-gate  * is 'lock-free' because we only discard the pointer arrays at
64410Sstevel@tonic-gate  * ddi_soft_state_fini() time.
64420Sstevel@tonic-gate  */
64430Sstevel@tonic-gate void *
ddi_get_soft_state(void * state,int item)64440Sstevel@tonic-gate ddi_get_soft_state(void *state, int item)
64450Sstevel@tonic-gate {
644610696SDavid.Hollister@Sun.COM 	i_ddi_soft_state	*ss = (i_ddi_soft_state *)state;
644710696SDavid.Hollister@Sun.COM 
644810696SDavid.Hollister@Sun.COM 	ASSERT((ss != NULL) && (item >= 0));
64490Sstevel@tonic-gate 
64500Sstevel@tonic-gate 	if (item < ss->n_items && ss->array != NULL)
64510Sstevel@tonic-gate 		return (ss->array[item]);
64520Sstevel@tonic-gate 	return (NULL);
64530Sstevel@tonic-gate }
64540Sstevel@tonic-gate 
64550Sstevel@tonic-gate /*
64560Sstevel@tonic-gate  * Free the state structure corresponding to 'item.'   Freeing an
64570Sstevel@tonic-gate  * element that has either gone or was never allocated is not
64580Sstevel@tonic-gate  * considered an error.  Note that we free the state structure, but
64590Sstevel@tonic-gate  * we don't shrink our pointer array, or discard 'dirty' arrays,
64600Sstevel@tonic-gate  * since even a few pointers don't really waste too much memory.
64610Sstevel@tonic-gate  *
64620Sstevel@tonic-gate  * Passing an item number that is out of bounds, or a null pointer will
64630Sstevel@tonic-gate  * provoke an error message.
64640Sstevel@tonic-gate  */
64650Sstevel@tonic-gate void
ddi_soft_state_free(void * state,int item)64660Sstevel@tonic-gate ddi_soft_state_free(void *state, int item)
64670Sstevel@tonic-gate {
646810696SDavid.Hollister@Sun.COM 	i_ddi_soft_state	*ss = (i_ddi_soft_state *)state;
646910696SDavid.Hollister@Sun.COM 	void			**array;
647010696SDavid.Hollister@Sun.COM 	void			*element;
647110696SDavid.Hollister@Sun.COM 	static char		msg[] = "ddi_soft_state_free:";
647210696SDavid.Hollister@Sun.COM 
647310696SDavid.Hollister@Sun.COM 	if (ss == NULL) {
64740Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s null handle: %s",
64750Sstevel@tonic-gate 		    msg, mod_containing_pc(caller()));
64760Sstevel@tonic-gate 		return;
64770Sstevel@tonic-gate 	}
64780Sstevel@tonic-gate 
64790Sstevel@tonic-gate 	element = NULL;
64800Sstevel@tonic-gate 
64810Sstevel@tonic-gate 	mutex_enter(&ss->lock);
64820Sstevel@tonic-gate 
64830Sstevel@tonic-gate 	if ((array = ss->array) == NULL || ss->size == 0) {
64840Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s bad handle: %s",
64850Sstevel@tonic-gate 		    msg, mod_containing_pc(caller()));
64860Sstevel@tonic-gate 	} else if (item < 0 || item >= ss->n_items) {
64870Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s item %d not in range [0..%lu]: %s",
64880Sstevel@tonic-gate 		    msg, item, ss->n_items - 1, mod_containing_pc(caller()));
64890Sstevel@tonic-gate 	} else if (array[item] != NULL) {
64900Sstevel@tonic-gate 		element = array[item];
64910Sstevel@tonic-gate 		array[item] = NULL;
64920Sstevel@tonic-gate 	}
64930Sstevel@tonic-gate 
64940Sstevel@tonic-gate 	mutex_exit(&ss->lock);
64950Sstevel@tonic-gate 
64960Sstevel@tonic-gate 	if (element)
64970Sstevel@tonic-gate 		kmem_free(element, ss->size);
64980Sstevel@tonic-gate }
64990Sstevel@tonic-gate 
65000Sstevel@tonic-gate /*
65010Sstevel@tonic-gate  * Free the entire set of pointers, and any
65020Sstevel@tonic-gate  * soft state structures contained therein.
65030Sstevel@tonic-gate  *
65040Sstevel@tonic-gate  * Note that we don't grab the ss->lock mutex, even though
65050Sstevel@tonic-gate  * we're inspecting the various fields of the data structure.
65060Sstevel@tonic-gate  *
65070Sstevel@tonic-gate  * There is an implicit assumption that this routine will
65080Sstevel@tonic-gate  * never run concurrently with any of the above on this
65090Sstevel@tonic-gate  * particular state structure i.e. by the time the driver
65100Sstevel@tonic-gate  * calls this routine, there should be no other threads
65110Sstevel@tonic-gate  * running in the driver.
65120Sstevel@tonic-gate  */
65130Sstevel@tonic-gate void
ddi_soft_state_fini(void ** state_p)65140Sstevel@tonic-gate ddi_soft_state_fini(void **state_p)
65150Sstevel@tonic-gate {
651610696SDavid.Hollister@Sun.COM 	i_ddi_soft_state	*ss, *dirty;
651710696SDavid.Hollister@Sun.COM 	int			item;
651810696SDavid.Hollister@Sun.COM 	static char		msg[] = "ddi_soft_state_fini:";
651910696SDavid.Hollister@Sun.COM 
652010696SDavid.Hollister@Sun.COM 	if (state_p == NULL ||
652110696SDavid.Hollister@Sun.COM 	    (ss = (i_ddi_soft_state *)(*state_p)) == NULL) {
65220Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s null handle: %s",
65230Sstevel@tonic-gate 		    msg, mod_containing_pc(caller()));
65240Sstevel@tonic-gate 		return;
65250Sstevel@tonic-gate 	}
65260Sstevel@tonic-gate 
65270Sstevel@tonic-gate 	if (ss->size == 0) {
65280Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s bad handle: %s",
65290Sstevel@tonic-gate 		    msg, mod_containing_pc(caller()));
65300Sstevel@tonic-gate 		return;
65310Sstevel@tonic-gate 	}
65320Sstevel@tonic-gate 
65330Sstevel@tonic-gate 	if (ss->n_items > 0) {
65340Sstevel@tonic-gate 		for (item = 0; item < ss->n_items; item++)
65350Sstevel@tonic-gate 			ddi_soft_state_free(ss, item);
65360Sstevel@tonic-gate 		kmem_free(ss->array, ss->n_items * sizeof (void *));
65370Sstevel@tonic-gate 	}
65380Sstevel@tonic-gate 
65390Sstevel@tonic-gate 	/*
65400Sstevel@tonic-gate 	 * Now delete any dirty arrays from previous 'grow' operations
65410Sstevel@tonic-gate 	 */
65420Sstevel@tonic-gate 	for (dirty = ss->next; dirty; dirty = ss->next) {
65430Sstevel@tonic-gate 		ss->next = dirty->next;
65440Sstevel@tonic-gate 		kmem_free(dirty->array, dirty->n_items * sizeof (void *));
65450Sstevel@tonic-gate 		kmem_free(dirty, sizeof (*dirty));
65460Sstevel@tonic-gate 	}
65470Sstevel@tonic-gate 
65480Sstevel@tonic-gate 	mutex_destroy(&ss->lock);
65490Sstevel@tonic-gate 	kmem_free(ss, sizeof (*ss));
65500Sstevel@tonic-gate 
65510Sstevel@tonic-gate 	*state_p = NULL;
65520Sstevel@tonic-gate }
65530Sstevel@tonic-gate 
655410696SDavid.Hollister@Sun.COM #define	SS_N_ITEMS_PER_HASH	16
655510696SDavid.Hollister@Sun.COM #define	SS_MIN_HASH_SZ		16
655610696SDavid.Hollister@Sun.COM #define	SS_MAX_HASH_SZ		4096
655710696SDavid.Hollister@Sun.COM 
655810696SDavid.Hollister@Sun.COM int
ddi_soft_state_bystr_init(ddi_soft_state_bystr ** state_p,size_t size,int n_items)655910696SDavid.Hollister@Sun.COM ddi_soft_state_bystr_init(ddi_soft_state_bystr **state_p, size_t size,
656010696SDavid.Hollister@Sun.COM     int n_items)
656110696SDavid.Hollister@Sun.COM {
656210696SDavid.Hollister@Sun.COM 	i_ddi_soft_state_bystr	*sss;
656310696SDavid.Hollister@Sun.COM 	int			hash_sz;
656410696SDavid.Hollister@Sun.COM 
656510696SDavid.Hollister@Sun.COM 	ASSERT(state_p && size && n_items);
656610696SDavid.Hollister@Sun.COM 	if ((state_p == NULL) || (size == 0) || (n_items == 0))
656710696SDavid.Hollister@Sun.COM 		return (EINVAL);
656810696SDavid.Hollister@Sun.COM 
656910696SDavid.Hollister@Sun.COM 	/* current implementation is based on hash, convert n_items to hash */
657010696SDavid.Hollister@Sun.COM 	hash_sz = n_items / SS_N_ITEMS_PER_HASH;
657110696SDavid.Hollister@Sun.COM 	if (hash_sz < SS_MIN_HASH_SZ)
657210696SDavid.Hollister@Sun.COM 		hash_sz = SS_MIN_HASH_SZ;
657310696SDavid.Hollister@Sun.COM 	else if (hash_sz > SS_MAX_HASH_SZ)
657410696SDavid.Hollister@Sun.COM 		hash_sz = SS_MAX_HASH_SZ;
657510696SDavid.Hollister@Sun.COM 
657610696SDavid.Hollister@Sun.COM 	/* allocate soft_state pool */
657710696SDavid.Hollister@Sun.COM 	sss = kmem_zalloc(sizeof (*sss), KM_SLEEP);
657810696SDavid.Hollister@Sun.COM 	sss->ss_size = size;
657910696SDavid.Hollister@Sun.COM 	sss->ss_mod_hash = mod_hash_create_strhash("soft_state_bystr",
658010696SDavid.Hollister@Sun.COM 	    hash_sz, mod_hash_null_valdtor);
658110696SDavid.Hollister@Sun.COM 	*state_p = (ddi_soft_state_bystr *)sss;
658210696SDavid.Hollister@Sun.COM 	return (0);
658310696SDavid.Hollister@Sun.COM }
658410696SDavid.Hollister@Sun.COM 
658510696SDavid.Hollister@Sun.COM int
ddi_soft_state_bystr_zalloc(ddi_soft_state_bystr * state,const char * str)658610696SDavid.Hollister@Sun.COM ddi_soft_state_bystr_zalloc(ddi_soft_state_bystr *state, const char *str)
658710696SDavid.Hollister@Sun.COM {
658810696SDavid.Hollister@Sun.COM 	i_ddi_soft_state_bystr	*sss = (i_ddi_soft_state_bystr *)state;
658910696SDavid.Hollister@Sun.COM 	void			*sso;
659010696SDavid.Hollister@Sun.COM 	char			*dup_str;
659110696SDavid.Hollister@Sun.COM 
659210696SDavid.Hollister@Sun.COM 	ASSERT(sss && str && sss->ss_mod_hash);
659310696SDavid.Hollister@Sun.COM 	if ((sss == NULL) || (str == NULL) || (sss->ss_mod_hash == NULL))
659410696SDavid.Hollister@Sun.COM 		return (DDI_FAILURE);
659510696SDavid.Hollister@Sun.COM 	sso = kmem_zalloc(sss->ss_size, KM_SLEEP);
659610696SDavid.Hollister@Sun.COM 	dup_str = i_ddi_strdup((char *)str, KM_SLEEP);
659710696SDavid.Hollister@Sun.COM 	if (mod_hash_insert(sss->ss_mod_hash,
659810696SDavid.Hollister@Sun.COM 	    (mod_hash_key_t)dup_str, (mod_hash_val_t)sso) == 0)
659910696SDavid.Hollister@Sun.COM 		return (DDI_SUCCESS);
660010696SDavid.Hollister@Sun.COM 
660110696SDavid.Hollister@Sun.COM 	/*
660210696SDavid.Hollister@Sun.COM 	 * The only error from an strhash insert is caused by a duplicate key.
660310696SDavid.Hollister@Sun.COM 	 * We refuse to tread on an existing elements, so free and fail.
660410696SDavid.Hollister@Sun.COM 	 */
660510696SDavid.Hollister@Sun.COM 	kmem_free(dup_str, strlen(dup_str) + 1);
660610696SDavid.Hollister@Sun.COM 	kmem_free(sso, sss->ss_size);
660710696SDavid.Hollister@Sun.COM 	return (DDI_FAILURE);
660810696SDavid.Hollister@Sun.COM }
660910696SDavid.Hollister@Sun.COM 
661010696SDavid.Hollister@Sun.COM void *
ddi_soft_state_bystr_get(ddi_soft_state_bystr * state,const char * str)661110696SDavid.Hollister@Sun.COM ddi_soft_state_bystr_get(ddi_soft_state_bystr *state, const char *str)
661210696SDavid.Hollister@Sun.COM {
661310696SDavid.Hollister@Sun.COM 	i_ddi_soft_state_bystr	*sss = (i_ddi_soft_state_bystr *)state;
661410696SDavid.Hollister@Sun.COM 	void			*sso;
661510696SDavid.Hollister@Sun.COM 
661610696SDavid.Hollister@Sun.COM 	ASSERT(sss && str && sss->ss_mod_hash);
661710696SDavid.Hollister@Sun.COM 	if ((sss == NULL) || (str == NULL) || (sss->ss_mod_hash == NULL))
661810696SDavid.Hollister@Sun.COM 		return (NULL);
661910696SDavid.Hollister@Sun.COM 
662010696SDavid.Hollister@Sun.COM 	if (mod_hash_find(sss->ss_mod_hash,
662110696SDavid.Hollister@Sun.COM 	    (mod_hash_key_t)str, (mod_hash_val_t *)&sso) == 0)
662210696SDavid.Hollister@Sun.COM 		return (sso);
662310696SDavid.Hollister@Sun.COM 	return (NULL);
662410696SDavid.Hollister@Sun.COM }
662510696SDavid.Hollister@Sun.COM 
662610696SDavid.Hollister@Sun.COM void
ddi_soft_state_bystr_free(ddi_soft_state_bystr * state,const char * str)662710696SDavid.Hollister@Sun.COM ddi_soft_state_bystr_free(ddi_soft_state_bystr *state, const char *str)
662810696SDavid.Hollister@Sun.COM {
662910696SDavid.Hollister@Sun.COM 	i_ddi_soft_state_bystr	*sss = (i_ddi_soft_state_bystr *)state;
663010696SDavid.Hollister@Sun.COM 	void			*sso;
663110696SDavid.Hollister@Sun.COM 
663210696SDavid.Hollister@Sun.COM 	ASSERT(sss && str && sss->ss_mod_hash);
663310696SDavid.Hollister@Sun.COM 	if ((sss == NULL) || (str == NULL) || (sss->ss_mod_hash == NULL))
663410696SDavid.Hollister@Sun.COM 		return;
663510696SDavid.Hollister@Sun.COM 
663610696SDavid.Hollister@Sun.COM 	(void) mod_hash_remove(sss->ss_mod_hash,
663710696SDavid.Hollister@Sun.COM 	    (mod_hash_key_t)str, (mod_hash_val_t *)&sso);
663810696SDavid.Hollister@Sun.COM 	kmem_free(sso, sss->ss_size);
663910696SDavid.Hollister@Sun.COM }
664010696SDavid.Hollister@Sun.COM 
664110696SDavid.Hollister@Sun.COM void
ddi_soft_state_bystr_fini(ddi_soft_state_bystr ** state_p)664210696SDavid.Hollister@Sun.COM ddi_soft_state_bystr_fini(ddi_soft_state_bystr **state_p)
664310696SDavid.Hollister@Sun.COM {
664410696SDavid.Hollister@Sun.COM 	i_ddi_soft_state_bystr	*sss;
664510696SDavid.Hollister@Sun.COM 
664610696SDavid.Hollister@Sun.COM 	ASSERT(state_p);
664710696SDavid.Hollister@Sun.COM 	if (state_p == NULL)
664810696SDavid.Hollister@Sun.COM 		return;
664910696SDavid.Hollister@Sun.COM 
665010696SDavid.Hollister@Sun.COM 	sss = (i_ddi_soft_state_bystr *)(*state_p);
665110696SDavid.Hollister@Sun.COM 	if (sss == NULL)
665210696SDavid.Hollister@Sun.COM 		return;
665310696SDavid.Hollister@Sun.COM 
665410696SDavid.Hollister@Sun.COM 	ASSERT(sss->ss_mod_hash);
665510696SDavid.Hollister@Sun.COM 	if (sss->ss_mod_hash) {
665610696SDavid.Hollister@Sun.COM 		mod_hash_destroy_strhash(sss->ss_mod_hash);
665710696SDavid.Hollister@Sun.COM 		sss->ss_mod_hash = NULL;
665810696SDavid.Hollister@Sun.COM 	}
665910696SDavid.Hollister@Sun.COM 
666010696SDavid.Hollister@Sun.COM 	kmem_free(sss, sizeof (*sss));
666110696SDavid.Hollister@Sun.COM 	*state_p = NULL;
666210696SDavid.Hollister@Sun.COM }
666310696SDavid.Hollister@Sun.COM 
666410696SDavid.Hollister@Sun.COM /*
666510696SDavid.Hollister@Sun.COM  * The ddi_strid_* routines provide string-to-index management utilities.
666610696SDavid.Hollister@Sun.COM  */
666710696SDavid.Hollister@Sun.COM /* allocate and initialize an strid set */
666810696SDavid.Hollister@Sun.COM int
ddi_strid_init(ddi_strid ** strid_p,int n_items)666910696SDavid.Hollister@Sun.COM ddi_strid_init(ddi_strid **strid_p, int n_items)
667010696SDavid.Hollister@Sun.COM {
667110696SDavid.Hollister@Sun.COM 	i_ddi_strid	*ss;
667210696SDavid.Hollister@Sun.COM 	int		hash_sz;
667310696SDavid.Hollister@Sun.COM 
667410696SDavid.Hollister@Sun.COM 	if (strid_p == NULL)
667510696SDavid.Hollister@Sun.COM 		return (DDI_FAILURE);
667610696SDavid.Hollister@Sun.COM 
667710696SDavid.Hollister@Sun.COM 	/* current implementation is based on hash, convert n_items to hash */
667810696SDavid.Hollister@Sun.COM 	hash_sz = n_items / SS_N_ITEMS_PER_HASH;
667910696SDavid.Hollister@Sun.COM 	if (hash_sz < SS_MIN_HASH_SZ)
668010696SDavid.Hollister@Sun.COM 		hash_sz = SS_MIN_HASH_SZ;
668110696SDavid.Hollister@Sun.COM 	else if (hash_sz > SS_MAX_HASH_SZ)
668210696SDavid.Hollister@Sun.COM 		hash_sz = SS_MAX_HASH_SZ;
668310696SDavid.Hollister@Sun.COM 
668410696SDavid.Hollister@Sun.COM 	ss = kmem_alloc(sizeof (*ss), KM_SLEEP);
668511068SJohn.Danielson@Sun.COM 	ss->strid_chunksz = n_items;
668611068SJohn.Danielson@Sun.COM 	ss->strid_spacesz = n_items;
668710696SDavid.Hollister@Sun.COM 	ss->strid_space = id_space_create("strid", 1, n_items);
668810696SDavid.Hollister@Sun.COM 	ss->strid_bystr = mod_hash_create_strhash("strid_bystr", hash_sz,
668910696SDavid.Hollister@Sun.COM 	    mod_hash_null_valdtor);
669010696SDavid.Hollister@Sun.COM 	ss->strid_byid = mod_hash_create_idhash("strid_byid", hash_sz,
669110696SDavid.Hollister@Sun.COM 	    mod_hash_null_valdtor);
669210696SDavid.Hollister@Sun.COM 	*strid_p = (ddi_strid *)ss;
669310696SDavid.Hollister@Sun.COM 	return (DDI_SUCCESS);
669410696SDavid.Hollister@Sun.COM }
669510696SDavid.Hollister@Sun.COM 
669610696SDavid.Hollister@Sun.COM /* allocate an id mapping within the specified set for str, return id */
669710696SDavid.Hollister@Sun.COM static id_t
i_ddi_strid_alloc(ddi_strid * strid,char * str)669811068SJohn.Danielson@Sun.COM i_ddi_strid_alloc(ddi_strid *strid, char *str)
669910696SDavid.Hollister@Sun.COM {
670010696SDavid.Hollister@Sun.COM 	i_ddi_strid	*ss = (i_ddi_strid *)strid;
670110696SDavid.Hollister@Sun.COM 	id_t		id;
670210696SDavid.Hollister@Sun.COM 	char		*s;
670310696SDavid.Hollister@Sun.COM 
670410696SDavid.Hollister@Sun.COM 	ASSERT(ss && str);
670510696SDavid.Hollister@Sun.COM 	if ((ss == NULL) || (str == NULL))
670610696SDavid.Hollister@Sun.COM 		return (0);
670710696SDavid.Hollister@Sun.COM 
670810696SDavid.Hollister@Sun.COM 	/*
670910696SDavid.Hollister@Sun.COM 	 * Allocate an id using VM_FIRSTFIT in order to keep allocated id
671010696SDavid.Hollister@Sun.COM 	 * range as compressed as possible.  This is important to minimize
671110696SDavid.Hollister@Sun.COM 	 * the amount of space used when the id is used as a ddi_soft_state
671210696SDavid.Hollister@Sun.COM 	 * index by the caller.
671310696SDavid.Hollister@Sun.COM 	 *
671411068SJohn.Danielson@Sun.COM 	 * If the id list is exhausted, increase the size of the list
671511068SJohn.Danielson@Sun.COM 	 * by the chuck size specified in ddi_strid_init and reattempt
671611068SJohn.Danielson@Sun.COM 	 * the allocation
671711068SJohn.Danielson@Sun.COM 	 */
671811068SJohn.Danielson@Sun.COM 	if ((id = id_allocff_nosleep(ss->strid_space)) == (id_t)-1) {
671911068SJohn.Danielson@Sun.COM 		id_space_extend(ss->strid_space, ss->strid_spacesz,
672011068SJohn.Danielson@Sun.COM 		    ss->strid_spacesz + ss->strid_chunksz);
672111068SJohn.Danielson@Sun.COM 		ss->strid_spacesz += ss->strid_chunksz;
672211068SJohn.Danielson@Sun.COM 		if ((id = id_allocff_nosleep(ss->strid_space)) == (id_t)-1)
672310696SDavid.Hollister@Sun.COM 			return (0);
672410696SDavid.Hollister@Sun.COM 	}
672510696SDavid.Hollister@Sun.COM 
672610696SDavid.Hollister@Sun.COM 	/*
672710696SDavid.Hollister@Sun.COM 	 * NOTE: since we create and destroy in unison we can save space by
672810696SDavid.Hollister@Sun.COM 	 * using bystr key as the byid value.  This means destroy must occur
672910696SDavid.Hollister@Sun.COM 	 * in (byid, bystr) order.
673010696SDavid.Hollister@Sun.COM 	 */
673110696SDavid.Hollister@Sun.COM 	s = i_ddi_strdup(str, KM_SLEEP);
673210696SDavid.Hollister@Sun.COM 	if (mod_hash_insert(ss->strid_bystr, (mod_hash_key_t)s,
673310696SDavid.Hollister@Sun.COM 	    (mod_hash_val_t)(intptr_t)id) != 0) {
673410696SDavid.Hollister@Sun.COM 		ddi_strid_free(strid, id);
673510696SDavid.Hollister@Sun.COM 		return (0);
673610696SDavid.Hollister@Sun.COM 	}
673710696SDavid.Hollister@Sun.COM 	if (mod_hash_insert(ss->strid_byid, (mod_hash_key_t)(intptr_t)id,
673810696SDavid.Hollister@Sun.COM 	    (mod_hash_val_t)s) != 0) {
673910696SDavid.Hollister@Sun.COM 		ddi_strid_free(strid, id);
674010696SDavid.Hollister@Sun.COM 		return (0);
674110696SDavid.Hollister@Sun.COM 	}
674210696SDavid.Hollister@Sun.COM 
674310696SDavid.Hollister@Sun.COM 	/* NOTE: s if freed on mod_hash_destroy by mod_hash_strval_dtor */
674410696SDavid.Hollister@Sun.COM 	return (id);
674510696SDavid.Hollister@Sun.COM }
674610696SDavid.Hollister@Sun.COM 
674710696SDavid.Hollister@Sun.COM /* allocate an id mapping within the specified set for str, return id */
674810696SDavid.Hollister@Sun.COM id_t
ddi_strid_alloc(ddi_strid * strid,char * str)674910696SDavid.Hollister@Sun.COM ddi_strid_alloc(ddi_strid *strid, char *str)
675010696SDavid.Hollister@Sun.COM {
675111068SJohn.Danielson@Sun.COM 	return (i_ddi_strid_alloc(strid, str));
675210696SDavid.Hollister@Sun.COM }
675310696SDavid.Hollister@Sun.COM 
675410696SDavid.Hollister@Sun.COM /* return the id within the specified strid given the str */
675510696SDavid.Hollister@Sun.COM id_t
ddi_strid_str2id(ddi_strid * strid,char * str)675610696SDavid.Hollister@Sun.COM ddi_strid_str2id(ddi_strid *strid, char *str)
675710696SDavid.Hollister@Sun.COM {
675810696SDavid.Hollister@Sun.COM 	i_ddi_strid	*ss = (i_ddi_strid *)strid;
675910696SDavid.Hollister@Sun.COM 	id_t		id = 0;
676010696SDavid.Hollister@Sun.COM 	mod_hash_val_t	hv;
676110696SDavid.Hollister@Sun.COM 
676210696SDavid.Hollister@Sun.COM 	ASSERT(ss && str);
676310696SDavid.Hollister@Sun.COM 	if (ss && str && (mod_hash_find(ss->strid_bystr,
676410696SDavid.Hollister@Sun.COM 	    (mod_hash_key_t)str, &hv) == 0))
676510696SDavid.Hollister@Sun.COM 		id = (int)(intptr_t)hv;
676610696SDavid.Hollister@Sun.COM 	return (id);
676710696SDavid.Hollister@Sun.COM }
676810696SDavid.Hollister@Sun.COM 
676910696SDavid.Hollister@Sun.COM /* return str within the specified strid given the id */
677010696SDavid.Hollister@Sun.COM char *
ddi_strid_id2str(ddi_strid * strid,id_t id)677110696SDavid.Hollister@Sun.COM ddi_strid_id2str(ddi_strid *strid, id_t id)
677210696SDavid.Hollister@Sun.COM {
677310696SDavid.Hollister@Sun.COM 	i_ddi_strid	*ss = (i_ddi_strid *)strid;
677410696SDavid.Hollister@Sun.COM 	char		*str = NULL;
677510696SDavid.Hollister@Sun.COM 	mod_hash_val_t	hv;
677610696SDavid.Hollister@Sun.COM 
677710696SDavid.Hollister@Sun.COM 	ASSERT(ss && id > 0);
677810696SDavid.Hollister@Sun.COM 	if (ss && (id > 0) && (mod_hash_find(ss->strid_byid,
677910696SDavid.Hollister@Sun.COM 	    (mod_hash_key_t)(uintptr_t)id, &hv) == 0))
678010696SDavid.Hollister@Sun.COM 		str = (char *)hv;
678110696SDavid.Hollister@Sun.COM 	return (str);
678210696SDavid.Hollister@Sun.COM }
678310696SDavid.Hollister@Sun.COM 
678410696SDavid.Hollister@Sun.COM /* free the id mapping within the specified strid */
678510696SDavid.Hollister@Sun.COM void
ddi_strid_free(ddi_strid * strid,id_t id)678610696SDavid.Hollister@Sun.COM ddi_strid_free(ddi_strid *strid, id_t id)
678710696SDavid.Hollister@Sun.COM {
678810696SDavid.Hollister@Sun.COM 	i_ddi_strid	*ss = (i_ddi_strid *)strid;
678910696SDavid.Hollister@Sun.COM 	char		*str;
679010696SDavid.Hollister@Sun.COM 
679110696SDavid.Hollister@Sun.COM 	ASSERT(ss && id > 0);
679210696SDavid.Hollister@Sun.COM 	if ((ss == NULL) || (id <= 0))
679310696SDavid.Hollister@Sun.COM 		return;
679410696SDavid.Hollister@Sun.COM 
679510696SDavid.Hollister@Sun.COM 	/* bystr key is byid value: destroy order must be (byid, bystr) */
679610696SDavid.Hollister@Sun.COM 	str = ddi_strid_id2str(strid, id);
679710696SDavid.Hollister@Sun.COM 	(void) mod_hash_destroy(ss->strid_byid, (mod_hash_key_t)(uintptr_t)id);
679810696SDavid.Hollister@Sun.COM 	id_free(ss->strid_space, id);
679910696SDavid.Hollister@Sun.COM 
680010696SDavid.Hollister@Sun.COM 	if (str)
680110696SDavid.Hollister@Sun.COM 		(void) mod_hash_destroy(ss->strid_bystr, (mod_hash_key_t)str);
680210696SDavid.Hollister@Sun.COM }
680310696SDavid.Hollister@Sun.COM 
680410696SDavid.Hollister@Sun.COM /* destroy the strid set */
680510696SDavid.Hollister@Sun.COM void
ddi_strid_fini(ddi_strid ** strid_p)680610696SDavid.Hollister@Sun.COM ddi_strid_fini(ddi_strid **strid_p)
680710696SDavid.Hollister@Sun.COM {
680810696SDavid.Hollister@Sun.COM 	i_ddi_strid	*ss;
680910696SDavid.Hollister@Sun.COM 
681010696SDavid.Hollister@Sun.COM 	ASSERT(strid_p);
681110696SDavid.Hollister@Sun.COM 	if (strid_p == NULL)
681210696SDavid.Hollister@Sun.COM 		return;
681310696SDavid.Hollister@Sun.COM 
681410696SDavid.Hollister@Sun.COM 	ss = (i_ddi_strid *)(*strid_p);
681510696SDavid.Hollister@Sun.COM 	if (ss == NULL)
681610696SDavid.Hollister@Sun.COM 		return;
681710696SDavid.Hollister@Sun.COM 
681810696SDavid.Hollister@Sun.COM 	/* bystr key is byid value: destroy order must be (byid, bystr) */
681910696SDavid.Hollister@Sun.COM 	if (ss->strid_byid)
682010696SDavid.Hollister@Sun.COM 		mod_hash_destroy_hash(ss->strid_byid);
682110696SDavid.Hollister@Sun.COM 	if (ss->strid_byid)
682210696SDavid.Hollister@Sun.COM 		mod_hash_destroy_hash(ss->strid_bystr);
682310696SDavid.Hollister@Sun.COM 	if (ss->strid_space)
682410696SDavid.Hollister@Sun.COM 		id_space_destroy(ss->strid_space);
682510696SDavid.Hollister@Sun.COM 	kmem_free(ss, sizeof (*ss));
682610696SDavid.Hollister@Sun.COM 	*strid_p = NULL;
682710696SDavid.Hollister@Sun.COM }
682810696SDavid.Hollister@Sun.COM 
6829439Scth /*
6830439Scth  * This sets the devi_addr entry in the dev_info structure 'dip' to 'name'.
6831439Scth  * Storage is double buffered to prevent updates during devi_addr use -
6832439Scth  * double buffering is adaquate for reliable ddi_deviname() consumption.
6833439Scth  * The double buffer is not freed until dev_info structure destruction
6834439Scth  * (by i_ddi_free_node).
68350Sstevel@tonic-gate  */
68360Sstevel@tonic-gate void
ddi_set_name_addr(dev_info_t * dip,char * name)68370Sstevel@tonic-gate ddi_set_name_addr(dev_info_t *dip, char *name)
68380Sstevel@tonic-gate {
6839439Scth 	char	*buf = DEVI(dip)->devi_addr_buf;
6840439Scth 	char	*newaddr;
6841439Scth 
6842439Scth 	if (buf == NULL) {
6843439Scth 		buf = kmem_zalloc(2 * MAXNAMELEN, KM_SLEEP);
6844439Scth 		DEVI(dip)->devi_addr_buf = buf;
6845439Scth 	}
6846439Scth 
6847439Scth 	if (name) {
6848439Scth 		ASSERT(strlen(name) < MAXNAMELEN);
6849439Scth 		newaddr = (DEVI(dip)->devi_addr == buf) ?
6850439Scth 		    (buf + MAXNAMELEN) : buf;
6851439Scth 		(void) strlcpy(newaddr, name, MAXNAMELEN);
6852439Scth 	} else
6853439Scth 		newaddr = NULL;
6854439Scth 
6855439Scth 	DEVI(dip)->devi_addr = newaddr;
68560Sstevel@tonic-gate }
68570Sstevel@tonic-gate 
68580Sstevel@tonic-gate char *
ddi_get_name_addr(dev_info_t * dip)68590Sstevel@tonic-gate ddi_get_name_addr(dev_info_t *dip)
68600Sstevel@tonic-gate {
68610Sstevel@tonic-gate 	return (DEVI(dip)->devi_addr);
68620Sstevel@tonic-gate }
68630Sstevel@tonic-gate 
68640Sstevel@tonic-gate void
ddi_set_parent_data(dev_info_t * dip,void * pd)68650Sstevel@tonic-gate ddi_set_parent_data(dev_info_t *dip, void *pd)
68660Sstevel@tonic-gate {
68670Sstevel@tonic-gate 	DEVI(dip)->devi_parent_data = pd;
68680Sstevel@tonic-gate }
68690Sstevel@tonic-gate 
68700Sstevel@tonic-gate void *
ddi_get_parent_data(dev_info_t * dip)68710Sstevel@tonic-gate ddi_get_parent_data(dev_info_t *dip)
68720Sstevel@tonic-gate {
68730Sstevel@tonic-gate 	return (DEVI(dip)->devi_parent_data);
68740Sstevel@tonic-gate }
68750Sstevel@tonic-gate 
68760Sstevel@tonic-gate /*
68778459SJerry.Gilliam@Sun.COM  * ddi_name_to_major: returns the major number of a named module,
68788459SJerry.Gilliam@Sun.COM  * derived from the current driver alias binding.
68798459SJerry.Gilliam@Sun.COM  *
68808459SJerry.Gilliam@Sun.COM  * Caveat: drivers should avoid the use of this function, in particular
68818459SJerry.Gilliam@Sun.COM  * together with ddi_get_name/ddi_binding name, as per
68828459SJerry.Gilliam@Sun.COM  *	major = ddi_name_to_major(ddi_get_name(devi));
68838459SJerry.Gilliam@Sun.COM  * ddi_name_to_major() relies on the state of the device/alias binding,
68848459SJerry.Gilliam@Sun.COM  * which can and does change dynamically as aliases are administered
68858459SJerry.Gilliam@Sun.COM  * over time.  An attached device instance cannot rely on the major
68868459SJerry.Gilliam@Sun.COM  * number returned by ddi_name_to_major() to match its own major number.
68878459SJerry.Gilliam@Sun.COM  *
68888459SJerry.Gilliam@Sun.COM  * For driver use, ddi_driver_major() reliably returns the major number
68898459SJerry.Gilliam@Sun.COM  * for the module to which the device was bound at attach time over
68908459SJerry.Gilliam@Sun.COM  * the life of the instance.
68918459SJerry.Gilliam@Sun.COM  *	major = ddi_driver_major(dev_info_t *)
68920Sstevel@tonic-gate  */
68930Sstevel@tonic-gate major_t
ddi_name_to_major(char * name)68940Sstevel@tonic-gate ddi_name_to_major(char *name)
68950Sstevel@tonic-gate {
68960Sstevel@tonic-gate 	return (mod_name_to_major(name));
68970Sstevel@tonic-gate }
68980Sstevel@tonic-gate 
68990Sstevel@tonic-gate /*
69000Sstevel@tonic-gate  * ddi_major_to_name: Returns the module name bound to a major number.
69010Sstevel@tonic-gate  */
69020Sstevel@tonic-gate char *
ddi_major_to_name(major_t major)69030Sstevel@tonic-gate ddi_major_to_name(major_t major)
69040Sstevel@tonic-gate {
69050Sstevel@tonic-gate 	return (mod_major_to_name(major));
69060Sstevel@tonic-gate }
69070Sstevel@tonic-gate 
69080Sstevel@tonic-gate /*
69090Sstevel@tonic-gate  * Return the name of the devinfo node pointed at by 'dip' in the buffer
69100Sstevel@tonic-gate  * pointed at by 'name.'  A devinfo node is named as a result of calling
69110Sstevel@tonic-gate  * ddi_initchild().
69120Sstevel@tonic-gate  *
69130Sstevel@tonic-gate  * Note: the driver must be held before calling this function!
69140Sstevel@tonic-gate  */
69150Sstevel@tonic-gate char *
ddi_deviname(dev_info_t * dip,char * name)69160Sstevel@tonic-gate ddi_deviname(dev_info_t *dip, char *name)
69170Sstevel@tonic-gate {
69180Sstevel@tonic-gate 	char *addrname;
69190Sstevel@tonic-gate 	char none = '\0';
69200Sstevel@tonic-gate 
69210Sstevel@tonic-gate 	if (dip == ddi_root_node()) {
69220Sstevel@tonic-gate 		*name = '\0';
69230Sstevel@tonic-gate 		return (name);
69240Sstevel@tonic-gate 	}
69250Sstevel@tonic-gate 
69264145Scth 	if (i_ddi_node_state(dip) < DS_BOUND) {
69270Sstevel@tonic-gate 		addrname = &none;
69280Sstevel@tonic-gate 	} else {
69294145Scth 		/*
69304145Scth 		 * Use ddi_get_name_addr() without checking state so we get
69314145Scth 		 * a unit-address if we are called after ddi_set_name_addr()
69324145Scth 		 * by nexus DDI_CTL_INITCHILD code, but before completing
69334145Scth 		 * node promotion to DS_INITIALIZED.  We currently have
69344145Scth 		 * two situations where we are called in this state:
69354145Scth 		 *   o  For framework processing of a path-oriented alias.
69364145Scth 		 *   o  If a SCSA nexus driver calls ddi_devid_register()
69374145Scth 		 *	from it's tran_tgt_init(9E) implementation.
69384145Scth 		 */
69390Sstevel@tonic-gate 		addrname = ddi_get_name_addr(dip);
69404145Scth 		if (addrname == NULL)
69414145Scth 			addrname = &none;
69420Sstevel@tonic-gate 	}
69430Sstevel@tonic-gate 
69440Sstevel@tonic-gate 	if (*addrname == '\0') {
69450Sstevel@tonic-gate 		(void) sprintf(name, "/%s", ddi_node_name(dip));
69460Sstevel@tonic-gate 	} else {
69470Sstevel@tonic-gate 		(void) sprintf(name, "/%s@%s", ddi_node_name(dip), addrname);
69480Sstevel@tonic-gate 	}
69490Sstevel@tonic-gate 
69500Sstevel@tonic-gate 	return (name);
69510Sstevel@tonic-gate }
69520Sstevel@tonic-gate 
69530Sstevel@tonic-gate /*
69540Sstevel@tonic-gate  * Spits out the name of device node, typically name@addr, for a given node,
69550Sstevel@tonic-gate  * using the driver name, not the nodename.
69560Sstevel@tonic-gate  *
69570Sstevel@tonic-gate  * Used by match_parent. Not to be used elsewhere.
69580Sstevel@tonic-gate  */
69590Sstevel@tonic-gate char *
i_ddi_parname(dev_info_t * dip,char * name)69600Sstevel@tonic-gate i_ddi_parname(dev_info_t *dip, char *name)
69610Sstevel@tonic-gate {
69620Sstevel@tonic-gate 	char *addrname;
69630Sstevel@tonic-gate 
69640Sstevel@tonic-gate 	if (dip == ddi_root_node()) {
69650Sstevel@tonic-gate 		*name = '\0';
69660Sstevel@tonic-gate 		return (name);
69670Sstevel@tonic-gate 	}
69680Sstevel@tonic-gate 
69690Sstevel@tonic-gate 	ASSERT(i_ddi_node_state(dip) >= DS_INITIALIZED);
69700Sstevel@tonic-gate 
69710Sstevel@tonic-gate 	if (*(addrname = ddi_get_name_addr(dip)) == '\0')
69720Sstevel@tonic-gate 		(void) sprintf(name, "%s", ddi_binding_name(dip));
69730Sstevel@tonic-gate 	else
69740Sstevel@tonic-gate 		(void) sprintf(name, "%s@%s", ddi_binding_name(dip), addrname);
69750Sstevel@tonic-gate 	return (name);
69760Sstevel@tonic-gate }
69770Sstevel@tonic-gate 
69780Sstevel@tonic-gate static char *
pathname_work(dev_info_t * dip,char * path)69790Sstevel@tonic-gate pathname_work(dev_info_t *dip, char *path)
69800Sstevel@tonic-gate {
69810Sstevel@tonic-gate 	char *bp;
69820Sstevel@tonic-gate 
69830Sstevel@tonic-gate 	if (dip == ddi_root_node()) {
69840Sstevel@tonic-gate 		*path = '\0';
69850Sstevel@tonic-gate 		return (path);
69860Sstevel@tonic-gate 	}
69870Sstevel@tonic-gate 	(void) pathname_work(ddi_get_parent(dip), path);
69880Sstevel@tonic-gate 	bp = path + strlen(path);
69890Sstevel@tonic-gate 	(void) ddi_deviname(dip, bp);
69900Sstevel@tonic-gate 	return (path);
69910Sstevel@tonic-gate }
69920Sstevel@tonic-gate 
69930Sstevel@tonic-gate char *
ddi_pathname(dev_info_t * dip,char * path)69940Sstevel@tonic-gate ddi_pathname(dev_info_t *dip, char *path)
69950Sstevel@tonic-gate {
69960Sstevel@tonic-gate 	return (pathname_work(dip, path));
69970Sstevel@tonic-gate }
69980Sstevel@tonic-gate 
69997627SChris.Horne@Sun.COM char *
ddi_pathname_minor(struct ddi_minor_data * dmdp,char * path)70007627SChris.Horne@Sun.COM ddi_pathname_minor(struct ddi_minor_data *dmdp, char *path)
70017627SChris.Horne@Sun.COM {
70027627SChris.Horne@Sun.COM 	if (dmdp->dip == NULL)
70037627SChris.Horne@Sun.COM 		*path = '\0';
70047627SChris.Horne@Sun.COM 	else {
70057627SChris.Horne@Sun.COM 		(void) ddi_pathname(dmdp->dip, path);
70067627SChris.Horne@Sun.COM 		if (dmdp->ddm_name) {
70077627SChris.Horne@Sun.COM 			(void) strcat(path, ":");
70087627SChris.Horne@Sun.COM 			(void) strcat(path, dmdp->ddm_name);
70097627SChris.Horne@Sun.COM 		}
70107627SChris.Horne@Sun.COM 	}
70117627SChris.Horne@Sun.COM 	return (path);
70127627SChris.Horne@Sun.COM }
70137627SChris.Horne@Sun.COM 
70147413SJaven.Wu@Sun.COM static char *
pathname_work_obp(dev_info_t * dip,char * path)70157413SJaven.Wu@Sun.COM pathname_work_obp(dev_info_t *dip, char *path)
70167413SJaven.Wu@Sun.COM {
70177413SJaven.Wu@Sun.COM 	char *bp;
70187413SJaven.Wu@Sun.COM 	char *obp_path;
70197413SJaven.Wu@Sun.COM 
70207413SJaven.Wu@Sun.COM 	/*
70217413SJaven.Wu@Sun.COM 	 * look up the "obp-path" property, return the path if it exists
70227413SJaven.Wu@Sun.COM 	 */
70237413SJaven.Wu@Sun.COM 	if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
70247413SJaven.Wu@Sun.COM 	    "obp-path", &obp_path) == DDI_PROP_SUCCESS) {
70257413SJaven.Wu@Sun.COM 		(void) strcpy(path, obp_path);
70267413SJaven.Wu@Sun.COM 		ddi_prop_free(obp_path);
70277413SJaven.Wu@Sun.COM 		return (path);
70287413SJaven.Wu@Sun.COM 	}
70297413SJaven.Wu@Sun.COM 
70307413SJaven.Wu@Sun.COM 	/*
70317413SJaven.Wu@Sun.COM 	 * stop at root, no obp path
70327413SJaven.Wu@Sun.COM 	 */
70337413SJaven.Wu@Sun.COM 	if (dip == ddi_root_node()) {
70347413SJaven.Wu@Sun.COM 		return (NULL);
70357413SJaven.Wu@Sun.COM 	}
70367413SJaven.Wu@Sun.COM 
70377413SJaven.Wu@Sun.COM 	obp_path = pathname_work_obp(ddi_get_parent(dip), path);
70387413SJaven.Wu@Sun.COM 	if (obp_path == NULL)
70397413SJaven.Wu@Sun.COM 		return (NULL);
70407413SJaven.Wu@Sun.COM 
70417413SJaven.Wu@Sun.COM 	/*
70427413SJaven.Wu@Sun.COM 	 * append our component to parent's obp path
70437413SJaven.Wu@Sun.COM 	 */
70447413SJaven.Wu@Sun.COM 	bp = path + strlen(path);
70457413SJaven.Wu@Sun.COM 	if (*(bp - 1) != '/')
70467413SJaven.Wu@Sun.COM 		(void) strcat(bp++, "/");
70477413SJaven.Wu@Sun.COM 	(void) ddi_deviname(dip, bp);
70487413SJaven.Wu@Sun.COM 	return (path);
70497413SJaven.Wu@Sun.COM }
70507413SJaven.Wu@Sun.COM 
70517413SJaven.Wu@Sun.COM /*
70527413SJaven.Wu@Sun.COM  * return the 'obp-path' based path for the given node, or NULL if the node
70537413SJaven.Wu@Sun.COM  * does not have a different obp path. NOTE: Unlike ddi_pathname, this
70547413SJaven.Wu@Sun.COM  * function can't be called from interrupt context (since we need to
70557413SJaven.Wu@Sun.COM  * lookup a string property).
70567413SJaven.Wu@Sun.COM  */
70577413SJaven.Wu@Sun.COM char *
ddi_pathname_obp(dev_info_t * dip,char * path)70587413SJaven.Wu@Sun.COM ddi_pathname_obp(dev_info_t *dip, char *path)
70597413SJaven.Wu@Sun.COM {
70607413SJaven.Wu@Sun.COM 	ASSERT(!servicing_interrupt());
70617413SJaven.Wu@Sun.COM 	if (dip == NULL || path == NULL)
70627413SJaven.Wu@Sun.COM 		return (NULL);
70637413SJaven.Wu@Sun.COM 
70647413SJaven.Wu@Sun.COM 	/* split work into a separate function to aid debugging */
70657413SJaven.Wu@Sun.COM 	return (pathname_work_obp(dip, path));
70667413SJaven.Wu@Sun.COM }
70677413SJaven.Wu@Sun.COM 
70687413SJaven.Wu@Sun.COM int
ddi_pathname_obp_set(dev_info_t * dip,char * component)70697413SJaven.Wu@Sun.COM ddi_pathname_obp_set(dev_info_t *dip, char *component)
70707413SJaven.Wu@Sun.COM {
70717413SJaven.Wu@Sun.COM 	dev_info_t *pdip;
70727853SJaven.Wu@Sun.COM 	char *obp_path = NULL;
70737853SJaven.Wu@Sun.COM 	int rc = DDI_FAILURE;
70747413SJaven.Wu@Sun.COM 
70757413SJaven.Wu@Sun.COM 	if (dip == NULL)
70767413SJaven.Wu@Sun.COM 		return (DDI_FAILURE);
70777853SJaven.Wu@Sun.COM 
70787853SJaven.Wu@Sun.COM 	obp_path = kmem_zalloc(MAXPATHLEN, KM_SLEEP);
70797853SJaven.Wu@Sun.COM 
70807413SJaven.Wu@Sun.COM 	pdip = ddi_get_parent(dip);
70817413SJaven.Wu@Sun.COM 
70827413SJaven.Wu@Sun.COM 	if (ddi_pathname_obp(pdip, obp_path) == NULL) {
70837413SJaven.Wu@Sun.COM 		(void) ddi_pathname(pdip, obp_path);
70847413SJaven.Wu@Sun.COM 	}
70857413SJaven.Wu@Sun.COM 
70867413SJaven.Wu@Sun.COM 	if (component) {
70877853SJaven.Wu@Sun.COM 		(void) strncat(obp_path, "/", MAXPATHLEN);
70887853SJaven.Wu@Sun.COM 		(void) strncat(obp_path, component, MAXPATHLEN);
70897853SJaven.Wu@Sun.COM 	}
70907853SJaven.Wu@Sun.COM 	rc = ndi_prop_update_string(DDI_DEV_T_NONE, dip, "obp-path",
70917853SJaven.Wu@Sun.COM 	    obp_path);
70927853SJaven.Wu@Sun.COM 
70937853SJaven.Wu@Sun.COM 	if (obp_path)
70947853SJaven.Wu@Sun.COM 		kmem_free(obp_path, MAXPATHLEN);
70957853SJaven.Wu@Sun.COM 
70967853SJaven.Wu@Sun.COM 	return (rc);
70977413SJaven.Wu@Sun.COM }
70987413SJaven.Wu@Sun.COM 
70990Sstevel@tonic-gate /*
71000Sstevel@tonic-gate  * Given a dev_t, return the pathname of the corresponding device in the
71010Sstevel@tonic-gate  * buffer pointed at by "path."  The buffer is assumed to be large enough
71020Sstevel@tonic-gate  * to hold the pathname of the device (MAXPATHLEN).
71030Sstevel@tonic-gate  *
71040Sstevel@tonic-gate  * The pathname of a device is the pathname of the devinfo node to which
71050Sstevel@tonic-gate  * the device "belongs," concatenated with the character ':' and the name
71060Sstevel@tonic-gate  * of the minor node corresponding to the dev_t.  If spec_type is 0 then
71070Sstevel@tonic-gate  * just the pathname of the devinfo node is returned without driving attach
71080Sstevel@tonic-gate  * of that node.  For a non-zero spec_type, an attach is performed and a
71090Sstevel@tonic-gate  * search of the minor list occurs.
71100Sstevel@tonic-gate  *
71110Sstevel@tonic-gate  * It is possible that the path associated with the dev_t is not
71120Sstevel@tonic-gate  * currently available in the devinfo tree.  In order to have a
71130Sstevel@tonic-gate  * dev_t, a device must have been discovered before, which means
71140Sstevel@tonic-gate  * that the path is always in the instance tree.  The one exception
71150Sstevel@tonic-gate  * to this is if the dev_t is associated with a pseudo driver, in
71160Sstevel@tonic-gate  * which case the device must exist on the pseudo branch of the
71170Sstevel@tonic-gate  * devinfo tree as a result of parsing .conf files.
71180Sstevel@tonic-gate  */
71190Sstevel@tonic-gate int
ddi_dev_pathname(dev_t devt,int spec_type,char * path)71200Sstevel@tonic-gate ddi_dev_pathname(dev_t devt, int spec_type, char *path)
71210Sstevel@tonic-gate {
71227224Scth 	int		circ;
71230Sstevel@tonic-gate 	major_t		major = getmajor(devt);
71240Sstevel@tonic-gate 	int		instance;
71250Sstevel@tonic-gate 	dev_info_t	*dip;
71260Sstevel@tonic-gate 	char		*minorname;
71270Sstevel@tonic-gate 	char		*drvname;
71280Sstevel@tonic-gate 
71290Sstevel@tonic-gate 	if (major >= devcnt)
71300Sstevel@tonic-gate 		goto fail;
71310Sstevel@tonic-gate 	if (major == clone_major) {
71320Sstevel@tonic-gate 		/* clone has no minor nodes, manufacture the path here */
71330Sstevel@tonic-gate 		if ((drvname = ddi_major_to_name(getminor(devt))) == NULL)
71340Sstevel@tonic-gate 			goto fail;
71350Sstevel@tonic-gate 
71360Sstevel@tonic-gate 		(void) snprintf(path, MAXPATHLEN, "%s:%s", CLONE_PATH, drvname);
71370Sstevel@tonic-gate 		return (DDI_SUCCESS);
71380Sstevel@tonic-gate 	}
71390Sstevel@tonic-gate 
71400Sstevel@tonic-gate 	/* extract instance from devt (getinfo(9E) DDI_INFO_DEVT2INSTANCE). */
71410Sstevel@tonic-gate 	if ((instance = dev_to_instance(devt)) == -1)
71420Sstevel@tonic-gate 		goto fail;
71430Sstevel@tonic-gate 
71440Sstevel@tonic-gate 	/* reconstruct the path given the major/instance */
71450Sstevel@tonic-gate 	if (e_ddi_majorinstance_to_path(major, instance, path) != DDI_SUCCESS)
71460Sstevel@tonic-gate 		goto fail;
71470Sstevel@tonic-gate 
71480Sstevel@tonic-gate 	/* if spec_type given we must drive attach and search minor nodes */
71490Sstevel@tonic-gate 	if ((spec_type == S_IFCHR) || (spec_type == S_IFBLK)) {
71500Sstevel@tonic-gate 		/* attach the path so we can search minors */
71510Sstevel@tonic-gate 		if ((dip = e_ddi_hold_devi_by_path(path, 0)) == NULL)
71520Sstevel@tonic-gate 			goto fail;
71530Sstevel@tonic-gate 
71540Sstevel@tonic-gate 		/* Add minorname to path. */
71557224Scth 		ndi_devi_enter(dip, &circ);
71560Sstevel@tonic-gate 		minorname = i_ddi_devtspectype_to_minorname(dip,
71570Sstevel@tonic-gate 		    devt, spec_type);
71580Sstevel@tonic-gate 		if (minorname) {
71590Sstevel@tonic-gate 			(void) strcat(path, ":");
71600Sstevel@tonic-gate 			(void) strcat(path, minorname);
71610Sstevel@tonic-gate 		}
71627224Scth 		ndi_devi_exit(dip, circ);
71630Sstevel@tonic-gate 		ddi_release_devi(dip);
71640Sstevel@tonic-gate 		if (minorname == NULL)
71650Sstevel@tonic-gate 			goto fail;
71660Sstevel@tonic-gate 	}
71670Sstevel@tonic-gate 	ASSERT(strlen(path) < MAXPATHLEN);
71680Sstevel@tonic-gate 	return (DDI_SUCCESS);
71690Sstevel@tonic-gate 
71700Sstevel@tonic-gate fail:	*path = 0;
71710Sstevel@tonic-gate 	return (DDI_FAILURE);
71720Sstevel@tonic-gate }
71730Sstevel@tonic-gate 
71740Sstevel@tonic-gate /*
71750Sstevel@tonic-gate  * Given a major number and an instance, return the path.
71760Sstevel@tonic-gate  * This interface does NOT drive attach.
71770Sstevel@tonic-gate  */
71780Sstevel@tonic-gate int
e_ddi_majorinstance_to_path(major_t major,int instance,char * path)71790Sstevel@tonic-gate e_ddi_majorinstance_to_path(major_t major, int instance, char *path)
71800Sstevel@tonic-gate {
7181349Scth 	struct devnames *dnp;
71820Sstevel@tonic-gate 	dev_info_t	*dip;
71830Sstevel@tonic-gate 
7184349Scth 	if ((major >= devcnt) || (instance == -1)) {
7185349Scth 		*path = 0;
7186349Scth 		return (DDI_FAILURE);
7187349Scth 	}
7188349Scth 
71890Sstevel@tonic-gate 	/* look for the major/instance in the instance tree */
71900Sstevel@tonic-gate 	if (e_ddi_instance_majorinstance_to_path(major, instance,
7191349Scth 	    path) == DDI_SUCCESS) {
7192349Scth 		ASSERT(strlen(path) < MAXPATHLEN);
7193349Scth 		return (DDI_SUCCESS);
7194349Scth 	}
7195349Scth 
7196349Scth 	/*
7197349Scth 	 * Not in instance tree, find the instance on the per driver list and
7198349Scth 	 * construct path to instance via ddi_pathname(). This is how paths
7199349Scth 	 * down the 'pseudo' branch are constructed.
7200349Scth 	 */
7201349Scth 	dnp = &(devnamesp[major]);
7202349Scth 	LOCK_DEV_OPS(&(dnp->dn_lock));
7203349Scth 	for (dip = dnp->dn_head; dip;
7204349Scth 	    dip = (dev_info_t *)DEVI(dip)->devi_next) {
7205349Scth 		/* Skip if instance does not match. */
7206349Scth 		if (DEVI(dip)->devi_instance != instance)
7207349Scth 			continue;
7208349Scth 
7209349Scth 		/*
7210349Scth 		 * An ndi_hold_devi() does not prevent DS_INITIALIZED->DS_BOUND
7211349Scth 		 * node demotion, so it is not an effective way of ensuring
7212349Scth 		 * that the ddi_pathname result has a unit-address.  Instead,
7213349Scth 		 * we reverify the node state after calling ddi_pathname().
7214349Scth 		 */
7215349Scth 		if (i_ddi_node_state(dip) >= DS_INITIALIZED) {
7216349Scth 			(void) ddi_pathname(dip, path);
7217349Scth 			if (i_ddi_node_state(dip) < DS_INITIALIZED)
7218349Scth 				continue;
7219349Scth 			UNLOCK_DEV_OPS(&(dnp->dn_lock));
7220349Scth 			ASSERT(strlen(path) < MAXPATHLEN);
7221349Scth 			return (DDI_SUCCESS);
72220Sstevel@tonic-gate 		}
7223349Scth 	}
7224349Scth 	UNLOCK_DEV_OPS(&(dnp->dn_lock));
7225349Scth 
7226349Scth 	/* can't reconstruct the path */
7227349Scth 	*path = 0;
7228349Scth 	return (DDI_FAILURE);
7229349Scth }
72300Sstevel@tonic-gate 
72310Sstevel@tonic-gate #define	GLD_DRIVER_PPA "SUNW,gld_v0_ppa"
72320Sstevel@tonic-gate 
72330Sstevel@tonic-gate /*
72340Sstevel@tonic-gate  * Given the dip for a network interface return the ppa for that interface.
72350Sstevel@tonic-gate  *
72360Sstevel@tonic-gate  * In all cases except GLD v0 drivers, the ppa == instance.
72370Sstevel@tonic-gate  * In the case of GLD v0 drivers, the ppa is equal to the attach order.
72380Sstevel@tonic-gate  * So for these drivers when the attach routine calls gld_register(),
72390Sstevel@tonic-gate  * the GLD framework creates an integer property called "gld_driver_ppa"
72400Sstevel@tonic-gate  * that can be queried here.
72410Sstevel@tonic-gate  *
72420Sstevel@tonic-gate  * The only time this function is used is when a system is booting over nfs.
72430Sstevel@tonic-gate  * In this case the system has to resolve the pathname of the boot device
72440Sstevel@tonic-gate  * to it's ppa.
72450Sstevel@tonic-gate  */
72460Sstevel@tonic-gate int
i_ddi_devi_get_ppa(dev_info_t * dip)72470Sstevel@tonic-gate i_ddi_devi_get_ppa(dev_info_t *dip)
72480Sstevel@tonic-gate {
72490Sstevel@tonic-gate 	return (ddi_prop_get_int(DDI_DEV_T_ANY, dip,
72504582Scth 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM,
72514582Scth 	    GLD_DRIVER_PPA, ddi_get_instance(dip)));
72520Sstevel@tonic-gate }
72530Sstevel@tonic-gate 
72540Sstevel@tonic-gate /*
72550Sstevel@tonic-gate  * i_ddi_devi_set_ppa() should only be called from gld_register()
72560Sstevel@tonic-gate  * and only for GLD v0 drivers
72570Sstevel@tonic-gate  */
72580Sstevel@tonic-gate void
i_ddi_devi_set_ppa(dev_info_t * dip,int ppa)72590Sstevel@tonic-gate i_ddi_devi_set_ppa(dev_info_t *dip, int ppa)
72600Sstevel@tonic-gate {
72610Sstevel@tonic-gate 	(void) e_ddi_prop_update_int(DDI_DEV_T_NONE, dip, GLD_DRIVER_PPA, ppa);
72620Sstevel@tonic-gate }
72630Sstevel@tonic-gate 
72640Sstevel@tonic-gate 
72650Sstevel@tonic-gate /*
72660Sstevel@tonic-gate  * Private DDI Console bell functions.
72670Sstevel@tonic-gate  */
72680Sstevel@tonic-gate void
ddi_ring_console_bell(clock_t duration)72690Sstevel@tonic-gate ddi_ring_console_bell(clock_t duration)
72700Sstevel@tonic-gate {
72710Sstevel@tonic-gate 	if (ddi_console_bell_func != NULL)
72720Sstevel@tonic-gate 		(*ddi_console_bell_func)(duration);
72730Sstevel@tonic-gate }
72740Sstevel@tonic-gate 
72750Sstevel@tonic-gate void
ddi_set_console_bell(void (* bellfunc)(clock_t duration))72760Sstevel@tonic-gate ddi_set_console_bell(void (*bellfunc)(clock_t duration))
72770Sstevel@tonic-gate {
72780Sstevel@tonic-gate 	ddi_console_bell_func = bellfunc;
72790Sstevel@tonic-gate }
72800Sstevel@tonic-gate 
72810Sstevel@tonic-gate int
ddi_dma_alloc_handle(dev_info_t * dip,ddi_dma_attr_t * attr,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_handle_t * handlep)72820Sstevel@tonic-gate ddi_dma_alloc_handle(dev_info_t *dip, ddi_dma_attr_t *attr,
72830Sstevel@tonic-gate 	int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
72840Sstevel@tonic-gate {
72850Sstevel@tonic-gate 	int (*funcp)() = ddi_dma_allochdl;
72860Sstevel@tonic-gate 	ddi_dma_attr_t dma_attr;
72870Sstevel@tonic-gate 	struct bus_ops *bop;
72880Sstevel@tonic-gate 
72890Sstevel@tonic-gate 	if (attr == (ddi_dma_attr_t *)0)
72900Sstevel@tonic-gate 		return (DDI_DMA_BADATTR);
72910Sstevel@tonic-gate 
72920Sstevel@tonic-gate 	dma_attr = *attr;
72930Sstevel@tonic-gate 
72940Sstevel@tonic-gate 	bop = DEVI(dip)->devi_ops->devo_bus_ops;
72950Sstevel@tonic-gate 	if (bop && bop->bus_dma_allochdl)
72960Sstevel@tonic-gate 		funcp = bop->bus_dma_allochdl;
72970Sstevel@tonic-gate 
72980Sstevel@tonic-gate 	return ((*funcp)(dip, dip, &dma_attr, waitfp, arg, handlep));
72990Sstevel@tonic-gate }
73000Sstevel@tonic-gate 
73010Sstevel@tonic-gate void
ddi_dma_free_handle(ddi_dma_handle_t * handlep)73020Sstevel@tonic-gate ddi_dma_free_handle(ddi_dma_handle_t *handlep)
73030Sstevel@tonic-gate {
73040Sstevel@tonic-gate 	ddi_dma_handle_t h = *handlep;
73050Sstevel@tonic-gate 	(void) ddi_dma_freehdl(HD, HD, h);
73060Sstevel@tonic-gate }
73070Sstevel@tonic-gate 
73080Sstevel@tonic-gate static uintptr_t dma_mem_list_id = 0;
73090Sstevel@tonic-gate 
73100Sstevel@tonic-gate 
73110Sstevel@tonic-gate int
ddi_dma_mem_alloc(ddi_dma_handle_t handle,size_t length,ddi_device_acc_attr_t * accattrp,uint_t flags,int (* waitfp)(caddr_t),caddr_t arg,caddr_t * kaddrp,size_t * real_length,ddi_acc_handle_t * handlep)73120Sstevel@tonic-gate ddi_dma_mem_alloc(ddi_dma_handle_t handle, size_t length,
73131900Seota 	ddi_device_acc_attr_t *accattrp, uint_t flags,
73140Sstevel@tonic-gate 	int (*waitfp)(caddr_t), caddr_t arg, caddr_t *kaddrp,
73150Sstevel@tonic-gate 	size_t *real_length, ddi_acc_handle_t *handlep)
73160Sstevel@tonic-gate {
73170Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
73180Sstevel@tonic-gate 	dev_info_t *dip = hp->dmai_rdip;
73190Sstevel@tonic-gate 	ddi_acc_hdl_t *ap;
73200Sstevel@tonic-gate 	ddi_dma_attr_t *attrp = &hp->dmai_attr;
73211900Seota 	uint_t sleepflag, xfermodes;
73220Sstevel@tonic-gate 	int (*fp)(caddr_t);
73230Sstevel@tonic-gate 	int rval;
73240Sstevel@tonic-gate 
73250Sstevel@tonic-gate 	if (waitfp == DDI_DMA_SLEEP)
73260Sstevel@tonic-gate 		fp = (int (*)())KM_SLEEP;
73270Sstevel@tonic-gate 	else if (waitfp == DDI_DMA_DONTWAIT)
73280Sstevel@tonic-gate 		fp = (int (*)())KM_NOSLEEP;
73290Sstevel@tonic-gate 	else
73300Sstevel@tonic-gate 		fp = waitfp;
73310Sstevel@tonic-gate 	*handlep = impl_acc_hdl_alloc(fp, arg);
73320Sstevel@tonic-gate 	if (*handlep == NULL)
73330Sstevel@tonic-gate 		return (DDI_FAILURE);
73340Sstevel@tonic-gate 
73351910Seota 	/* check if the cache attributes are supported */
73361910Seota 	if (i_ddi_check_cache_attr(flags) == B_FALSE)
73371900Seota 		return (DDI_FAILURE);
73381900Seota 
73391900Seota 	/*
73401900Seota 	 * Transfer the meaningful bits to xfermodes.
73411900Seota 	 * Double-check if the 3rd party driver correctly sets the bits.
73421900Seota 	 * If not, set DDI_DMA_STREAMING to keep compatibility.
73431900Seota 	 */
73441900Seota 	xfermodes = flags & (DDI_DMA_CONSISTENT | DDI_DMA_STREAMING);
73451900Seota 	if (xfermodes == 0) {
73461900Seota 		xfermodes = DDI_DMA_STREAMING;
73471900Seota 	}
73481900Seota 
73490Sstevel@tonic-gate 	/*
73500Sstevel@tonic-gate 	 * initialize the common elements of data access handle
73510Sstevel@tonic-gate 	 */
73520Sstevel@tonic-gate 	ap = impl_acc_hdl_get(*handlep);
73530Sstevel@tonic-gate 	ap->ah_vers = VERS_ACCHDL;
73540Sstevel@tonic-gate 	ap->ah_dip = dip;
73550Sstevel@tonic-gate 	ap->ah_offset = 0;
73560Sstevel@tonic-gate 	ap->ah_len = 0;
73571900Seota 	ap->ah_xfermodes = flags;
73580Sstevel@tonic-gate 	ap->ah_acc = *accattrp;
73590Sstevel@tonic-gate 
73600Sstevel@tonic-gate 	sleepflag = ((waitfp == DDI_DMA_SLEEP) ? 1 : 0);
73610Sstevel@tonic-gate 	if (xfermodes == DDI_DMA_CONSISTENT) {
73621900Seota 		rval = i_ddi_mem_alloc(dip, attrp, length, sleepflag,
73631900Seota 		    flags, accattrp, kaddrp, NULL, ap);
73640Sstevel@tonic-gate 		*real_length = length;
73650Sstevel@tonic-gate 	} else {
73661900Seota 		rval = i_ddi_mem_alloc(dip, attrp, length, sleepflag,
73671900Seota 		    flags, accattrp, kaddrp, real_length, ap);
73680Sstevel@tonic-gate 	}
73690Sstevel@tonic-gate 	if (rval == DDI_SUCCESS) {
73700Sstevel@tonic-gate 		ap->ah_len = (off_t)(*real_length);
73710Sstevel@tonic-gate 		ap->ah_addr = *kaddrp;
73720Sstevel@tonic-gate 	} else {
73730Sstevel@tonic-gate 		impl_acc_hdl_free(*handlep);
73740Sstevel@tonic-gate 		*handlep = (ddi_acc_handle_t)NULL;
73750Sstevel@tonic-gate 		if (waitfp != DDI_DMA_SLEEP && waitfp != DDI_DMA_DONTWAIT) {
73760Sstevel@tonic-gate 			ddi_set_callback(waitfp, arg, &dma_mem_list_id);
73770Sstevel@tonic-gate 		}
73780Sstevel@tonic-gate 		rval = DDI_FAILURE;
73790Sstevel@tonic-gate 	}
73800Sstevel@tonic-gate 	return (rval);
73810Sstevel@tonic-gate }
73820Sstevel@tonic-gate 
73830Sstevel@tonic-gate void
ddi_dma_mem_free(ddi_acc_handle_t * handlep)73840Sstevel@tonic-gate ddi_dma_mem_free(ddi_acc_handle_t *handlep)
73850Sstevel@tonic-gate {
73860Sstevel@tonic-gate 	ddi_acc_hdl_t *ap;
73870Sstevel@tonic-gate 
73880Sstevel@tonic-gate 	ap = impl_acc_hdl_get(*handlep);
73890Sstevel@tonic-gate 	ASSERT(ap);
73900Sstevel@tonic-gate 
73911900Seota 	i_ddi_mem_free((caddr_t)ap->ah_addr, ap);
73920Sstevel@tonic-gate 
73930Sstevel@tonic-gate 	/*
73940Sstevel@tonic-gate 	 * free the handle
73950Sstevel@tonic-gate 	 */
73960Sstevel@tonic-gate 	impl_acc_hdl_free(*handlep);
73970Sstevel@tonic-gate 	*handlep = (ddi_acc_handle_t)NULL;
73980Sstevel@tonic-gate 
73990Sstevel@tonic-gate 	if (dma_mem_list_id != 0) {
74000Sstevel@tonic-gate 		ddi_run_callback(&dma_mem_list_id);
74010Sstevel@tonic-gate 	}
74020Sstevel@tonic-gate }
74030Sstevel@tonic-gate 
74040Sstevel@tonic-gate int
ddi_dma_buf_bind_handle(ddi_dma_handle_t handle,struct buf * bp,uint_t flags,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_cookie_t * cookiep,uint_t * ccountp)74050Sstevel@tonic-gate ddi_dma_buf_bind_handle(ddi_dma_handle_t handle, struct buf *bp,
74060Sstevel@tonic-gate 	uint_t flags, int (*waitfp)(caddr_t), caddr_t arg,
74070Sstevel@tonic-gate 	ddi_dma_cookie_t *cookiep, uint_t *ccountp)
74080Sstevel@tonic-gate {
74090Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
741010216SVikram.Hegde@Sun.COM 	dev_info_t *dip, *rdip;
74110Sstevel@tonic-gate 	struct ddi_dma_req dmareq;
74120Sstevel@tonic-gate 	int (*funcp)();
74130Sstevel@tonic-gate 
74140Sstevel@tonic-gate 	dmareq.dmar_flags = flags;
74150Sstevel@tonic-gate 	dmareq.dmar_fp = waitfp;
74160Sstevel@tonic-gate 	dmareq.dmar_arg = arg;
74170Sstevel@tonic-gate 	dmareq.dmar_object.dmao_size = (uint_t)bp->b_bcount;
74180Sstevel@tonic-gate 
74191299Scth 	if (bp->b_flags & B_PAGEIO) {
74200Sstevel@tonic-gate 		dmareq.dmar_object.dmao_type = DMA_OTYP_PAGES;
74210Sstevel@tonic-gate 		dmareq.dmar_object.dmao_obj.pp_obj.pp_pp = bp->b_pages;
74220Sstevel@tonic-gate 		dmareq.dmar_object.dmao_obj.pp_obj.pp_offset =
74230Sstevel@tonic-gate 		    (uint_t)(((uintptr_t)bp->b_un.b_addr) & MMU_PAGEOFFSET);
74240Sstevel@tonic-gate 	} else {
74250Sstevel@tonic-gate 		dmareq.dmar_object.dmao_obj.virt_obj.v_addr = bp->b_un.b_addr;
74261299Scth 		if (bp->b_flags & B_SHADOW) {
74270Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_priv =
74284582Scth 			    bp->b_shadow;
74290Sstevel@tonic-gate 			dmareq.dmar_object.dmao_type = DMA_OTYP_BUFVADDR;
74300Sstevel@tonic-gate 		} else {
74310Sstevel@tonic-gate 			dmareq.dmar_object.dmao_type =
74324582Scth 			    (bp->b_flags & (B_PHYS | B_REMAPPED)) ?
74334582Scth 			    DMA_OTYP_BUFVADDR : DMA_OTYP_VADDR;
74340Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
74350Sstevel@tonic-gate 		}
74360Sstevel@tonic-gate 
74370Sstevel@tonic-gate 		/*
74380Sstevel@tonic-gate 		 * If the buffer has no proc pointer, or the proc
74390Sstevel@tonic-gate 		 * struct has the kernel address space, or the buffer has
74400Sstevel@tonic-gate 		 * been marked B_REMAPPED (meaning that it is now
74410Sstevel@tonic-gate 		 * mapped into the kernel's address space), then
74420Sstevel@tonic-gate 		 * the address space is kas (kernel address space).
74430Sstevel@tonic-gate 		 */
74441299Scth 		if ((bp->b_proc == NULL) || (bp->b_proc->p_as == &kas) ||
74451299Scth 		    (bp->b_flags & B_REMAPPED)) {
74460Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_as = 0;
74470Sstevel@tonic-gate 		} else {
74480Sstevel@tonic-gate 			dmareq.dmar_object.dmao_obj.virt_obj.v_as =
74490Sstevel@tonic-gate 			    bp->b_proc->p_as;
74500Sstevel@tonic-gate 		}
74510Sstevel@tonic-gate 	}
74520Sstevel@tonic-gate 
745310216SVikram.Hegde@Sun.COM 	dip = rdip = hp->dmai_rdip;
745410216SVikram.Hegde@Sun.COM 	if (dip != ddi_root_node())
745510216SVikram.Hegde@Sun.COM 		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
745610216SVikram.Hegde@Sun.COM 	funcp = DEVI(rdip)->devi_bus_dma_bindfunc;
745710216SVikram.Hegde@Sun.COM 	return ((*funcp)(dip, rdip, handle, &dmareq, cookiep, ccountp));
74580Sstevel@tonic-gate }
74590Sstevel@tonic-gate 
74600Sstevel@tonic-gate int
ddi_dma_addr_bind_handle(ddi_dma_handle_t handle,struct as * as,caddr_t addr,size_t len,uint_t flags,int (* waitfp)(caddr_t),caddr_t arg,ddi_dma_cookie_t * cookiep,uint_t * ccountp)74610Sstevel@tonic-gate ddi_dma_addr_bind_handle(ddi_dma_handle_t handle, struct as *as,
74620Sstevel@tonic-gate 	caddr_t addr, size_t len, uint_t flags, int (*waitfp)(caddr_t),
74630Sstevel@tonic-gate 	caddr_t arg, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
74640Sstevel@tonic-gate {
74650Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
746610216SVikram.Hegde@Sun.COM 	dev_info_t *dip, *rdip;
74670Sstevel@tonic-gate 	struct ddi_dma_req dmareq;
74680Sstevel@tonic-gate 	int (*funcp)();
74690Sstevel@tonic-gate 
74700Sstevel@tonic-gate 	if (len == (uint_t)0) {
74710Sstevel@tonic-gate 		return (DDI_DMA_NOMAPPING);
74720Sstevel@tonic-gate 	}
74730Sstevel@tonic-gate 	dmareq.dmar_flags = flags;
74740Sstevel@tonic-gate 	dmareq.dmar_fp = waitfp;
74750Sstevel@tonic-gate 	dmareq.dmar_arg = arg;
74760Sstevel@tonic-gate 	dmareq.dmar_object.dmao_size = len;
74770Sstevel@tonic-gate 	dmareq.dmar_object.dmao_type = DMA_OTYP_VADDR;
74780Sstevel@tonic-gate 	dmareq.dmar_object.dmao_obj.virt_obj.v_as = as;
74790Sstevel@tonic-gate 	dmareq.dmar_object.dmao_obj.virt_obj.v_addr = addr;
74800Sstevel@tonic-gate 	dmareq.dmar_object.dmao_obj.virt_obj.v_priv = NULL;
74810Sstevel@tonic-gate 
748210216SVikram.Hegde@Sun.COM 	dip = rdip = hp->dmai_rdip;
748310216SVikram.Hegde@Sun.COM 	if (dip != ddi_root_node())
748410216SVikram.Hegde@Sun.COM 		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
748510216SVikram.Hegde@Sun.COM 	funcp = DEVI(rdip)->devi_bus_dma_bindfunc;
748610216SVikram.Hegde@Sun.COM 	return ((*funcp)(dip, rdip, handle, &dmareq, cookiep, ccountp));
74870Sstevel@tonic-gate }
74880Sstevel@tonic-gate 
74890Sstevel@tonic-gate void
ddi_dma_nextcookie(ddi_dma_handle_t handle,ddi_dma_cookie_t * cookiep)74900Sstevel@tonic-gate ddi_dma_nextcookie(ddi_dma_handle_t handle, ddi_dma_cookie_t *cookiep)
74910Sstevel@tonic-gate {
74920Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
74930Sstevel@tonic-gate 	ddi_dma_cookie_t *cp;
74940Sstevel@tonic-gate 
74950Sstevel@tonic-gate 	cp = hp->dmai_cookie;
74960Sstevel@tonic-gate 	ASSERT(cp);
74970Sstevel@tonic-gate 
74980Sstevel@tonic-gate 	cookiep->dmac_notused = cp->dmac_notused;
74990Sstevel@tonic-gate 	cookiep->dmac_type = cp->dmac_type;
75000Sstevel@tonic-gate 	cookiep->dmac_address = cp->dmac_address;
75010Sstevel@tonic-gate 	cookiep->dmac_size = cp->dmac_size;
75020Sstevel@tonic-gate 	hp->dmai_cookie++;
75030Sstevel@tonic-gate }
75040Sstevel@tonic-gate 
75050Sstevel@tonic-gate int
ddi_dma_numwin(ddi_dma_handle_t handle,uint_t * nwinp)75060Sstevel@tonic-gate ddi_dma_numwin(ddi_dma_handle_t handle, uint_t *nwinp)
75070Sstevel@tonic-gate {
75080Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
75090Sstevel@tonic-gate 	if ((hp->dmai_rflags & DDI_DMA_PARTIAL) == 0) {
75100Sstevel@tonic-gate 		return (DDI_FAILURE);
75110Sstevel@tonic-gate 	} else {
75120Sstevel@tonic-gate 		*nwinp = hp->dmai_nwin;
75130Sstevel@tonic-gate 		return (DDI_SUCCESS);
75140Sstevel@tonic-gate 	}
75150Sstevel@tonic-gate }
75160Sstevel@tonic-gate 
75170Sstevel@tonic-gate int
ddi_dma_getwin(ddi_dma_handle_t h,uint_t win,off_t * offp,size_t * lenp,ddi_dma_cookie_t * cookiep,uint_t * ccountp)75180Sstevel@tonic-gate ddi_dma_getwin(ddi_dma_handle_t h, uint_t win, off_t *offp,
75190Sstevel@tonic-gate 	size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
75200Sstevel@tonic-gate {
75210Sstevel@tonic-gate 	int (*funcp)() = ddi_dma_win;
75220Sstevel@tonic-gate 	struct bus_ops *bop;
75230Sstevel@tonic-gate 
75240Sstevel@tonic-gate 	bop = DEVI(HD)->devi_ops->devo_bus_ops;
75250Sstevel@tonic-gate 	if (bop && bop->bus_dma_win)
75260Sstevel@tonic-gate 		funcp = bop->bus_dma_win;
75270Sstevel@tonic-gate 
75280Sstevel@tonic-gate 	return ((*funcp)(HD, HD, h, win, offp, lenp, cookiep, ccountp));
75290Sstevel@tonic-gate }
75300Sstevel@tonic-gate 
75310Sstevel@tonic-gate int
ddi_dma_set_sbus64(ddi_dma_handle_t h,ulong_t burstsizes)75320Sstevel@tonic-gate ddi_dma_set_sbus64(ddi_dma_handle_t h, ulong_t burstsizes)
75330Sstevel@tonic-gate {
75340Sstevel@tonic-gate 	return (ddi_dma_mctl(HD, HD, h, DDI_DMA_SET_SBUS64, 0,
75354582Scth 	    &burstsizes, 0, 0));
75360Sstevel@tonic-gate }
75370Sstevel@tonic-gate 
75380Sstevel@tonic-gate int
i_ddi_dma_fault_check(ddi_dma_impl_t * hp)75390Sstevel@tonic-gate i_ddi_dma_fault_check(ddi_dma_impl_t *hp)
75400Sstevel@tonic-gate {
75410Sstevel@tonic-gate 	return (hp->dmai_fault);
75420Sstevel@tonic-gate }
75430Sstevel@tonic-gate 
75440Sstevel@tonic-gate int
ddi_check_dma_handle(ddi_dma_handle_t handle)75450Sstevel@tonic-gate ddi_check_dma_handle(ddi_dma_handle_t handle)
75460Sstevel@tonic-gate {
75470Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
75480Sstevel@tonic-gate 	int (*check)(ddi_dma_impl_t *);
75490Sstevel@tonic-gate 
75500Sstevel@tonic-gate 	if ((check = hp->dmai_fault_check) == NULL)
75510Sstevel@tonic-gate 		check = i_ddi_dma_fault_check;
75520Sstevel@tonic-gate 
75530Sstevel@tonic-gate 	return (((*check)(hp) == DDI_SUCCESS) ? DDI_SUCCESS : DDI_FAILURE);
75540Sstevel@tonic-gate }
75550Sstevel@tonic-gate 
75560Sstevel@tonic-gate void
i_ddi_dma_set_fault(ddi_dma_handle_t handle)75570Sstevel@tonic-gate i_ddi_dma_set_fault(ddi_dma_handle_t handle)
75580Sstevel@tonic-gate {
75590Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
75600Sstevel@tonic-gate 	void (*notify)(ddi_dma_impl_t *);
75610Sstevel@tonic-gate 
75620Sstevel@tonic-gate 	if (!hp->dmai_fault) {
75630Sstevel@tonic-gate 		hp->dmai_fault = 1;
75640Sstevel@tonic-gate 		if ((notify = hp->dmai_fault_notify) != NULL)
75650Sstevel@tonic-gate 			(*notify)(hp);
75660Sstevel@tonic-gate 	}
75670Sstevel@tonic-gate }
75680Sstevel@tonic-gate 
75690Sstevel@tonic-gate void
i_ddi_dma_clr_fault(ddi_dma_handle_t handle)75700Sstevel@tonic-gate i_ddi_dma_clr_fault(ddi_dma_handle_t handle)
75710Sstevel@tonic-gate {
75720Sstevel@tonic-gate 	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)handle;
75730Sstevel@tonic-gate 	void (*notify)(ddi_dma_impl_t *);
75740Sstevel@tonic-gate 
75750Sstevel@tonic-gate 	if (hp->dmai_fault) {
75760Sstevel@tonic-gate 		hp->dmai_fault = 0;
75770Sstevel@tonic-gate 		if ((notify = hp->dmai_fault_notify) != NULL)
75780Sstevel@tonic-gate 			(*notify)(hp);
75790Sstevel@tonic-gate 	}
75800Sstevel@tonic-gate }
75810Sstevel@tonic-gate 
75820Sstevel@tonic-gate /*
75830Sstevel@tonic-gate  * register mapping routines.
75840Sstevel@tonic-gate  */
75850Sstevel@tonic-gate int
ddi_regs_map_setup(dev_info_t * dip,uint_t rnumber,caddr_t * addrp,offset_t offset,offset_t len,ddi_device_acc_attr_t * accattrp,ddi_acc_handle_t * handle)75860Sstevel@tonic-gate ddi_regs_map_setup(dev_info_t *dip, uint_t rnumber, caddr_t *addrp,
75870Sstevel@tonic-gate 	offset_t offset, offset_t len, ddi_device_acc_attr_t *accattrp,
75880Sstevel@tonic-gate 	ddi_acc_handle_t *handle)
75890Sstevel@tonic-gate {
75900Sstevel@tonic-gate 	ddi_map_req_t mr;
75910Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
75920Sstevel@tonic-gate 	int result;
75930Sstevel@tonic-gate 
75940Sstevel@tonic-gate 	/*
75950Sstevel@tonic-gate 	 * Allocate and initialize the common elements of data access handle.
75960Sstevel@tonic-gate 	 */
75970Sstevel@tonic-gate 	*handle = impl_acc_hdl_alloc(KM_SLEEP, NULL);
75980Sstevel@tonic-gate 	hp = impl_acc_hdl_get(*handle);
75990Sstevel@tonic-gate 	hp->ah_vers = VERS_ACCHDL;
76000Sstevel@tonic-gate 	hp->ah_dip = dip;
76010Sstevel@tonic-gate 	hp->ah_rnumber = rnumber;
76020Sstevel@tonic-gate 	hp->ah_offset = offset;
76030Sstevel@tonic-gate 	hp->ah_len = len;
76040Sstevel@tonic-gate 	hp->ah_acc = *accattrp;
76050Sstevel@tonic-gate 
76060Sstevel@tonic-gate 	/*
76070Sstevel@tonic-gate 	 * Set up the mapping request and call to parent.
76080Sstevel@tonic-gate 	 */
76090Sstevel@tonic-gate 	mr.map_op = DDI_MO_MAP_LOCKED;
76100Sstevel@tonic-gate 	mr.map_type = DDI_MT_RNUMBER;
76110Sstevel@tonic-gate 	mr.map_obj.rnumber = rnumber;
76120Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
76130Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
76140Sstevel@tonic-gate 	mr.map_handlep = hp;
76150Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
76160Sstevel@tonic-gate 	result = ddi_map(dip, &mr, offset, len, addrp);
76170Sstevel@tonic-gate 
76180Sstevel@tonic-gate 	/*
76190Sstevel@tonic-gate 	 * check for end result
76200Sstevel@tonic-gate 	 */
76210Sstevel@tonic-gate 	if (result != DDI_SUCCESS) {
76220Sstevel@tonic-gate 		impl_acc_hdl_free(*handle);
76230Sstevel@tonic-gate 		*handle = (ddi_acc_handle_t)NULL;
76240Sstevel@tonic-gate 	} else {
76250Sstevel@tonic-gate 		hp->ah_addr = *addrp;
76260Sstevel@tonic-gate 	}
76270Sstevel@tonic-gate 
76280Sstevel@tonic-gate 	return (result);
76290Sstevel@tonic-gate }
76300Sstevel@tonic-gate 
76310Sstevel@tonic-gate void
ddi_regs_map_free(ddi_acc_handle_t * handlep)76320Sstevel@tonic-gate ddi_regs_map_free(ddi_acc_handle_t *handlep)
76330Sstevel@tonic-gate {
76340Sstevel@tonic-gate 	ddi_map_req_t mr;
76350Sstevel@tonic-gate 	ddi_acc_hdl_t *hp;
76360Sstevel@tonic-gate 
76370Sstevel@tonic-gate 	hp = impl_acc_hdl_get(*handlep);
76380Sstevel@tonic-gate 	ASSERT(hp);
76390Sstevel@tonic-gate 
76400Sstevel@tonic-gate 	mr.map_op = DDI_MO_UNMAP;
76410Sstevel@tonic-gate 	mr.map_type = DDI_MT_RNUMBER;
76420Sstevel@tonic-gate 	mr.map_obj.rnumber = hp->ah_rnumber;
76430Sstevel@tonic-gate 	mr.map_prot = PROT_READ | PROT_WRITE;
76440Sstevel@tonic-gate 	mr.map_flags = DDI_MF_KERNEL_MAPPING;
76450Sstevel@tonic-gate 	mr.map_handlep = hp;
76460Sstevel@tonic-gate 	mr.map_vers = DDI_MAP_VERSION;
76470Sstevel@tonic-gate 
76480Sstevel@tonic-gate 	/*
76490Sstevel@tonic-gate 	 * Call my parent to unmap my regs.
76500Sstevel@tonic-gate 	 */
76510Sstevel@tonic-gate 	(void) ddi_map(hp->ah_dip, &mr, hp->ah_offset,
76524582Scth 	    hp->ah_len, &hp->ah_addr);
76530Sstevel@tonic-gate 	/*
76540Sstevel@tonic-gate 	 * free the handle
76550Sstevel@tonic-gate 	 */
76560Sstevel@tonic-gate 	impl_acc_hdl_free(*handlep);
76570Sstevel@tonic-gate 	*handlep = (ddi_acc_handle_t)NULL;
76580Sstevel@tonic-gate }
76590Sstevel@tonic-gate 
76600Sstevel@tonic-gate int
ddi_device_zero(ddi_acc_handle_t handle,caddr_t dev_addr,size_t bytecount,ssize_t dev_advcnt,uint_t dev_datasz)76610Sstevel@tonic-gate ddi_device_zero(ddi_acc_handle_t handle, caddr_t dev_addr, size_t bytecount,
76620Sstevel@tonic-gate 	ssize_t dev_advcnt, uint_t dev_datasz)
76630Sstevel@tonic-gate {
76640Sstevel@tonic-gate 	uint8_t *b;
76650Sstevel@tonic-gate 	uint16_t *w;
76660Sstevel@tonic-gate 	uint32_t *l;
76670Sstevel@tonic-gate 	uint64_t *ll;
76680Sstevel@tonic-gate 
76690Sstevel@tonic-gate 	/* check for total byte count is multiple of data transfer size */
76700Sstevel@tonic-gate 	if (bytecount != ((bytecount / dev_datasz) * dev_datasz))
76710Sstevel@tonic-gate 		return (DDI_FAILURE);
76720Sstevel@tonic-gate 
76730Sstevel@tonic-gate 	switch (dev_datasz) {
76740Sstevel@tonic-gate 	case DDI_DATA_SZ01_ACC:
76750Sstevel@tonic-gate 		for (b = (uint8_t *)dev_addr;
76764582Scth 		    bytecount != 0; bytecount -= 1, b += dev_advcnt)
76770Sstevel@tonic-gate 			ddi_put8(handle, b, 0);
76780Sstevel@tonic-gate 		break;
76790Sstevel@tonic-gate 	case DDI_DATA_SZ02_ACC:
76800Sstevel@tonic-gate 		for (w = (uint16_t *)dev_addr;
76814582Scth 		    bytecount != 0; bytecount -= 2, w += dev_advcnt)
76820Sstevel@tonic-gate 			ddi_put16(handle, w, 0);
76830Sstevel@tonic-gate 		break;
76840Sstevel@tonic-gate 	case DDI_DATA_SZ04_ACC:
76850Sstevel@tonic-gate 		for (l = (uint32_t *)dev_addr;
76864582Scth 		    bytecount != 0; bytecount -= 4, l += dev_advcnt)
76870Sstevel@tonic-gate 			ddi_put32(handle, l, 0);
76880Sstevel@tonic-gate 		break;
76890Sstevel@tonic-gate 	case DDI_DATA_SZ08_ACC:
76900Sstevel@tonic-gate 		for (ll = (uint64_t *)dev_addr;
76914582Scth 		    bytecount != 0; bytecount -= 8, ll += dev_advcnt)
76920Sstevel@tonic-gate 			ddi_put64(handle, ll, 0x0ll);
76930Sstevel@tonic-gate 		break;
76940Sstevel@tonic-gate 	default:
76950Sstevel@tonic-gate 		return (DDI_FAILURE);
76960Sstevel@tonic-gate 	}
76970Sstevel@tonic-gate 	return (DDI_SUCCESS);
76980Sstevel@tonic-gate }
76990Sstevel@tonic-gate 
77000Sstevel@tonic-gate int
ddi_device_copy(ddi_acc_handle_t src_handle,caddr_t src_addr,ssize_t src_advcnt,ddi_acc_handle_t dest_handle,caddr_t dest_addr,ssize_t dest_advcnt,size_t bytecount,uint_t dev_datasz)77010Sstevel@tonic-gate ddi_device_copy(
77020Sstevel@tonic-gate 	ddi_acc_handle_t src_handle, caddr_t src_addr, ssize_t src_advcnt,
77030Sstevel@tonic-gate 	ddi_acc_handle_t dest_handle, caddr_t dest_addr, ssize_t dest_advcnt,
77040Sstevel@tonic-gate 	size_t bytecount, uint_t dev_datasz)
77050Sstevel@tonic-gate {
77060Sstevel@tonic-gate 	uint8_t *b_src, *b_dst;
77070Sstevel@tonic-gate 	uint16_t *w_src, *w_dst;
77080Sstevel@tonic-gate 	uint32_t *l_src, *l_dst;
77090Sstevel@tonic-gate 	uint64_t *ll_src, *ll_dst;
77100Sstevel@tonic-gate 
77110Sstevel@tonic-gate 	/* check for total byte count is multiple of data transfer size */
77120Sstevel@tonic-gate 	if (bytecount != ((bytecount / dev_datasz) * dev_datasz))
77130Sstevel@tonic-gate 		return (DDI_FAILURE);
77140Sstevel@tonic-gate 
77150Sstevel@tonic-gate 	switch (dev_datasz) {
77160Sstevel@tonic-gate 	case DDI_DATA_SZ01_ACC:
77170Sstevel@tonic-gate 		b_src = (uint8_t *)src_addr;
77180Sstevel@tonic-gate 		b_dst = (uint8_t *)dest_addr;
77190Sstevel@tonic-gate 
77200Sstevel@tonic-gate 		for (; bytecount != 0; bytecount -= 1) {
77210Sstevel@tonic-gate 			ddi_put8(dest_handle, b_dst,
77224582Scth 			    ddi_get8(src_handle, b_src));
77230Sstevel@tonic-gate 			b_dst += dest_advcnt;
77240Sstevel@tonic-gate 			b_src += src_advcnt;
77250Sstevel@tonic-gate 		}
77260Sstevel@tonic-gate 		break;
77270Sstevel@tonic-gate 	case DDI_DATA_SZ02_ACC:
77280Sstevel@tonic-gate 		w_src = (uint16_t *)src_addr;
77290Sstevel@tonic-gate 		w_dst = (uint16_t *)dest_addr;
77300Sstevel@tonic-gate 
77310Sstevel@tonic-gate 		for (; bytecount != 0; bytecount -= 2) {
77320Sstevel@tonic-gate 			ddi_put16(dest_handle, w_dst,
77334582Scth 			    ddi_get16(src_handle, w_src));
77340Sstevel@tonic-gate 			w_dst += dest_advcnt;
77350Sstevel@tonic-gate 			w_src += src_advcnt;
77360Sstevel@tonic-gate 		}
77370Sstevel@tonic-gate 		break;
77380Sstevel@tonic-gate 	case DDI_DATA_SZ04_ACC:
77390Sstevel@tonic-gate 		l_src = (uint32_t *)src_addr;
77400Sstevel@tonic-gate 		l_dst = (uint32_t *)dest_addr;
77410Sstevel@tonic-gate 
77420Sstevel@tonic-gate 		for (; bytecount != 0; bytecount -= 4) {
77430Sstevel@tonic-gate 			ddi_put32(dest_handle, l_dst,
77444582Scth 			    ddi_get32(src_handle, l_src));
77450Sstevel@tonic-gate 			l_dst += dest_advcnt;
77460Sstevel@tonic-gate 			l_src += src_advcnt;
77470Sstevel@tonic-gate 		}
77480Sstevel@tonic-gate 		break;
77490Sstevel@tonic-gate 	case DDI_DATA_SZ08_ACC:
77500Sstevel@tonic-gate 		ll_src = (uint64_t *)src_addr;
77510Sstevel@tonic-gate 		ll_dst = (uint64_t *)dest_addr;
77520Sstevel@tonic-gate 
77530Sstevel@tonic-gate 		for (; bytecount != 0; bytecount -= 8) {
77540Sstevel@tonic-gate 			ddi_put64(dest_handle, ll_dst,
77554582Scth 			    ddi_get64(src_handle, ll_src));
77560Sstevel@tonic-gate 			ll_dst += dest_advcnt;
77570Sstevel@tonic-gate 			ll_src += src_advcnt;
77580Sstevel@tonic-gate 		}
77590Sstevel@tonic-gate 		break;
77600Sstevel@tonic-gate 	default:
77610Sstevel@tonic-gate 		return (DDI_FAILURE);
77620Sstevel@tonic-gate 	}
77630Sstevel@tonic-gate 	return (DDI_SUCCESS);
77640Sstevel@tonic-gate }
77650Sstevel@tonic-gate 
77660Sstevel@tonic-gate #define	swap16(value)  \
77670Sstevel@tonic-gate 	((((value) & 0xff) << 8) | ((value) >> 8))
77680Sstevel@tonic-gate 
77690Sstevel@tonic-gate #define	swap32(value)	\
77700Sstevel@tonic-gate 	(((uint32_t)swap16((uint16_t)((value) & 0xffff)) << 16) | \
77710Sstevel@tonic-gate 	(uint32_t)swap16((uint16_t)((value) >> 16)))
77720Sstevel@tonic-gate 
77730Sstevel@tonic-gate #define	swap64(value)	\
77740Sstevel@tonic-gate 	(((uint64_t)swap32((uint32_t)((value) & 0xffffffff)) \
77750Sstevel@tonic-gate 	    << 32) | \
77760Sstevel@tonic-gate 	(uint64_t)swap32((uint32_t)((value) >> 32)))
77770Sstevel@tonic-gate 
77780Sstevel@tonic-gate uint16_t
ddi_swap16(uint16_t value)77790Sstevel@tonic-gate ddi_swap16(uint16_t value)
77800Sstevel@tonic-gate {
77810Sstevel@tonic-gate 	return (swap16(value));
77820Sstevel@tonic-gate }
77830Sstevel@tonic-gate 
77840Sstevel@tonic-gate uint32_t
ddi_swap32(uint32_t value)77850Sstevel@tonic-gate ddi_swap32(uint32_t value)
77860Sstevel@tonic-gate {
77870Sstevel@tonic-gate 	return (swap32(value));
77880Sstevel@tonic-gate }
77890Sstevel@tonic-gate 
77900Sstevel@tonic-gate uint64_t
ddi_swap64(uint64_t value)77910Sstevel@tonic-gate ddi_swap64(uint64_t value)
77920Sstevel@tonic-gate {
77930Sstevel@tonic-gate 	return (swap64(value));
77940Sstevel@tonic-gate }
77950Sstevel@tonic-gate 
77960Sstevel@tonic-gate /*
77970Sstevel@tonic-gate  * Convert a binding name to a driver name.
77980Sstevel@tonic-gate  * A binding name is the name used to determine the driver for a
77990Sstevel@tonic-gate  * device - it may be either an alias for the driver or the name
78000Sstevel@tonic-gate  * of the driver itself.
78010Sstevel@tonic-gate  */
78020Sstevel@tonic-gate char *
i_binding_to_drv_name(char * bname)78030Sstevel@tonic-gate i_binding_to_drv_name(char *bname)
78040Sstevel@tonic-gate {
78050Sstevel@tonic-gate 	major_t major_no;
78060Sstevel@tonic-gate 
78070Sstevel@tonic-gate 	ASSERT(bname != NULL);
78080Sstevel@tonic-gate 
78090Sstevel@tonic-gate 	if ((major_no = ddi_name_to_major(bname)) == -1)
78100Sstevel@tonic-gate 		return (NULL);
78110Sstevel@tonic-gate 	return (ddi_major_to_name(major_no));
78120Sstevel@tonic-gate }
78130Sstevel@tonic-gate 
78140Sstevel@tonic-gate /*
78150Sstevel@tonic-gate  * Search for minor name that has specified dev_t and spec_type.
78160Sstevel@tonic-gate  * If spec_type is zero then any dev_t match works.  Since we
78170Sstevel@tonic-gate  * are returning a pointer to the minor name string, we require the
78180Sstevel@tonic-gate  * caller to do the locking.
78190Sstevel@tonic-gate  */
78200Sstevel@tonic-gate char *
i_ddi_devtspectype_to_minorname(dev_info_t * dip,dev_t dev,int spec_type)78210Sstevel@tonic-gate i_ddi_devtspectype_to_minorname(dev_info_t *dip, dev_t dev, int spec_type)
78220Sstevel@tonic-gate {
78230Sstevel@tonic-gate 	struct ddi_minor_data	*dmdp;
78240Sstevel@tonic-gate 
78250Sstevel@tonic-gate 	/*
78260Sstevel@tonic-gate 	 * The did layered driver currently intentionally returns a
78270Sstevel@tonic-gate 	 * devinfo ptr for an underlying sd instance based on a did
78280Sstevel@tonic-gate 	 * dev_t. In this case it is not an error.
78290Sstevel@tonic-gate 	 *
78300Sstevel@tonic-gate 	 * The did layered driver is associated with Sun Cluster.
78310Sstevel@tonic-gate 	 */
78320Sstevel@tonic-gate 	ASSERT((ddi_driver_major(dip) == getmajor(dev)) ||
78334582Scth 	    (strcmp(ddi_major_to_name(getmajor(dev)), "did") == 0));
78347224Scth 
78357224Scth 	ASSERT(DEVI_BUSY_OWNED(dip));
78360Sstevel@tonic-gate 	for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) {
78370Sstevel@tonic-gate 		if (((dmdp->type == DDM_MINOR) ||
78380Sstevel@tonic-gate 		    (dmdp->type == DDM_INTERNAL_PATH) ||
78390Sstevel@tonic-gate 		    (dmdp->type == DDM_DEFAULT)) &&
78400Sstevel@tonic-gate 		    (dmdp->ddm_dev == dev) &&
78410Sstevel@tonic-gate 		    ((((spec_type & (S_IFCHR|S_IFBLK))) == 0) ||
78420Sstevel@tonic-gate 		    (dmdp->ddm_spec_type == spec_type)))
78430Sstevel@tonic-gate 			return (dmdp->ddm_name);
78440Sstevel@tonic-gate 	}
78450Sstevel@tonic-gate 
78460Sstevel@tonic-gate 	return (NULL);
78470Sstevel@tonic-gate }
78480Sstevel@tonic-gate 
78490Sstevel@tonic-gate /*
78500Sstevel@tonic-gate  * Find the devt and spectype of the specified minor_name.
78510Sstevel@tonic-gate  * Return DDI_FAILURE if minor_name not found. Since we are
78520Sstevel@tonic-gate  * returning everything via arguments we can do the locking.
78530Sstevel@tonic-gate  */
78540Sstevel@tonic-gate int
i_ddi_minorname_to_devtspectype(dev_info_t * dip,char * minor_name,dev_t * devtp,int * spectypep)78550Sstevel@tonic-gate i_ddi_minorname_to_devtspectype(dev_info_t *dip, char *minor_name,
78560Sstevel@tonic-gate 	dev_t *devtp, int *spectypep)
78570Sstevel@tonic-gate {
78587224Scth 	int			circ;
78590Sstevel@tonic-gate 	struct ddi_minor_data	*dmdp;
78600Sstevel@tonic-gate 
78610Sstevel@tonic-gate 	/* deal with clone minor nodes */
78620Sstevel@tonic-gate 	if (dip == clone_dip) {
78630Sstevel@tonic-gate 		major_t	major;
78640Sstevel@tonic-gate 		/*
78650Sstevel@tonic-gate 		 * Make sure minor_name is a STREAMS driver.
78660Sstevel@tonic-gate 		 * We load the driver but don't attach to any instances.
78670Sstevel@tonic-gate 		 */
78680Sstevel@tonic-gate 
78690Sstevel@tonic-gate 		major = ddi_name_to_major(minor_name);
78707009Scth 		if (major == DDI_MAJOR_T_NONE)
78710Sstevel@tonic-gate 			return (DDI_FAILURE);
78720Sstevel@tonic-gate 
78730Sstevel@tonic-gate 		if (ddi_hold_driver(major) == NULL)
78740Sstevel@tonic-gate 			return (DDI_FAILURE);
78750Sstevel@tonic-gate 
78760Sstevel@tonic-gate 		if (STREAMSTAB(major) == NULL) {
78770Sstevel@tonic-gate 			ddi_rele_driver(major);
78780Sstevel@tonic-gate 			return (DDI_FAILURE);
78790Sstevel@tonic-gate 		}
78800Sstevel@tonic-gate 		ddi_rele_driver(major);
78810Sstevel@tonic-gate 
78820Sstevel@tonic-gate 		if (devtp)
78830Sstevel@tonic-gate 			*devtp = makedevice(clone_major, (minor_t)major);
78840Sstevel@tonic-gate 
78850Sstevel@tonic-gate 		if (spectypep)
78860Sstevel@tonic-gate 			*spectypep = S_IFCHR;
78870Sstevel@tonic-gate 
78880Sstevel@tonic-gate 		return (DDI_SUCCESS);
78890Sstevel@tonic-gate 	}
78900Sstevel@tonic-gate 
78917224Scth 	ndi_devi_enter(dip, &circ);
78920Sstevel@tonic-gate 	for (dmdp = DEVI(dip)->devi_minor; dmdp; dmdp = dmdp->next) {
78930Sstevel@tonic-gate 		if (((dmdp->type != DDM_MINOR) &&
78940Sstevel@tonic-gate 		    (dmdp->type != DDM_INTERNAL_PATH) &&
78950Sstevel@tonic-gate 		    (dmdp->type != DDM_DEFAULT)) ||
78960Sstevel@tonic-gate 		    strcmp(minor_name, dmdp->ddm_name))
78970Sstevel@tonic-gate 			continue;
78980Sstevel@tonic-gate 
78990Sstevel@tonic-gate 		if (devtp)
79000Sstevel@tonic-gate 			*devtp = dmdp->ddm_dev;
79010Sstevel@tonic-gate 
79020Sstevel@tonic-gate 		if (spectypep)
79030Sstevel@tonic-gate 			*spectypep = dmdp->ddm_spec_type;
79040Sstevel@tonic-gate 
79057224Scth 		ndi_devi_exit(dip, circ);
79060Sstevel@tonic-gate 		return (DDI_SUCCESS);
79070Sstevel@tonic-gate 	}
79087224Scth 	ndi_devi_exit(dip, circ);
79097224Scth 
79100Sstevel@tonic-gate 	return (DDI_FAILURE);
79110Sstevel@tonic-gate }
79120Sstevel@tonic-gate 
79130Sstevel@tonic-gate static kmutex_t devid_gen_mutex;
79140Sstevel@tonic-gate static short	devid_gen_number;
79150Sstevel@tonic-gate 
79160Sstevel@tonic-gate #ifdef DEBUG
79170Sstevel@tonic-gate 
79180Sstevel@tonic-gate static int	devid_register_corrupt = 0;
79190Sstevel@tonic-gate static int	devid_register_corrupt_major = 0;
79200Sstevel@tonic-gate static int	devid_register_corrupt_hint = 0;
79210Sstevel@tonic-gate static int	devid_register_corrupt_hint_major = 0;
79220Sstevel@tonic-gate 
79230Sstevel@tonic-gate static int devid_lyr_debug = 0;
79240Sstevel@tonic-gate 
79250Sstevel@tonic-gate #define	DDI_DEBUG_DEVID_DEVTS(msg, ndevs, devs)		\
79260Sstevel@tonic-gate 	if (devid_lyr_debug)					\
79270Sstevel@tonic-gate 		ddi_debug_devid_devts(msg, ndevs, devs)
79280Sstevel@tonic-gate 
79290Sstevel@tonic-gate #else
79300Sstevel@tonic-gate 
79310Sstevel@tonic-gate #define	DDI_DEBUG_DEVID_DEVTS(msg, ndevs, devs)
79320Sstevel@tonic-gate 
79330Sstevel@tonic-gate #endif /* DEBUG */
79340Sstevel@tonic-gate 
79350Sstevel@tonic-gate 
79360Sstevel@tonic-gate #ifdef	DEBUG
79370Sstevel@tonic-gate 
79380Sstevel@tonic-gate static void
ddi_debug_devid_devts(char * msg,int ndevs,dev_t * devs)79390Sstevel@tonic-gate ddi_debug_devid_devts(char *msg, int ndevs, dev_t *devs)
79400Sstevel@tonic-gate {
79410Sstevel@tonic-gate 	int i;
79420Sstevel@tonic-gate 
79430Sstevel@tonic-gate 	cmn_err(CE_CONT, "%s:\n", msg);
79440Sstevel@tonic-gate 	for (i = 0; i < ndevs; i++) {
79450Sstevel@tonic-gate 		cmn_err(CE_CONT, "    0x%lx\n", devs[i]);
79460Sstevel@tonic-gate 	}
79470Sstevel@tonic-gate }
79480Sstevel@tonic-gate 
79490Sstevel@tonic-gate static void
ddi_debug_devid_paths(char * msg,int npaths,char ** paths)79500Sstevel@tonic-gate ddi_debug_devid_paths(char *msg, int npaths, char **paths)
79510Sstevel@tonic-gate {
79520Sstevel@tonic-gate 	int i;
79530Sstevel@tonic-gate 
79540Sstevel@tonic-gate 	cmn_err(CE_CONT, "%s:\n", msg);
79550Sstevel@tonic-gate 	for (i = 0; i < npaths; i++) {
79560Sstevel@tonic-gate 		cmn_err(CE_CONT, "    %s\n", paths[i]);
79570Sstevel@tonic-gate 	}
79580Sstevel@tonic-gate }
79590Sstevel@tonic-gate 
79600Sstevel@tonic-gate static void
ddi_debug_devid_devts_per_path(char * path,int ndevs,dev_t * devs)79610Sstevel@tonic-gate ddi_debug_devid_devts_per_path(char *path, int ndevs, dev_t *devs)
79620Sstevel@tonic-gate {
79630Sstevel@tonic-gate 	int i;
79640Sstevel@tonic-gate 
79650Sstevel@tonic-gate 	cmn_err(CE_CONT, "dev_ts per path %s\n", path);
79660Sstevel@tonic-gate 	for (i = 0; i < ndevs; i++) {
79670Sstevel@tonic-gate 		cmn_err(CE_CONT, "    0x%lx\n", devs[i]);
79680Sstevel@tonic-gate 	}
79690Sstevel@tonic-gate }
79700Sstevel@tonic-gate 
79710Sstevel@tonic-gate #endif	/* DEBUG */
79720Sstevel@tonic-gate 
79730Sstevel@tonic-gate /*
79740Sstevel@tonic-gate  * Register device id into DDI framework.
797512121SReed.Liu@Sun.COM  * Must be called when the driver is bound.
79760Sstevel@tonic-gate  */
79770Sstevel@tonic-gate static int
i_ddi_devid_register(dev_info_t * dip,ddi_devid_t devid)79780Sstevel@tonic-gate i_ddi_devid_register(dev_info_t *dip, ddi_devid_t devid)
79790Sstevel@tonic-gate {
79800Sstevel@tonic-gate 	impl_devid_t	*i_devid = (impl_devid_t *)devid;
79810Sstevel@tonic-gate 	size_t		driver_len;
79820Sstevel@tonic-gate 	const char	*driver_name;
79830Sstevel@tonic-gate 	char		*devid_str;
79840Sstevel@tonic-gate 	major_t		major;
79850Sstevel@tonic-gate 
79860Sstevel@tonic-gate 	if ((dip == NULL) ||
79877009Scth 	    ((major = ddi_driver_major(dip)) == DDI_MAJOR_T_NONE))
79880Sstevel@tonic-gate 		return (DDI_FAILURE);
79890Sstevel@tonic-gate 
79900Sstevel@tonic-gate 	/* verify that the devid is valid */
79910Sstevel@tonic-gate 	if (ddi_devid_valid(devid) != DDI_SUCCESS)
79920Sstevel@tonic-gate 		return (DDI_FAILURE);
79930Sstevel@tonic-gate 
79940Sstevel@tonic-gate 	/* Updating driver name hint in devid */
79950Sstevel@tonic-gate 	driver_name = ddi_driver_name(dip);
79960Sstevel@tonic-gate 	driver_len = strlen(driver_name);
79970Sstevel@tonic-gate 	if (driver_len > DEVID_HINT_SIZE) {
79980Sstevel@tonic-gate 		/* Pick up last four characters of driver name */
79990Sstevel@tonic-gate 		driver_name += driver_len - DEVID_HINT_SIZE;
80000Sstevel@tonic-gate 		driver_len = DEVID_HINT_SIZE;
80010Sstevel@tonic-gate 	}
80020Sstevel@tonic-gate 	bzero(i_devid->did_driver, DEVID_HINT_SIZE);
80030Sstevel@tonic-gate 	bcopy(driver_name, i_devid->did_driver, driver_len);
80040Sstevel@tonic-gate 
80050Sstevel@tonic-gate #ifdef DEBUG
80060Sstevel@tonic-gate 	/* Corrupt the devid for testing. */
80070Sstevel@tonic-gate 	if (devid_register_corrupt)
80080Sstevel@tonic-gate 		i_devid->did_id[0] += devid_register_corrupt;
80090Sstevel@tonic-gate 	if (devid_register_corrupt_major &&
80100Sstevel@tonic-gate 	    (major == devid_register_corrupt_major))
80110Sstevel@tonic-gate 		i_devid->did_id[0] += 1;
80120Sstevel@tonic-gate 	if (devid_register_corrupt_hint)
80130Sstevel@tonic-gate 		i_devid->did_driver[0] += devid_register_corrupt_hint;
80140Sstevel@tonic-gate 	if (devid_register_corrupt_hint_major &&
80150Sstevel@tonic-gate 	    (major == devid_register_corrupt_hint_major))
80160Sstevel@tonic-gate 		i_devid->did_driver[0] += 1;
80170Sstevel@tonic-gate #endif /* DEBUG */
80180Sstevel@tonic-gate 
80190Sstevel@tonic-gate 	/* encode the devid as a string */
80200Sstevel@tonic-gate 	if ((devid_str = ddi_devid_str_encode(devid, NULL)) == NULL)
80210Sstevel@tonic-gate 		return (DDI_FAILURE);
80220Sstevel@tonic-gate 
80230Sstevel@tonic-gate 	/* add string as a string property */
80240Sstevel@tonic-gate 	if (ndi_prop_update_string(DDI_DEV_T_NONE, dip,
80250Sstevel@tonic-gate 	    DEVID_PROP_NAME, devid_str) != DDI_SUCCESS) {
80260Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: devid property update failed",
80274582Scth 		    ddi_driver_name(dip), ddi_get_instance(dip));
80280Sstevel@tonic-gate 		ddi_devid_str_free(devid_str);
80290Sstevel@tonic-gate 		return (DDI_FAILURE);
80300Sstevel@tonic-gate 	}
80310Sstevel@tonic-gate 
80326640Scth 	/* keep pointer to devid string for interrupt context fma code */
80336640Scth 	if (DEVI(dip)->devi_devid_str)
80346640Scth 		ddi_devid_str_free(DEVI(dip)->devi_devid_str);
80356640Scth 	DEVI(dip)->devi_devid_str = devid_str;
80360Sstevel@tonic-gate 	return (DDI_SUCCESS);
80370Sstevel@tonic-gate }
80380Sstevel@tonic-gate 
80390Sstevel@tonic-gate int
ddi_devid_register(dev_info_t * dip,ddi_devid_t devid)80400Sstevel@tonic-gate ddi_devid_register(dev_info_t *dip, ddi_devid_t devid)
80410Sstevel@tonic-gate {
80420Sstevel@tonic-gate 	int rval;
80430Sstevel@tonic-gate 
80440Sstevel@tonic-gate 	rval = i_ddi_devid_register(dip, devid);
80450Sstevel@tonic-gate 	if (rval == DDI_SUCCESS) {
80460Sstevel@tonic-gate 		/*
80470Sstevel@tonic-gate 		 * Register devid in devid-to-path cache
80480Sstevel@tonic-gate 		 */
80490Sstevel@tonic-gate 		if (e_devid_cache_register(dip, devid) == DDI_SUCCESS) {
80500Sstevel@tonic-gate 			mutex_enter(&DEVI(dip)->devi_lock);
8051*13015Sgavin.maltby@oracle.com 			DEVI(dip)->devi_flags |= DEVI_CACHED_DEVID;
80520Sstevel@tonic-gate 			mutex_exit(&DEVI(dip)->devi_lock);
805312121SReed.Liu@Sun.COM 		} else if (ddi_get_name_addr(dip)) {
805412121SReed.Liu@Sun.COM 			/*
805512121SReed.Liu@Sun.COM 			 * We only expect cache_register DDI_FAILURE when we
805612121SReed.Liu@Sun.COM 			 * can't form the full path because of NULL devi_addr.
805712121SReed.Liu@Sun.COM 			 */
80580Sstevel@tonic-gate 			cmn_err(CE_WARN, "%s%d: failed to cache devid",
80594582Scth 			    ddi_driver_name(dip), ddi_get_instance(dip));
80600Sstevel@tonic-gate 		}
80610Sstevel@tonic-gate 	} else {
80620Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d: failed to register devid",
80634582Scth 		    ddi_driver_name(dip), ddi_get_instance(dip));
80640Sstevel@tonic-gate 	}
80650Sstevel@tonic-gate 	return (rval);
80660Sstevel@tonic-gate }
80670Sstevel@tonic-gate 
80680Sstevel@tonic-gate /*
80690Sstevel@tonic-gate  * Remove (unregister) device id from DDI framework.
80700Sstevel@tonic-gate  * Must be called when device is detached.
80710Sstevel@tonic-gate  */
80720Sstevel@tonic-gate static void
i_ddi_devid_unregister(dev_info_t * dip)80730Sstevel@tonic-gate i_ddi_devid_unregister(dev_info_t *dip)
80740Sstevel@tonic-gate {
80756640Scth 	if (DEVI(dip)->devi_devid_str) {
80766640Scth 		ddi_devid_str_free(DEVI(dip)->devi_devid_str);
80776640Scth 		DEVI(dip)->devi_devid_str = NULL;
80786640Scth 	}
80790Sstevel@tonic-gate 
80800Sstevel@tonic-gate 	/* remove the devid property */
80810Sstevel@tonic-gate 	(void) ndi_prop_remove(DDI_DEV_T_NONE, dip, DEVID_PROP_NAME);
80820Sstevel@tonic-gate }
80830Sstevel@tonic-gate 
80840Sstevel@tonic-gate void
ddi_devid_unregister(dev_info_t * dip)80850Sstevel@tonic-gate ddi_devid_unregister(dev_info_t *dip)
80860Sstevel@tonic-gate {
80870Sstevel@tonic-gate 	mutex_enter(&DEVI(dip)->devi_lock);
8088*13015Sgavin.maltby@oracle.com 	DEVI(dip)->devi_flags &= ~DEVI_CACHED_DEVID;
80890Sstevel@tonic-gate 	mutex_exit(&DEVI(dip)->devi_lock);
80900Sstevel@tonic-gate 	e_devid_cache_unregister(dip);
80910Sstevel@tonic-gate 	i_ddi_devid_unregister(dip);
80920Sstevel@tonic-gate }
80930Sstevel@tonic-gate 
80940Sstevel@tonic-gate /*
80950Sstevel@tonic-gate  * Allocate and initialize a device id.
80960Sstevel@tonic-gate  */
80970Sstevel@tonic-gate int
ddi_devid_init(dev_info_t * dip,ushort_t devid_type,ushort_t nbytes,void * id,ddi_devid_t * ret_devid)80980Sstevel@tonic-gate ddi_devid_init(
80990Sstevel@tonic-gate 	dev_info_t	*dip,
81000Sstevel@tonic-gate 	ushort_t	devid_type,
81010Sstevel@tonic-gate 	ushort_t	nbytes,
81020Sstevel@tonic-gate 	void		*id,
81030Sstevel@tonic-gate 	ddi_devid_t	*ret_devid)
81040Sstevel@tonic-gate {
81050Sstevel@tonic-gate 	impl_devid_t	*i_devid;
81060Sstevel@tonic-gate 	int		sz = sizeof (*i_devid) + nbytes - sizeof (char);
81070Sstevel@tonic-gate 	int		driver_len;
81080Sstevel@tonic-gate 	const char	*driver_name;
81090Sstevel@tonic-gate 
81100Sstevel@tonic-gate 	switch (devid_type) {
81110Sstevel@tonic-gate 	case DEVID_SCSI3_WWN:
81120Sstevel@tonic-gate 		/*FALLTHRU*/
81130Sstevel@tonic-gate 	case DEVID_SCSI_SERIAL:
81140Sstevel@tonic-gate 		/*FALLTHRU*/
81150Sstevel@tonic-gate 	case DEVID_ATA_SERIAL:
81160Sstevel@tonic-gate 		/*FALLTHRU*/
81170Sstevel@tonic-gate 	case DEVID_ENCAP:
81180Sstevel@tonic-gate 		if (nbytes == 0)
81190Sstevel@tonic-gate 			return (DDI_FAILURE);
81200Sstevel@tonic-gate 		if (id == NULL)
81210Sstevel@tonic-gate 			return (DDI_FAILURE);
81220Sstevel@tonic-gate 		break;
81230Sstevel@tonic-gate 	case DEVID_FAB:
81240Sstevel@tonic-gate 		if (nbytes != 0)
81250Sstevel@tonic-gate 			return (DDI_FAILURE);
81260Sstevel@tonic-gate 		if (id != NULL)
81270Sstevel@tonic-gate 			return (DDI_FAILURE);
81280Sstevel@tonic-gate 		nbytes = sizeof (int) +
81290Sstevel@tonic-gate 		    sizeof (struct timeval32) + sizeof (short);
81300Sstevel@tonic-gate 		sz += nbytes;
81310Sstevel@tonic-gate 		break;
81320Sstevel@tonic-gate 	default:
81330Sstevel@tonic-gate 		return (DDI_FAILURE);
81340Sstevel@tonic-gate 	}
81350Sstevel@tonic-gate 
81360Sstevel@tonic-gate 	if ((i_devid = kmem_zalloc(sz, KM_SLEEP)) == NULL)
81370Sstevel@tonic-gate 		return (DDI_FAILURE);
81380Sstevel@tonic-gate 
81390Sstevel@tonic-gate 	i_devid->did_magic_hi = DEVID_MAGIC_MSB;
81400Sstevel@tonic-gate 	i_devid->did_magic_lo = DEVID_MAGIC_LSB;
81410Sstevel@tonic-gate 	i_devid->did_rev_hi = DEVID_REV_MSB;
81420Sstevel@tonic-gate 	i_devid->did_rev_lo = DEVID_REV_LSB;
81430Sstevel@tonic-gate 	DEVID_FORMTYPE(i_devid, devid_type);
81440Sstevel@tonic-gate 	DEVID_FORMLEN(i_devid, nbytes);
81450Sstevel@tonic-gate 
81460Sstevel@tonic-gate 	/* Fill in driver name hint */
81470Sstevel@tonic-gate 	driver_name = ddi_driver_name(dip);
81480Sstevel@tonic-gate 	driver_len = strlen(driver_name);
81490Sstevel@tonic-gate 	if (driver_len > DEVID_HINT_SIZE) {
81500Sstevel@tonic-gate 		/* Pick up last four characters of driver name */
81510Sstevel@tonic-gate 		driver_name += driver_len - DEVID_HINT_SIZE;
81520Sstevel@tonic-gate 		driver_len = DEVID_HINT_SIZE;
81530Sstevel@tonic-gate 	}
81540Sstevel@tonic-gate 
81550Sstevel@tonic-gate 	bcopy(driver_name, i_devid->did_driver, driver_len);
81560Sstevel@tonic-gate 
81570Sstevel@tonic-gate 	/* Fill in id field */
81580Sstevel@tonic-gate 	if (devid_type == DEVID_FAB) {
81590Sstevel@tonic-gate 		char		*cp;
81608662SJordan.Vaughan@Sun.com 		uint32_t	hostid;
81610Sstevel@tonic-gate 		struct timeval32 timestamp32;
81620Sstevel@tonic-gate 		int		i;
81630Sstevel@tonic-gate 		int		*ip;
81640Sstevel@tonic-gate 		short		gen;
81650Sstevel@tonic-gate 
81660Sstevel@tonic-gate 		/* increase the generation number */
81670Sstevel@tonic-gate 		mutex_enter(&devid_gen_mutex);
81680Sstevel@tonic-gate 		gen = devid_gen_number++;
81690Sstevel@tonic-gate 		mutex_exit(&devid_gen_mutex);
81700Sstevel@tonic-gate 
81710Sstevel@tonic-gate 		cp = i_devid->did_id;
81720Sstevel@tonic-gate 
81730Sstevel@tonic-gate 		/* Fill in host id (big-endian byte ordering) */
81748662SJordan.Vaughan@Sun.com 		hostid = zone_get_hostid(NULL);
81750Sstevel@tonic-gate 		*cp++ = hibyte(hiword(hostid));
81760Sstevel@tonic-gate 		*cp++ = lobyte(hiword(hostid));
81770Sstevel@tonic-gate 		*cp++ = hibyte(loword(hostid));
81780Sstevel@tonic-gate 		*cp++ = lobyte(loword(hostid));
81790Sstevel@tonic-gate 
81800Sstevel@tonic-gate 		/*
81810Sstevel@tonic-gate 		 * Fill in timestamp (big-endian byte ordering)
81820Sstevel@tonic-gate 		 *
81830Sstevel@tonic-gate 		 * (Note that the format may have to be changed
81840Sstevel@tonic-gate 		 * before 2038 comes around, though it's arguably
81850Sstevel@tonic-gate 		 * unique enough as it is..)
81860Sstevel@tonic-gate 		 */
81870Sstevel@tonic-gate 		uniqtime32(&timestamp32);
81880Sstevel@tonic-gate 		ip = (int *)&timestamp32;
81890Sstevel@tonic-gate 		for (i = 0;
81900Sstevel@tonic-gate 		    i < sizeof (timestamp32) / sizeof (int); i++, ip++) {
81910Sstevel@tonic-gate 			int	val;
81920Sstevel@tonic-gate 			val = *ip;
81930Sstevel@tonic-gate 			*cp++ = hibyte(hiword(val));
81940Sstevel@tonic-gate 			*cp++ = lobyte(hiword(val));
81950Sstevel@tonic-gate 			*cp++ = hibyte(loword(val));
81960Sstevel@tonic-gate 			*cp++ = lobyte(loword(val));
81970Sstevel@tonic-gate 		}
81980Sstevel@tonic-gate 
81990Sstevel@tonic-gate 		/* fill in the generation number */
82000Sstevel@tonic-gate 		*cp++ = hibyte(gen);
82010Sstevel@tonic-gate 		*cp++ = lobyte(gen);
82020Sstevel@tonic-gate 	} else
82030Sstevel@tonic-gate 		bcopy(id, i_devid->did_id, nbytes);
82040Sstevel@tonic-gate 
82050Sstevel@tonic-gate 	/* return device id */
82060Sstevel@tonic-gate 	*ret_devid = (ddi_devid_t)i_devid;
82070Sstevel@tonic-gate 	return (DDI_SUCCESS);
82080Sstevel@tonic-gate }
82090Sstevel@tonic-gate 
82100Sstevel@tonic-gate int
ddi_devid_get(dev_info_t * dip,ddi_devid_t * ret_devid)82114876Smlf ddi_devid_get(dev_info_t *dip, ddi_devid_t *ret_devid)
82124876Smlf {
82134876Smlf 	return (i_ddi_devi_get_devid(DDI_DEV_T_ANY, dip, ret_devid));
82144876Smlf }
82154876Smlf 
82164876Smlf int
i_ddi_devi_get_devid(dev_t dev,dev_info_t * dip,ddi_devid_t * ret_devid)82170Sstevel@tonic-gate i_ddi_devi_get_devid(dev_t dev, dev_info_t *dip, ddi_devid_t *ret_devid)
82180Sstevel@tonic-gate {
82190Sstevel@tonic-gate 	char		*devidstr;
82200Sstevel@tonic-gate 
82210Sstevel@tonic-gate 	ASSERT(dev != DDI_DEV_T_NONE);
82220Sstevel@tonic-gate 
82230Sstevel@tonic-gate 	/* look up the property, devt specific first */
82240Sstevel@tonic-gate 	if (ddi_prop_lookup_string(dev, dip, DDI_PROP_DONTPASS,
82250Sstevel@tonic-gate 	    DEVID_PROP_NAME, &devidstr) != DDI_PROP_SUCCESS) {
82260Sstevel@tonic-gate 		if ((dev == DDI_DEV_T_ANY) ||
82270Sstevel@tonic-gate 		    (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip,
82284582Scth 		    DDI_PROP_DONTPASS, DEVID_PROP_NAME, &devidstr) !=
82294582Scth 		    DDI_PROP_SUCCESS)) {
82304582Scth 			return (DDI_FAILURE);
82310Sstevel@tonic-gate 		}
82320Sstevel@tonic-gate 	}
82330Sstevel@tonic-gate 
82340Sstevel@tonic-gate 	/* convert to binary form */
82350Sstevel@tonic-gate 	if (ddi_devid_str_decode(devidstr, ret_devid, NULL) == -1) {
82360Sstevel@tonic-gate 		ddi_prop_free(devidstr);
82370Sstevel@tonic-gate 		return (DDI_FAILURE);
82380Sstevel@tonic-gate 	}
82390Sstevel@tonic-gate 	ddi_prop_free(devidstr);
82400Sstevel@tonic-gate 	return (DDI_SUCCESS);
82410Sstevel@tonic-gate }
82420Sstevel@tonic-gate 
82430Sstevel@tonic-gate /*
82440Sstevel@tonic-gate  * Return a copy of the device id for dev_t
82450Sstevel@tonic-gate  */
82460Sstevel@tonic-gate int
ddi_lyr_get_devid(dev_t dev,ddi_devid_t * ret_devid)82470Sstevel@tonic-gate ddi_lyr_get_devid(dev_t dev, ddi_devid_t *ret_devid)
82480Sstevel@tonic-gate {
82490Sstevel@tonic-gate 	dev_info_t	*dip;
82500Sstevel@tonic-gate 	int		rval;
82510Sstevel@tonic-gate 
82520Sstevel@tonic-gate 	/* get the dip */
82530Sstevel@tonic-gate 	if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL)
82540Sstevel@tonic-gate 		return (DDI_FAILURE);
82550Sstevel@tonic-gate 
82560Sstevel@tonic-gate 	rval = i_ddi_devi_get_devid(dev, dip, ret_devid);
82570Sstevel@tonic-gate 
82580Sstevel@tonic-gate 	ddi_release_devi(dip);		/* e_ddi_hold_devi_by_dev() */
82590Sstevel@tonic-gate 	return (rval);
82600Sstevel@tonic-gate }
82610Sstevel@tonic-gate 
82620Sstevel@tonic-gate /*
82630Sstevel@tonic-gate  * Return a copy of the minor name for dev_t and spec_type
82640Sstevel@tonic-gate  */
82650Sstevel@tonic-gate int
ddi_lyr_get_minor_name(dev_t dev,int spec_type,char ** minor_name)82660Sstevel@tonic-gate ddi_lyr_get_minor_name(dev_t dev, int spec_type, char **minor_name)
82670Sstevel@tonic-gate {
82687224Scth 	char		*buf;
82697224Scth 	int		circ;
82700Sstevel@tonic-gate 	dev_info_t	*dip;
82710Sstevel@tonic-gate 	char		*nm;
82727224Scth 	int		rval;
82737224Scth 
82747224Scth 	if ((dip = e_ddi_hold_devi_by_dev(dev, 0)) == NULL) {
82757224Scth 		*minor_name = NULL;
82760Sstevel@tonic-gate 		return (DDI_FAILURE);
82770Sstevel@tonic-gate 	}
82780Sstevel@tonic-gate 
82797224Scth 	/* Find the minor name and copy into max size buf */
82807224Scth 	buf = kmem_alloc(MAXNAMELEN, KM_SLEEP);
82817224Scth 	ndi_devi_enter(dip, &circ);
82827224Scth 	nm = i_ddi_devtspectype_to_minorname(dip, dev, spec_type);
82837224Scth 	if (nm)
82847224Scth 		(void) strcpy(buf, nm);
82857224Scth 	ndi_devi_exit(dip, circ);
82867224Scth 	ddi_release_devi(dip);	/* e_ddi_hold_devi_by_dev() */
82877224Scth 
82887224Scth 	if (nm) {
82897224Scth 		/* duplicate into min size buf for return result */
82907224Scth 		*minor_name = i_ddi_strdup(buf, KM_SLEEP);
82917224Scth 		rval = DDI_SUCCESS;
82927224Scth 	} else {
82930Sstevel@tonic-gate 		*minor_name = NULL;
82947224Scth 		rval = DDI_FAILURE;
82957224Scth 	}
82967224Scth 
82977224Scth 	/* free max size buf and return */
82987224Scth 	kmem_free(buf, MAXNAMELEN);
82997224Scth 	return (rval);
83000Sstevel@tonic-gate }
83010Sstevel@tonic-gate 
83020Sstevel@tonic-gate int
ddi_lyr_devid_to_devlist(ddi_devid_t devid,char * minor_name,int * retndevs,dev_t ** retdevs)83030Sstevel@tonic-gate ddi_lyr_devid_to_devlist(
83040Sstevel@tonic-gate 	ddi_devid_t	devid,
83050Sstevel@tonic-gate 	char		*minor_name,
83060Sstevel@tonic-gate 	int		*retndevs,
83070Sstevel@tonic-gate 	dev_t		**retdevs)
83080Sstevel@tonic-gate {
83090Sstevel@tonic-gate 	ASSERT(ddi_devid_valid(devid) == DDI_SUCCESS);
83100Sstevel@tonic-gate 
83110Sstevel@tonic-gate 	if (e_devid_cache_to_devt_list(devid, minor_name,
83120Sstevel@tonic-gate 	    retndevs, retdevs) == DDI_SUCCESS) {
83130Sstevel@tonic-gate 		ASSERT(*retndevs > 0);
83140Sstevel@tonic-gate 		DDI_DEBUG_DEVID_DEVTS("ddi_lyr_devid_to_devlist",
83154582Scth 		    *retndevs, *retdevs);
83160Sstevel@tonic-gate 		return (DDI_SUCCESS);
83170Sstevel@tonic-gate 	}
83180Sstevel@tonic-gate 
83190Sstevel@tonic-gate 	if (e_ddi_devid_discovery(devid) == DDI_FAILURE) {
83200Sstevel@tonic-gate 		return (DDI_FAILURE);
83210Sstevel@tonic-gate 	}
83220Sstevel@tonic-gate 
83230Sstevel@tonic-gate 	if (e_devid_cache_to_devt_list(devid, minor_name,
83240Sstevel@tonic-gate 	    retndevs, retdevs) == DDI_SUCCESS) {
83250Sstevel@tonic-gate 		ASSERT(*retndevs > 0);
83260Sstevel@tonic-gate 		DDI_DEBUG_DEVID_DEVTS("ddi_lyr_devid_to_devlist",
83274582Scth 		    *retndevs, *retdevs);
83280Sstevel@tonic-gate 		return (DDI_SUCCESS);
83290Sstevel@tonic-gate 	}
83300Sstevel@tonic-gate 
83310Sstevel@tonic-gate 	return (DDI_FAILURE);
83320Sstevel@tonic-gate }
83330Sstevel@tonic-gate 
83340Sstevel@tonic-gate void
ddi_lyr_free_devlist(dev_t * devlist,int ndevs)83350Sstevel@tonic-gate ddi_lyr_free_devlist(dev_t *devlist, int ndevs)
83360Sstevel@tonic-gate {
83370Sstevel@tonic-gate 	kmem_free(devlist, sizeof (dev_t) * ndevs);
83380Sstevel@tonic-gate }
83390Sstevel@tonic-gate 
83400Sstevel@tonic-gate /*
83410Sstevel@tonic-gate  * Note: This will need to be fixed if we ever allow processes to
83420Sstevel@tonic-gate  * have more than one data model per exec.
83430Sstevel@tonic-gate  */
83440Sstevel@tonic-gate model_t
ddi_mmap_get_model(void)83450Sstevel@tonic-gate ddi_mmap_get_model(void)
83460Sstevel@tonic-gate {
83470Sstevel@tonic-gate 	return (get_udatamodel());
83480Sstevel@tonic-gate }
83490Sstevel@tonic-gate 
83500Sstevel@tonic-gate model_t
ddi_model_convert_from(model_t model)83510Sstevel@tonic-gate ddi_model_convert_from(model_t model)
83520Sstevel@tonic-gate {
83530Sstevel@tonic-gate 	return ((model & DDI_MODEL_MASK) & ~DDI_MODEL_NATIVE);
83540Sstevel@tonic-gate }
83550Sstevel@tonic-gate 
83560Sstevel@tonic-gate /*
83570Sstevel@tonic-gate  * ddi interfaces managing storage and retrieval of eventcookies.
83580Sstevel@tonic-gate  */
83590Sstevel@tonic-gate 
83600Sstevel@tonic-gate /*
83610Sstevel@tonic-gate  * Invoke bus nexus driver's implementation of the
83620Sstevel@tonic-gate  * (*bus_remove_eventcall)() interface to remove a registered
83630Sstevel@tonic-gate  * callback handler for "event".
83640Sstevel@tonic-gate  */
83650Sstevel@tonic-gate int
ddi_remove_event_handler(ddi_callback_id_t id)83660Sstevel@tonic-gate ddi_remove_event_handler(ddi_callback_id_t id)
83670Sstevel@tonic-gate {
83680Sstevel@tonic-gate 	ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)id;
83690Sstevel@tonic-gate 	dev_info_t *ddip;
83700Sstevel@tonic-gate 
83710Sstevel@tonic-gate 	ASSERT(cb);
83720Sstevel@tonic-gate 	if (!cb) {
83730Sstevel@tonic-gate 		return (DDI_FAILURE);
83740Sstevel@tonic-gate 	}
83750Sstevel@tonic-gate 
83760Sstevel@tonic-gate 	ddip = NDI_EVENT_DDIP(cb->ndi_evtcb_cookie);
83770Sstevel@tonic-gate 	return (ndi_busop_remove_eventcall(ddip, id));
83780Sstevel@tonic-gate }
83790Sstevel@tonic-gate 
83800Sstevel@tonic-gate /*
83810Sstevel@tonic-gate  * Invoke bus nexus driver's implementation of the
83820Sstevel@tonic-gate  * (*bus_add_eventcall)() interface to register a callback handler
83830Sstevel@tonic-gate  * for "event".
83840Sstevel@tonic-gate  */
83850Sstevel@tonic-gate int
ddi_add_event_handler(dev_info_t * dip,ddi_eventcookie_t event,void (* handler)(dev_info_t *,ddi_eventcookie_t,void *,void *),void * arg,ddi_callback_id_t * id)83860Sstevel@tonic-gate ddi_add_event_handler(dev_info_t *dip, ddi_eventcookie_t event,
83870Sstevel@tonic-gate     void (*handler)(dev_info_t *, ddi_eventcookie_t, void *, void *),
83880Sstevel@tonic-gate     void *arg, ddi_callback_id_t *id)
83890Sstevel@tonic-gate {
83900Sstevel@tonic-gate 	return (ndi_busop_add_eventcall(dip, dip, event, handler, arg, id));
83910Sstevel@tonic-gate }
83920Sstevel@tonic-gate 
83930Sstevel@tonic-gate 
83940Sstevel@tonic-gate /*
83950Sstevel@tonic-gate  * Return a handle for event "name" by calling up the device tree
83960Sstevel@tonic-gate  * hierarchy via  (*bus_get_eventcookie)() interface until claimed
83970Sstevel@tonic-gate  * by a bus nexus or top of dev_info tree is reached.
83980Sstevel@tonic-gate  */
83990Sstevel@tonic-gate int
ddi_get_eventcookie(dev_info_t * dip,char * name,ddi_eventcookie_t * event_cookiep)84000Sstevel@tonic-gate ddi_get_eventcookie(dev_info_t *dip, char *name,
84010Sstevel@tonic-gate     ddi_eventcookie_t *event_cookiep)
84020Sstevel@tonic-gate {
84030Sstevel@tonic-gate 	return (ndi_busop_get_eventcookie(dip, dip,
84040Sstevel@tonic-gate 	    name, event_cookiep));
84050Sstevel@tonic-gate }
84060Sstevel@tonic-gate 
84070Sstevel@tonic-gate /*
84080Sstevel@tonic-gate  * This procedure is provided as the general callback function when
84090Sstevel@tonic-gate  * umem_lockmemory calls as_add_callback for long term memory locking.
84100Sstevel@tonic-gate  * When as_unmap, as_setprot, or as_free encounter segments which have
84110Sstevel@tonic-gate  * locked memory, this callback will be invoked.
84120Sstevel@tonic-gate  */
84130Sstevel@tonic-gate void
umem_lock_undo(struct as * as,void * arg,uint_t event)84140Sstevel@tonic-gate umem_lock_undo(struct as *as, void *arg, uint_t event)
84150Sstevel@tonic-gate {
84160Sstevel@tonic-gate 	_NOTE(ARGUNUSED(as, event))
84170Sstevel@tonic-gate 	struct ddi_umem_cookie *cp = (struct ddi_umem_cookie *)arg;
84180Sstevel@tonic-gate 
84190Sstevel@tonic-gate 	/*
84200Sstevel@tonic-gate 	 * Call the cleanup function.  Decrement the cookie reference
84210Sstevel@tonic-gate 	 * count, if it goes to zero, return the memory for the cookie.
84220Sstevel@tonic-gate 	 * The i_ddi_umem_unlock for this cookie may or may not have been
84230Sstevel@tonic-gate 	 * called already.  It is the responsibility of the caller of
84240Sstevel@tonic-gate 	 * umem_lockmemory to handle the case of the cleanup routine
84250Sstevel@tonic-gate 	 * being called after a ddi_umem_unlock for the cookie
84260Sstevel@tonic-gate 	 * was called.
84270Sstevel@tonic-gate 	 */
84280Sstevel@tonic-gate 
84290Sstevel@tonic-gate 	(*cp->callbacks.cbo_umem_lock_cleanup)((ddi_umem_cookie_t)cp);
84300Sstevel@tonic-gate 
84310Sstevel@tonic-gate 	/* remove the cookie if reference goes to zero */
84320Sstevel@tonic-gate 	if (atomic_add_long_nv((ulong_t *)(&(cp->cook_refcnt)), -1) == 0) {
84330Sstevel@tonic-gate 		kmem_free(cp, sizeof (struct ddi_umem_cookie));
84340Sstevel@tonic-gate 	}
84350Sstevel@tonic-gate }
84360Sstevel@tonic-gate 
84370Sstevel@tonic-gate /*
84380Sstevel@tonic-gate  * The following two Consolidation Private routines provide generic
84390Sstevel@tonic-gate  * interfaces to increase/decrease the amount of device-locked memory.
84400Sstevel@tonic-gate  *
84410Sstevel@tonic-gate  * To keep project_rele and project_hold consistent, i_ddi_decr_locked_memory()
84420Sstevel@tonic-gate  * must be called every time i_ddi_incr_locked_memory() is called.
84430Sstevel@tonic-gate  */
84440Sstevel@tonic-gate int
84450Sstevel@tonic-gate /* ARGSUSED */
i_ddi_incr_locked_memory(proc_t * procp,rctl_qty_t inc)84462768Ssl108498 i_ddi_incr_locked_memory(proc_t *procp, rctl_qty_t inc)
84472768Ssl108498 {
84482768Ssl108498 	ASSERT(procp != NULL);
84492768Ssl108498 	mutex_enter(&procp->p_lock);
84502768Ssl108498 	if (rctl_incr_locked_mem(procp, NULL, inc, 1)) {
84512768Ssl108498 		mutex_exit(&procp->p_lock);
84520Sstevel@tonic-gate 		return (ENOMEM);
84530Sstevel@tonic-gate 	}
84542768Ssl108498 	mutex_exit(&procp->p_lock);
84550Sstevel@tonic-gate 	return (0);
84560Sstevel@tonic-gate }
84570Sstevel@tonic-gate 
84580Sstevel@tonic-gate /*
84590Sstevel@tonic-gate  * To keep project_rele and project_hold consistent, i_ddi_incr_locked_memory()
84600Sstevel@tonic-gate  * must be called every time i_ddi_decr_locked_memory() is called.
84610Sstevel@tonic-gate  */
84620Sstevel@tonic-gate /* ARGSUSED */
84630Sstevel@tonic-gate void
i_ddi_decr_locked_memory(proc_t * procp,rctl_qty_t dec)84642768Ssl108498 i_ddi_decr_locked_memory(proc_t *procp, rctl_qty_t dec)
84652768Ssl108498 {
84662768Ssl108498 	ASSERT(procp != NULL);
84672768Ssl108498 	mutex_enter(&procp->p_lock);
84682768Ssl108498 	rctl_decr_locked_mem(procp, NULL, dec, 1);
84692768Ssl108498 	mutex_exit(&procp->p_lock);
84702768Ssl108498 }
84712768Ssl108498 
84722768Ssl108498 /*
847312400Sgerald.jelinek@sun.com  * The cookie->upd_max_lock_rctl flag is used to determine if we should
847412400Sgerald.jelinek@sun.com  * charge device locked memory to the max-locked-memory rctl.  Tracking
847512400Sgerald.jelinek@sun.com  * device locked memory causes the rctl locks to get hot under high-speed
847612400Sgerald.jelinek@sun.com  * I/O such as RDSv3 over IB.  If there is no max-locked-memory rctl limit,
847712400Sgerald.jelinek@sun.com  * we bypass charging the locked memory to the rctl altogether.  The cookie's
847812400Sgerald.jelinek@sun.com  * flag tells us if the rctl value should be updated when unlocking the memory,
847912400Sgerald.jelinek@sun.com  * in case the rctl gets changed after the memory was locked.  Any device
848012400Sgerald.jelinek@sun.com  * locked memory in that rare case will not be counted toward the rctl limit.
848112400Sgerald.jelinek@sun.com  *
848212400Sgerald.jelinek@sun.com  * When tracking the locked memory, the kproject_t parameter is always NULL
848312400Sgerald.jelinek@sun.com  * in the code paths:
848412400Sgerald.jelinek@sun.com  *	i_ddi_incr_locked_memory -> rctl_incr_locked_mem
848512400Sgerald.jelinek@sun.com  *	i_ddi_decr_locked_memory -> rctl_decr_locked_mem
848612400Sgerald.jelinek@sun.com  * Thus, we always use the tk_proj member to check the projp setting.
848712400Sgerald.jelinek@sun.com  */
848812400Sgerald.jelinek@sun.com static void
init_lockedmem_rctl_flag(struct ddi_umem_cookie * cookie)848912400Sgerald.jelinek@sun.com init_lockedmem_rctl_flag(struct ddi_umem_cookie *cookie)
849012400Sgerald.jelinek@sun.com {
849112400Sgerald.jelinek@sun.com 	proc_t		*p;
849212400Sgerald.jelinek@sun.com 	kproject_t	*projp;
849312400Sgerald.jelinek@sun.com 	zone_t		*zonep;
849412400Sgerald.jelinek@sun.com 
849512400Sgerald.jelinek@sun.com 	ASSERT(cookie);
849612400Sgerald.jelinek@sun.com 	p = cookie->procp;
849712400Sgerald.jelinek@sun.com 	ASSERT(p);
849812400Sgerald.jelinek@sun.com 
849912400Sgerald.jelinek@sun.com 	zonep = p->p_zone;
850012400Sgerald.jelinek@sun.com 	projp = p->p_task->tk_proj;
850112400Sgerald.jelinek@sun.com 
850212400Sgerald.jelinek@sun.com 	ASSERT(zonep);
850312400Sgerald.jelinek@sun.com 	ASSERT(projp);
850412400Sgerald.jelinek@sun.com 
850512400Sgerald.jelinek@sun.com 	if (zonep->zone_locked_mem_ctl == UINT64_MAX &&
850612400Sgerald.jelinek@sun.com 	    projp->kpj_data.kpd_locked_mem_ctl == UINT64_MAX)
850712400Sgerald.jelinek@sun.com 		cookie->upd_max_lock_rctl = 0;
850812400Sgerald.jelinek@sun.com 	else
850912400Sgerald.jelinek@sun.com 		cookie->upd_max_lock_rctl = 1;
851012400Sgerald.jelinek@sun.com }
851112400Sgerald.jelinek@sun.com 
851212400Sgerald.jelinek@sun.com /*
85132768Ssl108498  * This routine checks if the max-locked-memory resource ctl is
85140Sstevel@tonic-gate  * exceeded, if not increments it, grabs a hold on the project.
85150Sstevel@tonic-gate  * Returns 0 if successful otherwise returns error code
85160Sstevel@tonic-gate  */
85170Sstevel@tonic-gate static int
umem_incr_devlockmem(struct ddi_umem_cookie * cookie)85180Sstevel@tonic-gate umem_incr_devlockmem(struct ddi_umem_cookie *cookie)
85190Sstevel@tonic-gate {
85200Sstevel@tonic-gate 	proc_t		*procp;
85210Sstevel@tonic-gate 	int		ret;
85220Sstevel@tonic-gate 
85230Sstevel@tonic-gate 	ASSERT(cookie);
852412400Sgerald.jelinek@sun.com 	if (cookie->upd_max_lock_rctl == 0)
852512400Sgerald.jelinek@sun.com 		return (0);
852612400Sgerald.jelinek@sun.com 
85270Sstevel@tonic-gate 	procp = cookie->procp;
85280Sstevel@tonic-gate 	ASSERT(procp);
85290Sstevel@tonic-gate 
85302768Ssl108498 	if ((ret = i_ddi_incr_locked_memory(procp,
85314582Scth 	    cookie->size)) != 0) {
85320Sstevel@tonic-gate 		return (ret);
85330Sstevel@tonic-gate 	}
85340Sstevel@tonic-gate 	return (0);
85350Sstevel@tonic-gate }
85360Sstevel@tonic-gate 
85370Sstevel@tonic-gate /*
85382768Ssl108498  * Decrements the max-locked-memory resource ctl and releases
85390Sstevel@tonic-gate  * the hold on the project that was acquired during umem_incr_devlockmem
85400Sstevel@tonic-gate  */
85410Sstevel@tonic-gate static void
umem_decr_devlockmem(struct ddi_umem_cookie * cookie)85420Sstevel@tonic-gate umem_decr_devlockmem(struct ddi_umem_cookie *cookie)
85430Sstevel@tonic-gate {
85442768Ssl108498 	proc_t		*proc;
85452768Ssl108498 
854612400Sgerald.jelinek@sun.com 	if (cookie->upd_max_lock_rctl == 0)
854712400Sgerald.jelinek@sun.com 		return;
854812400Sgerald.jelinek@sun.com 
85492768Ssl108498 	proc = (proc_t *)cookie->procp;
85502768Ssl108498 	if (!proc)
85510Sstevel@tonic-gate 		return;
85520Sstevel@tonic-gate 
85532768Ssl108498 	i_ddi_decr_locked_memory(proc, cookie->size);
85540Sstevel@tonic-gate }
85550Sstevel@tonic-gate 
85560Sstevel@tonic-gate /*
85570Sstevel@tonic-gate  * A consolidation private function which is essentially equivalent to
85580Sstevel@tonic-gate  * ddi_umem_lock but with the addition of arguments ops_vector and procp.
85590Sstevel@tonic-gate  * A call to as_add_callback is done if DDI_UMEMLOCK_LONGTERM is set, and
85600Sstevel@tonic-gate  * the ops_vector is valid.
85610Sstevel@tonic-gate  *
85620Sstevel@tonic-gate  * Lock the virtual address range in the current process and create a
85630Sstevel@tonic-gate  * ddi_umem_cookie (of type UMEM_LOCKED). This can be used to pass to
85640Sstevel@tonic-gate  * ddi_umem_iosetup to create a buf or do devmap_umem_setup/remap to export
85650Sstevel@tonic-gate  * to user space.
85660Sstevel@tonic-gate  *
85670Sstevel@tonic-gate  * Note: The resource control accounting currently uses a full charge model
85680Sstevel@tonic-gate  * in other words attempts to lock the same/overlapping areas of memory
85690Sstevel@tonic-gate  * will deduct the full size of the buffer from the projects running
85700Sstevel@tonic-gate  * counter for the device locked memory.
85710Sstevel@tonic-gate  *
85720Sstevel@tonic-gate  * addr, size should be PAGESIZE aligned
85730Sstevel@tonic-gate  *
85740Sstevel@tonic-gate  * flags - DDI_UMEMLOCK_READ, DDI_UMEMLOCK_WRITE or both
85750Sstevel@tonic-gate  *	identifies whether the locked memory will be read or written or both
85760Sstevel@tonic-gate  *      DDI_UMEMLOCK_LONGTERM  must be set when the locking will
85770Sstevel@tonic-gate  * be maintained for an indefinitely long period (essentially permanent),
85780Sstevel@tonic-gate  * rather than for what would be required for a typical I/O completion.
85790Sstevel@tonic-gate  * When DDI_UMEMLOCK_LONGTERM is set, umem_lockmemory will return EFAULT
85800Sstevel@tonic-gate  * if the memory pertains to a regular file which is mapped MAP_SHARED.
85810Sstevel@tonic-gate  * This is to prevent a deadlock if a file truncation is attempted after
85820Sstevel@tonic-gate  * after the locking is done.
85830Sstevel@tonic-gate  *
85840Sstevel@tonic-gate  * Returns 0 on success
85850Sstevel@tonic-gate  *	EINVAL - for invalid parameters
85860Sstevel@tonic-gate  *	EPERM, ENOMEM and other error codes returned by as_pagelock
85870Sstevel@tonic-gate  *	ENOMEM - is returned if the current request to lock memory exceeds
85882768Ssl108498  *		*.max-locked-memory resource control value.
85890Sstevel@tonic-gate  *      EFAULT - memory pertains to a regular file mapped shared and
85900Sstevel@tonic-gate  *		and DDI_UMEMLOCK_LONGTERM flag is set
85910Sstevel@tonic-gate  *	EAGAIN - could not start the ddi_umem_unlock list processing thread
85920Sstevel@tonic-gate  */
85930Sstevel@tonic-gate int
umem_lockmemory(caddr_t addr,size_t len,int flags,ddi_umem_cookie_t * cookie,struct umem_callback_ops * ops_vector,proc_t * procp)85940Sstevel@tonic-gate umem_lockmemory(caddr_t addr, size_t len, int flags, ddi_umem_cookie_t *cookie,
85950Sstevel@tonic-gate 		struct umem_callback_ops *ops_vector,
85960Sstevel@tonic-gate 		proc_t *procp)
85970Sstevel@tonic-gate {
85980Sstevel@tonic-gate 	int	error;
85990Sstevel@tonic-gate 	struct ddi_umem_cookie *p;
86000Sstevel@tonic-gate 	void	(*driver_callback)() = NULL;
860110366SBill.Taylor@Sun.COM 	struct as *as;
86020Sstevel@tonic-gate 	struct seg		*seg;
86030Sstevel@tonic-gate 	vnode_t			*vp;
86040Sstevel@tonic-gate 
860510366SBill.Taylor@Sun.COM 	/* Allow device drivers to not have to reference "curproc" */
860610366SBill.Taylor@Sun.COM 	if (procp == NULL)
860710366SBill.Taylor@Sun.COM 		procp = curproc;
860810366SBill.Taylor@Sun.COM 	as = procp->p_as;
86090Sstevel@tonic-gate 	*cookie = NULL;		/* in case of any error return */
86100Sstevel@tonic-gate 
86110Sstevel@tonic-gate 	/* These are the only three valid flags */
86120Sstevel@tonic-gate 	if ((flags & ~(DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE |
86130Sstevel@tonic-gate 	    DDI_UMEMLOCK_LONGTERM)) != 0)
86140Sstevel@tonic-gate 		return (EINVAL);
86150Sstevel@tonic-gate 
86160Sstevel@tonic-gate 	/* At least one (can be both) of the two access flags must be set */
86170Sstevel@tonic-gate 	if ((flags & (DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE)) == 0)
86180Sstevel@tonic-gate 		return (EINVAL);
86190Sstevel@tonic-gate 
86200Sstevel@tonic-gate 	/* addr and len must be page-aligned */
86210Sstevel@tonic-gate 	if (((uintptr_t)addr & PAGEOFFSET) != 0)
86220Sstevel@tonic-gate 		return (EINVAL);
86230Sstevel@tonic-gate 
86240Sstevel@tonic-gate 	if ((len & PAGEOFFSET) != 0)
86250Sstevel@tonic-gate 		return (EINVAL);
86260Sstevel@tonic-gate 
86270Sstevel@tonic-gate 	/*
86280Sstevel@tonic-gate 	 * For longterm locking a driver callback must be specified; if
86290Sstevel@tonic-gate 	 * not longterm then a callback is optional.
86300Sstevel@tonic-gate 	 */
86310Sstevel@tonic-gate 	if (ops_vector != NULL) {
86320Sstevel@tonic-gate 		if (ops_vector->cbo_umem_callback_version !=
86330Sstevel@tonic-gate 		    UMEM_CALLBACK_VERSION)
86340Sstevel@tonic-gate 			return (EINVAL);
86350Sstevel@tonic-gate 		else
86360Sstevel@tonic-gate 			driver_callback = ops_vector->cbo_umem_lock_cleanup;
86370Sstevel@tonic-gate 	}
86380Sstevel@tonic-gate 	if ((driver_callback == NULL) && (flags & DDI_UMEMLOCK_LONGTERM))
86390Sstevel@tonic-gate 		return (EINVAL);
86400Sstevel@tonic-gate 
86410Sstevel@tonic-gate 	/*
86420Sstevel@tonic-gate 	 * Call i_ddi_umem_unlock_thread_start if necessary.  It will
86430Sstevel@tonic-gate 	 * be called on first ddi_umem_lock or umem_lockmemory call.
86440Sstevel@tonic-gate 	 */
86450Sstevel@tonic-gate 	if (ddi_umem_unlock_thread == NULL)
86460Sstevel@tonic-gate 		i_ddi_umem_unlock_thread_start();
86470Sstevel@tonic-gate 
86480Sstevel@tonic-gate 	/* Allocate memory for the cookie */
86490Sstevel@tonic-gate 	p = kmem_zalloc(sizeof (struct ddi_umem_cookie), KM_SLEEP);
86500Sstevel@tonic-gate 
86510Sstevel@tonic-gate 	/* Convert the flags to seg_rw type */
86520Sstevel@tonic-gate 	if (flags & DDI_UMEMLOCK_WRITE) {
86530Sstevel@tonic-gate 		p->s_flags = S_WRITE;
86540Sstevel@tonic-gate 	} else {
86550Sstevel@tonic-gate 		p->s_flags = S_READ;
86560Sstevel@tonic-gate 	}
86570Sstevel@tonic-gate 
86580Sstevel@tonic-gate 	/* Store procp in cookie for later iosetup/unlock */
86590Sstevel@tonic-gate 	p->procp = (void *)procp;
86600Sstevel@tonic-gate 
86610Sstevel@tonic-gate 	/*
86620Sstevel@tonic-gate 	 * Store the struct as pointer in cookie for later use by
86630Sstevel@tonic-gate 	 * ddi_umem_unlock.  The proc->p_as will be stale if ddi_umem_unlock
86640Sstevel@tonic-gate 	 * is called after relvm is called.
86650Sstevel@tonic-gate 	 */
86660Sstevel@tonic-gate 	p->asp = as;
86670Sstevel@tonic-gate 
86680Sstevel@tonic-gate 	/*
86690Sstevel@tonic-gate 	 * The size field is needed for lockmem accounting.
86700Sstevel@tonic-gate 	 */
86710Sstevel@tonic-gate 	p->size = len;
867212400Sgerald.jelinek@sun.com 	init_lockedmem_rctl_flag(p);
86730Sstevel@tonic-gate 
86740Sstevel@tonic-gate 	if (umem_incr_devlockmem(p) != 0) {
86750Sstevel@tonic-gate 		/*
86760Sstevel@tonic-gate 		 * The requested memory cannot be locked
86770Sstevel@tonic-gate 		 */
86780Sstevel@tonic-gate 		kmem_free(p, sizeof (struct ddi_umem_cookie));
86790Sstevel@tonic-gate 		*cookie = (ddi_umem_cookie_t)NULL;
86800Sstevel@tonic-gate 		return (ENOMEM);
86810Sstevel@tonic-gate 	}
86820Sstevel@tonic-gate 
86830Sstevel@tonic-gate 	/* Lock the pages corresponding to addr, len in memory */
86840Sstevel@tonic-gate 	error = as_pagelock(as, &(p->pparray), addr, len, p->s_flags);
86850Sstevel@tonic-gate 	if (error != 0) {
86860Sstevel@tonic-gate 		umem_decr_devlockmem(p);
86870Sstevel@tonic-gate 		kmem_free(p, sizeof (struct ddi_umem_cookie));
86880Sstevel@tonic-gate 		*cookie = (ddi_umem_cookie_t)NULL;
86890Sstevel@tonic-gate 		return (error);
86900Sstevel@tonic-gate 	}
86910Sstevel@tonic-gate 
86920Sstevel@tonic-gate 	/*
86930Sstevel@tonic-gate 	 * For longterm locking the addr must pertain to a seg_vn segment or
86940Sstevel@tonic-gate 	 * or a seg_spt segment.
86950Sstevel@tonic-gate 	 * If the segment pertains to a regular file, it cannot be
86960Sstevel@tonic-gate 	 * mapped MAP_SHARED.
86970Sstevel@tonic-gate 	 * This is to prevent a deadlock if a file truncation is attempted
86980Sstevel@tonic-gate 	 * after the locking is done.
86990Sstevel@tonic-gate 	 * Doing this after as_pagelock guarantees persistence of the as; if
87000Sstevel@tonic-gate 	 * an unacceptable segment is found, the cleanup includes calling
87010Sstevel@tonic-gate 	 * as_pageunlock before returning EFAULT.
870210366SBill.Taylor@Sun.COM 	 *
870310366SBill.Taylor@Sun.COM 	 * segdev is allowed here as it is already locked.  This allows
870410366SBill.Taylor@Sun.COM 	 * for memory exported by drivers through mmap() (which is already
870510366SBill.Taylor@Sun.COM 	 * locked) to be allowed for LONGTERM.
87060Sstevel@tonic-gate 	 */
87070Sstevel@tonic-gate 	if (flags & DDI_UMEMLOCK_LONGTERM) {
87080Sstevel@tonic-gate 		extern  struct seg_ops segspt_shmops;
870910366SBill.Taylor@Sun.COM 		extern	struct seg_ops segdev_ops;
87100Sstevel@tonic-gate 		AS_LOCK_ENTER(as, &as->a_lock, RW_READER);
87110Sstevel@tonic-gate 		for (seg = as_segat(as, addr); ; seg = AS_SEGNEXT(as, seg)) {
87120Sstevel@tonic-gate 			if (seg == NULL || seg->s_base > addr + len)
87130Sstevel@tonic-gate 				break;
871410366SBill.Taylor@Sun.COM 			if (seg->s_ops == &segdev_ops)
871510366SBill.Taylor@Sun.COM 				continue;
87160Sstevel@tonic-gate 			if (((seg->s_ops != &segvn_ops) &&
87170Sstevel@tonic-gate 			    (seg->s_ops != &segspt_shmops)) ||
87180Sstevel@tonic-gate 			    ((SEGOP_GETVP(seg, addr, &vp) == 0 &&
87190Sstevel@tonic-gate 			    vp != NULL && vp->v_type == VREG) &&
87200Sstevel@tonic-gate 			    (SEGOP_GETTYPE(seg, addr) & MAP_SHARED))) {
87210Sstevel@tonic-gate 				as_pageunlock(as, p->pparray,
87224582Scth 				    addr, len, p->s_flags);
87230Sstevel@tonic-gate 				AS_LOCK_EXIT(as, &as->a_lock);
87240Sstevel@tonic-gate 				umem_decr_devlockmem(p);
87250Sstevel@tonic-gate 				kmem_free(p, sizeof (struct ddi_umem_cookie));
87260Sstevel@tonic-gate 				*cookie = (ddi_umem_cookie_t)NULL;
87270Sstevel@tonic-gate 				return (EFAULT);
87280Sstevel@tonic-gate 			}
87290Sstevel@tonic-gate 		}
87300Sstevel@tonic-gate 		AS_LOCK_EXIT(as, &as->a_lock);
87310Sstevel@tonic-gate 	}
87320Sstevel@tonic-gate 
87330Sstevel@tonic-gate 
87340Sstevel@tonic-gate 	/* Initialize the fields in the ddi_umem_cookie */
87350Sstevel@tonic-gate 	p->cvaddr = addr;
87360Sstevel@tonic-gate 	p->type = UMEM_LOCKED;
87370Sstevel@tonic-gate 	if (driver_callback != NULL) {
87380Sstevel@tonic-gate 		/* i_ddi_umem_unlock and umem_lock_undo may need the cookie */
87390Sstevel@tonic-gate 		p->cook_refcnt = 2;
87400Sstevel@tonic-gate 		p->callbacks = *ops_vector;
87410Sstevel@tonic-gate 	} else {
87420Sstevel@tonic-gate 		/* only i_ddi_umme_unlock needs the cookie */
87430Sstevel@tonic-gate 		p->cook_refcnt = 1;
87440Sstevel@tonic-gate 	}
87450Sstevel@tonic-gate 
87460Sstevel@tonic-gate 	*cookie = (ddi_umem_cookie_t)p;
87470Sstevel@tonic-gate 
87480Sstevel@tonic-gate 	/*
87490Sstevel@tonic-gate 	 * If a driver callback was specified, add an entry to the
87500Sstevel@tonic-gate 	 * as struct callback list. The as_pagelock above guarantees
87510Sstevel@tonic-gate 	 * the persistence of as.
87520Sstevel@tonic-gate 	 */
87530Sstevel@tonic-gate 	if (driver_callback) {
87540Sstevel@tonic-gate 		error = as_add_callback(as, umem_lock_undo, p, AS_ALL_EVENT,
87554582Scth 		    addr, len, KM_SLEEP);
87560Sstevel@tonic-gate 		if (error != 0) {
87570Sstevel@tonic-gate 			as_pageunlock(as, p->pparray,
87584582Scth 			    addr, len, p->s_flags);
87590Sstevel@tonic-gate 			umem_decr_devlockmem(p);
87600Sstevel@tonic-gate 			kmem_free(p, sizeof (struct ddi_umem_cookie));
87610Sstevel@tonic-gate 			*cookie = (ddi_umem_cookie_t)NULL;
87620Sstevel@tonic-gate 		}
87630Sstevel@tonic-gate 	}
87640Sstevel@tonic-gate 	return (error);
87650Sstevel@tonic-gate }
87660Sstevel@tonic-gate 
87670Sstevel@tonic-gate /*
87680Sstevel@tonic-gate  * Unlock the pages locked by ddi_umem_lock or umem_lockmemory and free
87690Sstevel@tonic-gate  * the cookie.  Called from i_ddi_umem_unlock_thread.
87700Sstevel@tonic-gate  */
87710Sstevel@tonic-gate 
87720Sstevel@tonic-gate static void
i_ddi_umem_unlock(struct ddi_umem_cookie * p)87730Sstevel@tonic-gate i_ddi_umem_unlock(struct ddi_umem_cookie *p)
87740Sstevel@tonic-gate {
87750Sstevel@tonic-gate 	uint_t	rc;
87760Sstevel@tonic-gate 
87770Sstevel@tonic-gate 	/*
87780Sstevel@tonic-gate 	 * There is no way to determine whether a callback to
87790Sstevel@tonic-gate 	 * umem_lock_undo was registered via as_add_callback.
87800Sstevel@tonic-gate 	 * (i.e. umem_lockmemory was called with DDI_MEMLOCK_LONGTERM and
87810Sstevel@tonic-gate 	 * a valid callback function structure.)  as_delete_callback
87820Sstevel@tonic-gate 	 * is called to delete a possible registered callback.  If the
87830Sstevel@tonic-gate 	 * return from as_delete_callbacks is AS_CALLBACK_DELETED, it
87840Sstevel@tonic-gate 	 * indicates that there was a callback registered, and that is was
87850Sstevel@tonic-gate 	 * successfully deleted.  Thus, the cookie reference count
87860Sstevel@tonic-gate 	 * will never be decremented by umem_lock_undo.  Just return the
87870Sstevel@tonic-gate 	 * memory for the cookie, since both users of the cookie are done.
87880Sstevel@tonic-gate 	 * A return of AS_CALLBACK_NOTFOUND indicates a callback was
87890Sstevel@tonic-gate 	 * never registered.  A return of AS_CALLBACK_DELETE_DEFERRED
87900Sstevel@tonic-gate 	 * indicates that callback processing is taking place and, and
87910Sstevel@tonic-gate 	 * umem_lock_undo is, or will be, executing, and thus decrementing
87920Sstevel@tonic-gate 	 * the cookie reference count when it is complete.
87930Sstevel@tonic-gate 	 *
87940Sstevel@tonic-gate 	 * This needs to be done before as_pageunlock so that the
87950Sstevel@tonic-gate 	 * persistence of as is guaranteed because of the locked pages.
87960Sstevel@tonic-gate 	 *
87970Sstevel@tonic-gate 	 */
87980Sstevel@tonic-gate 	rc = as_delete_callback(p->asp, p);
87990Sstevel@tonic-gate 
88000Sstevel@tonic-gate 
88010Sstevel@tonic-gate 	/*
88020Sstevel@tonic-gate 	 * The proc->p_as will be stale if i_ddi_umem_unlock is called
88030Sstevel@tonic-gate 	 * after relvm is called so use p->asp.
88040Sstevel@tonic-gate 	 */
88050Sstevel@tonic-gate 	as_pageunlock(p->asp, p->pparray, p->cvaddr, p->size, p->s_flags);
88060Sstevel@tonic-gate 
88070Sstevel@tonic-gate 	/*
88080Sstevel@tonic-gate 	 * Now that we have unlocked the memory decrement the
88092768Ssl108498 	 * *.max-locked-memory rctl
88100Sstevel@tonic-gate 	 */
88110Sstevel@tonic-gate 	umem_decr_devlockmem(p);
88120Sstevel@tonic-gate 
88130Sstevel@tonic-gate 	if (rc == AS_CALLBACK_DELETED) {
88140Sstevel@tonic-gate 		/* umem_lock_undo will not happen, return the cookie memory */
88150Sstevel@tonic-gate 		ASSERT(p->cook_refcnt == 2);
88160Sstevel@tonic-gate 		kmem_free(p, sizeof (struct ddi_umem_cookie));
88170Sstevel@tonic-gate 	} else {
88180Sstevel@tonic-gate 		/*
88190Sstevel@tonic-gate 		 * umem_undo_lock may happen if as_delete_callback returned
88200Sstevel@tonic-gate 		 * AS_CALLBACK_DELETE_DEFERRED.  In that case, decrement the
88210Sstevel@tonic-gate 		 * reference count, atomically, and return the cookie
88220Sstevel@tonic-gate 		 * memory if the reference count goes to zero.  The only
88230Sstevel@tonic-gate 		 * other value for rc is AS_CALLBACK_NOTFOUND.  In that
88240Sstevel@tonic-gate 		 * case, just return the cookie memory.
88250Sstevel@tonic-gate 		 */
88260Sstevel@tonic-gate 		if ((rc != AS_CALLBACK_DELETE_DEFERRED) ||
88270Sstevel@tonic-gate 		    (atomic_add_long_nv((ulong_t *)(&(p->cook_refcnt)), -1)
88280Sstevel@tonic-gate 		    == 0)) {
88290Sstevel@tonic-gate 			kmem_free(p, sizeof (struct ddi_umem_cookie));
88300Sstevel@tonic-gate 		}
88310Sstevel@tonic-gate 	}
88320Sstevel@tonic-gate }
88330Sstevel@tonic-gate 
88340Sstevel@tonic-gate /*
88350Sstevel@tonic-gate  * i_ddi_umem_unlock_thread - deferred ddi_umem_unlock list handler.
88360Sstevel@tonic-gate  *
88370Sstevel@tonic-gate  * Call i_ddi_umem_unlock for entries in the ddi_umem_unlock list
88380Sstevel@tonic-gate  * until it is empty.  Then, wait for more to be added.  This thread is awoken
88390Sstevel@tonic-gate  * via calls to ddi_umem_unlock.
88400Sstevel@tonic-gate  */
88410Sstevel@tonic-gate 
88420Sstevel@tonic-gate static void
i_ddi_umem_unlock_thread(void)88430Sstevel@tonic-gate i_ddi_umem_unlock_thread(void)
88440Sstevel@tonic-gate {
88450Sstevel@tonic-gate 	struct ddi_umem_cookie	*ret_cookie;
88460Sstevel@tonic-gate 	callb_cpr_t	cprinfo;
88470Sstevel@tonic-gate 
88480Sstevel@tonic-gate 	/* process the ddi_umem_unlock list */
88490Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &ddi_umem_unlock_mutex,
88500Sstevel@tonic-gate 	    callb_generic_cpr, "unlock_thread");
88510Sstevel@tonic-gate 	for (;;) {
88520Sstevel@tonic-gate 		mutex_enter(&ddi_umem_unlock_mutex);
88530Sstevel@tonic-gate 		if (ddi_umem_unlock_head != NULL) {	/* list not empty */
88540Sstevel@tonic-gate 			ret_cookie = ddi_umem_unlock_head;
88550Sstevel@tonic-gate 			/* take if off the list */
88560Sstevel@tonic-gate 			if ((ddi_umem_unlock_head =
88570Sstevel@tonic-gate 			    ddi_umem_unlock_head->unl_forw) == NULL) {
88580Sstevel@tonic-gate 				ddi_umem_unlock_tail = NULL;
88590Sstevel@tonic-gate 			}
88600Sstevel@tonic-gate 			mutex_exit(&ddi_umem_unlock_mutex);
88610Sstevel@tonic-gate 			/* unlock the pages in this cookie */
88620Sstevel@tonic-gate 			(void) i_ddi_umem_unlock(ret_cookie);
88630Sstevel@tonic-gate 		} else {   /* list is empty, wait for next ddi_umem_unlock */
88640Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
88650Sstevel@tonic-gate 			cv_wait(&ddi_umem_unlock_cv, &ddi_umem_unlock_mutex);
88660Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(&cprinfo, &ddi_umem_unlock_mutex);
88670Sstevel@tonic-gate 			mutex_exit(&ddi_umem_unlock_mutex);
88680Sstevel@tonic-gate 		}
88690Sstevel@tonic-gate 	}
88700Sstevel@tonic-gate 	/* ddi_umem_unlock_thread does not exit */
88710Sstevel@tonic-gate 	/* NOTREACHED */
88720Sstevel@tonic-gate }
88730Sstevel@tonic-gate 
88740Sstevel@tonic-gate /*
88750Sstevel@tonic-gate  * Start the thread that will process the ddi_umem_unlock list if it is
88760Sstevel@tonic-gate  * not already started (i_ddi_umem_unlock_thread).
88770Sstevel@tonic-gate  */
88780Sstevel@tonic-gate static void
i_ddi_umem_unlock_thread_start(void)88790Sstevel@tonic-gate i_ddi_umem_unlock_thread_start(void)
88800Sstevel@tonic-gate {
88810Sstevel@tonic-gate 	mutex_enter(&ddi_umem_unlock_mutex);
88820Sstevel@tonic-gate 	if (ddi_umem_unlock_thread == NULL) {
88830Sstevel@tonic-gate 		ddi_umem_unlock_thread = thread_create(NULL, 0,
88840Sstevel@tonic-gate 		    i_ddi_umem_unlock_thread, NULL, 0, &p0,
88850Sstevel@tonic-gate 		    TS_RUN, minclsyspri);
88860Sstevel@tonic-gate 	}
88870Sstevel@tonic-gate 	mutex_exit(&ddi_umem_unlock_mutex);
88880Sstevel@tonic-gate }
88890Sstevel@tonic-gate 
88900Sstevel@tonic-gate /*
88910Sstevel@tonic-gate  * Lock the virtual address range in the current process and create a
88920Sstevel@tonic-gate  * ddi_umem_cookie (of type UMEM_LOCKED). This can be used to pass to
88930Sstevel@tonic-gate  * ddi_umem_iosetup to create a buf or do devmap_umem_setup/remap to export
88940Sstevel@tonic-gate  * to user space.
88950Sstevel@tonic-gate  *
88960Sstevel@tonic-gate  * Note: The resource control accounting currently uses a full charge model
88970Sstevel@tonic-gate  * in other words attempts to lock the same/overlapping areas of memory
88980Sstevel@tonic-gate  * will deduct the full size of the buffer from the projects running
88990Sstevel@tonic-gate  * counter for the device locked memory. This applies to umem_lockmemory too.
89000Sstevel@tonic-gate  *
89010Sstevel@tonic-gate  * addr, size should be PAGESIZE aligned
89020Sstevel@tonic-gate  * flags - DDI_UMEMLOCK_READ, DDI_UMEMLOCK_WRITE or both
89030Sstevel@tonic-gate  *	identifies whether the locked memory will be read or written or both
89040Sstevel@tonic-gate  *
89050Sstevel@tonic-gate  * Returns 0 on success
89060Sstevel@tonic-gate  *	EINVAL - for invalid parameters
89070Sstevel@tonic-gate  *	EPERM, ENOMEM and other error codes returned by as_pagelock
89080Sstevel@tonic-gate  *	ENOMEM - is returned if the current request to lock memory exceeds
89092768Ssl108498  *		*.max-locked-memory resource control value.
89100Sstevel@tonic-gate  *	EAGAIN - could not start the ddi_umem_unlock list processing thread
89110Sstevel@tonic-gate  */
89120Sstevel@tonic-gate int
ddi_umem_lock(caddr_t addr,size_t len,int flags,ddi_umem_cookie_t * cookie)89130Sstevel@tonic-gate ddi_umem_lock(caddr_t addr, size_t len, int flags, ddi_umem_cookie_t *cookie)
89140Sstevel@tonic-gate {
89150Sstevel@tonic-gate 	int	error;
89160Sstevel@tonic-gate 	struct ddi_umem_cookie *p;
89170Sstevel@tonic-gate 
89180Sstevel@tonic-gate 	*cookie = NULL;		/* in case of any error return */
89190Sstevel@tonic-gate 
89200Sstevel@tonic-gate 	/* These are the only two valid flags */
89210Sstevel@tonic-gate 	if ((flags & ~(DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE)) != 0) {
89220Sstevel@tonic-gate 		return (EINVAL);
89230Sstevel@tonic-gate 	}
89240Sstevel@tonic-gate 
89250Sstevel@tonic-gate 	/* At least one of the two flags (or both) must be set */
89260Sstevel@tonic-gate 	if ((flags & (DDI_UMEMLOCK_READ | DDI_UMEMLOCK_WRITE)) == 0) {
89270Sstevel@tonic-gate 		return (EINVAL);
89280Sstevel@tonic-gate 	}
89290Sstevel@tonic-gate 
89300Sstevel@tonic-gate 	/* addr and len must be page-aligned */
89310Sstevel@tonic-gate 	if (((uintptr_t)addr & PAGEOFFSET) != 0) {
89320Sstevel@tonic-gate 		return (EINVAL);
89330Sstevel@tonic-gate 	}
89340Sstevel@tonic-gate 
89350Sstevel@tonic-gate 	if ((len & PAGEOFFSET) != 0) {
89360Sstevel@tonic-gate 		return (EINVAL);
89370Sstevel@tonic-gate 	}
89380Sstevel@tonic-gate 
89390Sstevel@tonic-gate 	/*
89400Sstevel@tonic-gate 	 * Call i_ddi_umem_unlock_thread_start if necessary.  It will
89410Sstevel@tonic-gate 	 * be called on first ddi_umem_lock or umem_lockmemory call.
89420Sstevel@tonic-gate 	 */
89430Sstevel@tonic-gate 	if (ddi_umem_unlock_thread == NULL)
89440Sstevel@tonic-gate 		i_ddi_umem_unlock_thread_start();
89450Sstevel@tonic-gate 
89460Sstevel@tonic-gate 	/* Allocate memory for the cookie */
89470Sstevel@tonic-gate 	p = kmem_zalloc(sizeof (struct ddi_umem_cookie), KM_SLEEP);
89480Sstevel@tonic-gate 
89490Sstevel@tonic-gate 	/* Convert the flags to seg_rw type */
89500Sstevel@tonic-gate 	if (flags & DDI_UMEMLOCK_WRITE) {
89510Sstevel@tonic-gate 		p->s_flags = S_WRITE;
89520Sstevel@tonic-gate 	} else {
89530Sstevel@tonic-gate 		p->s_flags = S_READ;
89540Sstevel@tonic-gate 	}
89550Sstevel@tonic-gate 
89560Sstevel@tonic-gate 	/* Store curproc in cookie for later iosetup/unlock */
89570Sstevel@tonic-gate 	p->procp = (void *)curproc;
89580Sstevel@tonic-gate 
89590Sstevel@tonic-gate 	/*
89600Sstevel@tonic-gate 	 * Store the struct as pointer in cookie for later use by
89610Sstevel@tonic-gate 	 * ddi_umem_unlock.  The proc->p_as will be stale if ddi_umem_unlock
89620Sstevel@tonic-gate 	 * is called after relvm is called.
89630Sstevel@tonic-gate 	 */
89640Sstevel@tonic-gate 	p->asp = curproc->p_as;
89650Sstevel@tonic-gate 	/*
89660Sstevel@tonic-gate 	 * The size field is needed for lockmem accounting.
89670Sstevel@tonic-gate 	 */
89680Sstevel@tonic-gate 	p->size = len;
896912400Sgerald.jelinek@sun.com 	init_lockedmem_rctl_flag(p);
89700Sstevel@tonic-gate 
89710Sstevel@tonic-gate 	if (umem_incr_devlockmem(p) != 0) {
89720Sstevel@tonic-gate 		/*
89730Sstevel@tonic-gate 		 * The requested memory cannot be locked
89740Sstevel@tonic-gate 		 */
89750Sstevel@tonic-gate 		kmem_free(p, sizeof (struct ddi_umem_cookie));
89760Sstevel@tonic-gate 		*cookie = (ddi_umem_cookie_t)NULL;
89770Sstevel@tonic-gate 		return (ENOMEM);
89780Sstevel@tonic-gate 	}
89790Sstevel@tonic-gate 
89800Sstevel@tonic-gate 	/* Lock the pages corresponding to addr, len in memory */
89810Sstevel@tonic-gate 	error = as_pagelock(((proc_t *)p->procp)->p_as, &(p->pparray),
89820Sstevel@tonic-gate 	    addr, len, p->s_flags);
89830Sstevel@tonic-gate 	if (error != 0) {
89840Sstevel@tonic-gate 		umem_decr_devlockmem(p);
89850Sstevel@tonic-gate 		kmem_free(p, sizeof (struct ddi_umem_cookie));
89860Sstevel@tonic-gate 		*cookie = (ddi_umem_cookie_t)NULL;
89870Sstevel@tonic-gate 		return (error);
89880Sstevel@tonic-gate 	}
89890Sstevel@tonic-gate 
89900Sstevel@tonic-gate 	/* Initialize the fields in the ddi_umem_cookie */
89910Sstevel@tonic-gate 	p->cvaddr = addr;
89920Sstevel@tonic-gate 	p->type = UMEM_LOCKED;
89930Sstevel@tonic-gate 	p->cook_refcnt = 1;
89940Sstevel@tonic-gate 
89950Sstevel@tonic-gate 	*cookie = (ddi_umem_cookie_t)p;
89960Sstevel@tonic-gate 	return (error);
89970Sstevel@tonic-gate }
89980Sstevel@tonic-gate 
89990Sstevel@tonic-gate /*
90000Sstevel@tonic-gate  * Add the cookie to the ddi_umem_unlock list.  Pages will be
90010Sstevel@tonic-gate  * unlocked by i_ddi_umem_unlock_thread.
90020Sstevel@tonic-gate  */
90030Sstevel@tonic-gate 
90040Sstevel@tonic-gate void
ddi_umem_unlock(ddi_umem_cookie_t cookie)90050Sstevel@tonic-gate ddi_umem_unlock(ddi_umem_cookie_t cookie)
90060Sstevel@tonic-gate {
90070Sstevel@tonic-gate 	struct ddi_umem_cookie	*p = (struct ddi_umem_cookie *)cookie;
90080Sstevel@tonic-gate 
90090Sstevel@tonic-gate 	ASSERT(p->type == UMEM_LOCKED);
90100Sstevel@tonic-gate 	ASSERT(CPU_ON_INTR(CPU) == 0); /* cannot be high level */
90110Sstevel@tonic-gate 	ASSERT(ddi_umem_unlock_thread != NULL);
90120Sstevel@tonic-gate 
90130Sstevel@tonic-gate 	p->unl_forw = (struct ddi_umem_cookie *)NULL;	/* end of list */
90142066Seota 	/*
90152066Seota 	 * Queue the unlock request and notify i_ddi_umem_unlock thread
90162066Seota 	 * if it's called in the interrupt context. Otherwise, unlock pages
90172066Seota 	 * immediately.
90182066Seota 	 */
90192066Seota 	if (servicing_interrupt()) {
90202066Seota 		/* queue the unlock request and notify the thread */
90212066Seota 		mutex_enter(&ddi_umem_unlock_mutex);
90222066Seota 		if (ddi_umem_unlock_head == NULL) {
90232066Seota 			ddi_umem_unlock_head = ddi_umem_unlock_tail = p;
90242066Seota 			cv_broadcast(&ddi_umem_unlock_cv);
90252066Seota 		} else {
90262066Seota 			ddi_umem_unlock_tail->unl_forw = p;
90272066Seota 			ddi_umem_unlock_tail = p;
90282066Seota 		}
90292066Seota 		mutex_exit(&ddi_umem_unlock_mutex);
90300Sstevel@tonic-gate 	} else {
90312066Seota 		/* unlock the pages right away */
90322066Seota 		(void) i_ddi_umem_unlock(p);
90332066Seota 	}
90340Sstevel@tonic-gate }
90350Sstevel@tonic-gate 
90360Sstevel@tonic-gate /*
90370Sstevel@tonic-gate  * Create a buf structure from a ddi_umem_cookie
90380Sstevel@tonic-gate  * cookie - is a ddi_umem_cookie for from ddi_umem_lock and ddi_umem_alloc
90390Sstevel@tonic-gate  *		(only UMEM_LOCKED & KMEM_NON_PAGEABLE types supported)
90400Sstevel@tonic-gate  * off, len - identifies the portion of the memory represented by the cookie
90410Sstevel@tonic-gate  *		that the buf points to.
90420Sstevel@tonic-gate  *	NOTE: off, len need to follow the alignment/size restrictions of the
90430Sstevel@tonic-gate  *		device (dev) that this buf will be passed to. Some devices
90440Sstevel@tonic-gate  *		will accept unrestricted alignment/size, whereas others (such as
90450Sstevel@tonic-gate  *		st) require some block-size alignment/size. It is the caller's
90460Sstevel@tonic-gate  *		responsibility to ensure that the alignment/size restrictions
90470Sstevel@tonic-gate  *		are met (we cannot assert as we do not know the restrictions)
90480Sstevel@tonic-gate  *
90490Sstevel@tonic-gate  * direction - is one of B_READ or B_WRITE and needs to be compatible with
90500Sstevel@tonic-gate  *		the flags used in ddi_umem_lock
90510Sstevel@tonic-gate  *
90520Sstevel@tonic-gate  * The following three arguments are used to initialize fields in the
90530Sstevel@tonic-gate  * buf structure and are uninterpreted by this routine.
90540Sstevel@tonic-gate  *
90550Sstevel@tonic-gate  * dev
90560Sstevel@tonic-gate  * blkno
90570Sstevel@tonic-gate  * iodone
90580Sstevel@tonic-gate  *
90590Sstevel@tonic-gate  * sleepflag - is one of DDI_UMEM_SLEEP or DDI_UMEM_NOSLEEP
90600Sstevel@tonic-gate  *
90610Sstevel@tonic-gate  * Returns a buf structure pointer on success (to be freed by freerbuf)
90620Sstevel@tonic-gate  *	NULL on any parameter error or memory alloc failure
90630Sstevel@tonic-gate  *
90640Sstevel@tonic-gate  */
90650Sstevel@tonic-gate struct buf *
ddi_umem_iosetup(ddi_umem_cookie_t cookie,off_t off,size_t len,int direction,dev_t dev,daddr_t blkno,int (* iodone)(struct buf *),int sleepflag)90660Sstevel@tonic-gate ddi_umem_iosetup(ddi_umem_cookie_t cookie, off_t off, size_t len,
90670Sstevel@tonic-gate 	int direction, dev_t dev, daddr_t blkno,
90680Sstevel@tonic-gate 	int (*iodone)(struct buf *), int sleepflag)
90690Sstevel@tonic-gate {
90700Sstevel@tonic-gate 	struct ddi_umem_cookie *p = (struct ddi_umem_cookie *)cookie;
90710Sstevel@tonic-gate 	struct buf *bp;
90720Sstevel@tonic-gate 
90730Sstevel@tonic-gate 	/*
90740Sstevel@tonic-gate 	 * check for valid cookie offset, len
90750Sstevel@tonic-gate 	 */
90760Sstevel@tonic-gate 	if ((off + len) > p->size) {
90770Sstevel@tonic-gate 		return (NULL);
90780Sstevel@tonic-gate 	}
90790Sstevel@tonic-gate 
90800Sstevel@tonic-gate 	if (len > p->size) {
90810Sstevel@tonic-gate 		return (NULL);
90820Sstevel@tonic-gate 	}
90830Sstevel@tonic-gate 
90840Sstevel@tonic-gate 	/* direction has to be one of B_READ or B_WRITE */
90850Sstevel@tonic-gate 	if ((direction != B_READ) && (direction != B_WRITE)) {
90860Sstevel@tonic-gate 		return (NULL);
90870Sstevel@tonic-gate 	}
90880Sstevel@tonic-gate 
90890Sstevel@tonic-gate 	/* These are the only two valid sleepflags */
90900Sstevel@tonic-gate 	if ((sleepflag != DDI_UMEM_SLEEP) && (sleepflag != DDI_UMEM_NOSLEEP)) {
90910Sstevel@tonic-gate 		return (NULL);
90920Sstevel@tonic-gate 	}
90930Sstevel@tonic-gate 
90940Sstevel@tonic-gate 	/*
90950Sstevel@tonic-gate 	 * Only cookies of type UMEM_LOCKED and KMEM_NON_PAGEABLE are supported
90960Sstevel@tonic-gate 	 */
90970Sstevel@tonic-gate 	if ((p->type != UMEM_LOCKED) && (p->type != KMEM_NON_PAGEABLE)) {
90980Sstevel@tonic-gate 		return (NULL);
90990Sstevel@tonic-gate 	}
91000Sstevel@tonic-gate 
91010Sstevel@tonic-gate 	/* If type is KMEM_NON_PAGEABLE procp is NULL */
91020Sstevel@tonic-gate 	ASSERT((p->type == KMEM_NON_PAGEABLE) ?
91034582Scth 	    (p->procp == NULL) : (p->procp != NULL));
91040Sstevel@tonic-gate 
91050Sstevel@tonic-gate 	bp = kmem_alloc(sizeof (struct buf), sleepflag);
91060Sstevel@tonic-gate 	if (bp == NULL) {
91070Sstevel@tonic-gate 		return (NULL);
91080Sstevel@tonic-gate 	}
91090Sstevel@tonic-gate 	bioinit(bp);
91100Sstevel@tonic-gate 
91110Sstevel@tonic-gate 	bp->b_flags = B_BUSY | B_PHYS | direction;
91120Sstevel@tonic-gate 	bp->b_edev = dev;
91130Sstevel@tonic-gate 	bp->b_lblkno = blkno;
91140Sstevel@tonic-gate 	bp->b_iodone = iodone;
91150Sstevel@tonic-gate 	bp->b_bcount = len;
91160Sstevel@tonic-gate 	bp->b_proc = (proc_t *)p->procp;
91170Sstevel@tonic-gate 	ASSERT(((uintptr_t)(p->cvaddr) & PAGEOFFSET) == 0);
91180Sstevel@tonic-gate 	bp->b_un.b_addr = (caddr_t)((uintptr_t)(p->cvaddr) + off);
91190Sstevel@tonic-gate 	if (p->pparray != NULL) {
91200Sstevel@tonic-gate 		bp->b_flags |= B_SHADOW;
91210Sstevel@tonic-gate 		ASSERT(((uintptr_t)(p->cvaddr) & PAGEOFFSET) == 0);
91220Sstevel@tonic-gate 		bp->b_shadow = p->pparray + btop(off);
91230Sstevel@tonic-gate 	}
91240Sstevel@tonic-gate 	return (bp);
91250Sstevel@tonic-gate }
91260Sstevel@tonic-gate 
91270Sstevel@tonic-gate /*
91280Sstevel@tonic-gate  * Fault-handling and related routines
91290Sstevel@tonic-gate  */
91300Sstevel@tonic-gate 
91310Sstevel@tonic-gate ddi_devstate_t
ddi_get_devstate(dev_info_t * dip)91320Sstevel@tonic-gate ddi_get_devstate(dev_info_t *dip)
91330Sstevel@tonic-gate {
91340Sstevel@tonic-gate 	if (DEVI_IS_DEVICE_OFFLINE(dip))
91350Sstevel@tonic-gate 		return (DDI_DEVSTATE_OFFLINE);
91360Sstevel@tonic-gate 	else if (DEVI_IS_DEVICE_DOWN(dip) || DEVI_IS_BUS_DOWN(dip))
91370Sstevel@tonic-gate 		return (DDI_DEVSTATE_DOWN);
91380Sstevel@tonic-gate 	else if (DEVI_IS_BUS_QUIESCED(dip))
91390Sstevel@tonic-gate 		return (DDI_DEVSTATE_QUIESCED);
91400Sstevel@tonic-gate 	else if (DEVI_IS_DEVICE_DEGRADED(dip))
91410Sstevel@tonic-gate 		return (DDI_DEVSTATE_DEGRADED);
91420Sstevel@tonic-gate 	else
91430Sstevel@tonic-gate 		return (DDI_DEVSTATE_UP);
91440Sstevel@tonic-gate }
91450Sstevel@tonic-gate 
91460Sstevel@tonic-gate void
ddi_dev_report_fault(dev_info_t * dip,ddi_fault_impact_t impact,ddi_fault_location_t location,const char * message)91470Sstevel@tonic-gate ddi_dev_report_fault(dev_info_t *dip, ddi_fault_impact_t impact,
91480Sstevel@tonic-gate 	ddi_fault_location_t location, const char *message)
91490Sstevel@tonic-gate {
91500Sstevel@tonic-gate 	struct ddi_fault_event_data fd;
91510Sstevel@tonic-gate 	ddi_eventcookie_t ec;
91520Sstevel@tonic-gate 
91530Sstevel@tonic-gate 	/*
91540Sstevel@tonic-gate 	 * Assemble all the information into a fault-event-data structure
91550Sstevel@tonic-gate 	 */
91560Sstevel@tonic-gate 	fd.f_dip = dip;
91570Sstevel@tonic-gate 	fd.f_impact = impact;
91580Sstevel@tonic-gate 	fd.f_location = location;
91590Sstevel@tonic-gate 	fd.f_message = message;
91600Sstevel@tonic-gate 	fd.f_oldstate = ddi_get_devstate(dip);
91610Sstevel@tonic-gate 
91620Sstevel@tonic-gate 	/*
91630Sstevel@tonic-gate 	 * Get eventcookie from defining parent.
91640Sstevel@tonic-gate 	 */
91650Sstevel@tonic-gate 	if (ddi_get_eventcookie(dip, DDI_DEVI_FAULT_EVENT, &ec) !=
91660Sstevel@tonic-gate 	    DDI_SUCCESS)
91670Sstevel@tonic-gate 		return;
91680Sstevel@tonic-gate 
91690Sstevel@tonic-gate 	(void) ndi_post_event(dip, dip, ec, &fd);
91700Sstevel@tonic-gate }
91710Sstevel@tonic-gate 
91720Sstevel@tonic-gate char *
i_ddi_devi_class(dev_info_t * dip)91730Sstevel@tonic-gate i_ddi_devi_class(dev_info_t *dip)
91740Sstevel@tonic-gate {
91750Sstevel@tonic-gate 	return (DEVI(dip)->devi_device_class);
91760Sstevel@tonic-gate }
91770Sstevel@tonic-gate 
91780Sstevel@tonic-gate int
i_ddi_set_devi_class(dev_info_t * dip,char * devi_class,int flag)91790Sstevel@tonic-gate i_ddi_set_devi_class(dev_info_t *dip, char *devi_class, int flag)
91800Sstevel@tonic-gate {
91810Sstevel@tonic-gate 	struct dev_info *devi = DEVI(dip);
91820Sstevel@tonic-gate 
91830Sstevel@tonic-gate 	mutex_enter(&devi->devi_lock);
91840Sstevel@tonic-gate 
91850Sstevel@tonic-gate 	if (devi->devi_device_class)
91860Sstevel@tonic-gate 		kmem_free(devi->devi_device_class,
91870Sstevel@tonic-gate 		    strlen(devi->devi_device_class) + 1);
91880Sstevel@tonic-gate 
91890Sstevel@tonic-gate 	if ((devi->devi_device_class = i_ddi_strdup(devi_class, flag))
91900Sstevel@tonic-gate 	    != NULL) {
91910Sstevel@tonic-gate 		mutex_exit(&devi->devi_lock);
91920Sstevel@tonic-gate 		return (DDI_SUCCESS);
91930Sstevel@tonic-gate 	}
91940Sstevel@tonic-gate 
91950Sstevel@tonic-gate 	mutex_exit(&devi->devi_lock);
91960Sstevel@tonic-gate 
91970Sstevel@tonic-gate 	return (DDI_FAILURE);
91980Sstevel@tonic-gate }
91990Sstevel@tonic-gate 
92000Sstevel@tonic-gate 
92010Sstevel@tonic-gate /*
92020Sstevel@tonic-gate  * Task Queues DDI interfaces.
92030Sstevel@tonic-gate  */
92040Sstevel@tonic-gate 
92050Sstevel@tonic-gate /* ARGSUSED */
92060Sstevel@tonic-gate ddi_taskq_t *
ddi_taskq_create(dev_info_t * dip,const char * name,int nthreads,pri_t pri,uint_t cflags)92070Sstevel@tonic-gate ddi_taskq_create(dev_info_t *dip, const char *name, int nthreads,
92080Sstevel@tonic-gate     pri_t pri, uint_t cflags)
92090Sstevel@tonic-gate {
92100Sstevel@tonic-gate 	char full_name[TASKQ_NAMELEN];
92110Sstevel@tonic-gate 	const char *tq_name;
92120Sstevel@tonic-gate 	int nodeid = 0;
92130Sstevel@tonic-gate 
92140Sstevel@tonic-gate 	if (dip == NULL)
92150Sstevel@tonic-gate 		tq_name = name;
92160Sstevel@tonic-gate 	else {
92170Sstevel@tonic-gate 		nodeid = ddi_get_instance(dip);
92180Sstevel@tonic-gate 
92190Sstevel@tonic-gate 		if (name == NULL)
92200Sstevel@tonic-gate 			name = "tq";
92210Sstevel@tonic-gate 
92220Sstevel@tonic-gate 		(void) snprintf(full_name, sizeof (full_name), "%s_%s",
92230Sstevel@tonic-gate 		    ddi_driver_name(dip), name);
92240Sstevel@tonic-gate 
92250Sstevel@tonic-gate 		tq_name = full_name;
92260Sstevel@tonic-gate 	}
92270Sstevel@tonic-gate 
92280Sstevel@tonic-gate 	return ((ddi_taskq_t *)taskq_create_instance(tq_name, nodeid, nthreads,
92294582Scth 	    pri == TASKQ_DEFAULTPRI ? minclsyspri : pri,
92304582Scth 	    nthreads, INT_MAX, TASKQ_PREPOPULATE));
92310Sstevel@tonic-gate }
92320Sstevel@tonic-gate 
92330Sstevel@tonic-gate void
ddi_taskq_destroy(ddi_taskq_t * tq)92340Sstevel@tonic-gate ddi_taskq_destroy(ddi_taskq_t *tq)
92350Sstevel@tonic-gate {
92360Sstevel@tonic-gate 	taskq_destroy((taskq_t *)tq);
92370Sstevel@tonic-gate }
92380Sstevel@tonic-gate 
92390Sstevel@tonic-gate int
ddi_taskq_dispatch(ddi_taskq_t * tq,void (* func)(void *),void * arg,uint_t dflags)92400Sstevel@tonic-gate ddi_taskq_dispatch(ddi_taskq_t *tq, void (* func)(void *),
92410Sstevel@tonic-gate     void *arg, uint_t dflags)
92420Sstevel@tonic-gate {
92430Sstevel@tonic-gate 	taskqid_t id = taskq_dispatch((taskq_t *)tq, func, arg,
92440Sstevel@tonic-gate 	    dflags == DDI_SLEEP ? TQ_SLEEP : TQ_NOSLEEP);
92450Sstevel@tonic-gate 
92460Sstevel@tonic-gate 	return (id != 0 ? DDI_SUCCESS : DDI_FAILURE);
92470Sstevel@tonic-gate }
92480Sstevel@tonic-gate 
92490Sstevel@tonic-gate void
ddi_taskq_wait(ddi_taskq_t * tq)92500Sstevel@tonic-gate ddi_taskq_wait(ddi_taskq_t *tq)
92510Sstevel@tonic-gate {
92520Sstevel@tonic-gate 	taskq_wait((taskq_t *)tq);
92530Sstevel@tonic-gate }
92540Sstevel@tonic-gate 
92550Sstevel@tonic-gate void
ddi_taskq_suspend(ddi_taskq_t * tq)92560Sstevel@tonic-gate ddi_taskq_suspend(ddi_taskq_t *tq)
92570Sstevel@tonic-gate {
92580Sstevel@tonic-gate 	taskq_suspend((taskq_t *)tq);
92590Sstevel@tonic-gate }
92600Sstevel@tonic-gate 
92610Sstevel@tonic-gate boolean_t
ddi_taskq_suspended(ddi_taskq_t * tq)92620Sstevel@tonic-gate ddi_taskq_suspended(ddi_taskq_t *tq)
92630Sstevel@tonic-gate {
92640Sstevel@tonic-gate 	return (taskq_suspended((taskq_t *)tq));
92650Sstevel@tonic-gate }
92660Sstevel@tonic-gate 
92670Sstevel@tonic-gate void
ddi_taskq_resume(ddi_taskq_t * tq)92680Sstevel@tonic-gate ddi_taskq_resume(ddi_taskq_t *tq)
92690Sstevel@tonic-gate {
92700Sstevel@tonic-gate 	taskq_resume((taskq_t *)tq);
92710Sstevel@tonic-gate }
92720Sstevel@tonic-gate 
92730Sstevel@tonic-gate int
ddi_parse(const char * ifname,char * alnum,uint_t * nump)92740Sstevel@tonic-gate ddi_parse(
92750Sstevel@tonic-gate 	const char	*ifname,
92760Sstevel@tonic-gate 	char		*alnum,
92770Sstevel@tonic-gate 	uint_t		*nump)
92780Sstevel@tonic-gate {
92790Sstevel@tonic-gate 	const char	*p;
92800Sstevel@tonic-gate 	int		l;
92810Sstevel@tonic-gate 	ulong_t		num;
92820Sstevel@tonic-gate 	boolean_t	nonum = B_TRUE;
92830Sstevel@tonic-gate 	char		c;
92840Sstevel@tonic-gate 
92850Sstevel@tonic-gate 	l = strlen(ifname);
92860Sstevel@tonic-gate 	for (p = ifname + l; p != ifname; l--) {
92870Sstevel@tonic-gate 		c = *--p;
92880Sstevel@tonic-gate 		if (!isdigit(c)) {
92890Sstevel@tonic-gate 			(void) strlcpy(alnum, ifname, l + 1);
92900Sstevel@tonic-gate 			if (ddi_strtoul(p + 1, NULL, 10, &num) != 0)
92910Sstevel@tonic-gate 				return (DDI_FAILURE);
92920Sstevel@tonic-gate 			break;
92930Sstevel@tonic-gate 		}
92940Sstevel@tonic-gate 		nonum = B_FALSE;
92950Sstevel@tonic-gate 	}
92960Sstevel@tonic-gate 	if (l == 0 || nonum)
92970Sstevel@tonic-gate 		return (DDI_FAILURE);
92980Sstevel@tonic-gate 
92990Sstevel@tonic-gate 	*nump = num;
93000Sstevel@tonic-gate 	return (DDI_SUCCESS);
93010Sstevel@tonic-gate }
93027656SSherry.Moore@Sun.COM 
93037656SSherry.Moore@Sun.COM /*
93047656SSherry.Moore@Sun.COM  * Default initialization function for drivers that don't need to quiesce.
93057656SSherry.Moore@Sun.COM  */
93067656SSherry.Moore@Sun.COM /* ARGSUSED */
93077656SSherry.Moore@Sun.COM int
ddi_quiesce_not_needed(dev_info_t * dip)93087656SSherry.Moore@Sun.COM ddi_quiesce_not_needed(dev_info_t *dip)
93097656SSherry.Moore@Sun.COM {
93107656SSherry.Moore@Sun.COM 	return (DDI_SUCCESS);
93117656SSherry.Moore@Sun.COM }
93127656SSherry.Moore@Sun.COM 
93137656SSherry.Moore@Sun.COM /*
93147656SSherry.Moore@Sun.COM  * Initialization function for drivers that should implement quiesce()
93157656SSherry.Moore@Sun.COM  * but haven't yet.
93167656SSherry.Moore@Sun.COM  */
93177656SSherry.Moore@Sun.COM /* ARGSUSED */
93187656SSherry.Moore@Sun.COM int
ddi_quiesce_not_supported(dev_info_t * dip)93197656SSherry.Moore@Sun.COM ddi_quiesce_not_supported(dev_info_t *dip)
93207656SSherry.Moore@Sun.COM {
93217656SSherry.Moore@Sun.COM 	return (DDI_FAILURE);
93227656SSherry.Moore@Sun.COM }
93238561SScott.Carter@Sun.COM 
93248863SEdward.Pilatowicz@Sun.COM char *
ddi_strdup(const char * str,int flag)93258863SEdward.Pilatowicz@Sun.COM ddi_strdup(const char *str, int flag)
93268863SEdward.Pilatowicz@Sun.COM {
93278863SEdward.Pilatowicz@Sun.COM 	int	n;
93288863SEdward.Pilatowicz@Sun.COM 	char	*ptr;
93298863SEdward.Pilatowicz@Sun.COM 
93308863SEdward.Pilatowicz@Sun.COM 	ASSERT(str != NULL);
93318863SEdward.Pilatowicz@Sun.COM 	ASSERT((flag == KM_SLEEP) || (flag == KM_NOSLEEP));
93328863SEdward.Pilatowicz@Sun.COM 
93338863SEdward.Pilatowicz@Sun.COM 	n = strlen(str);
93348863SEdward.Pilatowicz@Sun.COM 	if ((ptr = kmem_alloc(n + 1, flag)) == NULL)
93358863SEdward.Pilatowicz@Sun.COM 		return (NULL);
93368863SEdward.Pilatowicz@Sun.COM 	bcopy(str, ptr, n + 1);
93378863SEdward.Pilatowicz@Sun.COM 	return (ptr);
93388863SEdward.Pilatowicz@Sun.COM }
93398863SEdward.Pilatowicz@Sun.COM 
93408863SEdward.Pilatowicz@Sun.COM char *
strdup(const char * str)93418863SEdward.Pilatowicz@Sun.COM strdup(const char *str)
93428863SEdward.Pilatowicz@Sun.COM {
93438863SEdward.Pilatowicz@Sun.COM 	return (ddi_strdup(str, KM_SLEEP));
93448863SEdward.Pilatowicz@Sun.COM }
93458863SEdward.Pilatowicz@Sun.COM 
93468863SEdward.Pilatowicz@Sun.COM void
strfree(char * str)93478863SEdward.Pilatowicz@Sun.COM strfree(char *str)
93488863SEdward.Pilatowicz@Sun.COM {
93498863SEdward.Pilatowicz@Sun.COM 	ASSERT(str != NULL);
93508863SEdward.Pilatowicz@Sun.COM 	kmem_free(str, strlen(str) + 1);
93518863SEdward.Pilatowicz@Sun.COM }
93528863SEdward.Pilatowicz@Sun.COM 
93538561SScott.Carter@Sun.COM /*
93548561SScott.Carter@Sun.COM  * Generic DDI callback interfaces.
93558561SScott.Carter@Sun.COM  */
93568561SScott.Carter@Sun.COM 
93578561SScott.Carter@Sun.COM int
ddi_cb_register(dev_info_t * dip,ddi_cb_flags_t flags,ddi_cb_func_t cbfunc,void * arg1,void * arg2,ddi_cb_handle_t * ret_hdlp)93588561SScott.Carter@Sun.COM ddi_cb_register(dev_info_t *dip, ddi_cb_flags_t flags, ddi_cb_func_t cbfunc,
93598561SScott.Carter@Sun.COM     void *arg1, void *arg2, ddi_cb_handle_t *ret_hdlp)
93608561SScott.Carter@Sun.COM {
93618561SScott.Carter@Sun.COM 	ddi_cb_t	*cbp;
93628561SScott.Carter@Sun.COM 
93638561SScott.Carter@Sun.COM 	ASSERT(dip != NULL);
93648561SScott.Carter@Sun.COM 	ASSERT(DDI_CB_FLAG_VALID(flags));
93658561SScott.Carter@Sun.COM 	ASSERT(cbfunc != NULL);
93668561SScott.Carter@Sun.COM 	ASSERT(ret_hdlp != NULL);
93678561SScott.Carter@Sun.COM 
93688561SScott.Carter@Sun.COM 	/* Sanity check the context */
93698561SScott.Carter@Sun.COM 	ASSERT(!servicing_interrupt());
93708561SScott.Carter@Sun.COM 	if (servicing_interrupt())
93718561SScott.Carter@Sun.COM 		return (DDI_FAILURE);
93728561SScott.Carter@Sun.COM 
93738561SScott.Carter@Sun.COM 	/* Validate parameters */
93748561SScott.Carter@Sun.COM 	if ((dip == NULL) || !DDI_CB_FLAG_VALID(flags) ||
93758561SScott.Carter@Sun.COM 	    (cbfunc == NULL) || (ret_hdlp == NULL))
93768561SScott.Carter@Sun.COM 		return (DDI_EINVAL);
93778561SScott.Carter@Sun.COM 
93788561SScott.Carter@Sun.COM 	/* Check for previous registration */
93798561SScott.Carter@Sun.COM 	if (DEVI(dip)->devi_cb_p != NULL)
93808561SScott.Carter@Sun.COM 		return (DDI_EALREADY);
93818561SScott.Carter@Sun.COM 
93828561SScott.Carter@Sun.COM 	/* Allocate and initialize callback */
93838561SScott.Carter@Sun.COM 	cbp = kmem_zalloc(sizeof (ddi_cb_t), KM_SLEEP);
93848561SScott.Carter@Sun.COM 	cbp->cb_dip = dip;
93858561SScott.Carter@Sun.COM 	cbp->cb_func = cbfunc;
93868561SScott.Carter@Sun.COM 	cbp->cb_arg1 = arg1;
93878561SScott.Carter@Sun.COM 	cbp->cb_arg2 = arg2;
93888561SScott.Carter@Sun.COM 	cbp->cb_flags = flags;
93898561SScott.Carter@Sun.COM 	DEVI(dip)->devi_cb_p = cbp;
93908561SScott.Carter@Sun.COM 
93918561SScott.Carter@Sun.COM 	/* If adding an IRM callback, notify IRM */
93928561SScott.Carter@Sun.COM 	if (flags & DDI_CB_FLAG_INTR)
93938561SScott.Carter@Sun.COM 		i_ddi_irm_set_cb(dip, B_TRUE);
93948561SScott.Carter@Sun.COM 
93958561SScott.Carter@Sun.COM 	*ret_hdlp = (ddi_cb_handle_t)&(DEVI(dip)->devi_cb_p);
93968561SScott.Carter@Sun.COM 	return (DDI_SUCCESS);
93978561SScott.Carter@Sun.COM }
93988561SScott.Carter@Sun.COM 
93998561SScott.Carter@Sun.COM int
ddi_cb_unregister(ddi_cb_handle_t hdl)94008561SScott.Carter@Sun.COM ddi_cb_unregister(ddi_cb_handle_t hdl)
94018561SScott.Carter@Sun.COM {
94028561SScott.Carter@Sun.COM 	ddi_cb_t	*cbp;
94038561SScott.Carter@Sun.COM 	dev_info_t	*dip;
94048561SScott.Carter@Sun.COM 
94058561SScott.Carter@Sun.COM 	ASSERT(hdl != NULL);
94068561SScott.Carter@Sun.COM 
94078561SScott.Carter@Sun.COM 	/* Sanity check the context */
94088561SScott.Carter@Sun.COM 	ASSERT(!servicing_interrupt());
94098561SScott.Carter@Sun.COM 	if (servicing_interrupt())
94108561SScott.Carter@Sun.COM 		return (DDI_FAILURE);
94118561SScott.Carter@Sun.COM 
94128561SScott.Carter@Sun.COM 	/* Validate parameters */
94138561SScott.Carter@Sun.COM 	if ((hdl == NULL) || ((cbp = *(ddi_cb_t **)hdl) == NULL) ||
94148561SScott.Carter@Sun.COM 	    ((dip = cbp->cb_dip) == NULL))
94158561SScott.Carter@Sun.COM 		return (DDI_EINVAL);
94168561SScott.Carter@Sun.COM 
94178561SScott.Carter@Sun.COM 	/* If removing an IRM callback, notify IRM */
94188561SScott.Carter@Sun.COM 	if (cbp->cb_flags & DDI_CB_FLAG_INTR)
94198561SScott.Carter@Sun.COM 		i_ddi_irm_set_cb(dip, B_FALSE);
94208561SScott.Carter@Sun.COM 
94218561SScott.Carter@Sun.COM 	/* Destroy the callback */
94228561SScott.Carter@Sun.COM 	kmem_free(cbp, sizeof (ddi_cb_t));
94238561SScott.Carter@Sun.COM 	DEVI(dip)->devi_cb_p = NULL;
94248561SScott.Carter@Sun.COM 
94258561SScott.Carter@Sun.COM 	return (DDI_SUCCESS);
94268561SScott.Carter@Sun.COM }
942712004Sjiang.liu@intel.com 
942812004Sjiang.liu@intel.com /*
942912004Sjiang.liu@intel.com  * Platform independent DR routines
943012004Sjiang.liu@intel.com  */
943112004Sjiang.liu@intel.com 
943212004Sjiang.liu@intel.com static int
ndi2errno(int n)943312004Sjiang.liu@intel.com ndi2errno(int n)
943412004Sjiang.liu@intel.com {
943512004Sjiang.liu@intel.com 	int err = 0;
943612004Sjiang.liu@intel.com 
943712004Sjiang.liu@intel.com 	switch (n) {
943812004Sjiang.liu@intel.com 		case NDI_NOMEM:
943912004Sjiang.liu@intel.com 			err = ENOMEM;
944012004Sjiang.liu@intel.com 			break;
944112004Sjiang.liu@intel.com 		case NDI_BUSY:
944212004Sjiang.liu@intel.com 			err = EBUSY;
944312004Sjiang.liu@intel.com 			break;
944412004Sjiang.liu@intel.com 		case NDI_FAULT:
944512004Sjiang.liu@intel.com 			err = EFAULT;
944612004Sjiang.liu@intel.com 			break;
944712004Sjiang.liu@intel.com 		case NDI_FAILURE:
944812004Sjiang.liu@intel.com 			err = EIO;
944912004Sjiang.liu@intel.com 			break;
945012004Sjiang.liu@intel.com 		case NDI_SUCCESS:
945112004Sjiang.liu@intel.com 			break;
945212004Sjiang.liu@intel.com 		case NDI_BADHANDLE:
945312004Sjiang.liu@intel.com 		default:
945412004Sjiang.liu@intel.com 			err = EINVAL;
945512004Sjiang.liu@intel.com 			break;
945612004Sjiang.liu@intel.com 	}
945712004Sjiang.liu@intel.com 	return (err);
945812004Sjiang.liu@intel.com }
945912004Sjiang.liu@intel.com 
946012004Sjiang.liu@intel.com /*
946112004Sjiang.liu@intel.com  * Prom tree node list
946212004Sjiang.liu@intel.com  */
946312004Sjiang.liu@intel.com struct ptnode {
946412004Sjiang.liu@intel.com 	pnode_t		nodeid;
946512004Sjiang.liu@intel.com 	struct ptnode	*next;
946612004Sjiang.liu@intel.com };
946712004Sjiang.liu@intel.com 
946812004Sjiang.liu@intel.com /*
946912004Sjiang.liu@intel.com  * Prom tree walk arg
947012004Sjiang.liu@intel.com  */
947112004Sjiang.liu@intel.com struct pta {
947212004Sjiang.liu@intel.com 	dev_info_t	*pdip;
947312004Sjiang.liu@intel.com 	devi_branch_t	*bp;
947412004Sjiang.liu@intel.com 	uint_t		flags;
947512004Sjiang.liu@intel.com 	dev_info_t	*fdip;
947612004Sjiang.liu@intel.com 	struct ptnode	*head;
947712004Sjiang.liu@intel.com };
947812004Sjiang.liu@intel.com 
947912004Sjiang.liu@intel.com static void
visit_node(pnode_t nodeid,struct pta * ap)948012004Sjiang.liu@intel.com visit_node(pnode_t nodeid, struct pta *ap)
948112004Sjiang.liu@intel.com {
948212004Sjiang.liu@intel.com 	struct ptnode	**nextp;
948312004Sjiang.liu@intel.com 	int		(*select)(pnode_t, void *, uint_t);
948412004Sjiang.liu@intel.com 
948512004Sjiang.liu@intel.com 	ASSERT(nodeid != OBP_NONODE && nodeid != OBP_BADNODE);
948612004Sjiang.liu@intel.com 
948712004Sjiang.liu@intel.com 	select = ap->bp->create.prom_branch_select;
948812004Sjiang.liu@intel.com 
948912004Sjiang.liu@intel.com 	ASSERT(select);
949012004Sjiang.liu@intel.com 
949112004Sjiang.liu@intel.com 	if (select(nodeid, ap->bp->arg, 0) == DDI_SUCCESS) {
949212004Sjiang.liu@intel.com 
949312004Sjiang.liu@intel.com 		for (nextp = &ap->head; *nextp; nextp = &(*nextp)->next)
949412004Sjiang.liu@intel.com 			;
949512004Sjiang.liu@intel.com 
949612004Sjiang.liu@intel.com 		*nextp = kmem_zalloc(sizeof (struct ptnode), KM_SLEEP);
949712004Sjiang.liu@intel.com 
949812004Sjiang.liu@intel.com 		(*nextp)->nodeid = nodeid;
949912004Sjiang.liu@intel.com 	}
950012004Sjiang.liu@intel.com 
950112004Sjiang.liu@intel.com 	if ((ap->flags & DEVI_BRANCH_CHILD) == DEVI_BRANCH_CHILD)
950212004Sjiang.liu@intel.com 		return;
950312004Sjiang.liu@intel.com 
950412004Sjiang.liu@intel.com 	nodeid = prom_childnode(nodeid);
950512004Sjiang.liu@intel.com 	while (nodeid != OBP_NONODE && nodeid != OBP_BADNODE) {
950612004Sjiang.liu@intel.com 		visit_node(nodeid, ap);
950712004Sjiang.liu@intel.com 		nodeid = prom_nextnode(nodeid);
950812004Sjiang.liu@intel.com 	}
950912004Sjiang.liu@intel.com }
951012004Sjiang.liu@intel.com 
951112004Sjiang.liu@intel.com /*
951212004Sjiang.liu@intel.com  * NOTE: The caller of this function must check for device contracts
951312004Sjiang.liu@intel.com  * or LDI callbacks against this dip before setting the dip offline.
951412004Sjiang.liu@intel.com  */
951512004Sjiang.liu@intel.com static int
set_infant_dip_offline(dev_info_t * dip,void * arg)951612004Sjiang.liu@intel.com set_infant_dip_offline(dev_info_t *dip, void *arg)
951712004Sjiang.liu@intel.com {
951812004Sjiang.liu@intel.com 	char	*path = (char *)arg;
951912004Sjiang.liu@intel.com 
952012004Sjiang.liu@intel.com 	ASSERT(dip);
952112004Sjiang.liu@intel.com 	ASSERT(arg);
952212004Sjiang.liu@intel.com 
952312004Sjiang.liu@intel.com 	if (i_ddi_node_state(dip) >= DS_ATTACHED) {
952412004Sjiang.liu@intel.com 		(void) ddi_pathname(dip, path);
952512004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "Attempt to set offline flag on attached "
952612004Sjiang.liu@intel.com 		    "node: %s", path);
952712004Sjiang.liu@intel.com 		return (DDI_FAILURE);
952812004Sjiang.liu@intel.com 	}
952912004Sjiang.liu@intel.com 
953012004Sjiang.liu@intel.com 	mutex_enter(&(DEVI(dip)->devi_lock));
953112004Sjiang.liu@intel.com 	if (!DEVI_IS_DEVICE_OFFLINE(dip))
953212004Sjiang.liu@intel.com 		DEVI_SET_DEVICE_OFFLINE(dip);
953312004Sjiang.liu@intel.com 	mutex_exit(&(DEVI(dip)->devi_lock));
953412004Sjiang.liu@intel.com 
953512004Sjiang.liu@intel.com 	return (DDI_SUCCESS);
953612004Sjiang.liu@intel.com }
953712004Sjiang.liu@intel.com 
953812004Sjiang.liu@intel.com typedef struct result {
953912004Sjiang.liu@intel.com 	char	*path;
954012004Sjiang.liu@intel.com 	int	result;
954112004Sjiang.liu@intel.com } result_t;
954212004Sjiang.liu@intel.com 
954312004Sjiang.liu@intel.com static int
dip_set_offline(dev_info_t * dip,void * arg)954412004Sjiang.liu@intel.com dip_set_offline(dev_info_t *dip, void *arg)
954512004Sjiang.liu@intel.com {
954612004Sjiang.liu@intel.com 	int end;
954712004Sjiang.liu@intel.com 	result_t *resp = (result_t *)arg;
954812004Sjiang.liu@intel.com 
954912004Sjiang.liu@intel.com 	ASSERT(dip);
955012004Sjiang.liu@intel.com 	ASSERT(resp);
955112004Sjiang.liu@intel.com 
955212004Sjiang.liu@intel.com 	/*
955312004Sjiang.liu@intel.com 	 * We stop the walk if e_ddi_offline_notify() returns
955412004Sjiang.liu@intel.com 	 * failure, because this implies that one or more consumers
955512004Sjiang.liu@intel.com 	 * (either LDI or contract based) has blocked the offline.
955612004Sjiang.liu@intel.com 	 * So there is no point in conitnuing the walk
955712004Sjiang.liu@intel.com 	 */
955812004Sjiang.liu@intel.com 	if (e_ddi_offline_notify(dip) == DDI_FAILURE) {
955912004Sjiang.liu@intel.com 		resp->result = DDI_FAILURE;
956012004Sjiang.liu@intel.com 		return (DDI_WALK_TERMINATE);
956112004Sjiang.liu@intel.com 	}
956212004Sjiang.liu@intel.com 
956312004Sjiang.liu@intel.com 	/*
956412004Sjiang.liu@intel.com 	 * If set_infant_dip_offline() returns failure, it implies
956512004Sjiang.liu@intel.com 	 * that we failed to set a particular dip offline. This
956612004Sjiang.liu@intel.com 	 * does not imply that the offline as a whole should fail.
956712004Sjiang.liu@intel.com 	 * We want to do the best we can, so we continue the walk.
956812004Sjiang.liu@intel.com 	 */
956912004Sjiang.liu@intel.com 	if (set_infant_dip_offline(dip, resp->path) == DDI_SUCCESS)
957012004Sjiang.liu@intel.com 		end = DDI_SUCCESS;
957112004Sjiang.liu@intel.com 	else
957212004Sjiang.liu@intel.com 		end = DDI_FAILURE;
957312004Sjiang.liu@intel.com 
957412004Sjiang.liu@intel.com 	e_ddi_offline_finalize(dip, end);
957512004Sjiang.liu@intel.com 
957612004Sjiang.liu@intel.com 	return (DDI_WALK_CONTINUE);
957712004Sjiang.liu@intel.com }
957812004Sjiang.liu@intel.com 
957912004Sjiang.liu@intel.com /*
958012004Sjiang.liu@intel.com  * The call to e_ddi_offline_notify() exists for the
958112004Sjiang.liu@intel.com  * unlikely error case that a branch we are trying to
958212004Sjiang.liu@intel.com  * create already exists and has device contracts or LDI
958312004Sjiang.liu@intel.com  * event callbacks against it.
958412004Sjiang.liu@intel.com  *
958512004Sjiang.liu@intel.com  * We allow create to succeed for such branches only if
958612004Sjiang.liu@intel.com  * no constraints block the offline.
958712004Sjiang.liu@intel.com  */
958812004Sjiang.liu@intel.com static int
branch_set_offline(dev_info_t * dip,char * path)958912004Sjiang.liu@intel.com branch_set_offline(dev_info_t *dip, char *path)
959012004Sjiang.liu@intel.com {
959112004Sjiang.liu@intel.com 	int		circ;
959212004Sjiang.liu@intel.com 	int		end;
959312004Sjiang.liu@intel.com 	result_t	res;
959412004Sjiang.liu@intel.com 
959512004Sjiang.liu@intel.com 
959612004Sjiang.liu@intel.com 	if (e_ddi_offline_notify(dip) == DDI_FAILURE) {
959712004Sjiang.liu@intel.com 		return (DDI_FAILURE);
959812004Sjiang.liu@intel.com 	}
959912004Sjiang.liu@intel.com 
960012004Sjiang.liu@intel.com 	if (set_infant_dip_offline(dip, path) == DDI_SUCCESS)
960112004Sjiang.liu@intel.com 		end = DDI_SUCCESS;
960212004Sjiang.liu@intel.com 	else
960312004Sjiang.liu@intel.com 		end = DDI_FAILURE;
960412004Sjiang.liu@intel.com 
960512004Sjiang.liu@intel.com 	e_ddi_offline_finalize(dip, end);
960612004Sjiang.liu@intel.com 
960712004Sjiang.liu@intel.com 	if (end == DDI_FAILURE)
960812004Sjiang.liu@intel.com 		return (DDI_FAILURE);
960912004Sjiang.liu@intel.com 
961012004Sjiang.liu@intel.com 	res.result = DDI_SUCCESS;
961112004Sjiang.liu@intel.com 	res.path = path;
961212004Sjiang.liu@intel.com 
961312004Sjiang.liu@intel.com 	ndi_devi_enter(dip, &circ);
961412004Sjiang.liu@intel.com 	ddi_walk_devs(ddi_get_child(dip), dip_set_offline, &res);
961512004Sjiang.liu@intel.com 	ndi_devi_exit(dip, circ);
961612004Sjiang.liu@intel.com 
961712004Sjiang.liu@intel.com 	return (res.result);
961812004Sjiang.liu@intel.com }
961912004Sjiang.liu@intel.com 
962012004Sjiang.liu@intel.com /*ARGSUSED*/
962112004Sjiang.liu@intel.com static int
create_prom_branch(void * arg,int has_changed)962212004Sjiang.liu@intel.com create_prom_branch(void *arg, int has_changed)
962312004Sjiang.liu@intel.com {
962412004Sjiang.liu@intel.com 	int		circ;
962512004Sjiang.liu@intel.com 	int		exists, rv;
962612004Sjiang.liu@intel.com 	pnode_t		nodeid;
962712004Sjiang.liu@intel.com 	struct ptnode	*tnp;
962812004Sjiang.liu@intel.com 	dev_info_t	*dip;
962912004Sjiang.liu@intel.com 	struct pta	*ap = arg;
963012004Sjiang.liu@intel.com 	devi_branch_t	*bp;
963112004Sjiang.liu@intel.com 	char		*path;
963212004Sjiang.liu@intel.com 
963312004Sjiang.liu@intel.com 	ASSERT(ap);
963412004Sjiang.liu@intel.com 	ASSERT(ap->fdip == NULL);
963512004Sjiang.liu@intel.com 	ASSERT(ap->pdip && ndi_dev_is_prom_node(ap->pdip));
963612004Sjiang.liu@intel.com 
963712004Sjiang.liu@intel.com 	bp = ap->bp;
963812004Sjiang.liu@intel.com 
963912004Sjiang.liu@intel.com 	nodeid = ddi_get_nodeid(ap->pdip);
964012004Sjiang.liu@intel.com 	if (nodeid == OBP_NONODE || nodeid == OBP_BADNODE) {
964112004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "create_prom_branch: invalid "
964212004Sjiang.liu@intel.com 		    "nodeid: 0x%x", nodeid);
964312004Sjiang.liu@intel.com 		return (EINVAL);
964412004Sjiang.liu@intel.com 	}
964512004Sjiang.liu@intel.com 
964612004Sjiang.liu@intel.com 	ap->head = NULL;
964712004Sjiang.liu@intel.com 
964812004Sjiang.liu@intel.com 	nodeid = prom_childnode(nodeid);
964912004Sjiang.liu@intel.com 	while (nodeid != OBP_NONODE && nodeid != OBP_BADNODE) {
965012004Sjiang.liu@intel.com 		visit_node(nodeid, ap);
965112004Sjiang.liu@intel.com 		nodeid = prom_nextnode(nodeid);
965212004Sjiang.liu@intel.com 	}
965312004Sjiang.liu@intel.com 
965412004Sjiang.liu@intel.com 	if (ap->head == NULL)
965512004Sjiang.liu@intel.com 		return (ENODEV);
965612004Sjiang.liu@intel.com 
965712004Sjiang.liu@intel.com 	path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
965812004Sjiang.liu@intel.com 	rv = 0;
965912004Sjiang.liu@intel.com 	while ((tnp = ap->head) != NULL) {
966012004Sjiang.liu@intel.com 		ap->head = tnp->next;
966112004Sjiang.liu@intel.com 
966212004Sjiang.liu@intel.com 		ndi_devi_enter(ap->pdip, &circ);
966312004Sjiang.liu@intel.com 
966412004Sjiang.liu@intel.com 		/*
966512004Sjiang.liu@intel.com 		 * Check if the branch already exists.
966612004Sjiang.liu@intel.com 		 */
966712004Sjiang.liu@intel.com 		exists = 0;
966812004Sjiang.liu@intel.com 		dip = e_ddi_nodeid_to_dip(tnp->nodeid);
966912004Sjiang.liu@intel.com 		if (dip != NULL) {
967012004Sjiang.liu@intel.com 			exists = 1;
967112004Sjiang.liu@intel.com 
967212004Sjiang.liu@intel.com 			/* Parent is held busy, so release hold */
967312004Sjiang.liu@intel.com 			ndi_rele_devi(dip);
967412004Sjiang.liu@intel.com #ifdef	DEBUG
967512004Sjiang.liu@intel.com 			cmn_err(CE_WARN, "create_prom_branch: dip(%p) exists"
967612004Sjiang.liu@intel.com 			    " for nodeid 0x%x", (void *)dip, tnp->nodeid);
967712004Sjiang.liu@intel.com #endif
967812004Sjiang.liu@intel.com 		} else {
967912004Sjiang.liu@intel.com 			dip = i_ddi_create_branch(ap->pdip, tnp->nodeid);
968012004Sjiang.liu@intel.com 		}
968112004Sjiang.liu@intel.com 
968212004Sjiang.liu@intel.com 		kmem_free(tnp, sizeof (struct ptnode));
968312004Sjiang.liu@intel.com 
968412004Sjiang.liu@intel.com 		/*
968512004Sjiang.liu@intel.com 		 * Hold the branch if it is not already held
968612004Sjiang.liu@intel.com 		 */
968712004Sjiang.liu@intel.com 		if (dip && !exists) {
968812004Sjiang.liu@intel.com 			e_ddi_branch_hold(dip);
968912004Sjiang.liu@intel.com 		}
969012004Sjiang.liu@intel.com 
969112004Sjiang.liu@intel.com 		ASSERT(dip == NULL || e_ddi_branch_held(dip));
969212004Sjiang.liu@intel.com 
969312004Sjiang.liu@intel.com 		/*
969412004Sjiang.liu@intel.com 		 * Set all dips in the newly created branch offline so that
969512004Sjiang.liu@intel.com 		 * only a "configure" operation can attach
969612004Sjiang.liu@intel.com 		 * the branch
969712004Sjiang.liu@intel.com 		 */
969812004Sjiang.liu@intel.com 		if (dip == NULL || branch_set_offline(dip, path)
969912004Sjiang.liu@intel.com 		    == DDI_FAILURE) {
970012004Sjiang.liu@intel.com 			ndi_devi_exit(ap->pdip, circ);
970112004Sjiang.liu@intel.com 			rv = EIO;
970212004Sjiang.liu@intel.com 			continue;
970312004Sjiang.liu@intel.com 		}
970412004Sjiang.liu@intel.com 
970512004Sjiang.liu@intel.com 		ASSERT(ddi_get_parent(dip) == ap->pdip);
970612004Sjiang.liu@intel.com 
970712004Sjiang.liu@intel.com 		ndi_devi_exit(ap->pdip, circ);
970812004Sjiang.liu@intel.com 
970912004Sjiang.liu@intel.com 		if (ap->flags & DEVI_BRANCH_CONFIGURE) {
971012004Sjiang.liu@intel.com 			int error = e_ddi_branch_configure(dip, &ap->fdip, 0);
971112004Sjiang.liu@intel.com 			if (error && rv == 0)
971212004Sjiang.liu@intel.com 				rv = error;
971312004Sjiang.liu@intel.com 		}
971412004Sjiang.liu@intel.com 
971512004Sjiang.liu@intel.com 		/*
971612004Sjiang.liu@intel.com 		 * Invoke devi_branch_callback() (if it exists) only for
971712004Sjiang.liu@intel.com 		 * newly created branches
971812004Sjiang.liu@intel.com 		 */
971912004Sjiang.liu@intel.com 		if (bp->devi_branch_callback && !exists)
972012004Sjiang.liu@intel.com 			bp->devi_branch_callback(dip, bp->arg, 0);
972112004Sjiang.liu@intel.com 	}
972212004Sjiang.liu@intel.com 
972312004Sjiang.liu@intel.com 	kmem_free(path, MAXPATHLEN);
972412004Sjiang.liu@intel.com 
972512004Sjiang.liu@intel.com 	return (rv);
972612004Sjiang.liu@intel.com }
972712004Sjiang.liu@intel.com 
972812004Sjiang.liu@intel.com static int
sid_node_create(dev_info_t * pdip,devi_branch_t * bp,dev_info_t ** rdipp)972912004Sjiang.liu@intel.com sid_node_create(dev_info_t *pdip, devi_branch_t *bp, dev_info_t **rdipp)
973012004Sjiang.liu@intel.com {
973112004Sjiang.liu@intel.com 	int			rv, circ, len;
973212004Sjiang.liu@intel.com 	int			i, flags, ret;
973312004Sjiang.liu@intel.com 	dev_info_t		*dip;
973412004Sjiang.liu@intel.com 	char			*nbuf;
973512004Sjiang.liu@intel.com 	char			*path;
973612004Sjiang.liu@intel.com 	static const char	*noname = "<none>";
973712004Sjiang.liu@intel.com 
973812004Sjiang.liu@intel.com 	ASSERT(pdip);
973912004Sjiang.liu@intel.com 	ASSERT(DEVI_BUSY_OWNED(pdip));
974012004Sjiang.liu@intel.com 
974112004Sjiang.liu@intel.com 	flags = 0;
974212004Sjiang.liu@intel.com 
974312004Sjiang.liu@intel.com 	/*
974412004Sjiang.liu@intel.com 	 * Creating the root of a branch ?
974512004Sjiang.liu@intel.com 	 */
974612004Sjiang.liu@intel.com 	if (rdipp) {
974712004Sjiang.liu@intel.com 		*rdipp = NULL;
974812004Sjiang.liu@intel.com 		flags = DEVI_BRANCH_ROOT;
974912004Sjiang.liu@intel.com 	}
975012004Sjiang.liu@intel.com 
975112004Sjiang.liu@intel.com 	ndi_devi_alloc_sleep(pdip, (char *)noname, DEVI_SID_NODEID, &dip);
975212004Sjiang.liu@intel.com 	rv = bp->create.sid_branch_create(dip, bp->arg, flags);
975312004Sjiang.liu@intel.com 
975412004Sjiang.liu@intel.com 	nbuf = kmem_alloc(OBP_MAXDRVNAME, KM_SLEEP);
975512004Sjiang.liu@intel.com 
975612004Sjiang.liu@intel.com 	if (rv == DDI_WALK_ERROR) {
975712004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "e_ddi_branch_create: Error setting"
975812004Sjiang.liu@intel.com 		    " properties on devinfo node %p",  (void *)dip);
975912004Sjiang.liu@intel.com 		goto fail;
976012004Sjiang.liu@intel.com 	}
976112004Sjiang.liu@intel.com 
976212004Sjiang.liu@intel.com 	len = OBP_MAXDRVNAME;
976312004Sjiang.liu@intel.com 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip,
976412004Sjiang.liu@intel.com 	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "name", nbuf, &len)
976512004Sjiang.liu@intel.com 	    != DDI_PROP_SUCCESS) {
976612004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "e_ddi_branch_create: devinfo node %p has"
976712004Sjiang.liu@intel.com 		    "no name property", (void *)dip);
976812004Sjiang.liu@intel.com 		goto fail;
976912004Sjiang.liu@intel.com 	}
977012004Sjiang.liu@intel.com 
977112004Sjiang.liu@intel.com 	ASSERT(i_ddi_node_state(dip) == DS_PROTO);
977212004Sjiang.liu@intel.com 	if (ndi_devi_set_nodename(dip, nbuf, 0) != NDI_SUCCESS) {
977312004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "e_ddi_branch_create: cannot set name (%s)"
977412004Sjiang.liu@intel.com 		    " for devinfo node %p", nbuf, (void *)dip);
977512004Sjiang.liu@intel.com 		goto fail;
977612004Sjiang.liu@intel.com 	}
977712004Sjiang.liu@intel.com 
977812004Sjiang.liu@intel.com 	kmem_free(nbuf, OBP_MAXDRVNAME);
977912004Sjiang.liu@intel.com 
978012004Sjiang.liu@intel.com 	/*
978112004Sjiang.liu@intel.com 	 * Ignore bind failures just like boot does
978212004Sjiang.liu@intel.com 	 */
978312004Sjiang.liu@intel.com 	(void) ndi_devi_bind_driver(dip, 0);
978412004Sjiang.liu@intel.com 
978512004Sjiang.liu@intel.com 	switch (rv) {
978612004Sjiang.liu@intel.com 	case DDI_WALK_CONTINUE:
978712004Sjiang.liu@intel.com 	case DDI_WALK_PRUNESIB:
978812004Sjiang.liu@intel.com 		ndi_devi_enter(dip, &circ);
978912004Sjiang.liu@intel.com 
979012004Sjiang.liu@intel.com 		i = DDI_WALK_CONTINUE;
979112004Sjiang.liu@intel.com 		for (; i == DDI_WALK_CONTINUE; ) {
979212004Sjiang.liu@intel.com 			i = sid_node_create(dip, bp, NULL);
979312004Sjiang.liu@intel.com 		}
979412004Sjiang.liu@intel.com 
979512004Sjiang.liu@intel.com 		ASSERT(i == DDI_WALK_ERROR || i == DDI_WALK_PRUNESIB);
979612004Sjiang.liu@intel.com 		if (i == DDI_WALK_ERROR)
979712004Sjiang.liu@intel.com 			rv = i;
979812004Sjiang.liu@intel.com 		/*
979912004Sjiang.liu@intel.com 		 * If PRUNESIB stop creating siblings
980012004Sjiang.liu@intel.com 		 * of dip's child. Subsequent walk behavior
980112004Sjiang.liu@intel.com 		 * is determined by rv returned by dip.
980212004Sjiang.liu@intel.com 		 */
980312004Sjiang.liu@intel.com 
980412004Sjiang.liu@intel.com 		ndi_devi_exit(dip, circ);
980512004Sjiang.liu@intel.com 		break;
980612004Sjiang.liu@intel.com 	case DDI_WALK_TERMINATE:
980712004Sjiang.liu@intel.com 		/*
980812004Sjiang.liu@intel.com 		 * Don't create children and ask our parent
980912004Sjiang.liu@intel.com 		 * to not create siblings either.
981012004Sjiang.liu@intel.com 		 */
981112004Sjiang.liu@intel.com 		rv = DDI_WALK_PRUNESIB;
981212004Sjiang.liu@intel.com 		break;
981312004Sjiang.liu@intel.com 	case DDI_WALK_PRUNECHILD:
981412004Sjiang.liu@intel.com 		/*
981512004Sjiang.liu@intel.com 		 * Don't create children, but ask parent to continue
981612004Sjiang.liu@intel.com 		 * with siblings.
981712004Sjiang.liu@intel.com 		 */
981812004Sjiang.liu@intel.com 		rv = DDI_WALK_CONTINUE;
981912004Sjiang.liu@intel.com 		break;
982012004Sjiang.liu@intel.com 	default:
982112004Sjiang.liu@intel.com 		ASSERT(0);
982212004Sjiang.liu@intel.com 		break;
982312004Sjiang.liu@intel.com 	}
982412004Sjiang.liu@intel.com 
982512004Sjiang.liu@intel.com 	if (rdipp)
982612004Sjiang.liu@intel.com 		*rdipp = dip;
982712004Sjiang.liu@intel.com 
982812004Sjiang.liu@intel.com 	/*
982912004Sjiang.liu@intel.com 	 * Set device offline - only the "configure" op should cause an attach.
983012004Sjiang.liu@intel.com 	 * Note that it is safe to set the dip offline without checking
983112004Sjiang.liu@intel.com 	 * for either device contract or layered driver (LDI) based constraints
983212004Sjiang.liu@intel.com 	 * since there cannot be any contracts or LDI opens of this device.
983312004Sjiang.liu@intel.com 	 * This is because this node is a newly created dip with the parent busy
983412004Sjiang.liu@intel.com 	 * held, so no other thread can come in and attach this dip. A dip that
983512004Sjiang.liu@intel.com 	 * has never been attached cannot have contracts since by definition
983612004Sjiang.liu@intel.com 	 * a device contract (an agreement between a process and a device minor
983712004Sjiang.liu@intel.com 	 * node) can only be created against a device that has minor nodes
983812004Sjiang.liu@intel.com 	 * i.e is attached. Similarly an LDI open will only succeed if the
983912004Sjiang.liu@intel.com 	 * dip is attached. We assert below that the dip is not attached.
984012004Sjiang.liu@intel.com 	 */
984112004Sjiang.liu@intel.com 	ASSERT(i_ddi_node_state(dip) < DS_ATTACHED);
984212004Sjiang.liu@intel.com 	path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
984312004Sjiang.liu@intel.com 	ret = set_infant_dip_offline(dip, path);
984412004Sjiang.liu@intel.com 	ASSERT(ret == DDI_SUCCESS);
984512004Sjiang.liu@intel.com 	kmem_free(path, MAXPATHLEN);
984612004Sjiang.liu@intel.com 
984712004Sjiang.liu@intel.com 	return (rv);
984812004Sjiang.liu@intel.com fail:
984912004Sjiang.liu@intel.com 	(void) ndi_devi_free(dip);
985012004Sjiang.liu@intel.com 	kmem_free(nbuf, OBP_MAXDRVNAME);
985112004Sjiang.liu@intel.com 	return (DDI_WALK_ERROR);
985212004Sjiang.liu@intel.com }
985312004Sjiang.liu@intel.com 
985412004Sjiang.liu@intel.com static int
create_sid_branch(dev_info_t * pdip,devi_branch_t * bp,dev_info_t ** dipp,uint_t flags)985512004Sjiang.liu@intel.com create_sid_branch(
985612004Sjiang.liu@intel.com 	dev_info_t	*pdip,
985712004Sjiang.liu@intel.com 	devi_branch_t	*bp,
985812004Sjiang.liu@intel.com 	dev_info_t	**dipp,
985912004Sjiang.liu@intel.com 	uint_t		flags)
986012004Sjiang.liu@intel.com {
986112004Sjiang.liu@intel.com 	int		rv = 0, state = DDI_WALK_CONTINUE;
986212004Sjiang.liu@intel.com 	dev_info_t	*rdip;
986312004Sjiang.liu@intel.com 
986412004Sjiang.liu@intel.com 	while (state == DDI_WALK_CONTINUE) {
986512004Sjiang.liu@intel.com 		int	circ;
986612004Sjiang.liu@intel.com 
986712004Sjiang.liu@intel.com 		ndi_devi_enter(pdip, &circ);
986812004Sjiang.liu@intel.com 
986912004Sjiang.liu@intel.com 		state = sid_node_create(pdip, bp, &rdip);
987012004Sjiang.liu@intel.com 		if (rdip == NULL) {
987112004Sjiang.liu@intel.com 			ndi_devi_exit(pdip, circ);
987212004Sjiang.liu@intel.com 			ASSERT(state == DDI_WALK_ERROR);
987312004Sjiang.liu@intel.com 			break;
987412004Sjiang.liu@intel.com 		}
987512004Sjiang.liu@intel.com 
987612004Sjiang.liu@intel.com 		e_ddi_branch_hold(rdip);
987712004Sjiang.liu@intel.com 
987812004Sjiang.liu@intel.com 		ndi_devi_exit(pdip, circ);
987912004Sjiang.liu@intel.com 
988012004Sjiang.liu@intel.com 		if (flags & DEVI_BRANCH_CONFIGURE) {
988112004Sjiang.liu@intel.com 			int error = e_ddi_branch_configure(rdip, dipp, 0);
988212004Sjiang.liu@intel.com 			if (error && rv == 0)
988312004Sjiang.liu@intel.com 				rv = error;
988412004Sjiang.liu@intel.com 		}
988512004Sjiang.liu@intel.com 
988612004Sjiang.liu@intel.com 		/*
988712004Sjiang.liu@intel.com 		 * devi_branch_callback() is optional
988812004Sjiang.liu@intel.com 		 */
988912004Sjiang.liu@intel.com 		if (bp->devi_branch_callback)
989012004Sjiang.liu@intel.com 			bp->devi_branch_callback(rdip, bp->arg, 0);
989112004Sjiang.liu@intel.com 	}
989212004Sjiang.liu@intel.com 
989312004Sjiang.liu@intel.com 	ASSERT(state == DDI_WALK_ERROR || state == DDI_WALK_PRUNESIB);
989412004Sjiang.liu@intel.com 
989512004Sjiang.liu@intel.com 	return (state == DDI_WALK_ERROR ? EIO : rv);
989612004Sjiang.liu@intel.com }
989712004Sjiang.liu@intel.com 
989812004Sjiang.liu@intel.com int
e_ddi_branch_create(dev_info_t * pdip,devi_branch_t * bp,dev_info_t ** dipp,uint_t flags)989912004Sjiang.liu@intel.com e_ddi_branch_create(
990012004Sjiang.liu@intel.com 	dev_info_t	*pdip,
990112004Sjiang.liu@intel.com 	devi_branch_t	*bp,
990212004Sjiang.liu@intel.com 	dev_info_t	**dipp,
990312004Sjiang.liu@intel.com 	uint_t		flags)
990412004Sjiang.liu@intel.com {
990512004Sjiang.liu@intel.com 	int prom_devi, sid_devi, error;
990612004Sjiang.liu@intel.com 
990712004Sjiang.liu@intel.com 	if (pdip == NULL || bp == NULL || bp->type == 0)
990812004Sjiang.liu@intel.com 		return (EINVAL);
990912004Sjiang.liu@intel.com 
991012004Sjiang.liu@intel.com 	prom_devi = (bp->type == DEVI_BRANCH_PROM) ? 1 : 0;
991112004Sjiang.liu@intel.com 	sid_devi = (bp->type == DEVI_BRANCH_SID) ? 1 : 0;
991212004Sjiang.liu@intel.com 
991312004Sjiang.liu@intel.com 	if (prom_devi && bp->create.prom_branch_select == NULL)
991412004Sjiang.liu@intel.com 		return (EINVAL);
991512004Sjiang.liu@intel.com 	else if (sid_devi && bp->create.sid_branch_create == NULL)
991612004Sjiang.liu@intel.com 		return (EINVAL);
991712004Sjiang.liu@intel.com 	else if (!prom_devi && !sid_devi)
991812004Sjiang.liu@intel.com 		return (EINVAL);
991912004Sjiang.liu@intel.com 
992012004Sjiang.liu@intel.com 	if (flags & DEVI_BRANCH_EVENT)
992112004Sjiang.liu@intel.com 		return (EINVAL);
992212004Sjiang.liu@intel.com 
992312004Sjiang.liu@intel.com 	if (prom_devi) {
992412004Sjiang.liu@intel.com 		struct pta pta = {0};
992512004Sjiang.liu@intel.com 
992612004Sjiang.liu@intel.com 		pta.pdip = pdip;
992712004Sjiang.liu@intel.com 		pta.bp = bp;
992812004Sjiang.liu@intel.com 		pta.flags = flags;
992912004Sjiang.liu@intel.com 
993012004Sjiang.liu@intel.com 		error = prom_tree_access(create_prom_branch, &pta, NULL);
993112004Sjiang.liu@intel.com 
993212004Sjiang.liu@intel.com 		if (dipp)
993312004Sjiang.liu@intel.com 			*dipp = pta.fdip;
993412004Sjiang.liu@intel.com 		else if (pta.fdip)
993512004Sjiang.liu@intel.com 			ndi_rele_devi(pta.fdip);
993612004Sjiang.liu@intel.com 	} else {
993712004Sjiang.liu@intel.com 		error = create_sid_branch(pdip, bp, dipp, flags);
993812004Sjiang.liu@intel.com 	}
993912004Sjiang.liu@intel.com 
994012004Sjiang.liu@intel.com 	return (error);
994112004Sjiang.liu@intel.com }
994212004Sjiang.liu@intel.com 
994312004Sjiang.liu@intel.com int
e_ddi_branch_configure(dev_info_t * rdip,dev_info_t ** dipp,uint_t flags)994412004Sjiang.liu@intel.com e_ddi_branch_configure(dev_info_t *rdip, dev_info_t **dipp, uint_t flags)
994512004Sjiang.liu@intel.com {
994612004Sjiang.liu@intel.com 	int		rv;
994712004Sjiang.liu@intel.com 	char		*devnm;
994812004Sjiang.liu@intel.com 	dev_info_t	*pdip;
994912004Sjiang.liu@intel.com 
995012004Sjiang.liu@intel.com 	if (dipp)
995112004Sjiang.liu@intel.com 		*dipp = NULL;
995212004Sjiang.liu@intel.com 
995312004Sjiang.liu@intel.com 	if (rdip == NULL || flags != 0 || (flags & DEVI_BRANCH_EVENT))
995412004Sjiang.liu@intel.com 		return (EINVAL);
995512004Sjiang.liu@intel.com 
995612004Sjiang.liu@intel.com 	pdip = ddi_get_parent(rdip);
995712004Sjiang.liu@intel.com 
995812004Sjiang.liu@intel.com 	ndi_hold_devi(pdip);
995912004Sjiang.liu@intel.com 
996012004Sjiang.liu@intel.com 	if (!e_ddi_branch_held(rdip)) {
996112004Sjiang.liu@intel.com 		ndi_rele_devi(pdip);
996212004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "e_ddi_branch_configure: "
996312004Sjiang.liu@intel.com 		    "dip(%p) not held", (void *)rdip);
996412004Sjiang.liu@intel.com 		return (EINVAL);
996512004Sjiang.liu@intel.com 	}
996612004Sjiang.liu@intel.com 
996712004Sjiang.liu@intel.com 	if (i_ddi_node_state(rdip) < DS_INITIALIZED) {
996812004Sjiang.liu@intel.com 		/*
996912004Sjiang.liu@intel.com 		 * First attempt to bind a driver. If we fail, return
997012004Sjiang.liu@intel.com 		 * success (On some platforms, dips for some device
997112004Sjiang.liu@intel.com 		 * types (CPUs) may not have a driver)
997212004Sjiang.liu@intel.com 		 */
997312004Sjiang.liu@intel.com 		if (ndi_devi_bind_driver(rdip, 0) != NDI_SUCCESS) {
997412004Sjiang.liu@intel.com 			ndi_rele_devi(pdip);
997512004Sjiang.liu@intel.com 			return (0);
997612004Sjiang.liu@intel.com 		}
997712004Sjiang.liu@intel.com 
997812004Sjiang.liu@intel.com 		if (ddi_initchild(pdip, rdip) != DDI_SUCCESS) {
997912004Sjiang.liu@intel.com 			rv = NDI_FAILURE;
998012004Sjiang.liu@intel.com 			goto out;
998112004Sjiang.liu@intel.com 		}
998212004Sjiang.liu@intel.com 	}
998312004Sjiang.liu@intel.com 
998412004Sjiang.liu@intel.com 	ASSERT(i_ddi_node_state(rdip) >= DS_INITIALIZED);
998512004Sjiang.liu@intel.com 
998612004Sjiang.liu@intel.com 	devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
998712004Sjiang.liu@intel.com 
998812004Sjiang.liu@intel.com 	(void) ddi_deviname(rdip, devnm);
998912004Sjiang.liu@intel.com 
999012004Sjiang.liu@intel.com 	if ((rv = ndi_devi_config_one(pdip, devnm+1, &rdip,
999112004Sjiang.liu@intel.com 	    NDI_DEVI_ONLINE | NDI_CONFIG)) == NDI_SUCCESS) {
999212004Sjiang.liu@intel.com 		/* release hold from ndi_devi_config_one() */
999312004Sjiang.liu@intel.com 		ndi_rele_devi(rdip);
999412004Sjiang.liu@intel.com 	}
999512004Sjiang.liu@intel.com 
999612004Sjiang.liu@intel.com 	kmem_free(devnm, MAXNAMELEN + 1);
999712004Sjiang.liu@intel.com out:
999812004Sjiang.liu@intel.com 	if (rv != NDI_SUCCESS && dipp && rdip) {
999912004Sjiang.liu@intel.com 		ndi_hold_devi(rdip);
1000012004Sjiang.liu@intel.com 		*dipp = rdip;
1000112004Sjiang.liu@intel.com 	}
1000212004Sjiang.liu@intel.com 	ndi_rele_devi(pdip);
1000312004Sjiang.liu@intel.com 	return (ndi2errno(rv));
1000412004Sjiang.liu@intel.com }
1000512004Sjiang.liu@intel.com 
1000612004Sjiang.liu@intel.com void
e_ddi_branch_hold(dev_info_t * rdip)1000712004Sjiang.liu@intel.com e_ddi_branch_hold(dev_info_t *rdip)
1000812004Sjiang.liu@intel.com {
1000912004Sjiang.liu@intel.com 	if (e_ddi_branch_held(rdip)) {
1001012004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "e_ddi_branch_hold: branch already held");
1001112004Sjiang.liu@intel.com 		return;
1001212004Sjiang.liu@intel.com 	}
1001312004Sjiang.liu@intel.com 
1001412004Sjiang.liu@intel.com 	mutex_enter(&DEVI(rdip)->devi_lock);
1001512004Sjiang.liu@intel.com 	if ((DEVI(rdip)->devi_flags & DEVI_BRANCH_HELD) == 0) {
1001612004Sjiang.liu@intel.com 		DEVI(rdip)->devi_flags |= DEVI_BRANCH_HELD;
1001712004Sjiang.liu@intel.com 		DEVI(rdip)->devi_ref++;
1001812004Sjiang.liu@intel.com 	}
1001912004Sjiang.liu@intel.com 	ASSERT(DEVI(rdip)->devi_ref > 0);
1002012004Sjiang.liu@intel.com 	mutex_exit(&DEVI(rdip)->devi_lock);
1002112004Sjiang.liu@intel.com }
1002212004Sjiang.liu@intel.com 
1002312004Sjiang.liu@intel.com int
e_ddi_branch_held(dev_info_t * rdip)1002412004Sjiang.liu@intel.com e_ddi_branch_held(dev_info_t *rdip)
1002512004Sjiang.liu@intel.com {
1002612004Sjiang.liu@intel.com 	int rv = 0;
1002712004Sjiang.liu@intel.com 
1002812004Sjiang.liu@intel.com 	mutex_enter(&DEVI(rdip)->devi_lock);
1002912004Sjiang.liu@intel.com 	if ((DEVI(rdip)->devi_flags & DEVI_BRANCH_HELD) &&
1003012004Sjiang.liu@intel.com 	    DEVI(rdip)->devi_ref > 0) {
1003112004Sjiang.liu@intel.com 		rv = 1;
1003212004Sjiang.liu@intel.com 	}
1003312004Sjiang.liu@intel.com 	mutex_exit(&DEVI(rdip)->devi_lock);
1003412004Sjiang.liu@intel.com 
1003512004Sjiang.liu@intel.com 	return (rv);
1003612004Sjiang.liu@intel.com }
1003712004Sjiang.liu@intel.com 
1003812004Sjiang.liu@intel.com void
e_ddi_branch_rele(dev_info_t * rdip)1003912004Sjiang.liu@intel.com e_ddi_branch_rele(dev_info_t *rdip)
1004012004Sjiang.liu@intel.com {
1004112004Sjiang.liu@intel.com 	mutex_enter(&DEVI(rdip)->devi_lock);
1004212004Sjiang.liu@intel.com 	DEVI(rdip)->devi_flags &= ~DEVI_BRANCH_HELD;
1004312004Sjiang.liu@intel.com 	DEVI(rdip)->devi_ref--;
1004412004Sjiang.liu@intel.com 	mutex_exit(&DEVI(rdip)->devi_lock);
1004512004Sjiang.liu@intel.com }
1004612004Sjiang.liu@intel.com 
1004712004Sjiang.liu@intel.com int
e_ddi_branch_unconfigure(dev_info_t * rdip,dev_info_t ** dipp,uint_t flags)1004812004Sjiang.liu@intel.com e_ddi_branch_unconfigure(
1004912004Sjiang.liu@intel.com 	dev_info_t *rdip,
1005012004Sjiang.liu@intel.com 	dev_info_t **dipp,
1005112004Sjiang.liu@intel.com 	uint_t flags)
1005212004Sjiang.liu@intel.com {
1005312004Sjiang.liu@intel.com 	int	circ, rv;
1005412004Sjiang.liu@intel.com 	int	destroy;
1005512004Sjiang.liu@intel.com 	char	*devnm;
1005612004Sjiang.liu@intel.com 	uint_t	nflags;
1005712004Sjiang.liu@intel.com 	dev_info_t *pdip;
1005812004Sjiang.liu@intel.com 
1005912004Sjiang.liu@intel.com 	if (dipp)
1006012004Sjiang.liu@intel.com 		*dipp = NULL;
1006112004Sjiang.liu@intel.com 
1006212004Sjiang.liu@intel.com 	if (rdip == NULL)
1006312004Sjiang.liu@intel.com 		return (EINVAL);
1006412004Sjiang.liu@intel.com 
1006512004Sjiang.liu@intel.com 	pdip = ddi_get_parent(rdip);
1006612004Sjiang.liu@intel.com 
1006712004Sjiang.liu@intel.com 	ASSERT(pdip);
1006812004Sjiang.liu@intel.com 
1006912004Sjiang.liu@intel.com 	/*
1007012004Sjiang.liu@intel.com 	 * Check if caller holds pdip busy - can cause deadlocks during
1007112004Sjiang.liu@intel.com 	 * devfs_clean()
1007212004Sjiang.liu@intel.com 	 */
1007312004Sjiang.liu@intel.com 	if (DEVI_BUSY_OWNED(pdip)) {
1007412004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "e_ddi_branch_unconfigure: failed: parent"
1007512004Sjiang.liu@intel.com 		    " devinfo node(%p) is busy held", (void *)pdip);
1007612004Sjiang.liu@intel.com 		return (EINVAL);
1007712004Sjiang.liu@intel.com 	}
1007812004Sjiang.liu@intel.com 
1007912004Sjiang.liu@intel.com 	destroy = (flags & DEVI_BRANCH_DESTROY) ? 1 : 0;
1008012004Sjiang.liu@intel.com 
1008112004Sjiang.liu@intel.com 	devnm = kmem_alloc(MAXNAMELEN + 1, KM_SLEEP);
1008212004Sjiang.liu@intel.com 
1008312004Sjiang.liu@intel.com 	ndi_devi_enter(pdip, &circ);
1008412004Sjiang.liu@intel.com 	(void) ddi_deviname(rdip, devnm);
1008512004Sjiang.liu@intel.com 	ndi_devi_exit(pdip, circ);
1008612004Sjiang.liu@intel.com 
1008712004Sjiang.liu@intel.com 	/*
1008812004Sjiang.liu@intel.com 	 * ddi_deviname() returns a component name with / prepended.
1008912004Sjiang.liu@intel.com 	 */
1009012004Sjiang.liu@intel.com 	(void) devfs_clean(pdip, devnm + 1, DV_CLEAN_FORCE);
1009112004Sjiang.liu@intel.com 
1009212004Sjiang.liu@intel.com 	ndi_devi_enter(pdip, &circ);
1009312004Sjiang.liu@intel.com 
1009412004Sjiang.liu@intel.com 	/*
1009512004Sjiang.liu@intel.com 	 * Recreate device name as it may have changed state (init/uninit)
1009612004Sjiang.liu@intel.com 	 * when parent busy lock was dropped for devfs_clean()
1009712004Sjiang.liu@intel.com 	 */
1009812004Sjiang.liu@intel.com 	(void) ddi_deviname(rdip, devnm);
1009912004Sjiang.liu@intel.com 
1010012004Sjiang.liu@intel.com 	if (!e_ddi_branch_held(rdip)) {
1010112004Sjiang.liu@intel.com 		kmem_free(devnm, MAXNAMELEN + 1);
1010212004Sjiang.liu@intel.com 		ndi_devi_exit(pdip, circ);
1010312004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "e_ddi_%s_branch: dip(%p) not held",
1010412004Sjiang.liu@intel.com 		    destroy ? "destroy" : "unconfigure", (void *)rdip);
1010512004Sjiang.liu@intel.com 		return (EINVAL);
1010612004Sjiang.liu@intel.com 	}
1010712004Sjiang.liu@intel.com 
1010812004Sjiang.liu@intel.com 	/*
1010912004Sjiang.liu@intel.com 	 * Release hold on the branch. This is ok since we are holding the
1011012004Sjiang.liu@intel.com 	 * parent busy. If rdip is not removed, we must do a hold on the
1011112004Sjiang.liu@intel.com 	 * branch before returning.
1011212004Sjiang.liu@intel.com 	 */
1011312004Sjiang.liu@intel.com 	e_ddi_branch_rele(rdip);
1011412004Sjiang.liu@intel.com 
1011512004Sjiang.liu@intel.com 	nflags = NDI_DEVI_OFFLINE;
1011612004Sjiang.liu@intel.com 	if (destroy || (flags & DEVI_BRANCH_DESTROY)) {
1011712004Sjiang.liu@intel.com 		nflags |= NDI_DEVI_REMOVE;
1011812004Sjiang.liu@intel.com 		destroy = 1;
1011912004Sjiang.liu@intel.com 	} else {
1012012004Sjiang.liu@intel.com 		nflags |= NDI_UNCONFIG;		/* uninit but don't remove */
1012112004Sjiang.liu@intel.com 	}
1012212004Sjiang.liu@intel.com 
1012312004Sjiang.liu@intel.com 	if (flags & DEVI_BRANCH_EVENT)
1012412004Sjiang.liu@intel.com 		nflags |= NDI_POST_EVENT;
1012512004Sjiang.liu@intel.com 
1012612004Sjiang.liu@intel.com 	if (i_ddi_devi_attached(pdip) &&
1012712004Sjiang.liu@intel.com 	    (i_ddi_node_state(rdip) >= DS_INITIALIZED)) {
1012812004Sjiang.liu@intel.com 		rv = ndi_devi_unconfig_one(pdip, devnm+1, dipp, nflags);
1012912004Sjiang.liu@intel.com 	} else {
1013012004Sjiang.liu@intel.com 		rv = e_ddi_devi_unconfig(rdip, dipp, nflags);
1013112004Sjiang.liu@intel.com 		if (rv == NDI_SUCCESS) {
1013212004Sjiang.liu@intel.com 			ASSERT(!destroy || ddi_get_child(rdip) == NULL);
1013312004Sjiang.liu@intel.com 			rv = ndi_devi_offline(rdip, nflags);
1013412004Sjiang.liu@intel.com 		}
1013512004Sjiang.liu@intel.com 	}
1013612004Sjiang.liu@intel.com 
1013712004Sjiang.liu@intel.com 	if (!destroy || rv != NDI_SUCCESS) {
1013812004Sjiang.liu@intel.com 		/* The dip still exists, so do a hold */
1013912004Sjiang.liu@intel.com 		e_ddi_branch_hold(rdip);
1014012004Sjiang.liu@intel.com 	}
1014112004Sjiang.liu@intel.com out:
1014212004Sjiang.liu@intel.com 	kmem_free(devnm, MAXNAMELEN + 1);
1014312004Sjiang.liu@intel.com 	ndi_devi_exit(pdip, circ);
1014412004Sjiang.liu@intel.com 	return (ndi2errno(rv));
1014512004Sjiang.liu@intel.com }
1014612004Sjiang.liu@intel.com 
1014712004Sjiang.liu@intel.com int
e_ddi_branch_destroy(dev_info_t * rdip,dev_info_t ** dipp,uint_t flag)1014812004Sjiang.liu@intel.com e_ddi_branch_destroy(dev_info_t *rdip, dev_info_t **dipp, uint_t flag)
1014912004Sjiang.liu@intel.com {
1015012004Sjiang.liu@intel.com 	return (e_ddi_branch_unconfigure(rdip, dipp,
1015112004Sjiang.liu@intel.com 	    flag|DEVI_BRANCH_DESTROY));
1015212004Sjiang.liu@intel.com }
1015312004Sjiang.liu@intel.com 
1015412004Sjiang.liu@intel.com /*
1015512004Sjiang.liu@intel.com  * Number of chains for hash table
1015612004Sjiang.liu@intel.com  */
1015712004Sjiang.liu@intel.com #define	NUMCHAINS	17
1015812004Sjiang.liu@intel.com 
1015912004Sjiang.liu@intel.com /*
1016012004Sjiang.liu@intel.com  * Devinfo busy arg
1016112004Sjiang.liu@intel.com  */
1016212004Sjiang.liu@intel.com struct devi_busy {
1016312004Sjiang.liu@intel.com 	int dv_total;
1016412004Sjiang.liu@intel.com 	int s_total;
1016512004Sjiang.liu@intel.com 	mod_hash_t *dv_hash;
1016612004Sjiang.liu@intel.com 	mod_hash_t *s_hash;
1016712004Sjiang.liu@intel.com 	int (*callback)(dev_info_t *, void *, uint_t);
1016812004Sjiang.liu@intel.com 	void *arg;
1016912004Sjiang.liu@intel.com };
1017012004Sjiang.liu@intel.com 
1017112004Sjiang.liu@intel.com static int
visit_dip(dev_info_t * dip,void * arg)1017212004Sjiang.liu@intel.com visit_dip(dev_info_t *dip, void *arg)
1017312004Sjiang.liu@intel.com {
1017412004Sjiang.liu@intel.com 	uintptr_t sbusy, dvbusy, ref;
1017512004Sjiang.liu@intel.com 	struct devi_busy *bsp = arg;
1017612004Sjiang.liu@intel.com 
1017712004Sjiang.liu@intel.com 	ASSERT(bsp->callback);
1017812004Sjiang.liu@intel.com 
1017912004Sjiang.liu@intel.com 	/*
1018012004Sjiang.liu@intel.com 	 * A dip cannot be busy if its reference count is 0
1018112004Sjiang.liu@intel.com 	 */
1018212004Sjiang.liu@intel.com 	if ((ref = e_ddi_devi_holdcnt(dip)) == 0) {
1018312004Sjiang.liu@intel.com 		return (bsp->callback(dip, bsp->arg, 0));
1018412004Sjiang.liu@intel.com 	}
1018512004Sjiang.liu@intel.com 
1018612004Sjiang.liu@intel.com 	if (mod_hash_find(bsp->dv_hash, dip, (mod_hash_val_t *)&dvbusy))
1018712004Sjiang.liu@intel.com 		dvbusy = 0;
1018812004Sjiang.liu@intel.com 
1018912004Sjiang.liu@intel.com 	/*
1019012004Sjiang.liu@intel.com 	 * To catch device opens currently maintained on specfs common snodes.
1019112004Sjiang.liu@intel.com 	 */
1019212004Sjiang.liu@intel.com 	if (mod_hash_find(bsp->s_hash, dip, (mod_hash_val_t *)&sbusy))
1019312004Sjiang.liu@intel.com 		sbusy = 0;
1019412004Sjiang.liu@intel.com 
1019512004Sjiang.liu@intel.com #ifdef	DEBUG
1019612004Sjiang.liu@intel.com 	if (ref < sbusy || ref < dvbusy) {
1019712004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "dip(%p): sopen = %lu, dvopen = %lu "
1019812004Sjiang.liu@intel.com 		    "dip ref = %lu\n", (void *)dip, sbusy, dvbusy, ref);
1019912004Sjiang.liu@intel.com 	}
1020012004Sjiang.liu@intel.com #endif
1020112004Sjiang.liu@intel.com 
1020212004Sjiang.liu@intel.com 	dvbusy = (sbusy > dvbusy) ? sbusy : dvbusy;
1020312004Sjiang.liu@intel.com 
1020412004Sjiang.liu@intel.com 	return (bsp->callback(dip, bsp->arg, dvbusy));
1020512004Sjiang.liu@intel.com }
1020612004Sjiang.liu@intel.com 
1020712004Sjiang.liu@intel.com static int
visit_snode(struct snode * sp,void * arg)1020812004Sjiang.liu@intel.com visit_snode(struct snode *sp, void *arg)
1020912004Sjiang.liu@intel.com {
1021012004Sjiang.liu@intel.com 	uintptr_t sbusy;
1021112004Sjiang.liu@intel.com 	dev_info_t *dip;
1021212004Sjiang.liu@intel.com 	int count;
1021312004Sjiang.liu@intel.com 	struct devi_busy *bsp = arg;
1021412004Sjiang.liu@intel.com 
1021512004Sjiang.liu@intel.com 	ASSERT(sp);
1021612004Sjiang.liu@intel.com 
1021712004Sjiang.liu@intel.com 	/*
1021812004Sjiang.liu@intel.com 	 * The stable lock is held. This prevents
1021912004Sjiang.liu@intel.com 	 * the snode and its associated dip from
1022012004Sjiang.liu@intel.com 	 * going away.
1022112004Sjiang.liu@intel.com 	 */
1022212004Sjiang.liu@intel.com 	dip = NULL;
1022312004Sjiang.liu@intel.com 	count = spec_devi_open_count(sp, &dip);
1022412004Sjiang.liu@intel.com 
1022512004Sjiang.liu@intel.com 	if (count <= 0)
1022612004Sjiang.liu@intel.com 		return (DDI_WALK_CONTINUE);
1022712004Sjiang.liu@intel.com 
1022812004Sjiang.liu@intel.com 	ASSERT(dip);
1022912004Sjiang.liu@intel.com 
1023012004Sjiang.liu@intel.com 	if (mod_hash_remove(bsp->s_hash, dip, (mod_hash_val_t *)&sbusy))
1023112004Sjiang.liu@intel.com 		sbusy = count;
1023212004Sjiang.liu@intel.com 	else
1023312004Sjiang.liu@intel.com 		sbusy += count;
1023412004Sjiang.liu@intel.com 
1023512004Sjiang.liu@intel.com 	if (mod_hash_insert(bsp->s_hash, dip, (mod_hash_val_t)sbusy)) {
1023612004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "%s: s_hash insert failed: dip=0x%p, "
1023712004Sjiang.liu@intel.com 		    "sbusy = %lu", "e_ddi_branch_referenced",
1023812004Sjiang.liu@intel.com 		    (void *)dip, sbusy);
1023912004Sjiang.liu@intel.com 	}
1024012004Sjiang.liu@intel.com 
1024112004Sjiang.liu@intel.com 	bsp->s_total += count;
1024212004Sjiang.liu@intel.com 
1024312004Sjiang.liu@intel.com 	return (DDI_WALK_CONTINUE);
1024412004Sjiang.liu@intel.com }
1024512004Sjiang.liu@intel.com 
1024612004Sjiang.liu@intel.com static void
visit_dvnode(struct dv_node * dv,void * arg)1024712004Sjiang.liu@intel.com visit_dvnode(struct dv_node *dv, void *arg)
1024812004Sjiang.liu@intel.com {
1024912004Sjiang.liu@intel.com 	uintptr_t dvbusy;
1025012004Sjiang.liu@intel.com 	uint_t count;
1025112004Sjiang.liu@intel.com 	struct vnode *vp;
1025212004Sjiang.liu@intel.com 	struct devi_busy *bsp = arg;
1025312004Sjiang.liu@intel.com 
1025412004Sjiang.liu@intel.com 	ASSERT(dv && dv->dv_devi);
1025512004Sjiang.liu@intel.com 
1025612004Sjiang.liu@intel.com 	vp = DVTOV(dv);
1025712004Sjiang.liu@intel.com 
1025812004Sjiang.liu@intel.com 	mutex_enter(&vp->v_lock);
1025912004Sjiang.liu@intel.com 	count = vp->v_count;
1026012004Sjiang.liu@intel.com 	mutex_exit(&vp->v_lock);
1026112004Sjiang.liu@intel.com 
1026212004Sjiang.liu@intel.com 	if (!count)
1026312004Sjiang.liu@intel.com 		return;
1026412004Sjiang.liu@intel.com 
1026512004Sjiang.liu@intel.com 	if (mod_hash_remove(bsp->dv_hash, dv->dv_devi,
1026612004Sjiang.liu@intel.com 	    (mod_hash_val_t *)&dvbusy))
1026712004Sjiang.liu@intel.com 		dvbusy = count;
1026812004Sjiang.liu@intel.com 	else
1026912004Sjiang.liu@intel.com 		dvbusy += count;
1027012004Sjiang.liu@intel.com 
1027112004Sjiang.liu@intel.com 	if (mod_hash_insert(bsp->dv_hash, dv->dv_devi,
1027212004Sjiang.liu@intel.com 	    (mod_hash_val_t)dvbusy)) {
1027312004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "%s: dv_hash insert failed: dip=0x%p, "
1027412004Sjiang.liu@intel.com 		    "dvbusy=%lu", "e_ddi_branch_referenced",
1027512004Sjiang.liu@intel.com 		    (void *)dv->dv_devi, dvbusy);
1027612004Sjiang.liu@intel.com 	}
1027712004Sjiang.liu@intel.com 
1027812004Sjiang.liu@intel.com 	bsp->dv_total += count;
1027912004Sjiang.liu@intel.com }
1028012004Sjiang.liu@intel.com 
1028112004Sjiang.liu@intel.com /*
1028212004Sjiang.liu@intel.com  * Returns reference count on success or -1 on failure.
1028312004Sjiang.liu@intel.com  */
1028412004Sjiang.liu@intel.com int
e_ddi_branch_referenced(dev_info_t * rdip,int (* callback)(dev_info_t * dip,void * arg,uint_t ref),void * arg)1028512004Sjiang.liu@intel.com e_ddi_branch_referenced(
1028612004Sjiang.liu@intel.com 	dev_info_t *rdip,
1028712004Sjiang.liu@intel.com 	int (*callback)(dev_info_t *dip, void *arg, uint_t ref),
1028812004Sjiang.liu@intel.com 	void *arg)
1028912004Sjiang.liu@intel.com {
1029012004Sjiang.liu@intel.com 	int circ;
1029112004Sjiang.liu@intel.com 	char *path;
1029212004Sjiang.liu@intel.com 	dev_info_t *pdip;
1029312004Sjiang.liu@intel.com 	struct devi_busy bsa = {0};
1029412004Sjiang.liu@intel.com 
1029512004Sjiang.liu@intel.com 	ASSERT(rdip);
1029612004Sjiang.liu@intel.com 
1029712004Sjiang.liu@intel.com 	path = kmem_alloc(MAXPATHLEN, KM_SLEEP);
1029812004Sjiang.liu@intel.com 
1029912004Sjiang.liu@intel.com 	ndi_hold_devi(rdip);
1030012004Sjiang.liu@intel.com 
1030112004Sjiang.liu@intel.com 	pdip = ddi_get_parent(rdip);
1030212004Sjiang.liu@intel.com 
1030312004Sjiang.liu@intel.com 	ASSERT(pdip);
1030412004Sjiang.liu@intel.com 
1030512004Sjiang.liu@intel.com 	/*
1030612004Sjiang.liu@intel.com 	 * Check if caller holds pdip busy - can cause deadlocks during
1030712004Sjiang.liu@intel.com 	 * devfs_walk()
1030812004Sjiang.liu@intel.com 	 */
1030912004Sjiang.liu@intel.com 	if (!e_ddi_branch_held(rdip) || DEVI_BUSY_OWNED(pdip)) {
1031012004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "e_ddi_branch_referenced: failed: "
1031112004Sjiang.liu@intel.com 		    "devinfo branch(%p) not held or parent busy held",
1031212004Sjiang.liu@intel.com 		    (void *)rdip);
1031312004Sjiang.liu@intel.com 		ndi_rele_devi(rdip);
1031412004Sjiang.liu@intel.com 		kmem_free(path, MAXPATHLEN);
1031512004Sjiang.liu@intel.com 		return (-1);
1031612004Sjiang.liu@intel.com 	}
1031712004Sjiang.liu@intel.com 
1031812004Sjiang.liu@intel.com 	ndi_devi_enter(pdip, &circ);
1031912004Sjiang.liu@intel.com 	(void) ddi_pathname(rdip, path);
1032012004Sjiang.liu@intel.com 	ndi_devi_exit(pdip, circ);
1032112004Sjiang.liu@intel.com 
1032212004Sjiang.liu@intel.com 	bsa.dv_hash = mod_hash_create_ptrhash("dv_node busy hash", NUMCHAINS,
1032312004Sjiang.liu@intel.com 	    mod_hash_null_valdtor, sizeof (struct dev_info));
1032412004Sjiang.liu@intel.com 
1032512004Sjiang.liu@intel.com 	bsa.s_hash = mod_hash_create_ptrhash("snode busy hash", NUMCHAINS,
1032612004Sjiang.liu@intel.com 	    mod_hash_null_valdtor, sizeof (struct snode));
1032712004Sjiang.liu@intel.com 
1032812004Sjiang.liu@intel.com 	if (devfs_walk(path, visit_dvnode, &bsa)) {
1032912004Sjiang.liu@intel.com 		cmn_err(CE_WARN, "e_ddi_branch_referenced: "
1033012004Sjiang.liu@intel.com 		    "devfs walk failed for: %s", path);
1033112004Sjiang.liu@intel.com 		kmem_free(path, MAXPATHLEN);
1033212004Sjiang.liu@intel.com 		bsa.s_total = bsa.dv_total = -1;
1033312004Sjiang.liu@intel.com 		goto out;
1033412004Sjiang.liu@intel.com 	}
1033512004Sjiang.liu@intel.com 
1033612004Sjiang.liu@intel.com 	kmem_free(path, MAXPATHLEN);
1033712004Sjiang.liu@intel.com 
1033812004Sjiang.liu@intel.com 	/*
1033912004Sjiang.liu@intel.com 	 * Walk the snode table to detect device opens, which are currently
1034012004Sjiang.liu@intel.com 	 * maintained on specfs common snodes.
1034112004Sjiang.liu@intel.com 	 */
1034212004Sjiang.liu@intel.com 	spec_snode_walk(visit_snode, &bsa);
1034312004Sjiang.liu@intel.com 
1034412004Sjiang.liu@intel.com 	if (callback == NULL)
1034512004Sjiang.liu@intel.com 		goto out;
1034612004Sjiang.liu@intel.com 
1034712004Sjiang.liu@intel.com 	bsa.callback = callback;
1034812004Sjiang.liu@intel.com 	bsa.arg = arg;
1034912004Sjiang.liu@intel.com 
1035012004Sjiang.liu@intel.com 	if (visit_dip(rdip, &bsa) == DDI_WALK_CONTINUE) {
1035112004Sjiang.liu@intel.com 		ndi_devi_enter(rdip, &circ);
1035212004Sjiang.liu@intel.com 		ddi_walk_devs(ddi_get_child(rdip), visit_dip, &bsa);
1035312004Sjiang.liu@intel.com 		ndi_devi_exit(rdip, circ);
1035412004Sjiang.liu@intel.com 	}
1035512004Sjiang.liu@intel.com 
1035612004Sjiang.liu@intel.com out:
1035712004Sjiang.liu@intel.com 	ndi_rele_devi(rdip);
1035812004Sjiang.liu@intel.com 	mod_hash_destroy_ptrhash(bsa.s_hash);
1035912004Sjiang.liu@intel.com 	mod_hash_destroy_ptrhash(bsa.dv_hash);
1036012004Sjiang.liu@intel.com 	return (bsa.s_total > bsa.dv_total ? bsa.s_total : bsa.dv_total);
1036112004Sjiang.liu@intel.com }
10362