/*
* 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 2009 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
/*
* Copyright 2012 Garrett D'Amore <garrett@damore.org>. All rights reserved.
*/
/*
* pseudo bus nexus driver
* hotplug framework test facility
*/
/*
* The pshot driver can be used to exercise the i/o framework together
* with devfs by configuring an arbitrarily complex device tree.
*
* illustrate the operation of devfs together with pshot's bus_config.
* The first command demonstrates that, like the magician showing there's
* conjures up a branch of pshot nodes. Note that pshot's bus_config is
* called sequentially by devfs for each node, as part of the pathname
* resolution, and that each pshot node is fully configured and
* attached before that node's bus_config is called to configure the
* next child down the tree. The final result is a "disk" node configured
* at the bottom of the named hierarchy of pshot nodes.
*
* #
* #
* drwxr-xr-x 2 root sys 512 Feb 6 15:10
*
* pshot supports some unique behaviors as aids for test error cases.
*
* Match these special address formats to behavior:
*
* err.* - induce bus_config error
* delay - induce 1 second of bus_config delay time
* delay,n - induce n seconds of bus_config delay time
* wait - induce 1 second of bus_config wait time
* wait,n - induce n seconds of bus_config wait time
* failinit.* - induce error at INITCHILD
* failprobe.* - induce error at probe
* failattach.* - induce error at attach
*/
#endif
#include <sys/ddi_impldefs.h>
#include <sys/autoconf.h>
static int pshot_log = 0;
static int pshot_devctl_debug = 0;
static int pshot_debug_busy = 0;
static void *pshot_softstatep;
static int pshot_prop_autoattach;
/*
* device configuration data
*/
/* should keep in sync with current release */
static struct {
char *name;
char *val;
} pshot_nodetypes[] = {
{"DDI_NT_SERIAL", DDI_NT_SERIAL},
{"DDI_NT_SERIAL_MB", DDI_NT_SERIAL_MB},
{"DDI_NT_SERIAL_DO", DDI_NT_SERIAL_DO},
{"DDI_NT_SERIAL_MB_DO", DDI_NT_SERIAL_MB_DO},
{"DDI_NT_SERIAL_LOMCON", DDI_NT_SERIAL_LOMCON},
{"DDI_NT_BLOCK", DDI_NT_BLOCK},
{"DDI_NT_BLOCK_CHAN", DDI_NT_BLOCK_CHAN},
{"DDI_NT_BLOCK_WWN", DDI_NT_BLOCK_WWN},
{"DDI_NT_BLOCK_SAS", DDI_NT_BLOCK_SAS},
{"DDI_NT_CD", DDI_NT_CD},
{"DDI_NT_CD_CHAN", DDI_NT_CD_CHAN},
{"DDI_NT_FD", DDI_NT_FD},
{"DDI_NT_ENCLOSURE", DDI_NT_ENCLOSURE},
{"DDI_NT_SCSI_ENCLOSURE", DDI_NT_SCSI_ENCLOSURE},
{"DDI_NT_TAPE", DDI_NT_TAPE},
{"DDI_NT_NET", DDI_NT_NET},
{"DDI_NT_DISPLAY", DDI_NT_DISPLAY},
{"DDI_PSEUDO", DDI_PSEUDO},
{"DDI_NT_AUDIO", DDI_NT_AUDIO},
{"DDI_NT_MOUSE", DDI_NT_MOUSE},
{"DDI_NT_KEYBOARD", DDI_NT_KEYBOARD},
{"DDI_NT_PARALLEL", DDI_NT_PARALLEL},
{"DDI_NT_PRINTER", DDI_NT_PRINTER},
{"DDI_NT_UGEN", DDI_NT_UGEN},
{"DDI_NT_NEXUS", DDI_NT_NEXUS},
{"DDI_NT_SCSI_NEXUS", DDI_NT_SCSI_NEXUS},
{"DDI_NT_ATTACHMENT_POINT", DDI_NT_ATTACHMENT_POINT},
{"DDI_NT_SCSI_ATTACHMENT_POINT", DDI_NT_SCSI_ATTACHMENT_POINT},
{"DDI_NT_PCI_ATTACHMENT_POINT", DDI_NT_PCI_ATTACHMENT_POINT},
{"DDI_NT_SBD_ATTACHMENT_POINT", DDI_NT_SBD_ATTACHMENT_POINT},
{"DDI_NT_FC_ATTACHMENT_POINT", DDI_NT_FC_ATTACHMENT_POINT},
{"DDI_NT_USB_ATTACHMENT_POINT", DDI_NT_USB_ATTACHMENT_POINT},
{"DDI_NT_BLOCK_FABRIC", DDI_NT_BLOCK_FABRIC},
{"DDI_NT_AV_ASYNC", DDI_NT_AV_ASYNC},
{"DDI_NT_AV_ISOCH", DDI_NT_AV_ISOCH},
};
/* Node name */
/* Compatible names... */
static char *pshot_compat_psramdisks[] = {
"psramhead",
"psramrom",
"psramdisk",
"psramd",
"psramwhat"
};
/*
* devices "natively" supported by pshot (i.e. included with SUNWiotu)
* used to initialize pshot_devices with
*/
/* Note: use bad_drv to force attach errors */
};
#define PSHOT_N_STOCK_DEVICES \
(sizeof (pshot_stock_devices) / sizeof (pshot_device_t))
/* protects <pshot_devices>, <pshot_devices_len> */
/*
* event testing
*/
};
#define PSHOT_N_NDI_EVENTS \
(sizeof (pshot_ndi_event_defs) / sizeof (ndi_event_definition_t))
#ifdef DEBUG
};
};
#define PSHOT_N_TEST_EVENTS \
(sizeof (pshot_test_events)/sizeof (ndi_event_definition_t))
#endif
struct register_events {
char *event_name;
void (*event_callback)
(dev_info_t *,
void *arg,
void *impldata);
};
{ PSHOT_EVENT_NAME_DEV_OFFLINE, 0, pshot_event_cb, 0 },
{ PSHOT_EVENT_NAME_DEV_RESET, 0, pshot_event_cb, 0 },
{ PSHOT_EVENT_NAME_BUS_RESET, 0, pshot_event_cb, 0 },
{ PSHOT_EVENT_NAME_BUS_QUIESCE, 0, pshot_event_cb, 0 },
{ PSHOT_EVENT_NAME_BUS_UNQUIESCE, 0, pshot_event_cb, 0 },
{ PSHOT_EVENT_NAME_BUS_TEST_POST, 0, pshot_event_cb, 0 }
};
#define PSHOT_N_DDI_EVENTS \
(sizeof (pshot_register_events) / sizeof (struct register_events))
#ifdef DEBUG
{ "test event 0", 0, pshot_event_cb_test, 0},
{ "test event 1", 0, pshot_event_cb_test, 0},
{ "test event 2", 0, pshot_event_cb_test, 0},
{ "test event 3", 0, pshot_event_cb_test, 0},
{ "test event 4", 0, pshot_event_cb_test, 0},
{ "test event 5", 0, pshot_event_cb_test, 0},
{ "test event 6", 0, pshot_event_cb_test, 0},
{ "test event 7", 0, pshot_event_cb_test, 0}
};
{"test event high 0", 0, pshot_event_cb_test, 0}
};
#endif /* DEBUG */
static struct {
int ioctl_int;
char *ioctl_char;
} pshot_devctls[] = {
{DEVCTL_DEVICE_GETSTATE, "DEVCTL_DEVICE_GETSTATE"},
{DEVCTL_DEVICE_ONLINE, "DEVCTL_DEVICE_ONLINE"},
{DEVCTL_DEVICE_OFFLINE, "DEVCTL_DEVICE_OFFLINE"},
{DEVCTL_DEVICE_REMOVE, "DEVCTL_DEVICE_REMOVE"},
{DEVCTL_BUS_GETSTATE, "DEVCTL_BUS_GETSTATE"},
{DEVCTL_BUS_DEV_CREATE, "DEVCTL_BUS_DEV_CREATE"},
{DEVCTL_BUS_RESET, "DEVCTL_BUS_RESET"},
{DEVCTL_BUS_RESETALL, "DEVCTL_BUS_RESETALL"},
{0, NULL}
};
BUSO_REV, /* busops_rev */
nullbusmap, /* bus_map */
NULL, /* bus_get_intrspec */
NULL, /* bus_add_interspec */
NULL, /* bus_remove_interspec */
i_ddi_map_fault, /* bus_map_fault */
NULL, /* bus_dma_map */
ddi_dma_allochdl, /* bus_dma_allochdl */
ddi_dma_freehdl, /* bus_dma_freehdl */
ddi_dma_bindhdl, /* bus_dma_bindhdl */
ddi_dma_unbindhdl, /* bus_dma_unbindhdl */
ddi_dma_flush, /* bus_dma_flush */
ddi_dma_win, /* bus_dma_win */
ddi_dma_mctl, /* bus_dma_ctl */
pshot_ctl, /* bus_ctl */
ddi_bus_prop_op, /* bus_prop_op */
pshot_get_eventcookie, /* bus_get_eventcookie */
pshot_add_eventcall, /* bus_add_eventcall */
pshot_remove_eventcall, /* bus_remove_event */
pshot_post_event, /* bus_post_event */
NULL, /* bus_intr_ctl */
pshot_bus_config, /* bus_config */
pshot_bus_unconfig, /* bus_unconfig */
NULL, /* bus_fm_init */
NULL, /* bus_fm_fini */
NULL, /* bus_fm_access_enter */
NULL, /* bus_fm_access_exit */
pshot_bus_power, /* bus_power */
pshot_bus_introp /* bus_intr_op */
};
pshot_open, /* open */
pshot_close, /* close */
nodev, /* strategy */
nodev, /* print */
nodev, /* dump */
nodev, /* read */
nodev, /* write */
pshot_ioctl, /* ioctl */
nodev, /* devmap */
nodev, /* mmap */
nodev, /* segmap */
nochpoll, /* poll */
ddi_prop_op, /* prop_op */
NULL, /* streamtab */
CB_REV, /* cb_rev */
nodev, /* aread */
nodev, /* awrite */
};
DEVO_REV, /* devo_rev, */
0, /* refcnt */
pshot_info, /* getinfo */
nulldev, /* identify */
pshot_probe, /* probe */
pshot_attach, /* attach */
pshot_detach, /* detach */
nodev, /* reset */
&pshot_cb_ops, /* driver operations */
&pshot_bus_ops, /* bus operations */
pshot_power, /* power */
ddi_quiesce_not_supported, /* devo_quiesce */
};
/*
* Module linkage information for the kernel.
*/
"pshotnex",
};
};
/*
* pshot_devices is set up on the first attach and destroyed on fini
*
* therefore PSHOT_PROP_DEV* properties may be set just for the root device,
* instead of being set globably, in pshot.conf by specifying the properties
* on a single line in the form:
* name="pshot" parent="/" <dev props ..>
* to unclutter a device tree snapshot.
* this of course produces a long single line that may wrap around several
* times on screen
*/
int
_init(void)
{
int rv;
if (rv != DDI_SUCCESS)
return (rv);
pshot_devices_len = 0;
}
return (rv);
}
int
_fini(void)
{
int rv;
return (rv);
if (pshot_devices)
return (0);
}
int
{
}
/*ARGSUSED*/
static int
{
char *bus_addr;
/*
* Hook for tests to force probe fail
*/
&bus_addr) == DDI_PROP_SUCCESS) {
if (pshot_debug)
"%s forced probe failure\n",
return (DDI_PROBE_FAILURE);
}
}
return (DDI_PROBE_SUCCESS);
}
/*ARGSUSED*/
static int
{
int instance;
switch (infocmd) {
case DDI_INFO_DEVT2DEVINFO:
return (DDI_FAILURE);
}
break;
case DDI_INFO_DEVT2INSTANCE:
break;
default:
return (DDI_FAILURE);
}
return (DDI_SUCCESS);
}
static int
{
int rval, i;
char *bus_addr;
char *pm_comp[] = {
"NAME=bus",
"0=B3",
"1=B2",
"2=B1",
"3=B0"};
prop_flags, "autoattach", 0);
switch (cmd) {
case DDI_ATTACH:
if (pshot_debug)
instance);
/*
* Hook for tests to force attach fail
*/
if (pshot_debug)
"%s forced attach failure\n",
return (DDI_FAILURE);
}
}
/*
* minor nodes setup
*/
DDI_SUCCESS) {
return (DDI_FAILURE);
}
/* set each minor, then create on dip all together */
i = PSHOT_NODENUM_DEVCTL;
/* this assumes contiguous a filling */
for (i = 0; i <= PSHOT_MAX_NODENUM; i++) {
DDI_SUCCESS) {
goto FAIL_ATTACH;
}
}
/*
* pshot_devices setup
*/
if (pshot_devices_setup(devi)) {
"failed");
goto FAIL_ATTACH;
}
/*
* events setup
*/
for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) {
if (pshot_debug)
"ddi_get_eventcookie rval=%d\n",
if (rval == DDI_SUCCESS) {
(void *)pshot,
&pshot->callback_cache[i]);
if (pshot_debug)
"ddi_add_event_handler rval=%d\n",
rval);
}
}
#ifdef DEBUG
if (pshot_event_test_enable) {
pshot_event_test((void *)pshot);
}
#endif
/*
* allocate an ndi event handle
*/
NDI_SLEEP) != NDI_SUCCESS) {
goto FAIL_ATTACH;
}
NDI_SLEEP) != NDI_SUCCESS) {
instance);
}
/*
* setup a test for nexus auto-attach iff we are
* a second level pshot node (parent == /SUNW,pshot)
* enable by setting "autoattach=1" in pshot.conf
*/
/*
* initialize internal state to idle: busy = 0,
* power level = -1
*/
pshot->busy_ioctl = 0;
/*
* Create the "pm-want-child-notification?" property
*/
if (instance == 0) {
if (pshot_debug) {
" create the"
" \"pm-want-child-notification?\" property"
" for the root node\n", instance);
}
"pm-want-child-notification?", NULL, 0)
!= DDI_PROP_SUCCESS) {
" unable to create the"
" \"pm-want-child-notification?\""
goto FAIL_ATTACH;
}
}
/*
* Check if the pm-want-child-notification? property was
* created in pshot_bus_config_setup_nexus() by the parent.
* Set the STRICT_PARENT flag if not.
*/
"pm-want-child-notification?") != 1) {
if (pshot_debug) {
" STRICT PARENT\n", instance);
}
} else {
if (pshot_debug) {
" INVOLVED PARENT\n", instance);
}
}
/*
* create the pm-components property: one component
* with 4 power levels.
* - skip for pshot@XXX,nopm and pshot@XXX,nopm_strict:
* "no-pm-components" property
*/
"no-pm-components") == 0) {
if (pshot_debug) {
" create the \"pm_components\" property\n",
instance);
}
" unable to create the \"pm-components\""
goto FAIL_ATTACH;
}
} else {
if (pshot_debug) {
" NO-PM_COMPONENTS PARENT\n", instance);
}
}
/*
* create the property needed to get DDI_SUSPEND
* and DDI_RESUME calls
*/
if (pshot_debug) {
" create pm-hardware-state property\n",
instance);
}
" unable to create the \"pm-hardware-state\""
goto FAIL_ATTACH;
}
/*
* set power level to max via pm_raise_power(),
* - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
*/
if (pshot_debug) {
" raise power to MAXPWR\n", instance);
}
DDI_SUCCESS) {
" pm_raise_power failed",
goto FAIL_ATTACH;
}
}
if (pshot_log)
return (DDI_SUCCESS);
/*NOTREACHED*/
return (DDI_FAILURE);
case DDI_RESUME:
if (pshot_debug) {
instance);
}
/*
* set power level to max via pm_raise_power(),
* - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
*/
if (pshot_debug) {
" raise power to MAXPWR\n", instance);
}
DDI_SUCCESS) {
" pm_raise_power failed",
}
}
if (pshot_debug) {
instance);
}
return (DDI_SUCCESS);
default:
return (DDI_FAILURE);
}
}
static int
{
int i, rval;
int level_tmp;
return (DDI_FAILURE);
switch (cmd) {
case DDI_DETACH:
if (pshot_debug)
/*
* power off component 0
* - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
*/
if (pshot_debug) {
" power off\n", instance);
}
"pm_lower_power failed for comp 0 to"
return (DDI_FAILURE);
}
/*
* Check if the power level is actually OFF.
* Issue pm_power_has_changed if not.
*/
if (pshot_debug) {
" DDI_DETACH: power off via"
" pm_power_has_changed instead\n",
instance);
}
DDI_SUCCESS) {
if (pshot_debug) {
" DDI_DETACH:"
" pm_power_has_changed"
" failed\n", instance);
}
return (DDI_FAILURE);
}
}
}
for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) {
pshot->callback_cache[i]);
}
}
#ifdef DEBUG
for (i = 0; i < PSHOT_N_TEST_EVENTS; i++) {
pshot->test_callback_cache[i]);
}
}
#endif
if (pshot_log)
break;
case DDI_SUSPEND:
if (pshot_debug)
/*
* fail the suspend if FAIL_SUSPEND_FLAG is set.
* clear the FAIL_SUSPEND_FLAG flag
*/
if (pshot_debug) {
" FAIL_SUSPEND_FLAG set, fail suspend\n",
}
rval = DDI_FAILURE;
} else {
rval = DDI_SUCCESS;
}
/*
* power OFF via pm_power_has_changed
*/
if (pshot_debug) {
" power off via pm_power_has_changed\n",
instance);
}
DDI_SUCCESS) {
if (pshot_debug) {
" DDI_SUSPEND:"
" pm_power_has_changed failed\n",
instance);
}
rval = DDI_FAILURE;
}
}
return (rval);
default:
break;
}
return (DDI_SUCCESS);
}
/*
* returns number of bits to represent <val>
*/
static size_t
{
if (val == 0)
return (0);
;
return (bitcnt);
}
/*
* returns a minor number encoded with instance <inst> and an index <nodenum>
* that identifies the minor node for this instance
*/
static minor_t
{
}
/*
* returns instance of <minor>
*/
static int
{
return (minor >> PSHOT_NODENUM_BITS());
}
/*
* returns node number indexing a minor node for the instance in <minor>
*/
static minor_t
{
}
/*
* pshot_bus_introp: pshot convert an interrupt number to an
* interrupt. NO OP for pseudo drivers.
*/
/*ARGSUSED*/
static int
{
return (DDI_FAILURE);
}
static int
{
int instance;
char *childname;
int childinstance;
char *name;
int circ;
return (ENXIO);
}
switch (ctlop) {
case DDI_CTLOPS_REPORTDEV:
if (rdip == (dev_info_t *)0)
return (DDI_FAILURE);
return (DDI_SUCCESS);
case DDI_CTLOPS_INITCHILD:
{
if (pshot_debug) {
}
}
case DDI_CTLOPS_UNINITCHILD:
{
if (pshot_debug) {
}
}
case DDI_CTLOPS_DMAPMAPC:
case DDI_CTLOPS_REPORTINT:
case DDI_CTLOPS_REGSIZE:
case DDI_CTLOPS_NREGS:
case DDI_CTLOPS_SIDDEV:
case DDI_CTLOPS_SLAVEONLY:
case DDI_CTLOPS_AFFINITY:
case DDI_CTLOPS_POKE:
case DDI_CTLOPS_PEEK:
/*
* These ops correspond to functions that "shouldn't" be called
* by a pseudo driver. So we whine when we're called.
*/
return (DDI_FAILURE);
case DDI_CTLOPS_ATTACH:
{
"no-pm-components") == 1) {
}
if (pshot_debug) {
}
case DDI_PRE:
/*
* Mark nexus busy before a child attaches.
* - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
* - pshot@XXX,nopm_strict)
*/
break;
if (pshot_debug_busy) {
" ctl_attach_pre: busy for %s%d:"
}
break;
case DDI_POST:
/*
* Mark nexus idle after a child attaches.
* - skip if PM_SUPPORTED is not set (pshot@XXX,nopm).
* - also skip if this is not a stict parent and
* - the child is a tape device or a no-pm-components
* - nexus node.
*/
break;
if (pshot_debug_busy) {
" ctl_attach_post: idle for %s%d:"
}
break;
}
return (rval);
}
case DDI_CTLOPS_DETACH:
{
"no-pm-components") == 1) {
}
if (pshot_debug) {
"%s%d: ctl_detach %s%d [%d]\n",
}
case DDI_PRE:
/*
* Mark nexus busy before a child detaches.
* - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
* - pshot@XXX,nopm_strict), or if the child is a
* - no-pm-components nexus node.
*/
break;
if (pshot_debug_busy) {
" ctl_detach_pre: busy for %s%d:"
}
break;
case DDI_POST:
/*
* Mark nexus idle after a child detaches.
* - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
*/
break;
if (pshot_debug_busy) {
" ctl_detach_post: idle for %s%d:"
}
/*
* Mark the driver idle if the NO_INVOL_FLAG
* is set. This is needed to make sure the
* parent is idle after the child detaches
* without calling pm_lower_power().
* Clear the NO_INVOL_FLAG.
* - also mark idle if a tape device has detached
*/
break;
if (pshot_debug_busy) {
" ctl_detach_post: NO_INVOL:"
" idle for %s%d: busy = %d\n",
}
break;
}
return (rval);
}
case DDI_CTLOPS_BTOP:
case DDI_CTLOPS_BTOPR:
case DDI_CTLOPS_DVMAPAGESIZE:
case DDI_CTLOPS_IOMIN:
case DDI_CTLOPS_PTOB:
default:
/*
* The ops that we pass up (default). We pass up memory
* allocation oriented ops that we receive - these may be
* associated with pseudo HBA drivers below us with target
* drivers below them that use ddi memory allocation
* interfaces like scsi_alloc_consistent_buf.
*/
}
}
/*ARGSUSED0*/
static int
{
int circ;
int rv;
return (DDI_FAILURE);
}
/*
* set POWER_FLAG when power() is called.
* ioctl(DEVCT_PM_POWER) is a clear on read call.
*/
/*
* refuse to power OFF if the component is busy
*/
" (%d->%d), DEVICE NOT IDLE: busy = %d",
rv = DDI_FAILURE;
} else {
if (pshot_debug) {
}
rv = DDI_SUCCESS;
}
return (rv);
}
/*ARGSUSED0*/
static int
{
int ret;
int pwrup_res;
int ret_failed = 0;
int pwrup_res_failed = 0;
return (DDI_FAILURE);
}
switch (op) {
if (pshot_debug) {
" %s%d comp %d (%d->%d)\n",
bpc->bpc_nlevel);
}
/*
* mark parent busy if old_level is either -1 or 0,
* and new level is == MAXPWR
* - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
*/
if (pshot_debug_busy) {
"%s%d: pre_bus_power:"
" busy parent for %s%d (%d->%d): "
" busy = %d\n",
}
}
/*
* if new_level > 0, power up parent, if not already at
* MAXPWR, via pm_busop_bus_power
* - skip for the no-pm nexus (pshot@XXX,nopm)
*/
/*
* stuff the bpn struct
*/
/*
* ask pm to power parent up
*/
if (pshot_debug) {
" pm_busop_bus_power on parent for %s%d"
}
BUS_POWER_NEXUS_PWRUP, (void *)&bpn,
(void *)&pwrup_res);
/*
* check the return status individually,
* idle parent and exit if either failed.
*/
if (ret != DDI_SUCCESS) {
"%s%d: pre_bus_power:"
" pm_busop_bus_power FAILED (ret) FOR"
" %s%d (%d->%d)",
ret_failed = 1;
}
if (pwrup_res != DDI_SUCCESS) {
"%s%d: pre_bus_power:"
" pm_busop_bus_power FAILED (pwrup_res)"
" FOR %s%d (%d->%d)",
pwrup_res_failed = 1;
}
if (ret_failed || pwrup_res_failed) {
/*
* decrement the busy count if it
* had been incremented.
*/
bpc->bpc_olevel <= 0) &&
if (pshot_debug_busy) {
" pm_busop_bus_power"
" failed: idle parent for"
" %s%d (%d->%d):"
" busy = %d\n",
}
}
return (DDI_FAILURE);
} else {
if (pshot_debug) {
"%s%d: pre_bus_power:"
" pm_busop_bus_power on parent"
" for %s%d (%d->%d)\n",
}
}
}
break;
if (pshot_debug) {
" %s%d comp %d (%d->%d) result %d\n",
}
/*
* handle pm_busop_bus_power() failure case.
* mark parent idle if had been marked busy.
* - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
*/
if (*(int *)result != DDI_SUCCESS) {
"pshot%d: post_bus_power_failed:"
" pm_busop_bus_power FAILED FOR %s%d (%d->%d)",
bpc->bpc_olevel <= 0) &&
if (pshot_debug_busy) {
" post_bus_power_failed:"
" idle parent for %s%d"
" (%d->%d): busy = %d\n",
}
}
}
/*
* Mark nexus idle when a child's comp 0
* is set to level 0 from level 1, 2, or 3 only.
* And only if result arg == DDI_SUCCESS.
* This will leave the parent busy when the child
* does not call pm_lower_power() on detach after
* unsetting the NO_LOWER_POWER flag.
* If so, need to notify the parent to mark itself
* idle anyway, else the no-involumtary-power-cycles
* test cases will report false passes!
* - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
*/
!(bpc->bpc_olevel <= 0) &&
*(int *)result == DDI_SUCCESS) &&
if (pshot_debug_busy) {
"%s%d: post_bus_power:"
" idle parent for %s%d (%d->%d):"
}
}
break;
case BUS_POWER_HAS_CHANGED:
if (pshot_debug) {
" %s%d comp %d (%d->%d) result %d\n",
}
/*
* Mark nexus idle when a child's comp 0
* is set to level 0 from levels 1, 2, or 3 only.
*
* pm_power_has_changed() calls, first issue
* DEVCTL_PM_BUSY_COMP ioctl to mark parent busy
* before powering the parent up, then power up the
* child node.
* - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
*/
!(bphc->bphc_olevel <= 0)) &&
if (pshot_debug_busy) {
"%s%d: has_changed_bus_power:"
" idle parent for %s%d (%d->%d):"
}
}
break;
default:
}
return (DDI_SUCCESS);
}
static int
{
char *bus_addr;
char *c_nodename;
int bus_id;
int enum_base;
int enum_extent;
/* check for bus_enum node */
#ifdef NOT_USED
return (DDI_FAILURE);
#endif
"busid_ebase", 0);
DDI_PROP_DONTPASS, "busid_range", 0);
/*
* bus enumeration node
*/
if ((enum_base != 0) && (enum_extent != 0)) {
&enum_child) != NDI_SUCCESS)
return (DDI_FAILURE);
(void) ndi_devi_free(enum_child);
return (DDI_FAILURE);
}
if (ndi_devi_online(enum_child, 0) !=
DDI_SUCCESS) {
(void) ndi_devi_free(enum_child);
return (DDI_FAILURE);
}
}
/*
* fail the enumeration node itself
*/
return (DDI_FAILURE);
}
&bus_addr) != DDI_PROP_SUCCESS) {
return (DDI_NOT_WELL_FORMED);
}
return (DDI_FAILURE);
}
if (pshot_debug)
"pshot%d: %s forced INITCHILD failure\n",
return (DDI_FAILURE);
}
if (pshot_log) {
}
return (DDI_SUCCESS);
}
/*ARGSUSED*/
static int
{
return (DDI_SUCCESS);
}
/*
* devctl IOCTL support
*/
/* ARGSUSED */
static int
{
int instance;
return (EINVAL);
return (ENXIO);
/*
* Access is currently determined on a per-instance basis.
* If we want per-node, then need to add state and lock members to
* pshot_minor_t
*/
return (EBUSY);
}
if (pshot_debug)
return (0);
}
/*
* pshot_close
*/
/* ARGSUSED */
static int
{
int instance;
return (EINVAL);
return (ENXIO);
if (pshot_debug)
return (0);
}
/*
* pshot_ioctl: redirects to appropriate command handler based on various
* criteria
*/
/* ARGSUSED */
static int
int *rvalp)
{
int instance;
char *nodename;
return (ENXIO);
if (pshot_debug)
"pshot%d ioctl: dev=%p, cmd=%x, arg=%p, mode=%x\n",
rvalp));
rvalp));
return (ENXIO);
}
/*
* pshot_devctl: handle DEVCTL operations
*/
/* ARGSUSED */
static int
{
int rv = 0;
int instance;
int i;
int ret;
/*
* We can use the generic implementation for these ioctls
*/
for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
if (pshot_debug)
}
}
switch (cmd) {
case DEVCTL_DEVICE_GETSTATE:
case DEVCTL_DEVICE_ONLINE:
case DEVCTL_DEVICE_OFFLINE:
case DEVCTL_DEVICE_REMOVE:
case DEVCTL_BUS_GETSTATE:
case DEVCTL_BUS_DEV_CREATE:
if (pshot_debug && rv != 0) {
}
return (rv);
}
/*
* read devctl ioctl data
*/
return (EFAULT);
switch (cmd) {
case DEVCTL_DEVICE_RESET:
if (pshot_debug)
" DEVCTL_DEVICE_RESET\n", instance);
break;
case DEVCTL_BUS_QUIESCE:
if (pshot_debug)
" DEVCTL_BUS_QUIESCE\n", instance);
if (state == BUS_QUIESCED) {
break;
}
}
break;
case DEVCTL_BUS_UNQUIESCE:
if (pshot_debug)
" DEVCTL_BUS_UNQUIESCE\n", instance);
if (state == BUS_ACTIVE) {
break;
}
}
/*
* quiesce the bus through bus-specific means
*/
break;
case DEVCTL_BUS_RESET:
case DEVCTL_BUS_RESETALL:
/*
* no reset support for the pseudo bus
* but if there were....
*/
break;
/*
* PM related ioctls
*/
case DEVCTL_PM_BUSY_COMP:
/*
* mark component 0 busy.
* Keep track of ioctl updates to the busy count
* via pshot->busy_ioctl.
*/
if (pshot_debug) {
" DEVCTL_PM_BUSY_COMP\n", instance);
}
++(pshot->busy_ioctl);
if (pshot_debug_busy) {
" DEVCTL_PM_BUSY_COMP comp 0 busy"
pshot->busy_ioctl);
}
break;
case DEVCTL_PM_BUSY_COMP_TEST:
/*
* test bus's busy state
*/
if (pshot_debug) {
" DEVCTL_PM_BUSY_COMP_TEST\n", instance);
}
sizeof (uint_t)) != 0) {
" DEVCTL_PM_BUSY_COMP_TEST: copyout failed",
instance);
}
if (pshot_debug_busy) {
" comp 0 busy %d busy_ioctl %d\n", instance,
}
break;
case DEVCTL_PM_IDLE_COMP:
/*
* mark component 0 idle.
* NOP if pshot->busy_ioctl <= 0.
*/
if (pshot_debug) {
" DEVCTL_PM_IDLE_COMP\n", instance);
}
if (pshot->busy_ioctl > 0) {
--(pshot->busy_ioctl);
if (pshot_debug_busy) {
" DEVCTL_PM_IDLE_COM: comp 0"
" busy %d busy_ioctl %d\n", instance,
}
} else {
}
break;
case DEVCTL_PM_RAISE_PWR:
/*
* raise component 0 to full power level MAXPWR via a
* pm_raise_power() call
*/
if (pshot_debug) {
" DEVCTL_PM_RAISE_PWR\n", instance);
}
} else {
if (pshot_debug) {
" DEVCTL_PM_RAISE_POWER: comp 0"
}
}
break;
case DEVCTL_PM_LOWER_PWR:
/*
* pm_lower_power() call for negative testing
* expected to fail.
*/
if (pshot_debug) {
" DEVCTL_PM_LOWER_PWR\n", instance);
}
} else {
if (pshot_debug) {
" DEVCTL_PM_LOWER_POWER comp 0"
}
}
break;
case DEVCTL_PM_CHANGE_PWR_LOW:
/*
* inform the PM framework that component 0 has changed
* power level to 0 via a pm_power_has_changed() call
*/
if (pshot_debug) {
" DEVCTL_PM_CHANGE_PWR_LOW\n", instance);
}
} else {
if (pshot_debug) {
" DEVCTL_PM_CHANGE_PWR_LOW comp 0 to"
}
}
break;
/*
* inform the PM framework that component 0 has changed
* power level to MAXPWR via a pm_power_has_changed() call
*/
if (pshot_debug) {
" DEVCTL_PM_CHANGE_PWR_HIGH\n", instance);
}
!= DDI_SUCCESS) {
} else {
if (pshot_debug) {
" DEVCTL_PM_CHANGE_PWR_HIGH comp 0 to"
}
}
break;
case DEVCTL_PM_POWER:
/*
* test if the pshot_power() routine has been called,
* then clear
*/
if (pshot_debug) {
" DEVCTL_PM_POWER\n", instance);
}
sizeof (uint_t)) != 0) {
" DEVCTL_PM_POWER: copyout failed",
instance);
}
if (pshot_debug) {
}
break;
case DEVCTL_PM_FAIL_SUSPEND:
/*
* fail DDI_SUSPEND
*/
if (pshot_debug) {
" DEVCTL_PM_FAIL_SUSPEND\n", instance);
}
if (pshot_debug) {
instance);
}
break;
/*
* test the STRICT_PARENT flag:
* set => STRICT PARENT
* not set => INVOLVED PARENT
*/
sizeof (uint_t)) != 0) {
" DEVCTL_PM_BUS_STRICT_TEST: copyout failed",
instance);
}
if (pshot_debug) {
" DEVCTL_PM_BUS_STRICT_TEST: type = %s\n",
}
break;
case DEVCTL_PM_BUS_NO_INVOL:
/*
* Set the NO_INVOL_FLAG flag to
* notify the driver that the child will not
* call pm_lower_power() on detach.
* The driver needs to mark itself idle twice
* during DDI_CTLOPS_DETACH (post).
*/
if (pshot_debug) {
" DEVCTL_PM_BUS_NO_INVOL\n", instance);
}
break;
default:
}
return (rv);
}
/*
* pshot_testctl: handle other test operations
* - If <cmd> is a DEVCTL cmd, then <arg> is a dev_t indicating which
* child to direct the DEVCTL to, if applicable;
* furthermore, any cmd here can be sent by layered ioctls (unlike
* those to pshot_devctl() which must come from userland)
*/
/* ARGSUSED */
static int
{
int rv = 0;
int instance;
int i;
/* uint_t flags; */
/* flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0; */
if (cmd & DEVCTL_IOC) {
}
for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
if (pshot_debug)
}
}
switch (cmd) {
case DEVCTL_DEVICE_RESET:
if (pshot_debug)
" DEVCTL_PM_POWER\n", instance);
break;
case DEVCTL_BUS_QUIESCE:
if (pshot_debug)
" DEVCTL_PM_POWER\n", instance);
if (state == BUS_QUIESCED) {
break;
}
}
break;
case DEVCTL_BUS_UNQUIESCE:
if (pshot_debug)
" DEVCTL_PM_POWER\n", instance);
if (state == BUS_ACTIVE) {
break;
}
}
/*
* quiesce the bus through bus-specific means
*/
break;
case DEVCTL_BUS_RESET:
case DEVCTL_BUS_RESETALL:
/*
* no reset support for the pseudo bus
* but if there were....
*/
break;
default:
}
return (rv);
}
static int
{
if (pshot_debug)
"pshot_get_eventcookie:\n\t"
"dip = 0x%p rdip = 0x%p (%s/%d) eventname = %s\n",
}
static int
{
if (pshot_debug)
"pshot_add_eventcall:\n\t"
"dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n\t"
"cb = 0x%p, arg = 0x%p\n",
/* add callback to our event handle */
}
static int
{
if (pshot_debug)
"pshot_remove_eventcall:\n\t"
"dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n",
(void *)cb->ndi_evtcb_cookie,
}
static int
{
if (pshot_debug) {
if (rdip) {
"pshot_post_event:\n\t"
"dip = 0x%p rdip = 0x%p (%s%d\n\t"
"cookie = 0x%p (%s)\n\tbus_impl = 0x%p\n",
(void *)cookie,
} else {
"pshot_post_event:\n\t"
"dip = 0x%p cookie = 0x%p (%s) bus_impl = 0x%p\n",
}
}
/* run callbacks for this event */
}
/*
* the nexus driver will generate events
* that need to go to children
*/
static int
void *bus_impldata)
{
if (pshot_debug) {
if (child) {
"pshot_event: event_tag = 0x%x (%s)\n\t"
"child = 0x%p (%s%d) bus_impl = 0x%p (%s%d)\n",
} else {
"pshot_event: event_tag = 0x%x (%s)\n\t"
"child = NULL, bus_impl = 0x%p (%s%d)\n",
}
}
}
/*
* the pshot driver event notification callback
*/
static void
void *arg, void *bus_impldata)
{
int event_tag;
/* look up the event */
if (pshot_debug) {
"pshot_event_cb:\n\t"
"dip = 0x%p cookie = 0x%p (%s), tag = 0x%x\n\t"
"arg = 0x%p bus_impl = 0x%p (%s%d)\n",
}
switch (event_tag) {
case PSHOT_EVENT_TAG_OFFLINE:
/* notify all subscribers of the this event */
if (pshot_debug) {
}
/*FALLTHRU*/
default:
return;
}
}
static int
{
int rval;
char *devname;
int devstrlen;
int circ;
if (pshot_debug) {
flags |= NDI_DEVI_DEBUG;
"pshot%d: bus_config %s flags=0x%x\n",
}
return (NDI_FAILURE);
}
/*
* Hold the nexus across the bus_config
*/
switch (op) {
case BUS_CONFIG_ONE:
/*
* lookup and hold child device, create if not found
*/
/*
* The framework ensures that the node has
* a name but each nexus is responsible for
* the bus address name space. This driver
* requires that a bus address be specified,
* as will most nexus drivers.
*/
"pshot%d: malformed name %s (no bus address)",
return (NDI_FAILURE);
}
/*
* Handle a few special cases for testing purposes
*/
if (rval == NDI_SUCCESS) {
/*
* Set up either a leaf or nexus device
*/
} else {
}
}
break;
case BUS_CONFIG_DRIVER:
case BUS_CONFIG_ALL:
rval = NDI_SUCCESS;
break;
default:
rval = NDI_FAILURE;
break;
}
if (rval == NDI_SUCCESS)
if (pshot_debug)
return (rval);
}
static int
{
int circ;
if (pshot_debug) {
flags |= NDI_DEVI_DEBUG;
"pshot%d: bus_unconfig %s flags=0x%x\n",
}
/*
* Hold the nexus across the bus_unconfig
*/
switch (op) {
case BUS_UNCONFIG_ONE:
/*
* Nothing special required here
*/
if (pshot_debug) {
}
break;
case BUS_UNCONFIG_DRIVER:
if (pshot_debug > 0) {
"pshot%d: BUS_UNCONFIG_DRIVER: %s\n",
}
break;
case BUS_UNCONFIG_ALL:
if (pshot_debug) {
}
break;
default:
if (pshot_debug) {
}
rval = NDI_FAILURE;
}
if (rval == NDI_SUCCESS)
if (pshot_debug)
return (rval);
}
static dev_info_t *
{
char *addr;
continue;
return (dip);
}
}
} else {
return (dip);
}
}
return (NULL);
}
static void
char *caddr)
{
char *extension;
/*
* extract the address extension
*/
++extension;
} else {
extension = "null";
}
/*
* Create the "pm-want-child-notification?" property for all
* nodes that do not have the "pm_strict" or "nopm_strict"
* extension
*/
"pm-want-child-notification?") == 0) {
if (pshot_debug) {
" nexus_properties:\n\tcreate the"
" \"pm-want-child-notification?\""
" property for %s@%s\n",
}
"pm-want-child-notification?", NULL, 0)
!= DDI_PROP_SUCCESS) {
" nexus_properties:\n\tunable to create"
" the \"pm-want-child-notification?\""
" property for %s@%s",
}
}
}
/*
* Create the "no-pm-components" property for all nodes
* with extension "nopm" or "nopm_strict"
*/
"no-pm-components") == 0) {
if (pshot_debug) {
" nexus_properties:\n\tcreate the"
" \"no-pm-components\""
" property for %s@%s\n",
}
"no-pm-components", NULL, 0)
!= DDI_PROP_SUCCESS) {
" nexus_properties:\n\tunable to create"
" the \"no-pm-components\""
" property for %s@%s",
}
}
}
}
static void
char *caddr)
{
char *extension;
/*
* extract the address extension
*/
++extension;
} else {
extension = "null";
}
/*
* Create the "no-involuntary-power-cycles" property for
* all leaf nodes with extension "no_invol"
*/
"no-involuntary-power-cycles") == 0) {
if (pshot_debug) {
" leaf_properties:\n\tcreate the"
" \"no-involuntary-power-cycles\""
" property for %s@%s\n",
}
"no-involuntary-power-cycles", NULL, 0)
!= DDI_PROP_SUCCESS) {
" leaf_properties:\n\tunable to create the"
" \"no-involuntary-power-cycles\""
" property for %s@%s",
}
}
}
/*
* Create the "dependency-property" property for all leaf
* nodes with extension "dep_prop"
* to be used with the PM_ADD_DEPENDENT_PROPERTY ioctl
*/
"dependency-property") == 0) {
if (pshot_debug) {
" leaf_properties:\n\tcreate the"
" \"dependency-property\""
" property for %s@%s\n",
}
!= DDI_PROP_SUCCESS) {
" leaf_properties:\n\tunable to create the"
" \"dependency-property\" property for"
}
}
}
}
/*
* BUS_CONFIG_ONE: setup a child nexus instance.
*/
static int
{
int rval;
if (child) {
if (pshot_debug) {
"pshot%d: bus_config one %s@%s found\n",
}
/*
* create the "pm-want-child-notification?" property
* for this child, if it doesn't already exist
*/
return (NDI_SUCCESS);
}
(void) ndi_devi_free(child);
return (NDI_FAILURE);
}
if (rval != NDI_SUCCESS) {
(void) ndi_devi_free(child);
return (NDI_FAILURE);
}
/*
* create the "pm-want-child-notification?" property
*/
return (NDI_SUCCESS);
}
/*
* BUS_CONFIG_ONE: setup a child leaf device instance.
* for testing purposes, we will create nodes of a variety of types.
*/
static int
{
char *compat_name;
char *nodetype;
int rval;
int i;
/*
* if we already have a node with this name, return it
*/
/*
* create the "no-involuntary-power-cycles" or
* the "dependency-property" property, if they
* don't already exit
*/
return (NDI_SUCCESS);
}
caddr) != DDI_PROP_SUCCESS) {
(void) ndi_devi_free(child);
return (NDI_FAILURE);
}
/*
* test compatible naming
* if the child nodename is "cdisk", attach the list of compatible
* named disks
*/
5)) != DDI_PROP_SUCCESS) {
(void) ndi_devi_free(child);
return (NDI_FAILURE);
}
} else {
i++) {
if (pshot_debug) {
}
(void) ndi_devi_free(child);
return (NDI_FAILURE);
}
if ((ndi_prop_update_string(
nodetype)) != DDI_PROP_SUCCESS) {
(void) ndi_devi_free(child);
return (NDI_FAILURE);
}
}
}
}
if (rval != NDI_SUCCESS) {
(void) ndi_devi_free(child);
return (NDI_FAILURE);
}
/*
* create the "no-involuntary-power-cycles" or
* the "dependency-property" property
*/
return (NDI_SUCCESS);
}
/*
* Handle some special cases for testing bus_config via pshot
*
* Match these special address formats to behavior:
*
* err.* - induce bus_config error
* delay - induce 1 second of bus_config delay time
* delay,n - induce n seconds of bus_config delay time
* wait - induce 1 second of bus_config wait time
* wait,n - induce n seconds of bus_config wait time
* failinit.* - induce error at INITCHILD
* failprobe.* - induce error at probe
* failattach.* - induce error at attach
*/
/*ARGSUSED*/
static int
{
char *p;
int n;
if (pshot_debug)
"pshot%d: %s forced failure\n",
return (NDI_FAILURE);
}
/*
* The delay and wait strings have the same effect.
* The "wait[,]" support should be removed once the
* devfs test suites are fixed.
* NOTE: delay should not be called from interrupt context
*/
p = caddr+6;
n = stoi(&p);
if (*p != 0)
n = 1;
if (pshot_debug)
"pshot%d: %s delay %d second\n",
if (pshot_debug)
"pshot%d: %s delay 1 second\n",
p = caddr+5;
n = stoi(&p);
if (*p != 0)
n = 1;
if (pshot_debug)
"pshot%d: %s wait %d second\n",
if (pshot_debug)
"pshot%d: %s wait 1 second\n",
}
return (NDI_SUCCESS);
}
/*
* translate nodetype name to actual value
*/
static char *
{
int i;
for (i = 0; pshot_nodetypes[i].name; i++) {
return (pshot_nodetypes[i].val);
}
return (NULL);
}
/*
* grows array pointed to by <dstp>, with <src> data
* <dstlen> = # elements of the original <*dstp>
* <srclen> = # elements of <src>
*
* on success, returns 0 and a pointer to the new array through <dstp> with
* <srclen> + <dstlen> number of elements;
* else returns non-zero
*
* a NULL <*dstp> is OK (a NULL <dstp> is not) and so is a zero <dstlen>
*/
static int
{
size_t i;
KM_SLEEP);
/* keep old pointers and dup new ones */
if (*dstp)
for (i = 0; i < srclen; i++) {
}
/* do last */
if (*dstp)
return (0);
}
/*
* free a pshot_device_t array <dp> with <len> elements
* null pointers within the elements are ok
*/
static void
{
size_t i;
for (i = 0; i < len; i++) {
}
}
/*
* returns an array of pshot_device_t parsed from <dip>'s properties
*
* property structure (i.e. pshot.conf) for pshot:
*
* corresponding | pshot_device_t array elements
* pshot_device_t |
* member by prop name | [0] [1] [2]
* ----------------------|--------------|-------------|-----------------------
* <PSHOT_PROP_DEVNAME> ="disk", "tape", "testdev";
* <PSHOT_PROP_DEVNT> ="DDI_NT_BLOCK","DDI_NT_TAPE","ddi_testdev_nodetype";
* <PSHOT_PROP_DEVCOMPAT>="testdrv", "testdrv", "testdrv";
*
*
* if any of these properties are specified, then:
* - all the members must be specified
* - the number of elements for each string array property must be the same
* - no empty strings allowed
* - nodetypes (PSHOT_PROP_DEVNT) must be the nodetype name as specified in
*
* NOTE: the pshot_nodetypes[] table should be kept in sync with the list
* of ddi nodetypes. It's not normally critical to always be in sync so
* keeping this up-to-date can usually be done "on-demand".
*
* if <flags> & PSHOT_DEV_ANYNT, then custom nodetype strings are allowed.
* these will be duplicated verbatim
*/
static pshot_device_t *
{
uint_t i;
char *str;
compat_arr = NULL;
/*
* warn about any incorrect usage, if specified
*/
return (NULL);
(name_arr_len != nt_arr_len) ||
(name_arr_len != compat_arr_len))
goto FAIL;
for (i = 0; i < name_arr_len; i++) {
if (*name_arr[i] == '\0' ||
*nt_arr[i] == '\0' ||
*compat_arr[i] == '\0')
goto FAIL;
}
for (i = 0; i < name_arr_len; i++) {
if (flags & PSHOT_DEV_ANYNT)
else
goto FAIL;
}
/* set <*lenp> ONLY on success */
*lenp = name_arr_len;
return (devarr);
/*NOTREACHED*/
FAIL:
if (name_arr)
if (nt_arr)
if (compat_arr)
if (devarr)
return (NULL);
}
/*
* if global <pshot_devices> was not set up already (i.e. is NULL):
* sets up global <pshot_devices> and <pshot_devices_len>,
* using device properties from <dip> and global <pshot_stock_devices>.
* device properties, if any, overrides pshot_stock_devices.
*
* returns 0 on success (or if pshot_devices already set up)
*
* INTERNAL LOCKING: <pshot_devices_lock>
*/
static int
{
int rv = 0;
if (pshot_devices != NULL)
goto FAIL;
ASSERT(pshot_devices_len == 0);
if (rv != 0) {
"failed");
goto FAIL;
}
rv = 0;
FAIL:
return (rv);
}
#ifdef NOTNEEDED
/* ARGSUSED */
static int
{
&child)) != NDI_SUCCESS) {
return (DDI_FAILURE);
}
(void) ndi_devi_free(child);
if (return_dip != NULL)
return (DDI_FAILURE);
}
return (DDI_FAILURE);
}
}
return (DDI_SUCCESS);
}
static int
{
int c;
int val;
val *= 10;
val += c - '0';
}
return (val);
}
#endif
static void
{
int rv;
if (rv == NDI_SUCCESS) {
"bus-addr", "0");
&l2child);
if (rv == NDI_SUCCESS)
(void) ndi_prop_update_string(DDI_DEV_T_NONE,
}
if (rv == NDI_SUCCESS)
"bus-addr", "99");
if (rv == NDI_SUCCESS)
"bus-addr", "99");
if (rv == NDI_SUCCESS)
&l2child);
}
#ifdef PRUNE_SNUBS
(DEVI_PROM_NODE((d)->devi_nodeid)) && \
/*
* test code to remove OBP nodes that have not attached
*/
static void
{
int maj;
int rv;
if (maj != -1) {
if (PRUNE_THIS_NODE(cdip)) {
"parent %s@%s pruning node %s",
if (rv != NDI_SUCCESS)
"failed to prune node, "
"err %d", rv);
}
}
}
}
}
#endif /* PRUBE_SNUBS */
#ifdef KERNEL_DEVICE_TREE_WALKER
static void
{
}
static void
{
static void pshot_timeout(void *arg);
while (1) {
mutex_enter(&pwl);
mutex_exit(&pwl);
}
}
static void
{
mutex_enter(&pwl);
mutex_exit(&pwl);
}
static int
{
if (dip != ddi_root_node()) {
"node (%s/%s@%s)\n",
"NULL"));
}
}
return (DDI_WALK_CONTINUE);
}
#endif /* KERNEL_DEVICE_TREE_WALKER */
#ifdef DEBUG
static void
void *arg, void *bus_impldata)
{
int event_tag;
/* look up the event */
"dip = 0x%p cookie = 0x%p (%s), tag = %d\n\t"
"arg = 0x%p bus_impl = 0x%p\n",
}
static void
{
int i, rval;
for (i = 0; i < 8; i++) {
}
for (i = 10; i < 18; i++) {
(void *)hdl);
i, rval);
}
for (i = 10; i < 18; i++) {
i, rval);
}
for (i = 0; i < 8; i++) {
(void) ndi_event_remove_callback(hdl,
pshot->test_callback_cache[i]);
pshot->test_callback_cache[i] = 0;
}
}
void
{
int rval;
&cookie) != DDI_SUCCESS) {
return;
}
}
#endif /* DEBUG */