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