1 /*
   2  * CDDL HEADER START
   3  *
   4  * The contents of this file are subject to the terms of the
   5  * Common Development and Distribution License (the "License").
   6  * You may not use this file except in compliance with the License.
   7  *
   8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
   9  * or http://www.opensolaris.org/os/licensing.
  10  * See the License for the specific language governing permissions
  11  * and limitations under the License.
  12  *
  13  * When distributing Covered Code, include this CDDL HEADER in each
  14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
  15  * If applicable, add the following below this CDDL HEADER, with the
  16  * fields enclosed by brackets "[]" replaced with your own identifying
  17  * information: Portions Copyright [yyyy] [name of copyright owner]
  18  *
  19  * CDDL HEADER END
  20  */
  21 /*
  22  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
  23  * Use is subject to license terms.
  24  */
  25 /*
  26  * Copyright 2012 Garrett D'Amore <garrett@damore.org>.  All rights reserved.
  27  */
  28 
  29 /*
  30  * pseudo bus nexus driver
  31  * hotplug framework test facility
  32  */
  33 
  34 /*
  35  * The pshot driver can be used to exercise the i/o framework together
  36  * with devfs by configuring an arbitrarily complex device tree.
  37  *
  38  * The pshot driver is rooted at /devices/pshot.  The following commands
  39  * illustrate the operation of devfs together with pshot's bus_config.
  40  * The first command demonstrates that, like the magician showing there's
  41  * nothing up his sleeve, /devices/pshot is empty.  The second command
  42  * conjures up a branch of pshot nodes.  Note that pshot's bus_config is
  43  * called sequentially by devfs for each node, as part of the pathname
  44  * resolution, and that each pshot node is fully configured and
  45  * attached before that node's bus_config is called to configure the
  46  * next child down the tree.  The final result is a "disk" node configured
  47  * at the bottom of the named hierarchy of pshot nodes.
  48  *
  49  *      #
  50  *      # ls /devices/pshot
  51  *      #
  52  *      # ls -ld /devices/pshot/pshot@0/pshot@1/pshot@2/disk@3,0
  53  *      drwxr-xr-x   2 root     sys          512 Feb  6 15:10
  54  *              /devices/pshot/pshot@0/pshot@1/pshot@2/disk@3,0
  55  *
  56  * pshot supports some unique behaviors as aids for test error cases.
  57  *
  58  * Match these special address formats to behavior:
  59  *
  60  *      err.*           - induce bus_config error
  61  *      delay           - induce 1 second of bus_config delay time
  62  *      delay,n         - induce n seconds of bus_config delay time
  63  *      wait            - induce 1 second of bus_config wait time
  64  *      wait,n          - induce n seconds of bus_config wait time
  65  *      failinit.*      - induce error at INITCHILD
  66  *      failprobe.*     - induce error at probe
  67  *      failattach.*    - induce error at attach
  68  */
  69 
  70 #if defined(lint) && !defined(DEBUG)
  71 #define DEBUG   1
  72 #endif
  73 
  74 #include <sys/types.h>
  75 #include <sys/cmn_err.h>
  76 #include <sys/conf.h>
  77 #include <sys/ddi_impldefs.h>
  78 #include <sys/autoconf.h>
  79 #include <sys/open.h>
  80 #include <sys/stat.h>
  81 #include <sys/file.h>
  82 #include <sys/errno.h>
  83 #include <sys/systm.h>
  84 #include <sys/modctl.h>
  85 #include <sys/kmem.h>
  86 #include <sys/ddi.h>
  87 #include <sys/sunddi.h>
  88 #include <sys/sunndi.h>
  89 #include <sys/devctl.h>
  90 #include <sys/disp.h>
  91 #include <sys/utsname.h>
  92 #include <sys/pshot.h>
  93 #include <sys/debug.h>
  94 
  95 static int pshot_log            = 0;
  96 static int pshot_devctl_debug   = 0;
  97 static int pshot_debug_busy     = 0;
  98 
  99 static void *pshot_softstatep;
 100 
 101 static int pshot_prop_autoattach;
 102 
 103 #define MAXPWR  3
 104 
 105 
 106 /*
 107  * device configuration data
 108  */
 109 
 110 /* should keep in sync with current release */
 111 static struct {
 112         char *name;
 113         char *val;
 114 } pshot_nodetypes[] = {
 115         {"DDI_NT_SERIAL", DDI_NT_SERIAL},
 116         {"DDI_NT_SERIAL_MB", DDI_NT_SERIAL_MB},
 117         {"DDI_NT_SERIAL_DO", DDI_NT_SERIAL_DO},
 118         {"DDI_NT_SERIAL_MB_DO", DDI_NT_SERIAL_MB_DO},
 119         {"DDI_NT_SERIAL_LOMCON", DDI_NT_SERIAL_LOMCON},
 120         {"DDI_NT_BLOCK", DDI_NT_BLOCK},
 121         {"DDI_NT_BLOCK_CHAN", DDI_NT_BLOCK_CHAN},
 122         {"DDI_NT_BLOCK_WWN", DDI_NT_BLOCK_WWN},
 123         {"DDI_NT_BLOCK_SAS", DDI_NT_BLOCK_SAS},
 124         {"DDI_NT_CD", DDI_NT_CD},
 125         {"DDI_NT_CD_CHAN", DDI_NT_CD_CHAN},
 126         {"DDI_NT_FD", DDI_NT_FD},
 127         {"DDI_NT_ENCLOSURE", DDI_NT_ENCLOSURE},
 128         {"DDI_NT_SCSI_ENCLOSURE", DDI_NT_SCSI_ENCLOSURE},
 129         {"DDI_NT_TAPE", DDI_NT_TAPE},
 130         {"DDI_NT_NET", DDI_NT_NET},
 131         {"DDI_NT_DISPLAY", DDI_NT_DISPLAY},
 132         {"DDI_PSEUDO", DDI_PSEUDO},
 133         {"DDI_NT_AUDIO", DDI_NT_AUDIO},
 134         {"DDI_NT_MOUSE", DDI_NT_MOUSE},
 135         {"DDI_NT_KEYBOARD", DDI_NT_KEYBOARD},
 136         {"DDI_NT_PARALLEL", DDI_NT_PARALLEL},
 137         {"DDI_NT_PRINTER", DDI_NT_PRINTER},
 138         {"DDI_NT_UGEN", DDI_NT_UGEN},
 139         {"DDI_NT_NEXUS", DDI_NT_NEXUS},
 140         {"DDI_NT_SCSI_NEXUS", DDI_NT_SCSI_NEXUS},
 141         {"DDI_NT_ATTACHMENT_POINT", DDI_NT_ATTACHMENT_POINT},
 142         {"DDI_NT_SCSI_ATTACHMENT_POINT", DDI_NT_SCSI_ATTACHMENT_POINT},
 143         {"DDI_NT_PCI_ATTACHMENT_POINT", DDI_NT_PCI_ATTACHMENT_POINT},
 144         {"DDI_NT_SBD_ATTACHMENT_POINT", DDI_NT_SBD_ATTACHMENT_POINT},
 145         {"DDI_NT_FC_ATTACHMENT_POINT", DDI_NT_FC_ATTACHMENT_POINT},
 146         {"DDI_NT_USB_ATTACHMENT_POINT", DDI_NT_USB_ATTACHMENT_POINT},
 147         {"DDI_NT_BLOCK_FABRIC", DDI_NT_BLOCK_FABRIC},
 148         {"DDI_NT_AV_ASYNC", DDI_NT_AV_ASYNC},
 149         {"DDI_NT_AV_ISOCH", DDI_NT_AV_ISOCH},
 150         { NULL, NULL }
 151 };
 152 
 153 /* Node name */
 154 static char *pshot_compat_diskname = "cdisk";
 155 
 156 /* Compatible names... */
 157 static char *pshot_compat_psramdisks[] = {
 158         "psramhead",
 159         "psramrom",
 160         "psramdisk",
 161         "psramd",
 162         "psramwhat"
 163 };
 164 
 165 /*
 166  * devices "natively" supported by pshot (i.e. included with SUNWiotu)
 167  * used to initialize pshot_devices with
 168  */
 169 static pshot_device_t pshot_stock_devices[] = {
 170         {"disk",        DDI_NT_BLOCK,           "gen_drv"},
 171         {"disk_chan",   DDI_NT_BLOCK_CHAN,      "gen_drv"},
 172         {"disk_wwn",    DDI_NT_BLOCK_WWN,       "gen_drv"},
 173         {"disk_cdrom",  DDI_NT_CD,              "gen_drv"},
 174         {"disk_cdrom.chan", DDI_NT_CD_CHAN,     "gen_drv"},
 175 /* Note: use bad_drv to force attach errors */
 176         {"disk_fd",     DDI_NT_FD,              "bad_drv"},
 177         {"tape",        DDI_NT_TAPE,            "gen_drv"},
 178         {"net",         DDI_NT_NET,             "gen_drv"},
 179         {"display",     DDI_NT_DISPLAY,         "gen_drv"},
 180         {"pseudo",      DDI_PSEUDO,             "gen_drv"},
 181         {"audio",       DDI_NT_AUDIO,           "gen_drv"},
 182         {"mouse",       DDI_NT_MOUSE,           "gen_drv"},
 183         {"keyboard",    DDI_NT_KEYBOARD,        "gen_drv"},
 184         {"nexus",       DDI_NT_NEXUS,           "pshot"}
 185 };
 186 #define PSHOT_N_STOCK_DEVICES \
 187         (sizeof (pshot_stock_devices) / sizeof (pshot_device_t))
 188 
 189 static pshot_device_t *pshot_devices = NULL;
 190 static size_t pshot_devices_len = 0;
 191 
 192 /* protects <pshot_devices>, <pshot_devices_len> */
 193 static kmutex_t pshot_devices_lock;
 194 
 195 
 196 /*
 197  * event testing
 198  */
 199 
 200 static ndi_event_definition_t pshot_ndi_event_defs[] = {
 201 { PSHOT_EVENT_TAG_OFFLINE, PSHOT_EVENT_NAME_DEV_OFFLINE,
 202         EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
 203 
 204 { PSHOT_EVENT_TAG_DEV_RESET, PSHOT_EVENT_NAME_DEV_RESET,
 205         EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT },
 206 
 207 { PSHOT_EVENT_TAG_BUS_RESET, PSHOT_EVENT_NAME_BUS_RESET,
 208         EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
 209 
 210 { PSHOT_EVENT_TAG_BUS_QUIESCE, PSHOT_EVENT_NAME_BUS_QUIESCE,
 211         EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
 212 
 213 { PSHOT_EVENT_TAG_BUS_UNQUIESCE, PSHOT_EVENT_NAME_BUS_UNQUIESCE,
 214         EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
 215 
 216 { PSHOT_EVENT_TAG_TEST_POST, PSHOT_EVENT_NAME_BUS_TEST_POST,
 217         EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT }
 218 };
 219 
 220 
 221 #define PSHOT_N_NDI_EVENTS \
 222         (sizeof (pshot_ndi_event_defs) / sizeof (ndi_event_definition_t))
 223 
 224 #ifdef DEBUG
 225 
 226 static ndi_event_definition_t pshot_test_events[] = {
 227 { 10, "test event 0", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
 228 { 11, "test event 1", EPL_KERNEL, NDI_EVENT_POST_TO_TGT },
 229 { 12, "test event 2", EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT },
 230 { 13, "test event 3", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
 231 { 14, "test event 4", EPL_KERNEL, NDI_EVENT_POST_TO_ALL},
 232 { 15, "test event 5", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL },
 233 { 16, "test event 6", EPL_KERNEL, NDI_EVENT_POST_TO_ALL },
 234 { 17, "test event 7", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL }
 235 };
 236 
 237 static ndi_event_definition_t pshot_test_events_high[] = {
 238 { 20, "test event high 0", EPL_HIGHLEVEL, NDI_EVENT_POST_TO_ALL}
 239 };
 240 
 241 #define PSHOT_N_TEST_EVENTS \
 242         (sizeof (pshot_test_events)/sizeof (ndi_event_definition_t))
 243 #endif
 244 
 245 struct register_events {
 246         char            *event_name;
 247         ddi_eventcookie_t event_cookie;
 248         void    (*event_callback)
 249                         (dev_info_t *,
 250                         ddi_eventcookie_t,
 251                         void *arg,
 252                         void *impldata);
 253         ddi_callback_id_t cb_id;
 254 };
 255 
 256 struct register_events pshot_register_events[] = {
 257 { PSHOT_EVENT_NAME_DEV_OFFLINE, 0, pshot_event_cb, 0 },
 258 { PSHOT_EVENT_NAME_DEV_RESET, 0, pshot_event_cb, 0 },
 259 { PSHOT_EVENT_NAME_BUS_RESET, 0, pshot_event_cb, 0 },
 260 { PSHOT_EVENT_NAME_BUS_QUIESCE, 0, pshot_event_cb, 0 },
 261 { PSHOT_EVENT_NAME_BUS_UNQUIESCE, 0, pshot_event_cb, 0 },
 262 { PSHOT_EVENT_NAME_BUS_TEST_POST, 0, pshot_event_cb, 0 }
 263 };
 264 
 265 #define PSHOT_N_DDI_EVENTS \
 266         (sizeof (pshot_register_events) / sizeof (struct register_events))
 267 
 268 
 269 #ifdef DEBUG
 270 
 271 static struct register_events pshot_register_test[] = {
 272 { "test event 0", 0, pshot_event_cb_test, 0},
 273 { "test event 1", 0, pshot_event_cb_test, 0},
 274 { "test event 2", 0, pshot_event_cb_test, 0},
 275 { "test event 3", 0, pshot_event_cb_test, 0},
 276 { "test event 4", 0, pshot_event_cb_test, 0},
 277 { "test event 5", 0, pshot_event_cb_test, 0},
 278 { "test event 6", 0, pshot_event_cb_test, 0},
 279 { "test event 7", 0, pshot_event_cb_test, 0}
 280 };
 281 
 282 
 283 static struct register_events pshot_register_high_test[] = {
 284         {"test event high 0", 0, pshot_event_cb_test, 0}
 285 };
 286 
 287 #endif /* DEBUG */
 288 
 289 static struct {
 290         int ioctl_int;
 291         char *ioctl_char;
 292 } pshot_devctls[] = {
 293         {DEVCTL_DEVICE_GETSTATE, "DEVCTL_DEVICE_GETSTATE"},
 294         {DEVCTL_DEVICE_ONLINE, "DEVCTL_DEVICE_ONLINE"},
 295         {DEVCTL_DEVICE_OFFLINE, "DEVCTL_DEVICE_OFFLINE"},
 296         {DEVCTL_DEVICE_REMOVE, "DEVCTL_DEVICE_REMOVE"},
 297         {DEVCTL_BUS_GETSTATE, "DEVCTL_BUS_GETSTATE"},
 298         {DEVCTL_BUS_DEV_CREATE, "DEVCTL_BUS_DEV_CREATE"},
 299         {DEVCTL_BUS_RESET, "DEVCTL_BUS_RESET"},
 300         {DEVCTL_BUS_RESETALL, "DEVCTL_BUS_RESETALL"},
 301         {0, NULL}
 302 };
 303 
 304 static struct bus_ops pshot_bus_ops = {
 305         BUSO_REV,                       /* busops_rev */
 306         nullbusmap,                     /* bus_map */
 307         NULL,                           /* bus_get_intrspec */
 308         NULL,                           /* bus_add_interspec */
 309         NULL,                           /* bus_remove_interspec */
 310         i_ddi_map_fault,                /* bus_map_fault */
 311         NULL,                           /* bus_dma_map */
 312         ddi_dma_allochdl,               /* bus_dma_allochdl */
 313         ddi_dma_freehdl,                /* bus_dma_freehdl */
 314         ddi_dma_bindhdl,                /* bus_dma_bindhdl */
 315         ddi_dma_unbindhdl,              /* bus_dma_unbindhdl */
 316         ddi_dma_flush,                  /* bus_dma_flush */
 317         ddi_dma_win,                    /* bus_dma_win */
 318         ddi_dma_mctl,                   /* bus_dma_ctl */
 319         pshot_ctl,                      /* bus_ctl */
 320         ddi_bus_prop_op,                /* bus_prop_op */
 321         pshot_get_eventcookie,          /* bus_get_eventcookie */
 322         pshot_add_eventcall,            /* bus_add_eventcall */
 323         pshot_remove_eventcall,         /* bus_remove_event */
 324         pshot_post_event,               /* bus_post_event */
 325         NULL,                           /* bus_intr_ctl */
 326         pshot_bus_config,               /* bus_config */
 327         pshot_bus_unconfig,             /* bus_unconfig */
 328         NULL,                           /* bus_fm_init */
 329         NULL,                           /* bus_fm_fini */
 330         NULL,                           /* bus_fm_access_enter */
 331         NULL,                           /* bus_fm_access_exit */
 332         pshot_bus_power,                /* bus_power */
 333         pshot_bus_introp                /* bus_intr_op */
 334 };
 335 
 336 static struct cb_ops pshot_cb_ops = {
 337         pshot_open,                     /* open */
 338         pshot_close,                    /* close */
 339         nodev,                          /* strategy */
 340         nodev,                          /* print */
 341         nodev,                          /* dump */
 342         nodev,                          /* read */
 343         nodev,                          /* write */
 344         pshot_ioctl,                    /* ioctl */
 345         nodev,                          /* devmap */
 346         nodev,                          /* mmap */
 347         nodev,                          /* segmap */
 348         nochpoll,                       /* poll */
 349         ddi_prop_op,                    /* prop_op */
 350         NULL,                           /* streamtab */
 351         D_NEW | D_MP | D_HOTPLUG,       /* flags */
 352         CB_REV,                         /* cb_rev */
 353         nodev,                          /* aread */
 354         nodev,                          /* awrite */
 355 };
 356 
 357 static struct dev_ops pshot_ops = {
 358         DEVO_REV,               /* devo_rev, */
 359         0,                      /* refcnt  */
 360         pshot_info,             /* getinfo */
 361         nulldev,                /* identify */
 362         pshot_probe,            /* probe */
 363         pshot_attach,           /* attach */
 364         pshot_detach,           /* detach */
 365         nodev,                  /* reset */
 366         &pshot_cb_ops,              /* driver operations */
 367         &pshot_bus_ops,             /* bus operations */
 368         pshot_power,            /* power */
 369         ddi_quiesce_not_supported,      /* devo_quiesce */
 370 
 371 };
 372 
 373 
 374 /*
 375  * Module linkage information for the kernel.
 376  */
 377 static struct modldrv modldrv = {
 378         &mod_driverops,
 379         "pshotnex",
 380         &pshot_ops,
 381 };
 382 
 383 static struct modlinkage modlinkage = {
 384         MODREV_1, { &modldrv, NULL }
 385 };
 386 
 387 
 388 /*
 389  * pshot_devices is set up on the first attach and destroyed on fini
 390  *
 391  * therefore PSHOT_PROP_DEV* properties may be set just for the root device,
 392  * instead of being set globably, in pshot.conf by specifying the properties
 393  * on a single line in the form:
 394  *      name="pshot" parent="/" <dev props ..>
 395  * to unclutter a device tree snapshot.
 396  * this of course produces a long single line that may wrap around several
 397  * times on screen
 398  */
 399 
 400 int
 401 _init(void)
 402 {
 403         int rv;
 404 
 405         rv = ddi_soft_state_init(&pshot_softstatep, sizeof (pshot_t), 0);
 406 
 407         if (rv != DDI_SUCCESS)
 408                 return (rv);
 409 
 410         mutex_init(&pshot_devices_lock, NULL, MUTEX_DRIVER, NULL);
 411         pshot_devices = NULL;
 412         pshot_devices_len = 0;
 413 
 414         if ((rv = mod_install(&modlinkage)) != 0) {
 415                 ddi_soft_state_fini(&pshot_softstatep);
 416                 mutex_destroy(&pshot_devices_lock);
 417         }
 418         return (rv);
 419 }
 420 
 421 int
 422 _fini(void)
 423 {
 424         int rv;
 425 
 426         if ((rv = mod_remove(&modlinkage)) != 0)
 427                 return (rv);
 428 
 429         ddi_soft_state_fini(&pshot_softstatep);
 430         mutex_destroy(&pshot_devices_lock);
 431         if (pshot_devices)
 432                 pshot_devices_free(pshot_devices, pshot_devices_len);
 433         return (0);
 434 }
 435 
 436 int
 437 _info(struct modinfo *modinfop)
 438 {
 439         return (mod_info(&modlinkage, modinfop));
 440 }
 441 
 442 
 443 /*ARGSUSED*/
 444 static int
 445 pshot_probe(dev_info_t *devi)
 446 {
 447         int     instance = ddi_get_instance(devi);
 448         char    *bus_addr;
 449 
 450         /*
 451          * Hook for tests to force probe fail
 452          */
 453         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 0, "bus-addr",
 454             &bus_addr) == DDI_PROP_SUCCESS) {
 455                 if (strncmp(bus_addr, "failprobe", 9) == 0) {
 456                         if (pshot_debug)
 457                                 cmn_err(CE_CONT, "pshot%d: "
 458                                     "%s forced probe failure\n",
 459                                     instance, bus_addr);
 460                         ddi_prop_free(bus_addr);
 461                         return (DDI_PROBE_FAILURE);
 462                 }
 463                 ddi_prop_free(bus_addr);
 464         }
 465 
 466         return (DDI_PROBE_SUCCESS);
 467 }
 468 
 469 
 470 /*ARGSUSED*/
 471 static int
 472 pshot_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result)
 473 {
 474         int instance;
 475         minor_t minor;
 476         pshot_t *pshot;
 477 
 478         minor = getminor((dev_t)arg);
 479         instance = pshot_minor_decode_inst(minor);
 480         switch (infocmd) {
 481         case DDI_INFO_DEVT2DEVINFO:
 482                 pshot = ddi_get_soft_state(pshot_softstatep, instance);
 483                 if (pshot == NULL) {
 484                         cmn_err(CE_WARN, "pshot_info: get soft state failed "
 485                             "on minor %u, instance %d", minor, instance);
 486                         return (DDI_FAILURE);
 487                 }
 488                 *result = (void *)pshot->dip;
 489                 break;
 490         case DDI_INFO_DEVT2INSTANCE:
 491                 *result = (void *)(uintptr_t)instance;
 492                 break;
 493         default:
 494                 cmn_err(CE_WARN, "pshot_info: unrecognized cmd 0x%x on "
 495                     "minor %u, instance %d", infocmd, minor, instance);
 496                 return (DDI_FAILURE);
 497         }
 498 
 499         return (DDI_SUCCESS);
 500 }
 501 
 502 
 503 static int
 504 pshot_attach(dev_info_t *devi, ddi_attach_cmd_t cmd)
 505 {
 506         int instance = ddi_get_instance(devi);
 507         pshot_t *pshot;
 508         int rval, i;
 509         int prop_flags = DDI_PROP_DONTPASS | DDI_PROP_NOTPROM;
 510         char *bus_addr;
 511         char *pm_comp[] = {
 512                 "NAME=bus",
 513                 "0=B3",
 514                 "1=B2",
 515                 "2=B1",
 516                 "3=B0"};
 517         char *pm_hw_state = {"needs-suspend-resume"};
 518 
 519         pshot_prop_autoattach = ddi_prop_get_int(DDI_DEV_T_ANY, devi,
 520             prop_flags, "autoattach", 0);
 521 
 522         switch (cmd) {
 523 
 524         case DDI_ATTACH:
 525                 if (pshot_debug)
 526                         cmn_err(CE_CONT, "attach: %s%d/pshot%d\n",
 527                             ddi_get_name(ddi_get_parent(devi)),
 528                             ddi_get_instance(ddi_get_parent(devi)),
 529                             instance);
 530 
 531                 /*
 532                  * Hook for tests to force attach fail
 533                  */
 534                 if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 0, "bus-addr",
 535                     &bus_addr) == DDI_PROP_SUCCESS) && bus_addr != NULL) {
 536                         if (strncmp(bus_addr, "failattach", 10) == 0) {
 537                                 if (pshot_debug)
 538                                         cmn_err(CE_CONT, "pshot%d: "
 539                                             "%s forced attach failure\n",
 540                                             instance, bus_addr);
 541                                 ddi_prop_free(bus_addr);
 542                                 return (DDI_FAILURE);
 543                         }
 544                         ddi_prop_free(bus_addr);
 545                 }
 546 
 547                 /*
 548                  * minor nodes setup
 549                  */
 550                 if (ddi_soft_state_zalloc(pshot_softstatep, instance) !=
 551                     DDI_SUCCESS) {
 552                         return (DDI_FAILURE);
 553                 }
 554                 pshot = ddi_get_soft_state(pshot_softstatep, instance);
 555                 pshot->dip = devi;
 556                 pshot->instance = instance;
 557                 mutex_init(&pshot->lock, NULL, MUTEX_DRIVER, NULL);
 558 
 559                 /* set each minor, then create on dip all together */
 560 
 561                 i = PSHOT_NODENUM_DEVCTL;
 562                 pshot->nodes[i].pshot = pshot;
 563                 pshot->nodes[i].minor = pshot_minor_encode(instance, i);
 564                 (void) strncpy(pshot->nodes[i].name, PSHOT_NODENAME_DEVCTL,
 565                     PSHOT_MAX_MINOR_NAMELEN);
 566 
 567                 i = PSHOT_NODENUM_TESTCTL;
 568                 pshot->nodes[i].pshot = pshot;
 569                 pshot->nodes[i].minor = pshot_minor_encode(instance, i);
 570                 (void) strncpy(pshot->nodes[i].name, PSHOT_NODENAME_TESTCTL,
 571                     PSHOT_MAX_MINOR_NAMELEN);
 572 
 573                 /* this assumes contiguous a filling */
 574                 for (i = 0; i <= PSHOT_MAX_NODENUM; i++) {
 575                         if (ddi_create_minor_node(devi, pshot->nodes[i].name,
 576                             S_IFCHR, pshot->nodes[i].minor, DDI_NT_NEXUS, 0) !=
 577                             DDI_SUCCESS) {
 578                                 cmn_err(CE_WARN, "attach: cannot create "
 579                                     "minor %s", pshot->nodes[i].name);
 580                                 goto FAIL_ATTACH;
 581                         }
 582                 }
 583 
 584                 /*
 585                  * pshot_devices setup
 586                  */
 587                 if (pshot_devices_setup(devi)) {
 588                         cmn_err(CE_WARN, "attach: pshot devices setup "
 589                             "failed");
 590                         goto FAIL_ATTACH;
 591                 }
 592 
 593                 /*
 594                  * events setup
 595                  */
 596                 for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) {
 597                         rval =  ddi_get_eventcookie(devi,
 598                             pshot_register_events[i].event_name,
 599                             &pshot_register_events[i].event_cookie);
 600 
 601                         if (pshot_debug)
 602                                 cmn_err(CE_CONT, "pshot%d: event=%s:"
 603                                     "ddi_get_eventcookie rval=%d\n",
 604                                     instance,
 605                                     pshot_register_events[i].event_name, rval);
 606 
 607                         if (rval == DDI_SUCCESS) {
 608                                 rval = ddi_add_event_handler(devi,
 609                                     pshot_register_events[i].event_cookie,
 610                                     pshot_register_events[i].event_callback,
 611                                     (void *)pshot,
 612                                     &pshot->callback_cache[i]);
 613 
 614                                 if (pshot_debug)
 615                                         cmn_err(CE_CONT, "pshot%d: event=%s: "
 616                                             "ddi_add_event_handler rval=%d\n",
 617                                             instance,
 618                                             pshot_register_events[i].event_name,
 619                                             rval);
 620                         }
 621                 }
 622 
 623 #ifdef DEBUG
 624                 if (pshot_event_test_enable) {
 625                         pshot_event_test((void *)pshot);
 626                         (void) timeout(pshot_event_test_post_one, (void *)pshot,
 627                             instance * drv_usectohz(60000000));
 628                 }
 629 #endif
 630 
 631                 /*
 632                  * allocate an ndi event handle
 633                  */
 634                 if (ndi_event_alloc_hdl(devi, NULL, &pshot->ndi_event_hdl,
 635                     NDI_SLEEP) != NDI_SUCCESS) {
 636                         goto FAIL_ATTACH;
 637                 }
 638 
 639                 pshot->ndi_events.ndi_events_version = NDI_EVENTS_REV1;
 640                 pshot->ndi_events.ndi_n_events = PSHOT_N_NDI_EVENTS;
 641                 pshot->ndi_events.ndi_event_defs = pshot_ndi_event_defs;
 642 
 643                 if (ndi_event_bind_set(pshot->ndi_event_hdl, &pshot->ndi_events,
 644                     NDI_SLEEP) != NDI_SUCCESS) {
 645                         cmn_err(CE_CONT, "pshot%d bind set failed\n",
 646                             instance);
 647                 }
 648 
 649                 /*
 650                  * setup a test for nexus auto-attach iff we are
 651                  * a second level pshot node (parent == /SUNW,pshot)
 652                  * enable by setting "autoattach=1" in pshot.conf
 653                  */
 654                 if ((PARENT_IS_PSHOT(devi)) && (pshot_prop_autoattach != 0) &&
 655                     (ddi_get_instance(ddi_get_parent(devi))) == 0)
 656                         pshot_setup_autoattach(devi);
 657 
 658                 /*
 659                  * initialize internal state to idle: busy = 0,
 660                  * power level = -1
 661                  */
 662                 mutex_enter(&pshot->lock);
 663                 pshot->busy = 0;
 664                 pshot->busy_ioctl = 0;
 665                 pshot->level = -1;
 666                 pshot->state &= ~STRICT_PARENT;
 667                 pshot->state |= PM_SUPPORTED;
 668                 mutex_exit(&pshot->lock);
 669 
 670                 /*
 671                  * Create the "pm-want-child-notification?" property
 672                  * for the root node /devices/pshot
 673                  */
 674                 if (instance == 0) {
 675                         if (pshot_debug) {
 676                                 cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:\n\t"
 677                                     " create the"
 678                                     " \"pm-want-child-notification?\" property"
 679                                     " for the root node\n", instance);
 680                         }
 681                         if (ddi_prop_create(DDI_DEV_T_NONE, devi, 0,
 682                             "pm-want-child-notification?", NULL, 0)
 683                             != DDI_PROP_SUCCESS) {
 684                                 cmn_err(CE_WARN, "%s%d:\n\t"
 685                                     " unable to create the"
 686                                     " \"pm-want-child-notification?\""
 687                                     " property", ddi_get_name(devi),
 688                                     ddi_get_instance(devi));
 689 
 690                                 goto FAIL_ATTACH;
 691                         }
 692                 }
 693 
 694                 /*
 695                  * Check if the pm-want-child-notification? property was
 696                  * created in pshot_bus_config_setup_nexus() by the parent.
 697                  * Set the STRICT_PARENT flag if not.
 698                  */
 699                 if (ddi_prop_exists(DDI_DEV_T_ANY, devi,
 700                     (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
 701                     "pm-want-child-notification?") != 1) {
 702                         if (pshot_debug) {
 703                                 cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
 704                                     " STRICT PARENT\n", instance);
 705                         }
 706                         mutex_enter(&pshot->lock);
 707                         pshot->state |= STRICT_PARENT;
 708                         mutex_exit(&pshot->lock);
 709                 } else {
 710                         if (pshot_debug) {
 711                                 cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
 712                                     " INVOLVED PARENT\n", instance);
 713                         }
 714                         mutex_enter(&pshot->lock);
 715                         pshot->state &= ~STRICT_PARENT;
 716                         mutex_exit(&pshot->lock);
 717                 }
 718 
 719                 /*
 720                  * create the pm-components property: one component
 721                  * with 4 power levels.
 722                  * - skip for pshot@XXX,nopm and pshot@XXX,nopm_strict:
 723                  * "no-pm-components" property
 724                  */
 725                 if (ddi_prop_exists(DDI_DEV_T_ANY, devi,
 726                     (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
 727                     "no-pm-components") == 0) {
 728                         if (pshot_debug) {
 729                                 cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
 730                                     " create the \"pm_components\" property\n",
 731                                     instance);
 732                         }
 733                         if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi,
 734                             "pm-components", pm_comp, 5) != DDI_PROP_SUCCESS) {
 735                                 cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t"
 736                                     " unable to create the \"pm-components\""
 737                                     " property", ddi_get_name(devi),
 738                                     ddi_get_instance(devi));
 739 
 740                                 goto FAIL_ATTACH;
 741                         }
 742                 } else {
 743                         if (pshot_debug) {
 744                                 cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
 745                                     " NO-PM_COMPONENTS PARENT\n", instance);
 746                         }
 747                         mutex_enter(&pshot->lock);
 748                         pshot->state &= ~PM_SUPPORTED;
 749                         mutex_exit(&pshot->lock);
 750                 }
 751 
 752                 /*
 753                  * create the property needed to get DDI_SUSPEND
 754                  * and DDI_RESUME calls
 755                  */
 756                 if (pshot_debug) {
 757                         cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
 758                             " create pm-hardware-state property\n",
 759                             instance);
 760                 }
 761                 if (ddi_prop_update_string(DDI_DEV_T_NONE, devi,
 762                     "pm-hardware-state", pm_hw_state) != DDI_PROP_SUCCESS) {
 763                         cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t"
 764                             " unable to create the \"pm-hardware-state\""
 765                             " property", ddi_get_name(devi),
 766                             ddi_get_instance(devi));
 767 
 768                         goto FAIL_ATTACH;
 769                 }
 770 
 771                 /*
 772                  * set power level to max via pm_raise_power(),
 773                  * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
 774                  */
 775                 if (pshot->state & PM_SUPPORTED) {
 776                         if (pshot_debug) {
 777                                 cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:"
 778                                     " raise power to MAXPWR\n", instance);
 779                         }
 780                         if (pm_raise_power(pshot->dip, 0, MAXPWR) !=
 781                             DDI_SUCCESS) {
 782                                 cmn_err(CE_WARN, "%s%d: DDI_ATTACH:"
 783                                     " pm_raise_power failed",
 784                                     ddi_get_name(devi),
 785                                     ddi_get_instance(devi));
 786 
 787                                 goto FAIL_ATTACH;
 788 
 789                         }
 790                 }
 791 
 792                 if (pshot_log)
 793                         cmn_err(CE_CONT, "pshot%d attached\n", instance);
 794                 ddi_report_dev(devi);
 795 
 796                 return (DDI_SUCCESS);
 797                 /*NOTREACHED*/
 798 FAIL_ATTACH:
 799                 ddi_remove_minor_node(devi, NULL);
 800                 mutex_destroy(&pshot->lock);
 801                 ddi_soft_state_free(pshot_softstatep, instance);
 802                 return (DDI_FAILURE);
 803 
 804         case DDI_RESUME:
 805                 if (pshot_debug) {
 806                         cmn_err(CE_CONT, "pshot%d: DDI_RESUME: resuming\n",
 807                             instance);
 808                 }
 809                 pshot = ddi_get_soft_state(pshot_softstatep, instance);
 810 
 811                 /*
 812                  * set power level to max via pm_raise_power(),
 813                  * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
 814                  */
 815                 if (pshot->state & PM_SUPPORTED) {
 816                         if (pshot_debug) {
 817                                 cmn_err(CE_CONT, "pshot%d: DDI_RESUME:"
 818                                     " raise power to MAXPWR\n", instance);
 819                         }
 820                         if (pm_raise_power(pshot->dip, 0, MAXPWR) !=
 821                             DDI_SUCCESS) {
 822                                 cmn_err(CE_WARN, "%s%d: DDI_RESUME:"
 823                                     " pm_raise_power failed",
 824                                     ddi_get_name(devi),
 825                                     ddi_get_instance(devi));
 826                         }
 827                 }
 828 
 829                 if (pshot_debug) {
 830                         cmn_err(CE_CONT, "pshot%d: DDI_RESUME: resumed\n",
 831                             instance);
 832                 }
 833                 return (DDI_SUCCESS);
 834 
 835         default:
 836                 return (DDI_FAILURE);
 837         }
 838 }
 839 
 840 static int
 841 pshot_detach(dev_info_t *devi, ddi_detach_cmd_t cmd)
 842 {
 843         int instance = ddi_get_instance(devi);
 844         int i, rval;
 845         pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
 846         int level_tmp;
 847 
 848         if (pshot == NULL)
 849                 return (DDI_FAILURE);
 850 
 851         switch (cmd) {
 852 
 853         case DDI_DETACH:
 854                 if (pshot_debug)
 855                         cmn_err(CE_CONT, "pshot%d: DDI_DETACH\n", instance);
 856                 /*
 857                  * power off component 0
 858                  * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
 859                  */
 860                 if (pshot->state & PM_SUPPORTED) {
 861                         if (pshot_debug) {
 862                                 cmn_err(CE_CONT, "pshot%d: DDI_DETACH:"
 863                                     " power off\n", instance);
 864                         }
 865                         if (pm_lower_power(pshot->dip, 0, 0) != DDI_SUCCESS) {
 866                                 cmn_err(CE_WARN, "%s%d: DDI_DETACH:\n\t"
 867                                     "pm_lower_power failed for comp 0 to"
 868                                     " level 0", ddi_get_name(devi),
 869                                     ddi_get_instance(devi));
 870 
 871                                 return (DDI_FAILURE);
 872                         }
 873 
 874                         /*
 875                          * Check if the power level is actually OFF.
 876                          * Issue pm_power_has_changed if not.
 877                          */
 878                         mutex_enter(&pshot->lock);
 879                         if (pshot->level != 0) {
 880                                 if (pshot_debug) {
 881                                         cmn_err(CE_NOTE, "pshot%d:"
 882                                             " DDI_DETACH: power off via"
 883                                             " pm_power_has_changed instead\n",
 884                                             instance);
 885                                 }
 886                                 level_tmp = pshot->level;
 887                                 pshot->level = 0;
 888                                 if (pm_power_has_changed(pshot->dip, 0, 0) !=
 889                                     DDI_SUCCESS) {
 890                                         if (pshot_debug) {
 891                                                 cmn_err(CE_NOTE, "pshot%d:"
 892                                                     " DDI_DETACH:"
 893                                                     " pm_power_has_changed"
 894                                                     " failed\n", instance);
 895                                         }
 896                                         pshot->level = level_tmp;
 897                                         mutex_exit(&pshot->lock);
 898 
 899                                         return (DDI_FAILURE);
 900                                 }
 901                         }
 902                         mutex_exit(&pshot->lock);
 903                 }
 904 
 905                 for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) {
 906                         if (pshot->callback_cache[i] != NULL) {
 907                                 rval = ddi_remove_event_handler(
 908                                     pshot->callback_cache[i]);
 909                                 ASSERT(rval == DDI_SUCCESS);
 910                         }
 911                 }
 912 
 913 #ifdef DEBUG
 914                 for (i = 0; i < PSHOT_N_TEST_EVENTS; i++) {
 915                         if (pshot->test_callback_cache[i] != NULL) {
 916                                 rval = ddi_remove_event_handler(
 917                                     pshot->test_callback_cache[i]);
 918                                 ASSERT(rval == DDI_SUCCESS);
 919                         }
 920                 }
 921 #endif
 922                 rval = ndi_event_free_hdl(pshot->ndi_event_hdl);
 923                 ASSERT(rval == DDI_SUCCESS);
 924 
 925                 if (pshot_log)
 926                         cmn_err(CE_CONT, "pshot%d detached\n", instance);
 927 
 928                 ddi_remove_minor_node(devi, NULL);
 929                 mutex_destroy(&pshot->lock);
 930                 ddi_soft_state_free(pshot_softstatep, instance);
 931                 break;
 932 
 933         case DDI_SUSPEND:
 934                 if (pshot_debug)
 935                         cmn_err(CE_CONT, "pshot%d: DDI_SUSPEND\n", instance);
 936                 /*
 937                  * fail the suspend if FAIL_SUSPEND_FLAG is set.
 938                  * clear the FAIL_SUSPEND_FLAG flag
 939                  */
 940                 mutex_enter(&pshot->lock);
 941                 if (pshot->state & FAIL_SUSPEND_FLAG) {
 942                         if (pshot_debug) {
 943                                 cmn_err(CE_CONT, "pshot%d:"
 944                                     " FAIL_SUSPEND_FLAG set, fail suspend\n",
 945                                     ddi_get_instance(devi));
 946                         }
 947                         pshot->state &= ~FAIL_SUSPEND_FLAG;
 948                         rval = DDI_FAILURE;
 949                 } else {
 950                         rval = DDI_SUCCESS;
 951                 }
 952                 mutex_exit(&pshot->lock);
 953 
 954                 /*
 955                  * power OFF via pm_power_has_changed
 956                  */
 957                 mutex_enter(&pshot->lock);
 958                 if (pshot->state & PM_SUPPORTED) {
 959                         if (pshot_debug) {
 960                                 cmn_err(CE_CONT, "pshot%d: DDI_SUSPEND:"
 961                                     " power off via pm_power_has_changed\n",
 962                                     instance);
 963                         }
 964                         level_tmp = pshot->level;
 965                         pshot->level = 0;
 966                         if (pm_power_has_changed(pshot->dip, 0, 0) !=
 967                             DDI_SUCCESS) {
 968                                 if (pshot_debug) {
 969                                         cmn_err(CE_NOTE, "pshot%d:"
 970                                             " DDI_SUSPEND:"
 971                                             " pm_power_has_changed failed\n",
 972                                             instance);
 973                                 }
 974                                 pshot->level = level_tmp;
 975                                 rval = DDI_FAILURE;
 976                         }
 977                 }
 978                 mutex_exit(&pshot->lock);
 979                 return (rval);
 980 
 981         default:
 982                 break;
 983         }
 984 
 985         return (DDI_SUCCESS);
 986 }
 987 
 988 
 989 /*
 990  * returns number of bits to represent <val>
 991  */
 992 static size_t
 993 pshot_numbits(size_t val)
 994 {
 995         size_t bitcnt;
 996 
 997         if (val == 0)
 998                 return (0);
 999         for (bitcnt = 1; 1 << bitcnt < val; bitcnt++)
1000                 ;
1001         return (bitcnt);
1002 }
1003 
1004 /*
1005  * returns a minor number encoded with instance <inst> and an index <nodenum>
1006  * that identifies the minor node for this instance
1007  */
1008 static minor_t
1009 pshot_minor_encode(int inst, minor_t nodenum)
1010 {
1011         return (((minor_t)inst << PSHOT_NODENUM_BITS()) |
1012             (((1 << PSHOT_NODENUM_BITS()) - 1) & nodenum));
1013 }
1014 
1015 /*
1016  * returns instance of <minor>
1017  */
1018 static int
1019 pshot_minor_decode_inst(minor_t minor)
1020 {
1021         return (minor >> PSHOT_NODENUM_BITS());
1022 }
1023 
1024 /*
1025  * returns node number indexing a minor node for the instance in <minor>
1026  */
1027 static minor_t
1028 pshot_minor_decode_nodenum(minor_t minor)
1029 {
1030         return (minor & ((1 << PSHOT_NODENUM_BITS()) - 1));
1031 }
1032 
1033 
1034 /*
1035  * pshot_bus_introp: pshot convert an interrupt number to an
1036  *                         interrupt. NO OP for pseudo drivers.
1037  */
1038 /*ARGSUSED*/
1039 static int
1040 pshot_bus_introp(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op,
1041     ddi_intr_handle_impl_t *hdlp, void *result)
1042 {
1043         return (DDI_FAILURE);
1044 }
1045 static int
1046 pshot_ctl(dev_info_t *dip, dev_info_t *rdip,
1047     ddi_ctl_enum_t ctlop, void *arg, void *result)
1048 {
1049         int instance;
1050         pshot_t *pshot;
1051         char *childname;
1052         int childinstance;
1053         char *name;
1054         int circ;
1055         struct attachspec *as;
1056         struct detachspec *ds;
1057         int rval = DDI_SUCCESS;
1058         int no_pm_components_child;
1059 
1060         name = ddi_get_name(dip);
1061         instance = ddi_get_instance(dip);
1062         pshot = ddi_get_soft_state(pshot_softstatep, instance);
1063         if (pshot == NULL) {
1064                 return (ENXIO);
1065         }
1066 
1067         switch (ctlop) {
1068         case DDI_CTLOPS_REPORTDEV:
1069                 if (rdip == (dev_info_t *)0)
1070                         return (DDI_FAILURE);
1071                 cmn_err(CE_CONT, "?pshot-device: %s%d\n",
1072                     ddi_get_name(rdip), ddi_get_instance(rdip));
1073                 return (DDI_SUCCESS);
1074 
1075         case DDI_CTLOPS_INITCHILD:
1076         {
1077                 dev_info_t *child = (dev_info_t *)arg;
1078 
1079                 if (pshot_debug) {
1080                         cmn_err(CE_CONT, "initchild %s%d/%s%d state 0x%x\n",
1081                             ddi_get_name(dip), ddi_get_instance(dip),
1082                             ddi_node_name(child), ddi_get_instance(child),
1083                             DEVI(child)->devi_state);
1084                 }
1085 
1086                 return (pshot_initchild(dip, child));
1087         }
1088 
1089         case DDI_CTLOPS_UNINITCHILD:
1090         {
1091                 dev_info_t *child = (dev_info_t *)arg;
1092 
1093                 if (pshot_debug) {
1094                         cmn_err(CE_CONT, "uninitchild %s%d/%s%d state 0x%x\n",
1095                             ddi_get_name(dip), ddi_get_instance(dip),
1096                             ddi_node_name(child), ddi_get_instance(child),
1097                             DEVI(child)->devi_state);
1098                 }
1099 
1100                 return (pshot_uninitchild(dip, child));
1101         }
1102 
1103         case DDI_CTLOPS_DMAPMAPC:
1104         case DDI_CTLOPS_REPORTINT:
1105         case DDI_CTLOPS_REGSIZE:
1106         case DDI_CTLOPS_NREGS:
1107         case DDI_CTLOPS_SIDDEV:
1108         case DDI_CTLOPS_SLAVEONLY:
1109         case DDI_CTLOPS_AFFINITY:
1110         case DDI_CTLOPS_POKE:
1111         case DDI_CTLOPS_PEEK:
1112                 /*
1113                  * These ops correspond to functions that "shouldn't" be called
1114                  * by a pseudo driver.  So we whine when we're called.
1115                  */
1116                 cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n",
1117                     ddi_get_name(dip), ddi_get_instance(dip),
1118                     ctlop, ddi_get_name(rdip), ddi_get_instance(rdip));
1119                 return (DDI_FAILURE);
1120 
1121         case DDI_CTLOPS_ATTACH:
1122         {
1123                 dev_info_t *child = (dev_info_t *)rdip;
1124                 childname = ddi_node_name(child);
1125                 childinstance = ddi_get_instance(child);
1126                 as = (struct attachspec *)arg;
1127 
1128                 no_pm_components_child = 0;
1129                 if (ddi_prop_exists(DDI_DEV_T_ANY, child,
1130                     (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
1131                     "no-pm-components") == 1) {
1132                         no_pm_components_child = 1;
1133                 }
1134                 if (pshot_debug) {
1135                         cmn_err(CE_CONT, "%s%d: ctl_attach %s%d [%d]\n",
1136                             name, instance, childname, childinstance,
1137                             no_pm_components_child);
1138                 }
1139 
1140                 ndi_devi_enter(dip, &circ);
1141 
1142                 switch (as->when) {
1143                 case DDI_PRE:
1144                         /*
1145                          * Mark nexus busy before a child attaches.
1146                          * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
1147                          * - pshot@XXX,nopm_strict)
1148                          */
1149                         if (!(pshot->state & PM_SUPPORTED))
1150                                 break;
1151                         mutex_enter(&pshot->lock);
1152                         ++(pshot->busy);
1153                         if (pshot_debug_busy) {
1154                                 cmn_err(CE_CONT, "%s%d:"
1155                                     " ctl_attach_pre: busy for %s%d:"
1156                                     " busy = %d\n", name, instance,
1157                                     childname, childinstance,
1158                                     pshot->busy);
1159                         }
1160                         mutex_exit(&pshot->lock);
1161                         rval = pm_busy_component(dip, 0);
1162                         ASSERT(rval == DDI_SUCCESS);
1163                         break;
1164                 case DDI_POST:
1165                         /*
1166                          * Mark nexus idle after a child attaches.
1167                          * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm).
1168                          * - also skip if this is not a stict parent and
1169                          * - the child is a tape device or a no-pm-components
1170                          * - nexus node.
1171                          */
1172                         if (!(pshot->state & PM_SUPPORTED) ||
1173                             (strcmp(childname, "tape") == 0 &&
1174                             !(pshot->state & STRICT_PARENT)) ||
1175                             no_pm_components_child)
1176                                 break;
1177                         mutex_enter(&pshot->lock);
1178                         ASSERT(pshot->busy > 0);
1179                         --pshot->busy;
1180                         if (pshot_debug_busy) {
1181                                 cmn_err(CE_CONT, "%s%d:"
1182                                     " ctl_attach_post: idle for %s%d:"
1183                                     " busy = %d\n", name, instance,
1184                                     childname, childinstance,
1185                                     pshot->busy);
1186                         }
1187                         mutex_exit(&pshot->lock);
1188                         rval = pm_idle_component(dip, 0);
1189                         ASSERT(rval == DDI_SUCCESS);
1190                         break;
1191                 }
1192 
1193                 ndi_devi_exit(dip, circ);
1194 
1195                 return (rval);
1196         }
1197         case DDI_CTLOPS_DETACH:
1198                 {
1199                 dev_info_t *child = (dev_info_t *)rdip;
1200                 childname = ddi_node_name(child);
1201                 childinstance = ddi_get_instance(child);
1202                 ds = (struct detachspec *)arg;
1203 
1204                 no_pm_components_child = 0;
1205                 if (ddi_prop_exists(DDI_DEV_T_ANY, child,
1206                     (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
1207                     "no-pm-components") == 1) {
1208                         no_pm_components_child = 1;
1209                 }
1210                 if (pshot_debug) {
1211                         cmn_err(CE_CONT,
1212                             "%s%d: ctl_detach %s%d [%d]\n",
1213                             name, instance, childname, childinstance,
1214                             no_pm_components_child);
1215                 }
1216 
1217                 ndi_devi_enter(dip, &circ);
1218 
1219                 switch (ds->when) {
1220                 case DDI_PRE:
1221                         /*
1222                          * Mark nexus busy before a child detaches.
1223                          * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm
1224                          * - pshot@XXX,nopm_strict), or if the child is a
1225                          * - no-pm-components nexus node.
1226                          */
1227                         if (!(pshot->state & PM_SUPPORTED) ||
1228                             (strcmp(childname, "tape") == 0 &&
1229                             !(pshot->state & STRICT_PARENT)) ||
1230                             no_pm_components_child)
1231                                 break;
1232                         mutex_enter(&pshot->lock);
1233                         ++(pshot->busy);
1234                         if (pshot_debug_busy) {
1235                                 cmn_err(CE_CONT, "%s%d:"
1236                                     " ctl_detach_pre: busy for %s%d:"
1237                                     " busy = %d\n", name, instance,
1238                                     childname, childinstance,
1239                                     pshot->busy);
1240                         }
1241                         mutex_exit(&pshot->lock);
1242                         rval = pm_busy_component(dip, 0);
1243                         ASSERT(rval == DDI_SUCCESS);
1244 
1245                         break;
1246                 case DDI_POST:
1247                         /*
1248                          * Mark nexus idle after a child detaches.
1249                          * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1250                          */
1251                         if (!(pshot->state & PM_SUPPORTED))
1252                                 break;
1253                         mutex_enter(&pshot->lock);
1254                         ASSERT(pshot->busy > 0);
1255                         --pshot->busy;
1256                         if (pshot_debug_busy) {
1257                                 cmn_err(CE_CONT, "%s%d:"
1258                                     " ctl_detach_post: idle for %s%d:"
1259                                     " busy = %d\n", name, instance,
1260                                     childname, childinstance,
1261                                     pshot->busy);
1262                         }
1263                         mutex_exit(&pshot->lock);
1264                         rval = pm_idle_component(dip, 0);
1265                         ASSERT(rval == DDI_SUCCESS);
1266 
1267                         /*
1268                          * Mark the driver idle if the NO_INVOL_FLAG
1269                          * is set. This is needed to make sure the
1270                          * parent is idle after the child detaches
1271                          * without calling pm_lower_power().
1272                          * Clear the NO_INVOL_FLAG.
1273                          * - also mark idle if a tape device has detached
1274                          */
1275                         if (!(pshot->state & NO_INVOL_FLAG))
1276                                 break;
1277                         mutex_enter(&pshot->lock);
1278                         ASSERT(pshot->busy > 0);
1279                         --pshot->busy;
1280                         if (pshot_debug_busy) {
1281                                 cmn_err(CE_CONT, "%s%d:"
1282                                     " ctl_detach_post: NO_INVOL:"
1283                                     " idle for %s%d: busy = %d\n",
1284                                     name, instance, childname,
1285                                     childinstance, pshot->busy);
1286                         }
1287                         pshot->state &= ~NO_INVOL_FLAG;
1288                         mutex_exit(&pshot->lock);
1289                         rval = pm_idle_component(dip, 0);
1290                         ASSERT(rval == DDI_SUCCESS);
1291 
1292                         break;
1293                 }
1294 
1295                 ndi_devi_exit(dip, circ);
1296 
1297                 return (rval);
1298         }
1299 
1300         case DDI_CTLOPS_BTOP:
1301         case DDI_CTLOPS_BTOPR:
1302         case DDI_CTLOPS_DVMAPAGESIZE:
1303         case DDI_CTLOPS_IOMIN:
1304         case DDI_CTLOPS_PTOB:
1305         default:
1306                 /*
1307                  * The ops that we pass up (default).  We pass up memory
1308                  * allocation oriented ops that we receive - these may be
1309                  * associated with pseudo HBA drivers below us with target
1310                  * drivers below them that use ddi memory allocation
1311                  * interfaces like scsi_alloc_consistent_buf.
1312                  */
1313                 return (ddi_ctlops(dip, rdip, ctlop, arg, result));
1314         }
1315 }
1316 
1317 /*ARGSUSED0*/
1318 static int
1319 pshot_power(dev_info_t *dip, int cmpt, int level)
1320 {
1321         pshot_t *pshot;
1322         int instance = ddi_get_instance(dip);
1323         char *name = ddi_node_name(dip);
1324         int circ;
1325         int rv;
1326 
1327         pshot = ddi_get_soft_state(pshot_softstatep, instance);
1328         if (pshot == NULL) {
1329 
1330                 return (DDI_FAILURE);
1331         }
1332 
1333         ndi_devi_enter(dip, &circ);
1334 
1335         /*
1336          * set POWER_FLAG when power() is called.
1337          * ioctl(DEVCT_PM_POWER) is a clear on read call.
1338          */
1339         mutex_enter(&pshot->lock);
1340         pshot->state |= POWER_FLAG;
1341         /*
1342          * refuse to power OFF if the component is busy
1343          */
1344         if (pshot->busy != 0 && pshot->level > level) {
1345                 cmn_err(CE_WARN, "%s%d: power: REFUSING POWER LEVEL CHANGE"
1346                     " (%d->%d), DEVICE NOT IDLE: busy = %d",
1347                     name, instance, pshot->level, level, pshot->busy);
1348                 rv = DDI_FAILURE;
1349         } else {
1350                 if (pshot_debug) {
1351                         cmn_err(CE_CONT, "%s%d: power: comp %d (%d->%d)\n",
1352                             name, instance, cmpt, pshot->level, level);
1353                 }
1354                 pshot->level = level;
1355                 rv = DDI_SUCCESS;
1356         }
1357         mutex_exit(&pshot->lock);
1358 
1359         ndi_devi_exit(dip, circ);
1360 
1361         return (rv);
1362 }
1363 
1364 /*ARGSUSED0*/
1365 static int
1366 pshot_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op,
1367     void *arg, void *result)
1368 
1369 {
1370         int                             ret;
1371         int                             instance = ddi_get_instance(dip);
1372         char                            *name = ddi_node_name(dip);
1373         pshot_t                         *pshot;
1374         pm_bp_child_pwrchg_t            *bpc;
1375         pm_bp_nexus_pwrup_t             bpn;
1376         pm_bp_has_changed_t             *bphc;
1377         int                             pwrup_res;
1378         int                             ret_failed = 0;
1379         int                             pwrup_res_failed = 0;
1380 
1381         pshot = ddi_get_soft_state(pshot_softstatep, instance);
1382         if (pshot == NULL) {
1383 
1384                 return (DDI_FAILURE);
1385         }
1386 
1387         switch (op) {
1388         case BUS_POWER_PRE_NOTIFICATION:
1389                 bpc = (pm_bp_child_pwrchg_t *)arg;
1390                 if (pshot_debug) {
1391                         cmn_err(CE_CONT, "%s%d: pre_bus_power:"
1392                             " %s%d comp %d (%d->%d)\n",
1393                             name, instance, ddi_node_name(bpc->bpc_dip),
1394                             ddi_get_instance(bpc->bpc_dip),
1395                             bpc->bpc_comp, bpc->bpc_olevel,
1396                             bpc->bpc_nlevel);
1397                 }
1398 
1399                 /*
1400                  * mark parent busy if old_level is either -1 or 0,
1401                  * and new level is == MAXPWR
1402                  * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1403                  */
1404                 if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR &&
1405                     bpc->bpc_olevel <= 0) && (pshot->state & PM_SUPPORTED)) {
1406                         mutex_enter(&pshot->lock);
1407                         ++(pshot->busy);
1408                         if (pshot_debug_busy) {
1409                                 cmn_err(CE_CONT,
1410                                     "%s%d: pre_bus_power:"
1411                                     " busy parent for %s%d (%d->%d): "
1412                                     " busy = %d\n",
1413                                     name, instance,
1414                                     ddi_node_name(bpc->bpc_dip),
1415                                     ddi_get_instance(bpc->bpc_dip),
1416                                     bpc->bpc_olevel, bpc->bpc_nlevel,
1417                                     pshot->busy);
1418                         }
1419                         mutex_exit(&pshot->lock);
1420                         ret = pm_busy_component(dip, 0);
1421                         ASSERT(ret == DDI_SUCCESS);
1422                 }
1423 
1424                 /*
1425                  * if new_level > 0, power up parent, if not already at
1426                  * MAXPWR, via pm_busop_bus_power
1427                  * - skip for the no-pm nexus (pshot@XXX,nopm)
1428                  */
1429                 if (bpc->bpc_comp == 0 && bpc->bpc_nlevel > 0 &&
1430                     pshot->level < MAXPWR && (pshot->state & PM_SUPPORTED)) {
1431                         /*
1432                          * stuff the bpn struct
1433                          */
1434                         bpn.bpn_comp = 0;
1435                         bpn.bpn_level = MAXPWR;
1436                         bpn.bpn_private = bpc->bpc_private;
1437                         bpn.bpn_dip = dip;
1438 
1439                         /*
1440                          * ask pm to power parent up
1441                          */
1442                         if (pshot_debug) {
1443                                 cmn_err(CE_CONT, "%s%d: pre_bus_power:"
1444                                     " pm_busop_bus_power on parent for %s%d"
1445                                     " (%d->%d): enter", name, instance,
1446                                     ddi_node_name(bpc->bpc_dip),
1447                                     ddi_get_instance(bpc->bpc_dip),
1448                                     bpc->bpc_olevel, bpc->bpc_nlevel);
1449                         }
1450                         ret = pm_busop_bus_power(dip, impl_arg,
1451                             BUS_POWER_NEXUS_PWRUP, (void *)&bpn,
1452                             (void *)&pwrup_res);
1453 
1454                         /*
1455                          * check the return status individually,
1456                          * idle parent and exit if either failed.
1457                          */
1458                         if (ret != DDI_SUCCESS) {
1459                                 cmn_err(CE_WARN,
1460                                     "%s%d: pre_bus_power:"
1461                                     " pm_busop_bus_power FAILED (ret) FOR"
1462                                     " %s%d (%d->%d)",
1463                                     name, instance,
1464                                     ddi_node_name(bpc->bpc_dip),
1465                                     ddi_get_instance(bpc->bpc_dip),
1466                                     bpc->bpc_olevel, bpc->bpc_nlevel);
1467                                 ret_failed = 1;
1468                         }
1469                         if (pwrup_res != DDI_SUCCESS) {
1470                                 cmn_err(CE_WARN,
1471                                     "%s%d: pre_bus_power:"
1472                                     " pm_busop_bus_power FAILED (pwrup_res)"
1473                                     " FOR %s%d (%d->%d)",
1474                                     name, instance,
1475                                     ddi_node_name(bpc->bpc_dip),
1476                                     ddi_get_instance(bpc->bpc_dip),
1477                                     bpc->bpc_olevel, bpc->bpc_nlevel);
1478                                 pwrup_res_failed = 1;
1479                         }
1480                         if (ret_failed || pwrup_res_failed) {
1481                                 /*
1482                                  * decrement the busy count if it
1483                                  * had been incremented.
1484                                  */
1485                                 if ((bpc->bpc_comp == 0 &&
1486                                     bpc->bpc_nlevel == MAXPWR &&
1487                                     bpc->bpc_olevel <= 0) &&
1488                                     (pshot->state & PM_SUPPORTED)) {
1489                                         mutex_enter(&pshot->lock);
1490                                         ASSERT(pshot->busy > 0);
1491                                         --(pshot->busy);
1492                                         if (pshot_debug_busy) {
1493                                                 cmn_err(CE_CONT, "%s%d:"
1494                                                     " pm_busop_bus_power"
1495                                                     " failed: idle parent for"
1496                                                     " %s%d (%d->%d):"
1497                                                     " busy = %d\n",
1498                                                     name, instance,
1499                                                     ddi_node_name(
1500                                                     bpc->bpc_dip),
1501                                                     ddi_get_instance(
1502                                                     bpc->bpc_dip),
1503                                                     bpc->bpc_olevel,
1504                                                     bpc->bpc_nlevel,
1505                                                     pshot->busy);
1506                                         }
1507                                         mutex_exit(&pshot->lock);
1508                                         ret = pm_idle_component(dip, 0);
1509                                         ASSERT(ret == DDI_SUCCESS);
1510                                 }
1511                                 return (DDI_FAILURE);
1512 
1513                         } else {
1514                                 if (pshot_debug) {
1515                                         cmn_err(CE_CONT,
1516                                             "%s%d: pre_bus_power:"
1517                                             " pm_busop_bus_power on parent"
1518                                             " for %s%d (%d->%d)\n",
1519                                             name, instance,
1520                                             ddi_node_name(bpc->bpc_dip),
1521                                             ddi_get_instance(bpc->bpc_dip),
1522                                             bpc->bpc_olevel, bpc->bpc_nlevel);
1523                                 }
1524                         }
1525                 }
1526                 break;
1527 
1528         case BUS_POWER_POST_NOTIFICATION:
1529                 bpc = (pm_bp_child_pwrchg_t *)arg;
1530                 if (pshot_debug) {
1531                         cmn_err(CE_CONT, "%s%d: post_bus_power:"
1532                             " %s%d comp %d (%d->%d) result %d\n",
1533                             name, instance, ddi_node_name(bpc->bpc_dip),
1534                             ddi_get_instance(bpc->bpc_dip),
1535                             bpc->bpc_comp, bpc->bpc_olevel,
1536                             bpc->bpc_nlevel, *(int *)result);
1537                 }
1538 
1539                 /*
1540                  * handle pm_busop_bus_power() failure case.
1541                  * mark parent idle if had been marked busy.
1542                  * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1543                  */
1544                 if (*(int *)result != DDI_SUCCESS) {
1545                         cmn_err(CE_WARN,
1546                             "pshot%d: post_bus_power_failed:"
1547                             " pm_busop_bus_power FAILED FOR %s%d (%d->%d)",
1548                             instance, ddi_node_name(bpc->bpc_dip),
1549                             ddi_get_instance(bpc->bpc_dip),
1550                             bpc->bpc_olevel, bpc->bpc_nlevel);
1551 
1552                         if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR &&
1553                             bpc->bpc_olevel <= 0) &&
1554                             (pshot->state & PM_SUPPORTED)) {
1555                                 mutex_enter(&pshot->lock);
1556                                 ASSERT(pshot->busy > 0);
1557                                 --(pshot->busy);
1558                                 if (pshot_debug_busy) {
1559                                         cmn_err(CE_CONT, "%s%d:"
1560                                             " post_bus_power_failed:"
1561                                             " idle parent for %s%d"
1562                                             " (%d->%d): busy = %d\n",
1563                                             name, instance,
1564                                             ddi_node_name(bpc->bpc_dip),
1565                                             ddi_get_instance(bpc->bpc_dip),
1566                                             bpc->bpc_olevel, bpc->bpc_nlevel,
1567                                             pshot->busy);
1568                                 }
1569                                 mutex_exit(&pshot->lock);
1570                                 ret = pm_idle_component(dip, 0);
1571                                 ASSERT(ret == DDI_SUCCESS);
1572                         }
1573                 }
1574 
1575                 /*
1576                  * Mark nexus idle when a child's comp 0
1577                  * is set to level 0 from level 1, 2, or 3 only.
1578                  * And only if result arg == DDI_SUCCESS.
1579                  * This will leave the parent busy when the child
1580                  * does not call pm_lower_power() on detach after
1581                  * unsetting the NO_LOWER_POWER flag.
1582                  * If so, need to notify the parent to mark itself
1583                  * idle anyway, else the no-involumtary-power-cycles
1584                  * test cases will report false passes!
1585                  * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1586                  */
1587                 if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == 0 &&
1588                     !(bpc->bpc_olevel <= 0) &&
1589                     *(int *)result == DDI_SUCCESS) &&
1590                     (pshot->state & PM_SUPPORTED)) {
1591                         mutex_enter(&pshot->lock);
1592                         ASSERT(pshot->busy > 0);
1593                         --(pshot->busy);
1594                         if (pshot_debug_busy) {
1595                                 cmn_err(CE_CONT,
1596                                     "%s%d: post_bus_power:"
1597                                     " idle parent for %s%d (%d->%d):"
1598                                     " busy = %d\n", name, instance,
1599                                     ddi_node_name(bpc->bpc_dip),
1600                                     ddi_get_instance(bpc->bpc_dip),
1601                                     bpc->bpc_olevel, bpc->bpc_nlevel,
1602                                     pshot->busy);
1603                         }
1604                         mutex_exit(&pshot->lock);
1605                         ret = pm_idle_component(dip, 0);
1606                         ASSERT(ret == DDI_SUCCESS);
1607                 }
1608                 break;
1609 
1610         case BUS_POWER_HAS_CHANGED:
1611                 bphc = (pm_bp_has_changed_t *)arg;
1612                 if (pshot_debug) {
1613                         cmn_err(CE_CONT, "%s%d: has_changed_bus_power:"
1614                             " %s%d comp %d (%d->%d) result %d\n",
1615                             name, instance, ddi_node_name(bphc->bphc_dip),
1616                             ddi_get_instance(bphc->bphc_dip),
1617                             bphc->bphc_comp, bphc->bphc_olevel,
1618                             bphc->bphc_nlevel, *(int *)result);
1619                 }
1620 
1621                 /*
1622                  * Mark nexus idle when a child's comp 0
1623                  * is set to level 0 from levels 1, 2, or 3 only.
1624                  *
1625                  * If powering up child leaf/nexus nodes via
1626                  * pm_power_has_changed() calls, first issue
1627                  * DEVCTL_PM_BUSY_COMP ioctl to mark parent busy
1628                  * before powering the parent up, then power up the
1629                  * child node.
1630                  * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm)
1631                  */
1632                 if ((bphc->bphc_comp == 0 && bphc->bphc_nlevel == 0 &&
1633                     !(bphc->bphc_olevel <= 0)) &&
1634                     pshot->state & PM_SUPPORTED) {
1635                         mutex_enter(&pshot->lock);
1636                         ASSERT(pshot->busy > 0);
1637                         --(pshot->busy);
1638                         if (pshot_debug_busy) {
1639                                 cmn_err(CE_CONT,
1640                                     "%s%d: has_changed_bus_power:"
1641                                     " idle parent for %s%d (%d->%d):"
1642                                     " busy = %d\n", name, instance,
1643                                     ddi_node_name(bphc->bphc_dip),
1644                                     ddi_get_instance(bphc->bphc_dip),
1645                                     bphc->bphc_olevel,
1646                                     bphc->bphc_nlevel, pshot->busy);
1647                         }
1648                         mutex_exit(&pshot->lock);
1649                         ret = pm_idle_component(dip, 0);
1650                         ASSERT(ret == DDI_SUCCESS);
1651                 }
1652                 break;
1653 
1654         default:
1655                 return (pm_busop_bus_power(dip, impl_arg, op, arg, result));
1656 
1657         }
1658 
1659         return (DDI_SUCCESS);
1660 }
1661 
1662 static int
1663 pshot_initchild(dev_info_t *dip, dev_info_t *child)
1664 {
1665         char    name[64];
1666         char    *bus_addr;
1667         char    *c_nodename;
1668         int     bus_id;
1669         dev_info_t *enum_child;
1670         int     enum_base;
1671         int     enum_extent;
1672 
1673 
1674         /* check for bus_enum node */
1675 
1676 #ifdef  NOT_USED
1677         if (impl_ddi_merge_child(child) != DDI_SUCCESS)
1678                 return (DDI_FAILURE);
1679 #endif
1680 
1681         enum_base = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS,
1682             "busid_ebase", 0);
1683 
1684         enum_extent = ddi_prop_get_int(DDI_DEV_T_ANY, child,
1685             DDI_PROP_DONTPASS, "busid_range", 0);
1686 
1687         /*
1688          * bus enumeration node
1689          */
1690         if ((enum_base != 0) && (enum_extent != 0))     {
1691                 c_nodename = ddi_node_name(child);
1692                 bus_id = enum_base;
1693                 for (; bus_id < enum_extent; bus_id++) {
1694                         if (ndi_devi_alloc(dip, c_nodename, DEVI_PSEUDO_NODEID,
1695                             &enum_child) != NDI_SUCCESS)
1696                                 return (DDI_FAILURE);
1697 
1698                         (void) sprintf(name, "%d", bus_id);
1699                         if (ndi_prop_update_string(DDI_DEV_T_NONE, enum_child,
1700                             "bus-addr", name) != DDI_PROP_SUCCESS) {
1701                                 (void) ndi_devi_free(enum_child);
1702                                 return (DDI_FAILURE);
1703                         }
1704 
1705                         if (ndi_devi_online(enum_child, 0) !=
1706                             DDI_SUCCESS) {
1707                                 (void) ndi_devi_free(enum_child);
1708                                 return (DDI_FAILURE);
1709                         }
1710                 }
1711                 /*
1712                  * fail the enumeration node itself
1713                  */
1714                 return (DDI_FAILURE);
1715         }
1716 
1717         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, 0, "bus-addr",
1718             &bus_addr) != DDI_PROP_SUCCESS) {
1719                 cmn_err(CE_WARN, "pshot_initchild: bus-addr not defined (%s)",
1720                     ddi_node_name(child));
1721                 return (DDI_NOT_WELL_FORMED);
1722         }
1723 
1724         if (strlen(bus_addr) == 0) {
1725                 cmn_err(CE_WARN, "pshot_initchild: NULL bus-addr (%s)",
1726                     ddi_node_name(child));
1727                 ddi_prop_free(bus_addr);
1728                 return (DDI_FAILURE);
1729         }
1730 
1731         if (strncmp(bus_addr, "failinit", 8) == 0) {
1732                 if (pshot_debug)
1733                         cmn_err(CE_CONT,
1734                             "pshot%d: %s forced INITCHILD failure\n",
1735                             ddi_get_instance(dip), bus_addr);
1736                 ddi_prop_free(bus_addr);
1737                 return (DDI_FAILURE);
1738         }
1739 
1740         if (pshot_log) {
1741                 cmn_err(CE_CONT, "initchild %s%d/%s@%s\n",
1742                     ddi_get_name(dip), ddi_get_instance(dip),
1743                     ddi_node_name(child), bus_addr);
1744         }
1745 
1746         ddi_set_name_addr(child, bus_addr);
1747         ddi_prop_free(bus_addr);
1748         return (DDI_SUCCESS);
1749 }
1750 
1751 /*ARGSUSED*/
1752 static int
1753 pshot_uninitchild(dev_info_t *dip, dev_info_t *child)
1754 {
1755         ddi_set_name_addr(child, NULL);
1756         return (DDI_SUCCESS);
1757 }
1758 
1759 
1760 /*
1761  * devctl IOCTL support
1762  */
1763 /* ARGSUSED */
1764 static int
1765 pshot_open(dev_t *devp, int flags, int otyp, cred_t *credp)
1766 {
1767         int instance;
1768         pshot_t *pshot;
1769 
1770         if (otyp != OTYP_CHR)
1771                 return (EINVAL);
1772 
1773         instance = pshot_minor_decode_inst(getminor(*devp));
1774         if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
1775                 return (ENXIO);
1776 
1777         /*
1778          * Access is currently determined on a per-instance basis.
1779          * If we want per-node, then need to add state and lock members to
1780          * pshot_minor_t
1781          */
1782         mutex_enter(&pshot->lock);
1783         if (((flags & FEXCL) && (pshot->state & IS_OPEN)) ||
1784             (!(flags & FEXCL) && (pshot->state & IS_OPEN_EXCL))) {
1785                 mutex_exit(&pshot->lock);
1786                 return (EBUSY);
1787         }
1788         pshot->state |= IS_OPEN;
1789         if (flags & FEXCL)
1790                 pshot->state |= IS_OPEN_EXCL;
1791 
1792         if (pshot_debug)
1793                 cmn_err(CE_CONT, "pshot%d open\n", instance);
1794 
1795         mutex_exit(&pshot->lock);
1796         return (0);
1797 }
1798 
1799 /*
1800  * pshot_close
1801  */
1802 /* ARGSUSED */
1803 static int
1804 pshot_close(dev_t dev, int flag, int otyp, cred_t *credp)
1805 {
1806         int instance;
1807         pshot_t *pshot;
1808 
1809         if (otyp != OTYP_CHR)
1810                 return (EINVAL);
1811 
1812         instance = pshot_minor_decode_inst(getminor(dev));
1813         if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
1814                 return (ENXIO);
1815 
1816         mutex_enter(&pshot->lock);
1817         pshot->state &= ~(IS_OPEN | IS_OPEN_EXCL);
1818         mutex_exit(&pshot->lock);
1819         if (pshot_debug)
1820                 cmn_err(CE_CONT, "pshot%d closed\n", instance);
1821         return (0);
1822 }
1823 
1824 
1825 /*
1826  * pshot_ioctl: redirects to appropriate command handler based on various
1827  *      criteria
1828  */
1829 /* ARGSUSED */
1830 static int
1831 pshot_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp,
1832     int *rvalp)
1833 {
1834         pshot_t *pshot;
1835         int instance;
1836         minor_t nodenum;
1837         char *nodename;
1838 
1839         instance = pshot_minor_decode_inst(getminor(dev));
1840         if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL)
1841                 return (ENXIO);
1842 
1843         nodenum = pshot_minor_decode_nodenum(getminor(dev));
1844         nodename = pshot->nodes[nodenum].name;
1845 
1846         if (pshot_debug)
1847                 cmn_err(CE_CONT,
1848                     "pshot%d ioctl: dev=%p, cmd=%x, arg=%p, mode=%x\n",
1849                     instance, (void *)dev, cmd, (void *)arg, mode);
1850 
1851         if (strcmp(nodename, PSHOT_NODENAME_DEVCTL) == 0)
1852                 return (pshot_devctl(pshot, nodenum, cmd, arg, mode, credp,
1853                     rvalp));
1854 
1855         if (strcmp(nodename, PSHOT_NODENAME_TESTCTL) == 0)
1856                 return (pshot_testctl(pshot, nodenum, cmd, arg, mode, credp,
1857                     rvalp));
1858 
1859         cmn_err(CE_WARN, "pshot_ioctl: unmatched nodename on minor %u",
1860             pshot->nodes[nodenum].minor);
1861         return (ENXIO);
1862 }
1863 
1864 
1865 /*
1866  * pshot_devctl: handle DEVCTL operations
1867  */
1868 /* ARGSUSED */
1869 static int
1870 pshot_devctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode,
1871     cred_t *credp, int *rvalp)
1872 {
1873         dev_info_t *self;
1874         dev_info_t *child = NULL;
1875         struct devctl_iocdata *dcp;
1876         uint_t state;
1877         int rv = 0;
1878         uint_t flags;
1879         int instance;
1880         int i;
1881         int ret;
1882 
1883         self = pshot->dip;
1884 
1885         flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0;
1886         instance = pshot->instance;
1887 
1888         /*
1889          * We can use the generic implementation for these ioctls
1890          */
1891         for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
1892                 if (pshot_devctls[i].ioctl_int == cmd) {
1893                         if (pshot_debug)
1894                                 cmn_err(CE_CONT, "pshot%d devctl: %s",
1895                                     instance, pshot_devctls[i].ioctl_char);
1896                 }
1897         }
1898         switch (cmd) {
1899         case DEVCTL_DEVICE_GETSTATE:
1900         case DEVCTL_DEVICE_ONLINE:
1901         case DEVCTL_DEVICE_OFFLINE:
1902         case DEVCTL_DEVICE_REMOVE:
1903         case DEVCTL_BUS_GETSTATE:
1904         case DEVCTL_BUS_DEV_CREATE:
1905                 rv = ndi_devctl_ioctl(self, cmd, arg, mode, flags);
1906                 if (pshot_debug && rv != 0) {
1907                         cmn_err(CE_CONT, "pshot%d ndi_devctl_ioctl:"
1908                             " failed, rv = %d", instance, rv);
1909                 }
1910 
1911                 return (rv);
1912         }
1913 
1914         /*
1915          * read devctl ioctl data
1916          */
1917         if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS)
1918                 return (EFAULT);
1919 
1920         switch (cmd) {
1921 
1922         case DEVCTL_DEVICE_RESET:
1923                 if (pshot_debug)
1924                         cmn_err(CE_CONT, "pshot%d devctl:"
1925                             " DEVCTL_DEVICE_RESET\n", instance);
1926                 rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET,
1927                     child, (void *)self);
1928                 ASSERT(rv == NDI_SUCCESS);
1929                 break;
1930 
1931         case DEVCTL_BUS_QUIESCE:
1932                 if (pshot_debug)
1933                         cmn_err(CE_CONT, "pshot%d devctl:"
1934                             " DEVCTL_BUS_QUIESCE\n", instance);
1935                 if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
1936                         if (state == BUS_QUIESCED) {
1937                                 break;
1938                         }
1939                         (void) ndi_set_bus_state(self, BUS_QUIESCED);
1940                 }
1941                 rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE,
1942                     child, (void *)self);
1943                 ASSERT(rv == NDI_SUCCESS);
1944 
1945                 break;
1946 
1947         case DEVCTL_BUS_UNQUIESCE:
1948                 if (pshot_debug)
1949                         cmn_err(CE_CONT, "pshot%d devctl:"
1950                             " DEVCTL_BUS_UNQUIESCE\n", instance);
1951                 if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
1952                         if (state == BUS_ACTIVE) {
1953                                 break;
1954                         }
1955                 }
1956 
1957                 /*
1958                  * quiesce the bus through bus-specific means
1959                  */
1960                 (void) ndi_set_bus_state(self, BUS_ACTIVE);
1961                 rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE,
1962                     child, (void *)self);
1963                 ASSERT(rv == NDI_SUCCESS);
1964                 break;
1965 
1966         case DEVCTL_BUS_RESET:
1967         case DEVCTL_BUS_RESETALL:
1968                 /*
1969                  * no reset support for the pseudo bus
1970                  * but if there were....
1971                  */
1972                 rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET,
1973                     child, (void *)self);
1974                 ASSERT(rv == NDI_SUCCESS);
1975                 break;
1976 
1977         /*
1978          * PM related ioctls
1979          */
1980         case DEVCTL_PM_BUSY_COMP:
1981                 /*
1982                  * mark component 0 busy.
1983                  * Keep track of ioctl updates to the busy count
1984                  * via pshot->busy_ioctl.
1985                  */
1986                 if (pshot_debug) {
1987                         cmn_err(CE_CONT, "pshot%d devctl:"
1988                             " DEVCTL_PM_BUSY_COMP\n", instance);
1989                 }
1990                 mutex_enter(&pshot->lock);
1991                 ++(pshot->busy);
1992                 ++(pshot->busy_ioctl);
1993                 if (pshot_debug_busy) {
1994                         cmn_err(CE_CONT, "pshot%d:"
1995                             " DEVCTL_PM_BUSY_COMP comp 0 busy"
1996                             " %d busy_ioctl %d\n", instance, pshot->busy,
1997                             pshot->busy_ioctl);
1998                 }
1999                 mutex_exit(&pshot->lock);
2000                 ret = pm_busy_component(pshot->dip, 0);
2001                 ASSERT(ret == DDI_SUCCESS);
2002 
2003                 break;
2004 
2005         case DEVCTL_PM_BUSY_COMP_TEST:
2006                 /*
2007                  * test bus's busy state
2008                  */
2009                 if (pshot_debug) {
2010                         cmn_err(CE_CONT, "pshot%d devctl:"
2011                             " DEVCTL_PM_BUSY_COMP_TEST\n", instance);
2012                 }
2013                 mutex_enter(&pshot->lock);
2014                 state = pshot->busy;
2015                 if (copyout(&state, dcp->cpyout_buf,
2016                     sizeof (uint_t)) != 0) {
2017                         cmn_err(CE_WARN, "pshot%d devctl:"
2018                             " DEVCTL_PM_BUSY_COMP_TEST: copyout failed",
2019                             instance);
2020                         rv = EINVAL;
2021                 }
2022                 if (pshot_debug_busy) {
2023                         cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_BUSY_COMP_TEST:"
2024                             " comp 0 busy %d busy_ioctl %d\n", instance,
2025                             state, pshot->busy_ioctl);
2026                 }
2027                 mutex_exit(&pshot->lock);
2028                 break;
2029 
2030         case DEVCTL_PM_IDLE_COMP:
2031                 /*
2032                  * mark component 0 idle.
2033                  * NOP if pshot->busy_ioctl <= 0.
2034                  */
2035                 if (pshot_debug) {
2036                         cmn_err(CE_CONT, "pshot%d devctl:"
2037                             " DEVCTL_PM_IDLE_COMP\n", instance);
2038                 }
2039                 mutex_enter(&pshot->lock);
2040                 if (pshot->busy_ioctl > 0) {
2041                         ASSERT(pshot->busy > 0);
2042                         --(pshot->busy);
2043                         --(pshot->busy_ioctl);
2044                         if (pshot_debug_busy) {
2045                                 cmn_err(CE_CONT, "pshot%d:"
2046                                     " DEVCTL_PM_IDLE_COM: comp 0"
2047                                     " busy %d busy_ioctl %d\n", instance,
2048                                     pshot->busy, pshot->busy_ioctl);
2049                         }
2050                         mutex_exit(&pshot->lock);
2051                         ret = pm_idle_component(pshot->dip, 0);
2052                         ASSERT(ret == DDI_SUCCESS);
2053 
2054                 } else {
2055                         mutex_exit(&pshot->lock);
2056                 }
2057                 break;
2058 
2059         case DEVCTL_PM_RAISE_PWR:
2060                 /*
2061                  * raise component 0 to full power level MAXPWR via a
2062                  * pm_raise_power() call
2063                  */
2064                 if (pshot_debug) {
2065                         cmn_err(CE_CONT, "pshot%d devctl:"
2066                             " DEVCTL_PM_RAISE_PWR\n", instance);
2067                 }
2068                 if (pm_raise_power(pshot->dip, 0, MAXPWR) != DDI_SUCCESS) {
2069                         rv = EINVAL;
2070                 } else {
2071                         mutex_enter(&pshot->lock);
2072                         if (pshot_debug) {
2073                                 cmn_err(CE_CONT, "pshot%d:"
2074                                     " DEVCTL_PM_RAISE_POWER: comp 0"
2075                                     " to level %d\n", instance, pshot->level);
2076                         }
2077                         mutex_exit(&pshot->lock);
2078                 }
2079                 break;
2080 
2081         case DEVCTL_PM_LOWER_PWR:
2082                 /*
2083                  * pm_lower_power() call for negative testing
2084                  * expected to fail.
2085                  */
2086                 if (pshot_debug) {
2087                         cmn_err(CE_CONT, "pshot%d devctl:"
2088                             " DEVCTL_PM_LOWER_PWR\n", instance);
2089                 }
2090                 if (pm_lower_power(pshot->dip, 0, 0) != DDI_SUCCESS) {
2091                         rv = EINVAL;
2092                 } else {
2093                         mutex_enter(&pshot->lock);
2094                         if (pshot_debug) {
2095                                 cmn_err(CE_CONT, "pshot%d:"
2096                                     " DEVCTL_PM_LOWER_POWER comp 0"
2097                                     " to level %d\n", instance, pshot->level);
2098                         }
2099                         mutex_exit(&pshot->lock);
2100                 }
2101                 break;
2102 
2103         case DEVCTL_PM_CHANGE_PWR_LOW:
2104                 /*
2105                  * inform the PM framework that component 0 has changed
2106                  * power level to 0 via a pm_power_has_changed() call
2107                  */
2108                 if (pshot_debug) {
2109                         cmn_err(CE_CONT, "pshot%d devctl:"
2110                             " DEVCTL_PM_CHANGE_PWR_LOW\n", instance);
2111                 }
2112                 mutex_enter(&pshot->lock);
2113                 pshot->level = 0;
2114                 if (pm_power_has_changed(pshot->dip, 0, 0) != DDI_SUCCESS) {
2115                         rv = EINVAL;
2116                 } else {
2117                         if (pshot_debug) {
2118                                 cmn_err(CE_CONT, "pshot%d:"
2119                                     " DEVCTL_PM_CHANGE_PWR_LOW comp 0 to"
2120                                     " level %d\n", instance, pshot->level);
2121                         }
2122                 }
2123                 mutex_exit(&pshot->lock);
2124                 break;
2125 
2126         case DEVCTL_PM_CHANGE_PWR_HIGH:
2127                 /*
2128                  * inform the PM framework that component 0 has changed
2129                  * power level to MAXPWR via a pm_power_has_changed() call
2130                  */
2131                 if (pshot_debug) {
2132                         cmn_err(CE_CONT, "pshot%d devctl:"
2133                             " DEVCTL_PM_CHANGE_PWR_HIGH\n", instance);
2134                 }
2135                 mutex_enter(&pshot->lock);
2136                 pshot->level = MAXPWR;
2137                 if (pm_power_has_changed(pshot->dip, 0, MAXPWR)
2138                     != DDI_SUCCESS) {
2139                         rv = EINVAL;
2140                 } else {
2141                         if (pshot_debug) {
2142                                 cmn_err(CE_CONT, "pshot%d:"
2143                                     " DEVCTL_PM_CHANGE_PWR_HIGH comp 0 to"
2144                                     " level %d\n", instance, pshot->level);
2145                         }
2146                 }
2147                 mutex_exit(&pshot->lock);
2148                 break;
2149 
2150         case DEVCTL_PM_POWER:
2151                 /*
2152                  * test if the pshot_power() routine has been called,
2153                  * then clear
2154                  */
2155                 if (pshot_debug) {
2156                         cmn_err(CE_CONT, "pshot%d devctl:"
2157                             " DEVCTL_PM_POWER\n", instance);
2158                 }
2159                 mutex_enter(&pshot->lock);
2160                 state = (pshot->state & POWER_FLAG) ? 1 : 0;
2161                 if (copyout(&state, dcp->cpyout_buf,
2162                     sizeof (uint_t)) != 0) {
2163                         cmn_err(CE_WARN, "pshot%d devctl:"
2164                             " DEVCTL_PM_POWER: copyout failed",
2165                             instance);
2166                         rv = EINVAL;
2167                 }
2168                 if (pshot_debug) {
2169                         cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_POWER:"
2170                             " POWER_FLAG = %d\n", instance, state);
2171                 }
2172                 pshot->state &= ~POWER_FLAG;
2173                 mutex_exit(&pshot->lock);
2174                 break;
2175 
2176         case DEVCTL_PM_FAIL_SUSPEND:
2177                 /*
2178                  * fail DDI_SUSPEND
2179                  */
2180                 if (pshot_debug) {
2181                         cmn_err(CE_CONT, "pshot%d devctl:"
2182                             " DEVCTL_PM_FAIL_SUSPEND\n", instance);
2183                 }
2184                 mutex_enter(&pshot->lock);
2185                 pshot->state |= FAIL_SUSPEND_FLAG;
2186                 mutex_exit(&pshot->lock);
2187                 if (pshot_debug) {
2188                         cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_FAIL_SUSPEND\n",
2189                             instance);
2190                 }
2191                 break;
2192 
2193         case DEVCTL_PM_BUS_STRICT_TEST:
2194                 /*
2195                  * test the STRICT_PARENT flag:
2196                  *      set => STRICT PARENT
2197                  *      not set => INVOLVED PARENT
2198                  */
2199                 mutex_enter(&pshot->lock);
2200                 state = (pshot->state & STRICT_PARENT) ? 1 : 0;
2201                 if (copyout(&state, dcp->cpyout_buf,
2202                     sizeof (uint_t)) != 0) {
2203                         cmn_err(CE_WARN, "pshot%d devctl:"
2204                             " DEVCTL_PM_BUS_STRICT_TEST: copyout failed",
2205                             instance);
2206                         rv = EINVAL;
2207                 }
2208                 if (pshot_debug) {
2209                         cmn_err(CE_CONT, "pshot%d devctl:"
2210                             " DEVCTL_PM_BUS_STRICT_TEST: type = %s\n",
2211                             instance, ((state == 0) ? "INVOLVED" : "STRICT"));
2212                 }
2213                 mutex_exit(&pshot->lock);
2214                 break;
2215 
2216         case DEVCTL_PM_BUS_NO_INVOL:
2217                 /*
2218                  * Set the NO_INVOL_FLAG flag to
2219                  * notify the driver that the child will not
2220                  * call pm_lower_power() on detach.
2221                  * The driver needs to mark itself idle twice
2222                  * during DDI_CTLOPS_DETACH (post).
2223                  */
2224                 if (pshot_debug) {
2225                         cmn_err(CE_CONT, "pshot%d devctl:"
2226                             " DEVCTL_PM_BUS_NO_INVOL\n", instance);
2227                 }
2228                 mutex_enter(&pshot->lock);
2229                 pshot->state |= NO_INVOL_FLAG;
2230                 mutex_exit(&pshot->lock);
2231                 break;
2232 
2233         default:
2234                 rv = ENOTTY;
2235         }
2236 
2237         ndi_dc_freehdl(dcp);
2238         return (rv);
2239 }
2240 
2241 
2242 /*
2243  * pshot_testctl: handle other test operations
2244  *      - If <cmd> is a DEVCTL cmd, then <arg> is a dev_t indicating which
2245  *        child to direct the DEVCTL to, if applicable;
2246  *        furthermore, any cmd here can be sent by layered ioctls (unlike
2247  *        those to pshot_devctl() which must come from userland)
2248  */
2249 /* ARGSUSED */
2250 static int
2251 pshot_testctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode,
2252     cred_t *credp, int *rvalp)
2253 {
2254         dev_info_t *self;
2255         dev_info_t *child = NULL;
2256         uint_t state;
2257         int rv = 0;
2258         int instance;
2259         int i;
2260 
2261         /* uint_t flags; */
2262 
2263         /* flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0; */
2264         self = pshot->dip;
2265         instance = pshot->instance;
2266 
2267         if (cmd & DEVCTL_IOC) {
2268                 child = e_ddi_hold_devi_by_dev((dev_t)arg, 0);
2269         }
2270 
2271         for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) {
2272                 if (pshot_devctls[i].ioctl_int == cmd) {
2273                         if (pshot_debug)
2274                                 cmn_err(CE_CONT, "pshot%d devctl: %s",
2275                                     instance, pshot_devctls[i].ioctl_char);
2276                 }
2277         }
2278         switch (cmd) {
2279         case DEVCTL_DEVICE_RESET:
2280                 if (pshot_debug)
2281                         cmn_err(CE_CONT, "pshot%d testctl:"
2282                             " DEVCTL_PM_POWER\n", instance);
2283                 rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET,
2284                     child, (void *)self);
2285                 ASSERT(rv == NDI_SUCCESS);
2286                 break;
2287 
2288         case DEVCTL_BUS_QUIESCE:
2289                 if (pshot_debug)
2290                         cmn_err(CE_CONT, "pshot%d testctl:"
2291                             " DEVCTL_PM_POWER\n", instance);
2292                 if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
2293                         if (state == BUS_QUIESCED) {
2294                                 break;
2295                         }
2296                         (void) ndi_set_bus_state(self, BUS_QUIESCED);
2297                 }
2298                 rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE,
2299                     child, (void *)self);
2300                 ASSERT(rv == NDI_SUCCESS);
2301 
2302                 break;
2303 
2304         case DEVCTL_BUS_UNQUIESCE:
2305                 if (pshot_debug)
2306                         cmn_err(CE_CONT, "pshot%d testctl:"
2307                             " DEVCTL_PM_POWER\n", instance);
2308                 if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) {
2309                         if (state == BUS_ACTIVE) {
2310                                 break;
2311                         }
2312                 }
2313 
2314                 /*
2315                  * quiesce the bus through bus-specific means
2316                  */
2317                 (void) ndi_set_bus_state(self, BUS_ACTIVE);
2318                 rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE,
2319                     child, (void *)self);
2320                 ASSERT(rv == NDI_SUCCESS);
2321                 break;
2322 
2323         case DEVCTL_BUS_RESET:
2324         case DEVCTL_BUS_RESETALL:
2325                 /*
2326                  * no reset support for the pseudo bus
2327                  * but if there were....
2328                  */
2329                 rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET,
2330                     child, (void *)self);
2331                 ASSERT(rv == NDI_SUCCESS);
2332                 break;
2333 
2334         default:
2335                 rv = ENOTTY;
2336         }
2337 
2338         if (child != NULL)
2339                 ddi_release_devi(child);
2340         return (rv);
2341 }
2342 
2343 
2344 static int
2345 pshot_get_eventcookie(dev_info_t *dip, dev_info_t *rdip,
2346         char *eventname, ddi_eventcookie_t *event_cookiep)
2347 {
2348         int     instance = ddi_get_instance(dip);
2349         pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2350 
2351         if (pshot_debug)
2352                 cmn_err(CE_CONT, "pshot%d: "
2353                     "pshot_get_eventcookie:\n\t"
2354                     "dip = 0x%p rdip = 0x%p (%s/%d) eventname = %s\n",
2355                     instance, (void *)dip, (void *)rdip,
2356                     ddi_node_name(rdip), ddi_get_instance(rdip),
2357                     eventname);
2358 
2359 
2360         return (ndi_event_retrieve_cookie(pshot->ndi_event_hdl,
2361             rdip, eventname, event_cookiep, NDI_EVENT_NOPASS));
2362 }
2363 
2364 static int
2365 pshot_add_eventcall(dev_info_t *dip, dev_info_t *rdip,
2366         ddi_eventcookie_t cookie,
2367         void (*callback)(), void *arg, ddi_callback_id_t *cb_id)
2368 {
2369         int     instance = ddi_get_instance(dip);
2370         pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2371 
2372         if (pshot_debug)
2373                 cmn_err(CE_CONT, "pshot%d: "
2374                     "pshot_add_eventcall:\n\t"
2375                     "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n\t"
2376                     "cb = 0x%p, arg = 0x%p\n",
2377                     instance, (void *)dip, (void *)rdip,
2378                     ddi_node_name(rdip), ddi_get_instance(rdip), (void *)cookie,
2379                     NDI_EVENT_NAME(cookie), (void *)callback, arg);
2380 
2381         /* add callback to our event handle */
2382         return (ndi_event_add_callback(pshot->ndi_event_hdl, rdip,
2383             cookie, callback, arg, NDI_SLEEP, cb_id));
2384 }
2385 
2386 static int
2387 pshot_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id)
2388 {
2389 
2390         ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id;
2391 
2392         int instance = ddi_get_instance(dip);
2393         pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2394 
2395         ASSERT(cb);
2396 
2397         if (pshot_debug)
2398                 cmn_err(CE_CONT, "pshot%d: "
2399                     "pshot_remove_eventcall:\n\t"
2400                     "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n",
2401                     instance, (void *)dip, (void *)cb->ndi_evtcb_dip,
2402                     ddi_node_name(cb->ndi_evtcb_dip),
2403                     ddi_get_instance(cb->ndi_evtcb_dip),
2404                     (void *)cb->ndi_evtcb_cookie,
2405                     NDI_EVENT_NAME(cb->ndi_evtcb_cookie));
2406 
2407         return (ndi_event_remove_callback(pshot->ndi_event_hdl, cb_id));
2408 }
2409 
2410 static int
2411 pshot_post_event(dev_info_t *dip, dev_info_t *rdip,
2412         ddi_eventcookie_t cookie, void *impl_data)
2413 {
2414         int     instance = ddi_get_instance(dip);
2415         pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance);
2416 
2417         if (pshot_debug) {
2418                 if (rdip) {
2419                         cmn_err(CE_CONT, "pshot%d: "
2420                             "pshot_post_event:\n\t"
2421                             "dip = 0x%p rdip = 0x%p (%s%d\n\t"
2422                             "cookie = 0x%p (%s)\n\tbus_impl = 0x%p\n",
2423                             instance, (void *)dip, (void *)rdip,
2424                             ddi_node_name(rdip), ddi_get_instance(rdip),
2425                             (void *)cookie,
2426                             NDI_EVENT_NAME(cookie), impl_data);
2427                 } else {
2428                         cmn_err(CE_CONT, "pshot%d: "
2429                             "pshot_post_event:\n\t"
2430                             "dip = 0x%p cookie = 0x%p (%s) bus_impl = 0x%p\n",
2431                             instance, (void *)dip, (void *)cookie,
2432                             NDI_EVENT_NAME(cookie), impl_data);
2433                 }
2434         }
2435 
2436         /*  run callbacks for this event */
2437         return (ndi_event_run_callbacks(pshot->ndi_event_hdl, rdip,
2438             cookie, impl_data));
2439 }
2440 
2441 /*
2442  * the nexus driver will generate events
2443  * that need to go to children
2444  */
2445 static int
2446 pshot_event(pshot_t *pshot, int event_tag, dev_info_t *child,
2447         void *bus_impldata)
2448 {
2449         ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(
2450             pshot->ndi_event_hdl, event_tag);
2451 
2452         if (pshot_debug) {
2453                 if (child) {
2454                         cmn_err(CE_CONT, "pshot%d: "
2455                             "pshot_event: event_tag = 0x%x (%s)\n\t"
2456                             "child = 0x%p (%s%d) bus_impl = 0x%p (%s%d)\n",
2457                             pshot->instance, event_tag,
2458                             ndi_event_tag_to_name(pshot->ndi_event_hdl,
2459                             event_tag),
2460                             (void *)child, ddi_node_name(child),
2461                             ddi_get_instance(child), bus_impldata,
2462                             ddi_node_name((dev_info_t *)bus_impldata),
2463                             ddi_get_instance((dev_info_t *)bus_impldata));
2464                 } else {
2465                         cmn_err(CE_CONT, "pshot%d: "
2466                             "pshot_event: event_tag = 0x%x (%s)\n\t"
2467                             "child = NULL,  bus_impl = 0x%p (%s%d)\n",
2468                             pshot->instance, event_tag,
2469                             ndi_event_tag_to_name(pshot->ndi_event_hdl,
2470                             event_tag),
2471                             bus_impldata,
2472                             ddi_node_name((dev_info_t *)bus_impldata),
2473                             ddi_get_instance((dev_info_t *)bus_impldata));
2474                 }
2475         }
2476 
2477         return (ndi_event_run_callbacks(pshot->ndi_event_hdl,
2478             child, cookie, bus_impldata));
2479 }
2480 
2481 
2482 /*
2483  * the pshot driver event notification callback
2484  */
2485 static void
2486 pshot_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie,
2487         void *arg, void *bus_impldata)
2488 {
2489         pshot_t *pshot = (pshot_t *)arg;
2490         int event_tag;
2491 
2492         /* look up the event */
2493         event_tag = NDI_EVENT_TAG(cookie);
2494 
2495         if (pshot_debug) {
2496                 cmn_err(CE_CONT, "pshot%d: "
2497                     "pshot_event_cb:\n\t"
2498                     "dip = 0x%p cookie = 0x%p (%s), tag = 0x%x\n\t"
2499                     "arg = 0x%p bus_impl = 0x%p (%s%d)\n",
2500                     pshot->instance, (void *)dip, (void *)cookie,
2501                     NDI_EVENT_NAME(cookie), event_tag, arg, bus_impldata,
2502                     ddi_node_name((dev_info_t *)bus_impldata),
2503                     ddi_get_instance((dev_info_t *)bus_impldata));
2504         }
2505 
2506         switch (event_tag) {
2507         case PSHOT_EVENT_TAG_OFFLINE:
2508         case PSHOT_EVENT_TAG_BUS_RESET:
2509         case PSHOT_EVENT_TAG_BUS_QUIESCE:
2510         case PSHOT_EVENT_TAG_BUS_UNQUIESCE:
2511                 /* notify all subscribers of the this event */
2512                 (void) ndi_event_run_callbacks(pshot->ndi_event_hdl,
2513                     NULL, cookie, bus_impldata);
2514                 if (pshot_debug) {
2515                         cmn_err(CE_CONT, "pshot%d: event=%s\n\t"
2516                             "pshot_event_cb\n", pshot->instance,
2517                             NDI_EVENT_NAME(cookie));
2518                 }
2519                 /*FALLTHRU*/
2520         case PSHOT_EVENT_TAG_TEST_POST:
2521         case PSHOT_EVENT_TAG_DEV_RESET:
2522         default:
2523                 return;
2524         }
2525 }
2526 
2527 static int
2528 pshot_bus_config(dev_info_t *parent, uint_t flags,
2529     ddi_bus_config_op_t op, void *arg, dev_info_t **childp)
2530 {
2531         int             rval;
2532         char            *devname;
2533         char            *devstr, *cname, *caddr;
2534         int             devstrlen;
2535         int             circ;
2536         pshot_t         *pshot;
2537         int             instance = ddi_get_instance(parent);
2538 
2539         if (pshot_debug) {
2540                 flags |= NDI_DEVI_DEBUG;
2541                 cmn_err(CE_CONT,
2542                     "pshot%d: bus_config %s flags=0x%x\n",
2543                     ddi_get_instance(parent),
2544                     (op == BUS_CONFIG_ONE) ? (char *)arg : "", flags);
2545         }
2546 
2547         pshot = ddi_get_soft_state(pshot_softstatep, instance);
2548         if (pshot == NULL) {
2549 
2550                 return (NDI_FAILURE);
2551         }
2552 
2553         /*
2554          * Hold the nexus across the bus_config
2555          */
2556         ndi_devi_enter(parent, &circ);
2557 
2558         switch (op) {
2559         case BUS_CONFIG_ONE:
2560 
2561                 /*
2562                  * lookup and hold child device, create if not found
2563                  */
2564                 devname = (char *)arg;
2565                 devstrlen = strlen(devname) + 1;
2566                 devstr = i_ddi_strdup(devname, KM_SLEEP);
2567                 i_ddi_parse_name(devstr, &cname, &caddr, NULL);
2568 
2569                 /*
2570                  * The framework ensures that the node has
2571                  * a name but each nexus is responsible for
2572                  * the bus address name space.  This driver
2573                  * requires that a bus address be specified,
2574                  * as will most nexus drivers.
2575                  */
2576                 ASSERT(cname && strlen(cname) > 0);
2577                 if (caddr == NULL || strlen(caddr) == 0) {
2578                         cmn_err(CE_WARN,
2579                             "pshot%d: malformed name %s (no bus address)",
2580                             ddi_get_instance(parent), devname);
2581                         kmem_free(devstr, devstrlen);
2582                         ndi_devi_exit(parent, circ);
2583                         return (NDI_FAILURE);
2584                 }
2585 
2586                 /*
2587                  * Handle a few special cases for testing purposes
2588                  */
2589                 rval = pshot_bus_config_test_specials(parent,
2590                     devname, cname, caddr);
2591 
2592                 if (rval == NDI_SUCCESS) {
2593                         /*
2594                          * Set up either a leaf or nexus device
2595                          */
2596                         if (strcmp(cname, "pshot") == 0) {
2597                                 rval = pshot_bus_config_setup_nexus(parent,
2598                                     cname, caddr);
2599                         } else {
2600                                 rval = pshot_bus_config_setup_leaf(parent,
2601                                     cname, caddr);
2602                         }
2603                 }
2604 
2605                 kmem_free(devstr, devstrlen);
2606                 break;
2607 
2608         case BUS_CONFIG_DRIVER:
2609         case BUS_CONFIG_ALL:
2610                 rval = NDI_SUCCESS;
2611                 break;
2612 
2613         default:
2614                 rval = NDI_FAILURE;
2615                 break;
2616         }
2617 
2618         if (rval == NDI_SUCCESS)
2619                 rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0);
2620 
2621         ndi_devi_exit(parent, circ);
2622 
2623         if (pshot_debug)
2624                 cmn_err(CE_CONT, "pshot%d: bus_config %s\n",
2625                     ddi_get_instance(parent),
2626                     (rval == NDI_SUCCESS) ? "ok" : "failed");
2627 
2628         return (rval);
2629 }
2630 
2631 static int
2632 pshot_bus_unconfig(dev_info_t *parent, uint_t flags,
2633     ddi_bus_config_op_t op, void *arg)
2634 {
2635         major_t         major;
2636         int             rval = NDI_SUCCESS;
2637         int             circ;
2638 
2639         if (pshot_debug) {
2640                 flags |= NDI_DEVI_DEBUG;
2641                 cmn_err(CE_CONT,
2642                     "pshot%d: bus_unconfig %s flags=0x%x\n",
2643                     ddi_get_instance(parent),
2644                     (op == BUS_UNCONFIG_ONE) ? (char *)arg : "", flags);
2645         }
2646 
2647         /*
2648          * Hold the nexus across the bus_unconfig
2649          */
2650         ndi_devi_enter(parent, &circ);
2651 
2652         switch (op) {
2653         case BUS_UNCONFIG_ONE:
2654                 /*
2655                  * Nothing special required here
2656                  */
2657                 if (pshot_debug) {
2658                         cmn_err(CE_CONT, "pshot%d: bus_unconfig:"
2659                             " BUS_UNCONFIG_ONE\n", ddi_get_instance(parent));
2660                 }
2661                 break;
2662 
2663         case BUS_UNCONFIG_DRIVER:
2664                 if (pshot_debug > 0) {
2665                         major = (major_t)(uintptr_t)arg;
2666                         cmn_err(CE_CONT,
2667                             "pshot%d: BUS_UNCONFIG_DRIVER: %s\n",
2668                             ddi_get_instance(parent),
2669                             ddi_major_to_name(major));
2670                 }
2671                 break;
2672 
2673         case BUS_UNCONFIG_ALL:
2674                 if (pshot_debug) {
2675                         cmn_err(CE_CONT, "pshot%d: bus_unconfig:"
2676                             " BUS_UNCONFIG_ALL\n", ddi_get_instance(parent));
2677                 }
2678                 break;
2679 
2680         default:
2681                 if (pshot_debug) {
2682                         cmn_err(CE_CONT, "pshot%d: bus_unconfig: DEFAULT\n",
2683                             ddi_get_instance(parent));
2684                 }
2685                 rval = NDI_FAILURE;
2686         }
2687 
2688         if (rval == NDI_SUCCESS)
2689                 rval = ndi_busop_bus_unconfig(parent, flags, op, arg);
2690 
2691         ndi_devi_exit(parent, circ);
2692 
2693         if (pshot_debug)
2694                 cmn_err(CE_CONT, "pshot%d: bus_unconfig %s\n",
2695                     ddi_get_instance(parent),
2696                     (rval == NDI_SUCCESS) ? "ok" : "failed");
2697 
2698         return (rval);
2699 }
2700 
2701 static dev_info_t *
2702 pshot_findchild(dev_info_t *pdip, char *cname, char *caddr)
2703 {
2704         dev_info_t *dip;
2705         char *addr;
2706 
2707         ASSERT(cname != NULL && caddr != NULL);
2708         ASSERT(DEVI_BUSY_OWNED(pdip));
2709 
2710         for (dip = ddi_get_child(pdip); dip != NULL;
2711             dip = ddi_get_next_sibling(dip)) {
2712                 if (strcmp(cname, ddi_node_name(dip)) != 0)
2713                         continue;
2714 
2715                 if ((addr = ddi_get_name_addr(dip)) == NULL) {
2716                         if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0,
2717                             "bus-addr", &addr) == DDI_PROP_SUCCESS) {
2718                                 if (strcmp(caddr, addr) == 0) {
2719                                         ddi_prop_free(addr);
2720                                         return (dip);
2721                                 }
2722                                 ddi_prop_free(addr);
2723                         }
2724                 } else {
2725                         if (strcmp(caddr, addr) == 0)
2726                                 return (dip);
2727                 }
2728         }
2729 
2730         return (NULL);
2731 }
2732 
2733 static void
2734 pshot_nexus_properties(dev_info_t *parent, dev_info_t *child, char *cname,
2735     char *caddr)
2736 {
2737         char *extension;
2738 
2739         /*
2740          * extract the address extension
2741          */
2742         extension = strstr(caddr, ",");
2743         if (extension != NULL) {
2744                 ++extension;
2745         } else {
2746                 extension = "null";
2747         }
2748 
2749         /*
2750          * Create the "pm-want-child-notification?" property for all
2751          * nodes that do not have the "pm_strict" or "nopm_strict"
2752          * extension
2753          */
2754         if (strcmp(extension, "pm_strict") != 0 &&
2755             strcmp(extension, "nopm_strict") != 0) {
2756                 if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2757                     (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2758                     "pm-want-child-notification?") == 0) {
2759                         if (pshot_debug) {
2760                                 cmn_err(CE_CONT, "pshot%d:"
2761                                     " nexus_properties:\n\tcreate the"
2762                                     " \"pm-want-child-notification?\""
2763                                     " property for %s@%s\n",
2764                                     ddi_get_instance(parent), cname, caddr);
2765                         }
2766                         if (ddi_prop_create(DDI_DEV_T_NONE, child, 0,
2767                             "pm-want-child-notification?", NULL, 0)
2768                             != DDI_PROP_SUCCESS) {
2769                                 cmn_err(CE_WARN, "pshot%d:"
2770                                     " nexus_properties:\n\tunable to create"
2771                                     " the \"pm-want-child-notification?\""
2772                                     " property for %s@%s",
2773                                     ddi_get_instance(parent), cname, caddr);
2774                         }
2775                 }
2776         }
2777 
2778         /*
2779          * Create the "no-pm-components" property for all nodes
2780          * with extension "nopm" or "nopm_strict"
2781          */
2782         if (strcmp(extension, "nopm") == 0 ||
2783             strcmp(extension, "nopm_strict") == 0) {
2784                 if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2785                     (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2786                     "no-pm-components") == 0) {
2787                         if (pshot_debug) {
2788                                 cmn_err(CE_CONT, "pshot%d:"
2789                                     " nexus_properties:\n\tcreate the"
2790                                     " \"no-pm-components\""
2791                                     " property for %s@%s\n",
2792                                     ddi_get_instance(parent), cname, caddr);
2793                         }
2794                         if (ddi_prop_create(DDI_DEV_T_NONE, child, 0,
2795                             "no-pm-components", NULL, 0)
2796                             != DDI_PROP_SUCCESS) {
2797                                 cmn_err(CE_WARN, "pshot%d:"
2798                                     " nexus_properties:\n\tunable to create"
2799                                     " the \"no-pm-components\""
2800                                     " property for %s@%s",
2801                                     ddi_get_instance(parent), cname, caddr);
2802                         }
2803                 }
2804         }
2805 }
2806 
2807 static void
2808 pshot_leaf_properties(dev_info_t *parent, dev_info_t *child, char *cname,
2809     char *caddr)
2810 {
2811         char *extension;
2812 
2813         /*
2814          * extract the address extension
2815          */
2816         extension = strstr(caddr, ",");
2817         if (extension != NULL) {
2818                 ++extension;
2819         } else {
2820                 extension = "null";
2821         }
2822 
2823         /*
2824          * Create the "no-involuntary-power-cycles" property for
2825          * all leaf nodes with extension "no_invol"
2826          */
2827         if (strcmp(extension, "no_invol") == 0) {
2828                 if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2829                     (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2830                     "no-involuntary-power-cycles") == 0) {
2831                         if (pshot_debug) {
2832                                 cmn_err(CE_CONT, "pshot%d:"
2833                                     " leaf_properties:\n\tcreate the"
2834                                     " \"no-involuntary-power-cycles\""
2835                                     " property for %s@%s\n",
2836                                     ddi_get_instance(parent), cname, caddr);
2837                         }
2838                         if (ddi_prop_create(DDI_DEV_T_NONE, child,
2839                             DDI_PROP_CANSLEEP,
2840                             "no-involuntary-power-cycles", NULL, 0)
2841                             != DDI_PROP_SUCCESS) {
2842                                 cmn_err(CE_WARN, "pshot%d:"
2843                                     " leaf_properties:\n\tunable to create the"
2844                                     " \"no-involuntary-power-cycles\""
2845                                     " property for %s@%s",
2846                                     ddi_get_instance(parent), cname, caddr);
2847                         }
2848                 }
2849         }
2850 
2851         /*
2852          * Create the "dependency-property" property for all leaf
2853          * nodes with extension "dep_prop"
2854          * to be used with the PM_ADD_DEPENDENT_PROPERTY ioctl
2855          */
2856         if (strcmp(extension, "dep_prop") == 0) {
2857                 if (ddi_prop_exists(DDI_DEV_T_ANY, child,
2858                     (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM),
2859                     "dependency-property") == 0) {
2860                         if (pshot_debug) {
2861                                 cmn_err(CE_CONT, "pshot%d:"
2862                                     " leaf_properties:\n\tcreate the"
2863                                     " \"dependency-property\""
2864                                     " property for %s@%s\n",
2865                                     ddi_get_instance(parent), cname, caddr);
2866                         }
2867                         if (ddi_prop_create(DDI_DEV_T_NONE, child,
2868                             DDI_PROP_CANSLEEP, "dependency-property", NULL, 0)
2869                             != DDI_PROP_SUCCESS) {
2870                                 cmn_err(CE_WARN, "pshot%d:"
2871                                     " leaf_properties:\n\tunable to create the"
2872                                     " \"dependency-property\" property for"
2873                                     " %s@%s", ddi_get_instance(parent),
2874                                     cname, caddr);
2875                         }
2876                 }
2877         }
2878 }
2879 
2880 /*
2881  * BUS_CONFIG_ONE: setup a child nexus instance.
2882  */
2883 static int
2884 pshot_bus_config_setup_nexus(dev_info_t *parent, char *cname, char *caddr)
2885 {
2886         dev_info_t *child;
2887         int rval;
2888 
2889         ASSERT(parent != 0);
2890         ASSERT(cname != NULL);
2891         ASSERT(caddr != NULL);
2892 
2893         child = pshot_findchild(parent, cname, caddr);
2894         if (child) {
2895                 if (pshot_debug) {
2896                         cmn_err(CE_CONT,
2897                             "pshot%d: bus_config one %s@%s found\n",
2898                             ddi_get_instance(parent), cname, caddr);
2899                 }
2900 
2901                 /*
2902                  * create the "pm-want-child-notification?" property
2903                  * for this child, if it doesn't already exist
2904                  */
2905                 (void) pshot_nexus_properties(parent, child, cname, caddr);
2906 
2907                 return (NDI_SUCCESS);
2908         }
2909 
2910         ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child);
2911         ASSERT(child != NULL);
2912 
2913         if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
2914             "bus-addr", caddr) != DDI_PROP_SUCCESS) {
2915                 cmn_err(CE_WARN, "pshot%d: _prop_update %s@%s failed",
2916                     ddi_get_instance(parent), cname, caddr);
2917                 (void) ndi_devi_free(child);
2918                 return (NDI_FAILURE);
2919         }
2920 
2921         rval = ndi_devi_bind_driver(child, 0);
2922         if (rval != NDI_SUCCESS) {
2923                 cmn_err(CE_WARN, "pshot%d: bind_driver %s failed",
2924                     ddi_get_instance(parent), cname);
2925                 (void) ndi_devi_free(child);
2926                 return (NDI_FAILURE);
2927         }
2928 
2929         /*
2930          * create the "pm-want-child-notification?" property
2931          */
2932         (void) pshot_nexus_properties(parent, child, cname, caddr);
2933 
2934         return (NDI_SUCCESS);
2935 }
2936 
2937 /*
2938  * BUS_CONFIG_ONE: setup a child leaf device instance.
2939  * for testing purposes, we will create nodes of a variety of types.
2940  */
2941 static int
2942 pshot_bus_config_setup_leaf(dev_info_t *parent, char *cname, char *caddr)
2943 {
2944         dev_info_t *child;
2945         char *compat_name;
2946         char *nodetype;
2947         int rval;
2948         int i;
2949 
2950         ASSERT(parent != 0);
2951         ASSERT(cname != NULL);
2952         ASSERT(caddr != NULL);
2953 
2954         /*
2955          * if we already have a node with this name, return it
2956          */
2957         if ((child = pshot_findchild(parent, cname, caddr)) != NULL) {
2958                 /*
2959                  * create the "no-involuntary-power-cycles" or
2960                  * the "dependency-property" property, if they
2961                  * don't already exit
2962                  */
2963                 (void) pshot_leaf_properties(parent, child, cname, caddr);
2964 
2965                 return (NDI_SUCCESS);
2966         }
2967 
2968         ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child);
2969         ASSERT(child != NULL);
2970 
2971         if (ndi_prop_update_string(DDI_DEV_T_NONE, child, "bus-addr",
2972             caddr) != DDI_PROP_SUCCESS) {
2973                 (void) ndi_devi_free(child);
2974                 return (NDI_FAILURE);
2975         }
2976 
2977         /*
2978          * test compatible naming
2979          * if the child nodename is "cdisk", attach the list of compatible
2980          * named disks
2981          */
2982         if (strcmp(cname, pshot_compat_diskname) == 0) {
2983                 if ((ndi_prop_update_string_array(DDI_DEV_T_NONE,
2984                     child, "compatible", (char **)pshot_compat_psramdisks,
2985                     5)) != DDI_PROP_SUCCESS) {
2986                         (void) ndi_devi_free(child);
2987                         return (NDI_FAILURE);
2988                 }
2989         } else {
2990                 for (i = 0; i < pshot_devices_len && pshot_devices[i].name;
2991                     i++) {
2992                         if (strcmp(cname, pshot_devices[i].name) == 0) {
2993                                 compat_name = pshot_devices[i].compat;
2994                                 nodetype = pshot_devices[i].nodetype;
2995                                 if (pshot_debug) {
2996                                         cmn_err(CE_CONT, "pshot%d: %s %s %s\n",
2997                                             ddi_get_instance(parent), cname,
2998                                             compat_name, nodetype);
2999                                 }
3000                                 if ((ndi_prop_update_string_array(
3001                                     DDI_DEV_T_NONE, child, "compatible",
3002                                     &compat_name, 1)) != DDI_PROP_SUCCESS) {
3003                                         (void) ndi_devi_free(child);
3004                                         return (NDI_FAILURE);
3005                                 }
3006                                 if ((ndi_prop_update_string(
3007                                     DDI_DEV_T_NONE, child, "node-type",
3008                                     nodetype)) != DDI_PROP_SUCCESS) {
3009                                         (void) ndi_devi_free(child);
3010                                         return (NDI_FAILURE);
3011                                 }
3012                         }
3013                 }
3014         }
3015 
3016         rval = ndi_devi_bind_driver(child, 0);
3017         if (rval != NDI_SUCCESS) {
3018                 cmn_err(CE_WARN, "pshot%d: bind_driver %s failed",
3019                     ddi_get_instance(parent), cname);
3020                 (void) ndi_devi_free(child);
3021                 return (NDI_FAILURE);
3022         }
3023 
3024         /*
3025          * create the "no-involuntary-power-cycles" or
3026          * the "dependency-property" property
3027          */
3028         (void) pshot_leaf_properties(parent, child, cname, caddr);
3029 
3030         return (NDI_SUCCESS);
3031 }
3032 
3033 /*
3034  * Handle some special cases for testing bus_config via pshot
3035  *
3036  * Match these special address formats to behavior:
3037  *
3038  *      err.*           - induce bus_config error
3039  *      delay           - induce 1 second of bus_config delay time
3040  *      delay,n         - induce n seconds of bus_config delay time
3041  *      wait            - induce 1 second of bus_config wait time
3042  *      wait,n          - induce n seconds of bus_config wait time
3043  *      failinit.*      - induce error at INITCHILD
3044  *      failprobe.*     - induce error at probe
3045  *      failattach.*    - induce error at attach
3046  */
3047 /*ARGSUSED*/
3048 static int
3049 pshot_bus_config_test_specials(dev_info_t *parent, char *devname,
3050         char *cname, char *caddr)
3051 {
3052         char    *p;
3053         int     n;
3054 
3055         if (strncmp(caddr, "err", 3) == 0) {
3056                 if (pshot_debug)
3057                         cmn_err(CE_CONT,
3058                             "pshot%d: %s forced failure\n",
3059                             ddi_get_instance(parent), devname);
3060                 return (NDI_FAILURE);
3061         }
3062 
3063         /*
3064          * The delay and wait strings have the same effect.
3065          * The "wait[,]" support should be removed once the
3066          * devfs test suites are fixed.
3067          * NOTE: delay should not be called from interrupt context
3068          */
3069         ASSERT(!servicing_interrupt());
3070 
3071         if (strncmp(caddr, "delay,", 6) == 0) {
3072                 p = caddr+6;
3073                 n = stoi(&p);
3074                 if (*p != 0)
3075                         n = 1;
3076                 if (pshot_debug)
3077                         cmn_err(CE_CONT,
3078                             "pshot%d: %s delay %d second\n",
3079                             ddi_get_instance(parent), devname, n);
3080                 delay(n * drv_usectohz(1000000));
3081         } else if (strncmp(caddr, "delay", 5) == 0) {
3082                 if (pshot_debug)
3083                         cmn_err(CE_CONT,
3084                             "pshot%d: %s delay 1 second\n",
3085                             ddi_get_instance(parent), devname);
3086                 delay(drv_usectohz(1000000));
3087         } else if (strncmp(caddr, "wait,", 5) == 0) {
3088                 p = caddr+5;
3089                 n = stoi(&p);
3090                 if (*p != 0)
3091                         n = 1;
3092                 if (pshot_debug)
3093                         cmn_err(CE_CONT,
3094                             "pshot%d: %s wait %d second\n",
3095                             ddi_get_instance(parent), devname, n);
3096                 delay(n * drv_usectohz(1000000));
3097         } else if (strncmp(caddr, "wait", 4) == 0) {
3098                 if (pshot_debug)
3099                         cmn_err(CE_CONT,
3100                             "pshot%d: %s wait 1 second\n",
3101                             ddi_get_instance(parent), devname);
3102                 delay(drv_usectohz(1000000));
3103         }
3104 
3105         return (NDI_SUCCESS);
3106 }
3107 
3108 /*
3109  * translate nodetype name to actual value
3110  */
3111 static char *
3112 pshot_str2nt(char *str)
3113 {
3114         int i;
3115 
3116         for (i = 0; pshot_nodetypes[i].name; i++) {
3117                 if (strcmp(pshot_nodetypes[i].name, str) == 0)
3118                         return (pshot_nodetypes[i].val);
3119         }
3120         return (NULL);
3121 }
3122 
3123 /*
3124  * grows array pointed to by <dstp>, with <src> data
3125  * <dstlen> = # elements of the original <*dstp>
3126  * <srclen> = # elements of <src>
3127  *
3128  * on success, returns 0 and a pointer to the new array through <dstp> with
3129  * <srclen> + <dstlen> number of elements;
3130  * else returns non-zero
3131  *
3132  * a NULL <*dstp> is OK (a NULL <dstp> is not) and so is a zero <dstlen>
3133  */
3134 static int
3135 pshot_devices_grow(pshot_device_t **dstp, size_t dstlen,
3136     const pshot_device_t *src, size_t srclen)
3137 {
3138         size_t i;
3139         pshot_device_t *newdst;
3140 
3141         newdst = kmem_alloc((srclen + dstlen) * sizeof (*src),
3142             KM_SLEEP);
3143 
3144         /* keep old pointers and dup new ones */
3145         if (*dstp)
3146                 bcopy(*dstp, newdst, dstlen * sizeof (*src));
3147         for (i = 0; i < srclen; i++) {
3148                 newdst[i + dstlen].name =
3149                     i_ddi_strdup(src[i].name, KM_SLEEP);
3150 
3151                 newdst[i + dstlen].nodetype =
3152                     i_ddi_strdup(src[i].nodetype, KM_SLEEP);
3153 
3154                 newdst[i + dstlen].compat =
3155                     i_ddi_strdup(src[i].compat, KM_SLEEP);
3156         }
3157 
3158         /* do last */
3159         if (*dstp)
3160                 kmem_free(*dstp, dstlen * sizeof (*src));
3161         *dstp = newdst;
3162         return (0);
3163 }
3164 
3165 /*
3166  * free a pshot_device_t array <dp> with <len> elements
3167  * null pointers within the elements are ok
3168  */
3169 static void
3170 pshot_devices_free(pshot_device_t *dp, size_t len)
3171 {
3172         size_t i;
3173 
3174         for (i = 0; i < len; i++) {
3175                 if (dp[i].name)
3176                         kmem_free(dp[i].name, strlen(dp[i].name) + 1);
3177                 if (dp[i].nodetype)
3178                         kmem_free(dp[i].nodetype, strlen(dp[i].nodetype) + 1);
3179                 if (dp[i].compat)
3180                         kmem_free(dp[i].compat, strlen(dp[i].compat) + 1);
3181         }
3182         kmem_free(dp, len * sizeof (*dp));
3183 }
3184 
3185 /*
3186  * returns an array of pshot_device_t parsed from <dip>'s properties
3187  *
3188  * property structure (i.e. pshot.conf) for pshot:
3189  *
3190  * corresponding         |   pshot_device_t array elements
3191  * pshot_device_t        |
3192  * member by prop name   |   [0]            [1]           [2]
3193  * ----------------------|--------------|-------------|-----------------------
3194  * <PSHOT_PROP_DEVNAME>  ="disk",        "tape",       "testdev";
3195  * <PSHOT_PROP_DEVNT>    ="DDI_NT_BLOCK","DDI_NT_TAPE","ddi_testdev_nodetype";
3196  * <PSHOT_PROP_DEVCOMPAT>="testdrv",     "testdrv",    "testdrv";
3197  *
3198  *
3199  * if any of these properties are specified, then:
3200  * - all the members must be specified
3201  * - the number of elements for each string array property must be the same
3202  * - no empty strings allowed
3203  * - nodetypes (PSHOT_PROP_DEVNT) must be the nodetype name as specified in
3204  *   sys/sunddi.h
3205  *
3206  * NOTE: the pshot_nodetypes[] table should be kept in sync with the list
3207  * of ddi nodetypes.  It's not normally critical to always be in sync so
3208  * keeping this up-to-date can usually be done "on-demand".
3209  *
3210  * if <flags> & PSHOT_DEV_ANYNT, then custom nodetype strings are allowed.
3211  * these will be duplicated verbatim
3212  */
3213 static pshot_device_t *
3214 pshot_devices_from_props(dev_info_t *dip, size_t *lenp, int flags)
3215 {
3216         pshot_device_t *devarr = NULL;
3217         char **name_arr = NULL, **nt_arr = NULL, **compat_arr = NULL;
3218         uint_t name_arr_len, nt_arr_len, compat_arr_len;
3219         uint_t i;
3220         char *str;
3221 
3222         if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
3223             PSHOT_PROP_DEVNAME, &name_arr, &name_arr_len) !=
3224             DDI_PROP_SUCCESS)
3225                 name_arr = NULL;
3226 
3227         if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
3228             PSHOT_PROP_DEVNT, &nt_arr, &nt_arr_len) !=
3229             DDI_PROP_SUCCESS)
3230                 nt_arr = NULL;
3231 
3232         if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0,
3233             PSHOT_PROP_DEVCOMPAT, &compat_arr, &compat_arr_len) !=
3234             DDI_PROP_SUCCESS)
3235                 compat_arr = NULL;
3236 
3237         /*
3238          * warn about any incorrect usage, if specified
3239          */
3240         if (!(name_arr || nt_arr || compat_arr))
3241                 return (NULL);
3242 
3243         if (!(name_arr && nt_arr && compat_arr) ||
3244             (name_arr_len != nt_arr_len) ||
3245             (name_arr_len != compat_arr_len))
3246                 goto FAIL;
3247 
3248         for (i = 0; i < name_arr_len; i++) {
3249                 if (*name_arr[i] == '\0' ||
3250                     *nt_arr[i] == '\0' ||
3251                     *compat_arr[i] == '\0')
3252                         goto FAIL;
3253         }
3254 
3255         devarr = kmem_zalloc(name_arr_len * sizeof (*devarr), KM_SLEEP);
3256         for (i = 0; i < name_arr_len; i++) {
3257                 devarr[i].name = i_ddi_strdup(name_arr[i], KM_SLEEP);
3258                 devarr[i].compat = i_ddi_strdup(compat_arr[i], KM_SLEEP);
3259 
3260                 if ((str = pshot_str2nt(nt_arr[i])) == NULL)
3261                         if (flags & PSHOT_DEV_ANYNT)
3262                                 str = nt_arr[i];
3263                         else
3264                                 goto FAIL;
3265                 devarr[i].nodetype = i_ddi_strdup(str, KM_SLEEP);
3266         }
3267         ddi_prop_free(name_arr);
3268         ddi_prop_free(nt_arr);
3269         ddi_prop_free(compat_arr);
3270 
3271         /* set <*lenp> ONLY on success */
3272         *lenp = name_arr_len;
3273 
3274         return (devarr);
3275         /*NOTREACHED*/
3276 FAIL:
3277         cmn_err(CE_WARN, "malformed device specification property");
3278         if (name_arr)
3279                 ddi_prop_free(name_arr);
3280         if (nt_arr)
3281                 ddi_prop_free(nt_arr);
3282         if (compat_arr)
3283                 ddi_prop_free(compat_arr);
3284         if (devarr)
3285                 pshot_devices_free(devarr, name_arr_len);
3286         return (NULL);
3287 }
3288 
3289 /*
3290  * if global <pshot_devices> was not set up already (i.e. is NULL):
3291  *      sets up global <pshot_devices> and <pshot_devices_len>,
3292  *      using device properties from <dip> and global <pshot_stock_devices>.
3293  *      device properties, if any, overrides pshot_stock_devices.
3294  *
3295  * returns 0 on success (or if pshot_devices already set up)
3296  *
3297  * INTERNAL LOCKING: <pshot_devices_lock>
3298  */
3299 static int
3300 pshot_devices_setup(dev_info_t *dip)
3301 {
3302         pshot_device_t *newdevs = NULL;
3303         size_t newdevs_len = 0;
3304         int rv = 0;
3305 
3306         mutex_enter(&pshot_devices_lock);
3307         if (pshot_devices != NULL)
3308                 goto FAIL;
3309 
3310         ASSERT(pshot_devices_len == 0);
3311 
3312         newdevs = pshot_devices_from_props(dip, &newdevs_len, PSHOT_DEV_ANYNT);
3313         rv = pshot_devices_grow(&newdevs, newdevs_len, pshot_stock_devices,
3314             PSHOT_N_STOCK_DEVICES);
3315         if (rv != 0) {
3316                 cmn_err(CE_WARN, "pshot_devices_setup: pshot_devices_grow "
3317                     "failed");
3318                 goto FAIL;
3319         }
3320         newdevs_len += PSHOT_N_STOCK_DEVICES;
3321 
3322         pshot_devices = newdevs;
3323         pshot_devices_len = newdevs_len;
3324         rv = 0;
3325 FAIL:
3326         if (rv && newdevs)
3327                 pshot_devices_free(newdevs, newdevs_len);
3328         mutex_exit(&pshot_devices_lock);
3329         return (rv);
3330 }
3331 
3332 
3333 #ifdef NOTNEEDED
3334 /* ARGSUSED */
3335 static int
3336 pshot_probe_family(dev_info_t *self, ddi_probe_method_t probe_how,
3337     dev_info_t **return_dip)
3338 {
3339         char name[64];
3340         uint_t bus_id;
3341         dev_info_t *child;
3342 
3343         for (bus_id = 10; bus_id < 20; bus_id++) {
3344                 (void) sprintf(name, "%d", bus_id);
3345                 if ((ndi_devi_alloc(self, "psramd", DEVI_SID_NODEID,
3346                     &child)) != NDI_SUCCESS) {
3347                         return (DDI_FAILURE);
3348                 }
3349 
3350                 if (ndi_prop_update_string(DDI_DEV_T_NONE, child,
3351                     "bus-addr", name) != DDI_PROP_SUCCESS) {
3352                         (void) ndi_devi_free(child);
3353                         if (return_dip != NULL)
3354                                 *return_dip = (dev_info_t *)NULL;
3355                         return (DDI_FAILURE);
3356                 }
3357 
3358                 if (ndi_devi_online(child, 0) != NDI_SUCCESS) {
3359                         return (DDI_FAILURE);
3360                 }
3361         }
3362         return (DDI_SUCCESS);
3363 }
3364 
3365 static int
3366 strtoi(char *str)
3367 {
3368         int c;
3369         int val;
3370 
3371         for (val = 0, c = *str++; c >= '0' && c <= '9'; c = *str++) {
3372                 val *= 10;
3373                 val += c - '0';
3374         }
3375         return (val);
3376 }
3377 
3378 #endif
3379 
3380 static void
3381 pshot_setup_autoattach(dev_info_t *devi)
3382 {
3383         dev_info_t *l1child, *l2child;
3384         int rv;
3385 
3386         rv = ndi_devi_alloc(devi, "pshot", DEVI_SID_NODEID, &l1child);
3387         if (rv == NDI_SUCCESS) {
3388                 (void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
3389                     "bus-addr", "0");
3390                 rv =  ndi_devi_alloc(l1child, "port", DEVI_SID_NODEID,
3391                     &l2child);
3392                 if (rv == NDI_SUCCESS)
3393                         (void) ndi_prop_update_string(DDI_DEV_T_NONE,
3394                             l2child, "bus-addr", "99");
3395         }
3396 
3397         rv = ndi_devi_alloc(devi, "port", DEVI_SID_NODEID, &l1child);
3398         if (rv == NDI_SUCCESS)
3399                 (void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
3400                     "bus-addr", "99");
3401 
3402         rv = ndi_devi_alloc(devi, "gen_drv", DEVI_SID_NODEID, &l1child);
3403         if (rv == NDI_SUCCESS)
3404                 (void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child,
3405                     "bus-addr", "99");
3406 
3407         rv = ndi_devi_alloc(devi, "no_driver", DEVI_SID_NODEID, &l1child);
3408         if (rv == NDI_SUCCESS)
3409                 (void) ndi_devi_alloc(l1child, "no_driver", DEVI_SID_NODEID,
3410                     &l2child);
3411 }
3412 
3413 #ifdef PRUNE_SNUBS
3414 
3415 #define PRUNE_THIS_NODE(d) (((d)->devi_node_name != NULL) && \
3416         (DEVI_PROM_NODE((d)->devi_nodeid)) && \
3417         ((d)->devi_addr == NULL))
3418 /*
3419  * test code to remove OBP nodes that have not attached
3420  */
3421 static void
3422 prune_snubs(const char *name)
3423 {
3424         struct dev_info *nex_dip, *cdip, *cndip;
3425         int maj;
3426         int rv;
3427 
3428         maj = ddi_name_to_major((char *)name);
3429         if (maj != -1) {
3430                 nex_dip = (struct dev_info *)devnamesp[maj].dn_head;
3431                 while (nex_dip != NULL) {
3432                         cndip = ddi_get_child(nex_dip);
3433                         while ((cdip = cndip) != NULL) {
3434                                 cndip = cdip->devi_sibling;
3435                                 if (PRUNE_THIS_NODE(cdip)) {
3436                                         cmn_err(CE_NOTE,
3437                                             "parent %s@%s pruning node %s",
3438                                             nex_dip->devi_node_name,
3439                                             nex_dip->devi_addr,
3440                                             cdip->devi_node_name);
3441                                         rv = ndi_devi_offline(cdip,
3442                                             NDI_DEVI_REMOVE);
3443                                         if (rv != NDI_SUCCESS)
3444                                                 cmn_err(CE_NOTE,
3445                                                     "failed to prune node, "
3446                                                     "err %d", rv);
3447                                 }
3448                         }
3449                 nex_dip = nex_dip->devi_next;
3450                 }
3451         }
3452 }
3453 
3454 #endif /* PRUBE_SNUBS */
3455 
3456 #ifdef KERNEL_DEVICE_TREE_WALKER
3457 static kthread_id_t pwt;
3458 static kmutex_t pwl;
3459 static kcondvar_t pwcv;
3460 
3461 static void
3462 pshot_walk_tree()
3463 {
3464         static int pshot_devnode(dev_info_t *dip, void * arg);
3465 
3466         dev_info_t *root = ddi_root_node();
3467         ddi_walk_devs(root, pshot_devnode, NULL);
3468 }
3469 
3470 static void
3471 pshot_walk_thread()
3472 {
3473         static void pshot_timeout(void *arg);
3474         static kthread_id_t pwt;
3475 
3476         pwt = curthread;
3477         mutex_init(&pwl, NULL, MUTEX_DRIVER, NULL);
3478         cv_init(&pwcv, NULL, CV_DRIVER, NULL);
3479 
3480         while (1) {
3481                 pshot_walk_tree();
3482                 mutex_enter(&pwl);
3483                 (void) timeout(pshot_timeout, NULL, 5 * drv_usectohz(1000000));
3484                 cv_wait(&pwcv, &pwl);
3485                 mutex_exit(&pwl);
3486         }
3487 }
3488 
3489 static void
3490 pshot_timeout(void *arg)
3491 {
3492         mutex_enter(&pwl);
3493         cv_signal(&pwcv);
3494         mutex_exit(&pwl);
3495 }
3496 
3497 static int
3498 pshot_devnode(dev_info_t *dip, void *arg)
3499 {
3500         dev_info_t *f_dip;
3501 
3502         if (dip != ddi_root_node()) {
3503                 f_dip = ndi_devi_find((dev_info_t *)DEVI(dip)->devi_parent,
3504                     DEVI(dip)->devi_node_name, DEVI(dip)->devi_addr);
3505                 if (f_dip != dip) {
3506                         cmn_err(CE_NOTE, "!pshot_devnode: failed lookup"
3507                             "node (%s/%s@%s)\n",
3508                             DEVI(DEVI(dip)->devi_parent)->devi_node_name,
3509                             (DEVI(dip)->devi_node_name ?
3510                             DEVI(dip)->devi_node_name : "NULL"),
3511                             (DEVI(dip)->devi_addr ? DEVI(dip)->devi_addr :
3512                             "NULL"));
3513                 }
3514         }
3515         return (DDI_WALK_CONTINUE);
3516 }
3517 #endif /* KERNEL_DEVICE_TREE_WALKER */
3518 
3519 #ifdef DEBUG
3520 static void
3521 pshot_event_cb_test(dev_info_t *dip, ddi_eventcookie_t cookie,
3522         void *arg, void *bus_impldata)
3523 {
3524         pshot_t *softstate = (pshot_t *)arg;
3525         int event_tag;
3526 
3527         /* look up the event */
3528         event_tag = NDI_EVENT_TAG(cookie);
3529         cmn_err(CE_CONT, "pshot_event_cb_test:\n\t"
3530             "dip = 0x%p cookie = 0x%p (%s), tag = %d\n\t"
3531             "arg = 0x%p bus_impl = 0x%p\n",
3532             (void *)dip, (void *)cookie, NDI_EVENT_NAME(cookie),
3533             event_tag, (void *)softstate, (void *)bus_impldata);
3534 
3535 }
3536 
3537 static void
3538 pshot_event_test(void *arg)
3539 {
3540         pshot_t *pshot = (pshot_t *)arg;
3541         ndi_event_hdl_t hdl;
3542         ndi_event_set_t events;
3543         int i, rval;
3544 
3545         (void) ndi_event_alloc_hdl(pshot->dip, NULL, &hdl, NDI_SLEEP);
3546 
3547         events.ndi_events_version = NDI_EVENTS_REV1;
3548         events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3549         events.ndi_event_defs = pshot_test_events;
3550 
3551         cmn_err(CE_CONT, "pshot: binding set of 8 events\n");
3552         delay(drv_usectohz(1000000));
3553         rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3554         cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3555 
3556         cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
3557         delay(drv_usectohz(1000000));
3558         rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3559         cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3560 
3561         cmn_err(CE_CONT, "pshot: unbinding  all events\n");
3562         delay(drv_usectohz(1000000));
3563         rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3564         cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3565 
3566 
3567         cmn_err(CE_CONT, "pshot: binding one highlevel event\n");
3568         delay(drv_usectohz(1000000));
3569         events.ndi_n_events = 1;
3570         events.ndi_event_defs = pshot_test_events_high;
3571         rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3572         cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3573 
3574         cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
3575         delay(drv_usectohz(1000000));
3576         events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3577         events.ndi_event_defs = pshot_test_events;
3578         rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3579         cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3580 
3581         cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n");
3582         delay(drv_usectohz(1000000));
3583         events.ndi_n_events = 1;
3584         events.ndi_event_defs = pshot_test_events_high;
3585         rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3586         cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3587 
3588         cmn_err(CE_CONT, "pshot: binding one highlevel event\n");
3589         delay(drv_usectohz(1000000));
3590         events.ndi_n_events = 1;
3591         events.ndi_event_defs = pshot_test_events_high;
3592         rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3593         cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3594 
3595         cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n");
3596         delay(drv_usectohz(1000000));
3597         events.ndi_n_events = 1;
3598         events.ndi_event_defs = pshot_test_events_high;
3599         rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3600         cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3601 
3602         cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n");
3603         delay(drv_usectohz(1000000));
3604         events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3605         events.ndi_event_defs = pshot_test_events;
3606         rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3607         cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3608 
3609         cmn_err(CE_CONT, "pshot: unbinding first 2 events\n");
3610         delay(drv_usectohz(1000000));
3611         events.ndi_n_events = 2;
3612         events.ndi_event_defs = pshot_test_events;
3613         rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3614         cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3615 
3616         cmn_err(CE_CONT, "pshot: unbinding first 2 events again\n");
3617         delay(drv_usectohz(1000000));
3618         events.ndi_n_events = 2;
3619         events.ndi_event_defs = pshot_test_events;
3620         rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3621         cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3622 
3623         cmn_err(CE_CONT, "pshot: unbinding  middle 2 events\n");
3624         delay(drv_usectohz(1000000));
3625         events.ndi_n_events = 2;
3626         events.ndi_event_defs = &pshot_test_events[4];
3627         rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3628         cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3629 
3630         cmn_err(CE_CONT, "pshot: binding those 2 events back\n");
3631         delay(drv_usectohz(1000000));
3632         events.ndi_n_events = 2;
3633         events.ndi_event_defs = &pshot_test_events[4];
3634         rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3635         cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3636 
3637         cmn_err(CE_CONT, "pshot: unbinding  2 events\n");
3638         delay(drv_usectohz(1000000));
3639         events.ndi_n_events = 2;
3640         events.ndi_event_defs = &pshot_test_events[4];
3641         rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3642         cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3643 
3644         cmn_err(CE_CONT, "pshot: unbinding  all events\n");
3645         delay(drv_usectohz(1000000));
3646         events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3647         events.ndi_event_defs = pshot_test_events;
3648         rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3649         cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3650 
3651         cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
3652         delay(drv_usectohz(1000000));
3653         events.ndi_n_events = 1;
3654         events.ndi_event_defs = &pshot_test_events[2];
3655         rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3656         cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3657 
3658         cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
3659         delay(drv_usectohz(1000000));
3660         events.ndi_n_events = 1;
3661         events.ndi_event_defs = &pshot_test_events[3];
3662         rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3663         cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3664 
3665         cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
3666         delay(drv_usectohz(1000000));
3667         events.ndi_n_events = 1;
3668         events.ndi_event_defs = &pshot_test_events[6];
3669         rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3670         cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3671 
3672         cmn_err(CE_CONT, "pshot: unbinding  1 event\n");
3673         delay(drv_usectohz(1000000));
3674         events.ndi_n_events = 1;
3675         events.ndi_event_defs = &pshot_test_events[7];
3676         rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP);
3677         cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval);
3678 
3679         events.ndi_n_events = PSHOT_N_TEST_EVENTS;
3680         events.ndi_event_defs = pshot_test_events;
3681 
3682         cmn_err(CE_CONT, "pshot: binding set of 8 events\n");
3683         delay(drv_usectohz(1000000));
3684         rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP);
3685         cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval);
3686 
3687         cmn_err(CE_CONT, "pshot: adding 8 callbacks\n");
3688         delay(drv_usectohz(1000000));
3689         for (i = 0; i < 8; i++) {
3690                 rval = ndi_event_add_callback(hdl, pshot->dip,
3691                     ndi_event_tag_to_cookie(hdl,
3692                     pshot_test_events[i].ndi_event_tag),
3693                     pshot_event_cb_test,
3694                     (void *)(uintptr_t)pshot_test_events[i].ndi_event_tag,
3695                     NDI_SLEEP, &pshot->test_callback_cache[i]);
3696                 ASSERT(rval == NDI_SUCCESS);
3697         }
3698 
3699         cmn_err(CE_CONT, "pshot: event callbacks\n");
3700 
3701         for (i = 10; i < 18; i++) {
3702                 ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i);
3703 
3704                 rval = ndi_event_run_callbacks(hdl, pshot->dip, cookie,
3705                     (void *)hdl);
3706 
3707                 cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n",
3708                     i, rval);
3709                 delay(drv_usectohz(1000000));
3710         }
3711 
3712         cmn_err(CE_CONT, "pshot: redo event callbacks\n");
3713 
3714         for (i = 10; i < 18; i++) {
3715                 ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i);
3716 
3717                 rval = ndi_event_run_callbacks(hdl,
3718                     pshot->dip, cookie, (void *)hdl);
3719 
3720                 cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n",
3721                     i, rval);
3722                 delay(drv_usectohz(1000000));
3723         }
3724 
3725         cmn_err(CE_CONT, "pshot: removing 8 callbacks\n");
3726         delay(drv_usectohz(1000000));
3727 
3728         for (i = 0; i < 8; i++) {
3729                 (void) ndi_event_remove_callback(hdl,
3730                     pshot->test_callback_cache[i]);
3731 
3732                 pshot->test_callback_cache[i] = 0;
3733         }
3734 
3735         cmn_err(CE_CONT, "pshot: freeing handle with bound set\n");
3736         delay(drv_usectohz(1000000));
3737 
3738         rval =  ndi_event_free_hdl(hdl);
3739 
3740         ASSERT(rval == NDI_SUCCESS);
3741 
3742 }
3743 
3744 void
3745 pshot_event_test_post_one(void *arg)
3746 {
3747         pshot_t *pshot = (pshot_t *)arg;
3748         int rval;
3749         ddi_eventcookie_t cookie;
3750 
3751         cmn_err(CE_CONT, "pshot%d: pshot_event_post_one event\n",
3752             pshot->instance);
3753 
3754         if (ddi_get_eventcookie(pshot->dip, PSHOT_EVENT_NAME_BUS_TEST_POST,
3755             &cookie) != DDI_SUCCESS) {
3756                 cmn_err(CE_NOTE, "pshot_bus_test_post cookie not found");
3757                 return;
3758         }
3759 
3760         rval = ndi_post_event(pshot->dip, pshot->dip, cookie, NULL);
3761 
3762         cmn_err(CE_CONT, "pshot%d: pshot_event_post_one rval=%d\n",
3763             pshot->instance, rval);
3764 
3765         (void) timeout(pshot_event_test_post_one, (void *)pshot,
3766             pshot->instance * drv_usectohz(60000000));
3767 
3768 }
3769 #endif /* DEBUG */