17c478bdstevel@tonic-gate/*
27c478bdstevel@tonic-gate * CDDL HEADER START
37c478bdstevel@tonic-gate *
47c478bdstevel@tonic-gate * The contents of this file are subject to the terms of the
54ab7525mrj * Common Development and Distribution License (the "License").
64ab7525mrj * You may not use this file except in compliance with the License.
77c478bdstevel@tonic-gate *
87c478bdstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bdstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
107c478bdstevel@tonic-gate * See the License for the specific language governing permissions
117c478bdstevel@tonic-gate * and limitations under the License.
127c478bdstevel@tonic-gate *
137c478bdstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
147c478bdstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bdstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
167c478bdstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
177c478bdstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bdstevel@tonic-gate *
197c478bdstevel@tonic-gate * CDDL HEADER END
207c478bdstevel@tonic-gate */
214ab7525mrj
227c478bdstevel@tonic-gate/*
234f1e984Reed * Copyright (c) 1990, 2010, Oracle and/or its affiliates. All rights reserved.
24b89e420Garrett D'Amore * Copyright 2014 Garrett D'Amore <garrett@damore.org>
257c478bdstevel@tonic-gate */
267c478bdstevel@tonic-gate
277c478bdstevel@tonic-gate#include <sys/note.h>
287c478bdstevel@tonic-gate#include <sys/types.h>
297c478bdstevel@tonic-gate#include <sys/param.h>
307c478bdstevel@tonic-gate#include <sys/systm.h>
317c478bdstevel@tonic-gate#include <sys/buf.h>
327c478bdstevel@tonic-gate#include <sys/uio.h>
337c478bdstevel@tonic-gate#include <sys/cred.h>
347c478bdstevel@tonic-gate#include <sys/poll.h>
357c478bdstevel@tonic-gate#include <sys/mman.h>
367c478bdstevel@tonic-gate#include <sys/kmem.h>
377c478bdstevel@tonic-gate#include <sys/model.h>
387c478bdstevel@tonic-gate#include <sys/file.h>
397c478bdstevel@tonic-gate#include <sys/proc.h>
407c478bdstevel@tonic-gate#include <sys/open.h>
417c478bdstevel@tonic-gate#include <sys/user.h>
427c478bdstevel@tonic-gate#include <sys/t_lock.h>
437c478bdstevel@tonic-gate#include <sys/vm.h>
447c478bdstevel@tonic-gate#include <sys/stat.h>
457c478bdstevel@tonic-gate#include <vm/hat.h>
467c478bdstevel@tonic-gate#include <vm/seg.h>
477c478bdstevel@tonic-gate#include <vm/seg_vn.h>
487c478bdstevel@tonic-gate#include <vm/seg_dev.h>
497c478bdstevel@tonic-gate#include <vm/as.h>
507c478bdstevel@tonic-gate#include <sys/cmn_err.h>
517c478bdstevel@tonic-gate#include <sys/cpuvar.h>
527c478bdstevel@tonic-gate#include <sys/debug.h>
537c478bdstevel@tonic-gate#include <sys/autoconf.h>
547c478bdstevel@tonic-gate#include <sys/sunddi.h>
557c478bdstevel@tonic-gate#include <sys/esunddi.h>
567c478bdstevel@tonic-gate#include <sys/sunndi.h>
577c478bdstevel@tonic-gate#include <sys/kstat.h>
587c478bdstevel@tonic-gate#include <sys/conf.h>
597c478bdstevel@tonic-gate#include <sys/ddi_impldefs.h>	/* include implementation structure defs */
607c478bdstevel@tonic-gate#include <sys/ndi_impldefs.h>	/* include prototypes */
61a288e5aJoshua M. Clulow#include <sys/ddi_periodic.h>
627c478bdstevel@tonic-gate#include <sys/hwconf.h>
637c478bdstevel@tonic-gate#include <sys/pathname.h>
647c478bdstevel@tonic-gate#include <sys/modctl.h>
657c478bdstevel@tonic-gate#include <sys/epm.h>
667c478bdstevel@tonic-gate#include <sys/devctl.h>
677c478bdstevel@tonic-gate#include <sys/callb.h>
687c478bdstevel@tonic-gate#include <sys/cladm.h>
697c478bdstevel@tonic-gate#include <sys/sysevent.h>
707c478bdstevel@tonic-gate#include <sys/dacf_impl.h>
717c478bdstevel@tonic-gate#include <sys/ddidevmap.h>
727c478bdstevel@tonic-gate#include <sys/bootconf.h>
737c478bdstevel@tonic-gate#include <sys/disp.h>
747c478bdstevel@tonic-gate#include <sys/atomic.h>
757c478bdstevel@tonic-gate#include <sys/promif.h>
767c478bdstevel@tonic-gate#include <sys/instance.h>
777c478bdstevel@tonic-gate#include <sys/sysevent/eventdefs.h>
787c478bdstevel@tonic-gate#include <sys/task.h>
797c478bdstevel@tonic-gate#include <sys/project.h>
807c478bdstevel@tonic-gate#include <sys/taskq.h>
817c478bdstevel@tonic-gate#include <sys/devpolicy.h>
827c478bdstevel@tonic-gate#include <sys/ctype.h>
837c478bdstevel@tonic-gate#include <net/if.h>
84c693965sl#include <sys/rctl.h>
855679c89jv#include <sys/zone.h>
86d3d5073Rafael Vanoni#include <sys/clock_impl.h>
874c06356dh#include <sys/ddi.h>
88a311483Gerry Liu#include <sys/modhash.h>
89a311483Gerry Liu#include <sys/sunldi_impl.h>
90a311483Gerry Liu#include <sys/fs/dv_node.h>
91a311483Gerry Liu#include <sys/fs/snode.h>
927c478bdstevel@tonic-gate
937c478bdstevel@tonic-gateextern	pri_t	minclsyspri;
947c478bdstevel@tonic-gate
95c693965slextern	rctl_hndl_t rc_project_locked_mem;
96c693965slextern	rctl_hndl_t rc_zone_locked_mem;
977c478bdstevel@tonic-gate
987c478bdstevel@tonic-gate#ifdef DEBUG
997c478bdstevel@tonic-gatestatic int sunddi_debug = 0;
1007c478bdstevel@tonic-gate#endif /* DEBUG */
1017c478bdstevel@tonic-gate
1027c478bdstevel@tonic-gate/* ddi_umem_unlock miscellaneous */
1037c478bdstevel@tonic-gate
1047c478bdstevel@tonic-gatestatic	void	i_ddi_umem_unlock_thread_start(void);
1057c478bdstevel@tonic-gate
1067c478bdstevel@tonic-gatestatic	kmutex_t	ddi_umem_unlock_mutex; /* unlock list mutex */
1077c478bdstevel@tonic-gatestatic	kcondvar_t	ddi_umem_unlock_cv; /* unlock list block/unblock */
1087c478bdstevel@tonic-gatestatic	kthread_t	*ddi_umem_unlock_thread;
1097c478bdstevel@tonic-gate/*
1107c478bdstevel@tonic-gate * The ddi_umem_unlock FIFO list.  NULL head pointer indicates empty list.
1117c478bdstevel@tonic-gate */
1127c478bdstevel@tonic-gatestatic	struct	ddi_umem_cookie *ddi_umem_unlock_head = NULL;
1137c478bdstevel@tonic-gatestatic	struct	ddi_umem_cookie *ddi_umem_unlock_tail = NULL;
1147c478bdstevel@tonic-gate
1157c478bdstevel@tonic-gate/*
1167c478bdstevel@tonic-gate * DDI(Sun) Function and flag definitions:
1177c478bdstevel@tonic-gate */
1187c478bdstevel@tonic-gate
1197c478bdstevel@tonic-gate#if defined(__x86)
1207c478bdstevel@tonic-gate/*
1217c478bdstevel@tonic-gate * Used to indicate which entries were chosen from a range.
1227c478bdstevel@tonic-gate */
1237c478bdstevel@tonic-gatechar	*chosen_reg = "chosen-reg";
1247c478bdstevel@tonic-gate#endif
1257c478bdstevel@tonic-gate
1267c478bdstevel@tonic-gate/*
1277c478bdstevel@tonic-gate * Function used to ring system console bell
1287c478bdstevel@tonic-gate */
1297c478bdstevel@tonic-gatevoid (*ddi_console_bell_func)(clock_t duration);
1307c478bdstevel@tonic-gate
1317c478bdstevel@tonic-gate/*
1327c478bdstevel@tonic-gate * Creating register mappings and handling interrupts:
1337c478bdstevel@tonic-gate */
1347c478bdstevel@tonic-gate
1357c478bdstevel@tonic-gate/*
1367c478bdstevel@tonic-gate * Generic ddi_map: Call parent to fulfill request...
1377c478bdstevel@tonic-gate */
1387c478bdstevel@tonic-gate
1397c478bdstevel@tonic-gateint
1407c478bdstevel@tonic-gateddi_map(dev_info_t *dp, ddi_map_req_t *mp, off_t offset,
1417c478bdstevel@tonic-gate    off_t len, caddr_t *addrp)
1427c478bdstevel@tonic-gate{
1437c478bdstevel@tonic-gate	dev_info_t *pdip;
1447c478bdstevel@tonic-gate
1457c478bdstevel@tonic-gate	ASSERT(dp);
1467c478bdstevel@tonic-gate	pdip = (dev_info_t *)DEVI(dp)->devi_parent;
1477c478bdstevel@tonic-gate	return ((DEVI(pdip)->devi_ops->devo_bus_ops->bus_map)(pdip,
1487c478bdstevel@tonic-gate	    dp, mp, offset, len, addrp));
1497c478bdstevel@tonic-gate}
1507c478bdstevel@tonic-gate
1517c478bdstevel@tonic-gate/*
1527c478bdstevel@tonic-gate * ddi_apply_range: (Called by nexi only.)
1537c478bdstevel@tonic-gate * Apply ranges in parent node dp, to child regspec rp...
1547c478bdstevel@tonic-gate */
1557c478bdstevel@tonic-gate
1567c478bdstevel@tonic-gateint
1577c478bdstevel@tonic-gateddi_apply_range(dev_info_t *dp, dev_info_t *rdip, struct regspec *rp)
1587c478bdstevel@tonic-gate{
1597c478bdstevel@tonic-gate	return (i_ddi_apply_range(dp, rdip, rp));
1607c478bdstevel@tonic-gate}
1617c478bdstevel@tonic-gate
1627c478bdstevel@tonic-gateint
1637c478bdstevel@tonic-gateddi_map_regs(dev_info_t *dip, uint_t rnumber, caddr_t *kaddrp, off_t offset,
1647c478bdstevel@tonic-gate    off_t len)
1657c478bdstevel@tonic-gate{
1667c478bdstevel@tonic-gate	ddi_map_req_t mr;
1677c478bdstevel@tonic-gate#if defined(__x86)
1687c478bdstevel@tonic-gate	struct {
1697c478bdstevel@tonic-gate		int	bus;
1707c478bdstevel@tonic-gate		int	addr;
1717c478bdstevel@tonic-gate		int	size;
1727c478bdstevel@tonic-gate	} reg, *reglist;
1737c478bdstevel@tonic-gate	uint_t	length;
1747c478bdstevel@tonic-gate	int	rc;
1757c478bdstevel@tonic-gate
1767c478bdstevel@tonic-gate	/*
1777c478bdstevel@tonic-gate	 * get the 'registers' or the 'reg' property.
1787c478bdstevel@tonic-gate	 * We look up the reg property as an array of
1797c478bdstevel@tonic-gate	 * int's.
1807c478bdstevel@tonic-gate	 */
1817c478bdstevel@tonic-gate	rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
1827c478bdstevel@tonic-gate	    DDI_PROP_DONTPASS, "registers", (int **)&reglist, &length);
1837c478bdstevel@tonic-gate	if (rc != DDI_PROP_SUCCESS)
1847c478bdstevel@tonic-gate		rc = ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip,
1857c478bdstevel@tonic-gate		    DDI_PROP_DONTPASS, "reg", (int **)&reglist, &length);
1867c478bdstevel@tonic-gate	if (rc == DDI_PROP_SUCCESS) {
1877c478bdstevel@tonic-gate		/*
1887c478bdstevel@tonic-gate		 * point to the required entry.
1897c478bdstevel@tonic-gate		 */
1907c478bdstevel@tonic-gate		reg = reglist[rnumber];
1917c478bdstevel@tonic-gate		reg.addr += offset;
1927c478bdstevel@tonic-gate		if (len != 0)
1937c478bdstevel@tonic-gate			reg.size = len;
1947c478bdstevel@tonic-gate		/*
1957c478bdstevel@tonic-gate		 * make a new property containing ONLY the required tuple.
1967c478bdstevel@tonic-gate		 */
1977c478bdstevel@tonic-gate		if (ddi_prop_update_int_array(DDI_DEV_T_NONE, dip,
1987c478bdstevel@tonic-gate		    chosen_reg, (int *)&reg, (sizeof (reg)/sizeof (int)))
1997c478bdstevel@tonic-gate		    != DDI_PROP_SUCCESS) {
2007c478bdstevel@tonic-gate			cmn_err(CE_WARN, "%s%d: cannot create '%s' "
2017c478bdstevel@tonic-gate			    "property", DEVI(dip)->devi_name,
2027c478bdstevel@tonic-gate			    DEVI(dip)->devi_instance, chosen_reg);
2037c478bdstevel@tonic-gate		}
2047c478bdstevel@tonic-gate		/*
2057c478bdstevel@tonic-gate		 * free the memory allocated by
2067c478bdstevel@tonic-gate		 * ddi_prop_lookup_int_array ().
2077c478bdstevel@tonic-gate		 */
2087c478bdstevel@tonic-gate		ddi_prop_free((void *)reglist);
2097c478bdstevel@tonic-gate	}
2107c478bdstevel@tonic-gate#endif
2117c478bdstevel@tonic-gate	mr.map_op = DDI_MO_MAP_LOCKED;
2127c478bdstevel@tonic-gate	mr.map_type = DDI_MT_RNUMBER;
2137c478bdstevel@tonic-gate	mr.map_obj.rnumber = rnumber;
2147c478bdstevel@tonic-gate	mr.map_prot = PROT_READ | PROT_WRITE;
2157c478bdstevel@tonic-gate	mr.map_flags = DDI_MF_KERNEL_MAPPING;
2167c478bdstevel@tonic-gate	mr.map_handlep = NULL;
2177c478bdstevel@tonic-gate	mr.map_vers = DDI_MAP_VERSION;
2187c478bdstevel@tonic-gate
2197c478bdstevel@tonic-gate	/*
2207c478bdstevel@tonic-gate	 * Call my parent to map in my regs.
2217c478bdstevel@tonic-gate	 */
2227c478bdstevel@tonic-gate
2237c478bdstevel@tonic-gate	return (ddi_map(dip, &mr, offset, len, kaddrp));
2247c478bdstevel@tonic-gate}
2257c478bdstevel@tonic-gate
2267c478bdstevel@tonic-gatevoid
2277c478bdstevel@tonic-gateddi_unmap_regs(dev_info_t *dip, uint_t rnumber, caddr_t *kaddrp, off_t offset,
2287c478bdstevel@tonic-gate    off_t len)
2297c478bdstevel@tonic-gate{
2307c478bdstevel@tonic-gate	ddi_map_req_t mr;
2317c478bdstevel@tonic-gate
2327c478bdstevel@tonic-gate	mr.map_op = DDI_MO_UNMAP;
2337c478bdstevel@tonic-gate	mr.map_type = DDI_MT_RNUMBER;
2347c478bdstevel@tonic-gate	mr.map_flags = DDI_MF_KERNEL_MAPPING;
2357c478bdstevel@tonic-gate	mr.map_prot = PROT_READ | PROT_WRITE;	/* who cares? */
2367c478bdstevel@tonic-gate	mr.map_obj.rnumber = rnumber;
2377c478bdstevel@tonic-gate	mr.map_handlep = NULL;
2387c478bdstevel@tonic-gate	mr.map_vers = DDI_MAP_VERSION;
2397c478bdstevel@tonic-gate
2407c478bdstevel@tonic-gate	/*
2417c478bdstevel@tonic-gate	 * Call my parent to unmap my regs.
2427c478bdstevel@tonic-gate	 */
2437c478bdstevel@tonic-gate
2447c478bdstevel@tonic-gate	(void) ddi_map(dip, &mr, offset, len, kaddrp);
2457c478bdstevel@tonic-gate	*kaddrp = (caddr_t)0;
2467c478bdstevel@tonic-gate#if defined(__x86)
2477c478bdstevel@tonic-gate	(void) ddi_prop_remove(DDI_DEV_T_NONE, dip, chosen_reg);
2487c478bdstevel@tonic-gate#endif
2497c478bdstevel@tonic-gate}
2507c478bdstevel@tonic-gate
2517c478bdstevel@tonic-gateint
2527c478bdstevel@tonic-gateddi_bus_map(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
2537c478bdstevel@tonic-gate	off_t offset, off_t len, caddr_t *vaddrp)
2547c478bdstevel@tonic-gate{
2557c478bdstevel@tonic-gate	return (i_ddi_bus_map(dip, rdip, mp, offset, len, vaddrp));
2567c478bdstevel@tonic-gate}
2577c478bdstevel@tonic-gate
2587c478bdstevel@tonic-gate/*
2597c478bdstevel@tonic-gate * nullbusmap:	The/DDI default bus_map entry point for nexi
2607c478bdstevel@tonic-gate *		not conforming to the reg/range paradigm (i.e. scsi, etc.)
2617c478bdstevel@tonic-gate *		with no HAT/MMU layer to be programmed at this level.
2627c478bdstevel@tonic-gate *
2637c478bdstevel@tonic-gate *		If the call is to map by rnumber, return an error,
2647c478bdstevel@tonic-gate *		otherwise pass anything else up the tree to my parent.
2657c478bdstevel@tonic-gate */
2667c478bdstevel@tonic-gateint
2677c478bdstevel@tonic-gatenullbusmap(dev_info_t *dip, dev_info_t *rdip, ddi_map_req_t *mp,
2687c478bdstevel@tonic-gate	off_t offset, off_t len, caddr_t *vaddrp)
2697c478bdstevel@tonic-gate{
2707c478bdstevel@tonic-gate	_NOTE(ARGUNUSED(rdip))
2717c478bdstevel@tonic-gate	if (mp->map_type == DDI_MT_RNUMBER)
2727c478bdstevel@tonic-gate		return (DDI_ME_UNSUPPORTED);
2737c478bdstevel@tonic-gate
2747c478bdstevel@tonic-gate	return (ddi_map(dip, mp, offset, len, vaddrp));
2757c478bdstevel@tonic-gate}
2767c478bdstevel@tonic-gate
2777c478bdstevel@tonic-gate/*
2787c478bdstevel@tonic-gate * ddi_rnumber_to_regspec: Not for use by leaf drivers.
2797c478bdstevel@tonic-gate *			   Only for use by nexi using the reg/range paradigm.
2807c478bdstevel@tonic-gate */
2817c478bdstevel@tonic-gatestruct regspec *
2827c478bdstevel@tonic-gateddi_rnumber_to_regspec(dev_info_t *dip, int rnumber)
2837c478bdstevel@tonic-gate{
2847c478bdstevel@tonic-gate	return (i_ddi_rnumber_to_regspec(dip, rnumber));
2857c478bdstevel@tonic-gate}
2867c478bdstevel@tonic-gate
2877c478bdstevel@tonic-gate
2887c478bdstevel@tonic-gate/*
2897c478bdstevel@tonic-gate * Note that we allow the dip to be nil because we may be called
2907c478bdstevel@tonic-gate * prior even to the instantiation of the devinfo tree itself - all
2917c478bdstevel@tonic-gate * regular leaf and nexus drivers should always use a non-nil dip!
2927c478bdstevel@tonic-gate *
2937c478bdstevel@tonic-gate * We treat peek in a somewhat cavalier fashion .. assuming that we'll
2947c478bdstevel@tonic-gate * simply get a synchronous fault as soon as we touch a missing address.
2957c478bdstevel@tonic-gate *
2967c478bdstevel@tonic-gate * Poke is rather more carefully handled because we might poke to a write
2977c478bdstevel@tonic-gate * buffer, "succeed", then only find some time later that we got an
2987c478bdstevel@tonic-gate * asynchronous fault that indicated that the address we were writing to
2997c478bdstevel@tonic-gate * was not really backed by hardware.
3007c478bdstevel@tonic-gate */
3017c478bdstevel@tonic-gate
3027c478bdstevel@tonic-gatestatic int
3037c478bdstevel@tonic-gatei_ddi_peekpoke(dev_info_t *devi, ddi_ctl_enum_t cmd, size_t size,
3047c478bdstevel@tonic-gate    void *addr, void *value_p)
3057c478bdstevel@tonic-gate{
3067c478bdstevel@tonic-gate	union {
3077c478bdstevel@tonic-gate		uint64_t	u64;
3087c478bdstevel@tonic-gate		uint32_t	u32;
3097c478bdstevel@tonic-gate		uint16_t	u16;
3107c478bdstevel@tonic-gate		uint8_t		u8;
3117c478bdstevel@tonic-gate	} peekpoke_value;
3127c478bdstevel@tonic-gate
3137c478bdstevel@tonic-gate	peekpoke_ctlops_t peekpoke_args;
3147c478bdstevel@tonic-gate	uint64_t dummy_result;
3157c478bdstevel@tonic-gate	int rval;
3167c478bdstevel@tonic-gate
3177c478bdstevel@tonic-gate	/* Note: size is assumed to be correct;  it is not checked. */
3187c478bdstevel@tonic-gate	peekpoke_args.size = size;
319abdbd06agiri	peekpoke_args.dev_addr = (uintptr_t)addr;
3207c478bdstevel@tonic-gate	peekpoke_args.handle = NULL;
3217c478bdstevel@tonic-gate	peekpoke_args.repcount = 1;
3227c478bdstevel@tonic-gate	peekpoke_args.flags = 0;
3237c478bdstevel@tonic-gate
3247c478bdstevel@tonic-gate	if (cmd == DDI_CTLOPS_POKE) {
3257c478bdstevel@tonic-gate		switch (size) {
3267c478bdstevel@tonic-gate		case sizeof (uint8_t):
3277c478bdstevel@tonic-gate			peekpoke_value.u8 = *(uint8_t *)value_p;
3287c478bdstevel@tonic-gate			break;
3297c478bdstevel@tonic-gate		case sizeof (uint16_t):
3307c478bdstevel@tonic-gate			peekpoke_value.u16 = *(uint16_t *)value_p;
3317c478bdstevel@tonic-gate			break;
3327c478bdstevel@tonic-gate		case sizeof (uint32_t):
3337c478bdstevel@tonic-gate			peekpoke_value.u32 = *(uint32_t *)value_p;
3347c478bdstevel@tonic-gate			break;
3357c478bdstevel@tonic-gate		case sizeof (uint64_t):
3367c478bdstevel@tonic-gate			peekpoke_value.u64 = *(uint64_t *)value_p;
3377c478bdstevel@tonic-gate			break;
3387c478bdstevel@tonic-gate		}
3397c478bdstevel@tonic-gate	}
3407c478bdstevel@tonic-gate
341abdbd06agiri	peekpoke_args.host_addr = (uintptr_t)&peekpoke_value.u64;
3427c478bdstevel@tonic-gate
3437c478bdstevel@tonic-gate	if (devi != NULL)
3447c478bdstevel@tonic-gate		rval = ddi_ctlops(devi, devi, cmd, &peekpoke_args,
3457c478bdstevel@tonic-gate		    &dummy_result);
3467c478bdstevel@tonic-gate	else
3477c478bdstevel@tonic-gate		rval = peekpoke_mem(cmd, &peekpoke_args);
3487c478bdstevel@tonic-gate
3497c478bdstevel@tonic-gate	/*
3507c478bdstevel@tonic-gate	 * A NULL value_p is permitted by ddi_peek(9F); discard the result.
3517c478bdstevel@tonic-gate	 */
3527c478bdstevel@tonic-gate	if ((cmd == DDI_CTLOPS_PEEK) & (value_p != NULL)) {
3537c478bdstevel@tonic-gate		switch (size) {
3547c478bdstevel@tonic-gate		case sizeof (uint8_t):
3557c478bdstevel@tonic-gate			*(uint8_t *)value_p = peekpoke_value.u8;
3567c478bdstevel@tonic-gate			break;
3577c478bdstevel@tonic-gate		case sizeof (uint16_t):
3587c478bdstevel@tonic-gate			*(uint16_t *)value_p = peekpoke_value.u16;
3597c478bdstevel@tonic-gate			break;
3607c478bdstevel@tonic-gate		case sizeof (uint32_t):
3617c478bdstevel@tonic-gate			*(uint32_t *)value_p = peekpoke_value.u32;
3627c478bdstevel@tonic-gate			break;
3637c478bdstevel@tonic-gate		case sizeof (uint64_t):
3647c478bdstevel@tonic-gate			*(uint64_t *)value_p = peekpoke_value.u64;
3657c478bdstevel@tonic-gate			break;
3667c478bdstevel@tonic-gate		}
3677c478bdstevel@tonic-gate	}
3687c478bdstevel@tonic-gate
3697c478bdstevel@tonic-gate	return (rval);
3707c478bdstevel@tonic-gate}
3717c478bdstevel@tonic-gate
3727c478bdstevel@tonic-gate/*
3737c478bdstevel@tonic-gate * Keep ddi_peek() and ddi_poke() in case 3rd parties are calling this.
3747c478bdstevel@tonic-gate * they shouldn't be, but the 9f manpage kind of pseudo exposes it.
3757c478bdstevel@tonic-gate */
3767c478bdstevel@tonic-gateint
3777c478bdstevel@tonic-gateddi_peek(dev_info_t *devi, size_t size, void *addr, void *value_p)
3787c478bdstevel@tonic-gate{
3797c478bdstevel@tonic-gate	switch (size) {
3807c478bdstevel@tonic-gate	case sizeof (uint8_t):
3817c478bdstevel@tonic-gate	case sizeof (uint16_t):
3827c478bdstevel@tonic-gate	case sizeof (uint32_t):
3837c478bdstevel@tonic-gate	case sizeof (uint64_t):
3847c478bdstevel@tonic-gate		break;
3857c478bdstevel@tonic-gate	default:
3867c478bdstevel@tonic-gate		return (DDI_FAILURE);
3877c478bdstevel@tonic-gate	}
3887c478bdstevel@tonic-gate
3897c478bdstevel@tonic-gate	return (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, size, addr, value_p));
3907c478bdstevel@tonic-gate}
3917c478bdstevel@tonic-gate
3927c478bdstevel@tonic-gateint
3937c478bdstevel@tonic-gateddi_poke(dev_info_t *devi, size_t size, void *addr, void *value_p)
3947c478bdstevel@tonic-gate{
3957c478bdstevel@tonic-gate	switch (size) {
3967c478bdstevel@tonic-gate	case sizeof (uint8_t):
3977c478bdstevel@tonic-gate	case sizeof (uint16_t):
3987c478bdstevel@tonic-gate	case sizeof (uint32_t):
3997c478bdstevel@tonic-gate	case sizeof (uint64_t):
4007c478bdstevel@tonic-gate		break;
4017c478bdstevel@tonic-gate	default:
4027c478bdstevel@tonic-gate		return (DDI_FAILURE);
4037c478bdstevel@tonic-gate	}
4047c478bdstevel@tonic-gate
4057c478bdstevel@tonic-gate	return (i_ddi_peekpoke(devi, DDI_CTLOPS_POKE, size, addr, value_p));
4067c478bdstevel@tonic-gate}
4077c478bdstevel@tonic-gate
4087c478bdstevel@tonic-gateint
4097c478bdstevel@tonic-gateddi_peek8(dev_info_t *dip, int8_t *addr, int8_t *val_p)
4107c478bdstevel@tonic-gate{
4117c478bdstevel@tonic-gate	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4127c478bdstevel@tonic-gate	    val_p));
4137c478bdstevel@tonic-gate}
4147c478bdstevel@tonic-gate
4157c478bdstevel@tonic-gateint
4167c478bdstevel@tonic-gateddi_peek16(dev_info_t *dip, int16_t *addr, int16_t *val_p)
4177c478bdstevel@tonic-gate{
4187c478bdstevel@tonic-gate	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4197c478bdstevel@tonic-gate	    val_p));
4207c478bdstevel@tonic-gate}
4217c478bdstevel@tonic-gate
4227c478bdstevel@tonic-gateint
4237c478bdstevel@tonic-gateddi_peek32(dev_info_t *dip, int32_t *addr, int32_t *val_p)
4247c478bdstevel@tonic-gate{
4257c478bdstevel@tonic-gate	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4267c478bdstevel@tonic-gate	    val_p));
4277c478bdstevel@tonic-gate}
4287c478bdstevel@tonic-gate
4297c478bdstevel@tonic-gateint
4307c478bdstevel@tonic-gateddi_peek64(dev_info_t *dip, int64_t *addr, int64_t *val_p)
4314ab7525mrj{
4324ab7525mrj	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4334ab7525mrj	    val_p));
4344ab7525mrj}
4354ab7525mrj
4364ab7525mrj
4374ab7525mrj/*
4384ab7525mrj * We need to separate the old interfaces from the new ones and leave them
4394ab7525mrj * in here for a while. Previous versions of the OS defined the new interfaces
4404ab7525mrj * to the old interfaces. This way we can fix things up so that we can
4414ab7525mrj * eventually remove these interfaces.
4424ab7525mrj * e.g. A 3rd party module/driver using ddi_peek8 and built against S10
4434ab7525mrj * or earlier will actually have a reference to ddi_peekc in the binary.
4444ab7525mrj */
4454ab7525mrj#ifdef _ILP32
4464ab7525mrjint
4474ab7525mrjddi_peekc(dev_info_t *dip, int8_t *addr, int8_t *val_p)
4484ab7525mrj{
4494ab7525mrj	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4504ab7525mrj	    val_p));
4514ab7525mrj}
4524ab7525mrj
4534ab7525mrjint
4544ab7525mrjddi_peeks(dev_info_t *dip, int16_t *addr, int16_t *val_p)
4554ab7525mrj{
4564ab7525mrj	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4574ab7525mrj	    val_p));
4584ab7525mrj}
4594ab7525mrj
4604ab7525mrjint
4614ab7525mrjddi_peekl(dev_info_t *dip, int32_t *addr, int32_t *val_p)
4624ab7525mrj{
4634ab7525mrj	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4644ab7525mrj	    val_p));
4654ab7525mrj}
4664ab7525mrj
4677c478bdstevel@tonic-gateint
4687c478bdstevel@tonic-gateddi_peekd(dev_info_t *dip, int64_t *addr, int64_t *val_p)
4697c478bdstevel@tonic-gate{
4707c478bdstevel@tonic-gate	return (i_ddi_peekpoke(dip, DDI_CTLOPS_PEEK, sizeof (*val_p), addr,
4717c478bdstevel@tonic-gate	    val_p));
4727c478bdstevel@tonic-gate}
4734ab7525mrj#endif /* _ILP32 */
4747c478bdstevel@tonic-gate
4757c478bdstevel@tonic-gateint
4767c478bdstevel@tonic-gateddi_poke8(dev_info_t *dip, int8_t *addr, int8_t val)
4777c478bdstevel@tonic-gate{
4787c478bdstevel@tonic-gate	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
4797c478bdstevel@tonic-gate}
4807c478bdstevel@tonic-gate
4817c478bdstevel@tonic-gateint
4827c478bdstevel@tonic-gateddi_poke16(dev_info_t *dip, int16_t *addr, int16_t val)
4837c478bdstevel@tonic-gate{
4847c478bdstevel@tonic-gate	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
4857c478bdstevel@tonic-gate}
4867c478bdstevel@tonic-gate
4877c478bdstevel@tonic-gateint
4887c478bdstevel@tonic-gateddi_poke32(dev_info_t *dip, int32_t *addr, int32_t val)
4897c478bdstevel@tonic-gate{
4907c478bdstevel@tonic-gate	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
4917c478bdstevel@tonic-gate}
4927c478bdstevel@tonic-gate
4937c478bdstevel@tonic-gateint
4947c478bdstevel@tonic-gateddi_poke64(dev_info_t *dip, int64_t *addr, int64_t val)
4954ab7525mrj{
4964ab7525mrj	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
4974ab7525mrj}
4984ab7525mrj
4994ab7525mrj/*
5004ab7525mrj * We need to separate the old interfaces from the new ones and leave them
5014ab7525mrj * in here for a while. Previous versions of the OS defined the new interfaces
5024ab7525mrj * to the old interfaces. This way we can fix things up so that we can
5034ab7525mrj * eventually remove these interfaces.
5044ab7525mrj * e.g. A 3rd party module/driver using ddi_poke8 and built against S10
5054ab7525mrj * or earlier will actually have a reference to ddi_pokec in the binary.
5064ab7525mrj */
5074ab7525mrj#ifdef _ILP32
5084ab7525mrjint
5094ab7525mrjddi_pokec(dev_info_t *dip, int8_t *addr, int8_t val)
5104ab7525mrj{
5114ab7525mrj	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
5124ab7525mrj}
5134ab7525mrj
5144ab7525mrjint
5154ab7525mrjddi_pokes(dev_info_t *dip, int16_t *addr, int16_t val)
5164ab7525mrj{
5174ab7525mrj	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
5184ab7525mrj}
5194ab7525mrj
5204ab7525mrjint
5214ab7525mrjddi_pokel(dev_info_t *dip, int32_t *addr, int32_t val)
5224ab7525mrj{
5234ab7525mrj	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
5244ab7525mrj}
5254ab7525mrj
5267c478bdstevel@tonic-gateint
5277c478bdstevel@tonic-gateddi_poked(dev_info_t *dip, int64_t *addr, int64_t val)
5287c478bdstevel@tonic-gate{
5297c478bdstevel@tonic-gate	return (i_ddi_peekpoke(dip, DDI_CTLOPS_POKE, sizeof (val), addr, &val));
5307c478bdstevel@tonic-gate}
5314ab7525mrj#endif /* _ILP32 */
5327c478bdstevel@tonic-gate
5337c478bdstevel@tonic-gate/*
5347c478bdstevel@tonic-gate * ddi_peekpokeio() is used primarily by the mem drivers for moving
5357c478bdstevel@tonic-gate * data to and from uio structures via peek and poke.  Note that we
5367c478bdstevel@tonic-gate * use "internal" routines ddi_peek and ddi_poke to make this go
5377c478bdstevel@tonic-gate * slightly faster, avoiding the call overhead ..
5387c478bdstevel@tonic-gate */
5397c478bdstevel@tonic-gateint
5407c478bdstevel@tonic-gateddi_peekpokeio(dev_info_t *devi, struct uio *uio, enum uio_rw rw,
5417c478bdstevel@tonic-gate    caddr_t addr, size_t len, uint_t xfersize)
5427c478bdstevel@tonic-gate{
5437c478bdstevel@tonic-gate	int64_t	ibuffer;
5447c478bdstevel@tonic-gate	int8_t w8;
5457c478bdstevel@tonic-gate	size_t sz;
5467c478bdstevel@tonic-gate	int o;
5477c478bdstevel@tonic-gate
5487c478bdstevel@tonic-gate	if (xfersize > sizeof (long))
5497c478bdstevel@tonic-gate		xfersize = sizeof (long);
5507c478bdstevel@tonic-gate
5517c478bdstevel@tonic-gate	while (len != 0) {
5527c478bdstevel@tonic-gate		if ((len | (uintptr_t)addr) & 1) {
5537c478bdstevel@tonic-gate			sz = sizeof (int8_t);
5547c478bdstevel@tonic-gate			if (rw == UIO_WRITE) {
5557c478bdstevel@tonic-gate				if ((o = uwritec(uio)) == -1)
5567c478bdstevel@tonic-gate					return (DDI_FAILURE);
5577c478bdstevel@tonic-gate				if (ddi_poke8(devi, (int8_t *)addr,
5587c478bdstevel@tonic-gate				    (int8_t)o) != DDI_SUCCESS)
5597c478bdstevel@tonic-gate					return (DDI_FAILURE);
5607c478bdstevel@tonic-gate			} else {
5617c478bdstevel@tonic-gate				if (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, sz,
5627c478bdstevel@tonic-gate				    (int8_t *)addr, &w8) != DDI_SUCCESS)
5637c478bdstevel@tonic-gate					return (DDI_FAILURE);
5647c478bdstevel@tonic-gate				if (ureadc(w8, uio))
5657c478bdstevel@tonic-gate					return (DDI_FAILURE);
5667c478bdstevel@tonic-gate			}
5677c478bdstevel@tonic-gate		} else {
5687c478bdstevel@tonic-gate			switch (xfersize) {
5697c478bdstevel@tonic-gate			case sizeof (int64_t):
5707c478bdstevel@tonic-gate				if (((len | (uintptr_t)addr) &
5717c478bdstevel@tonic-gate				    (sizeof (int64_t) - 1)) == 0) {
5727c478bdstevel@tonic-gate					sz = xfersize;
5737c478bdstevel@tonic-gate					break;
5747c478bdstevel@tonic-gate				}
5757c478bdstevel@tonic-gate				/*FALLTHROUGH*/
5767c478bdstevel@tonic-gate			case sizeof (int32_t):
5777c478bdstevel@tonic-gate				if (((len | (uintptr_t)addr) &
5787c478bdstevel@tonic-gate				    (sizeof (int32_t) - 1)) == 0) {
5797c478bdstevel@tonic-gate					sz = xfersize;
5807c478bdstevel@tonic-gate					break;
5817c478bdstevel@tonic-gate				}
5827c478bdstevel@tonic-gate				/*FALLTHROUGH*/
5837c478bdstevel@tonic-gate			default:
5847c478bdstevel@tonic-gate				/*
5857c478bdstevel@tonic-gate				 * This still assumes that we might have an
5867c478bdstevel@tonic-gate				 * I/O bus out there that permits 16-bit
5877c478bdstevel@tonic-gate				 * transfers (and that it would be upset by
5887c478bdstevel@tonic-gate				 * 32-bit transfers from such locations).
5897c478bdstevel@tonic-gate				 */
5907c478bdstevel@tonic-gate				sz = sizeof (int16_t);
5917c478bdstevel@tonic-gate				break;
5927c478bdstevel@tonic-gate			}
5937c478bdstevel@tonic-gate
5947c478bdstevel@tonic-gate			if (rw == UIO_READ) {
5957c478bdstevel@tonic-gate				if (i_ddi_peekpoke(devi, DDI_CTLOPS_PEEK, sz,
5967c478bdstevel@tonic-gate				    addr, &ibuffer) != DDI_SUCCESS)
5977c478bdstevel@tonic-gate					return (DDI_FAILURE);
5987c478bdstevel@tonic-gate			}
5997c478bdstevel@tonic-gate
6007c478bdstevel@tonic-gate			if (uiomove(&ibuffer, sz, rw, uio))
6017c478bdstevel@tonic-gate				return (DDI_FAILURE);
6027c478bdstevel@tonic-gate
6037c478bdstevel@tonic-gate			if (rw == UIO_WRITE) {
6047c478bdstevel@tonic-gate				if (i_ddi_peekpoke(devi, DDI_CTLOPS_POKE, sz,
6057c478bdstevel@tonic-gate				    addr, &ibuffer) != DDI_SUCCESS)
6067c478bdstevel@tonic-gate					return (DDI_FAILURE);
6077c478bdstevel@tonic-gate			}
6087c478bdstevel@tonic-gate		}
6097c478bdstevel@tonic-gate		addr += sz;
6107c478bdstevel@tonic-gate		len -= sz;
6117c478bdstevel@tonic-gate	}
6127c478bdstevel@tonic-gate	return (DDI_SUCCESS);
6137c478bdstevel@tonic-gate}
6147c478bdstevel@tonic-gate
6157c478bdstevel@tonic-gate/*
6167c478bdstevel@tonic-gate * These routines are used by drivers that do layered ioctls
6177c478bdstevel@tonic-gate * On sparc, they're implemented in assembler to avoid spilling
6187c478bdstevel@tonic-gate * register windows in the common (copyin) case ..
6197c478bdstevel@tonic-gate */
6207c478bdstevel@tonic-gate#if !defined(__sparc)
6217c478bdstevel@tonic-gateint
6227c478bdstevel@tonic-gateddi_copyin(const void *buf, void *kernbuf, size_t size, int flags)
6237c478bdstevel@tonic-gate{
6247c478bdstevel@tonic-gate	if (flags & FKIOCTL)
6257c478bdstevel@tonic-gate		return (kcopy(buf, kernbuf, size) ? -1 : 0);
6267c478bdstevel@tonic-gate	return (copyin(buf, kernbuf, size));
6277c478bdstevel@tonic-gate}
6287c478bdstevel@tonic-gate
6297c478bdstevel@tonic-gateint
6307c478bdstevel@tonic-gateddi_copyout(const void *buf, void *kernbuf, size_t size, int flags)
6317c478bdstevel@tonic-gate{
6327c478bdstevel@tonic-gate	if (flags & FKIOCTL)
6337c478bdstevel@tonic-gate		return (kcopy(buf, kernbuf, size) ? -1 : 0);
6347c478bdstevel@tonic-gate	return (copyout(buf, kernbuf, size));
6357c478bdstevel@tonic-gate}
6367c478bdstevel@tonic-gate#endif	/* !__sparc */
6377c478bdstevel@tonic-gate
6387c478bdstevel@tonic-gate/*
6397c478bdstevel@tonic-gate * Conversions in nexus pagesize units.  We don't duplicate the
6407c478bdstevel@tonic-gate * 'nil dip' semantics of peek/poke because btopr/btop/ptob are DDI/DKI
6417c478bdstevel@tonic-gate * routines anyway.
6427c478bdstevel@tonic-gate */
6437c478bdstevel@tonic-gateunsigned long
6447c478bdstevel@tonic-gateddi_btop(dev_info_t *dip, unsigned long bytes)
6457c478bdstevel@tonic-gate{
6467c478bdstevel@tonic-gate	unsigned long pages;
6477c478bdstevel@tonic-gate
6487c478bdstevel@tonic-gate	(void) ddi_ctlops(dip, dip, DDI_CTLOPS_BTOP, &bytes, &pages);
6497c478bdstevel@tonic-gate	return (pages);
6507c478bdstevel@tonic-gate}
6517c478bdstevel@tonic-gate
6527c478bdstevel@tonic-gateunsigned long
6537c478bdstevel@tonic-gateddi_btopr(dev_info_t *dip, unsigned long bytes)
6547c478bdstevel@tonic-gate{
6557c478bdstevel@tonic-gate	unsigned long pages;
6567c478bdstevel@tonic-gate
6577c478bdstevel@tonic-gate	(void) ddi_ctlops(dip, dip, DDI_CTLOPS_BTOPR, &bytes, &pages);
6587c478bdstevel@tonic-gate	return (pages);
6597c478bdstevel@tonic-gate}
6607c478bdstevel@tonic-gate
6617c478bdstevel@tonic-gateunsigned long
6627c478bdstevel@tonic-gateddi_ptob(dev_info_t *dip, unsigned long pages)
6637c478bdstevel@tonic-gate{
6647c478bdstevel@tonic-gate	unsigned long bytes;
6657c478bdstevel@tonic-gate
6667c478bdstevel@tonic-gate	(void) ddi_ctlops(dip, dip, DDI_CTLOPS_PTOB, &pages, &bytes);
6677c478bdstevel@tonic-gate	return (bytes);
6687c478bdstevel@tonic-gate}
6697c478bdstevel@tonic-gate
6707c478bdstevel@tonic-gateunsigned int
6717c478bdstevel@tonic-gateddi_enter_critical(void)
6727c478bdstevel@tonic-gate{
6737c478bdstevel@tonic-gate	return ((uint_t)spl7());
6747c478bdstevel@tonic-gate}
6757c478bdstevel@tonic-gate
6767c478bdstevel@tonic-gatevoid
6777c478bdstevel@tonic-gateddi_exit_critical(unsigned int spl)
6787c478bdstevel@tonic-gate{
6797c478bdstevel@tonic-gate	splx((int)spl);
6807c478bdstevel@tonic-gate}
6817c478bdstevel@tonic-gate
6827c478bdstevel@tonic-gate/*
6837c478bdstevel@tonic-gate * Nexus ctlops punter
6847c478bdstevel@tonic-gate */
6857c478bdstevel@tonic-gate
6867c478bdstevel@tonic-gate#if !defined(__sparc)
6877c478bdstevel@tonic-gate/*
6887c478bdstevel@tonic-gate * Request bus_ctl parent to handle a bus_ctl request
6897c478bdstevel@tonic-gate *
6907c478bdstevel@tonic-gate * (The sparc version is in sparc_ddi.s)
6917c478bdstevel@tonic-gate */
6927c478bdstevel@tonic-gateint
6937c478bdstevel@tonic-gateddi_ctlops(dev_info_t *d, dev_info_t *r, ddi_ctl_enum_t op, void *a, void *v)
6947c478bdstevel@tonic-gate{
6957c478bdstevel@tonic-gate	int (*fp)();
6967c478bdstevel@tonic-gate
6977c478bdstevel@tonic-gate	if (!d || !r)
6987c478bdstevel@tonic-gate		return (DDI_FAILURE);
6997c478bdstevel@tonic-gate
7007c478bdstevel@tonic-gate	if ((d = (dev_info_t *)DEVI(d)->devi_bus_ctl) == NULL)
7017c478bdstevel@tonic-gate		return (DDI_FAILURE);
7027c478bdstevel@tonic-gate
7037c478bdstevel@tonic-gate	fp = DEVI(d)->devi_ops->devo_bus_ops->bus_ctl;
7047c478bdstevel@tonic-gate	return ((*fp)(d, r, op, a, v));
7057c478bdstevel@tonic-gate}
7067c478bdstevel@tonic-gate
7077c478bdstevel@tonic-gate#endif
7087c478bdstevel@tonic-gate
7097c478bdstevel@tonic-gate/*
7107c478bdstevel@tonic-gate * DMA/DVMA setup
7117c478bdstevel@tonic-gate */
7127c478bdstevel@tonic-gate
7137c478bdstevel@tonic-gate#if !defined(__sparc)
7147c478bdstevel@tonic-gate/*
7157c478bdstevel@tonic-gate * Request bus_dma_ctl parent to fiddle with a dma request.
7167c478bdstevel@tonic-gate *
7177c478bdstevel@tonic-gate * (The sparc version is in sparc_subr.s)
7187c478bdstevel@tonic-gate */
7197c478bdstevel@tonic-gateint
7207c478bdstevel@tonic-gateddi_dma_mctl(dev_info_t *dip, dev_info_t *rdip,
7217c478bdstevel@tonic-gate    ddi_dma_handle_t handle, enum ddi_dma_ctlops request,
7227c478bdstevel@tonic-gate    off_t *offp, size_t *lenp, caddr_t *objp, uint_t flags)
7237c478bdstevel@tonic-gate{
7247c478bdstevel@tonic-gate	int (*fp)();
7257c478bdstevel@tonic-gate
726b51bbbfVikram Hegde	if (dip != ddi_root_node())
727b51bbbfVikram Hegde		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_ctl;
7287c478bdstevel@tonic-gate	fp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_ctl;
7297c478bdstevel@tonic-gate	return ((*fp) (dip, rdip, handle, request, offp, lenp, objp, flags));
7307c478bdstevel@tonic-gate}
7317c478bdstevel@tonic-gate#endif
7327c478bdstevel@tonic-gate
7337c478bdstevel@tonic-gate/*
7347c478bdstevel@tonic-gate * For all DMA control functions, call the DMA control
7357c478bdstevel@tonic-gate * routine and return status.
7367c478bdstevel@tonic-gate *
7377c478bdstevel@tonic-gate * Just plain assume that the parent is to be called.
7387c478bdstevel@tonic-gate * If a nexus driver or a thread outside the framework
7397c478bdstevel@tonic-gate * of a nexus driver or a leaf driver calls these functions,
7407c478bdstevel@tonic-gate * it is up to them to deal with the fact that the parent's
7417c478bdstevel@tonic-gate * bus_dma_ctl function will be the first one called.
7427c478bdstevel@tonic-gate */
7437c478bdstevel@tonic-gate
7447c478bdstevel@tonic-gate#define	HD	((ddi_dma_impl_t *)h)->dmai_rdip
7457c478bdstevel@tonic-gate
7467c478bdstevel@tonic-gate/*
747cd21e7cGarrett D'Amore * This routine is left in place to satisfy link dependencies
748cd21e7cGarrett D'Amore * for any 3rd party nexus drivers that rely on it.  It is never
749cd21e7cGarrett D'Amore * called, though.
7507c478bdstevel@tonic-gate */
751cd21e7cGarrett D'Amore/*ARGSUSED*/
7527c478bdstevel@tonic-gateint
753cd21e7cGarrett D'Amoreddi_dma_map(dev_info_t *dip, dev_info_t *rdip,
754b89e420Garrett D'Amore    struct ddi_dma_req *dmareqp, ddi_dma_handle_t *handlep)
7557c478bdstevel@tonic-gate{
756cd21e7cGarrett D'Amore	return (DDI_FAILURE);
7577c478bdstevel@tonic-gate}
7587c478bdstevel@tonic-gate
7597c478bdstevel@tonic-gate#if !defined(__sparc)
7607c478bdstevel@tonic-gate
7617c478bdstevel@tonic-gate/*
7627c478bdstevel@tonic-gate * The SPARC versions of these routines are done in assembler to
7637c478bdstevel@tonic-gate * save register windows, so they're in sparc_subr.s.
7647c478bdstevel@tonic-gate */
7657c478bdstevel@tonic-gate
7667c478bdstevel@tonic-gateint
7677c478bdstevel@tonic-gateddi_dma_allochdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_attr_t *attr,
7687c478bdstevel@tonic-gate    int (*waitfp)(caddr_t), caddr_t arg, ddi_dma_handle_t *handlep)
7697c478bdstevel@tonic-gate{
7707c478bdstevel@tonic-gate	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_attr_t *,
7717c478bdstevel@tonic-gate	    int (*)(caddr_t), caddr_t, ddi_dma_handle_t *);
7727c478bdstevel@tonic-gate
773b51bbbfVikram Hegde	if (dip != ddi_root_node())
774b51bbbfVikram Hegde		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_allochdl;
7757c478bdstevel@tonic-gate
776b51bbbfVikram Hegde	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_allochdl;
777b51bbbfVikram Hegde	return ((*funcp)(dip, rdip, attr, waitfp, arg, handlep));
7787c478bdstevel@tonic-gate}
7797c478bdstevel@tonic-gate
7807c478bdstevel@tonic-gateint
7817c478bdstevel@tonic-gateddi_dma_freehdl(dev_info_t *dip, dev_info_t *rdip, ddi_dma_handle_t handlep)
7827c478bdstevel@tonic-gate{
7837c478bdstevel@tonic-gate	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
7847c478bdstevel@tonic-gate
785b51bbbfVikram Hegde	if (dip != ddi_root_node())
786b51bbbfVikram Hegde		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_allochdl;
7877c478bdstevel@tonic-gate
788b51bbbfVikram Hegde	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_freehdl;
789b51bbbfVikram Hegde	return ((*funcp)(dip, rdip, handlep));
7907c478bdstevel@tonic-gate}
7917c478bdstevel@tonic-gate
7927c478bdstevel@tonic-gateint
7937c478bdstevel@tonic-gateddi_dma_bindhdl(dev_info_t *dip, dev_info_t *rdip,
7947c478bdstevel@tonic-gate    ddi_dma_handle_t handle, struct ddi_dma_req *dmareq,
7957c478bdstevel@tonic-gate    ddi_dma_cookie_t *cp, uint_t *ccountp)
7967c478bdstevel@tonic-gate{
7977c478bdstevel@tonic-gate	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
7987c478bdstevel@tonic-gate	    struct ddi_dma_req *, ddi_dma_cookie_t *, uint_t *);
7997c478bdstevel@tonic-gate
800b51bbbfVikram Hegde	if (dip != ddi_root_node())
801b51bbbfVikram Hegde		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_bindhdl;
8027c478bdstevel@tonic-gate
803b51bbbfVikram Hegde	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_bindhdl;
804b51bbbfVikram Hegde	return ((*funcp)(dip, rdip, handle, dmareq, cp, ccountp));
8057c478bdstevel@tonic-gate}
8067c478bdstevel@tonic-gate
8077c478bdstevel@tonic-gateint
8087c478bdstevel@tonic-gateddi_dma_unbindhdl(dev_info_t *dip, dev_info_t *rdip,
8097c478bdstevel@tonic-gate    ddi_dma_handle_t handle)
8107c478bdstevel@tonic-gate{
8117c478bdstevel@tonic-gate	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
8127c478bdstevel@tonic-gate
813b51bbbfVikram Hegde	if (dip != ddi_root_node())
814b51bbbfVikram Hegde		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
8157c478bdstevel@tonic-gate
816b51bbbfVikram Hegde	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_unbindhdl;
817b51bbbfVikram Hegde	return ((*funcp)(dip, rdip, handle));
8187c478bdstevel@tonic-gate}
8197c478bdstevel@tonic-gate
8207c478bdstevel@tonic-gate
8217c478bdstevel@tonic-gateint
8227c478bdstevel@tonic-gateddi_dma_flush(dev_info_t *dip, dev_info_t *rdip,
8237c478bdstevel@tonic-gate    ddi_dma_handle_t handle, off_t off, size_t len,
8247c478bdstevel@tonic-gate    uint_t cache_flags)
8257c478bdstevel@tonic-gate{
8267c478bdstevel@tonic-gate	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
8277c478bdstevel@tonic-gate	    off_t, size_t, uint_t);
8287c478bdstevel@tonic-gate
829b51bbbfVikram Hegde	if (dip != ddi_root_node())
830b51bbbfVikram Hegde		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_flush;
8317c478bdstevel@tonic-gate
832b51bbbfVikram Hegde	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_flush;
833b51bbbfVikram Hegde	return ((*funcp)(dip, rdip, handle, off, len, cache_flags));
8347c478bdstevel@tonic-gate}
8357c478bdstevel@tonic-gate
8367c478bdstevel@tonic-gateint
8377c478bdstevel@tonic-gateddi_dma_win(dev_info_t *dip, dev_info_t *rdip,
8387c478bdstevel@tonic-gate    ddi_dma_handle_t handle, uint_t win, off_t *offp,
8397c478bdstevel@tonic-gate    size_t *lenp, ddi_dma_cookie_t *cookiep, uint_t *ccountp)
8407c478bdstevel@tonic-gate{
8417c478bdstevel@tonic-gate	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t,
8427c478bdstevel@tonic-gate	    uint_t, off_t *, size_t *, ddi_dma_cookie_t *, uint_t *);
8437c478bdstevel@tonic-gate
844b51bbbfVikram Hegde	if (dip != ddi_root_node())
845b51bbbfVikram Hegde		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_win;
8467c478bdstevel@tonic-gate
847b51bbbfVikram Hegde	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_win;
848b51bbbfVikram Hegde	return ((*funcp)(dip, rdip, handle, win, offp, lenp,
8497c478bdstevel@tonic-gate	    cookiep, ccountp));
8507c478bdstevel@tonic-gate}
8517c478bdstevel@tonic-gate
8527c478bdstevel@tonic-gateint
8537c478bdstevel@tonic-gateddi_dma_sync(ddi_dma_handle_t h, off_t o, size_t l, uint_t whom)
8547c478bdstevel@tonic-gate{
8557c478bdstevel@tonic-gate	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)h;
856b51bbbfVikram Hegde	dev_info_t *dip, *rdip;
8577c478bdstevel@tonic-gate	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t, off_t,
858184cd04cth	    size_t, uint_t);
8597c478bdstevel@tonic-gate
8607c478bdstevel@tonic-gate	/*
8617c478bdstevel@tonic-gate	 * the DMA nexus driver will set DMP_NOSYNC if the
8627c478bdstevel@tonic-gate	 * platform does not require any sync operation. For
8637c478bdstevel@tonic-gate	 * example if the memory is uncached or consistent
8647c478bdstevel@tonic-gate	 * and without any I/O write buffers involved.
8657c478bdstevel@tonic-gate	 */
8667c478bdstevel@tonic-gate	if ((hp->dmai_rflags & DMP_NOSYNC) == DMP_NOSYNC)
8677c478bdstevel@tonic-gate		return (DDI_SUCCESS);
8687c478bdstevel@tonic-gate
869b51bbbfVikram Hegde	dip = rdip = hp->dmai_rdip;
870b51bbbfVikram Hegde	if (dip != ddi_root_node())
871b51bbbfVikram Hegde		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_flush;
872b51bbbfVikram Hegde	funcp = DEVI(dip)->devi_ops->devo_bus_ops->bus_dma_flush;
873b51bbbfVikram Hegde	return ((*funcp)(dip, rdip, h, o, l, whom));
8747c478bdstevel@tonic-gate}
8757c478bdstevel@tonic-gate
8767c478bdstevel@tonic-gateint
8777c478bdstevel@tonic-gateddi_dma_unbind_handle(ddi_dma_handle_t h)
8787c478bdstevel@tonic-gate{
8797c478bdstevel@tonic-gate	ddi_dma_impl_t *hp = (ddi_dma_impl_t *)h;
880b51bbbfVikram Hegde	dev_info_t *dip, *rdip;
8817c478bdstevel@tonic-gate	int (*funcp)(dev_info_t *, dev_info_t *, ddi_dma_handle_t);
8827c478bdstevel@tonic-gate
883b51bbbfVikram Hegde	dip = rdip = hp->dmai_rdip;
884b51bbbfVikram Hegde	if (dip != ddi_root_node())
885b51bbbfVikram Hegde		dip = (dev_info_t *)DEVI(dip)->devi_bus_dma_unbindhdl;
886b51bbbfVikram Hegde	funcp = DEVI(rdip)->devi_bus_dma_unbindfunc;
887b51bbbfVikram Hegde	return ((*funcp)(dip, rdip, h));
8887c478bdstevel@tonic-gate}
8897c478bdstevel@tonic-gate
8907c478bdstevel@tonic-gate#endif	/* !__sparc */
8917c478bdstevel@tonic-gate
8927c478bdstevel@tonic-gate/*
893cd21e7cGarrett D'Amore * DMA burst sizes, and transfer minimums
8947c478bdstevel@tonic-gate */
8957c478bdstevel@tonic-gate
8967c478bdstevel@tonic-gateint
8977c478bdstevel@tonic-gateddi_dma_burstsizes(ddi_dma_handle_t handle)
8987c478bdstevel@tonic-gate{
8997c478bdstevel@tonic-gate	ddi_dma_impl_t *dimp = (ddi_dma_impl_t *)handle;
9007c478bdstevel@tonic-gate
9017c478bdstevel@tonic-gate	if (!dimp)
9027c478bdstevel@tonic-gate		return (0);
9037c478bdstevel@tonic-gate	else
9047c478bdstevel@tonic-gate		return (dimp->dmai_burstsizes);
9057c478bdstevel@tonic-gate}
9067c478bdstevel@tonic-gate
9077c478bdstevel@tonic-gate/*
9087c478bdstevel@tonic-gate * Given two DMA attribute structures, apply the attributes
9097c478bdstevel@tonic-gate * of one to the other, following the rules of attributes
9107c478bdstevel@tonic-gate * and the wishes of the caller.
9117c478bdstevel@tonic-gate *
9127c478bdstevel@tonic-gate * The rules of DMA attribute structures are that you cannot
9137c478bdstevel@tonic-gate * make things *less* restrictive as you apply one set
9147c478bdstevel@tonic-gate * of attributes to another.
9157c478bdstevel@tonic-gate *
9167c478bdstevel@tonic-gate */
9177c478bdstevel@tonic-gatevoid
9187c478bdstevel@tonic-gateddi_dma_attr_merge(ddi_dma_attr_t *attr, ddi_dma_attr_t *mod)
9197c478bdstevel@tonic-gate{
9207c478bdstevel@tonic-gate	attr->dma_attr_addr_lo =
9217c478bdstevel@tonic-gate	    MAX(attr->dma_attr_addr_lo, mod->dma_attr_addr_lo);
9227c478bdstevel@tonic-gate	attr->dma_attr_addr_hi =
9237c478bdstevel@tonic-gate	    MIN(attr->dma_attr_addr_hi, mod->dma_attr_addr_hi);
9247c478bdstevel@tonic-gate	attr->dma_attr_count_max =
9257c478bdstevel@tonic-gate	    MIN(attr->dma_attr_count_max, mod->dma_attr_count_max);
9267c478bdstevel@tonic-gate	attr->dma_attr_align =
9277c478bdstevel@tonic-gate	    MAX(attr->dma_attr_align,  mod->dma_attr_align);
9287c478bdstevel@tonic-gate	attr->dma_attr_burstsizes =
9297c478bdstevel@tonic-gate	    (uint_t)(attr->dma_attr_burstsizes & mod->dma_attr_burstsizes);
9307c478bdstevel@tonic-gate	attr->dma_attr_minxfer =
9317c478bdstevel@tonic-gate	    maxbit(attr->dma_attr_minxfer, mod->dma_attr_minxfer);
9327c478bdstevel@tonic-gate	attr->dma_attr_maxxfer =
9337c478bdstevel@tonic-gate	    MIN(attr->dma_attr_maxxfer, mod->dma_attr_maxxfer);
9347c478bdstevel@tonic-gate	attr->dma_attr_seg = MIN(attr->dma_attr_seg, mod->dma_attr_seg);
9357c478bdstevel@tonic-gate	attr->dma_attr_sgllen = MIN((uint_t)attr->dma_attr_sgllen,
9367c478bdstevel@tonic-gate	    (uint_t)mod->dma_attr_sgllen);
9377c478bdstevel@tonic-gate	attr->dma_attr_granular =
9387c478bdstevel@tonic-gate	    MAX(attr->dma_attr_granular, mod->dma_attr_granular);
9397c478bdstevel@tonic-gate}
9407c478bdstevel@tonic-gate
9417c478bdstevel@tonic-gate/*
9427c478bdstevel@tonic-gate * mmap/segmap interface:
9437c478bdstevel@tonic-gate */
9447c478bdstevel@tonic-gate
9457c478bdstevel@tonic-gate/*
9467c478bdstevel@tonic-gate * ddi_segmap:		setup the default segment driver. Calls the drivers
9477c478bdstevel@tonic-gate *			XXmmap routine to validate the range to be mapped.
9487c478bdstevel@tonic-gate *			Return ENXIO of the range is not valid.  Create
9497c478bdstevel@tonic-gate *			a seg_dev segment that contains all of the
9507c478bdstevel@tonic-gate *			necessary information and will reference the
9517c478bdstevel@tonic-gate *			default segment driver routines. It returns zero
9527c478bdstevel@tonic-gate *			on success or non-zero on failure.
9537c478bdstevel@tonic-gate */
9547c478bdstevel@tonic-gateint
9557c478bdstevel@tonic-gateddi_segmap(dev_t dev, off_t offset, struct as *asp, caddr_t *addrp, off_t len,
9567c478bdstevel@tonic-gate    uint_t prot, uint_t maxprot, uint_t flags, cred_t *credp)
9577c478bdstevel@tonic-gate{
9587c478bdstevel@tonic-gate	extern int spec_segmap(dev_t, off_t, struct as *, caddr_t *,
9597c478bdstevel@tonic-gate	    off_t, uint_t, uint_t, uint_t, struct cred *);
9607c478bdstevel@tonic-gate
9617c478bdstevel@tonic-gate	return (spec_segmap(dev, offset, asp, addrp, len,
9627c478bdstevel@tonic-gate	    prot, maxprot, flags, credp));
9637c478bdstevel@tonic-gate}
9647c478bdstevel@tonic-gate
9657c478bdstevel@tonic-gate/*
9667c478bdstevel@tonic-gate * ddi_map_fault:	Resolve mappings at fault time.  Used by segment
9677c478bdstevel@tonic-gate *			drivers. Allows each successive parent to resolve
9687c478bdstevel@tonic-gate *			address translations and add its mappings to the
9697c478bdstevel@tonic-gate *			mapping list supplied in the page structure. It
9707c478bdstevel@tonic-gate *			returns zero on success	or non-zero on failure.
9717c478bdstevel@tonic-gate */
9727c478bdstevel@tonic-gate
9737c478bdstevel@tonic-gateint
9747c478bdstevel@tonic-gateddi_map_fault(dev_info_t *dip, struct hat *hat, struct seg *seg,
9757c478bdstevel@tonic-gate    caddr_t addr, struct devpage *dp, pfn_t pfn, uint_t prot, uint_t lock)
9767c478bdstevel@tonic-gate{
9777c478bdstevel@tonic-gate	return (i_ddi_map_fault(dip, dip, hat, seg, addr, dp, pfn, prot, lock));
9787c478bdstevel@tonic-gate}
9797c478bdstevel@tonic-gate
9807c478bdstevel@tonic-gate/*
9817c478bdstevel@tonic-gate * ddi_device_mapping_check:	Called from ddi_segmap_setup.
9827c478bdstevel@tonic-gate *	Invokes platform specific DDI to determine whether attributes specified
9837c478bdstevel@tonic-gate *	in attr(9s) are	valid for the region of memory that will be made
9847c478bdstevel@tonic-gate *	available for direct access to user process via the mmap(2) system call.
9857c478bdstevel@tonic-gate */
9867c478bdstevel@tonic-gateint
9877c478bdstevel@tonic-gateddi_device_mapping_check(dev_t dev, ddi_device_acc_attr_t *accattrp,
9887c478bdstevel@tonic-gate    uint_t rnumber, uint_t *hat_flags)
9897c478bdstevel@tonic-gate{
9907c478bdstevel@tonic-gate	ddi_acc_handle_t handle;
9917c478bdstevel@tonic-gate	ddi_map_req_t mr;
9927c478bdstevel@tonic-gate	ddi_acc_hdl_t *hp;
9937c478bdstevel@tonic-gate	int result;
9947c478bdstevel@tonic-gate	dev_info_t *dip;
9957c478bdstevel@tonic-gate
9967c478bdstevel@tonic-gate	/*
9977c478bdstevel@tonic-gate	 * we use e_ddi_hold_devi_by_dev to search for the devi.  We
9987c478bdstevel@tonic-gate	 * release it immediately since it should already be held by
9997c478bdstevel@tonic-gate	 * a devfs vnode.
10007c478bdstevel@tonic-gate	 */
10017c478bdstevel@tonic-gate	if ((dip =
10027c478bdstevel@tonic-gate	    e_ddi_hold_devi_by_dev(dev, E_DDI_HOLD_DEVI_NOATTACH)) == NULL)
10037c478bdstevel@tonic-gate		return (-1);
10047c478bdstevel@tonic-gate	ddi_release_devi(dip);		/* for e_ddi_hold_devi_by_dev() */
10057c478bdstevel@tonic-gate
10067c478bdstevel@tonic-gate	/*
10077c478bdstevel@tonic-gate	 * Allocate and initialize the common elements of data
10087c478bdstevel@tonic-gate	 * access handle.
10097c478bdstevel@tonic-gate	 */
10107c478bdstevel@tonic-gate	handle = impl_acc_hdl_alloc(KM_SLEEP, NULL);
10117c478bdstevel@tonic-gate	if (handle == NULL)
10127c478bdstevel@tonic-gate		return (-1);
10137c478bdstevel@tonic-gate
10147c478bdstevel@tonic-gate	hp = impl_acc_hdl_get(handle);
10157c478bdstevel@tonic-gate	hp->ah_vers = VERS_ACCHDL;
10167c478bdstevel@tonic-gate	hp->ah_dip = dip;
10177c478bdstevel@tonic-gate	hp->ah_rnumber = rnumber;
10187c478bdstevel@tonic-gate	hp->ah_offset = 0;
10197c478bdstevel@tonic-gate	hp->ah_len = 0;
10207c478bdstevel@tonic-gate	hp->ah_acc = *accattrp;
10217c478bdstevel@tonic-gate
10227c478bdstevel@tonic-gate	/*
10237c478bdstevel@tonic-gate	 * Set up the mapping request and call to parent.
10247c478bdstevel@tonic-gate	 */
10257c478bdstevel@tonic-gate	mr.map_op = DDI_MO_MAP_HANDLE;
10267c478bdstevel@tonic-gate	mr.map_type = DDI_MT_RNUMBER;
10277c478bdstevel@tonic-gate	mr.map_obj.rnumber = rnumber;
10287c478bdstevel@tonic-gate	mr.map_prot = PROT_READ | PROT_WRITE;
10297c478bdstevel@tonic-gate	mr.map_flags = DDI_MF_KERNEL_MAPPING;
10307c478bdstevel@tonic-gate	mr.map_handlep = hp;
10317c478bdstevel@tonic-gate	mr.map_vers = DDI_MAP_VERSION;
10327c478bdstevel@tonic-gate	result = ddi_map(dip, &mr, 0, 0, NULL);
10337c478bdstevel@tonic-gate
10347c478bdstevel@tonic-gate	/*
10357c478bdstevel@tonic-gate	 * Region must be mappable, pick up flags from the framework.
10367c478bdstevel@tonic-gate	 */
10377c478bdstevel@tonic-gate	*hat_flags = hp->ah_hat_flags;
10387c478bdstevel@tonic-gate
10397c478bdstevel@tonic-gate	impl_acc_hdl_free(handle);
10407c478bdstevel@tonic-gate
10417c478bdstevel@tonic-gate	/*
10427c478bdstevel@tonic-gate	 * check for end result.
10437c478bdstevel@tonic-gate	 */
10447c478bdstevel@tonic-gate	if (result != DDI_SUCCESS)
10457c478bdstevel@tonic-gate		return (-1);
10467c478bdstevel@tonic-gate	return (0);
10477c478bdstevel@tonic-gate}
10487c478bdstevel@tonic-gate
10497c478bdstevel@tonic-gate
10507c478bdstevel@tonic-gate/*
10517c478bdstevel@tonic-gate * Property functions:	 See also, ddipropdefs.h.
10527c478bdstevel@tonic-gate *
10537c478bdstevel@tonic-gate * These functions are the framework for the property functions,
10547c478bdstevel@tonic-gate * i.e. they support software defined properties.  All implementation
10557c478bdstevel@tonic-gate * specific property handling (i.e.: self-identifying devices and
10567c478bdstevel@tonic-gate * PROM defined properties are handled in the implementation specific
10577c478bdstevel@tonic-gate * functions (defined in ddi_implfuncs.h).
10587c478bdstevel@tonic-gate */
10597c478bdstevel@tonic-gate
10607c478bdstevel@tonic-gate/*
10617c478bdstevel@tonic-gate * nopropop:	Shouldn't be called, right?
10627c478bdstevel@tonic-gate */
10637c478bdstevel@tonic-gateint
10647c478bdstevel@tonic-gatenopropop(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
10657c478bdstevel@tonic-gate    char *name, caddr_t valuep, int *lengthp)
10667c478bdstevel@tonic-gate{
10677c478bdstevel@tonic-gate	_NOTE(ARGUNUSED(dev, dip, prop_op, mod_flags, name, valuep, lengthp))
10687c478bdstevel@tonic-gate	return (DDI_PROP_NOT_FOUND);
10697c478bdstevel@tonic-gate}
10707c478bdstevel@tonic-gate
10717c478bdstevel@tonic-gate#ifdef	DDI_PROP_DEBUG
10727c478bdstevel@tonic-gateint ddi_prop_debug_flag = 0;
10737c478bdstevel@tonic-gate
10747c478bdstevel@tonic-gateint
10757c478bdstevel@tonic-gateddi_prop_debug(int enable)
10767c478bdstevel@tonic-gate{
10777c478bdstevel@tonic-gate	int prev = ddi_prop_debug_flag;
10787c478bdstevel@tonic-gate
10797c478bdstevel@tonic-gate	if ((enable != 0) || (prev != 0))
10807c478bdstevel@tonic-gate		printf("ddi_prop_debug: debugging %s\n",
10817c478bdstevel@tonic-gate		    enable ? "enabled" : "disabled");
10827c478bdstevel@tonic-gate	ddi_prop_debug_flag = enable;
10837c478bdstevel@tonic-gate	return (prev);
10847c478bdstevel@tonic-gate}
10857c478bdstevel@tonic-gate
10867c478bdstevel@tonic-gate#endif	/* DDI_PROP_DEBUG */
10877c478bdstevel@tonic-gate
10887c478bdstevel@tonic-gate/*
10897c478bdstevel@tonic-gate * Search a property list for a match, if found return pointer
10907c478bdstevel@tonic-gate * to matching prop struct, else return NULL.
10917c478bdstevel@tonic-gate */
10927c478bdstevel@tonic-gate
10937c478bdstevel@tonic-gateddi_prop_t *
10947c478bdstevel@tonic-gatei_ddi_prop_search(dev_t dev, char *name, uint_t flags, ddi_prop_t **list_head)
10957c478bdstevel@tonic-gate{
10967c478bdstevel@tonic-gate	ddi_prop_t	*propp;
10977c478bdstevel@tonic-gate
10987c478bdstevel@tonic-gate	/*
10997c478bdstevel@tonic-gate	 * find the property in child's devinfo:
11009ac2ddecth	 * Search order defined by this search function is first matching
11019ac2ddecth	 * property with input dev == DDI_DEV_T_ANY matching any dev or
11029ac2ddecth	 * dev == propp->prop_dev, name == propp->name, and the correct
11039ac2ddecth	 * data type as specified in the flags.  If a DDI_DEV_T_NONE dev
11049ac2ddecth	 * value made it this far then it implies a DDI_DEV_T_ANY search.
11057c478bdstevel@tonic-gate	 */
11069ac2ddecth	if (dev == DDI_DEV_T_NONE)
11079ac2ddecth		dev = DDI_DEV_T_ANY;
11087c478bdstevel@tonic-gate
11097c478bdstevel@tonic-gate	for (propp = *list_head; propp != NULL; propp = propp->prop_next)  {
11107c478bdstevel@tonic-gate
11112cd7878cth		if (!DDI_STRSAME(propp->prop_name, name))
11127c478bdstevel@tonic-gate			continue;
11137c478bdstevel@tonic-gate
11147c478bdstevel@tonic-gate		if ((dev != DDI_DEV_T_ANY) && (propp->prop_dev != dev))
11157c478bdstevel@tonic-gate			continue;
11167c478bdstevel@tonic-gate
11177c478bdstevel@tonic-gate		if (((propp->prop_flags & flags) & DDI_PROP_TYPE_MASK) == 0)
11187c478bdstevel@tonic-gate			continue;
11197c478bdstevel@tonic-gate
11207c478bdstevel@tonic-gate		return (propp);
11217c478bdstevel@tonic-gate	}
11227c478bdstevel@tonic-gate
11237c478bdstevel@tonic-gate	return ((ddi_prop_t *)0);
11247c478bdstevel@tonic-gate}
11257c478bdstevel@tonic-gate
11267c478bdstevel@tonic-gate/*
11277c478bdstevel@tonic-gate * Search for property within devnames structures
11287c478bdstevel@tonic-gate */
11297c478bdstevel@tonic-gateddi_prop_t *
11307c478bdstevel@tonic-gatei_ddi_search_global_prop(dev_t dev, char *name, uint_t flags)
11317c478bdstevel@tonic-gate{
11327c478bdstevel@tonic-gate	major_t		major;
11337c478bdstevel@tonic-gate	struct devnames	*dnp;
11347c478bdstevel@tonic-gate	ddi_prop_t	*propp;
11357c478bdstevel@tonic-gate
11367c478bdstevel@tonic-gate	/*
11377c478bdstevel@tonic-gate	 * Valid dev_t value is needed to index into the
11387c478bdstevel@tonic-gate	 * correct devnames entry, therefore a dev_t
11397c478bdstevel@tonic-gate	 * value of DDI_DEV_T_ANY is not appropriate.
11407c478bdstevel@tonic-gate	 */
11417c478bdstevel@tonic-gate	ASSERT(dev != DDI_DEV_T_ANY);
11427c478bdstevel@tonic-gate	if (dev == DDI_DEV_T_ANY) {
11437c478bdstevel@tonic-gate		return ((ddi_prop_t *)0);
11447c478bdstevel@tonic-gate	}
11457c478bdstevel@tonic-gate
11467c478bdstevel@tonic-gate	major = getmajor(dev);
11477c478bdstevel@tonic-gate	dnp = &(devnamesp[major]);
11487c478bdstevel@tonic-gate
11497c478bdstevel@tonic-gate	if (dnp->dn_global_prop_ptr == NULL)
11507c478bdstevel@tonic-gate		return ((ddi_prop_t *)0);
11517c478bdstevel@tonic-gate
11527c478bdstevel@tonic-gate	LOCK_DEV_OPS(&dnp->dn_lock);
11537c478bdstevel@tonic-gate
11547c478bdstevel@tonic-gate	for (propp = dnp->dn_global_prop_ptr->prop_list;
11557c478bdstevel@tonic-gate	    propp != NULL;
11567c478bdstevel@tonic-gate	    propp = (ddi_prop_t *)propp->prop_next) {
11577c478bdstevel@tonic-gate
11582cd7878cth		if (!DDI_STRSAME(propp->prop_name, name))
11597c478bdstevel@tonic-gate			continue;
11607c478bdstevel@tonic-gate
116165cf7c9Vikram Hegde		if ((!(flags & DDI_PROP_ROOTNEX_GLOBAL)) &&
116265cf7c9Vikram Hegde		    (!(flags & LDI_DEV_T_ANY)) && (propp->prop_dev != dev))
11637c478bdstevel@tonic-gate			continue;
11647c478bdstevel@tonic-gate
11657c478bdstevel@tonic-gate		if (((propp->prop_flags & flags) & DDI_PROP_TYPE_MASK) == 0)
11667c478bdstevel@tonic-gate			continue;
11677c478bdstevel@tonic-gate
11687c478bdstevel@tonic-gate		/* Property found, return it */
11697c478bdstevel@tonic-gate		UNLOCK_DEV_OPS(&dnp->dn_lock);
11707c478bdstevel@tonic-gate		return (propp);
11717c478bdstevel@tonic-gate	}
11727c478bdstevel@tonic-gate
11737c478bdstevel@tonic-gate	UNLOCK_DEV_OPS(&dnp->dn_lock);
11747c478bdstevel@tonic-gate	return ((ddi_prop_t *)0);
11757c478bdstevel@tonic-gate}
11767c478bdstevel@tonic-gate
11777c478bdstevel@tonic-gatestatic char prop_no_mem_msg[] = "can't allocate memory for ddi property <%s>";
11787c478bdstevel@tonic-gate
11797c478bdstevel@tonic-gate/*
11807c478bdstevel@tonic-gate * ddi_prop_search_global:
11817c478bdstevel@tonic-gate *	Search the global property list within devnames
11827c478bdstevel@tonic-gate *	for the named property.  Return the encoded value.
11837c478bdstevel@tonic-gate */
11847c478bdstevel@tonic-gatestatic int
11857c478bdstevel@tonic-gatei_ddi_prop_search_global(dev_t dev, uint_t flags, char *name,
11867c478bdstevel@tonic-gate    void *valuep, uint_t *lengthp)
11877c478bdstevel@tonic-gate{
11887c478bdstevel@tonic-gate	ddi_prop_t	*propp;
11897c478bdstevel@tonic-gate	caddr_t		buffer;
11907c478bdstevel@tonic-gate
11917c478bdstevel@tonic-gate	propp =  i_ddi_search_global_prop(dev, name, flags);
11927c478bdstevel@tonic-gate
11937c478bdstevel@tonic-gate	/* Property NOT found, bail */
11947c478bdstevel@tonic-gate	if (propp == (ddi_prop_t *)0)
11957c478bdstevel@tonic-gate		return (DDI_PROP_NOT_FOUND);
11967c478bdstevel@tonic-gate
11977c478bdstevel@tonic-gate	if (propp->prop_flags & DDI_PROP_UNDEF_IT)
11987c478bdstevel@tonic-gate		return (DDI_PROP_UNDEFINED);
11997c478bdstevel@tonic-gate
12003b756ddcth	if ((buffer = kmem_alloc(propp->prop_len,
12013b756ddcth	    (flags & DDI_PROP_CANSLEEP) ? KM_SLEEP : KM_NOSLEEP)) == NULL) {
12027c478bdstevel@tonic-gate		cmn_err(CE_CONT, prop_no_mem_msg, name);
12037c478bdstevel@tonic-gate		return (DDI_PROP_NO_MEMORY);
12047c478bdstevel@tonic-gate	}
12057c478bdstevel@tonic-gate
12067c478bdstevel@tonic-gate	/*
12077c478bdstevel@tonic-gate	 * Return the encoded data
12087c478bdstevel@tonic-gate	 */
12097c478bdstevel@tonic-gate	*(caddr_t *)valuep = buffer;
12107c478bdstevel@tonic-gate	*lengthp = propp->prop_len;
12117c478bdstevel@tonic-gate	bcopy(propp->prop_val, buffer, propp->prop_len);
12127c478bdstevel@tonic-gate
12137c478bdstevel@tonic-gate	return (DDI_PROP_SUCCESS);
12147c478bdstevel@tonic-gate}
12157c478bdstevel@tonic-gate
12167c478bdstevel@tonic-gate/*
12177c478bdstevel@tonic-gate * ddi_prop_search_common:	Lookup and return the encoded value
12187c478bdstevel@tonic-gate */
12197c478bdstevel@tonic-gateint
12207c478bdstevel@tonic-gateddi_prop_search_common(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
12217c478bdstevel@tonic-gate    uint_t flags, char *name, void *valuep, uint_t *lengthp)
12227c478bdstevel@tonic-gate{
12237c478bdstevel@tonic-gate	ddi_prop_t	*propp;
12247c478bdstevel@tonic-gate	int		i;
1225c6f039cToomas Soome	caddr_t		buffer = NULL;
12267c478bdstevel@tonic-gate	caddr_t		prealloc = NULL;
12277c478bdstevel@tonic-gate	int		plength = 0;
12287c478bdstevel@tonic-gate	dev_info_t	*pdip;
12297c478bdstevel@tonic-gate	int		(*bop)();
12307c478bdstevel@tonic-gate
12317c478bdstevel@tonic-gate	/*CONSTANTCONDITION*/
12327c478bdstevel@tonic-gate	while (1)  {
12337c478bdstevel@tonic-gate
12347c478bdstevel@tonic-gate		mutex_enter(&(DEVI(dip)->devi_lock));
12357c478bdstevel@tonic-gate
12367c478bdstevel@tonic-gate
12377c478bdstevel@tonic-gate		/*
12387c478bdstevel@tonic-gate		 * find the property in child's devinfo:
12397c478bdstevel@tonic-gate		 * Search order is:
12407c478bdstevel@tonic-gate		 *	1. driver defined properties
12417c478bdstevel@tonic-gate		 *	2. system defined properties
12427c478bdstevel@tonic-gate		 *	3. driver global properties
12437c478bdstevel@tonic-gate		 *	4. boot defined properties
12447c478bdstevel@tonic-gate		 */
12457c478bdstevel@tonic-gate
12467c478bdstevel@tonic-gate		propp = i_ddi_prop_search(dev, name, flags,
12477c478bdstevel@tonic-gate		    &(DEVI(dip)->devi_drv_prop_ptr));
12487c478bdstevel@tonic-gate		if (propp == NULL)  {
12497c478bdstevel@tonic-gate			propp = i_ddi_prop_search(dev, name, flags,
12507c478bdstevel@tonic-gate			    &(DEVI(dip)->devi_sys_prop_ptr));
12517c478bdstevel@tonic-gate		}
12527c478bdstevel@tonic-gate		if ((propp == NULL) && DEVI(dip)->devi_global_prop_list) {
12537c478bdstevel@tonic-gate			propp = i_ddi_prop_search(dev, name, flags,
12547c478bdstevel@tonic-gate			    &DEVI(dip)->devi_global_prop_list->prop_list);
12557c478bdstevel@tonic-gate		}
12567c478bdstevel@tonic-gate
12577c478bdstevel@tonic-gate		if (propp == NULL)  {
12587c478bdstevel@tonic-gate			propp = i_ddi_prop_search(dev, name, flags,
12597c478bdstevel@tonic-gate			    &(DEVI(dip)->devi_hw_prop_ptr));
12607c478bdstevel@tonic-gate		}
12617c478bdstevel@tonic-gate
12627c478bdstevel@tonic-gate		/*
12637c478bdstevel@tonic-gate		 * Software property found?
12647c478bdstevel@tonic-gate		 */
12657c478bdstevel@tonic-gate		if (propp != (ddi_prop_t *)0)	{
12667c478bdstevel@tonic-gate
12677c478bdstevel@tonic-gate			/*
12687c478bdstevel@tonic-gate			 * If explicit undefine, return now.
12697c478bdstevel@tonic-gate			 */
12707c478bdstevel@tonic-gate			if (propp->prop_flags & DDI_PROP_UNDEF_IT) {
12717c478bdstevel@tonic-gate				mutex_exit(&(DEVI(dip)->devi_lock));
12727c478bdstevel@tonic-gate				if (prealloc)
12737c478bdstevel@tonic-gate					kmem_free(prealloc, plength);
12747c478bdstevel@tonic-gate				return (DDI_PROP_UNDEFINED);
12757c478bdstevel@tonic-gate			}
12767c478bdstevel@tonic-gate
12777c478bdstevel@tonic-gate			/*
12787c478bdstevel@tonic-gate			 * If we only want to know if it exists, return now
12797c478bdstevel@tonic-gate			 */
12807c478bdstevel@tonic-gate			if (prop_op == PROP_EXISTS) {
12817c478bdstevel@tonic-gate				mutex_exit(&(DEVI(dip)->devi_lock));
12827c478bdstevel@tonic-gate				ASSERT(prealloc == NULL);
12837c478bdstevel@tonic-gate				return (DDI_PROP_SUCCESS);
12847c478bdstevel@tonic-gate			}
12857c478bdstevel@tonic-gate
12867c478bdstevel@tonic-gate			/*
12877c478bdstevel@tonic-gate			 * If length only request or prop length == 0,
12887c478bdstevel@tonic-gate			 * service request and return now.
12897c478bdstevel@tonic-gate			 */
12907c478bdstevel@tonic-gate			if ((prop_op == PROP_LEN) ||(propp->prop_len == 0)) {
12917c478bdstevel@tonic-gate				*lengthp = propp->prop_len;
12927c478bdstevel@tonic-gate
12937c478bdstevel@tonic-gate				/*
12947c478bdstevel@tonic-gate				 * if prop_op is PROP_LEN_AND_VAL_ALLOC
12957c478bdstevel@tonic-gate				 * that means prop_len is 0, so set valuep
12967c478bdstevel@tonic-gate				 * also to NULL
12977c478bdstevel@tonic-gate				 */
12987c478bdstevel@tonic-gate				if (prop_op == PROP_LEN_AND_VAL_ALLOC)
12997c478bdstevel@tonic-gate					*(caddr_t *)valuep = NULL;
13007c478bdstevel@tonic-gate
13017c478bdstevel@tonic-gate				mutex_exit(&(DEVI(dip)->devi_lock));
13027c478bdstevel@tonic-gate				if (prealloc)
13037c478bdstevel@tonic-gate					kmem_free(prealloc, plength);
13047c478bdstevel@tonic-gate				return (DDI_PROP_SUCCESS);
13057c478bdstevel@tonic-gate			}
13067c478bdstevel@tonic-gate
13077c478bdstevel@tonic-gate			/*
13087c478bdstevel@tonic-gate			 * If LEN_AND_VAL_ALLOC and the request can sleep,
13097c478bdstevel@tonic-gate			 * drop the mutex, allocate the buffer, and go
13107c478bdstevel@tonic-gate			 * through the loop again.  If we already allocated
13117c478bdstevel@tonic-gate			 * the buffer, and the size of the property changed,
13127c478bdstevel@tonic-gate			 * keep trying...
13137c478bdstevel@tonic-gate			 */
13147c478bdstevel@tonic-gate			if ((prop_op == PROP_LEN_AND_VAL_ALLOC) &&
13157c478bdstevel@tonic-gate			    (flags & DDI_PROP_CANSLEEP))  {
13167c478bdstevel@tonic-gate				if (prealloc && (propp->prop_len != plength)) {
13177c478bdstevel@tonic-gate					kmem_free(prealloc, plength);
13187c478bdstevel@tonic-gate					prealloc = NULL;
13197c478bdstevel@tonic-gate				}
13207c478bdstevel@tonic-gate				if (prealloc == NULL)  {
13217c478bdstevel@tonic-gate					plength = propp->prop_len;
13227c478bdstevel@tonic-gate					mutex_exit(&(DEVI(dip)->devi_lock));
13237c478bdstevel@tonic-gate					prealloc = kmem_alloc(plength,
13247c478bdstevel@tonic-gate					    KM_SLEEP);
13257c478bdstevel@tonic-gate					continue;
13267c478bdstevel@tonic-gate				}
13277c478bdstevel@tonic-gate			}
13287c478bdstevel@tonic-gate
13297c478bdstevel@tonic-gate			/*
13307c478bdstevel@tonic-gate			 * Allocate buffer, if required.  Either way,
13317c478bdstevel@tonic-gate			 * set `buffer' variable.
13327c478bdstevel@tonic-gate			 */
13337c478bdstevel@tonic-gate			i = *lengthp;			/* Get callers length */
13347c478bdstevel@tonic-gate			*lengthp = propp->prop_len;	/* Set callers length */
13357c478bdstevel@tonic-gate
13367c478bdstevel@tonic-gate			switch (prop_op) {
13377c478bdstevel@tonic-gate
13387c478bdstevel@tonic-gate			case PROP_LEN_AND_VAL_ALLOC:
13397c478bdstevel@tonic-gate
13407c478bdstevel@tonic-gate				if (prealloc == NULL) {
13417c478bdstevel@tonic-gate					buffer = kmem_alloc(propp->prop_len,
13427c478bdstevel@tonic-gate					    KM_NOSLEEP);
13437c478bdstevel@tonic-gate				} else {
13447c478bdstevel@tonic-gate					buffer = prealloc;
13457c478bdstevel@tonic-gate				}
13467c478bdstevel@tonic-gate
13477c478bdstevel@tonic-gate				if (buffer == NULL)  {
13487c478bdstevel@tonic-gate					mutex_exit(&(DEVI(dip)->devi_lock));
13497c478bdstevel@tonic-gate					cmn_err(CE_CONT, prop_no_mem_msg, name);
13507c478bdstevel@tonic-gate					return (DDI_PROP_NO_MEMORY);
13517c478bdstevel@tonic-gate				}
13527c478bdstevel@tonic-gate				/* Set callers buf ptr */
13537c478bdstevel@tonic-gate				*(caddr_t *)valuep = buffer;
13547c478bdstevel@tonic-gate				break;
13557c478bdstevel@tonic-gate
13567c478bdstevel@tonic-gate			case PROP_LEN_AND_VAL_BUF:
13577c478bdstevel@tonic-gate
13587c478bdstevel@tonic-gate				if (propp->prop_len > (i)) {
13597c478bdstevel@tonic-gate					mutex_exit(&(DEVI(dip)->devi_lock));
13607c478bdstevel@tonic-gate					return (DDI_PROP_BUF_TOO_SMALL);
13617c478bdstevel@tonic-gate				}
13627c478bdstevel@tonic-gate
13637c478bdstevel@tonic-gate				buffer = valuep;  /* Get callers buf ptr */
13647c478bdstevel@tonic-gate				break;
13657c478bdstevel@tonic-gate
13667c478bdstevel@tonic-gate			default:
13677c478bdstevel@tonic-gate				break;
13687c478bdstevel@tonic-gate			}
13697c478bdstevel@tonic-gate
13707c478bdstevel@tonic-gate			/*
13717c478bdstevel@tonic-gate			 * Do the copy.
13727c478bdstevel@tonic-gate			 */
1373c6f039cToomas Soome			if (buffer != NULL)
1374c6f039cToomas Soome				bcopy(propp->prop_val, buffer, propp->prop_len);
13757c478bdstevel@tonic-gate			mutex_exit(&(DEVI(dip)->devi_lock));
13767c478bdstevel@tonic-gate			return (DDI_PROP_SUCCESS);
13777c478bdstevel@tonic-gate		}
13787c478bdstevel@tonic-gate
13797c478bdstevel@tonic-gate		mutex_exit(&(DEVI(dip)->devi_lock));
13807c478bdstevel@tonic-gate		if (prealloc)
13817c478bdstevel@tonic-gate			kmem_free(prealloc, plength);
13827c478bdstevel@tonic-gate		prealloc = NULL;
13837c478bdstevel@tonic-gate
13847c478bdstevel@tonic-gate		/*
13857c478bdstevel@tonic-gate		 * Prop not found, call parent bus_ops to deal with possible
13867c478bdstevel@tonic-gate		 * h/w layer (possible PROM defined props, etc.) and to
13877c478bdstevel@tonic-gate		 * possibly ascend the hierarchy, if allowed by flags.
13887c478bdstevel@tonic-gate		 */
13897c478bdstevel@tonic-gate		pdip = (dev_info_t *)DEVI(dip)->devi_parent;
13907c478bdstevel@tonic-gate
13917c478bdstevel@tonic-gate		/*
13927c478bdstevel@tonic-gate		 * One last call for the root driver PROM props?
13937c478bdstevel@tonic-gate		 */
13947c478bdstevel@tonic-gate		if (dip == ddi_root_node())  {
13957c478bdstevel@tonic-gate			return (ddi_bus_prop_op(dev, dip, dip, prop_op,
13967c478bdstevel@tonic-gate			    flags, name, valuep, (int *)lengthp));
13977c478bdstevel@tonic-gate		}
13987c478bdstevel@tonic-gate
13997c478bdstevel@tonic-gate		/*
14007c478bdstevel@tonic-gate		 * We may have been called to check for properties
14017c478bdstevel@tonic-gate		 * within a single devinfo node that has no parent -
14027c478bdstevel@tonic-gate		 * see make_prop()
14037c478bdstevel@tonic-gate		 */
14047c478bdstevel@tonic-gate		if (pdip == NULL) {
14057c478bdstevel@tonic-gate			ASSERT((flags &
14067c478bdstevel@tonic-gate			    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM)) ==
14077c478bdstevel@tonic-gate			    (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM));
14087c478bdstevel@tonic-gate			return (DDI_PROP_NOT_FOUND);
14097c478bdstevel@tonic-gate		}
14107c478bdstevel@tonic-gate
14117c478bdstevel@tonic-gate		/*
14127c478bdstevel@tonic-gate		 * Instead of recursing, we do iterative calls up the tree.
14137c478bdstevel@tonic-gate		 * As a bit of optimization, skip the bus_op level if the
14147c478bdstevel@tonic-gate		 * node is a s/w node and if the parent's bus_prop_op function
14157c478bdstevel@tonic-gate		 * is `ddi_bus_prop_op', because we know that in this case,
14167c478bdstevel@tonic-gate		 * this function does nothing.
14177c478bdstevel@tonic-gate		 *
14187c478bdstevel@tonic-gate		 * 4225415: If the parent isn't attached, or the child
14197c478bdstevel@tonic-gate		 * hasn't been named by the parent yet, use the default
14207c478bdstevel@tonic-gate		 * ddi_bus_prop_op as a proxy for the parent.  This
14217c478bdstevel@tonic-gate		 * allows property lookups in any child/parent state to
14227c478bdstevel@tonic-gate		 * include 'prom' and inherited properties, even when
14237c478bdstevel@tonic-gate		 * there are no drivers attached to the child or parent.
14247c478bdstevel@tonic-gate		 */
14257c478bdstevel@tonic-gate
14267c478bdstevel@tonic-gate		bop = ddi_bus_prop_op;
1427737d277cth		if (i_ddi_devi_attached(pdip) &&
14287c478bdstevel@tonic-gate		    (i_ddi_node_state(dip) >= DS_INITIALIZED))
14297c478bdstevel@tonic-gate			bop = DEVI(pdip)->devi_ops->devo_bus_ops->bus_prop_op;
14307c478bdstevel@tonic-gate
14317c478bdstevel@tonic-gate		i = DDI_PROP_NOT_FOUND;
14327c478bdstevel@tonic-gate
14337c478bdstevel@tonic-gate		if ((bop != ddi_bus_prop_op) || ndi_dev_is_prom_node(dip)) {
14347c478bdstevel@tonic-gate			i = (*bop)(dev, pdip, dip, prop_op,
14357c478bdstevel@tonic-gate			    flags | DDI_PROP_DONTPASS,
14367c478bdstevel@tonic-gate			    name, valuep, lengthp);
14377c478bdstevel@tonic-gate		}
14387c478bdstevel@tonic-gate
14397c478bdstevel@tonic-gate		if ((flags & DDI_PROP_DONTPASS) ||
14407c478bdstevel@tonic-gate		    (i != DDI_PROP_NOT_FOUND))
14417c478bdstevel@tonic-gate			return (i);
14427c478bdstevel@tonic-gate
14437c478bdstevel@tonic-gate		dip = pdip;
14447c478bdstevel@tonic-gate	}
14457c478bdstevel@tonic-gate	/*NOTREACHED*/
14467c478bdstevel@tonic-gate}
14477c478bdstevel@tonic-gate
14487c478bdstevel@tonic-gate
14497c478bdstevel@tonic-gate/*
14507c478bdstevel@tonic-gate * ddi_prop_op: The basic property operator for drivers.
14517c478bdstevel@tonic-gate *
14527c478bdstevel@tonic-gate * In ddi_prop_op, the type of valuep is interpreted based on prop_op:
14537c478bdstevel@tonic-gate *
14547c478bdstevel@tonic-gate *	prop_op			valuep
14557c478bdstevel@tonic-gate *	------			------
14567c478bdstevel@tonic-gate *
14577c478bdstevel@tonic-gate *	PROP_LEN		<unused>
14587c478bdstevel@tonic-gate *
14597c478bdstevel@tonic-gate *	PROP_LEN_AND_VAL_BUF	Pointer to callers buffer
14607c478bdstevel@tonic-gate *
14617c478bdstevel@tonic-gate *	PROP_LEN_AND_VAL_ALLOC	Address of callers pointer (will be set to
14627c478bdstevel@tonic-gate *				address of allocated buffer, if successful)
14637c478bdstevel@tonic-gate */
14647c478bdstevel@tonic-gateint
14657c478bdstevel@tonic-gateddi_prop_op(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op, int mod_flags,
14667c478bdstevel@tonic-gate    char *name, caddr_t valuep, int *lengthp)
14677c478bdstevel@tonic-gate{
14687c478bdstevel@tonic-gate	int	i;
14697c478bdstevel@tonic-gate
14707c478bdstevel@tonic-gate	ASSERT((mod_flags & DDI_PROP_TYPE_MASK) == 0);
14717c478bdstevel@tonic-gate
14727c478bdstevel@tonic-gate	/*
14737c478bdstevel@tonic-gate	 * If this was originally an LDI prop lookup then we bail here.
14747c478bdstevel@tonic-gate	 * The reason is that the LDI property lookup interfaces first call
14757c478bdstevel@tonic-gate	 * a drivers prop_op() entry point to allow it to override
14767c478bdstevel@tonic-gate	 * properties.  But if we've made it here, then the driver hasn't
14777c478bdstevel@tonic-gate	 * overriden any properties.  We don't want to continue with the
14787c478bdstevel@tonic-gate	 * property search here because we don't have any type inforamtion.
14797c478bdstevel@tonic-gate	 * When we return failure, the LDI interfaces will then proceed to
14807c478bdstevel@tonic-gate	 * call the typed property interfaces to look up the property.
14817c478bdstevel@tonic-gate	 */
14827c478bdstevel@tonic-gate	if (mod_flags & DDI_PROP_DYNAMIC)
14837c478bdstevel@tonic-gate		return (DDI_PROP_NOT_FOUND);
14847c478bdstevel@tonic-gate
14857c478bdstevel@tonic-gate	/*
14867c478bdstevel@tonic-gate	 * check for pre-typed property consumer asking for typed property:
14877c478bdstevel@tonic-gate	 * see e_ddi_getprop_int64.
14887c478bdstevel@tonic-gate	 */
14897c478bdstevel@tonic-gate	if (mod_flags & DDI_PROP_CONSUMER_TYPED)
14907c478bdstevel@tonic-gate		mod_flags |= DDI_PROP_TYPE_INT64;
14917c478bdstevel@tonic-gate	mod_flags |= DDI_PROP_TYPE_ANY;
14927c478bdstevel@tonic-gate
14937c478bdstevel@tonic-gate	i = ddi_prop_search_common(dev, dip, prop_op,
1494184cd04cth	    mod_flags, name, valuep, (uint_t *)lengthp);
14957c478bdstevel@tonic-gate	if (i == DDI_PROP_FOUND_1275)
14967c478bdstevel@tonic-gate		return (DDI_PROP_SUCCESS);
14977c478bdstevel@tonic-gate	return (i);
14987c478bdstevel@tonic-gate}
14997c478bdstevel@tonic-gate
15007c478bdstevel@tonic-gate/*
1501184cd04cth * ddi_prop_op_nblocks_blksize: The basic property operator for drivers that
1502184cd04cth * maintain size in number of blksize blocks.  Provides a dynamic property
1503184cd04cth * implementation for size oriented properties based on nblocks64 and blksize
1504184cd04cth * values passed in by the driver.  Fallback to ddi_prop_op if the nblocks64
1505184cd04cth * is too large.  This interface should not be used with a nblocks64 that
1506184cd04cth * represents the driver's idea of how to represent unknown, if nblocks is
1507184cd04cth * unknown use ddi_prop_op.
15087c478bdstevel@tonic-gate */
15097c478bdstevel@tonic-gateint
1510184cd04cthddi_prop_op_nblocks_blksize(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1511184cd04cth    int mod_flags, char *name, caddr_t valuep, int *lengthp,
1512184cd04cth    uint64_t nblocks64, uint_t blksize)
15137c478bdstevel@tonic-gate{
15147c478bdstevel@tonic-gate	uint64_t size64;
1515184cd04cth	int	blkshift;
1516184cd04cth
1517184cd04cth	/* convert block size to shift value */
1518184cd04cth	ASSERT(BIT_ONLYONESET(blksize));
1519184cd04cth	blkshift = highbit(blksize) - 1;
15207c478bdstevel@tonic-gate
15217c478bdstevel@tonic-gate	/*
15227c478bdstevel@tonic-gate	 * There is no point in supporting nblocks64 values that don't have
15237c478bdstevel@tonic-gate	 * an accurate uint64_t byte count representation.
15247c478bdstevel@tonic-gate	 */
1525184cd04cth	if (nblocks64 >= (UINT64_MAX >> blkshift))
15267c478bdstevel@tonic-gate		return (ddi_prop_op(dev, dip, prop_op, mod_flags,
15277c478bdstevel@tonic-gate		    name, valuep, lengthp));
15287c478bdstevel@tonic-gate
1529184cd04cth	size64 = nblocks64 << blkshift;
1530184cd04cth	return (ddi_prop_op_size_blksize(dev, dip, prop_op, mod_flags,
1531184cd04cth	    name, valuep, lengthp, size64, blksize));
15327c478bdstevel@tonic-gate}
15337c478bdstevel@tonic-gate
15347c478bdstevel@tonic-gate/*
1535184cd04cth * ddi_prop_op_nblocks: ddi_prop_op_nblocks_blksize with DEV_BSIZE blksize.
1536184cd04cth */
1537184cd04cthint
1538184cd04cthddi_prop_op_nblocks(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1539184cd04cth    int mod_flags, char *name, caddr_t valuep, int *lengthp, uint64_t nblocks64)
1540184cd04cth{
1541184cd04cth	return (ddi_prop_op_nblocks_blksize(dev, dip, prop_op,
1542184cd04cth	    mod_flags, name, valuep, lengthp, nblocks64, DEV_BSIZE));
1543184cd04cth}
1544184cd04cth
1545184cd04cth/*
1546184cd04cth * ddi_prop_op_size_blksize: The basic property operator for block drivers that
1547184cd04cth * maintain size in bytes. Provides a of dynamic property implementation for
1548184cd04cth * size oriented properties based on size64 value and blksize passed in by the
1549184cd04cth * driver.  Fallback to ddi_prop_op if the size64 is too large. This interface
1550184cd04cth * should not be used with a size64 that represents the driver's idea of how
1551184cd04cth * to represent unknown, if size is unknown use ddi_prop_op.
15527c478bdstevel@tonic-gate *
15537c478bdstevel@tonic-gate * NOTE: the legacy "nblocks"/"size" properties are treated as 32-bit unsigned
15547c478bdstevel@tonic-gate * integers. While the most likely interface to request them ([bc]devi_size)
15557c478bdstevel@tonic-gate * is declared int (signed) there is no enforcement of this, which means we
15567c478bdstevel@tonic-gate * can't enforce limitations here without risking regression.
15577c478bdstevel@tonic-gate */
15587c478bdstevel@tonic-gateint
1559184cd04cthddi_prop_op_size_blksize(dev_t dev, dev_info_t *dip, ddi_prop_op_t prop_op,
1560184cd04cth    int mod_flags, char *name, caddr_t valuep, int *lengthp, uint64_t size64,
1561184cd04cth    uint_t blksize)
15627c478bdstevel@tonic-gate{
15637c478bdstevel@tonic-gate	uint64_t nblocks64;
15647c478bdstevel@tonic-gate	int	callers_length;
15657c478bdstevel@tonic-gate	caddr_t	buffer;
1566184cd04cth	int	blkshift;
1567184cd04cth
1568b9ccdc5cth	/*
1569b9ccdc5cth	 * This is a kludge to support capture of size(9P) pure dynamic
1570b9ccdc5cth	 * properties in snapshots for non-cmlb code (without exposing
1571b9ccdc5cth	 * i_ddi_prop_dyn changes). When everyone uses cmlb, this code
1572b9ccdc5cth	 * should be removed.
1573b9ccdc5cth	 */
1574b9ccdc5cth	if (i_ddi_prop_dyn_driver_get(dip) == NULL) {
1575b9ccdc5cth		static i_ddi_prop_dyn_t prop_dyn_size[] = {
1576b9ccdc5cth		    {"Size",		DDI_PROP_TYPE_INT64,	S_IFCHR},
1577b9ccdc5cth		    {"Nblocks",		DDI_PROP_TYPE_INT64,	S_IFBLK},
1578b9ccdc5cth		    {NULL}
1579b9ccdc5cth		};
1580b9ccdc5cth		i_ddi_prop_dyn_driver_set(dip, prop_dyn_size);
1581b9ccdc5cth	}
1582b9ccdc5cth
1583184cd04cth	/* convert block size to shift value */
1584184cd04cth	ASSERT(BIT_ONLYONESET(blksize));
1585184cd04cth	blkshift = highbit(blksize) - 1;
15867c478bdstevel@tonic-gate
15877c478bdstevel@tonic-gate	/* compute DEV_BSIZE nblocks value */
1588184cd04cth	nblocks64 = size64 >> blkshift;
15897c478bdstevel@tonic-gate
15907c478bdstevel@tonic-gate	/* get callers length, establish length of our dynamic properties */
15917c478bdstevel@tonic-gate	callers_length = *lengthp;
15927c478bdstevel@tonic-gate
15937c478bdstevel@tonic-gate	if (strcmp(name, "Nblocks") == 0)
15947c478bdstevel@tonic-gate		*lengthp = sizeof (uint64_t);
15957c478bdstevel@tonic-gate	else if (strcmp(name, "Size") == 0)
15967c478bdstevel@tonic-gate		*lengthp = sizeof (uint64_t);
15977c478bdstevel@tonic-gate	else if ((strcmp(name, "nblocks") == 0) && (nblocks64 < UINT_MAX))
15987c478bdstevel@tonic-gate		*lengthp = sizeof (uint32_t);
15997c478bdstevel@tonic-gate	else if ((strcmp(name, "size") == 0) && (size64 < UINT_MAX))
16007c478bdstevel@tonic-gate		*lengthp = sizeof (uint32_t);
1601184cd04cth	else if ((strcmp(name, "blksize") == 0) && (blksize < UINT_MAX))
1602184cd04cth		*lengthp = sizeof (uint32_t);
16037c478bdstevel