sunddi.c revision 7b3700d1667b1178db936c8f0864fe50a502417e
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License (the "License").
* You may not use this file except in compliance with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2006 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <sys/autoconf.h>
#include <sys/pathname.h>
#include <sys/sysevent.h>
#include <sys/dacf_impl.h>
#include <sys/ddidevmap.h>
#include <sys/bootconf.h>
#include <sys/instance.h>
#include <sys/devpolicy.h>
extern pri_t minclsyspri;
extern rctl_hndl_t rc_project_devlockmem;
#ifdef DEBUG
static int sunddi_debug = 0;
#endif /* DEBUG */
/* ddi_umem_unlock miscellaneous */
static void i_ddi_umem_unlock_thread_start(void);
static kthread_t *ddi_umem_unlock_thread;
/*
* The ddi_umem_unlock FIFO list. NULL head pointer indicates empty list.
*/
/*
* This lock protects the project.max-device-locked-memory counter.
* When both p_lock (proc_t) and this lock need to acquired, p_lock
* should be acquired first.
*/
static kmutex_t umem_devlockmem_rctl_lock;
/*
* DDI(Sun) Function and flag definitions:
*/
#if defined(__x86)
/*
* Used to indicate which entries were chosen from a range.
*/
char *chosen_reg = "chosen-reg";
#endif
/*
* Function used to ring system console bell
*/
/*
* Creating register mappings and handling interrupts:
*/
/*
* Generic ddi_map: Call parent to fulfill request...
*/
int
{
}
/*
* ddi_apply_range: (Called by nexi only.)
* Apply ranges in parent node dp, to child regspec rp...
*/
int
{
}
int
{
#if defined(__x86)
struct {
int bus;
int addr;
int size;
int rc;
/*
* get the 'registers' or the 'reg' property.
* We look up the reg property as an array of
* int's.
*/
if (rc != DDI_PROP_SUCCESS)
if (rc == DDI_PROP_SUCCESS) {
/*
* point to the required entry.
*/
if (len != 0)
/*
* make a new property containing ONLY the required tuple.
*/
!= DDI_PROP_SUCCESS) {
}
/*
* free the memory allocated by
* ddi_prop_lookup_int_array ().
*/
ddi_prop_free((void *)reglist);
}
#endif
/*
* Call my parent to map in my regs.
*/
}
void
{
/*
* Call my parent to unmap my regs.
*/
#if defined(__x86)
#endif
}
int
{
}
/*
*
* If the call is to map by rnumber, return an error,
* otherwise pass anything else up the tree to my parent.
*/
int
{
return (DDI_ME_UNSUPPORTED);
}
/*
* ddi_rnumber_to_regspec: Not for use by leaf drivers.
*/
struct regspec *
{
}
/*
* Note that we allow the dip to be nil because we may be called
* prior even to the instantiation of the devinfo tree itself - all
* regular leaf and nexus drivers should always use a non-nil dip!
*
* We treat peek in a somewhat cavalier fashion .. assuming that we'll
* simply get a synchronous fault as soon as we touch a missing address.
*
* Poke is rather more carefully handled because we might poke to a write
* buffer, "succeed", then only find some time later that we got an
* asynchronous fault that indicated that the address we were writing to
* was not really backed by hardware.
*/
static int
{
union {
int rval;
/* Note: size is assumed to be correct; it is not checked. */
peekpoke_args.flags = 0;
if (cmd == DDI_CTLOPS_POKE) {
switch (size) {
case sizeof (uint8_t):
break;
case sizeof (uint16_t):
break;
case sizeof (uint32_t):
break;
case sizeof (uint64_t):
break;
}
}
&dummy_result);
else
/*
* A NULL value_p is permitted by ddi_peek(9F); discard the result.
*/
switch (size) {
case sizeof (uint8_t):
break;
case sizeof (uint16_t):
break;
case sizeof (uint32_t):
break;
case sizeof (uint64_t):
break;
}
}
return (rval);
}
/*
* Keep ddi_peek() and ddi_poke() in case 3rd parties are calling this.
* they shouldn't be, but the 9f manpage kind of pseudo exposes it.
*/
int
{
switch (size) {
case sizeof (uint8_t):
case sizeof (uint16_t):
case sizeof (uint32_t):
case sizeof (uint64_t):
break;
default:
return (DDI_FAILURE);
}
}
int
{
switch (size) {
case sizeof (uint8_t):
case sizeof (uint16_t):
case sizeof (uint32_t):
case sizeof (uint64_t):
break;
default:
return (DDI_FAILURE);
}
}
int
{
val_p));
}
int
{
val_p));
}
int
{
val_p));
}
int
{
val_p));
}
/*
* We need to separate the old interfaces from the new ones and leave them
* in here for a while. Previous versions of the OS defined the new interfaces
* to the old interfaces. This way we can fix things up so that we can
* eventually remove these interfaces.
* or earlier will actually have a reference to ddi_peekc in the binary.
*/
#ifdef _ILP32
int
{
val_p));
}
int
{
val_p));
}
int
{
val_p));
}
int
{
val_p));
}
#endif /* _ILP32 */
int
{
}
int
{
}
int
{
}
int
{
}
/*
* We need to separate the old interfaces from the new ones and leave them
* in here for a while. Previous versions of the OS defined the new interfaces
* to the old interfaces. This way we can fix things up so that we can
* eventually remove these interfaces.
* or earlier will actually have a reference to ddi_pokec in the binary.
*/
#ifdef _ILP32
int
{
}
int
{
}
int
{
}
int
{
}
#endif /* _ILP32 */
/*
* ddi_peekpokeio() is used primarily by the mem drivers for moving
* data to and from uio structures via peek and poke. Note that we
* use "internal" routines ddi_peek and ddi_poke to make this go
* slightly faster, avoiding the call overhead ..
*/
int
{
int o;
if (xfersize > sizeof (long))
xfersize = sizeof (long);
while (len != 0) {
return (DDI_FAILURE);
(int8_t)o) != DDI_SUCCESS)
return (DDI_FAILURE);
} else {
return (DDI_FAILURE);
return (DDI_FAILURE);
}
} else {
switch (xfersize) {
case sizeof (int64_t):
(sizeof (int64_t) - 1)) == 0) {
break;
}
/*FALLTHROUGH*/
case sizeof (int32_t):
(sizeof (int32_t) - 1)) == 0) {
break;
}
/*FALLTHROUGH*/
default:
/*
* This still assumes that we might have an
* I/O bus out there that permits 16-bit
* transfers (and that it would be upset by
* 32-bit transfers from such locations).
*/
break;
}
return (DDI_FAILURE);
}
return (DDI_FAILURE);
return (DDI_FAILURE);
}
}
}
return (DDI_SUCCESS);
}
/*
* These routines are used by drivers that do layered ioctls
* On sparc, they're implemented in assembler to avoid spilling
* register windows in the common (copyin) case ..
*/
#if !defined(__sparc)
int
{
}
int
{
}
#endif /* !__sparc */
/*
* Conversions in nexus pagesize units. We don't duplicate the
* routines anyway.
*/
unsigned long
{
unsigned long pages;
return (pages);
}
unsigned long
{
unsigned long pages;
return (pages);
}
unsigned long
{
unsigned long bytes;
return (bytes);
}
unsigned int
ddi_enter_critical(void)
{
}
void
ddi_exit_critical(unsigned int spl)
{
}
/*
* Nexus ctlops punter
*/
#if !defined(__sparc)
/*
* Request bus_ctl parent to handle a bus_ctl request
*
* (The sparc version is in sparc_ddi.s)
*/
int
{
int (*fp)();
if (!d || !r)
return (DDI_FAILURE);
return (DDI_FAILURE);
}
#endif
/*
*/
#if defined(__sparc)
static ddi_dma_lim_t standard_limits = {
(uint_t)0, /* addr_t dlim_addr_lo */
0 /* uint_t dlim_dmaspeed */
};
static ddi_dma_lim_t standard_limits = {
(uint_t)0, /* addr_t dlim_addr_lo */
(uint_t)0, /* uint_t dlim_cntr_max */
(uint_t)0, /* uint_t dlim_dmaspeed */
(int)1, /* int dlim_sgllen */
};
#endif
int
{
int (*funcp)() = ddi_dma_map;
#if defined(__sparc)
auto ddi_dma_lim_t dma_lim;
} else {
}
#endif
#if defined(__x86)
return (DDI_FAILURE);
#endif
/*
* Handle the case that the requester is both a leaf
* and a nexus driver simultaneously by calling the
* requester's bus_dma_map function directly instead
* of ddi_dma_map.
*/
}
int
{
int (*funcp)() = ddi_dma_map;
struct ddi_dma_req dmareq;
if (len == 0) {
return (DDI_DMA_NOMAPPING);
}
if (limits == (ddi_dma_lim_t *)0) {
} else {
}
/*
* Handle the case that the requester is both a leaf
* and a nexus driver simultaneously by calling the
* requester's bus_dma_map function directly instead
* of ddi_dma_map.
*/
}
int
{
int (*funcp)() = ddi_dma_map;
struct ddi_dma_req dmareq;
if (limits == (ddi_dma_lim_t *)0) {
} else {
}
} else {
} else {
}
/*
* If the buffer has no proc pointer, or the proc
* struct has the kernel address space, or the buffer has
* been marked B_REMAPPED (meaning that it is now
* mapped into the kernel's address space), then
* the address space is kas (kernel address space).
*/
} else {
}
}
/*
* Handle the case that the requester is both a leaf
* and a nexus driver simultaneously by calling the
* requester's bus_dma_map function directly instead
* of ddi_dma_map.
*/
}
#if !defined(__sparc)
/*
* Request bus_dma_ctl parent to fiddle with a dma request.
*
* (The sparc version is in sparc_subr.s)
*/
int
{
int (*fp)();
}
#endif
/*
* For all DMA control functions, call the DMA control
* routine and return status.
*
* Just plain assume that the parent is to be called.
* If a nexus driver or a thread outside the framework
* of a nexus driver or a leaf driver calls these functions,
* it is up to them to deal with the fact that the parent's
* bus_dma_ctl function will be the first one called.
*/
int
{
}
int
{
}
int
{
}
int
{
l, (caddr_t *)c, 0));
}
int
{
return (DDI_FAILURE);
}
int
{
}
int
{
}
/*
* This routine is Obsolete and should be removed from ALL architectures
* in a future release of Solaris.
*
* It is deliberately NOT ported to amd64; please fix the code that
* depends on this routine to use ddi_dma_nextcookie(9F).
*
* NOTE: even though we fixed the pointer through a 32-bit param issue (the fix
* is a side effect to some other cleanup), we're still not going to support
* this interface on x64.
*/
int
{
}
#endif /* (__i386 && !__amd64) || __sparc */
#if !defined(__sparc)
/*
* The SPARC versions of these routines are done in assembler to
* save register windows, so they're in sparc_subr.s.
*/
int
{
ddi_dma_handle_t *);
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
}
int
{
/*
* the DMA nexus driver will set DMP_NOSYNC if the
* platform does not require any sync operation. For
* example if the memory is uncached or consistent
* and without any I/O write buffers involved.
*/
return (DDI_SUCCESS);
}
int
{
}
#endif /* !__sparc */
int
{
}
int
{
if (!limp) {
}
}
void
{
}
int
{
if (!limits) {
}
}
void
{
}
/*
* DMA attributes, alignment, burst sizes, and transfer minimums
*/
int
{
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
int
{
if (!dimp)
return (0);
else
return (dimp->dmai_burstsizes);
}
int
{
return (DDI_FAILURE);
} else {
} else {
}
}
return (DDI_SUCCESS);
}
int
{
int r;
/*
* Make sure that the initial value is sane
*/
if (i & (i - 1))
return (0);
if (i == 0)
r = ddi_ctlops(a, a,
if (r != DDI_SUCCESS || (i & (i - 1)))
return (0);
return (i);
}
/*
* Given two DMA attribute structures, apply the attributes
* of one to the other, following the rules of attributes
* and the wishes of the caller.
*
* The rules of DMA attribute structures are that you cannot
* make things *less* restrictive as you apply one set
* of attributes to another.
*
*/
void
{
}
/*
*/
/*
* ddi_segmap: setup the default segment driver. Calls the drivers
* XXmmap routine to validate the range to be mapped.
* Return ENXIO of the range is not valid. Create
* a seg_dev segment that contains all of the
* necessary information and will reference the
* default segment driver routines. It returns zero
* on success or non-zero on failure.
*/
int
{
}
/*
* ddi_map_fault: Resolve mappings at fault time. Used by segment
* drivers. Allows each successive parent to resolve
* address translations and add its mappings to the
* mapping list supplied in the page structure. It
* returns zero on success or non-zero on failure.
*/
int
{
}
/*
* ddi_device_mapping_check: Called from ddi_segmap_setup.
* Invokes platform specific DDI to determine whether attributes specified
* in attr(9s) are valid for the region of memory that will be made
* available for direct access to user process via the mmap(2) system call.
*/
int
{
int result;
/*
* we use e_ddi_hold_devi_by_dev to search for the devi. We
* release it immediately since it should already be held by
* a devfs vnode.
*/
if ((dip =
return (-1);
/*
* Allocate and initialize the common elements of data
* access handle.
*/
return (-1);
/*
* Set up the mapping request and call to parent.
*/
/*
* Region must be mappable, pick up flags from the framework.
*/
/*
* check for end result.
*/
if (result != DDI_SUCCESS)
return (-1);
return (0);
}
/*
* Property functions: See also, ddipropdefs.h.
*
* These functions are the framework for the property functions,
* i.e. they support software defined properties. All implementation
* specific property handling (i.e.: self-identifying devices and
* PROM defined properties are handled in the implementation specific
* functions (defined in ddi_implfuncs.h).
*/
/*
* nopropop: Shouldn't be called, right?
*/
int
{
return (DDI_PROP_NOT_FOUND);
}
#ifdef DDI_PROP_DEBUG
int ddi_prop_debug_flag = 0;
int
ddi_prop_debug(int enable)
{
int prev = ddi_prop_debug_flag;
printf("ddi_prop_debug: debugging %s\n",
return (prev);
}
#endif /* DDI_PROP_DEBUG */
/*
* Search a property list for a match, if found return pointer
* to matching prop struct, else return NULL.
*/
{
/*
* find the property in child's devinfo:
* Search order defined by this search function is first matching
* property with input dev == DDI_DEV_T_ANY matching any dev or
* dev == propp->prop_dev, name == propp->name, and the correct
* data type as specified in the flags. If a DDI_DEV_T_NONE dev
* value made it this far then it implies a DDI_DEV_T_ANY search.
*/
if (dev == DDI_DEV_T_NONE)
dev = DDI_DEV_T_ANY;
continue;
continue;
continue;
return (propp);
}
return ((ddi_prop_t *)0);
}
/*
* Search for property within devnames structures
*/
{
/*
* Valid dev_t value is needed to index into the
* correct devnames entry, therefore a dev_t
* value of DDI_DEV_T_ANY is not appropriate.
*/
if (dev == DDI_DEV_T_ANY) {
return ((ddi_prop_t *)0);
}
return ((ddi_prop_t *)0);
continue;
continue;
continue;
/* Property found, return it */
return (propp);
}
return ((ddi_prop_t *)0);
}
static char prop_no_mem_msg[] = "can't allocate memory for ddi property <%s>";
/*
* ddi_prop_search_global:
* Search the global property list within devnames
* for the named property. Return the encoded value.
*/
static int
{
/* Property NOT found, bail */
if (propp == (ddi_prop_t *)0)
return (DDI_PROP_NOT_FOUND);
return (DDI_PROP_UNDEFINED);
return (DDI_PROP_NO_MEMORY);
}
/*
* Return the encoded data
*/
return (DDI_PROP_SUCCESS);
}
/*
* ddi_prop_search_common: Lookup and return the encoded value
*/
int
{
int i;
int plength = 0;
int (*bop)();
/*CONSTANTCONDITION*/
while (1) {
/*
* find the property in child's devinfo:
* Search order is:
* 1. driver defined properties
* 2. system defined properties
* 3. driver global properties
* 4. boot defined properties
*/
}
}
}
/*
* Software property found?
*/
if (propp != (ddi_prop_t *)0) {
/*
* If explicit undefine, return now.
*/
if (prealloc)
return (DDI_PROP_UNDEFINED);
}
/*
* If we only want to know if it exists, return now
*/
if (prop_op == PROP_EXISTS) {
return (DDI_PROP_SUCCESS);
}
/*
* If length only request or prop length == 0,
* service request and return now.
*/
/*
* if prop_op is PROP_LEN_AND_VAL_ALLOC
* that means prop_len is 0, so set valuep
* also to NULL
*/
if (prop_op == PROP_LEN_AND_VAL_ALLOC)
if (prealloc)
return (DDI_PROP_SUCCESS);
}
/*
* If LEN_AND_VAL_ALLOC and the request can sleep,
* drop the mutex, allocate the buffer, and go
* through the loop again. If we already allocated
* the buffer, and the size of the property changed,
* keep trying...
*/
if ((prop_op == PROP_LEN_AND_VAL_ALLOC) &&
(flags & DDI_PROP_CANSLEEP)) {
}
KM_SLEEP);
continue;
}
}
/*
* Allocate buffer, if required. Either way,
* set `buffer' variable.
*/
i = *lengthp; /* Get callers length */
switch (prop_op) {
case PROP_LEN_AND_VAL_ALLOC:
} else {
}
return (DDI_PROP_NO_MEMORY);
}
/* Set callers buf ptr */
break;
case PROP_LEN_AND_VAL_BUF:
return (DDI_PROP_BUF_TOO_SMALL);
}
break;
default:
break;
}
/*
* Do the copy.
*/
return (DDI_PROP_SUCCESS);
}
if (prealloc)
/*
* Prop not found, call parent bus_ops to deal with possible
* h/w layer (possible PROM defined props, etc.) and to
* possibly ascend the hierarchy, if allowed by flags.
*/
/*
* One last call for the root driver PROM props?
*/
if (dip == ddi_root_node()) {
}
/*
* We may have been called to check for properties
* within a single devinfo node that has no parent -
* see make_prop()
*/
(DDI_PROP_DONTPASS | DDI_PROP_NOTPROM)) ==
return (DDI_PROP_NOT_FOUND);
}
/*
* Instead of recursing, we do iterative calls up the tree.
* As a bit of optimization, skip the bus_op level if the
* node is a s/w node and if the parent's bus_prop_op function
* is `ddi_bus_prop_op', because we know that in this case,
* this function does nothing.
*
* 4225415: If the parent isn't attached, or the child
* hasn't been named by the parent yet, use the default
* ddi_bus_prop_op as a proxy for the parent. This
* include 'prom' and inherited properties, even when
* there are no drivers attached to the child or parent.
*/
if (i_ddi_devi_attached(pdip) &&
i = DDI_PROP_NOT_FOUND;
}
if ((flags & DDI_PROP_DONTPASS) ||
(i != DDI_PROP_NOT_FOUND))
return (i);
}
/*NOTREACHED*/
}
/*
* ddi_prop_op: The basic property operator for drivers.
*
* In ddi_prop_op, the type of valuep is interpreted based on prop_op:
*
* prop_op valuep
* ------ ------
*
* PROP_LEN <unused>
*
* PROP_LEN_AND_VAL_BUF Pointer to callers buffer
*
* PROP_LEN_AND_VAL_ALLOC Address of callers pointer (will be set to
* address of allocated buffer, if successful)
*/
int
{
int i;
/*
* If this was originally an LDI prop lookup then we bail here.
* The reason is that the LDI property lookup interfaces first call
* a drivers prop_op() entry point to allow it to override
* properties. But if we've made it here, then the driver hasn't
* overriden any properties. We don't want to continue with the
* property search here because we don't have any type inforamtion.
* When we return failure, the LDI interfaces will then proceed to
* call the typed property interfaces to look up the property.
*/
if (mod_flags & DDI_PROP_DYNAMIC)
return (DDI_PROP_NOT_FOUND);
/*
* check for pre-typed property consumer asking for typed property:
* see e_ddi_getprop_int64.
*/
if (mod_flags & DDI_PROP_CONSUMER_TYPED)
if (i == DDI_PROP_FOUND_1275)
return (DDI_PROP_SUCCESS);
return (i);
}
/*
* ddi_prop_op_nblocks: The basic property operator for drivers that maintain
* size in number of DEV_BSIZE blocks. Provides a dynamic property
* implementation for size oriented properties based on nblocks64 values passed
* in by the driver. Fallback to ddi_prop_op if the nblocks64 is too large.
* This interface should not be used with a nblocks64 that represents the
* driver's idea of how to represent unknown, if nblocks is unknown use
* ddi_prop_op.
*/
int
{
/*
* There is no point in supporting nblocks64 values that don't have
* an accurate uint64_t byte count representation.
*/
}
/*
* ddi_prop_op_size: The basic property operator for drivers that maintain size
* in bytes. Provides a of dynamic property implementation for size oriented
* properties based on size64 values passed in by the driver. Fallback to
* ddi_prop_op if the size64 is too large. This interface should not be used
* with a size64 that represents the driver's idea of how to represent unknown,
* if size is unknown use ddi_prop_op.
*
* NOTE: the legacy "nblocks"/"size" properties are treated as 32-bit unsigned
* integers. While the most likely interface to request them ([bc]devi_size)
* is declared int (signed) there is no enforcement of this, which means we
* can't enforce limitations here without risking regression.
*/
int
{
int callers_length;
/* compute DEV_BSIZE nblocks value */
/* get callers length, establish length of our dynamic properties */
else {
/* fallback to ddi_prop_op */
}
/* service request for the length of the property */
return (DDI_PROP_SUCCESS);
/* the length of the property and the request must match */
if (callers_length != *lengthp)
return (DDI_PROP_INVAL_ARG);
switch (prop_op) {
case PROP_LEN_AND_VAL_ALLOC:
(mod_flags & DDI_PROP_CANSLEEP) ?
return (DDI_PROP_NO_MEMORY);
break;
case PROP_LEN_AND_VAL_BUF:
break;
default:
return (DDI_PROP_INVAL_ARG);
}
/* transfer the value into the buffer */
return (DDI_PROP_SUCCESS);
}
/*
* Variable length props...
*/
/*
* ddi_getlongprop: Get variable length property len+val into a buffer
* allocated by property provider via kmem_alloc. Requester
* is responsible for freeing returned property via kmem_free.
*
* Arguments:
*
* dev_t: Input: dev_t of property.
* dip: Input: dev_info_t pointer of child.
* flags: Input: Possible flag modifiers are:
* DDI_PROP_DONTPASS: Don't pass to parent if prop not found.
* DDI_PROP_CANSLEEP: Memory allocation may sleep.
* name: Input: name of property.
* valuep: Output: Addr of callers buffer pointer.
* lengthp:Output: *lengthp will contain prop length on exit.
*
* Possible Returns:
*
* DDI_PROP_SUCCESS: Prop found and returned.
* DDI_PROP_NOT_FOUND: Prop not found
* DDI_PROP_UNDEFINED: Prop explicitly undefined.
* DDI_PROP_NO_MEMORY: Prop found, but unable to alloc mem.
*/
int
{
}
/*
*
* ddi_getlongprop_buf: Get long prop into pre-allocated callers
* buffer. (no memory allocation by provider).
*
* dev_t: Input: dev_t of property.
* dip: Input: dev_info_t pointer of child.
* flags: Input: DDI_PROP_DONTPASS or NULL
* name: Input: name of property
* valuep: Input: ptr to callers buffer.
* lengthp:I/O: ptr to length of callers buffer on entry,
* actual length of property on exit.
*
* Possible returns:
*
* DDI_PROP_SUCCESS Prop found and returned
* DDI_PROP_NOT_FOUND Prop not found
* DDI_PROP_UNDEFINED Prop explicitly undefined.
* DDI_PROP_BUF_TOO_SMALL Prop found, callers buf too small,
* no value returned, but actual prop
* length returned in *lengthp
*
*/
int
{
}
/*
*
* Call is value only... returns found boolean or int sized prop value or
* defvalue if prop not found or is wrong length or is explicitly undefined.
* Only flag is DDI_PROP_DONTPASS...
*
* By convention, this interface returns boolean (0) sized properties
* as value (int)1.
*
* This never returns an error, if property not found or specifically
* undefined, the input `defvalue' is returned.
*/
int
{
int proplength = sizeof (int);
int error;
propvalue = 1;
return (propvalue);
}
/*
* Get prop length interface: flags are 0 or DDI_PROP_DONTPASS
* if returns DDI_PROP_SUCCESS, length returned in *lengthp.
*/
int
{
}
/*
* Allocate a struct prop_driver_data, along with 'size' bytes
* for decoded property data. This structure is freed by
* calling ddi_prop_free(9F).
*/
static void *
{
struct prop_driver_data *pdd;
/*
* Allocate a structure with enough memory to store the decoded data.
*/
/*
* Return a pointer to the location to put the decoded data.
*/
}
/*
* Allocated the memory needed to store the encoded data in the property
* handle.
*/
static int
{
/*
* If size is zero, then set data to NULL and size to 0. This
* is a boolean property.
*/
if (size == 0) {
} else {
return (DDI_PROP_NO_MEMORY);
} else
}
return (DDI_PROP_SUCCESS);
}
/*
* Free the space allocated by the lookup routines. Each lookup routine
* returns a pointer to the decoded data to the driver. The driver then
* passes this pointer back to us. This data actually lives in a struct
* prop_driver_data. We use negative indexing to find the beginning of
* the structure and then free the entire structure using the size and
* the free routine stored in the structure.
*/
void
ddi_prop_free(void *datap)
{
struct prop_driver_data *pdd;
/*
* Get the structure
*/
pdd = (struct prop_driver_data *)
/*
* Call the free routine to free it
*/
}
/*
* Free the data associated with an array of ints,
* allocated with ddi_prop_decode_alloc().
*/
static void
{
}
/*
* Free a single string property or a single string contained within
* the argv style return value of an array of strings.
*/
static void
{
}
/*
* Free an array of strings.
*/
static void
{
}
/*
* Free the data associated with an array of bytes.
*/
static void
{
}
/*
* Reset the current location pointer in the property handle to the
* beginning of the data.
*/
void
{
}
/*
* Restore the current location pointer in the property handle to the
* saved position.
*/
void
{
}
/*
* Save the location that the current location pointer is pointing to..
*/
void
{
}
/*
*/
/*
* Decode a single integer property
*/
static int
{
int i;
int tmp;
/*
* If there is nothing to decode return an error
*/
return (DDI_PROP_END_OF_DATA);
/*
* Decode the property as a single integer and return it
* in data if we were able to decode it.
*/
if (i < DDI_PROP_RESULT_OK) {
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
*nelements = 1;
return (DDI_PROP_SUCCESS);
}
/*
* Decode a single 64 bit integer property
*/
static int
{
int i;
/*
* If there is nothing to decode return an error
*/
return (DDI_PROP_END_OF_DATA);
/*
* Decode the property as a single integer and return it
* in data if we were able to decode it.
*/
if (i < DDI_PROP_RESULT_OK) {
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
*nelements = 1;
return (DDI_PROP_SUCCESS);
}
/*
* Decode an array of integers property
*/
static int
{
int i;
int cnt = 0;
int *tmp;
int *intp;
int n;
/*
* Figure out how many array elements there are by going through the
* data without decoding it first and counting.
*/
for (;;) {
if (i < 0)
break;
cnt++;
}
/*
* If there are no elements return an error
*/
if (cnt == 0)
return (DDI_PROP_END_OF_DATA);
/*
* If we cannot skip through the data, we cannot decode it
*/
if (i == DDI_PROP_RESULT_ERROR)
return (DDI_PROP_CANNOT_DECODE);
/*
* Reset the data pointer to the beginning of the encoded data
*/
/*
* Allocated memory to store the decoded value in.
*/
/*
* Decode each element and place it in the space we just allocated
*/
if (i < DDI_PROP_RESULT_OK) {
/*
* Free the space we just allocated
* and return an error.
*/
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
}
return (DDI_PROP_SUCCESS);
}
/*
* Decode a 64 bit integer array property
*/
static int
{
int i;
int n;
int cnt = 0;
/*
* Count the number of array elements by going
* through the data without decoding it.
*/
for (;;) {
if (i < 0)
break;
cnt++;
}
/*
* If there are no elements return an error
*/
if (cnt == 0)
return (DDI_PROP_END_OF_DATA);
/*
* If we cannot skip through the data, we cannot decode it
*/
if (i == DDI_PROP_RESULT_ERROR)
return (DDI_PROP_CANNOT_DECODE);
/*
* Reset the data pointer to the beginning of the encoded data
*/
/*
* Allocate memory to store the decoded value.
*/
/*
* Decode each element and place it in the space allocated
*/
if (i < DDI_PROP_RESULT_OK) {
/*
* Free the space we just allocated
* and return an error.
*/
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
}
return (DDI_PROP_SUCCESS);
}
/*
* Encode an array of integers property (Can be one element)
*/
int
{
int i;
int *tmp;
int cnt;
int size;
/*
* If there is no data, we cannot do anything
*/
if (nelements == 0)
return (DDI_PROP_CANNOT_ENCODE);
/*
* Get the size of an encoded int.
*/
if (size < DDI_PROP_RESULT_OK) {
switch (size) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_ENCODE);
}
}
/*
* Allocate space in the handle to store the encoded int.
*/
return (DDI_PROP_NO_MEMORY);
/*
* Encode the array of ints.
*/
if (i < DDI_PROP_RESULT_OK) {
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_ENCODE);
}
}
}
return (DDI_PROP_SUCCESS);
}
/*
* Encode a 64 bit integer array property
*/
int
{
int i;
int cnt;
int size;
/*
* If there is no data, we cannot do anything
*/
if (nelements == 0)
return (DDI_PROP_CANNOT_ENCODE);
/*
* Get the size of an encoded 64 bit int.
*/
if (size < DDI_PROP_RESULT_OK) {
switch (size) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_ENCODE);
}
}
/*
* Allocate space in the handle to store the encoded int.
*/
return (DDI_PROP_NO_MEMORY);
/*
* Encode the array of ints.
*/
if (i < DDI_PROP_RESULT_OK) {
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_ENCODE);
}
}
}
return (DDI_PROP_SUCCESS);
}
/*
* Decode a single string property
*/
static int
{
char *tmp;
char *str;
int i;
int size;
/*
* If there is nothing to decode return an error
*/
return (DDI_PROP_END_OF_DATA);
/*
* Get the decoded size of the encoded string.
*/
if (size < DDI_PROP_RESULT_OK) {
switch (size) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
/*
* Allocated memory to store the decoded value in.
*/
/*
* Decode the str and place it in the space we just allocated
*/
if (i < DDI_PROP_RESULT_OK) {
/*
* Free the space we just allocated
* and return an error.
*/
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
*nelements = 1;
return (DDI_PROP_SUCCESS);
}
/*
* Decode an array of strings.
*/
int
{
int cnt = 0;
char **strs;
char **tmp;
char *ptr;
int i;
int n;
int size;
/*
* Figure out how many array elements there are by going through the
* data without decoding it first and counting.
*/
for (;;) {
if (i < 0)
break;
cnt++;
}
/*
* If there are no elements return an error
*/
if (cnt == 0)
return (DDI_PROP_END_OF_DATA);
/*
* If we cannot skip through the data, we cannot decode it
*/
if (i == DDI_PROP_RESULT_ERROR)
return (DDI_PROP_CANNOT_DECODE);
/*
* Reset the data pointer to the beginning of the encoded data
*/
/*
* Figure out how much memory we need for the sum total
*/
for (n = 0; n < cnt; n++) {
/*
* Get the decoded size of the current encoded string.
*/
if (size < DDI_PROP_RESULT_OK) {
switch (size) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
}
/*
* Allocate memory in which to store the decoded strings.
*/
/*
* Set up pointers for each string by figuring out yet
* again how long each string is.
*/
/*
* Get the decoded size of the current encoded string.
*/
if (size < DDI_PROP_RESULT_OK) {
switch (size) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
}
/*
* String array is terminated by a NULL
*/
/*
* Finally, we can decode each string
*/
if (i < DDI_PROP_RESULT_OK) {
/*
* Free the space we just allocated
* and return an error
*/
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
}
return (DDI_PROP_SUCCESS);
}
/*
* Encode a string.
*/
int
{
char **tmp;
int size;
int i;
/*
* If there is no data, we cannot do anything
*/
if (nelements == 0)
return (DDI_PROP_CANNOT_ENCODE);
/*
* Get the size of the encoded string.
*/
if (size < DDI_PROP_RESULT_OK) {
switch (size) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_ENCODE);
}
}
/*
* Allocate space in the handle to store the encoded string.
*/
return (DDI_PROP_NO_MEMORY);
/*
* Encode the string.
*/
if (i < DDI_PROP_RESULT_OK) {
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_ENCODE);
}
}
return (DDI_PROP_SUCCESS);
}
/*
* Encode an array of strings.
*/
int
{
int cnt = 0;
char **tmp;
int size;
int i;
/*
* If there is no data, we cannot do anything
*/
if (nelements == 0)
return (DDI_PROP_CANNOT_ENCODE);
/*
* Get the total size required to encode all the strings.
*/
total_size = 0;
if (size < DDI_PROP_RESULT_OK) {
switch (size) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_ENCODE);
}
}
}
/*
* Allocate space in the handle to store the encoded strings.
*/
return (DDI_PROP_NO_MEMORY);
/*
* Encode the array of strings.
*/
if (i < DDI_PROP_RESULT_OK) {
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_ENCODE);
}
}
}
return (DDI_PROP_SUCCESS);
}
/*
* Decode an array of bytes.
*/
static int
{
int nbytes;
int i;
/*
* If there are no elements return an error
*/
return (DDI_PROP_END_OF_DATA);
/*
* Get the size of the encoded array of bytes.
*/
if (nbytes < DDI_PROP_RESULT_OK) {
switch (nbytes) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
/*
* Allocated memory to store the decoded value in.
*/
/*
* Decode each element and place it in the space we just allocated
*/
if (i < DDI_PROP_RESULT_OK) {
/*
* Free the space we just allocated
* and return an error
*/
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
return (DDI_PROP_SUCCESS);
}
/*
* Encode an array of bytes.
*/
int
{
int size;
int i;
/*
* If there are no elements, then this is a boolean property,
* so just create a property handle with no data and return.
*/
if (nelements == 0) {
(void) ddi_prop_encode_alloc(ph, 0);
return (DDI_PROP_SUCCESS);
}
/*
* Get the size of the encoded array of bytes.
*/
if (size < DDI_PROP_RESULT_OK) {
switch (size) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_DECODE);
}
}
/*
* Allocate space in the handle to store the encoded bytes.
*/
return (DDI_PROP_NO_MEMORY);
/*
* Encode the array of bytes.
*/
if (i < DDI_PROP_RESULT_OK) {
switch (i) {
case DDI_PROP_RESULT_EOF:
return (DDI_PROP_END_OF_DATA);
case DDI_PROP_RESULT_ERROR:
return (DDI_PROP_CANNOT_ENCODE);
}
}
return (DDI_PROP_SUCCESS);
}
/*
* OBP 1275 integer, string and byte operators.
*
* DDI_PROP_CMD_DECODE:
*
* DDI_PROP_RESULT_ERROR: cannot decode the data
* DDI_PROP_RESULT_EOF: end of data
* DDI_PROP_OK: data was decoded
*
* DDI_PROP_CMD_ENCODE:
*
* DDI_PROP_RESULT_ERROR: cannot encode the data
* DDI_PROP_RESULT_EOF: end of data
* DDI_PROP_OK: data was encoded
*
* DDI_PROP_CMD_SKIP:
*
* DDI_PROP_RESULT_ERROR: cannot skip the data
* DDI_PROP_RESULT_EOF: end of data
* DDI_PROP_OK: data was skipped
*
* DDI_PROP_CMD_GET_ESIZE:
*
* DDI_PROP_RESULT_ERROR: cannot get encoded size
* DDI_PROP_RESULT_EOF: end of data
* > 0: the encoded size
*
* DDI_PROP_CMD_GET_DSIZE:
*
* DDI_PROP_RESULT_ERROR: cannot get decoded size
* DDI_PROP_RESULT_EOF: end of data
* > 0: the decoded size
*/
/*
* OBP 1275 integer operator
*
* OBP properties are a byte stream of data, so integers may not be
* properly aligned. Therefore we need to copy them one byte at a time.
*/
int
{
int i;
switch (cmd) {
case DDI_PROP_CMD_DECODE:
/*
* Check that there is encoded data
*/
return (DDI_PROP_RESULT_ERROR);
return (DDI_PROP_RESULT_ERROR);
} else {
return (DDI_PROP_RESULT_ERROR);
}
/*
* Copy the integer, using the implementation-specific
* copy function if the property is coming from the PROM.
*/
} else {
}
/*
* Move the current location to the start of the next
* bit of undecoded data.
*/
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_ENCODE:
/*
* Check that there is room to encoded the data
*/
return (DDI_PROP_RESULT_ERROR);
/*
* Encode the integer into the byte stream one byte at a
* time.
*/
/*
* Move the current location to the start of the next bit of
* space where we can store encoded data.
*/
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_SKIP:
/*
* Check that there is encoded data
*/
return (DDI_PROP_RESULT_ERROR);
return (DDI_PROP_RESULT_EOF);
return (DDI_PROP_RESULT_EOF);
}
/*
* Move the current location to the start of the next bit of
* undecoded data.
*/
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_GET_ESIZE:
/*
* Return the size of an encoded integer on OBP
*/
return (PROP_1275_INT_SIZE);
case DDI_PROP_CMD_GET_DSIZE:
/*
* Return the size of a decoded integer on the system.
*/
return (sizeof (int));
default:
#ifdef DEBUG
/*NOTREACHED*/
#else
return (DDI_PROP_RESULT_ERROR);
#endif /* DEBUG */
}
}
/*
* 64 bit integer operator.
*
* This is an extension, defined by Sun, to the 1275 integer
* 64 bit integer properties.
*/
int
{
switch (cmd) {
case DDI_PROP_CMD_DECODE:
/*
* Check that there is encoded data
*/
return (DDI_PROP_RESULT_ERROR);
return (DDI_PROP_RESULT_ERROR);
} else {
return (DDI_PROP_RESULT_ERROR);
}
/*
* Copy the integer, using the implementation-specific
* copy function if the property is coming from the PROM.
*/
return (DDI_PROP_RESULT_ERROR);
} else {
}
/*
* Move the current location to the start of the next
* bit of undecoded data.
*/
sizeof (int64_t);
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_ENCODE:
/*
* Check that there is room to encoded the data
*/
return (DDI_PROP_RESULT_ERROR);
/*
* Encode the integer into the byte stream one byte at a
* time.
*/
/*
* Move the current location to the start of the next bit of
* space where we can store encoded data.
*/
sizeof (int64_t);
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_SKIP:
/*
* Check that there is encoded data
*/
return (DDI_PROP_RESULT_ERROR);
return (DDI_PROP_RESULT_EOF);
return (DDI_PROP_RESULT_EOF);
}
/*
* Move the current location to the start of
* the next bit of undecoded data.
*/
sizeof (int64_t);
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_GET_ESIZE:
/*
* Return the size of an encoded integer on OBP
*/
return (sizeof (int64_t));
case DDI_PROP_CMD_GET_DSIZE:
/*
* Return the size of a decoded integer on the system.
*/
return (sizeof (int64_t));
default:
#ifdef DEBUG
/*NOTREACHED*/
#else
return (DDI_PROP_RESULT_ERROR);
#endif /* DEBUG */
}
}
/*
* OBP 1275 string operator.
*
* OBP strings are NULL terminated.
*/
int
{
int n;
char *p;
char *end;
switch (cmd) {
case DDI_PROP_CMD_DECODE:
/*
* Check that there is encoded data
*/
return (DDI_PROP_RESULT_ERROR);
}
/*
* Match DDI_PROP_CMD_GET_DSIZE logic for when to stop and
* how to NULL terminate result.
*/
p = (char *)ph->ph_cur_pos;
if (p >= end)
return (DDI_PROP_RESULT_EOF);
while (p < end) {
*data++ = *p;
if (*p++ == 0) { /* NULL from OBP */
ph->ph_cur_pos = p;
return (DDI_PROP_RESULT_OK);
}
}
/*
* If OBP did not NULL terminate string, which happens
* (at least) for 'true'/'false' boolean values, account for
* the space and store null termination on decode.
*/
ph->ph_cur_pos = p;
*data = 0;
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_ENCODE:
/*
* Check that there is room to encoded the data
*/
return (DDI_PROP_RESULT_ERROR);
}
return (DDI_PROP_RESULT_ERROR);
}
/*
* Copy the NULL terminated string
*/
/*
* Move the current location to the start of the next bit of
* space where we can store encoded data.
*/
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_SKIP:
/*
* Check that there is encoded data
*/
return (DDI_PROP_RESULT_ERROR);
}
/*
* Return the string length plus one for the NULL
* We know the size of the property, we need to
* ensure that the string is properly formatted,
* since we may be looking up random OBP data.
*/
p = (char *)ph->ph_cur_pos;
if (p >= end)
return (DDI_PROP_RESULT_EOF);
while (p < end) {
if (*p++ == 0) { /* NULL from OBP */
ph->ph_cur_pos = p;
return (DDI_PROP_RESULT_OK);
}
}
/*
* Accommodate the fact that OBP does not always NULL
* terminate strings.
*/
ph->ph_cur_pos = p;
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_GET_ESIZE:
/*
* Return the size of the encoded string on OBP.
*/
case DDI_PROP_CMD_GET_DSIZE:
/*
* Return the string length plus one for the NULL.
* We know the size of the property, we need to
* ensure that the string is properly formatted,
* since we may be looking up random OBP data.
*/
p = (char *)ph->ph_cur_pos;
if (p >= end)
return (DDI_PROP_RESULT_EOF);
for (n = 0; p < end; n++) {
if (*p++ == 0) { /* NULL from OBP */
ph->ph_cur_pos = p;
return (n + 1);
}
}
/*
* If OBP did not NULL terminate string, which happens for
* 'true'/'false' boolean values, account for the space
* to store null termination here.
*/
ph->ph_cur_pos = p;
return (n + 1);
default:
#ifdef DEBUG
/*NOTREACHED*/
#else
return (DDI_PROP_RESULT_ERROR);
#endif /* DEBUG */
}
}
/*
* OBP 1275 byte operator
*
* Caller must specify the number of bytes to get. OBP encodes bytes
* as a byte so there is a 1-to-1 translation.
*/
int
{
switch (cmd) {
case DDI_PROP_CMD_DECODE:
/*
* Check that there is encoded data
*/
return (DDI_PROP_RESULT_ERROR);
/*
* Copy out the bytes
*/
/*
* Move the current location
*/
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_ENCODE:
/*
* Check that there is room to encode the data
*/
return (DDI_PROP_RESULT_ERROR);
/*
* Copy in the bytes
*/
/*
* Move the current location to the start of the next bit of
* space where we can store encoded data.
*/
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_SKIP:
/*
* Check that there is encoded data
*/
return (DDI_PROP_RESULT_ERROR);
return (DDI_PROP_RESULT_EOF);
/*
* Move the current location
*/
return (DDI_PROP_RESULT_OK);
case DDI_PROP_CMD_GET_ESIZE:
/*
* The size in bytes of the encoded size is the
* same as the decoded size provided by the caller.
*/
return (nelements);
case DDI_PROP_CMD_GET_DSIZE:
/*
* Just return the number of bytes specified by the caller.
*/
return (nelements);
default:
#ifdef DEBUG
/*NOTREACHED*/
#else
return (DDI_PROP_RESULT_ERROR);
#endif /* DEBUG */
}
}
/*
* Used for properties that come from the OBP, hardware configuration files,
* or that are created by calls to ddi_prop_update(9F).
*/
static struct prop_handle_ops prop_1275_ops = {
};
/*
* Flags interpreted are:
* DDI_PROP_CANSLEEP: Allow memory allocation to sleep.
* DDI_PROP_SYSTEM_DEF: Manipulate system list rather than driver list.
*
* Use same dev_t when modifying or undefining a property.
* Search for properties with DDI_DEV_T_ANY to match first named
* property on the list.
*
* Properties are stored LIFO and subsequently will match the first
* `matching' instance.
*/
/*
* ddi_prop_add: Add a software defined property
*/
/*
* define to get a new ddi_prop_t.
* km_flags are KM_SLEEP or KM_NOSLEEP.
*/
#define DDI_NEW_PROP_T(km_flags) \
static int
{
int km_flags = KM_NOSLEEP;
int name_buf_len;
/*
* If dev_t is DDI_DEV_T_ANY or name's length is zero return error.
*/
return (DDI_PROP_INVAL_ARG);
if (flags & DDI_PROP_CANSLEEP)
if (flags & DDI_PROP_SYSTEM_DEF)
else if (flags & DDI_PROP_HW_DEF)
return (DDI_PROP_NO_MEMORY);
}
/*
* If dev is major number 0, then we need to do a ddi_name_to_major
* to get the real major number for the device. This needs to be
* done because some drivers need to call ddi_prop_create in their
* attach routines but they don't have a dev. By creating the dev
* ourself if the major number is 0, drivers will not have to know what
* their major number. They can just create a dev with major number
* 0 and pass it in. For device 0, we will be doing a little extra
* work by recreating the same dev that we already have, but its the
* price you pay :-).
*
* This fixes bug #1098060.
*/
} else
/*
* Allocate space for property name and copy it in...
*/
return (DDI_PROP_NO_MEMORY);
}
/*
* Set the property type
*/
/*
* Set length and value ONLY if not an explicit property undefine:
* NOTE: value and length are zero for explicit undefines.
*/
if (flags & DDI_PROP_UNDEF_IT) {
} else {
return (DDI_PROP_NO_MEMORY);
}
}
}
/*
* Link property into beginning of list. (Properties are LIFO order.)
*/
return (DDI_PROP_SUCCESS);
}
/*
* ddi_prop_change: Modify a software managed property value
*
* Set new length and value if found.
* returns DDI_PROP_INVAL_ARG if dev is DDI_DEV_T_ANY or
* input name is the NULL string.
* returns DDI_PROP_NO_MEMORY if unable to allocate memory
*
* Note: an undef can be modified to be a define,
* (you can't go the other way.)
*/
static int
{
ddi_prop_t **ppropp;
return (DDI_PROP_INVAL_ARG);
/*
* Preallocate buffer, even if we don't need it...
*/
if (length != 0) {
KM_SLEEP : KM_NOSLEEP);
if (p == NULL) {
return (DDI_PROP_NO_MEMORY);
}
}
/*
* If the dev_t value contains DDI_MAJOR_T_UNKNOWN for the major
* number, a real dev_t value should be created based upon the dip's
* binding driver. See ddi_prop_add...
*/
dev = makedevice(
/*
* Check to see if the property exists. If so we modify it.
* Else we create it by calling ddi_prop_add().
*/
if (flags & DDI_PROP_SYSTEM_DEF)
else if (flags & DDI_PROP_HW_DEF)
/*
* Need to reallocate buffer? If so, do it
* carefully (reuse same space if new prop
* is same size and non-NULL sized).
*/
if (length != 0)
return (DDI_PROP_SUCCESS);
}
if (length != 0)
}
/*
* Common update routine used to update and encode a property. Creates
* a property handle, calls the property encode routine, figures out if
* the property already exists and updates if it does. Otherwise it
* creates if it does not exist.
*/
int
{
int rval;
/*
* If dev_t is DDI_DEV_T_ANY or name's length is zero,
* return error.
*/
return (DDI_PROP_INVAL_ARG);
/*
* Create the handle
*/
/*
* ourflags:
* For compatibility with the old interfaces. The old interfaces
* didn't sleep by default and slept when the flag was set. These
* interfaces to the opposite. So the old interfaces now set the
* DDI_PROP_DONTSLEEP flag by default which tells us not to sleep.
*
* ph.ph_flags:
* Blocked data or unblocked data allocation
* for ph.ph_data in ddi_prop_encode_alloc()
*/
if (flags & DDI_PROP_DONTSLEEP) {
} else {
}
/*
* Encode the data and store it in the property handle by
* calling the prop_encode routine.
*/
if (rval == DDI_PROP_NO_MEMORY)
return (rval);
}
/*
* The old interfaces use a stacking approach to creating
* properties. If we are being called from the old interfaces,
* the DDI_PROP_STACK_CREATE flag will be set, so we just do a
* create without checking.
*/
if (flags & DDI_PROP_STACK_CREATE) {
} else {
}
/*
* Free the encoded data allocated in the prop_encode routine.
*/
return (rval);
}
/*
* ddi_prop_create: Define a managed property:
* See above for details.
*/
int
{
if (!(flag & DDI_PROP_CANSLEEP)) {
#ifdef DDI_PROP_DEBUG
if (length != 0)
"use ddi_prop_update (prop = %s, node = %s%d)",
#endif /* DDI_PROP_DEBUG */
}
flag &= ~DDI_PROP_SYSTEM_DEF;
}
int
{
if (!(flag & DDI_PROP_CANSLEEP))
}
int
{
/*
* If dev_t is DDI_DEV_T_ANY or name's length is zero,
* return error.
*/
return (DDI_PROP_INVAL_ARG);
if (!(flag & DDI_PROP_CANSLEEP))
flag &= ~DDI_PROP_SYSTEM_DEF;
return (DDI_PROP_NOT_FOUND);
}
int
{
/*
* If dev_t is DDI_DEV_T_ANY or name's length is zero,
* return error.
*/
return (DDI_PROP_INVAL_ARG);
return (DDI_PROP_NOT_FOUND);
if (!(flag & DDI_PROP_CANSLEEP))
}
/*
* Common lookup routine used to lookup and decode a property.
* Creates a property handle, searches for the raw encoded data,
* fills in the handle, and calls the property decode functions
* passed in.
*
* This routine is not static because ddi_bus_prop_op() which lives in
* ddi_impl.c calls it. No driver should be calling this routine.
*/
int
{
int rval;
if ((match_dev == DDI_DEV_T_NONE) ||
return (DDI_PROP_INVAL_ARG);
/*
* Get the encoded data
*/
if (flags & DDI_UNBND_DLPI2) {
/*
* For unbound dlpi style-2 devices, index into
* the devnames' array and search the global
* property list.
*/
ourflags &= ~DDI_UNBND_DLPI2;
} else {
}
return (rval);
}
/*
* If the encoded data came from a OBP or software
*/
/*
* Free the encoded data
*/
return (rval);
}
/*
* Lookup and return an array of composite properties. The driver must
* provide the decode routine.
*/
int
{
}
/*
* Return 1 if a property exists (no type checking done).
* Return 0 if it does not exist.
*/
int
{
int i;
uint_t x = 0;
return (i == DDI_PROP_SUCCESS || i == DDI_PROP_FOUND_1275);
}
/*
* Update an array of composite properties. The driver must
* provide the encode routine.
*/
int
{
}
/*
* Get a single integer or boolean property and return it.
* If the property does not exists, or cannot be decoded,
* then return the defvalue passed in.
*
* This routine always succeeds.
*/
int
{
int data;
int rval;
LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
#ifdef DEBUG
" 0x%x (prop = %s, node = %s%d)", flags,
}
#endif /* DEBUG */
}
if (rval == DDI_PROP_END_OF_DATA)
data = 1;
else
}
return (data);
}
/*
* Get a single 64 bit integer or boolean property and return it.
* If the property does not exists, or cannot be decoded,
* then return the defvalue passed in.
*
* This routine always succeeds.
*/
{
int rval;
LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
#ifdef DEBUG
" 0x%x (prop = %s, node = %s%d)", flags,
}
#endif /* DEBUG */
return (DDI_PROP_INVAL_ARG);
}
!= DDI_PROP_SUCCESS) {
if (rval == DDI_PROP_END_OF_DATA)
data = 1;
else
}
return (data);
}
/*
* Get an array of integer property
*/
int
{
LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
#ifdef DEBUG
"invalid flag 0x%x (prop = %s, node = %s%d)",
}
#endif /* DEBUG */
}
}
/*
* Get an array of 64 bit integer properties
*/
int
{
LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
#ifdef DEBUG
"invalid flag 0x%x (prop = %s, node = %s%d)",
}
#endif /* DEBUG */
return (DDI_PROP_INVAL_ARG);
}
}
/*
* Update a single integer property. If the property exists on the drivers
* property list it updates, else it creates it.
*/
int
{
}
/*
* Update a single 64 bit integer property.
* Update the driver property list if it exists, else create it.
*/
int
{
}
int
{
}
int
{
}
/*
* Update an array of integer property. If the property exists on the drivers
* property list it updates, else it creates it.
*/
int
{
}
/*
* Update an array of 64 bit integer properties.
* Update the driver property list if it exists, else create it.
*/
int
{
}
int
{
}
int
{
}
/*
* Get a single string property.
*/
int
{
uint_t x;
LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
#ifdef DEBUG
"(prop = %s, node = %s%d); invalid bits ignored",
}
#endif /* DEBUG */
}
&x, ddi_prop_fm_decode_string));
}
/*
* Get an array of strings property.
*/
int
{
LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
#ifdef DEBUG
"invalid flag 0x%x (prop = %s, node = %s%d)",
}
#endif /* DEBUG */
}
}
/*
* Update a single string property.
*/
int
{
}
int
{
}
/*
* Update an array of strings property.
*/
int
{
}
int
{
}
/*
* Get an array of bytes property.
*/
int
{
LDI_DEV_T_ANY | DDI_UNBND_DLPI2)) {
#ifdef DEBUG
" invalid flag 0x%x (prop = %s, node = %s%d)",
}
#endif /* DEBUG */
}
}
/*
* Update an array of bytes property.
*/
int
{
if (nelements == 0)
return (DDI_PROP_INVAL_ARG);
}
int
{
if (nelements == 0)
return (DDI_PROP_INVAL_ARG);
}
/*
* ddi_prop_remove_common: Undefine a managed property:
* Input dev_t must match dev_t when defined.
* Returns DDI_PROP_NOT_FOUND, possibly.
* DDI_PROP_INVAL_ARG is also possible if dev is
* DDI_DEV_T_ANY or incoming name is the NULL string.
*/
int
{
return (DDI_PROP_INVAL_ARG);
}
if (flag & DDI_PROP_SYSTEM_DEF)
else if (flag & DDI_PROP_HW_DEF)
/*
* Unlink this propp allowing for it to
* be first in the list:
*/
else
/*
* Free memory and return...
*/
return (DDI_PROP_SUCCESS);
}
}
return (DDI_PROP_NOT_FOUND);
}
int
{
}
int
{
}
/*
* e_ddi_prop_list_delete: remove a list of properties
* Note that the caller needs to provide the required protection
* (eg. devi_lock if these properties are still attached to a devi)
*/
void
{
}
/*
* ddi_prop_remove_all_common:
* Used before unloading a driver to remove
* all properties. (undefines all dev_t's props.)
* Also removes `explicitly undefined' props.
* No errors possible.
*/
void
{
if (flag & DDI_PROP_SYSTEM_DEF) {
} else if (flag & DDI_PROP_HW_DEF) {
} else {
}
}
/*
* ddi_prop_remove_all: Remove all driver prop definitions.
*/
void
{
}
/*
* e_ddi_prop_remove_all: Remove all system prop definitions.
*/
void
{
}
/*
* ddi_prop_undefine: Explicitly undefine a property. Property
* searches which match this property return
* the error code DDI_PROP_UNDEFINED.
*
* Use ddi_prop_remove to negate effect of
* ddi_prop_undefine
*
* See above for error returns.
*/
int
{
if (!(flag & DDI_PROP_CANSLEEP))
}
int
{
if (!(flag & DDI_PROP_CANSLEEP))
}
/*
* Code to search hardware layer (PROM), if it exists, on behalf of child.
*
* if input dip != child_dip, then call is on behalf of child
* to search PROM, do it via ddi_prop_search_common() and ascend only
* if allowed.
*
* if input dip == ch_dip (child_dip), call is on behalf of root driver,
* to search for PROM defined props only.
*
* Note that the PROM search is done only if the requested dev
* is either DDI_DEV_T_ANY or DDI_DEV_T_NONE. PROM properties
* have no associated dev, thus are automatically associated with
* DDI_DEV_T_NONE.
*
* Modifying flag DDI_PROP_NOTPROM inhibits the search in the h/w layer.
*
* Returns DDI_PROP_FOUND_1275 if found to indicate to framework
* that the property resides in the prom.
*/
int
{
int len;
/*
* If requested dev is DDI_DEV_T_NONE or DDI_DEV_T_ANY, then
* look in caller's PROM if it's a self identifying device...
*
* Note that this is very similar to ddi_prop_op, but we
* search the PROM instead of the s/w defined properties,
* and we are called on by the parent driver to do this for
* the child.
*/
((mod_flags & DDI_PROP_NOTPROM) == 0)) {
if (len == -1) {
return (DDI_PROP_NOT_FOUND);
}
/*
* If exists only request, we're done
*/
if (prop_op == PROP_EXISTS) {
return (DDI_PROP_FOUND_1275);
}
/*
* If length only request or prop length == 0, get out
*/
return (DDI_PROP_FOUND_1275);
}
/*
* Allocate buffer if required... (either way `buffer'
* is receiving address).
*/
switch (prop_op) {
case PROP_LEN_AND_VAL_ALLOC:
KM_SLEEP : KM_NOSLEEP);
return (DDI_PROP_NO_MEMORY);
}
break;
case PROP_LEN_AND_VAL_BUF:
return (DDI_PROP_BUF_TOO_SMALL);
}
break;
default:
break;
}
/*
* Call the PROM function to do the copy.
*/
return (DDI_PROP_FOUND_1275);
}
return (DDI_PROP_NOT_FOUND);
}
/*
* The ddi_bus_prop_op default bus nexus prop op function.
*
* Code to search hardware layer (PROM), if it exists,
* on behalf of child, then, if appropriate, ascend and check
* my own software defined properties...
*/
int
{
int error;
return (error);
if (error == DDI_PROP_NO_MEMORY) {
return (DDI_PROP_NO_MEMORY);
}
/*
* Check the 'options' node as a last resort
*/
if ((mod_flags & DDI_PROP_DONTPASS) != 0)
return (DDI_PROP_NOT_FOUND);
if (ch_dip == ddi_root_node()) {
/*
* As a last resort, when we've reached
* the top and still haven't found the
* property, see if the desired property
* is attached to the options node.
*
* The options dip is attached right after boot.
*/
/*
* Force the "don't pass" flag to *just* see
* what the options node has to offer.
*/
}
/*
* Otherwise, continue search with parent's s/w defined properties...
* NOTE: Using `dip' in following call increments the level.
*/
}
/*
* External property functions used by other parts of the kernel...
*/
/*
* e_ddi_getlongprop: See comments for ddi_get_longprop.
*/
int
{
int error;
return (DDI_PROP_NOT_FOUND);
return (error);
}
/*
* e_ddi_getlongprop_buf: See comments for ddi_getlongprop_buf.
*/
int
{
int error;
return (DDI_PROP_NOT_FOUND);
return (error);
}
/*
* e_ddi_getprop: See comments for ddi_getprop.
*/
int
{
int proplength = sizeof (int);
int error;
return (defvalue);
propvalue = 1;
return (propvalue);
}
/*
* e_ddi_getprop_int64:
*
* This is a typed interfaces, but predates typed properties. With the
* introduction of typed properties the framework tries to ensure
* consistent use of typed interfaces. This is why TYPE_INT64 is not
* part of TYPE_ANY. E_ddi_getprop_int64 is a special case where a
* typed interface invokes legacy (non-typed) interfaces:
* cdev_prop_op(), prop_op(9E), ddi_prop_op(9F)). In this case the
* fact that TYPE_INT64 is not part of TYPE_ANY matters. To support
* this type of lookup as a single operation we invoke the legacy
* non-typed interfaces with the special CONSUMER_TYPED bit set. The
* framework ddi_prop_op(9F) implementation is expected to check for
* CONSUMER_TYPED and, if set, expand type bits beyond TYPE_ANY
* (currently TYPE_INT64).
*/
{
int proplength = sizeof (propvalue);
int error;
return (defvalue);
propvalue = 1;
return (propvalue);
}
/*
* e_ddi_getproplen: See comments for ddi_getproplen.
*/
int
{
int error;
return (DDI_PROP_NOT_FOUND);
return (error);
}
/*
* Routines to get at elements of the dev_info structure
*/
/*
* ddi_binding_name: Return the driver binding name of the devinfo node
* This is the name the OS used to bind the node to a driver.
*/
char *
{
}
/*
* ddi_driver_major: Return the major number of the driver that
* the supplied devinfo is bound to (-1 if none)
*/
{
}
/*
* ddi_driver_name: Return the normalized driver name. this is the
* actual driver name
*/
const char *
{
return (ddi_major_to_name(major));
return (ddi_node_name(devi));
}
/*
* i_ddi_set_binding_name: Set binding name.
*
* Set the binding name to the given name.
* This routine is for use by the ddi implementation, not by drivers.
*/
void
{
}
/*
* ddi_get_name: A synonym of ddi_binding_name() ... returns a name
* the implementation has used to bind the node to a driver.
*/
char *
{
}
/*
* ddi_node_name: Return the name property of the devinfo node
* This may differ from ddi_binding_name if the node name
* does not define a binding to a driver (i.e. generic names).
*/
char *
{
}
/*
* ddi_get_nodeid: Get nodeid stored in dev_info structure.
*/
int
{
}
int
{
}
struct dev_ops *
{
}
void
{
}
/*
*/
void
{
}
void *
{
}
/*
* ddi_get_parent, ddi_get_child, ddi_get_next_sibling
*/
{
}
{
}
{
}
{
}
void
{
}
/*
* ddi_root_node: Return root node of devinfo tree
*/
ddi_root_node(void)
{
extern dev_info_t *top_devinfo;
return (top_devinfo);
}
/*
* Miscellaneous functions:
*/
/*
* Implementation specific hooks
*/
void
{
char *b;
(void) ddi_ctlops(d, d, DDI_CTLOPS_REPORTDEV, (void *)0, (void *)0);
/*
* If this devinfo node has cb_ops, it's implicitly accessible from
* userland, so we print its full name together with the instance
* number 'abbreviation' that the driver may use internally.
*/
ddi_driver_name(d), ddi_get_instance(d),
ddi_pathname(d, b));
kmem_free(b, MAXPATHLEN);
}
}
/*
* ddi_ctlops() is described in the assembler not to buy a new register
* window when it's called and can reduce cost in climbing the device tree
* without using the tail call optimization.
*/
int
{
int ret;
}
int
{
}
int
{
return (ddi_ctlops(d, d, DDI_CTLOPS_SIDDEV, (void *)0, (void *)0));
}
int
{
return (ddi_ctlops(d, d, DDI_CTLOPS_SLAVEONLY, (void *)0, (void *)0));
}
int
{
return (ddi_ctlops(a, a, DDI_CTLOPS_AFFINITY, (void *)b, (void *)0));
}
int
{
if (i_ddi_devi_attached(dip) &&
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
/*
* callback free list
*/
static int ncallbacks;
static int nc_low = 170;
static int nc_med = 512;
static int nc_high = 2048;
static struct ddi_callback *callbackq;
static struct ddi_callback *callbackqfree;
/*
*/
struct cbstats {
} cbstats = {
{"asked", KSTAT_DATA_UINT32},
{"new", KSTAT_DATA_UINT32},
{"run", KSTAT_DATA_UINT32},
{"delete", KSTAT_DATA_UINT32},
{"maxreq", KSTAT_DATA_UINT32},
{"maxlist", KSTAT_DATA_UINT32},
{"alloc", KSTAT_DATA_UINT32},
{"runouts", KSTAT_DATA_UINT32},
{"L2", KSTAT_DATA_UINT32},
{"grow", KSTAT_DATA_UINT32},
};
static kmutex_t ddi_callback_mutex;
/*
* we can't get callbacks from the L1 cache [because pageout is doing
* I/O at the time freemem is 0], we allocate callbacks out of the
* L2 cache. The L2 cache is static and depends on the memory size.
* [We might also count the number of devices at probe time and
* allocate one structure per device and adjust for deferred attach]
*/
void
impl_ddi_callback_init(void)
{
int i;
if (physmegs < 48) {
ncallbacks = nc_low;
} else if (physmegs < 128) {
ncallbacks = nc_med;
} else {
}
/*
* init free list
*/
for (i = 0; i < ncallbacks-1; i++)
/* init kstats */
}
}
static void
int count)
{
return;
}
}
new = callbackqfree;
} else {
}
}
} else {
}
}
void
{
}
static void
real_callback_run(void *Queue)
{
int check_pending = 1;
int pending = 0;
do {
return;
}
if (check_pending) {
}
check_pending = 0;
}
} else
do {
count);
} else {
pending--;
}
} while (pending > 0);
}
void
{
}
{
return ((dev_info_t *)0);
}
/*
* A driver should support its own getinfo(9E) entry point. This function
* is provided as a convenience for ON drivers that don't expect their
* getinfo(9E) entry point to be called. A driver that uses this must not
* call ddi_create_minor_node.
*/
int
{
return (DDI_FAILURE);
}
/*
* A driver should support its own getinfo(9E) entry point. This function
* is provided as a convenience for ON drivers that where the minor number
* is the instance. Drivers that do not have 1:1 mapping must implement
* their own getinfo(9E) function.
*/
int
{
int instance;
if (infocmd != DDI_INFO_DEVT2INSTANCE)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}
int
{
return (DDI_FAILURE);
}
int
{
return (DDI_DMA_NOMAPPING);
}
int
{
return (DDI_DMA_BADATTR);
}
int
{
return (DDI_FAILURE);
}
int
{
return (DDI_DMA_NOMAPPING);
}
int
{
return (DDI_FAILURE);
}
int
{
return (DDI_FAILURE);
}
int
{
return (DDI_FAILURE);
}
int
{
return (DDI_FAILURE);
}
void
ddivoid(void)
{}
int
{
return (ENXIO);
}
cred_t *
ddi_get_cred(void)
{
return (CRED());
}
ddi_get_lbolt(void)
{
return (lbolt);
}
ddi_get_time(void)
{
if ((now = gethrestime_sec()) == 0) {
} else {
return (now);
}
}
ddi_get_pid(void)
{
}
ddi_get_kt_did(void)
{
}
/*
* This function returns B_TRUE if the caller can reasonably expect that a call
* to cv_wait_sig(9F), cv_timedwait_sig(9F), or qwait_sig(9F) could be awakened
* by user-level signal. If it returns B_FALSE, then the caller should use
* other means to make certain that the wait will not hang "forever."
*
* It does not check the signal mask, nor for reception of any particular
* signal.
*
* Currently, a thread can receive a signal if it's not a kernel thread and it
* is not in the middle of exit(2) tear-down. Threads that are in that
* tear-down effectively convert cv_wait_sig to cv_wait, cv_timedwait_sig to
* cv_timedwait, and qwait_sig to qwait.
*/
ddi_can_receive_sig(void)
{
return (B_FALSE);
return (B_FALSE);
}
/*
* Swap bytes in 16-bit [half-]words
*/
void
{
int nshorts;
while (--nshorts >= 0) {
}
}
static void
{
struct ddi_minor_data *dp;
} else {
}
}
/*
* Part of the obsolete SunCluster DDI Hooks.
* Keep for binary compatibility
*/
{
}
static int
{
int se_flag;
int kmem_flag;
int se_err;
char *pathname;
/* determine interrupt context */
#ifdef DEBUG
"interrupt level by driver %s",
}
#endif /* DEBUG */
goto fail;
}
goto fail;
}
goto fail;
}
/*
* allow for NULL minor names
*/
if (minor_name != NULL) {
goto fail;
}
}
goto fail;
}
if (se_err == SE_NO_TRANSPORT) {
"for driver %s (%s). Run devfsadm -i %s",
} else {
goto fail;
}
}
return (DDI_SUCCESS);
fail:
"for driver %s. Run devfsadm -i %s",
return (DDI_SUCCESS);
}
/*
* failing to remove a minor node is not of interest
* therefore we do not generate an error message
*/
static int
{
char *pathname;
sysevent_t *ev;
/*
* only log ddi_remove_minor_node() calls outside the scope
* still initialized.
*/
return (DDI_SUCCESS);
}
return (DDI_SUCCESS);
}
return (DDI_SUCCESS);
}
return (DDI_SUCCESS);
}
/*
* allow for NULL minor names
*/
if (minor_name != NULL) {
goto fail;
}
}
} else {
}
fail:
return (DDI_SUCCESS);
}
/*
* Derive the device class of the node.
* Device class names aren't defined yet. Until this is done we use
* devfs event subclass names as device class names.
*/
static int
{
int rv = DDI_SUCCESS;
sizeof (DDI_NT_BLOCK) - 1) == 0 &&
sizeof (DDI_NT_NET) - 1) == 0 &&
}
}
return (rv);
}
/*
* Check compliance with PSARC 2003/375:
*
* The name must contain only characters a-z, A-Z, 0-9 or _ and it must not
* exceed IFNAMSIZ (16) characters in length.
*/
static boolean_t
verify_name(char *name)
{
char *cp;
return (B_FALSE);
return (B_FALSE);
}
return (B_TRUE);
}
/*
* ddi_create_minor_common: Create a ddi_minor_data structure and
* attach it to the given devinfo node.
*/
int
{
struct ddi_minor_data *dmdp;
return (DDI_FAILURE);
return (DDI_FAILURE);
/*
* Log a message if the minor number the driver is creating
* is not expressible on the on-disk filesystem (currently
* this is limited to 18 bits both by UFS). The device can
* be opened via devfs, but not by device special files created
* via mknod().
*/
if (minor_num > L_MAXMIN32) {
"%s%d:%s minor 0x%x too big for 32-bit applications",
return (DDI_FAILURE);
}
/* dip must be bound and attached */
/*
* Default node_type to DDI_PSEUDO and issue notice in debug mode
*/
" minor node %s; default to DDI_PSEUDO",
}
/*
* If the driver is a network driver, ensure that the name falls within
* the interface naming constraints specified by PSARC/2003/375.
*/
if (!verify_name(name))
return (DDI_FAILURE);
/* Mark driver as a network driver */
}
}
return (DDI_FAILURE);
}
/*
* Take care of minor number information for the node.
*/
KM_NOSLEEP)) == NULL) {
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
}
if (flag & PRIVONLY_DEV) {
}
if (read_priv || write_priv) {
}
/*
* only log ddi_create_minor_node() calls which occur
* outside the scope of attach(9e)/detach(9e) reconfigurations
*/
mtype != DDM_INTERNAL_PATH) {
}
/*
* Check if any dacf rules match the creation of this minor node
*/
return (DDI_SUCCESS);
}
int
{
}
int
{
}
int
{
}
/*
* Internal (non-ddi) routine for drivers to export names known
* to the kernel (especially ddi_pathname_to_dev_t and friends)
* but not exported externally to /dev
*/
int
{
}
void
{
struct ddi_minor_data **dmdp_prev;
(void) i_log_devfs_minor_remove(dip,
}
/*
* Release device privilege, if any.
* Release dacf client data associated with this minor
* node by storing NULL.
*/
if (dmdp->ddm_node_priv)
/*
* OK, we found it, so get out now -- if we drive on,
* we will strcmp against garbage. See 1139209.
*/
break;
} else {
}
}
}
int
{
}
/*
* Find first bit set in a mask (returned counting from 1 up)
*/
int
{
}
/*
* Find last bit set. Take mask and clear
* all but the most significant bit, and
* then let ffs do the rest of the work.
*
* Algorithm courtesy of Steve Chessin.
*/
int
{
extern int ffs(long);
while (mask) {
long nx;
break;
}
}
/*
* The next five routines comprise generic storage management utilities
* for driver soft state structures (in "the old days," this was done
* with a statically sized array - big systems and dynamic loading
* and unloading make heap allocation more attractive)
*/
/*
* Allocate a set of pointers to 'n_items' objects of size 'size'
* bytes. Each pointer is initialized to nil.
*
* The 'size' and 'n_items' values are stashed in the opaque
* handle returned to the caller.
*
* This implementation interprets 'set of pointers' to mean 'array
* of pointers' but note that nothing in the interface definition
* precludes an implementation that uses, for example, a linked list.
* However there should be a small efficiency gain from using an array
* at lookup time.
*
* NOTE As an optimization, we make our growable array allocations in
* powers of two (bytes), since that's how much kmem_alloc (currently)
*
* As a further optimization, we make the growable array start out
* with MIN_N_ITEMS in it.
*/
int
{
struct i_ddi_soft_state *ss;
return (EINVAL);
if (n_items < MIN_N_ITEMS)
else {
int bitlog;
bitlog--;
}
return (0);
}
/*
* Allocate a state structure of size 'size' to be associated
* with item 'item'.
*
* In this implementation, the array is extended to
* allow the requested offset, if needed.
*/
int
{
struct i_ddi_soft_state *ss;
void **array;
void *new_element;
return (DDI_FAILURE);
mod_containing_pc(caller()));
return (DDI_FAILURE);
}
/*
* refuse to tread on an existing element
*/
return (DDI_FAILURE);
}
/*
* Allocate a new element to plug in
*/
/*
* Check if the array is big enough, if not, grow it.
*/
void **new_array;
struct i_ddi_soft_state *dirty;
/*
* Allocate a new array of the right length, copy
* all the old pointers to the new array, then
* if it exists at all, put the old array on the
* dirty list.
*
* Note that we can't kmem_free() the old array.
*
* Why -- well the 'get' operation is 'mutex-free', so we
* can't easily catch a suspended thread that is just about
* to dereference the array we just grew out of. So we
* cons up a header and put it on a list of 'dirty'
* pointer arrays. (Dirty in the sense that there may
* be suspended threads somewhere that are in the middle
* of referencing them). Fortunately, we -can- garbage
* collect it all at ddi_soft_state_fini time.
*/
KM_SLEEP);
/*
* Copy the pointers into the new array
*/
/*
* Save the old array on the dirty list
*/
}
return (DDI_SUCCESS);
}
/*
* Fetch a pointer to the allocated soft state structure.
*
* This is designed to be cheap.
*
* There's an argument that there should be more checking for
* nil pointers and out of bounds on the array.. but we do a lot
*
* An array has the convenience that we don't need to lock read-access
* to it c.f. a linked list. However our "expanding array" strategy
* means that we should hold a readers lock on the i_ddi_soft_state
* structure.
*
* However, from a performance viewpoint, we need to do it without
* any locks at all -- this also makes it a leaf routine. The algorithm
* is 'lock-free' because we only discard the pointer arrays at
* ddi_soft_state_fini() time.
*/
void *
{
return (NULL);
}
/*
* Free the state structure corresponding to 'item.' Freeing an
* element that has either gone or was never allocated is not
* considered an error. Note that we free the state structure, but
* we don't shrink our pointer array, or discard 'dirty' arrays,
* since even a few pointers don't really waste too much memory.
*
* Passing an item number that is out of bounds, or a null pointer will
* provoke an error message.
*/
void
{
struct i_ddi_soft_state *ss;
void **array;
void *element;
static char msg[] = "ddi_soft_state_free:";
return;
}
}
if (element)
}
/*
* Free the entire set of pointers, and any
* soft state structures contained therein.
*
* Note that we don't grab the ss->lock mutex, even though
* we're inspecting the various fields of the data structure.
*
* There is an implicit assumption that this routine will
* never run concurrently with any of the above on this
* particular state structure i.e. by the time the driver
* calls this routine, there should be no other threads
* running in the driver.
*/
void
ddi_soft_state_fini(void **state_p)
{
int item;
static char msg[] = "ddi_soft_state_fini:";
return;
}
return;
}
}
/*
* Now delete any dirty arrays from previous 'grow' operations
*/
}
}
/*
* This sets the devi_addr entry in the dev_info structure 'dip' to 'name'.
* Storage is double buffered to prevent updates during devi_addr use -
* double buffering is adaquate for reliable ddi_deviname() consumption.
* The double buffer is not freed until dev_info structure destruction
* (by i_ddi_free_node).
*/
void
{
char *newaddr;
}
if (name) {
} else
}
char *
{
}
void
{
}
void *
{
}
/*
* ddi_name_to_major: Returns the major number of a module given its name.
*/
ddi_name_to_major(char *name)
{
return (mod_name_to_major(name));
}
/*
* ddi_major_to_name: Returns the module name bound to a major number.
*/
char *
{
return (mod_major_to_name(major));
}
/*
* Return the name of the devinfo node pointed at by 'dip' in the buffer
* pointed at by 'name.' A devinfo node is named as a result of calling
* ddi_initchild().
*
* Note: the driver must be held before calling this function!
*/
char *
{
char *addrname;
char none = '\0';
if (dip == ddi_root_node()) {
*name = '\0';
return (name);
}
} else {
}
if (*addrname == '\0') {
} else {
}
return (name);
}
/*
* Spits out the name of device node, typically name@addr, for a given node,
* using the driver name, not the nodename.
*
* Used by match_parent. Not to be used elsewhere.
*/
char *
{
char *addrname;
if (dip == ddi_root_node()) {
*name = '\0';
return (name);
}
else
return (name);
}
static char *
{
char *bp;
if (dip == ddi_root_node()) {
*path = '\0';
return (path);
}
return (path);
}
char *
{
}
/*
* Given a dev_t, return the pathname of the corresponding device in the
* buffer pointed at by "path." The buffer is assumed to be large enough
* to hold the pathname of the device (MAXPATHLEN).
*
* The pathname of a device is the pathname of the devinfo node to which
* the device "belongs," concatenated with the character ':' and the name
* of the minor node corresponding to the dev_t. If spec_type is 0 then
* just the pathname of the devinfo node is returned without driving attach
* of that node. For a non-zero spec_type, an attach is performed and a
* search of the minor list occurs.
*
* It is possible that the path associated with the dev_t is not
* currently available in the devinfo tree. In order to have a
* dev_t, a device must have been discovered before, which means
* that the path is always in the instance tree. The one exception
* to this is if the dev_t is associated with a pseudo driver, in
* which case the device must exist on the pseudo branch of the
* devinfo tree as a result of parsing .conf files.
*/
int
{
int instance;
char *minorname;
char *drvname;
goto fail;
if (major == clone_major) {
/* clone has no minor nodes, manufacture the path here */
goto fail;
return (DDI_SUCCESS);
}
/* extract instance from devt (getinfo(9E) DDI_INFO_DEVT2INSTANCE). */
goto fail;
goto fail;
/* if spec_type given we must drive attach and search minor nodes */
/* attach the path so we can search minors */
goto fail;
/* Add minorname to path. */
if (minorname) {
}
goto fail;
}
return (DDI_SUCCESS);
return (DDI_FAILURE);
}
/*
* Given a major number and an instance, return the path.
* This interface does NOT drive attach.
*/
int
{
*path = 0;
return (DDI_FAILURE);
}
path) == DDI_SUCCESS) {
return (DDI_SUCCESS);
}
/*
* Not in instance tree, find the instance on the per driver list and
* construct path to instance via ddi_pathname(). This is how paths
* down the 'pseudo' branch are constructed.
*/
/* Skip if instance does not match. */
continue;
/*
* An ndi_hold_devi() does not prevent DS_INITIALIZED->DS_BOUND
* node demotion, so it is not an effective way of ensuring
* that the ddi_pathname result has a unit-address. Instead,
* we reverify the node state after calling ddi_pathname().
*/
continue;
return (DDI_SUCCESS);
}
}
/* can't reconstruct the path */
*path = 0;
return (DDI_FAILURE);
}
#define GLD_DRIVER_PPA "SUNW,gld_v0_ppa"
/*
* Given the dip for a network interface return the ppa for that interface.
*
* In all cases except GLD v0 drivers, the ppa == instance.
* In the case of GLD v0 drivers, the ppa is equal to the attach order.
* So for these drivers when the attach routine calls gld_register(),
* the GLD framework creates an integer property called "gld_driver_ppa"
* that can be queried here.
*
* The only time this function is used is when a system is booting over nfs.
* In this case the system has to resolve the pathname of the boot device
* to it's ppa.
*/
int
{
}
/*
* i_ddi_devi_set_ppa() should only be called from gld_register()
* and only for GLD v0 drivers
*/
void
{
}
/*
* Private DDI Console bell functions.
*/
void
{
if (ddi_console_bell_func != NULL)
}
void
{
}
int
{
int (*funcp)() = ddi_dma_allochdl;
if (attr == (ddi_dma_attr_t *)0)
return (DDI_DMA_BADATTR);
}
void
{
ddi_dma_handle_t h = *handlep;
}
static uintptr_t dma_mem_list_id = 0;
int
{
int rval;
if (waitfp == DDI_DMA_SLEEP)
else if (waitfp == DDI_DMA_DONTWAIT)
fp = (int (*)())KM_NOSLEEP;
else
return (DDI_FAILURE);
/* check if the cache attributes are supported */
return (DDI_FAILURE);
/*
* Transfer the meaningful bits to xfermodes.
* Double-check if the 3rd party driver correctly sets the bits.
* If not, set DDI_DMA_STREAMING to keep compatibility.
*/
if (xfermodes == 0) {
}
/*
* initialize the common elements of data access handle
*/
if (xfermodes == DDI_DMA_CONSISTENT) {
*real_length = length;
} else {
}
if (rval == DDI_SUCCESS) {
} else {
}
rval = DDI_FAILURE;
}
return (rval);
}
void
{
/*
* free the handle
*/
if (dma_mem_list_id != 0) {
}
}
int
{
struct ddi_dma_req dmareq;
int (*funcp)();
} else {
} else {
}
/*
* If the buffer has no proc pointer, or the proc
* struct has the kernel address space, or the buffer has
* been marked B_REMAPPED (meaning that it is now
* mapped into the kernel's address space), then
* the address space is kas (kernel address space).
*/
} else {
}
}
}
int
{
struct ddi_dma_req dmareq;
int (*funcp)();
return (DDI_DMA_NOMAPPING);
}
}
void
{
hp->dmai_cookie++;
}
int
{
return (DDI_FAILURE);
} else {
return (DDI_SUCCESS);
}
}
int
{
int (*funcp)() = ddi_dma_win;
}
int
{
&burstsizes, 0, 0));
}
int
{
return (hp->dmai_fault);
}
int
{
int (*check)(ddi_dma_impl_t *);
}
void
{
void (*notify)(ddi_dma_impl_t *);
if (!hp->dmai_fault) {
}
}
void
{
void (*notify)(ddi_dma_impl_t *);
if (hp->dmai_fault) {
hp->dmai_fault = 0;
}
}
/*
* register mapping routines.
*/
int
{
int result;
/*
* Allocate and initialize the common elements of data access handle.
*/
/*
* Set up the mapping request and call to parent.
*/
/*
* check for end result
*/
if (result != DDI_SUCCESS) {
} else {
}
return (result);
}
void
{
/*
* Call my parent to unmap my regs.
*/
/*
* free the handle
*/
}
int
{
uint8_t *b;
uint16_t *w;
uint32_t *l;
/* check for total byte count is multiple of data transfer size */
return (DDI_FAILURE);
switch (dev_datasz) {
case DDI_DATA_SZ01_ACC:
break;
case DDI_DATA_SZ02_ACC:
break;
case DDI_DATA_SZ04_ACC:
break;
case DDI_DATA_SZ08_ACC:
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
int
{
/* check for total byte count is multiple of data transfer size */
return (DDI_FAILURE);
switch (dev_datasz) {
case DDI_DATA_SZ01_ACC:
b_dst += dest_advcnt;
b_src += src_advcnt;
}
break;
case DDI_DATA_SZ02_ACC:
w_dst += dest_advcnt;
w_src += src_advcnt;
}
break;
case DDI_DATA_SZ04_ACC:
l_dst += dest_advcnt;
l_src += src_advcnt;
}
break;
case DDI_DATA_SZ08_ACC:
ll_dst += dest_advcnt;
ll_src += src_advcnt;
}
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
<< 32) | \
{
}
{
}
{
}
/*
* Convert a binding name to a driver name.
* A binding name is the name used to determine the driver for a
* device - it may be either an alias for the driver or the name
* of the driver itself.
*/
char *
i_binding_to_drv_name(char *bname)
{
return (NULL);
return (ddi_major_to_name(major_no));
}
/*
* Search for minor name that has specified dev_t and spec_type.
* If spec_type is zero then any dev_t match works. Since we
* are returning a pointer to the minor name string, we require the
* caller to do the locking.
*/
char *
{
struct ddi_minor_data *dmdp;
/*
* The did layered driver currently intentionally returns a
* devinfo ptr for an underlying sd instance based on a did
* dev_t. In this case it is not an error.
*
* The did layered driver is associated with Sun Cluster.
*/
}
return (NULL);
}
/*
* Find the devt and spectype of the specified minor_name.
* Return DDI_FAILURE if minor_name not found. Since we are
* returning everything via arguments we can do the locking.
*/
int
{
struct ddi_minor_data *dmdp;
/* deal with clone minor nodes */
/*
* Make sure minor_name is a STREAMS driver.
* We load the driver but don't attach to any instances.
*/
return (DDI_FAILURE);
return (DDI_FAILURE);
return (DDI_FAILURE);
}
if (devtp)
if (spectypep)
return (DDI_SUCCESS);
}
continue;
if (devtp)
if (spectypep)
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
extern char hw_serial[];
static kmutex_t devid_gen_mutex;
static short devid_gen_number;
#ifdef DEBUG
static int devid_register_corrupt = 0;
static int devid_register_corrupt_major = 0;
static int devid_register_corrupt_hint = 0;
static int devid_register_corrupt_hint_major = 0;
static int devid_lyr_debug = 0;
if (devid_lyr_debug) \
#else
#endif /* DEBUG */
#ifdef DEBUG
static void
{
int i;
for (i = 0; i < ndevs; i++) {
}
}
static void
{
int i;
for (i = 0; i < npaths; i++) {
}
}
static void
{
int i;
for (i = 0; i < ndevs; i++) {
}
}
#endif /* DEBUG */
/*
* Register device id into DDI framework.
* Must be called when device is attached.
*/
static int
{
const char *driver_name;
char *devid_str;
return (DDI_FAILURE);
/* verify that the devid is valid */
return (DDI_FAILURE);
/* Updating driver name hint in devid */
if (driver_len > DEVID_HINT_SIZE) {
/* Pick up last four characters of driver name */
}
#ifdef DEBUG
/* Corrupt the devid for testing. */
if (devid_register_corrupt_major &&
#endif /* DEBUG */
/* encode the devid as a string */
return (DDI_FAILURE);
/* add string as a string property */
return (DDI_FAILURE);
}
#ifdef DEVID_COMPATIBILITY
/*
* marker for devinfo snapshot compatibility.
* This code gets deleted when di_devid is gone from libdevid
*/
#endif /* DEVID_COMPATIBILITY */
return (DDI_SUCCESS);
}
int
{
int rval;
if (rval == DDI_SUCCESS) {
/*
* Register devid in devid-to-path cache
*/
} else {
}
} else {
}
return (rval);
}
/*
* Remove (unregister) device id from DDI framework.
* Must be called when device is detached.
*/
static void
{
#ifdef DEVID_COMPATIBILITY
/*
* marker for micro release devinfo snapshot compatibility.
* This code gets deleted for the minor release.
*/
#endif /* DEVID_COMPATIBILITY */
/* remove the devid property */
}
void
{
}
/*
* Allocate and initialize a device id.
*/
int
void *id,
{
int driver_len;
const char *driver_name;
switch (devid_type) {
case DEVID_SCSI3_WWN:
/*FALLTHRU*/
case DEVID_SCSI_SERIAL:
/*FALLTHRU*/
case DEVID_ATA_SERIAL:
/*FALLTHRU*/
case DEVID_ENCAP:
if (nbytes == 0)
return (DDI_FAILURE);
return (DDI_FAILURE);
break;
case DEVID_FAB:
if (nbytes != 0)
return (DDI_FAILURE);
return (DDI_FAILURE);
nbytes = sizeof (int) +
sizeof (struct timeval32) + sizeof (short);
break;
default:
return (DDI_FAILURE);
}
return (DDI_FAILURE);
/* Fill in driver name hint */
if (driver_len > DEVID_HINT_SIZE) {
/* Pick up last four characters of driver name */
}
/* Fill in id field */
if (devid_type == DEVID_FAB) {
char *cp;
int hostid;
struct timeval32 timestamp32;
int i;
int *ip;
short gen;
/* increase the generation number */
gen = devid_gen_number++;
/* Fill in host id (big-endian byte ordering) */
/*
* Fill in timestamp (big-endian byte ordering)
*
* (Note that the format may have to be changed
* before 2038 comes around, though it's arguably
* unique enough as it is..)
*/
ip = (int *)×tamp32;
for (i = 0;
i < sizeof (timestamp32) / sizeof (int); i++, ip++) {
int val;
}
/* fill in the generation number */
} else
/* return device id */
return (DDI_SUCCESS);
}
int
{
char *devidstr;
/* look up the property, devt specific first */
if ((dev == DDI_DEV_T_ANY) ||
DDI_PROP_SUCCESS)) {
return (DDI_FAILURE);
}
}
/* convert to binary form */
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
/*
* Return a copy of the device id for dev_t
*/
int
{
int rval;
/* get the dip */
return (DDI_FAILURE);
return (rval);
}
/*
* Return a copy of the minor name for dev_t and spec_type
*/
int
{
char *nm;
return (DDI_FAILURE);
return (DDI_FAILURE);
}
/* make a copy */
/* drop lock to allocate memory */
/* re-check things, since we dropped the lock */
*minor_name = NULL;
return (DDI_FAILURE);
}
/* verify size is the same */
goto retry;
}
/* sz == alloc_sz - make a copy */
return (DDI_SUCCESS);
}
int
char *minor_name,
int *retndevs,
{
DDI_DEBUG_DEVID_DEVTS("ddi_lyr_devid_to_devlist",
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
DDI_DEBUG_DEVID_DEVTS("ddi_lyr_devid_to_devlist",
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
void
{
}
/*
* Note: This will need to be fixed if we ever allow processes to
* have more than one data model per exec.
*/
ddi_mmap_get_model(void)
{
return (get_udatamodel());
}
{
}
/*
* ddi interfaces managing storage and retrieval of eventcookies.
*/
/*
* Invoke bus nexus driver's implementation of the
* (*bus_remove_eventcall)() interface to remove a registered
* callback handler for "event".
*/
int
{
if (!cb) {
return (DDI_FAILURE);
}
}
/*
* Invoke bus nexus driver's implementation of the
* (*bus_add_eventcall)() interface to register a callback handler
* for "event".
*/
int
{
}
/*
* Return a handle for event "name" by calling up the device tree
* hierarchy via (*bus_get_eventcookie)() interface until claimed
* by a bus nexus or top of dev_info tree is reached.
*/
int
{
name, event_cookiep));
}
/*
* single thread access to dev_info node and set state
*/
void
{
if (!has_lock)
/*
* wait until state(s) have been changed
*/
}
if (!has_lock)
}
void
{
if (!has_lock)
/*
* clear the state(s) and wakeup any threads waiting
* for state change
*/
if (!has_lock)
}
/*
* This procedure is provided as the general callback function when
* umem_lockmemory calls as_add_callback for long term memory locking.
* When as_unmap, as_setprot, or as_free encounter segments which have
* locked memory, this callback will be invoked.
*/
void
{
/*
* Call the cleanup function. Decrement the cookie reference
* count, if it goes to zero, return the memory for the cookie.
* The i_ddi_umem_unlock for this cookie may or may not have been
* called already. It is the responsibility of the caller of
* umem_lockmemory to handle the case of the cleanup routine
* being called after a ddi_umem_unlock for the cookie
* was called.
*/
/* remove the cookie if reference goes to zero */
}
}
/*
* The following two Consolidation Private routines provide generic
*
* To keep project_rele and project_hold consistent, i_ddi_decr_locked_memory()
* must be called every time i_ddi_incr_locked_memory() is called.
*/
int
/* ARGSUSED */
{
/*
* Test if the requested memory can be locked without exceeding the
* limits.
*/
return (ENOMEM);
}
/*
* Grab a hold on the project.
*/
(void) project_hold(projp);
return (0);
}
/*
* To keep project_rele and project_hold consistent, i_ddi_incr_locked_memory()
* must be called every time i_ddi_decr_locked_memory() is called.
*/
/* ARGSUSED */
void
{
/*
* Release the project pointer reference accquired in
* i_ddi_incr_locked_memory().
*/
(void) project_rele(projectp);
}
/*
* This routine checks if the max-device-locked-memory resource ctl is
* exceeded, if not increments it, grabs a hold on the project.
* Returns 0 if successful otherwise returns error code
*/
static int
{
int ret;
return (ret);
}
/*
* save the project pointer in the
* umem cookie, project pointer already
* hold in i_ddi_incr_locked_memory
*/
return (0);
}
/*
* Decrements the max-device-locked-memory resource ctl and releases
* the hold on the project that was acquired during umem_incr_devlockmem
*/
static void
{
if (!cookie->lockmem_proj)
return;
}
/*
* A consolidation private function which is essentially equivalent to
* ddi_umem_lock but with the addition of arguments ops_vector and procp.
* A call to as_add_callback is done if DDI_UMEMLOCK_LONGTERM is set, and
* the ops_vector is valid.
*
* Lock the virtual address range in the current process and create a
* ddi_umem_cookie (of type UMEM_LOCKED). This can be used to pass to
* ddi_umem_iosetup to create a buf or do devmap_umem_setup/remap to export
* to user space.
*
* Note: The resource control accounting currently uses a full charge model
* in other words attempts to lock the same/overlapping areas of memory
* will deduct the full size of the buffer from the projects running
* counter for the device locked memory.
*
* addr, size should be PAGESIZE aligned
*
* flags - DDI_UMEMLOCK_READ, DDI_UMEMLOCK_WRITE or both
* identifies whether the locked memory will be read or written or both
* DDI_UMEMLOCK_LONGTERM must be set when the locking will
* be maintained for an indefinitely long period (essentially permanent),
* rather than for what would be required for a typical I/O completion.
* When DDI_UMEMLOCK_LONGTERM is set, umem_lockmemory will return EFAULT
* if the memory pertains to a regular file which is mapped MAP_SHARED.
* This is to prevent a deadlock if a file truncation is attempted after
* after the locking is done.
*
* Returns 0 on success
* EINVAL - for invalid parameters
* EPERM, ENOMEM and other error codes returned by as_pagelock
* ENOMEM - is returned if the current request to lock memory exceeds
* project.max-device-locked-memory resource control value.
* EFAULT - memory pertains to a regular file mapped shared and
* and DDI_UMEMLOCK_LONGTERM flag is set
* EAGAIN - could not start the ddi_umem_unlock list processing thread
*/
int
struct umem_callback_ops *ops_vector,
{
int error;
struct ddi_umem_cookie *p;
void (*driver_callback)() = NULL;
/* These are the only three valid flags */
DDI_UMEMLOCK_LONGTERM)) != 0)
return (EINVAL);
/* At least one (can be both) of the two access flags must be set */
return (EINVAL);
/* addr and len must be page-aligned */
return (EINVAL);
if ((len & PAGEOFFSET) != 0)
return (EINVAL);
/*
* For longterm locking a driver callback must be specified; if
* not longterm then a callback is optional.
*/
if (ops_vector != NULL) {
if (ops_vector->cbo_umem_callback_version !=
return (EINVAL);
else
}
return (EINVAL);
/*
* Call i_ddi_umem_unlock_thread_start if necessary. It will
* be called on first ddi_umem_lock or umem_lockmemory call.
*/
if (ddi_umem_unlock_thread == NULL)
/* Allocate memory for the cookie */
/* Convert the flags to seg_rw type */
if (flags & DDI_UMEMLOCK_WRITE) {
} else {
}
/*
* Store the struct as pointer in cookie for later use by
* ddi_umem_unlock. The proc->p_as will be stale if ddi_umem_unlock
* is called after relvm is called.
*/
/*
* The size field is needed for lockmem accounting.
*/
if (umem_incr_devlockmem(p) != 0) {
/*
* The requested memory cannot be locked
*/
kmem_free(p, sizeof (struct ddi_umem_cookie));
return (ENOMEM);
}
/*
* umem_incr_devlockmem stashes the project ptr into the
* cookie. This is needed during unlock since that can
* happen in a non-USER context
*/
ASSERT(p->lockmem_proj);
/* Lock the pages corresponding to addr, len in memory */
if (error != 0) {
kmem_free(p, sizeof (struct ddi_umem_cookie));
return (error);
}
/*
* For longterm locking the addr must pertain to a seg_vn segment or
* or a seg_spt segment.
* If the segment pertains to a regular file, it cannot be
* mapped MAP_SHARED.
* This is to prevent a deadlock if a file truncation is attempted
* after the locking is done.
* Doing this after as_pagelock guarantees persistence of the as; if
* an unacceptable segment is found, the cleanup includes calling
* as_pageunlock before returning EFAULT.
*/
if (flags & DDI_UMEMLOCK_LONGTERM) {
extern struct seg_ops segspt_shmops;
break;
kmem_free(p, sizeof (struct ddi_umem_cookie));
return (EFAULT);
}
}
}
/* Initialize the fields in the ddi_umem_cookie */
p->type = UMEM_LOCKED;
if (driver_callback != NULL) {
/* i_ddi_umem_unlock and umem_lock_undo may need the cookie */
p->cook_refcnt = 2;
p->callbacks = *ops_vector;
} else {
/* only i_ddi_umme_unlock needs the cookie */
p->cook_refcnt = 1;
}
*cookie = (ddi_umem_cookie_t)p;
/*
* If a driver callback was specified, add an entry to the
* as struct callback list. The as_pagelock above guarantees
* the persistence of as.
*/
if (driver_callback) {
if (error != 0) {
kmem_free(p, sizeof (struct ddi_umem_cookie));
}
}
return (error);
}
/*
* Unlock the pages locked by ddi_umem_lock or umem_lockmemory and free
* the cookie. Called from i_ddi_umem_unlock_thread.
*/
static void
i_ddi_umem_unlock(struct ddi_umem_cookie *p)
{
/*
* There is no way to determine whether a callback to
* umem_lock_undo was registered via as_add_callback.
* (i.e. umem_lockmemory was called with DDI_MEMLOCK_LONGTERM and
* a valid callback function structure.) as_delete_callback
* is called to delete a possible registered callback. If the
* return from as_delete_callbacks is AS_CALLBACK_DELETED, it
* indicates that there was a callback registered, and that is was
* successfully deleted. Thus, the cookie reference count
* will never be decremented by umem_lock_undo. Just return the
* memory for the cookie, since both users of the cookie are done.
* A return of AS_CALLBACK_NOTFOUND indicates a callback was
* never registered. A return of AS_CALLBACK_DELETE_DEFERRED
* indicates that callback processing is taking place and, and
* umem_lock_undo is, or will be, executing, and thus decrementing
* the cookie reference count when it is complete.
*
* This needs to be done before as_pageunlock so that the
* persistence of as is guaranteed because of the locked pages.
*
*/
/*
* The proc->p_as will be stale if i_ddi_umem_unlock is called
* after relvm is called so use p->asp.
*/
/*
* Now that we have unlocked the memory decrement the
* max-device-locked-memory rctl
*/
if (rc == AS_CALLBACK_DELETED) {
/* umem_lock_undo will not happen, return the cookie memory */
kmem_free(p, sizeof (struct ddi_umem_cookie));
} else {
/*
* umem_undo_lock may happen if as_delete_callback returned
* AS_CALLBACK_DELETE_DEFERRED. In that case, decrement the
* reference count, atomically, and return the cookie
* memory if the reference count goes to zero. The only
* other value for rc is AS_CALLBACK_NOTFOUND. In that
* case, just return the cookie memory.
*/
if ((rc != AS_CALLBACK_DELETE_DEFERRED) ||
== 0)) {
kmem_free(p, sizeof (struct ddi_umem_cookie));
}
}
}
/*
* i_ddi_umem_unlock_thread - deferred ddi_umem_unlock list handler.
*
* Call i_ddi_umem_unlock for entries in the ddi_umem_unlock list
* until it is empty. Then, wait for more to be added. This thread is awoken
* via calls to ddi_umem_unlock.
*/
static void
i_ddi_umem_unlock_thread(void)
{
struct ddi_umem_cookie *ret_cookie;
/* process the ddi_umem_unlock list */
callb_generic_cpr, "unlock_thread");
for (;;) {
/* take if off the list */
if ((ddi_umem_unlock_head =
}
/* unlock the pages in this cookie */
(void) i_ddi_umem_unlock(ret_cookie);
} else { /* list is empty, wait for next ddi_umem_unlock */
}
}
/* ddi_umem_unlock_thread does not exit */
/* NOTREACHED */
}
/*
* Start the thread that will process the ddi_umem_unlock list if it is
* not already started (i_ddi_umem_unlock_thread).
*/
static void
{
if (ddi_umem_unlock_thread == NULL) {
}
}
/*
* Lock the virtual address range in the current process and create a
* ddi_umem_cookie (of type UMEM_LOCKED). This can be used to pass to
* ddi_umem_iosetup to create a buf or do devmap_umem_setup/remap to export
* to user space.
*
* Note: The resource control accounting currently uses a full charge model
* in other words attempts to lock the same/overlapping areas of memory
* will deduct the full size of the buffer from the projects running
* counter for the device locked memory. This applies to umem_lockmemory too.
*
* addr, size should be PAGESIZE aligned
* flags - DDI_UMEMLOCK_READ, DDI_UMEMLOCK_WRITE or both
* identifies whether the locked memory will be read or written or both
*
* Returns 0 on success
* EINVAL - for invalid parameters
* EPERM, ENOMEM and other error codes returned by as_pagelock
* ENOMEM - is returned if the current request to lock memory exceeds
* project.max-device-locked-memory resource control value.
* EAGAIN - could not start the ddi_umem_unlock list processing thread
*/
int
{
int error;
struct ddi_umem_cookie *p;
/* These are the only two valid flags */
return (EINVAL);
}
/* At least one of the two flags (or both) must be set */
return (EINVAL);
}
/* addr and len must be page-aligned */
return (EINVAL);
}
if ((len & PAGEOFFSET) != 0) {
return (EINVAL);
}
/*
* Call i_ddi_umem_unlock_thread_start if necessary. It will
* be called on first ddi_umem_lock or umem_lockmemory call.
*/
if (ddi_umem_unlock_thread == NULL)
/* Allocate memory for the cookie */
/* Convert the flags to seg_rw type */
if (flags & DDI_UMEMLOCK_WRITE) {
} else {
}
/*
* Store the struct as pointer in cookie for later use by
* ddi_umem_unlock. The proc->p_as will be stale if ddi_umem_unlock
* is called after relvm is called.
*/
/*
* The size field is needed for lockmem accounting.
*/
if (umem_incr_devlockmem(p) != 0) {
/*
* The requested memory cannot be locked
*/
kmem_free(p, sizeof (struct ddi_umem_cookie));
return (ENOMEM);
}
/*
* umem_incr_devlockmem stashes the project ptr into the
* cookie. This is needed during unlock since that can
* happen in a non-USER context
*/
ASSERT(p->lockmem_proj);
/* Lock the pages corresponding to addr, len in memory */
if (error != 0) {
kmem_free(p, sizeof (struct ddi_umem_cookie));
return (error);
}
/* Initialize the fields in the ddi_umem_cookie */
p->type = UMEM_LOCKED;
p->cook_refcnt = 1;
*cookie = (ddi_umem_cookie_t)p;
return (error);
}
/*
* Add the cookie to the ddi_umem_unlock list. Pages will be
* unlocked by i_ddi_umem_unlock_thread.
*/
void
{
/*
* Queue the unlock request and notify i_ddi_umem_unlock thread
* if it's called in the interrupt context. Otherwise, unlock pages
* immediately.
*/
if (servicing_interrupt()) {
/* queue the unlock request and notify the thread */
if (ddi_umem_unlock_head == NULL) {
} else {
ddi_umem_unlock_tail->unl_forw = p;
ddi_umem_unlock_tail = p;
}
} else {
/* unlock the pages right away */
(void) i_ddi_umem_unlock(p);
}
}
/*
* Create a buf structure from a ddi_umem_cookie
* cookie - is a ddi_umem_cookie for from ddi_umem_lock and ddi_umem_alloc
* (only UMEM_LOCKED & KMEM_NON_PAGEABLE types supported)
* off, len - identifies the portion of the memory represented by the cookie
* that the buf points to.
* device (dev) that this buf will be passed to. Some devices
* are met (we cannot assert as we do not know the restrictions)
*
* direction - is one of B_READ or B_WRITE and needs to be compatible with
* the flags used in ddi_umem_lock
*
* The following three arguments are used to initialize fields in the
* buf structure and are uninterpreted by this routine.
*
* dev
* blkno
* iodone
*
* sleepflag - is one of DDI_UMEM_SLEEP or DDI_UMEM_NOSLEEP
*
* Returns a buf structure pointer on success (to be freed by freerbuf)
* NULL on any parameter error or memory alloc failure
*
*/
struct buf *
{
/*
* check for valid cookie offset, len
*/
return (NULL);
}
return (NULL);
}
/* direction has to be one of B_READ or B_WRITE */
return (NULL);
}
/* These are the only two valid sleepflags */
return (NULL);
}
/*
* Only cookies of type UMEM_LOCKED and KMEM_NON_PAGEABLE are supported
*/
return (NULL);
}
/* If type is KMEM_NON_PAGEABLE procp is NULL */
return (NULL);
}
}
return (bp);
}
/*
* Fault-handling and related routines
*/
{
if (DEVI_IS_DEVICE_OFFLINE(dip))
return (DDI_DEVSTATE_OFFLINE);
return (DDI_DEVSTATE_DOWN);
else if (DEVI_IS_BUS_QUIESCED(dip))
return (DDI_DEVSTATE_QUIESCED);
else if (DEVI_IS_DEVICE_DEGRADED(dip))
return (DDI_DEVSTATE_DEGRADED);
else
return (DDI_DEVSTATE_UP);
}
void
{
struct ddi_fault_event_data fd;
/*
* Assemble all the information into a fault-event-data structure
*/
/*
* Get eventcookie from defining parent.
*/
return;
}
char *
{
}
int
{
if (devi->devi_device_class)
!= NULL) {
return (DDI_SUCCESS);
}
return (DDI_FAILURE);
}
/*
* Task Queues DDI interfaces.
*/
/* ARGSUSED */
{
char full_name[TASKQ_NAMELEN];
const char *tq_name;
int nodeid = 0;
else {
name = "tq";
}
}
void
{
}
int
{
}
void
{
}
void
{
}
{
}
void
{
}
int
const char *ifname,
char *alnum,
{
const char *p;
int l;
char c;
c = *--p;
if (!isdigit(c)) {
return (DDI_FAILURE);
break;
}
}
if (l == 0 || nonum)
return (DDI_FAILURE);
return (DDI_SUCCESS);
}