1*0Sstevel@tonic-gate /* 2*0Sstevel@tonic-gate * CDDL HEADER START 3*0Sstevel@tonic-gate * 4*0Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*0Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 6*0Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 7*0Sstevel@tonic-gate * with the License. 8*0Sstevel@tonic-gate * 9*0Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 10*0Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 11*0Sstevel@tonic-gate * See the License for the specific language governing permissions 12*0Sstevel@tonic-gate * and limitations under the License. 13*0Sstevel@tonic-gate * 14*0Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 15*0Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 16*0Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 17*0Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 18*0Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 19*0Sstevel@tonic-gate * 20*0Sstevel@tonic-gate * CDDL HEADER END 21*0Sstevel@tonic-gate */ 22*0Sstevel@tonic-gate /* 23*0Sstevel@tonic-gate * Copyright 2004 Sun Microsystems, Inc. All rights reserved. 24*0Sstevel@tonic-gate * Use is subject to license terms. 25*0Sstevel@tonic-gate */ 26*0Sstevel@tonic-gate 27*0Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 28*0Sstevel@tonic-gate 29*0Sstevel@tonic-gate 30*0Sstevel@tonic-gate /* 31*0Sstevel@tonic-gate * generic character driver 32*0Sstevel@tonic-gate */ 33*0Sstevel@tonic-gate #include <sys/types.h> 34*0Sstevel@tonic-gate #include <sys/param.h> 35*0Sstevel@tonic-gate #include <sys/errno.h> 36*0Sstevel@tonic-gate #include <sys/uio.h> 37*0Sstevel@tonic-gate #include <sys/buf.h> 38*0Sstevel@tonic-gate #include <sys/modctl.h> 39*0Sstevel@tonic-gate #include <sys/open.h> 40*0Sstevel@tonic-gate #include <sys/kmem.h> 41*0Sstevel@tonic-gate #include <sys/conf.h> 42*0Sstevel@tonic-gate #include <sys/cmn_err.h> 43*0Sstevel@tonic-gate #include <sys/stat.h> 44*0Sstevel@tonic-gate #include <sys/ddi.h> 45*0Sstevel@tonic-gate #include <sys/sunddi.h> 46*0Sstevel@tonic-gate #include <sys/sunndi.h> 47*0Sstevel@tonic-gate 48*0Sstevel@tonic-gate 49*0Sstevel@tonic-gate #define NUMEVENTS 6 50*0Sstevel@tonic-gate #define COMPONENTS 2 51*0Sstevel@tonic-gate #define COMP_0_MAXPWR 3 52*0Sstevel@tonic-gate #define COMP_1_MAXPWR 2 53*0Sstevel@tonic-gate #define MINPWR 0 54*0Sstevel@tonic-gate static int maxpwr[] = { COMP_0_MAXPWR, COMP_1_MAXPWR }; 55*0Sstevel@tonic-gate 56*0Sstevel@tonic-gate /* 57*0Sstevel@tonic-gate * The state for each generic device. 58*0Sstevel@tonic-gate * NOTE: We save the node_type in the state structure. The node_type string 59*0Sstevel@tonic-gate * (and not a copy) is stashed in a minor node by ddi_create_minor_node(), 60*0Sstevel@tonic-gate * so ddi_remove_minor_node() must occur prior to state free. 61*0Sstevel@tonic-gate */ 62*0Sstevel@tonic-gate typedef struct dstate { 63*0Sstevel@tonic-gate uint_t flag; 64*0Sstevel@tonic-gate dev_info_t *dip; /* my devinfo handle */ 65*0Sstevel@tonic-gate char *node_type; /* stable node_type copy */ 66*0Sstevel@tonic-gate ddi_callback_id_t gen_cb_ids[NUMEVENTS]; 67*0Sstevel@tonic-gate kmutex_t lock; 68*0Sstevel@tonic-gate char *nodename; 69*0Sstevel@tonic-gate int level[COMPONENTS]; /* pm level */ 70*0Sstevel@tonic-gate int busy[COMPONENTS]; /* busy state */ 71*0Sstevel@tonic-gate } dstate_t; 72*0Sstevel@tonic-gate 73*0Sstevel@tonic-gate 74*0Sstevel@tonic-gate static void *dstates; 75*0Sstevel@tonic-gate 76*0Sstevel@tonic-gate static int gen_debug = 0; 77*0Sstevel@tonic-gate 78*0Sstevel@tonic-gate #ifdef DEBUG 79*0Sstevel@tonic-gate #define gen_debug gen_debug_on 80*0Sstevel@tonic-gate static int gen_debug_on = 0; 81*0Sstevel@tonic-gate #define GEN_DEBUG(args) if (gen_debug) cmn_err args 82*0Sstevel@tonic-gate #else 83*0Sstevel@tonic-gate #define GEN_DEBUG(args) 84*0Sstevel@tonic-gate #endif 85*0Sstevel@tonic-gate 86*0Sstevel@tonic-gate extern void prom_printf(const char *fmt, ...); 87*0Sstevel@tonic-gate 88*0Sstevel@tonic-gate static int gen_open(dev_t *devp, int flag, int otyp, cred_t *cred); 89*0Sstevel@tonic-gate static int gen_close(dev_t devp, int flag, int otyp, cred_t *cred); 90*0Sstevel@tonic-gate static int gen_read(dev_t dev, struct uio *uiop, cred_t *credp); 91*0Sstevel@tonic-gate static int gen_write(dev_t dev, struct uio *uiop, cred_t *credp); 92*0Sstevel@tonic-gate static int gen_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 93*0Sstevel@tonic-gate cred_t *credp, int *rvalp); 94*0Sstevel@tonic-gate static int gen_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 95*0Sstevel@tonic-gate static int gen_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 96*0Sstevel@tonic-gate static void gen_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie, 97*0Sstevel@tonic-gate void *arg, void *impl_data); 98*0Sstevel@tonic-gate 99*0Sstevel@tonic-gate static int gen_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 100*0Sstevel@tonic-gate void **result); 101*0Sstevel@tonic-gate static int gen_create_minor_nodes(dev_info_t *, struct dstate *); 102*0Sstevel@tonic-gate static int gen_power(dev_info_t *, int, int); 103*0Sstevel@tonic-gate 104*0Sstevel@tonic-gate static struct cb_ops gen_cb_ops = { 105*0Sstevel@tonic-gate gen_open, /* open */ 106*0Sstevel@tonic-gate gen_close, /* close */ 107*0Sstevel@tonic-gate nodev, /* strategy */ 108*0Sstevel@tonic-gate nodev, /* print */ 109*0Sstevel@tonic-gate nodev, /* dump */ 110*0Sstevel@tonic-gate gen_read, /* read */ 111*0Sstevel@tonic-gate gen_write, /* write */ 112*0Sstevel@tonic-gate gen_ioctl, /* ioctl */ 113*0Sstevel@tonic-gate nodev, /* devmap */ 114*0Sstevel@tonic-gate nodev, /* mmap */ 115*0Sstevel@tonic-gate nodev, /* segmap */ 116*0Sstevel@tonic-gate nochpoll, /* poll */ 117*0Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 118*0Sstevel@tonic-gate NULL, /* streamtab */ 119*0Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* flag */ 120*0Sstevel@tonic-gate CB_REV, /* cb_rev */ 121*0Sstevel@tonic-gate nodev, /* aread */ 122*0Sstevel@tonic-gate nodev /* awrite */ 123*0Sstevel@tonic-gate }; 124*0Sstevel@tonic-gate 125*0Sstevel@tonic-gate 126*0Sstevel@tonic-gate static struct dev_ops gen_ops = { 127*0Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 128*0Sstevel@tonic-gate 0, /* refcnt */ 129*0Sstevel@tonic-gate gen_info, /* getinfo */ 130*0Sstevel@tonic-gate nulldev, /* identify */ 131*0Sstevel@tonic-gate nulldev, /* probe */ 132*0Sstevel@tonic-gate gen_attach, /* attach */ 133*0Sstevel@tonic-gate gen_detach, /* detach */ 134*0Sstevel@tonic-gate nodev, /* reset */ 135*0Sstevel@tonic-gate &gen_cb_ops, /* driver ops */ 136*0Sstevel@tonic-gate (struct bus_ops *)0, /* bus ops */ 137*0Sstevel@tonic-gate gen_power /* power */ 138*0Sstevel@tonic-gate }; 139*0Sstevel@tonic-gate 140*0Sstevel@tonic-gate /* 141*0Sstevel@tonic-gate * INST_TO_MINOR() gives the starting minor number for a given gen_drv driver 142*0Sstevel@tonic-gate * instance. A shift left by 6 bits allows for each instance to have upto 143*0Sstevel@tonic-gate * 64 (2^6) minor numbers. The maximum minor number allowed by the system 144*0Sstevel@tonic-gate * is L_MAXMIN32 (0x3ffff). This effectively limits the gen_drv instance 145*0Sstevel@tonic-gate * numbers from 0 to 0xfff for a total of 4096 instances. 146*0Sstevel@tonic-gate */ 147*0Sstevel@tonic-gate #define INST_TO_MINOR(i) (i << 6) 148*0Sstevel@tonic-gate #define MINOR_TO_INST(mn) (mn >> 6) 149*0Sstevel@tonic-gate 150*0Sstevel@tonic-gate static char *mnodetypes[] = { 151*0Sstevel@tonic-gate "ddi_nt", 152*0Sstevel@tonic-gate "ddi_nt:device_type", 153*0Sstevel@tonic-gate "ddi_nt:device_class:bus_class", 154*0Sstevel@tonic-gate "ddi_nt2", 155*0Sstevel@tonic-gate "ddi_nt2:device_type", 156*0Sstevel@tonic-gate "ddi_nt2:device_type:bus_class", 157*0Sstevel@tonic-gate }; 158*0Sstevel@tonic-gate #define N_NTYPES (sizeof (mnodetypes) / sizeof (char *)) 159*0Sstevel@tonic-gate 160*0Sstevel@tonic-gate static struct modldrv modldrv = { 161*0Sstevel@tonic-gate &mod_driverops, 162*0Sstevel@tonic-gate "generic test driver %I%", 163*0Sstevel@tonic-gate &gen_ops 164*0Sstevel@tonic-gate }; 165*0Sstevel@tonic-gate 166*0Sstevel@tonic-gate static struct modlinkage modlinkage = { 167*0Sstevel@tonic-gate MODREV_1, &modldrv, NULL 168*0Sstevel@tonic-gate }; 169*0Sstevel@tonic-gate 170*0Sstevel@tonic-gate 171*0Sstevel@tonic-gate /* 172*0Sstevel@tonic-gate * flags 173*0Sstevel@tonic-gate */ 174*0Sstevel@tonic-gate #define OPEN_FLAG 0x001 175*0Sstevel@tonic-gate #define PWR_HAS_CHANGED_ON_RESUME_FLAG 0x002 176*0Sstevel@tonic-gate #define FAIL_SUSPEND_FLAG 0x004 177*0Sstevel@tonic-gate #define PUP_WITH_PWR_HAS_CHANGED_FLAG 0x008 178*0Sstevel@tonic-gate #define POWER_FLAG 0x010 179*0Sstevel@tonic-gate #define LOWER_POWER_FLAG 0x020 180*0Sstevel@tonic-gate #define NO_INVOL_FLAG 0x040 181*0Sstevel@tonic-gate #define PM_SUPPORTED_FLAG 0x080 182*0Sstevel@tonic-gate 183*0Sstevel@tonic-gate /* 184*0Sstevel@tonic-gate * ioctl commands (non-devctl ioctl commands) 185*0Sstevel@tonic-gate */ 186*0Sstevel@tonic-gate #define GENDRV_IOCTL ('P' << 8) 187*0Sstevel@tonic-gate #define GENDRV_IOFAULT_SIMULATE (GENDRV_IOCTL | 0) 188*0Sstevel@tonic-gate #define GENDRV_NDI_EVENT_TEST (GENDRV_IOCTL | 1) 189*0Sstevel@tonic-gate 190*0Sstevel@tonic-gate int 191*0Sstevel@tonic-gate _init(void) 192*0Sstevel@tonic-gate { 193*0Sstevel@tonic-gate int e; 194*0Sstevel@tonic-gate 195*0Sstevel@tonic-gate if ((e = ddi_soft_state_init(&dstates, 196*0Sstevel@tonic-gate sizeof (struct dstate), 0)) != 0) { 197*0Sstevel@tonic-gate return (e); 198*0Sstevel@tonic-gate } 199*0Sstevel@tonic-gate 200*0Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0) { 201*0Sstevel@tonic-gate ddi_soft_state_fini(&dstates); 202*0Sstevel@tonic-gate } 203*0Sstevel@tonic-gate 204*0Sstevel@tonic-gate return (e); 205*0Sstevel@tonic-gate } 206*0Sstevel@tonic-gate 207*0Sstevel@tonic-gate int 208*0Sstevel@tonic-gate _fini(void) 209*0Sstevel@tonic-gate { 210*0Sstevel@tonic-gate int e; 211*0Sstevel@tonic-gate 212*0Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) != 0) { 213*0Sstevel@tonic-gate return (e); 214*0Sstevel@tonic-gate } 215*0Sstevel@tonic-gate ddi_soft_state_fini(&dstates); 216*0Sstevel@tonic-gate return (e); 217*0Sstevel@tonic-gate } 218*0Sstevel@tonic-gate 219*0Sstevel@tonic-gate int 220*0Sstevel@tonic-gate _info(struct modinfo *modinfop) 221*0Sstevel@tonic-gate { 222*0Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 223*0Sstevel@tonic-gate } 224*0Sstevel@tonic-gate 225*0Sstevel@tonic-gate static int 226*0Sstevel@tonic-gate gen_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 227*0Sstevel@tonic-gate { 228*0Sstevel@tonic-gate int instance = ddi_get_instance(devi); 229*0Sstevel@tonic-gate struct dstate *dstatep; 230*0Sstevel@tonic-gate int rval; 231*0Sstevel@tonic-gate int n_devs; 232*0Sstevel@tonic-gate int n_minorcomps; 233*0Sstevel@tonic-gate int isclone; 234*0Sstevel@tonic-gate ddi_eventcookie_t dev_offline_cookie, dev_reset_cookie; 235*0Sstevel@tonic-gate ddi_eventcookie_t bus_reset_cookie, bus_quiesce_cookie; 236*0Sstevel@tonic-gate ddi_eventcookie_t bus_unquiesce_cookie, bus_test_post_cookie; 237*0Sstevel@tonic-gate int i_init = 0; 238*0Sstevel@tonic-gate int level_tmp; 239*0Sstevel@tonic-gate 240*0Sstevel@tonic-gate int i; 241*0Sstevel@tonic-gate char *pm_comp[] = { 242*0Sstevel@tonic-gate "NAME=leaf0", 243*0Sstevel@tonic-gate "0=D0", 244*0Sstevel@tonic-gate "1=D1", 245*0Sstevel@tonic-gate "2=D2", 246*0Sstevel@tonic-gate "3=D3", 247*0Sstevel@tonic-gate "NAME=leaf1", 248*0Sstevel@tonic-gate "0=off", 249*0Sstevel@tonic-gate "1=blank", 250*0Sstevel@tonic-gate "2=on"}; 251*0Sstevel@tonic-gate char *pm_hw_state = {"needs-suspend-resume"}; 252*0Sstevel@tonic-gate 253*0Sstevel@tonic-gate 254*0Sstevel@tonic-gate switch (cmd) { 255*0Sstevel@tonic-gate case DDI_ATTACH: 256*0Sstevel@tonic-gate 257*0Sstevel@tonic-gate if (ddi_soft_state_zalloc(dstates, instance) != 258*0Sstevel@tonic-gate DDI_SUCCESS) { 259*0Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: can't allocate state\n", 260*0Sstevel@tonic-gate ddi_get_name(devi), instance); 261*0Sstevel@tonic-gate 262*0Sstevel@tonic-gate return (DDI_FAILURE); 263*0Sstevel@tonic-gate } 264*0Sstevel@tonic-gate 265*0Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, instance); 266*0Sstevel@tonic-gate dstatep->dip = devi; 267*0Sstevel@tonic-gate mutex_init(&dstatep->lock, NULL, MUTEX_DRIVER, NULL); 268*0Sstevel@tonic-gate 269*0Sstevel@tonic-gate n_devs = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, 270*0Sstevel@tonic-gate "ndevs", 1); 271*0Sstevel@tonic-gate 272*0Sstevel@tonic-gate isclone = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, 273*0Sstevel@tonic-gate "isclone", 0); 274*0Sstevel@tonic-gate 275*0Sstevel@tonic-gate n_minorcomps = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, 276*0Sstevel@tonic-gate "ncomps", 1); 277*0Sstevel@tonic-gate 278*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 279*0Sstevel@tonic-gate "%s%d attaching: n_devs=%d n_minorcomps=%d isclone=%d", 280*0Sstevel@tonic-gate ddi_get_name(devi), ddi_get_instance(devi), 281*0Sstevel@tonic-gate n_devs, n_minorcomps, isclone)); 282*0Sstevel@tonic-gate 283*0Sstevel@tonic-gate if (isclone) { 284*0Sstevel@tonic-gate if (ddi_create_minor_node(devi, "gen", S_IFCHR, 285*0Sstevel@tonic-gate INST_TO_MINOR(instance), mnodetypes[0], 286*0Sstevel@tonic-gate isclone) != DDI_SUCCESS) { 287*0Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 288*0Sstevel@tonic-gate ddi_soft_state_free(dstates, instance); 289*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: can't create minor " 290*0Sstevel@tonic-gate "node", ddi_get_name(devi), instance); 291*0Sstevel@tonic-gate 292*0Sstevel@tonic-gate return (DDI_FAILURE); 293*0Sstevel@tonic-gate } 294*0Sstevel@tonic-gate rval = DDI_SUCCESS; 295*0Sstevel@tonic-gate } else { 296*0Sstevel@tonic-gate rval = gen_create_minor_nodes(devi, dstatep); 297*0Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 298*0Sstevel@tonic-gate ddi_prop_remove_all(devi); 299*0Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 300*0Sstevel@tonic-gate ddi_soft_state_free(dstates, instance); 301*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: can't create minor " 302*0Sstevel@tonic-gate "nodes", ddi_get_name(devi), instance); 303*0Sstevel@tonic-gate 304*0Sstevel@tonic-gate return (DDI_FAILURE); 305*0Sstevel@tonic-gate } 306*0Sstevel@tonic-gate } 307*0Sstevel@tonic-gate 308*0Sstevel@tonic-gate if (ddi_get_eventcookie(devi, "pshot_dev_offline", 309*0Sstevel@tonic-gate &dev_offline_cookie) == DDI_SUCCESS) { 310*0Sstevel@tonic-gate (void) ddi_add_event_handler(devi, dev_offline_cookie, 311*0Sstevel@tonic-gate gen_event_cb, NULL, &(dstatep->gen_cb_ids[0])); 312*0Sstevel@tonic-gate } 313*0Sstevel@tonic-gate 314*0Sstevel@tonic-gate if (ddi_get_eventcookie(devi, "pshot_dev_reset", 315*0Sstevel@tonic-gate &dev_reset_cookie) == DDI_SUCCESS) { 316*0Sstevel@tonic-gate (void) ddi_add_event_handler(devi, dev_reset_cookie, 317*0Sstevel@tonic-gate gen_event_cb, NULL, &(dstatep->gen_cb_ids[1])); 318*0Sstevel@tonic-gate } 319*0Sstevel@tonic-gate 320*0Sstevel@tonic-gate if (ddi_get_eventcookie(devi, "pshot_bus_reset", 321*0Sstevel@tonic-gate &bus_reset_cookie) == DDI_SUCCESS) { 322*0Sstevel@tonic-gate (void) ddi_add_event_handler(devi, bus_reset_cookie, 323*0Sstevel@tonic-gate gen_event_cb, NULL, &(dstatep->gen_cb_ids[2])); 324*0Sstevel@tonic-gate } 325*0Sstevel@tonic-gate 326*0Sstevel@tonic-gate if (ddi_get_eventcookie(devi, "pshot_bus_quiesce", 327*0Sstevel@tonic-gate &bus_quiesce_cookie) == DDI_SUCCESS) { 328*0Sstevel@tonic-gate (void) ddi_add_event_handler(devi, bus_quiesce_cookie, 329*0Sstevel@tonic-gate gen_event_cb, NULL, &(dstatep->gen_cb_ids[3])); 330*0Sstevel@tonic-gate } 331*0Sstevel@tonic-gate 332*0Sstevel@tonic-gate if (ddi_get_eventcookie(devi, "pshot_bus_unquiesce", 333*0Sstevel@tonic-gate &bus_unquiesce_cookie) == DDI_SUCCESS) { 334*0Sstevel@tonic-gate (void) ddi_add_event_handler(devi, 335*0Sstevel@tonic-gate bus_unquiesce_cookie, gen_event_cb, 336*0Sstevel@tonic-gate NULL, &(dstatep->gen_cb_ids[4])); 337*0Sstevel@tonic-gate } 338*0Sstevel@tonic-gate 339*0Sstevel@tonic-gate if (ddi_get_eventcookie(devi, "pshot_bus_test_post", 340*0Sstevel@tonic-gate &bus_test_post_cookie) == DDI_SUCCESS) { 341*0Sstevel@tonic-gate (void) ddi_add_event_handler(devi, 342*0Sstevel@tonic-gate bus_test_post_cookie, gen_event_cb, 343*0Sstevel@tonic-gate NULL, &(dstatep->gen_cb_ids[5])); 344*0Sstevel@tonic-gate } 345*0Sstevel@tonic-gate 346*0Sstevel@tonic-gate /* 347*0Sstevel@tonic-gate * initialize the devices' pm state 348*0Sstevel@tonic-gate */ 349*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 350*0Sstevel@tonic-gate dstatep->flag &= ~OPEN_FLAG; 351*0Sstevel@tonic-gate dstatep->flag &= ~PWR_HAS_CHANGED_ON_RESUME_FLAG; 352*0Sstevel@tonic-gate dstatep->flag &= ~FAIL_SUSPEND_FLAG; 353*0Sstevel@tonic-gate dstatep->flag &= ~PUP_WITH_PWR_HAS_CHANGED_FLAG; 354*0Sstevel@tonic-gate dstatep->flag |= LOWER_POWER_FLAG; 355*0Sstevel@tonic-gate dstatep->flag &= ~NO_INVOL_FLAG; 356*0Sstevel@tonic-gate dstatep->flag |= PM_SUPPORTED_FLAG; 357*0Sstevel@tonic-gate dstatep->busy[0] = 0; 358*0Sstevel@tonic-gate dstatep->busy[1] = 0; 359*0Sstevel@tonic-gate dstatep->level[0] = -1; 360*0Sstevel@tonic-gate dstatep->level[1] = -1; 361*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 362*0Sstevel@tonic-gate 363*0Sstevel@tonic-gate /* 364*0Sstevel@tonic-gate * stash the nodename 365*0Sstevel@tonic-gate */ 366*0Sstevel@tonic-gate dstatep->nodename = ddi_node_name(devi); 367*0Sstevel@tonic-gate 368*0Sstevel@tonic-gate /* 369*0Sstevel@tonic-gate * Check if the no-involuntary-power-cycles property 370*0Sstevel@tonic-gate * was created. Set NO_INVOL_FLAG if so. 371*0Sstevel@tonic-gate */ 372*0Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip, 373*0Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 374*0Sstevel@tonic-gate "no-involuntary-power-cycles") == 1) { 375*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 376*0Sstevel@tonic-gate "%s%d: DDI_ATTACH:\n\tno-involuntary-power-cycles" 377*0Sstevel@tonic-gate " property was created", 378*0Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi))); 379*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 380*0Sstevel@tonic-gate dstatep->flag |= NO_INVOL_FLAG; 381*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 382*0Sstevel@tonic-gate } 383*0Sstevel@tonic-gate 384*0Sstevel@tonic-gate /* 385*0Sstevel@tonic-gate * Check if the dependency-property property 386*0Sstevel@tonic-gate * was created. 387*0Sstevel@tonic-gate */ 388*0Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip, 389*0Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 390*0Sstevel@tonic-gate "dependency-property") == 1) { 391*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 392*0Sstevel@tonic-gate "%s%d: DDI_ATTACH:\n\tdependency-property" 393*0Sstevel@tonic-gate " property was created", 394*0Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi))); 395*0Sstevel@tonic-gate } 396*0Sstevel@tonic-gate 397*0Sstevel@tonic-gate /* 398*0Sstevel@tonic-gate * create the pm-components property. two comps: 399*0Sstevel@tonic-gate * 4 levels on comp0, 3 on comp 1. 400*0Sstevel@tonic-gate * - skip for a "tape" device, clear PM_SUPPORTED_FLAG 401*0Sstevel@tonic-gate */ 402*0Sstevel@tonic-gate if (strcmp(ddi_node_name(devi), "tape") != 0) { 403*0Sstevel@tonic-gate if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi, 404*0Sstevel@tonic-gate "pm-components", pm_comp, 9) != DDI_PROP_SUCCESS) { 405*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: %s\n", 406*0Sstevel@tonic-gate ddi_node_name(devi), 407*0Sstevel@tonic-gate ddi_get_instance(devi), 408*0Sstevel@tonic-gate "unable to create \"pm-components\" " 409*0Sstevel@tonic-gate " property."); 410*0Sstevel@tonic-gate 411*0Sstevel@tonic-gate return (DDI_FAILURE); 412*0Sstevel@tonic-gate } 413*0Sstevel@tonic-gate } else { 414*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 415*0Sstevel@tonic-gate dstatep->flag &= ~PM_SUPPORTED_FLAG; 416*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 417*0Sstevel@tonic-gate } 418*0Sstevel@tonic-gate 419*0Sstevel@tonic-gate /* 420*0Sstevel@tonic-gate * Check if the pm-components property was created 421*0Sstevel@tonic-gate */ 422*0Sstevel@tonic-gate if (dstatep->flag & PM_SUPPORTED_FLAG) { 423*0Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip, 424*0Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 425*0Sstevel@tonic-gate "pm-components") != 1) { 426*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t%s", 427*0Sstevel@tonic-gate ddi_node_name(devi), 428*0Sstevel@tonic-gate ddi_get_instance(devi), 429*0Sstevel@tonic-gate "\"pm-components\" property does" 430*0Sstevel@tonic-gate " not exist"); 431*0Sstevel@tonic-gate 432*0Sstevel@tonic-gate return (DDI_FAILURE); 433*0Sstevel@tonic-gate 434*0Sstevel@tonic-gate } else { 435*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_ATTACH:" 436*0Sstevel@tonic-gate " created pm-components property", 437*0Sstevel@tonic-gate ddi_node_name(devi), 438*0Sstevel@tonic-gate ddi_get_instance(devi))); 439*0Sstevel@tonic-gate } 440*0Sstevel@tonic-gate } 441*0Sstevel@tonic-gate 442*0Sstevel@tonic-gate /* 443*0Sstevel@tonic-gate * create the pm-hardware-state property. 444*0Sstevel@tonic-gate * needed to get DDI_SUSPEND and DDI_RESUME calls 445*0Sstevel@tonic-gate */ 446*0Sstevel@tonic-gate if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, 447*0Sstevel@tonic-gate "pm-hardware-state", pm_hw_state) != DDI_PROP_SUCCESS) { 448*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t%s\n", 449*0Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi), 450*0Sstevel@tonic-gate "unable to create \"pm-hardware-state\" " 451*0Sstevel@tonic-gate " property."); 452*0Sstevel@tonic-gate 453*0Sstevel@tonic-gate return (DDI_FAILURE); 454*0Sstevel@tonic-gate } 455*0Sstevel@tonic-gate 456*0Sstevel@tonic-gate /* 457*0Sstevel@tonic-gate * set power levels to max via pm_raise_power(), 458*0Sstevel@tonic-gate */ 459*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 460*0Sstevel@tonic-gate i_init = (dstatep->flag & PM_SUPPORTED_FLAG) ? 0 : COMPONENTS; 461*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 462*0Sstevel@tonic-gate for (i = i_init; i < COMPONENTS; i++) { 463*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 464*0Sstevel@tonic-gate "%s%d: DDI_ATTACH: pm_raise_power comp %d " 465*0Sstevel@tonic-gate "to level %d", ddi_node_name(devi), 466*0Sstevel@tonic-gate ddi_get_instance(devi), i, maxpwr[i])); 467*0Sstevel@tonic-gate if (pm_raise_power(dstatep->dip, i, maxpwr[i]) != 468*0Sstevel@tonic-gate DDI_SUCCESS) { 469*0Sstevel@tonic-gate cmn_err(CE_WARN, 470*0Sstevel@tonic-gate "%s%d: DDI_ATTACH: pm_raise_power failed\n", 471*0Sstevel@tonic-gate ddi_node_name(devi), 472*0Sstevel@tonic-gate ddi_get_instance(devi)); 473*0Sstevel@tonic-gate dstatep->level[i] = -1; 474*0Sstevel@tonic-gate 475*0Sstevel@tonic-gate return (DDI_FAILURE); 476*0Sstevel@tonic-gate } 477*0Sstevel@tonic-gate } 478*0Sstevel@tonic-gate 479*0Sstevel@tonic-gate if (rval == DDI_SUCCESS) { 480*0Sstevel@tonic-gate ddi_report_dev(devi); 481*0Sstevel@tonic-gate } 482*0Sstevel@tonic-gate return (rval); 483*0Sstevel@tonic-gate 484*0Sstevel@tonic-gate 485*0Sstevel@tonic-gate case DDI_RESUME: 486*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_RESUME", ddi_node_name(devi), 487*0Sstevel@tonic-gate ddi_get_instance(devi))); 488*0Sstevel@tonic-gate 489*0Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, ddi_get_instance(devi)); 490*0Sstevel@tonic-gate if (dstatep == NULL) { 491*0Sstevel@tonic-gate 492*0Sstevel@tonic-gate return (DDI_FAILURE); 493*0Sstevel@tonic-gate } 494*0Sstevel@tonic-gate 495*0Sstevel@tonic-gate /* 496*0Sstevel@tonic-gate * Call pm_power_has_changed() if flag 497*0Sstevel@tonic-gate * PWR_HAS_CHANGED_ON_RESUME_FLAG is set, 498*0Sstevel@tonic-gate * then clear the flag 499*0Sstevel@tonic-gate */ 500*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 501*0Sstevel@tonic-gate i_init = (dstatep->flag & PM_SUPPORTED_FLAG) ? 0 : COMPONENTS; 502*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 503*0Sstevel@tonic-gate if (dstatep->flag & PWR_HAS_CHANGED_ON_RESUME_FLAG) { 504*0Sstevel@tonic-gate for (i = i_init; i < COMPONENTS; i++) { 505*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 506*0Sstevel@tonic-gate "%s%d: DDI_RESUME: pm_power_has_changed " 507*0Sstevel@tonic-gate "comp %d to level %d", ddi_node_name(devi), 508*0Sstevel@tonic-gate ddi_get_instance(devi), i, maxpwr[i])); 509*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 510*0Sstevel@tonic-gate level_tmp = dstatep->level[i]; 511*0Sstevel@tonic-gate dstatep->level[i] = maxpwr[i]; 512*0Sstevel@tonic-gate if (pm_power_has_changed(dstatep->dip, i, 513*0Sstevel@tonic-gate maxpwr[i]) != DDI_SUCCESS) { 514*0Sstevel@tonic-gate cmn_err(CE_WARN, 515*0Sstevel@tonic-gate "%s%d: DDI_RESUME:\n\t" 516*0Sstevel@tonic-gate " pm_power_has_changed" 517*0Sstevel@tonic-gate " failed: comp %d to level %d\n", 518*0Sstevel@tonic-gate ddi_node_name(devi), 519*0Sstevel@tonic-gate ddi_get_instance(devi), 520*0Sstevel@tonic-gate i, maxpwr[i]); 521*0Sstevel@tonic-gate dstatep->level[i] = level_tmp; 522*0Sstevel@tonic-gate } 523*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 524*0Sstevel@tonic-gate } 525*0Sstevel@tonic-gate } else { 526*0Sstevel@tonic-gate /* 527*0Sstevel@tonic-gate * Call pm_raise_power() instead 528*0Sstevel@tonic-gate */ 529*0Sstevel@tonic-gate for (i = i_init; i < COMPONENTS; i++) { 530*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 531*0Sstevel@tonic-gate "%s%d: DDI_RESUME: pm_raise_power" 532*0Sstevel@tonic-gate " comp %d to level %d", 533*0Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi), 534*0Sstevel@tonic-gate i, maxpwr[i])); 535*0Sstevel@tonic-gate if (pm_raise_power(dstatep->dip, i, maxpwr[i]) 536*0Sstevel@tonic-gate != DDI_SUCCESS) { 537*0Sstevel@tonic-gate cmn_err(CE_WARN, 538*0Sstevel@tonic-gate "%s%d: DDI_RESUME:" 539*0Sstevel@tonic-gate "\n\tpm_raise_power" 540*0Sstevel@tonic-gate "failed: comp %d to level %d\n", 541*0Sstevel@tonic-gate ddi_node_name(devi), 542*0Sstevel@tonic-gate ddi_get_instance(devi), 543*0Sstevel@tonic-gate i, maxpwr[i]); 544*0Sstevel@tonic-gate } 545*0Sstevel@tonic-gate } 546*0Sstevel@tonic-gate } 547*0Sstevel@tonic-gate 548*0Sstevel@tonic-gate return (DDI_SUCCESS); 549*0Sstevel@tonic-gate 550*0Sstevel@tonic-gate default: 551*0Sstevel@tonic-gate GEN_DEBUG((CE_WARN, "attach: default")); 552*0Sstevel@tonic-gate return (DDI_FAILURE); 553*0Sstevel@tonic-gate } 554*0Sstevel@tonic-gate } 555*0Sstevel@tonic-gate 556*0Sstevel@tonic-gate static int 557*0Sstevel@tonic-gate gen_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 558*0Sstevel@tonic-gate { 559*0Sstevel@tonic-gate struct dstate *dstatep; 560*0Sstevel@tonic-gate int instance; 561*0Sstevel@tonic-gate int i; 562*0Sstevel@tonic-gate int rv; 563*0Sstevel@tonic-gate int rm_power; 564*0Sstevel@tonic-gate int level_tmp; 565*0Sstevel@tonic-gate 566*0Sstevel@tonic-gate #ifdef DEBUG 567*0Sstevel@tonic-gate int n_devs; 568*0Sstevel@tonic-gate int n_minorcomps; 569*0Sstevel@tonic-gate int isclone; 570*0Sstevel@tonic-gate #endif 571*0Sstevel@tonic-gate 572*0Sstevel@tonic-gate switch (cmd) { 573*0Sstevel@tonic-gate case DDI_DETACH: 574*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_DETACH", ddi_node_name(devi), 575*0Sstevel@tonic-gate ddi_get_instance(devi))); 576*0Sstevel@tonic-gate 577*0Sstevel@tonic-gate instance = ddi_get_instance(devi); 578*0Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, instance); 579*0Sstevel@tonic-gate if (dstatep == NULL) { 580*0Sstevel@tonic-gate 581*0Sstevel@tonic-gate return (DDI_FAILURE); 582*0Sstevel@tonic-gate } 583*0Sstevel@tonic-gate 584*0Sstevel@tonic-gate #ifdef DEBUG 585*0Sstevel@tonic-gate n_devs = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, 586*0Sstevel@tonic-gate "ndevs", 1); 587*0Sstevel@tonic-gate 588*0Sstevel@tonic-gate isclone = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, 589*0Sstevel@tonic-gate "isclone", 0); 590*0Sstevel@tonic-gate 591*0Sstevel@tonic-gate n_minorcomps = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, 592*0Sstevel@tonic-gate "ncomps", 1); 593*0Sstevel@tonic-gate #endif /* DEBUG */ 594*0Sstevel@tonic-gate 595*0Sstevel@tonic-gate /* 596*0Sstevel@tonic-gate * power off component 1. 597*0Sstevel@tonic-gate */ 598*0Sstevel@tonic-gate if (dstatep->flag & PM_SUPPORTED_FLAG) { 599*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 600*0Sstevel@tonic-gate "%s%d: DDI_DETACH: pm_lower_power comp 1 level %d", 601*0Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi), 602*0Sstevel@tonic-gate MINPWR)); 603*0Sstevel@tonic-gate if (pm_lower_power(dstatep->dip, 1, MINPWR) 604*0Sstevel@tonic-gate != DDI_SUCCESS) { 605*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_DETACH:\n\t" 606*0Sstevel@tonic-gate "pm_lower_power failed for comp 1 to" 607*0Sstevel@tonic-gate " level %d\n", ddi_node_name(devi), 608*0Sstevel@tonic-gate ddi_get_instance(devi), MINPWR); 609*0Sstevel@tonic-gate 610*0Sstevel@tonic-gate return (DDI_FAILURE); 611*0Sstevel@tonic-gate } 612*0Sstevel@tonic-gate 613*0Sstevel@tonic-gate /* 614*0Sstevel@tonic-gate * check power level. Issue pm_power_has_changed 615*0Sstevel@tonic-gate * if not at MINPWR. 616*0Sstevel@tonic-gate */ 617*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 618*0Sstevel@tonic-gate level_tmp = dstatep->level[1]; 619*0Sstevel@tonic-gate dstatep->level[1] = MINPWR; 620*0Sstevel@tonic-gate if (dstatep->level[1] != MINPWR) { 621*0Sstevel@tonic-gate GEN_DEBUG((CE_NOTE, "%s%d: DDI_DETACH:" 622*0Sstevel@tonic-gate " power off via pm_power_has_changed" 623*0Sstevel@tonic-gate " instead", ddi_node_name(devi), 624*0Sstevel@tonic-gate ddi_get_instance(devi))); 625*0Sstevel@tonic-gate if (pm_power_has_changed(dstatep->dip, 626*0Sstevel@tonic-gate 1, MINPWR) != DDI_SUCCESS) { 627*0Sstevel@tonic-gate GEN_DEBUG((CE_NOTE, "%s%d: DDI_DETACH:" 628*0Sstevel@tonic-gate " pm_power_has_changed failed for" 629*0Sstevel@tonic-gate " comp 1 to level %d", 630*0Sstevel@tonic-gate ddi_node_name(devi), 631*0Sstevel@tonic-gate ddi_get_instance(devi), 632*0Sstevel@tonic-gate MINPWR)); 633*0Sstevel@tonic-gate dstatep->level[1] = level_tmp; 634*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 635*0Sstevel@tonic-gate 636*0Sstevel@tonic-gate return (DDI_FAILURE); 637*0Sstevel@tonic-gate } 638*0Sstevel@tonic-gate } 639*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 640*0Sstevel@tonic-gate } 641*0Sstevel@tonic-gate 642*0Sstevel@tonic-gate /* 643*0Sstevel@tonic-gate * If the LOWER_POWER_FLAG flag is not set, 644*0Sstevel@tonic-gate * don't call pm_lowr_power() for comp 0. 645*0Sstevel@tonic-gate * This should be used only for the XXXXX@XX,no_invol 646*0Sstevel@tonic-gate * devices that export the 647*0Sstevel@tonic-gate * no-involuntary-power-cycles property 648*0Sstevel@tonic-gate */ 649*0Sstevel@tonic-gate if (!(dstatep->flag & LOWER_POWER_FLAG) && 650*0Sstevel@tonic-gate dstatep->flag & PM_SUPPORTED_FLAG) { 651*0Sstevel@tonic-gate cmn_err(CE_NOTE, "%s%d: DDI_DETACH:\n\t" 652*0Sstevel@tonic-gate " NOT CALLING PM_LOWER_POWER():" 653*0Sstevel@tonic-gate " LOWER_POWER_FLAG NOT SET\n", 654*0Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi)); 655*0Sstevel@tonic-gate } else if (dstatep->flag & PM_SUPPORTED_FLAG) { 656*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 657*0Sstevel@tonic-gate "%s%d: DDI_DETACH: pm_lower_power comp 0 level %d", 658*0Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi), 659*0Sstevel@tonic-gate MINPWR)); 660*0Sstevel@tonic-gate if (pm_lower_power(dstatep->dip, 0, MINPWR) 661*0Sstevel@tonic-gate != DDI_SUCCESS) { 662*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_DETACH:\n\t" 663*0Sstevel@tonic-gate "pm_lower_power failed for comp 0 to" 664*0Sstevel@tonic-gate " level %d\n", ddi_node_name(devi), 665*0Sstevel@tonic-gate ddi_get_instance(devi), MINPWR); 666*0Sstevel@tonic-gate 667*0Sstevel@tonic-gate return (DDI_FAILURE); 668*0Sstevel@tonic-gate } 669*0Sstevel@tonic-gate 670*0Sstevel@tonic-gate /* 671*0Sstevel@tonic-gate * check power level. Issue pm_power_has_changed 672*0Sstevel@tonic-gate * if not at MINPWR. 673*0Sstevel@tonic-gate */ 674*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 675*0Sstevel@tonic-gate level_tmp = dstatep->level[0]; 676*0Sstevel@tonic-gate dstatep->level[0] = MINPWR; 677*0Sstevel@tonic-gate if (dstatep->level[0] != MINPWR) { 678*0Sstevel@tonic-gate GEN_DEBUG((CE_NOTE, "%s%d: DDI_DETACH:" 679*0Sstevel@tonic-gate " power off via pm_power_has_changed" 680*0Sstevel@tonic-gate " instead", ddi_node_name(devi), 681*0Sstevel@tonic-gate ddi_get_instance(devi))); 682*0Sstevel@tonic-gate if (pm_power_has_changed(dstatep->dip, 683*0Sstevel@tonic-gate 0, MINPWR) != DDI_SUCCESS) { 684*0Sstevel@tonic-gate GEN_DEBUG((CE_NOTE, "%s%d: DDI_DETACH:" 685*0Sstevel@tonic-gate " pm_power_has_changed failed for" 686*0Sstevel@tonic-gate " comp 0 to level %d", 687*0Sstevel@tonic-gate ddi_node_name(devi), 688*0Sstevel@tonic-gate ddi_get_instance(devi), 689*0Sstevel@tonic-gate MINPWR)); 690*0Sstevel@tonic-gate dstatep->level[0] = level_tmp; 691*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 692*0Sstevel@tonic-gate 693*0Sstevel@tonic-gate return (DDI_FAILURE); 694*0Sstevel@tonic-gate } 695*0Sstevel@tonic-gate } 696*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 697*0Sstevel@tonic-gate } 698*0Sstevel@tonic-gate 699*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 700*0Sstevel@tonic-gate "%s%d detaching: n_devs=%d n_minorcomps=%d isclone=%d", 701*0Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi), 702*0Sstevel@tonic-gate n_devs, n_minorcomps, isclone)); 703*0Sstevel@tonic-gate 704*0Sstevel@tonic-gate for (i = 0; i < NUMEVENTS; i++) { 705*0Sstevel@tonic-gate if (dstatep->gen_cb_ids[i]) { 706*0Sstevel@tonic-gate (void) ddi_remove_event_handler(dstatep->gen_cb_ids[i]); 707*0Sstevel@tonic-gate dstatep->gen_cb_ids[i] = NULL; 708*0Sstevel@tonic-gate } 709*0Sstevel@tonic-gate } 710*0Sstevel@tonic-gate 711*0Sstevel@tonic-gate ddi_prop_remove_all(devi); 712*0Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 713*0Sstevel@tonic-gate if (dstatep->node_type) 714*0Sstevel@tonic-gate kmem_free(dstatep->node_type, 715*0Sstevel@tonic-gate strlen(dstatep->node_type) + 1); 716*0Sstevel@tonic-gate ddi_soft_state_free(dstates, instance); 717*0Sstevel@tonic-gate return (DDI_SUCCESS); 718*0Sstevel@tonic-gate 719*0Sstevel@tonic-gate case DDI_SUSPEND: 720*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND", 721*0Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi))); 722*0Sstevel@tonic-gate 723*0Sstevel@tonic-gate instance = ddi_get_instance(devi); 724*0Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, instance); 725*0Sstevel@tonic-gate if (dstatep == NULL) { 726*0Sstevel@tonic-gate 727*0Sstevel@tonic-gate return (DDI_FAILURE); 728*0Sstevel@tonic-gate } 729*0Sstevel@tonic-gate 730*0Sstevel@tonic-gate /* 731*0Sstevel@tonic-gate * fail the suspend if FAIL_SUSPEND_FLAG is set. 732*0Sstevel@tonic-gate * clear the FAIL_SUSPEND_FLAG flag 733*0Sstevel@tonic-gate */ 734*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 735*0Sstevel@tonic-gate if (dstatep->flag & FAIL_SUSPEND_FLAG) { 736*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND:" 737*0Sstevel@tonic-gate " FAIL_SUSPEND_FLAG is set," 738*0Sstevel@tonic-gate " fail suspend", 739*0Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi))); 740*0Sstevel@tonic-gate dstatep->flag &= ~FAIL_SUSPEND_FLAG; 741*0Sstevel@tonic-gate rv = DDI_FAILURE; 742*0Sstevel@tonic-gate } else { 743*0Sstevel@tonic-gate rv = DDI_SUCCESS; 744*0Sstevel@tonic-gate } 745*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 746*0Sstevel@tonic-gate 747*0Sstevel@tonic-gate /* 748*0Sstevel@tonic-gate * Issue ddi_removing_power() to determine if the suspend 749*0Sstevel@tonic-gate * was initiated by either CPR or DR. If CPR, the system 750*0Sstevel@tonic-gate * will be powered OFF; if this driver has set the 751*0Sstevel@tonic-gate * NO_INVOL_FLAG, then refuse to suspend. If DR, power 752*0Sstevel@tonic-gate * will not be removed, thus allow the suspend. 753*0Sstevel@tonic-gate */ 754*0Sstevel@tonic-gate if (dstatep->flag & NO_INVOL_FLAG && 755*0Sstevel@tonic-gate dstatep->flag & PM_SUPPORTED_FLAG) { 756*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND:" 757*0Sstevel@tonic-gate " check via ddi_removing_power()", 758*0Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi))); 759*0Sstevel@tonic-gate 760*0Sstevel@tonic-gate rm_power = ddi_removing_power(dstatep->dip); 761*0Sstevel@tonic-gate 762*0Sstevel@tonic-gate if (rm_power < 0) { 763*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_SUSPEND:" 764*0Sstevel@tonic-gate " ddi_removing_power() failed\n", 765*0Sstevel@tonic-gate ddi_node_name(devi), 766*0Sstevel@tonic-gate ddi_get_instance(devi)); 767*0Sstevel@tonic-gate } else if (rm_power == 1) { 768*0Sstevel@tonic-gate /* 769*0Sstevel@tonic-gate * CPR: power will be removed 770*0Sstevel@tonic-gate */ 771*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND:\n\t" 772*0Sstevel@tonic-gate " CPR: POWER WILL BE REMOVED, THEREFORE" 773*0Sstevel@tonic-gate " REFUSE TO SUSPEND", ddi_node_name(devi), 774*0Sstevel@tonic-gate ddi_get_instance(devi))); 775*0Sstevel@tonic-gate rv = DDI_FAILURE; 776*0Sstevel@tonic-gate } else if (rm_power == 0) { 777*0Sstevel@tonic-gate /* 778*0Sstevel@tonic-gate * DR: power will not be removed 779*0Sstevel@tonic-gate */ 780*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND:\n\t" 781*0Sstevel@tonic-gate " DR: POWER WILL NOT BE REMOVED, THEREFORE" 782*0Sstevel@tonic-gate " ALLOW THE SUSPEND", ddi_node_name(devi), 783*0Sstevel@tonic-gate ddi_get_instance(devi))); 784*0Sstevel@tonic-gate rv = DDI_SUCCESS; 785*0Sstevel@tonic-gate } 786*0Sstevel@tonic-gate } 787*0Sstevel@tonic-gate 788*0Sstevel@tonic-gate /* 789*0Sstevel@tonic-gate * power OFF via pm_power_has_changed() 790*0Sstevel@tonic-gate */ 791*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 792*0Sstevel@tonic-gate if (dstatep->flag & PM_SUPPORTED_FLAG && 793*0Sstevel@tonic-gate !(dstatep->flag & NO_INVOL_FLAG)) { 794*0Sstevel@tonic-gate level_tmp = dstatep->level[0]; 795*0Sstevel@tonic-gate dstatep->level[0] = MINPWR; 796*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 797*0Sstevel@tonic-gate "%s%d: DDI_SUSPEND: pm_power_has_changed comp 0" 798*0Sstevel@tonic-gate " level %d", ddi_node_name(devi), 799*0Sstevel@tonic-gate ddi_get_instance(devi), MINPWR)); 800*0Sstevel@tonic-gate if (pm_power_has_changed(dstatep->dip, 0, MINPWR) 801*0Sstevel@tonic-gate != DDI_SUCCESS) { 802*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_SUSPEND:\n\t" 803*0Sstevel@tonic-gate "pm_power_has_changed failed for comp 0 to" 804*0Sstevel@tonic-gate " level %d\n", ddi_node_name(devi), 805*0Sstevel@tonic-gate ddi_get_instance(devi), MINPWR); 806*0Sstevel@tonic-gate dstatep->level[0] = level_tmp; 807*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 808*0Sstevel@tonic-gate 809*0Sstevel@tonic-gate return (DDI_FAILURE); 810*0Sstevel@tonic-gate } 811*0Sstevel@tonic-gate } 812*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 813*0Sstevel@tonic-gate 814*0Sstevel@tonic-gate return (rv); 815*0Sstevel@tonic-gate 816*0Sstevel@tonic-gate default: 817*0Sstevel@tonic-gate 818*0Sstevel@tonic-gate return (DDI_FAILURE); 819*0Sstevel@tonic-gate } 820*0Sstevel@tonic-gate } 821*0Sstevel@tonic-gate 822*0Sstevel@tonic-gate /* ARGSUSED */ 823*0Sstevel@tonic-gate static int 824*0Sstevel@tonic-gate gen_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 825*0Sstevel@tonic-gate { 826*0Sstevel@tonic-gate dev_t dev; 827*0Sstevel@tonic-gate int instance; 828*0Sstevel@tonic-gate 829*0Sstevel@tonic-gate if (infocmd != DDI_INFO_DEVT2INSTANCE) 830*0Sstevel@tonic-gate return (DDI_FAILURE); 831*0Sstevel@tonic-gate 832*0Sstevel@tonic-gate dev = (dev_t)arg; 833*0Sstevel@tonic-gate instance = MINOR_TO_INST(getminor(dev)); 834*0Sstevel@tonic-gate *result = (void *)(uintptr_t)instance; 835*0Sstevel@tonic-gate return (DDI_SUCCESS); 836*0Sstevel@tonic-gate } 837*0Sstevel@tonic-gate 838*0Sstevel@tonic-gate 839*0Sstevel@tonic-gate /*ARGSUSED*/ 840*0Sstevel@tonic-gate static int 841*0Sstevel@tonic-gate gen_open(dev_t *devp, int flag, int otyp, cred_t *cred) 842*0Sstevel@tonic-gate { 843*0Sstevel@tonic-gate minor_t minor; 844*0Sstevel@tonic-gate struct dstate *dstatep; 845*0Sstevel@tonic-gate 846*0Sstevel@tonic-gate if (otyp != OTYP_BLK && otyp != OTYP_CHR) 847*0Sstevel@tonic-gate return (EINVAL); 848*0Sstevel@tonic-gate 849*0Sstevel@tonic-gate minor = getminor(*devp); 850*0Sstevel@tonic-gate if ((dstatep = ddi_get_soft_state(dstates, 851*0Sstevel@tonic-gate MINOR_TO_INST(minor))) == NULL) 852*0Sstevel@tonic-gate return (ENXIO); 853*0Sstevel@tonic-gate 854*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 855*0Sstevel@tonic-gate dstatep->flag |= OPEN_FLAG; 856*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 857*0Sstevel@tonic-gate 858*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 859*0Sstevel@tonic-gate "%s%d open", 860*0Sstevel@tonic-gate dstatep->nodename, MINOR_TO_INST(minor))); 861*0Sstevel@tonic-gate 862*0Sstevel@tonic-gate return (0); 863*0Sstevel@tonic-gate } 864*0Sstevel@tonic-gate 865*0Sstevel@tonic-gate /*ARGSUSED*/ 866*0Sstevel@tonic-gate static int 867*0Sstevel@tonic-gate gen_close(dev_t dev, int flag, int otyp, cred_t *cred) 868*0Sstevel@tonic-gate { 869*0Sstevel@tonic-gate struct dstate *dstatep; 870*0Sstevel@tonic-gate minor_t minor = getminor(dev); 871*0Sstevel@tonic-gate 872*0Sstevel@tonic-gate if (otyp != OTYP_BLK && otyp != OTYP_CHR) 873*0Sstevel@tonic-gate return (EINVAL); 874*0Sstevel@tonic-gate 875*0Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, MINOR_TO_INST(minor)); 876*0Sstevel@tonic-gate 877*0Sstevel@tonic-gate if (dstatep == NULL) 878*0Sstevel@tonic-gate return (ENXIO); 879*0Sstevel@tonic-gate 880*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 881*0Sstevel@tonic-gate dstatep->flag &= ~OPEN_FLAG; 882*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 883*0Sstevel@tonic-gate 884*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 885*0Sstevel@tonic-gate "%s%d close", 886*0Sstevel@tonic-gate dstatep->nodename, MINOR_TO_INST(minor))); 887*0Sstevel@tonic-gate 888*0Sstevel@tonic-gate return (0); 889*0Sstevel@tonic-gate } 890*0Sstevel@tonic-gate 891*0Sstevel@tonic-gate /*ARGSUSED*/ 892*0Sstevel@tonic-gate static int 893*0Sstevel@tonic-gate gen_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 894*0Sstevel@tonic-gate { 895*0Sstevel@tonic-gate struct dstate *dstatep; 896*0Sstevel@tonic-gate ddi_eventcookie_t cookie; 897*0Sstevel@tonic-gate int instance; 898*0Sstevel@tonic-gate int rval = 0; 899*0Sstevel@tonic-gate char *nodename; 900*0Sstevel@tonic-gate int i; 901*0Sstevel@tonic-gate struct devctl_iocdata *dcp; 902*0Sstevel@tonic-gate uint_t state; 903*0Sstevel@tonic-gate int ret; 904*0Sstevel@tonic-gate int level_tmp; 905*0Sstevel@tonic-gate 906*0Sstevel@tonic-gate instance = MINOR_TO_INST(getminor(dev)); 907*0Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, instance); 908*0Sstevel@tonic-gate nodename = dstatep->nodename; 909*0Sstevel@tonic-gate 910*0Sstevel@tonic-gate if (dstatep == NULL) 911*0Sstevel@tonic-gate return (ENXIO); 912*0Sstevel@tonic-gate 913*0Sstevel@tonic-gate /* 914*0Sstevel@tonic-gate * read devctl ioctl data 915*0Sstevel@tonic-gate */ 916*0Sstevel@tonic-gate if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 917*0Sstevel@tonic-gate return (EFAULT); 918*0Sstevel@tonic-gate 919*0Sstevel@tonic-gate switch (cmd) { 920*0Sstevel@tonic-gate case GENDRV_IOFAULT_SIMULATE: 921*0Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, DDI_DEVI_FAULT_EVENT, 922*0Sstevel@tonic-gate &(cookie)) != NDI_SUCCESS) 923*0Sstevel@tonic-gate return (DDI_FAILURE); 924*0Sstevel@tonic-gate 925*0Sstevel@tonic-gate return (ndi_post_event(dstatep->dip, dstatep->dip, cookie, 926*0Sstevel@tonic-gate NULL)); 927*0Sstevel@tonic-gate 928*0Sstevel@tonic-gate case GENDRV_NDI_EVENT_TEST: 929*0Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, "pshot_dev_offline", 930*0Sstevel@tonic-gate &cookie) == NDI_SUCCESS) { 931*0Sstevel@tonic-gate (void) ndi_post_event(dstatep->dip, dstatep->dip, 932*0Sstevel@tonic-gate cookie, NULL); 933*0Sstevel@tonic-gate } 934*0Sstevel@tonic-gate 935*0Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, "pshot_dev_reset", 936*0Sstevel@tonic-gate &cookie) == NDI_SUCCESS) { 937*0Sstevel@tonic-gate (void) ndi_post_event(dstatep->dip, dstatep->dip, 938*0Sstevel@tonic-gate cookie, NULL); 939*0Sstevel@tonic-gate } 940*0Sstevel@tonic-gate 941*0Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_reset", 942*0Sstevel@tonic-gate &cookie) == NDI_SUCCESS) { 943*0Sstevel@tonic-gate (void) ndi_post_event(dstatep->dip, dstatep->dip, 944*0Sstevel@tonic-gate cookie, NULL); 945*0Sstevel@tonic-gate } 946*0Sstevel@tonic-gate 947*0Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_quiesce", 948*0Sstevel@tonic-gate &cookie) == NDI_SUCCESS) { 949*0Sstevel@tonic-gate (void) ndi_post_event(dstatep->dip, dstatep->dip, 950*0Sstevel@tonic-gate cookie, NULL); 951*0Sstevel@tonic-gate } 952*0Sstevel@tonic-gate 953*0Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_unquiesce", 954*0Sstevel@tonic-gate &cookie) == NDI_SUCCESS) { 955*0Sstevel@tonic-gate (void) ndi_post_event(dstatep->dip, dstatep->dip, 956*0Sstevel@tonic-gate cookie, NULL); 957*0Sstevel@tonic-gate } 958*0Sstevel@tonic-gate 959*0Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_test_post", 960*0Sstevel@tonic-gate &cookie) == NDI_SUCCESS) { 961*0Sstevel@tonic-gate (void) ndi_post_event(dstatep->dip, dstatep->dip, 962*0Sstevel@tonic-gate cookie, NULL); 963*0Sstevel@tonic-gate } 964*0Sstevel@tonic-gate 965*0Sstevel@tonic-gate break; 966*0Sstevel@tonic-gate 967*0Sstevel@tonic-gate case DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME: 968*0Sstevel@tonic-gate /* 969*0Sstevel@tonic-gate * Issue pm_power_has_changed() call on DDI_RESUME 970*0Sstevel@tonic-gate */ 971*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 972*0Sstevel@tonic-gate dstatep->flag |= PWR_HAS_CHANGED_ON_RESUME_FLAG; 973*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 974*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d:" 975*0Sstevel@tonic-gate " DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME", nodename, 976*0Sstevel@tonic-gate instance)); 977*0Sstevel@tonic-gate 978*0Sstevel@tonic-gate break; 979*0Sstevel@tonic-gate 980*0Sstevel@tonic-gate case DEVCTL_PM_FAIL_SUSPEND: 981*0Sstevel@tonic-gate /* 982*0Sstevel@tonic-gate * Fail the suspend attempt in DDI_SUSPEND 983*0Sstevel@tonic-gate */ 984*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 985*0Sstevel@tonic-gate dstatep->flag |= FAIL_SUSPEND_FLAG; 986*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 987*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_FAIL_SUSPEND", 988*0Sstevel@tonic-gate nodename, instance)); 989*0Sstevel@tonic-gate 990*0Sstevel@tonic-gate break; 991*0Sstevel@tonic-gate 992*0Sstevel@tonic-gate case DEVCTL_PM_PUP_WITH_PWR_HAS_CHANGED: 993*0Sstevel@tonic-gate /* 994*0Sstevel@tonic-gate * Use pm_power_has_changed() to power up comp 0 when 995*0Sstevel@tonic-gate * enforcing the comp 0 vs comp-not 0 dependency: 996*0Sstevel@tonic-gate * Power up comp 0 first, if request for comp-not-0 997*0Sstevel@tonic-gate * comes in. 998*0Sstevel@tonic-gate * Else, default to pm_raise_power(). 999*0Sstevel@tonic-gate */ 1000*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 1001*0Sstevel@tonic-gate dstatep->flag |= PUP_WITH_PWR_HAS_CHANGED_FLAG; 1002*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 1003*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_PUP_WITH_PWR_HAS_CHANGED", 1004*0Sstevel@tonic-gate nodename, instance)); 1005*0Sstevel@tonic-gate 1006*0Sstevel@tonic-gate break; 1007*0Sstevel@tonic-gate 1008*0Sstevel@tonic-gate case DEVCTL_PM_BUSY_COMP: 1009*0Sstevel@tonic-gate /* 1010*0Sstevel@tonic-gate * mark component 0 busy via a pm_busy_component() call. 1011*0Sstevel@tonic-gate * update the busy[] array. 1012*0Sstevel@tonic-gate */ 1013*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 1014*0Sstevel@tonic-gate ++dstatep->busy[0]; 1015*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_BUSY_COMP: comp 0:" 1016*0Sstevel@tonic-gate " busy=%d", nodename, instance, dstatep->busy[0])); 1017*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 1018*0Sstevel@tonic-gate ret = pm_busy_component(dstatep->dip, 0); 1019*0Sstevel@tonic-gate ASSERT(ret == DDI_SUCCESS); 1020*0Sstevel@tonic-gate 1021*0Sstevel@tonic-gate break; 1022*0Sstevel@tonic-gate 1023*0Sstevel@tonic-gate case DEVCTL_PM_BUSY_COMP_TEST: 1024*0Sstevel@tonic-gate /* 1025*0Sstevel@tonic-gate * test busy state on component 0 1026*0Sstevel@tonic-gate */ 1027*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 1028*0Sstevel@tonic-gate state = dstatep->busy[0]; 1029*0Sstevel@tonic-gate if (copyout(&state, dcp->cpyout_buf, 1030*0Sstevel@tonic-gate sizeof (uint_t)) != 0) { 1031*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d:" 1032*0Sstevel@tonic-gate " DEVCTL_PM_BUSY_COMP_TEST: copyout failed\n", 1033*0Sstevel@tonic-gate nodename, instance); 1034*0Sstevel@tonic-gate rval = EINVAL; 1035*0Sstevel@tonic-gate } 1036*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_BUSY_COMP_TEST:" 1037*0Sstevel@tonic-gate " comp 0 busy %d", 1038*0Sstevel@tonic-gate nodename, instance, state)); 1039*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 1040*0Sstevel@tonic-gate 1041*0Sstevel@tonic-gate break; 1042*0Sstevel@tonic-gate 1043*0Sstevel@tonic-gate case DEVCTL_PM_IDLE_COMP: 1044*0Sstevel@tonic-gate /* 1045*0Sstevel@tonic-gate * mark component 0 idle via a pm_idle_component() call. 1046*0Sstevel@tonic-gate * NOP if dstatep->busy[0] == 0. 1047*0Sstevel@tonic-gate */ 1048*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 1049*0Sstevel@tonic-gate if (dstatep->busy[0] > 0) { 1050*0Sstevel@tonic-gate --dstatep->busy[0]; 1051*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_IDLE_COMP:" 1052*0Sstevel@tonic-gate " comp 0: busy=%d", nodename, instance, 1053*0Sstevel@tonic-gate dstatep->busy[0])); 1054*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 1055*0Sstevel@tonic-gate ret = pm_idle_component(dstatep->dip, 0); 1056*0Sstevel@tonic-gate ASSERT(ret == DDI_SUCCESS); 1057*0Sstevel@tonic-gate } else { 1058*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 1059*0Sstevel@tonic-gate } 1060*0Sstevel@tonic-gate 1061*0Sstevel@tonic-gate break; 1062*0Sstevel@tonic-gate 1063*0Sstevel@tonic-gate case DEVCTL_PM_PROM_PRINTF: 1064*0Sstevel@tonic-gate (void) prom_printf("%s%d: PROM_PRINTF FROM GEN_DRV\n", 1065*0Sstevel@tonic-gate nodename, instance); 1066*0Sstevel@tonic-gate 1067*0Sstevel@tonic-gate break; 1068*0Sstevel@tonic-gate 1069*0Sstevel@tonic-gate case DEVCTL_PM_RAISE_PWR: 1070*0Sstevel@tonic-gate /* 1071*0Sstevel@tonic-gate * power up both components to MAXPWR via 1072*0Sstevel@tonic-gate * pm_raise_power() calls. this ioctl() cmd 1073*0Sstevel@tonic-gate * assumes that the current level is 0 1074*0Sstevel@tonic-gate */ 1075*0Sstevel@tonic-gate for (i = 0; i < COMPONENTS; i++) { 1076*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_RAISE_PWR:" 1077*0Sstevel@tonic-gate " comp %d old 0 new %d", 1078*0Sstevel@tonic-gate nodename, instance, i, maxpwr[i])); 1079*0Sstevel@tonic-gate if (pm_raise_power(dstatep->dip, 0, maxpwr[i]) 1080*0Sstevel@tonic-gate != DDI_SUCCESS) { 1081*0Sstevel@tonic-gate rval = EINVAL; 1082*0Sstevel@tonic-gate } 1083*0Sstevel@tonic-gate } 1084*0Sstevel@tonic-gate 1085*0Sstevel@tonic-gate break; 1086*0Sstevel@tonic-gate 1087*0Sstevel@tonic-gate case DEVCTL_PM_CHANGE_PWR_LOW: 1088*0Sstevel@tonic-gate /* 1089*0Sstevel@tonic-gate * power off both components via pm_power_has_changed() calls 1090*0Sstevel@tonic-gate */ 1091*0Sstevel@tonic-gate for (i = (COMPONENTS - 1); i >= 0; --i) { 1092*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_CHANGE_PWR_LOW:" 1093*0Sstevel@tonic-gate " comp %d new 0", 1094*0Sstevel@tonic-gate nodename, instance, i)); 1095*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 1096*0Sstevel@tonic-gate level_tmp = dstatep->level[i]; 1097*0Sstevel@tonic-gate dstatep->level[i] = 0; 1098*0Sstevel@tonic-gate if (pm_power_has_changed(dstatep->dip, i, 0) 1099*0Sstevel@tonic-gate != DDI_SUCCESS) { 1100*0Sstevel@tonic-gate dstatep->level[i] = level_tmp; 1101*0Sstevel@tonic-gate rval = EINVAL; 1102*0Sstevel@tonic-gate } 1103*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 1104*0Sstevel@tonic-gate } 1105*0Sstevel@tonic-gate 1106*0Sstevel@tonic-gate break; 1107*0Sstevel@tonic-gate 1108*0Sstevel@tonic-gate case DEVCTL_PM_CHANGE_PWR_HIGH: 1109*0Sstevel@tonic-gate /* 1110*0Sstevel@tonic-gate * power up both components to MAXPWR via 1111*0Sstevel@tonic-gate * pm_power_has_changed() calls 1112*0Sstevel@tonic-gate */ 1113*0Sstevel@tonic-gate for (i = 0; i < COMPONENTS; i++) { 1114*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_CHANGE_PWR_HIGH:" 1115*0Sstevel@tonic-gate " comp %d new %d", 1116*0Sstevel@tonic-gate nodename, instance, i, maxpwr[i])); 1117*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 1118*0Sstevel@tonic-gate level_tmp = dstatep->level[i]; 1119*0Sstevel@tonic-gate dstatep->level[i] = maxpwr[i]; 1120*0Sstevel@tonic-gate if (pm_power_has_changed(dstatep->dip, i, maxpwr[i]) 1121*0Sstevel@tonic-gate != DDI_SUCCESS) { 1122*0Sstevel@tonic-gate dstatep->level[i] = level_tmp; 1123*0Sstevel@tonic-gate rval = EINVAL; 1124*0Sstevel@tonic-gate } 1125*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 1126*0Sstevel@tonic-gate } 1127*0Sstevel@tonic-gate 1128*0Sstevel@tonic-gate break; 1129*0Sstevel@tonic-gate 1130*0Sstevel@tonic-gate case DEVCTL_PM_POWER: 1131*0Sstevel@tonic-gate /* 1132*0Sstevel@tonic-gate * test if the gen_drv_power() routine has been called, 1133*0Sstevel@tonic-gate * then clear 1134*0Sstevel@tonic-gate */ 1135*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 1136*0Sstevel@tonic-gate state = (dstatep->flag & POWER_FLAG) ? 1 : 0; 1137*0Sstevel@tonic-gate if (copyout(&state, dcp->cpyout_buf, 1138*0Sstevel@tonic-gate sizeof (uint_t)) != 0) { 1139*0Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DEVCTL_PM_POWER:" 1140*0Sstevel@tonic-gate " copyout failed\n", nodename, instance); 1141*0Sstevel@tonic-gate rval = EINVAL; 1142*0Sstevel@tonic-gate } 1143*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: %s POWER_FLAG: %d", 1144*0Sstevel@tonic-gate nodename, instance, "DEVCTL_PM_POWER", state)); 1145*0Sstevel@tonic-gate dstatep->flag &= ~POWER_FLAG; 1146*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 1147*0Sstevel@tonic-gate break; 1148*0Sstevel@tonic-gate 1149*0Sstevel@tonic-gate case DEVCTL_PM_NO_LOWER_POWER: 1150*0Sstevel@tonic-gate /* 1151*0Sstevel@tonic-gate * issue to not invoke pm_lower_power() on detach 1152*0Sstevel@tonic-gate */ 1153*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 1154*0Sstevel@tonic-gate dstatep->flag &= ~LOWER_POWER_FLAG; 1155*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 1156*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_NO_LOWER_POWER", 1157*0Sstevel@tonic-gate nodename, instance)); 1158*0Sstevel@tonic-gate break; 1159*0Sstevel@tonic-gate 1160*0Sstevel@tonic-gate default: 1161*0Sstevel@tonic-gate return (ENOTTY); 1162*0Sstevel@tonic-gate } 1163*0Sstevel@tonic-gate 1164*0Sstevel@tonic-gate return (rval); 1165*0Sstevel@tonic-gate } 1166*0Sstevel@tonic-gate 1167*0Sstevel@tonic-gate /*ARGSUSED*/ 1168*0Sstevel@tonic-gate static int 1169*0Sstevel@tonic-gate gen_read(dev_t dev, struct uio *uiop, cred_t *credp) 1170*0Sstevel@tonic-gate { 1171*0Sstevel@tonic-gate return (0); 1172*0Sstevel@tonic-gate } 1173*0Sstevel@tonic-gate 1174*0Sstevel@tonic-gate /*ARGSUSED*/ 1175*0Sstevel@tonic-gate static int 1176*0Sstevel@tonic-gate gen_write(dev_t dev, struct uio *uiop, cred_t *credp) 1177*0Sstevel@tonic-gate { 1178*0Sstevel@tonic-gate return (0); 1179*0Sstevel@tonic-gate } 1180*0Sstevel@tonic-gate 1181*0Sstevel@tonic-gate /*ARGSUSED0*/ 1182*0Sstevel@tonic-gate static int 1183*0Sstevel@tonic-gate gen_power(dev_info_t *dip, int cmpt, int level) 1184*0Sstevel@tonic-gate { 1185*0Sstevel@tonic-gate struct dstate *dstatep; 1186*0Sstevel@tonic-gate int instance = ddi_get_instance(dip); 1187*0Sstevel@tonic-gate char *nodename = ddi_node_name(dip); 1188*0Sstevel@tonic-gate int level_tmp; 1189*0Sstevel@tonic-gate 1190*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: power: cmpt %d to level %d", 1191*0Sstevel@tonic-gate nodename, instance, cmpt, level)); 1192*0Sstevel@tonic-gate 1193*0Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, instance); 1194*0Sstevel@tonic-gate if (dstatep == NULL) { 1195*0Sstevel@tonic-gate 1196*0Sstevel@tonic-gate return (DDI_FAILURE); 1197*0Sstevel@tonic-gate } 1198*0Sstevel@tonic-gate 1199*0Sstevel@tonic-gate /* 1200*0Sstevel@tonic-gate * Keep track of the power levels for both components 1201*0Sstevel@tonic-gate * in the dstatep->comp[] array. 1202*0Sstevel@tonic-gate * Set comp 0 to full level if non-zero comps 1203*0Sstevel@tonic-gate * are being set to a higher, non-zero level. 1204*0Sstevel@tonic-gate */ 1205*0Sstevel@tonic-gate if (cmpt == 0) { 1206*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 1207*0Sstevel@tonic-gate dstatep->level[cmpt] = level; 1208*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 1209*0Sstevel@tonic-gate } else if (level > dstatep->level[cmpt] && level != 0 && 1210*0Sstevel@tonic-gate dstatep->level[0] != COMP_0_MAXPWR) { 1211*0Sstevel@tonic-gate /* 1212*0Sstevel@tonic-gate * If component 0 is not at COMP_0_MAXPWR, and component 1 1213*0Sstevel@tonic-gate * is being powered ON, invoke pm_raise_power() or 1214*0Sstevel@tonic-gate * pm_power_has_changed() based on the 1215*0Sstevel@tonic-gate * PUP_WITH_PWR_HAS_CHANGED_FLAG flag. 1216*0Sstevel@tonic-gate * PUP_WITH_PWR_HAS_CHANGED_FLAG = FALSE by default, invoking 1217*0Sstevel@tonic-gate * pm_raise_power(). 1218*0Sstevel@tonic-gate */ 1219*0Sstevel@tonic-gate if (!(dstatep->flag & PUP_WITH_PWR_HAS_CHANGED_FLAG)) { 1220*0Sstevel@tonic-gate /* 1221*0Sstevel@tonic-gate * first set comp 0 to level COMP_0_MAXPWR 1222*0Sstevel@tonic-gate */ 1223*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: power: " 1224*0Sstevel@tonic-gate "pm_raise_power: comp 0 to level %d", 1225*0Sstevel@tonic-gate nodename, instance, COMP_0_MAXPWR)); 1226*0Sstevel@tonic-gate if (pm_raise_power(dip, 0, COMP_0_MAXPWR) != 1227*0Sstevel@tonic-gate DDI_SUCCESS) { 1228*0Sstevel@tonic-gate cmn_err(CE_WARN, 1229*0Sstevel@tonic-gate "%s%d: power: pm_raise_power() " 1230*0Sstevel@tonic-gate "failed: comp 0 to level %d\n", 1231*0Sstevel@tonic-gate nodename, instance, COMP_0_MAXPWR); 1232*0Sstevel@tonic-gate 1233*0Sstevel@tonic-gate return (DDI_FAILURE); 1234*0Sstevel@tonic-gate 1235*0Sstevel@tonic-gate } else { 1236*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 1237*0Sstevel@tonic-gate dstatep->level[0] = COMP_0_MAXPWR; 1238*0Sstevel@tonic-gate /* 1239*0Sstevel@tonic-gate * now set the level on the non-zero comp 1240*0Sstevel@tonic-gate */ 1241*0Sstevel@tonic-gate dstatep->level[cmpt] = level; 1242*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 1243*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: power: " 1244*0Sstevel@tonic-gate "comp %d to level %d", 1245*0Sstevel@tonic-gate nodename, instance, cmpt, level)); 1246*0Sstevel@tonic-gate } 1247*0Sstevel@tonic-gate } else { 1248*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: power: " 1249*0Sstevel@tonic-gate "pm_power_has_changed: comp 0 to level %d", 1250*0Sstevel@tonic-gate nodename, instance, COMP_0_MAXPWR)); 1251*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 1252*0Sstevel@tonic-gate level_tmp = dstatep->level[0]; 1253*0Sstevel@tonic-gate dstatep->level[0] = COMP_0_MAXPWR; 1254*0Sstevel@tonic-gate if (pm_power_has_changed(dip, 0, COMP_0_MAXPWR) != 1255*0Sstevel@tonic-gate DDI_SUCCESS) { 1256*0Sstevel@tonic-gate cmn_err(CE_WARN, 1257*0Sstevel@tonic-gate "%s%d: power: pm_power_has_changed() " 1258*0Sstevel@tonic-gate "failed: comp 0 to level %d\n", 1259*0Sstevel@tonic-gate nodename, instance, COMP_0_MAXPWR); 1260*0Sstevel@tonic-gate dstatep->level[0] = level_tmp; 1261*0Sstevel@tonic-gate } else { 1262*0Sstevel@tonic-gate /* 1263*0Sstevel@tonic-gate * now set the level on the non-zero comp 1264*0Sstevel@tonic-gate */ 1265*0Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: power:" 1266*0Sstevel@tonic-gate " pm_power_has_changed: comp %d" 1267*0Sstevel@tonic-gate " to level %d", nodename, instance, 1268*0Sstevel@tonic-gate cmpt, level)); 1269*0Sstevel@tonic-gate dstatep->level[cmpt] = level; 1270*0Sstevel@tonic-gate } 1271*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 1272*0Sstevel@tonic-gate } 1273*0Sstevel@tonic-gate } else { 1274*0Sstevel@tonic-gate mutex_enter(&dstatep->lock); 1275*0Sstevel@tonic-gate dstatep->level[cmpt] = level; 1276*0Sstevel@tonic-gate mutex_exit(&dstatep->lock); 1277*0Sstevel@tonic-gate } 1278*0Sstevel@tonic-gate 1279*0Sstevel@tonic-gate return (DDI_SUCCESS); 1280*0Sstevel@tonic-gate } 1281*0Sstevel@tonic-gate 1282*0Sstevel@tonic-gate 1283*0Sstevel@tonic-gate /* 1284*0Sstevel@tonic-gate * Create properties of various data types for testing devfs events. 1285*0Sstevel@tonic-gate */ 1286*0Sstevel@tonic-gate static int 1287*0Sstevel@tonic-gate gen_create_properties(dev_info_t *devi) 1288*0Sstevel@tonic-gate { 1289*0Sstevel@tonic-gate int int_val = 3023; 1290*0Sstevel@tonic-gate int int_array[] = { 3, 10, 304, 230, 4}; 1291*0Sstevel@tonic-gate int64_t int64_val = 20; 1292*0Sstevel@tonic-gate int64_t int64_array[] = { 12, 24, 36, 48}; 1293*0Sstevel@tonic-gate char *string_val = "Dev_node_prop"; 1294*0Sstevel@tonic-gate char *string_array[] = {"Dev_node_prop:0", 1295*0Sstevel@tonic-gate "Dev_node_prop:1", "Dev_node_prop:2", "Dev_node_prop:3"}; 1296*0Sstevel@tonic-gate uchar_t byte_array[] = { (uchar_t)0xaa, (uchar_t)0x55, 1297*0Sstevel@tonic-gate (uchar_t)0x12, (uchar_t)0xcd }; 1298*0Sstevel@tonic-gate char bytes[] = { (char)0x00, (char)0xef, (char)0xff }; 1299*0Sstevel@tonic-gate 1300*0Sstevel@tonic-gate if (ddi_prop_update_int(DDI_DEV_T_NONE, devi, "int", int_val) 1301*0Sstevel@tonic-gate != DDI_PROP_SUCCESS) 1302*0Sstevel@tonic-gate return (DDI_FAILURE); 1303*0Sstevel@tonic-gate 1304*0Sstevel@tonic-gate if (ddi_prop_update_int_array(DDI_DEV_T_NONE, devi, "int-array", 1305*0Sstevel@tonic-gate int_array, sizeof (int_array) / sizeof (int)) != DDI_PROP_SUCCESS) 1306*0Sstevel@tonic-gate return (DDI_FAILURE); 1307*0Sstevel@tonic-gate 1308*0Sstevel@tonic-gate if (ddi_prop_update_int64(DDI_DEV_T_NONE, devi, "int64", int64_val) 1309*0Sstevel@tonic-gate != DDI_PROP_SUCCESS) 1310*0Sstevel@tonic-gate return (DDI_FAILURE); 1311*0Sstevel@tonic-gate 1312*0Sstevel@tonic-gate if (ddi_prop_update_int64_array(DDI_DEV_T_NONE, devi, "int64-array", 1313*0Sstevel@tonic-gate int64_array, sizeof (int64_array) / sizeof (int64_t)) 1314*0Sstevel@tonic-gate != DDI_PROP_SUCCESS) 1315*0Sstevel@tonic-gate return (DDI_FAILURE); 1316*0Sstevel@tonic-gate 1317*0Sstevel@tonic-gate if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "string", string_val) 1318*0Sstevel@tonic-gate != DDI_PROP_SUCCESS) 1319*0Sstevel@tonic-gate return (DDI_FAILURE); 1320*0Sstevel@tonic-gate 1321*0Sstevel@tonic-gate if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi, "string-array", 1322*0Sstevel@tonic-gate string_array, sizeof (string_array) / sizeof (char *)) 1323*0Sstevel@tonic-gate != DDI_PROP_SUCCESS) 1324*0Sstevel@tonic-gate return (DDI_FAILURE); 1325*0Sstevel@tonic-gate 1326*0Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP, 1327*0Sstevel@tonic-gate "boolean", NULL, 0) != DDI_PROP_SUCCESS) 1328*0Sstevel@tonic-gate return (DDI_FAILURE); 1329*0Sstevel@tonic-gate 1330*0Sstevel@tonic-gate if (ddi_prop_update_byte_array(DDI_DEV_T_NONE, devi, "byte-array", 1331*0Sstevel@tonic-gate byte_array, sizeof (byte_array)) != DDI_PROP_SUCCESS) 1332*0Sstevel@tonic-gate return (DDI_FAILURE); 1333*0Sstevel@tonic-gate 1334*0Sstevel@tonic-gate /* untyped property */ 1335*0Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP, "untyped", 1336*0Sstevel@tonic-gate (caddr_t)bytes, sizeof (bytes)) != DDI_PROP_SUCCESS) 1337*0Sstevel@tonic-gate return (DDI_FAILURE); 1338*0Sstevel@tonic-gate 1339*0Sstevel@tonic-gate return (DDI_SUCCESS); 1340*0Sstevel@tonic-gate } 1341*0Sstevel@tonic-gate 1342*0Sstevel@tonic-gate static struct driver_minor_data { 1343*0Sstevel@tonic-gate char *name; 1344*0Sstevel@tonic-gate minor_t minor; 1345*0Sstevel@tonic-gate int type; 1346*0Sstevel@tonic-gate } disk_minor_data[] = { 1347*0Sstevel@tonic-gate {"a", 0, S_IFBLK}, 1348*0Sstevel@tonic-gate {"b", 1, S_IFBLK}, 1349*0Sstevel@tonic-gate {"c", 2, S_IFBLK}, 1350*0Sstevel@tonic-gate {"d", 3, S_IFBLK}, 1351*0Sstevel@tonic-gate {"e", 4, S_IFBLK}, 1352*0Sstevel@tonic-gate {"f", 5, S_IFBLK}, 1353*0Sstevel@tonic-gate {"g", 6, S_IFBLK}, 1354*0Sstevel@tonic-gate {"h", 7, S_IFBLK}, 1355*0Sstevel@tonic-gate {"a,raw", 0, S_IFCHR}, 1356*0Sstevel@tonic-gate {"b,raw", 1, S_IFCHR}, 1357*0Sstevel@tonic-gate {"c,raw", 2, S_IFCHR}, 1358*0Sstevel@tonic-gate {"d,raw", 3, S_IFCHR}, 1359*0Sstevel@tonic-gate {"e,raw", 4, S_IFCHR}, 1360*0Sstevel@tonic-gate {"f,raw", 5, S_IFCHR}, 1361*0Sstevel@tonic-gate {"g,raw", 6, S_IFCHR}, 1362*0Sstevel@tonic-gate {"h,raw", 7, S_IFCHR}, 1363*0Sstevel@tonic-gate {0} 1364*0Sstevel@tonic-gate }; 1365*0Sstevel@tonic-gate 1366*0Sstevel@tonic-gate 1367*0Sstevel@tonic-gate static struct driver_serial_minor_data { 1368*0Sstevel@tonic-gate char *name; 1369*0Sstevel@tonic-gate minor_t minor; 1370*0Sstevel@tonic-gate int type; 1371*0Sstevel@tonic-gate char *node_type; 1372*0Sstevel@tonic-gate } serial_minor_data[] = { 1373*0Sstevel@tonic-gate {"0", 0, S_IFCHR, "ddi_serial"}, 1374*0Sstevel@tonic-gate {"1", 1, S_IFCHR, "ddi_serial"}, 1375*0Sstevel@tonic-gate {"0,cu", 2, S_IFCHR, "ddi_serial:dialout"}, 1376*0Sstevel@tonic-gate {"1,cu", 3, S_IFCHR, "ddi_serial:dialout"}, 1377*0Sstevel@tonic-gate {0} 1378*0Sstevel@tonic-gate }; 1379*0Sstevel@tonic-gate 1380*0Sstevel@tonic-gate 1381*0Sstevel@tonic-gate static int 1382*0Sstevel@tonic-gate gen_create_display(dev_info_t *devi) 1383*0Sstevel@tonic-gate { 1384*0Sstevel@tonic-gate 1385*0Sstevel@tonic-gate int instance = ddi_get_instance(devi); 1386*0Sstevel@tonic-gate char minor_name[15]; 1387*0Sstevel@tonic-gate 1388*0Sstevel@tonic-gate (void) sprintf(minor_name, "cgtwenty%d", instance); 1389*0Sstevel@tonic-gate 1390*0Sstevel@tonic-gate return (ddi_create_minor_node(devi, minor_name, S_IFCHR, 1391*0Sstevel@tonic-gate INST_TO_MINOR(instance), DDI_NT_DISPLAY, NULL)); 1392*0Sstevel@tonic-gate } 1393*0Sstevel@tonic-gate 1394*0Sstevel@tonic-gate static int 1395*0Sstevel@tonic-gate gen_create_mn_disk_chan(dev_info_t *devi) 1396*0Sstevel@tonic-gate { 1397*0Sstevel@tonic-gate struct driver_minor_data *dmdp; 1398*0Sstevel@tonic-gate int instance = ddi_get_instance(devi); 1399*0Sstevel@tonic-gate 1400*0Sstevel@tonic-gate if (gen_create_properties(devi) != DDI_SUCCESS) 1401*0Sstevel@tonic-gate return (DDI_FAILURE); 1402*0Sstevel@tonic-gate 1403*0Sstevel@tonic-gate for (dmdp = disk_minor_data; dmdp->name != NULL; dmdp++) { 1404*0Sstevel@tonic-gate if (ddi_create_minor_node(devi, dmdp->name, dmdp->type, 1405*0Sstevel@tonic-gate (INST_TO_MINOR(instance)) | dmdp->minor, 1406*0Sstevel@tonic-gate DDI_NT_BLOCK_CHAN, NULL) != DDI_SUCCESS) { 1407*0Sstevel@tonic-gate 1408*0Sstevel@tonic-gate return (DDI_FAILURE); 1409*0Sstevel@tonic-gate } 1410*0Sstevel@tonic-gate } 1411*0Sstevel@tonic-gate return (DDI_SUCCESS); 1412*0Sstevel@tonic-gate } 1413*0Sstevel@tonic-gate 1414*0Sstevel@tonic-gate static uint_t 1415*0Sstevel@tonic-gate atod(char *s) 1416*0Sstevel@tonic-gate { 1417*0Sstevel@tonic-gate uint_t val = 0; 1418*0Sstevel@tonic-gate uint_t digit; 1419*0Sstevel@tonic-gate 1420*0Sstevel@tonic-gate while (*s) { 1421*0Sstevel@tonic-gate if (*s >= '0' && *s <= '9') 1422*0Sstevel@tonic-gate digit = *s++ - '0'; 1423*0Sstevel@tonic-gate else 1424*0Sstevel@tonic-gate break; 1425*0Sstevel@tonic-gate val = (val * 10) + digit; 1426*0Sstevel@tonic-gate } 1427*0Sstevel@tonic-gate return (val); 1428*0Sstevel@tonic-gate } 1429*0Sstevel@tonic-gate 1430*0Sstevel@tonic-gate 1431*0Sstevel@tonic-gate static int 1432*0Sstevel@tonic-gate gen_create_mn_disk_wwn(dev_info_t *devi) 1433*0Sstevel@tonic-gate { 1434*0Sstevel@tonic-gate struct driver_minor_data *dmdp; 1435*0Sstevel@tonic-gate int instance = ddi_get_instance(devi); 1436*0Sstevel@tonic-gate char *address = ddi_get_name_addr(devi); 1437*0Sstevel@tonic-gate int target, lun; 1438*0Sstevel@tonic-gate 1439*0Sstevel@tonic-gate if (address[0] >= '0' && address[0] <= '9' && 1440*0Sstevel@tonic-gate strchr(address, ',')) { 1441*0Sstevel@tonic-gate target = atod(address); 1442*0Sstevel@tonic-gate address = strchr(address, ','); 1443*0Sstevel@tonic-gate lun = atod(++address); 1444*0Sstevel@tonic-gate } else { /* this hack is for rm_stale_link() testing */ 1445*0Sstevel@tonic-gate target = 10; 1446*0Sstevel@tonic-gate lun = 5; 1447*0Sstevel@tonic-gate } 1448*0Sstevel@tonic-gate 1449*0Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP, 1450*0Sstevel@tonic-gate "target", (caddr_t)&target, sizeof (int)) 1451*0Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 1452*0Sstevel@tonic-gate return (DDI_FAILURE); 1453*0Sstevel@tonic-gate } 1454*0Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP, 1455*0Sstevel@tonic-gate "lun", (caddr_t)&lun, sizeof (int)) 1456*0Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 1457*0Sstevel@tonic-gate return (DDI_FAILURE); 1458*0Sstevel@tonic-gate } 1459*0Sstevel@tonic-gate 1460*0Sstevel@tonic-gate for (dmdp = disk_minor_data; dmdp->name != NULL; dmdp++) { 1461*0Sstevel@tonic-gate if (ddi_create_minor_node(devi, dmdp->name, dmdp->type, 1462*0Sstevel@tonic-gate (INST_TO_MINOR(instance)) | dmdp->minor, 1463*0Sstevel@tonic-gate DDI_NT_BLOCK_WWN, NULL) != DDI_SUCCESS) { 1464*0Sstevel@tonic-gate 1465*0Sstevel@tonic-gate return (DDI_FAILURE); 1466*0Sstevel@tonic-gate } 1467*0Sstevel@tonic-gate } 1468*0Sstevel@tonic-gate return (DDI_SUCCESS); 1469*0Sstevel@tonic-gate } 1470*0Sstevel@tonic-gate 1471*0Sstevel@tonic-gate static int 1472*0Sstevel@tonic-gate gen_create_mn_disk_cdrom(dev_info_t *devi) 1473*0Sstevel@tonic-gate { 1474*0Sstevel@tonic-gate struct driver_minor_data *dmdp; 1475*0Sstevel@tonic-gate int instance = ddi_get_instance(devi); 1476*0Sstevel@tonic-gate 1477*0Sstevel@tonic-gate for (dmdp = disk_minor_data; dmdp->name != NULL; dmdp++) { 1478*0Sstevel@tonic-gate if (ddi_create_minor_node(devi, dmdp->name, dmdp->type, 1479*0Sstevel@tonic-gate (INST_TO_MINOR(instance)) | dmdp->minor, 1480*0Sstevel@tonic-gate DDI_NT_CD_CHAN, NULL) != DDI_SUCCESS) { 1481*0Sstevel@tonic-gate 1482*0Sstevel@tonic-gate return (DDI_FAILURE); 1483*0Sstevel@tonic-gate } 1484*0Sstevel@tonic-gate } 1485*0Sstevel@tonic-gate return (DDI_SUCCESS); 1486*0Sstevel@tonic-gate } 1487*0Sstevel@tonic-gate 1488*0Sstevel@tonic-gate static int 1489*0Sstevel@tonic-gate gen_create_mn_disk_fd(dev_info_t *devi) 1490*0Sstevel@tonic-gate { 1491*0Sstevel@tonic-gate struct driver_minor_data *dmdp; 1492*0Sstevel@tonic-gate int instance = ddi_get_instance(devi); 1493*0Sstevel@tonic-gate 1494*0Sstevel@tonic-gate for (dmdp = disk_minor_data; dmdp->name != NULL; dmdp++) { 1495*0Sstevel@tonic-gate if (ddi_create_minor_node(devi, dmdp->name, dmdp->type, 1496*0Sstevel@tonic-gate (INST_TO_MINOR(instance)) | dmdp->minor, 1497*0Sstevel@tonic-gate DDI_NT_BLOCK_CHAN, NULL) != DDI_SUCCESS) { 1498*0Sstevel@tonic-gate 1499*0Sstevel@tonic-gate return (DDI_FAILURE); 1500*0Sstevel@tonic-gate } 1501*0Sstevel@tonic-gate } 1502*0Sstevel@tonic-gate return (DDI_SUCCESS); 1503*0Sstevel@tonic-gate } 1504*0Sstevel@tonic-gate 1505*0Sstevel@tonic-gate static int 1506*0Sstevel@tonic-gate gen_create_serial(dev_info_t *devi) 1507*0Sstevel@tonic-gate { 1508*0Sstevel@tonic-gate struct driver_serial_minor_data *dmdp; 1509*0Sstevel@tonic-gate int instance = ddi_get_instance(devi); 1510*0Sstevel@tonic-gate 1511*0Sstevel@tonic-gate for (dmdp = serial_minor_data; dmdp->name != NULL; dmdp++) { 1512*0Sstevel@tonic-gate if (ddi_create_minor_node(devi, dmdp->name, dmdp->type, 1513*0Sstevel@tonic-gate (INST_TO_MINOR(instance)) | dmdp->minor, 1514*0Sstevel@tonic-gate dmdp->node_type, NULL) != DDI_SUCCESS) { 1515*0Sstevel@tonic-gate 1516*0Sstevel@tonic-gate return (DDI_FAILURE); 1517*0Sstevel@tonic-gate } 1518*0Sstevel@tonic-gate } 1519*0Sstevel@tonic-gate return (DDI_SUCCESS); 1520*0Sstevel@tonic-gate } 1521*0Sstevel@tonic-gate 1522*0Sstevel@tonic-gate static int 1523*0Sstevel@tonic-gate gen_create_net(dev_info_t *devi) 1524*0Sstevel@tonic-gate { 1525*0Sstevel@tonic-gate int instance = ddi_get_instance(devi); 1526*0Sstevel@tonic-gate char minorname[32]; 1527*0Sstevel@tonic-gate 1528*0Sstevel@tonic-gate if (gen_create_properties(devi) != DDI_SUCCESS) 1529*0Sstevel@tonic-gate return (DDI_FAILURE); 1530*0Sstevel@tonic-gate 1531*0Sstevel@tonic-gate (void) snprintf(minorname, sizeof (minorname), "gen_drv%d", instance); 1532*0Sstevel@tonic-gate return (ddi_create_minor_node(devi, minorname, S_IFCHR, 1533*0Sstevel@tonic-gate INST_TO_MINOR(instance), DDI_NT_NET, 0)); 1534*0Sstevel@tonic-gate } 1535*0Sstevel@tonic-gate 1536*0Sstevel@tonic-gate static int 1537*0Sstevel@tonic-gate gen_create_minor_nodes(dev_info_t *devi, struct dstate *dstatep) 1538*0Sstevel@tonic-gate { 1539*0Sstevel@tonic-gate int rval = DDI_SUCCESS; 1540*0Sstevel@tonic-gate char *node_name; 1541*0Sstevel@tonic-gate 1542*0Sstevel@tonic-gate node_name = ddi_node_name(devi); 1543*0Sstevel@tonic-gate 1544*0Sstevel@tonic-gate if (strcmp(node_name, "disk_chan") == 0) { 1545*0Sstevel@tonic-gate rval = gen_create_mn_disk_chan(devi); 1546*0Sstevel@tonic-gate } else if (strcmp(node_name, "disk_wwn") == 0) { 1547*0Sstevel@tonic-gate rval = gen_create_mn_disk_wwn(devi); 1548*0Sstevel@tonic-gate } else if (strcmp(node_name, "disk_cdrom") == 0) { 1549*0Sstevel@tonic-gate rval = gen_create_mn_disk_cdrom(devi); 1550*0Sstevel@tonic-gate } else if (strcmp(node_name, "disk_fd") == 0) { 1551*0Sstevel@tonic-gate rval = gen_create_mn_disk_fd(devi); 1552*0Sstevel@tonic-gate } else if (strcmp(node_name, "cgtwenty") == 0) { 1553*0Sstevel@tonic-gate rval = gen_create_display(devi); 1554*0Sstevel@tonic-gate } else if (strcmp(node_name, "genzs") == 0) { 1555*0Sstevel@tonic-gate rval = gen_create_serial(devi); 1556*0Sstevel@tonic-gate } else if (strcmp(node_name, "net") == 0) { 1557*0Sstevel@tonic-gate rval = gen_create_net(devi); 1558*0Sstevel@tonic-gate } else { 1559*0Sstevel@tonic-gate int instance = ddi_get_instance(devi); 1560*0Sstevel@tonic-gate char *node_type; 1561*0Sstevel@tonic-gate 1562*0Sstevel@tonic-gate /* 1563*0Sstevel@tonic-gate * Solaris may directly hang the node_type off the minor node 1564*0Sstevel@tonic-gate * (without making a copy). Since we free the node_type 1565*0Sstevel@tonic-gate * property below we need to make a private copy to pass 1566*0Sstevel@tonic-gate * to ddi_create_minor_node to avoid devinfo snapshot panics. 1567*0Sstevel@tonic-gate * We store a pointer to our copy in dstate and free it in 1568*0Sstevel@tonic-gate * gen_detach after the minor nodes have been deleted by 1569*0Sstevel@tonic-gate * ddi_remove_minor_node. 1570*0Sstevel@tonic-gate */ 1571*0Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 1572*0Sstevel@tonic-gate DDI_PROP_DONTPASS, "node-type", &node_type) != 0) { 1573*0Sstevel@tonic-gate cmn_err(CE_WARN, "couldn't get node-type\n"); 1574*0Sstevel@tonic-gate return (DDI_FAILURE); 1575*0Sstevel@tonic-gate } 1576*0Sstevel@tonic-gate if (node_type) { 1577*0Sstevel@tonic-gate dstatep->node_type = kmem_alloc( 1578*0Sstevel@tonic-gate strlen(node_type) + 1, KM_SLEEP); 1579*0Sstevel@tonic-gate (void) strcpy(dstatep->node_type, node_type); 1580*0Sstevel@tonic-gate } 1581*0Sstevel@tonic-gate ddi_prop_free(node_type); 1582*0Sstevel@tonic-gate 1583*0Sstevel@tonic-gate /* the minor name is the same as the node name */ 1584*0Sstevel@tonic-gate if (ddi_create_minor_node(devi, node_name, S_IFCHR, 1585*0Sstevel@tonic-gate (INST_TO_MINOR(instance)), dstatep->node_type, NULL) != 1586*0Sstevel@tonic-gate DDI_SUCCESS) { 1587*0Sstevel@tonic-gate if (dstatep->node_type) { 1588*0Sstevel@tonic-gate kmem_free(dstatep->node_type, 1589*0Sstevel@tonic-gate strlen(dstatep->node_type) + 1); 1590*0Sstevel@tonic-gate dstatep->node_type = NULL; 1591*0Sstevel@tonic-gate } 1592*0Sstevel@tonic-gate return (DDI_FAILURE); 1593*0Sstevel@tonic-gate } 1594*0Sstevel@tonic-gate return (DDI_SUCCESS); 1595*0Sstevel@tonic-gate } 1596*0Sstevel@tonic-gate 1597*0Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 1598*0Sstevel@tonic-gate ddi_prop_remove_all(devi); 1599*0Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 1600*0Sstevel@tonic-gate } 1601*0Sstevel@tonic-gate 1602*0Sstevel@tonic-gate return (rval); 1603*0Sstevel@tonic-gate } 1604*0Sstevel@tonic-gate 1605*0Sstevel@tonic-gate /*ARGSUSED*/ 1606*0Sstevel@tonic-gate static void 1607*0Sstevel@tonic-gate gen_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie, void *arg, 1608*0Sstevel@tonic-gate void *impl_data) 1609*0Sstevel@tonic-gate { 1610*0Sstevel@tonic-gate if (gen_debug) 1611*0Sstevel@tonic-gate cmn_err(CE_NOTE, "gen_event_cb invoked"); 1612*0Sstevel@tonic-gate 1613*0Sstevel@tonic-gate } 1614