17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 5*19397407SSherry Moore * Common Development and Distribution License (the "License"). 6*19397407SSherry Moore * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207c478bd9Sstevel@tonic-gate */ 217c478bd9Sstevel@tonic-gate /* 22*19397407SSherry Moore * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 237c478bd9Sstevel@tonic-gate * Use is subject to license terms. 247c478bd9Sstevel@tonic-gate */ 257c478bd9Sstevel@tonic-gate 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate 287c478bd9Sstevel@tonic-gate /* 297c478bd9Sstevel@tonic-gate * generic character driver 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate #include <sys/types.h> 327c478bd9Sstevel@tonic-gate #include <sys/param.h> 337c478bd9Sstevel@tonic-gate #include <sys/errno.h> 347c478bd9Sstevel@tonic-gate #include <sys/uio.h> 357c478bd9Sstevel@tonic-gate #include <sys/buf.h> 367c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 377c478bd9Sstevel@tonic-gate #include <sys/open.h> 387c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 397c478bd9Sstevel@tonic-gate #include <sys/conf.h> 407c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 417c478bd9Sstevel@tonic-gate #include <sys/stat.h> 427c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 437c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 447c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 457c478bd9Sstevel@tonic-gate 467c478bd9Sstevel@tonic-gate 477c478bd9Sstevel@tonic-gate #define NUMEVENTS 6 487c478bd9Sstevel@tonic-gate #define COMPONENTS 2 497c478bd9Sstevel@tonic-gate #define COMP_0_MAXPWR 3 507c478bd9Sstevel@tonic-gate #define COMP_1_MAXPWR 2 517c478bd9Sstevel@tonic-gate #define MINPWR 0 527c478bd9Sstevel@tonic-gate static int maxpwr[] = { COMP_0_MAXPWR, COMP_1_MAXPWR }; 537c478bd9Sstevel@tonic-gate 547c478bd9Sstevel@tonic-gate /* 557c478bd9Sstevel@tonic-gate * The state for each generic device. 567c478bd9Sstevel@tonic-gate * NOTE: We save the node_type in the state structure. The node_type string 577c478bd9Sstevel@tonic-gate * (and not a copy) is stashed in a minor node by ddi_create_minor_node(), 587c478bd9Sstevel@tonic-gate * so ddi_remove_minor_node() must occur prior to state free. 597c478bd9Sstevel@tonic-gate */ 607c478bd9Sstevel@tonic-gate typedef struct dstate { 617c478bd9Sstevel@tonic-gate uint_t flag; 627c478bd9Sstevel@tonic-gate dev_info_t *dip; /* my devinfo handle */ 637c478bd9Sstevel@tonic-gate char *node_type; /* stable node_type copy */ 647c478bd9Sstevel@tonic-gate ddi_callback_id_t gen_cb_ids[NUMEVENTS]; 657c478bd9Sstevel@tonic-gate kmutex_t lock; 667c478bd9Sstevel@tonic-gate char *nodename; 677c478bd9Sstevel@tonic-gate int level[COMPONENTS]; /* pm level */ 687c478bd9Sstevel@tonic-gate int busy[COMPONENTS]; /* busy state */ 697c478bd9Sstevel@tonic-gate } dstate_t; 707c478bd9Sstevel@tonic-gate 717c478bd9Sstevel@tonic-gate 727c478bd9Sstevel@tonic-gate static void *dstates; 737c478bd9Sstevel@tonic-gate 747c478bd9Sstevel@tonic-gate static int gen_debug = 0; 757c478bd9Sstevel@tonic-gate 767c478bd9Sstevel@tonic-gate #ifdef DEBUG 777c478bd9Sstevel@tonic-gate #define gen_debug gen_debug_on 787c478bd9Sstevel@tonic-gate static int gen_debug_on = 0; 797c478bd9Sstevel@tonic-gate #define GEN_DEBUG(args) if (gen_debug) cmn_err args 807c478bd9Sstevel@tonic-gate #else 817c478bd9Sstevel@tonic-gate #define GEN_DEBUG(args) 827c478bd9Sstevel@tonic-gate #endif 837c478bd9Sstevel@tonic-gate 847c478bd9Sstevel@tonic-gate extern void prom_printf(const char *fmt, ...); 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate static int gen_open(dev_t *devp, int flag, int otyp, cred_t *cred); 877c478bd9Sstevel@tonic-gate static int gen_close(dev_t devp, int flag, int otyp, cred_t *cred); 887c478bd9Sstevel@tonic-gate static int gen_read(dev_t dev, struct uio *uiop, cred_t *credp); 897c478bd9Sstevel@tonic-gate static int gen_write(dev_t dev, struct uio *uiop, cred_t *credp); 907c478bd9Sstevel@tonic-gate static int gen_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, 917c478bd9Sstevel@tonic-gate cred_t *credp, int *rvalp); 927c478bd9Sstevel@tonic-gate static int gen_attach(dev_info_t *dip, ddi_attach_cmd_t cmd); 937c478bd9Sstevel@tonic-gate static int gen_detach(dev_info_t *dip, ddi_detach_cmd_t cmd); 947c478bd9Sstevel@tonic-gate static void gen_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie, 957c478bd9Sstevel@tonic-gate void *arg, void *impl_data); 967c478bd9Sstevel@tonic-gate 977c478bd9Sstevel@tonic-gate static int gen_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, 987c478bd9Sstevel@tonic-gate void **result); 997c478bd9Sstevel@tonic-gate static int gen_create_minor_nodes(dev_info_t *, struct dstate *); 1007c478bd9Sstevel@tonic-gate static int gen_power(dev_info_t *, int, int); 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate static struct cb_ops gen_cb_ops = { 1037c478bd9Sstevel@tonic-gate gen_open, /* open */ 1047c478bd9Sstevel@tonic-gate gen_close, /* close */ 1057c478bd9Sstevel@tonic-gate nodev, /* strategy */ 1067c478bd9Sstevel@tonic-gate nodev, /* print */ 1077c478bd9Sstevel@tonic-gate nodev, /* dump */ 1087c478bd9Sstevel@tonic-gate gen_read, /* read */ 1097c478bd9Sstevel@tonic-gate gen_write, /* write */ 1107c478bd9Sstevel@tonic-gate gen_ioctl, /* ioctl */ 1117c478bd9Sstevel@tonic-gate nodev, /* devmap */ 1127c478bd9Sstevel@tonic-gate nodev, /* mmap */ 1137c478bd9Sstevel@tonic-gate nodev, /* segmap */ 1147c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 1157c478bd9Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 1167c478bd9Sstevel@tonic-gate NULL, /* streamtab */ 1177c478bd9Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* flag */ 1187c478bd9Sstevel@tonic-gate CB_REV, /* cb_rev */ 1197c478bd9Sstevel@tonic-gate nodev, /* aread */ 1207c478bd9Sstevel@tonic-gate nodev /* awrite */ 1217c478bd9Sstevel@tonic-gate }; 1227c478bd9Sstevel@tonic-gate 1237c478bd9Sstevel@tonic-gate 1247c478bd9Sstevel@tonic-gate static struct dev_ops gen_ops = { 1257c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev */ 1267c478bd9Sstevel@tonic-gate 0, /* refcnt */ 1277c478bd9Sstevel@tonic-gate gen_info, /* getinfo */ 1287c478bd9Sstevel@tonic-gate nulldev, /* identify */ 1297c478bd9Sstevel@tonic-gate nulldev, /* probe */ 1307c478bd9Sstevel@tonic-gate gen_attach, /* attach */ 1317c478bd9Sstevel@tonic-gate gen_detach, /* detach */ 1327c478bd9Sstevel@tonic-gate nodev, /* reset */ 1337c478bd9Sstevel@tonic-gate &gen_cb_ops, /* driver ops */ 1347c478bd9Sstevel@tonic-gate (struct bus_ops *)0, /* bus ops */ 135*19397407SSherry Moore gen_power, /* power */ 136*19397407SSherry Moore ddi_quiesce_not_supported, /* devo_quiesce */ 1377c478bd9Sstevel@tonic-gate }; 1387c478bd9Sstevel@tonic-gate 1397c478bd9Sstevel@tonic-gate /* 1407c478bd9Sstevel@tonic-gate * INST_TO_MINOR() gives the starting minor number for a given gen_drv driver 1417c478bd9Sstevel@tonic-gate * instance. A shift left by 6 bits allows for each instance to have upto 1427c478bd9Sstevel@tonic-gate * 64 (2^6) minor numbers. The maximum minor number allowed by the system 1437c478bd9Sstevel@tonic-gate * is L_MAXMIN32 (0x3ffff). This effectively limits the gen_drv instance 1447c478bd9Sstevel@tonic-gate * numbers from 0 to 0xfff for a total of 4096 instances. 1457c478bd9Sstevel@tonic-gate */ 1467c478bd9Sstevel@tonic-gate #define INST_TO_MINOR(i) (i << 6) 1477c478bd9Sstevel@tonic-gate #define MINOR_TO_INST(mn) (mn >> 6) 1487c478bd9Sstevel@tonic-gate 1497c478bd9Sstevel@tonic-gate static char *mnodetypes[] = { 1507c478bd9Sstevel@tonic-gate "ddi_nt", 1517c478bd9Sstevel@tonic-gate "ddi_nt:device_type", 1527c478bd9Sstevel@tonic-gate "ddi_nt:device_class:bus_class", 1537c478bd9Sstevel@tonic-gate "ddi_nt2", 1547c478bd9Sstevel@tonic-gate "ddi_nt2:device_type", 1557c478bd9Sstevel@tonic-gate "ddi_nt2:device_type:bus_class", 1567c478bd9Sstevel@tonic-gate }; 1577c478bd9Sstevel@tonic-gate #define N_NTYPES (sizeof (mnodetypes) / sizeof (char *)) 1587c478bd9Sstevel@tonic-gate 1597c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 1607c478bd9Sstevel@tonic-gate &mod_driverops, 161*19397407SSherry Moore "generic test driver", 1627c478bd9Sstevel@tonic-gate &gen_ops 1637c478bd9Sstevel@tonic-gate }; 1647c478bd9Sstevel@tonic-gate 1657c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 1667c478bd9Sstevel@tonic-gate MODREV_1, &modldrv, NULL 1677c478bd9Sstevel@tonic-gate }; 1687c478bd9Sstevel@tonic-gate 1697c478bd9Sstevel@tonic-gate 1707c478bd9Sstevel@tonic-gate /* 1717c478bd9Sstevel@tonic-gate * flags 1727c478bd9Sstevel@tonic-gate */ 1737c478bd9Sstevel@tonic-gate #define OPEN_FLAG 0x001 1747c478bd9Sstevel@tonic-gate #define PWR_HAS_CHANGED_ON_RESUME_FLAG 0x002 1757c478bd9Sstevel@tonic-gate #define FAIL_SUSPEND_FLAG 0x004 1767c478bd9Sstevel@tonic-gate #define PUP_WITH_PWR_HAS_CHANGED_FLAG 0x008 1777c478bd9Sstevel@tonic-gate #define POWER_FLAG 0x010 1787c478bd9Sstevel@tonic-gate #define LOWER_POWER_FLAG 0x020 1797c478bd9Sstevel@tonic-gate #define NO_INVOL_FLAG 0x040 1807c478bd9Sstevel@tonic-gate #define PM_SUPPORTED_FLAG 0x080 1817c478bd9Sstevel@tonic-gate 1827c478bd9Sstevel@tonic-gate /* 1837c478bd9Sstevel@tonic-gate * ioctl commands (non-devctl ioctl commands) 1847c478bd9Sstevel@tonic-gate */ 1857c478bd9Sstevel@tonic-gate #define GENDRV_IOCTL ('P' << 8) 1867c478bd9Sstevel@tonic-gate #define GENDRV_IOFAULT_SIMULATE (GENDRV_IOCTL | 0) 1877c478bd9Sstevel@tonic-gate #define GENDRV_NDI_EVENT_TEST (GENDRV_IOCTL | 1) 1887c478bd9Sstevel@tonic-gate 1897c478bd9Sstevel@tonic-gate int 1907c478bd9Sstevel@tonic-gate _init(void) 1917c478bd9Sstevel@tonic-gate { 1927c478bd9Sstevel@tonic-gate int e; 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate if ((e = ddi_soft_state_init(&dstates, 1957c478bd9Sstevel@tonic-gate sizeof (struct dstate), 0)) != 0) { 1967c478bd9Sstevel@tonic-gate return (e); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0) { 2007c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&dstates); 2017c478bd9Sstevel@tonic-gate } 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate return (e); 2047c478bd9Sstevel@tonic-gate } 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate int 2077c478bd9Sstevel@tonic-gate _fini(void) 2087c478bd9Sstevel@tonic-gate { 2097c478bd9Sstevel@tonic-gate int e; 2107c478bd9Sstevel@tonic-gate 2117c478bd9Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) != 0) { 2127c478bd9Sstevel@tonic-gate return (e); 2137c478bd9Sstevel@tonic-gate } 2147c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&dstates); 2157c478bd9Sstevel@tonic-gate return (e); 2167c478bd9Sstevel@tonic-gate } 2177c478bd9Sstevel@tonic-gate 2187c478bd9Sstevel@tonic-gate int 2197c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 2207c478bd9Sstevel@tonic-gate { 2217c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 2227c478bd9Sstevel@tonic-gate } 2237c478bd9Sstevel@tonic-gate 2247c478bd9Sstevel@tonic-gate static int 2257c478bd9Sstevel@tonic-gate gen_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 2267c478bd9Sstevel@tonic-gate { 2277c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(devi); 2287c478bd9Sstevel@tonic-gate struct dstate *dstatep; 2297c478bd9Sstevel@tonic-gate int rval; 2307c478bd9Sstevel@tonic-gate int n_devs; 2317c478bd9Sstevel@tonic-gate int n_minorcomps; 2327c478bd9Sstevel@tonic-gate int isclone; 2337c478bd9Sstevel@tonic-gate ddi_eventcookie_t dev_offline_cookie, dev_reset_cookie; 2347c478bd9Sstevel@tonic-gate ddi_eventcookie_t bus_reset_cookie, bus_quiesce_cookie; 2357c478bd9Sstevel@tonic-gate ddi_eventcookie_t bus_unquiesce_cookie, bus_test_post_cookie; 2367c478bd9Sstevel@tonic-gate int i_init = 0; 2377c478bd9Sstevel@tonic-gate int level_tmp; 2387c478bd9Sstevel@tonic-gate 2397c478bd9Sstevel@tonic-gate int i; 2407c478bd9Sstevel@tonic-gate char *pm_comp[] = { 2417c478bd9Sstevel@tonic-gate "NAME=leaf0", 2427c478bd9Sstevel@tonic-gate "0=D0", 2437c478bd9Sstevel@tonic-gate "1=D1", 2447c478bd9Sstevel@tonic-gate "2=D2", 2457c478bd9Sstevel@tonic-gate "3=D3", 2467c478bd9Sstevel@tonic-gate "NAME=leaf1", 2477c478bd9Sstevel@tonic-gate "0=off", 2487c478bd9Sstevel@tonic-gate "1=blank", 2497c478bd9Sstevel@tonic-gate "2=on"}; 2507c478bd9Sstevel@tonic-gate char *pm_hw_state = {"needs-suspend-resume"}; 2517c478bd9Sstevel@tonic-gate 2527c478bd9Sstevel@tonic-gate 2537c478bd9Sstevel@tonic-gate switch (cmd) { 2547c478bd9Sstevel@tonic-gate case DDI_ATTACH: 2557c478bd9Sstevel@tonic-gate 2567c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(dstates, instance) != 2577c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 2587c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: can't allocate state\n", 2597c478bd9Sstevel@tonic-gate ddi_get_name(devi), instance); 2607c478bd9Sstevel@tonic-gate 2617c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2627c478bd9Sstevel@tonic-gate } 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, instance); 2657c478bd9Sstevel@tonic-gate dstatep->dip = devi; 2667c478bd9Sstevel@tonic-gate mutex_init(&dstatep->lock, NULL, MUTEX_DRIVER, NULL); 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate n_devs = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, 2697c478bd9Sstevel@tonic-gate "ndevs", 1); 2707c478bd9Sstevel@tonic-gate 2717c478bd9Sstevel@tonic-gate isclone = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, 2727c478bd9Sstevel@tonic-gate "isclone", 0); 2737c478bd9Sstevel@tonic-gate 2747c478bd9Sstevel@tonic-gate n_minorcomps = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, 2757c478bd9Sstevel@tonic-gate "ncomps", 1); 2767c478bd9Sstevel@tonic-gate 2777c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 2787c478bd9Sstevel@tonic-gate "%s%d attaching: n_devs=%d n_minorcomps=%d isclone=%d", 2797c478bd9Sstevel@tonic-gate ddi_get_name(devi), ddi_get_instance(devi), 2807c478bd9Sstevel@tonic-gate n_devs, n_minorcomps, isclone)); 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate if (isclone) { 2837c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, "gen", S_IFCHR, 2847c478bd9Sstevel@tonic-gate INST_TO_MINOR(instance), mnodetypes[0], 2857c478bd9Sstevel@tonic-gate isclone) != DDI_SUCCESS) { 2867c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 2877c478bd9Sstevel@tonic-gate ddi_soft_state_free(dstates, instance); 2887c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: can't create minor " 2897c478bd9Sstevel@tonic-gate "node", ddi_get_name(devi), instance); 2907c478bd9Sstevel@tonic-gate 2917c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 2927c478bd9Sstevel@tonic-gate } 2937c478bd9Sstevel@tonic-gate rval = DDI_SUCCESS; 2947c478bd9Sstevel@tonic-gate } else { 2957c478bd9Sstevel@tonic-gate rval = gen_create_minor_nodes(devi, dstatep); 2967c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 2977c478bd9Sstevel@tonic-gate ddi_prop_remove_all(devi); 2987c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 2997c478bd9Sstevel@tonic-gate ddi_soft_state_free(dstates, instance); 3007c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: can't create minor " 3017c478bd9Sstevel@tonic-gate "nodes", ddi_get_name(devi), instance); 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 3047c478bd9Sstevel@tonic-gate } 3057c478bd9Sstevel@tonic-gate } 3067c478bd9Sstevel@tonic-gate 3077c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(devi, "pshot_dev_offline", 3087c478bd9Sstevel@tonic-gate &dev_offline_cookie) == DDI_SUCCESS) { 3097c478bd9Sstevel@tonic-gate (void) ddi_add_event_handler(devi, dev_offline_cookie, 3107c478bd9Sstevel@tonic-gate gen_event_cb, NULL, &(dstatep->gen_cb_ids[0])); 3117c478bd9Sstevel@tonic-gate } 3127c478bd9Sstevel@tonic-gate 3137c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(devi, "pshot_dev_reset", 3147c478bd9Sstevel@tonic-gate &dev_reset_cookie) == DDI_SUCCESS) { 3157c478bd9Sstevel@tonic-gate (void) ddi_add_event_handler(devi, dev_reset_cookie, 3167c478bd9Sstevel@tonic-gate gen_event_cb, NULL, &(dstatep->gen_cb_ids[1])); 3177c478bd9Sstevel@tonic-gate } 3187c478bd9Sstevel@tonic-gate 3197c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(devi, "pshot_bus_reset", 3207c478bd9Sstevel@tonic-gate &bus_reset_cookie) == DDI_SUCCESS) { 3217c478bd9Sstevel@tonic-gate (void) ddi_add_event_handler(devi, bus_reset_cookie, 3227c478bd9Sstevel@tonic-gate gen_event_cb, NULL, &(dstatep->gen_cb_ids[2])); 3237c478bd9Sstevel@tonic-gate } 3247c478bd9Sstevel@tonic-gate 3257c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(devi, "pshot_bus_quiesce", 3267c478bd9Sstevel@tonic-gate &bus_quiesce_cookie) == DDI_SUCCESS) { 3277c478bd9Sstevel@tonic-gate (void) ddi_add_event_handler(devi, bus_quiesce_cookie, 3287c478bd9Sstevel@tonic-gate gen_event_cb, NULL, &(dstatep->gen_cb_ids[3])); 3297c478bd9Sstevel@tonic-gate } 3307c478bd9Sstevel@tonic-gate 3317c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(devi, "pshot_bus_unquiesce", 3327c478bd9Sstevel@tonic-gate &bus_unquiesce_cookie) == DDI_SUCCESS) { 3337c478bd9Sstevel@tonic-gate (void) ddi_add_event_handler(devi, 3347c478bd9Sstevel@tonic-gate bus_unquiesce_cookie, gen_event_cb, 3357c478bd9Sstevel@tonic-gate NULL, &(dstatep->gen_cb_ids[4])); 3367c478bd9Sstevel@tonic-gate } 3377c478bd9Sstevel@tonic-gate 3387c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(devi, "pshot_bus_test_post", 3397c478bd9Sstevel@tonic-gate &bus_test_post_cookie) == DDI_SUCCESS) { 3407c478bd9Sstevel@tonic-gate (void) ddi_add_event_handler(devi, 3417c478bd9Sstevel@tonic-gate bus_test_post_cookie, gen_event_cb, 3427c478bd9Sstevel@tonic-gate NULL, &(dstatep->gen_cb_ids[5])); 3437c478bd9Sstevel@tonic-gate } 3447c478bd9Sstevel@tonic-gate 3457c478bd9Sstevel@tonic-gate /* 3467c478bd9Sstevel@tonic-gate * initialize the devices' pm state 3477c478bd9Sstevel@tonic-gate */ 3487c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 3497c478bd9Sstevel@tonic-gate dstatep->flag &= ~OPEN_FLAG; 3507c478bd9Sstevel@tonic-gate dstatep->flag &= ~PWR_HAS_CHANGED_ON_RESUME_FLAG; 3517c478bd9Sstevel@tonic-gate dstatep->flag &= ~FAIL_SUSPEND_FLAG; 3527c478bd9Sstevel@tonic-gate dstatep->flag &= ~PUP_WITH_PWR_HAS_CHANGED_FLAG; 3537c478bd9Sstevel@tonic-gate dstatep->flag |= LOWER_POWER_FLAG; 3547c478bd9Sstevel@tonic-gate dstatep->flag &= ~NO_INVOL_FLAG; 3557c478bd9Sstevel@tonic-gate dstatep->flag |= PM_SUPPORTED_FLAG; 3567c478bd9Sstevel@tonic-gate dstatep->busy[0] = 0; 3577c478bd9Sstevel@tonic-gate dstatep->busy[1] = 0; 3587c478bd9Sstevel@tonic-gate dstatep->level[0] = -1; 3597c478bd9Sstevel@tonic-gate dstatep->level[1] = -1; 3607c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 3617c478bd9Sstevel@tonic-gate 3627c478bd9Sstevel@tonic-gate /* 3637c478bd9Sstevel@tonic-gate * stash the nodename 3647c478bd9Sstevel@tonic-gate */ 3657c478bd9Sstevel@tonic-gate dstatep->nodename = ddi_node_name(devi); 3667c478bd9Sstevel@tonic-gate 3677c478bd9Sstevel@tonic-gate /* 3687c478bd9Sstevel@tonic-gate * Check if the no-involuntary-power-cycles property 3697c478bd9Sstevel@tonic-gate * was created. Set NO_INVOL_FLAG if so. 3707c478bd9Sstevel@tonic-gate */ 3717c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip, 3727c478bd9Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 3737c478bd9Sstevel@tonic-gate "no-involuntary-power-cycles") == 1) { 3747c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 3757c478bd9Sstevel@tonic-gate "%s%d: DDI_ATTACH:\n\tno-involuntary-power-cycles" 3767c478bd9Sstevel@tonic-gate " property was created", 3777c478bd9Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi))); 3787c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 3797c478bd9Sstevel@tonic-gate dstatep->flag |= NO_INVOL_FLAG; 3807c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate 3837c478bd9Sstevel@tonic-gate /* 3847c478bd9Sstevel@tonic-gate * Check if the dependency-property property 3857c478bd9Sstevel@tonic-gate * was created. 3867c478bd9Sstevel@tonic-gate */ 3877c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip, 3887c478bd9Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 3897c478bd9Sstevel@tonic-gate "dependency-property") == 1) { 3907c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 3917c478bd9Sstevel@tonic-gate "%s%d: DDI_ATTACH:\n\tdependency-property" 3927c478bd9Sstevel@tonic-gate " property was created", 3937c478bd9Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi))); 3947c478bd9Sstevel@tonic-gate } 3957c478bd9Sstevel@tonic-gate 3967c478bd9Sstevel@tonic-gate /* 3977c478bd9Sstevel@tonic-gate * create the pm-components property. two comps: 3987c478bd9Sstevel@tonic-gate * 4 levels on comp0, 3 on comp 1. 3997c478bd9Sstevel@tonic-gate * - skip for a "tape" device, clear PM_SUPPORTED_FLAG 4007c478bd9Sstevel@tonic-gate */ 4017c478bd9Sstevel@tonic-gate if (strcmp(ddi_node_name(devi), "tape") != 0) { 4027c478bd9Sstevel@tonic-gate if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi, 4037c478bd9Sstevel@tonic-gate "pm-components", pm_comp, 9) != DDI_PROP_SUCCESS) { 4047c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: %s\n", 4057c478bd9Sstevel@tonic-gate ddi_node_name(devi), 4067c478bd9Sstevel@tonic-gate ddi_get_instance(devi), 4077c478bd9Sstevel@tonic-gate "unable to create \"pm-components\" " 4087c478bd9Sstevel@tonic-gate " property."); 4097c478bd9Sstevel@tonic-gate 4107c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4117c478bd9Sstevel@tonic-gate } 4127c478bd9Sstevel@tonic-gate } else { 4137c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 4147c478bd9Sstevel@tonic-gate dstatep->flag &= ~PM_SUPPORTED_FLAG; 4157c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 4167c478bd9Sstevel@tonic-gate } 4177c478bd9Sstevel@tonic-gate 4187c478bd9Sstevel@tonic-gate /* 4197c478bd9Sstevel@tonic-gate * Check if the pm-components property was created 4207c478bd9Sstevel@tonic-gate */ 4217c478bd9Sstevel@tonic-gate if (dstatep->flag & PM_SUPPORTED_FLAG) { 4227c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, dstatep->dip, 4237c478bd9Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 4247c478bd9Sstevel@tonic-gate "pm-components") != 1) { 4257c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t%s", 4267c478bd9Sstevel@tonic-gate ddi_node_name(devi), 4277c478bd9Sstevel@tonic-gate ddi_get_instance(devi), 4287c478bd9Sstevel@tonic-gate "\"pm-components\" property does" 4297c478bd9Sstevel@tonic-gate " not exist"); 4307c478bd9Sstevel@tonic-gate 4317c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4327c478bd9Sstevel@tonic-gate 4337c478bd9Sstevel@tonic-gate } else { 4347c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_ATTACH:" 4357c478bd9Sstevel@tonic-gate " created pm-components property", 4367c478bd9Sstevel@tonic-gate ddi_node_name(devi), 4377c478bd9Sstevel@tonic-gate ddi_get_instance(devi))); 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate /* 4427c478bd9Sstevel@tonic-gate * create the pm-hardware-state property. 4437c478bd9Sstevel@tonic-gate * needed to get DDI_SUSPEND and DDI_RESUME calls 4447c478bd9Sstevel@tonic-gate */ 4457c478bd9Sstevel@tonic-gate if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, 4467c478bd9Sstevel@tonic-gate "pm-hardware-state", pm_hw_state) != DDI_PROP_SUCCESS) { 4477c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t%s\n", 4487c478bd9Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi), 4497c478bd9Sstevel@tonic-gate "unable to create \"pm-hardware-state\" " 4507c478bd9Sstevel@tonic-gate " property."); 4517c478bd9Sstevel@tonic-gate 4527c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4537c478bd9Sstevel@tonic-gate } 4547c478bd9Sstevel@tonic-gate 4557c478bd9Sstevel@tonic-gate /* 4567c478bd9Sstevel@tonic-gate * set power levels to max via pm_raise_power(), 4577c478bd9Sstevel@tonic-gate */ 4587c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 4597c478bd9Sstevel@tonic-gate i_init = (dstatep->flag & PM_SUPPORTED_FLAG) ? 0 : COMPONENTS; 4607c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 4617c478bd9Sstevel@tonic-gate for (i = i_init; i < COMPONENTS; i++) { 4627c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 4637c478bd9Sstevel@tonic-gate "%s%d: DDI_ATTACH: pm_raise_power comp %d " 4647c478bd9Sstevel@tonic-gate "to level %d", ddi_node_name(devi), 4657c478bd9Sstevel@tonic-gate ddi_get_instance(devi), i, maxpwr[i])); 4667c478bd9Sstevel@tonic-gate if (pm_raise_power(dstatep->dip, i, maxpwr[i]) != 4677c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 4687c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 4697c478bd9Sstevel@tonic-gate "%s%d: DDI_ATTACH: pm_raise_power failed\n", 4707c478bd9Sstevel@tonic-gate ddi_node_name(devi), 4717c478bd9Sstevel@tonic-gate ddi_get_instance(devi)); 4727c478bd9Sstevel@tonic-gate dstatep->level[i] = -1; 4737c478bd9Sstevel@tonic-gate 4747c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate } 4777c478bd9Sstevel@tonic-gate 4787c478bd9Sstevel@tonic-gate if (rval == DDI_SUCCESS) { 4797c478bd9Sstevel@tonic-gate ddi_report_dev(devi); 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate return (rval); 4827c478bd9Sstevel@tonic-gate 4837c478bd9Sstevel@tonic-gate 4847c478bd9Sstevel@tonic-gate case DDI_RESUME: 4857c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_RESUME", ddi_node_name(devi), 4867c478bd9Sstevel@tonic-gate ddi_get_instance(devi))); 4877c478bd9Sstevel@tonic-gate 4887c478bd9Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, ddi_get_instance(devi)); 4897c478bd9Sstevel@tonic-gate if (dstatep == NULL) { 4907c478bd9Sstevel@tonic-gate 4917c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4927c478bd9Sstevel@tonic-gate } 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate /* 4957c478bd9Sstevel@tonic-gate * Call pm_power_has_changed() if flag 4967c478bd9Sstevel@tonic-gate * PWR_HAS_CHANGED_ON_RESUME_FLAG is set, 4977c478bd9Sstevel@tonic-gate * then clear the flag 4987c478bd9Sstevel@tonic-gate */ 4997c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 5007c478bd9Sstevel@tonic-gate i_init = (dstatep->flag & PM_SUPPORTED_FLAG) ? 0 : COMPONENTS; 5017c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 5027c478bd9Sstevel@tonic-gate if (dstatep->flag & PWR_HAS_CHANGED_ON_RESUME_FLAG) { 5037c478bd9Sstevel@tonic-gate for (i = i_init; i < COMPONENTS; i++) { 5047c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 5057c478bd9Sstevel@tonic-gate "%s%d: DDI_RESUME: pm_power_has_changed " 5067c478bd9Sstevel@tonic-gate "comp %d to level %d", ddi_node_name(devi), 5077c478bd9Sstevel@tonic-gate ddi_get_instance(devi), i, maxpwr[i])); 5087c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 5097c478bd9Sstevel@tonic-gate level_tmp = dstatep->level[i]; 5107c478bd9Sstevel@tonic-gate dstatep->level[i] = maxpwr[i]; 5117c478bd9Sstevel@tonic-gate if (pm_power_has_changed(dstatep->dip, i, 5127c478bd9Sstevel@tonic-gate maxpwr[i]) != DDI_SUCCESS) { 5137c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 5147c478bd9Sstevel@tonic-gate "%s%d: DDI_RESUME:\n\t" 5157c478bd9Sstevel@tonic-gate " pm_power_has_changed" 5167c478bd9Sstevel@tonic-gate " failed: comp %d to level %d\n", 5177c478bd9Sstevel@tonic-gate ddi_node_name(devi), 5187c478bd9Sstevel@tonic-gate ddi_get_instance(devi), 5197c478bd9Sstevel@tonic-gate i, maxpwr[i]); 5207c478bd9Sstevel@tonic-gate dstatep->level[i] = level_tmp; 5217c478bd9Sstevel@tonic-gate } 5227c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 5237c478bd9Sstevel@tonic-gate } 5247c478bd9Sstevel@tonic-gate } else { 5257c478bd9Sstevel@tonic-gate /* 5267c478bd9Sstevel@tonic-gate * Call pm_raise_power() instead 5277c478bd9Sstevel@tonic-gate */ 5287c478bd9Sstevel@tonic-gate for (i = i_init; i < COMPONENTS; i++) { 5297c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 5307c478bd9Sstevel@tonic-gate "%s%d: DDI_RESUME: pm_raise_power" 5317c478bd9Sstevel@tonic-gate " comp %d to level %d", 5327c478bd9Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi), 5337c478bd9Sstevel@tonic-gate i, maxpwr[i])); 5347c478bd9Sstevel@tonic-gate if (pm_raise_power(dstatep->dip, i, maxpwr[i]) 5357c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 5367c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 5377c478bd9Sstevel@tonic-gate "%s%d: DDI_RESUME:" 5387c478bd9Sstevel@tonic-gate "\n\tpm_raise_power" 5397c478bd9Sstevel@tonic-gate "failed: comp %d to level %d\n", 5407c478bd9Sstevel@tonic-gate ddi_node_name(devi), 5417c478bd9Sstevel@tonic-gate ddi_get_instance(devi), 5427c478bd9Sstevel@tonic-gate i, maxpwr[i]); 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate } 5467c478bd9Sstevel@tonic-gate 5477c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 5487c478bd9Sstevel@tonic-gate 5497c478bd9Sstevel@tonic-gate default: 5507c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_WARN, "attach: default")); 5517c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5527c478bd9Sstevel@tonic-gate } 5537c478bd9Sstevel@tonic-gate } 5547c478bd9Sstevel@tonic-gate 5557c478bd9Sstevel@tonic-gate static int 5567c478bd9Sstevel@tonic-gate gen_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 5577c478bd9Sstevel@tonic-gate { 5587c478bd9Sstevel@tonic-gate struct dstate *dstatep; 5597c478bd9Sstevel@tonic-gate int instance; 5607c478bd9Sstevel@tonic-gate int i; 5617c478bd9Sstevel@tonic-gate int rv; 5627c478bd9Sstevel@tonic-gate int rm_power; 5637c478bd9Sstevel@tonic-gate int level_tmp; 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate #ifdef DEBUG 5667c478bd9Sstevel@tonic-gate int n_devs; 5677c478bd9Sstevel@tonic-gate int n_minorcomps; 5687c478bd9Sstevel@tonic-gate int isclone; 5697c478bd9Sstevel@tonic-gate #endif 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate switch (cmd) { 5727c478bd9Sstevel@tonic-gate case DDI_DETACH: 5737c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_DETACH", ddi_node_name(devi), 5747c478bd9Sstevel@tonic-gate ddi_get_instance(devi))); 5757c478bd9Sstevel@tonic-gate 5767c478bd9Sstevel@tonic-gate instance = ddi_get_instance(devi); 5777c478bd9Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, instance); 5787c478bd9Sstevel@tonic-gate if (dstatep == NULL) { 5797c478bd9Sstevel@tonic-gate 5807c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5817c478bd9Sstevel@tonic-gate } 5827c478bd9Sstevel@tonic-gate 5837c478bd9Sstevel@tonic-gate #ifdef DEBUG 5847c478bd9Sstevel@tonic-gate n_devs = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, 5857c478bd9Sstevel@tonic-gate "ndevs", 1); 5867c478bd9Sstevel@tonic-gate 5877c478bd9Sstevel@tonic-gate isclone = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, 5887c478bd9Sstevel@tonic-gate "isclone", 0); 5897c478bd9Sstevel@tonic-gate 5907c478bd9Sstevel@tonic-gate n_minorcomps = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 0, 5917c478bd9Sstevel@tonic-gate "ncomps", 1); 5927c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 5937c478bd9Sstevel@tonic-gate 5947c478bd9Sstevel@tonic-gate /* 5957c478bd9Sstevel@tonic-gate * power off component 1. 5967c478bd9Sstevel@tonic-gate */ 5977c478bd9Sstevel@tonic-gate if (dstatep->flag & PM_SUPPORTED_FLAG) { 5987c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 5997c478bd9Sstevel@tonic-gate "%s%d: DDI_DETACH: pm_lower_power comp 1 level %d", 6007c478bd9Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi), 6017c478bd9Sstevel@tonic-gate MINPWR)); 6027c478bd9Sstevel@tonic-gate if (pm_lower_power(dstatep->dip, 1, MINPWR) 6037c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 6047c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_DETACH:\n\t" 6057c478bd9Sstevel@tonic-gate "pm_lower_power failed for comp 1 to" 6067c478bd9Sstevel@tonic-gate " level %d\n", ddi_node_name(devi), 6077c478bd9Sstevel@tonic-gate ddi_get_instance(devi), MINPWR); 6087c478bd9Sstevel@tonic-gate 6097c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6107c478bd9Sstevel@tonic-gate } 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate /* 6137c478bd9Sstevel@tonic-gate * check power level. Issue pm_power_has_changed 6147c478bd9Sstevel@tonic-gate * if not at MINPWR. 6157c478bd9Sstevel@tonic-gate */ 6167c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 6177c478bd9Sstevel@tonic-gate level_tmp = dstatep->level[1]; 6187c478bd9Sstevel@tonic-gate dstatep->level[1] = MINPWR; 6197c478bd9Sstevel@tonic-gate if (dstatep->level[1] != MINPWR) { 6207c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_NOTE, "%s%d: DDI_DETACH:" 6217c478bd9Sstevel@tonic-gate " power off via pm_power_has_changed" 6227c478bd9Sstevel@tonic-gate " instead", ddi_node_name(devi), 6237c478bd9Sstevel@tonic-gate ddi_get_instance(devi))); 6247c478bd9Sstevel@tonic-gate if (pm_power_has_changed(dstatep->dip, 6257c478bd9Sstevel@tonic-gate 1, MINPWR) != DDI_SUCCESS) { 6267c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_NOTE, "%s%d: DDI_DETACH:" 6277c478bd9Sstevel@tonic-gate " pm_power_has_changed failed for" 6287c478bd9Sstevel@tonic-gate " comp 1 to level %d", 6297c478bd9Sstevel@tonic-gate ddi_node_name(devi), 6307c478bd9Sstevel@tonic-gate ddi_get_instance(devi), 6317c478bd9Sstevel@tonic-gate MINPWR)); 6327c478bd9Sstevel@tonic-gate dstatep->level[1] = level_tmp; 6337c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 6347c478bd9Sstevel@tonic-gate 6357c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6367c478bd9Sstevel@tonic-gate } 6377c478bd9Sstevel@tonic-gate } 6387c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 6397c478bd9Sstevel@tonic-gate } 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate /* 6427c478bd9Sstevel@tonic-gate * If the LOWER_POWER_FLAG flag is not set, 6437c478bd9Sstevel@tonic-gate * don't call pm_lowr_power() for comp 0. 6447c478bd9Sstevel@tonic-gate * This should be used only for the XXXXX@XX,no_invol 6457c478bd9Sstevel@tonic-gate * devices that export the 6467c478bd9Sstevel@tonic-gate * no-involuntary-power-cycles property 6477c478bd9Sstevel@tonic-gate */ 6487c478bd9Sstevel@tonic-gate if (!(dstatep->flag & LOWER_POWER_FLAG) && 6497c478bd9Sstevel@tonic-gate dstatep->flag & PM_SUPPORTED_FLAG) { 6507c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "%s%d: DDI_DETACH:\n\t" 6517c478bd9Sstevel@tonic-gate " NOT CALLING PM_LOWER_POWER():" 6527c478bd9Sstevel@tonic-gate " LOWER_POWER_FLAG NOT SET\n", 6537c478bd9Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi)); 6547c478bd9Sstevel@tonic-gate } else if (dstatep->flag & PM_SUPPORTED_FLAG) { 6557c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 6567c478bd9Sstevel@tonic-gate "%s%d: DDI_DETACH: pm_lower_power comp 0 level %d", 6577c478bd9Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi), 6587c478bd9Sstevel@tonic-gate MINPWR)); 6597c478bd9Sstevel@tonic-gate if (pm_lower_power(dstatep->dip, 0, MINPWR) 6607c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 6617c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_DETACH:\n\t" 6627c478bd9Sstevel@tonic-gate "pm_lower_power failed for comp 0 to" 6637c478bd9Sstevel@tonic-gate " level %d\n", ddi_node_name(devi), 6647c478bd9Sstevel@tonic-gate ddi_get_instance(devi), MINPWR); 6657c478bd9Sstevel@tonic-gate 6667c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6677c478bd9Sstevel@tonic-gate } 6687c478bd9Sstevel@tonic-gate 6697c478bd9Sstevel@tonic-gate /* 6707c478bd9Sstevel@tonic-gate * check power level. Issue pm_power_has_changed 6717c478bd9Sstevel@tonic-gate * if not at MINPWR. 6727c478bd9Sstevel@tonic-gate */ 6737c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 6747c478bd9Sstevel@tonic-gate level_tmp = dstatep->level[0]; 6757c478bd9Sstevel@tonic-gate dstatep->level[0] = MINPWR; 6767c478bd9Sstevel@tonic-gate if (dstatep->level[0] != MINPWR) { 6777c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_NOTE, "%s%d: DDI_DETACH:" 6787c478bd9Sstevel@tonic-gate " power off via pm_power_has_changed" 6797c478bd9Sstevel@tonic-gate " instead", ddi_node_name(devi), 6807c478bd9Sstevel@tonic-gate ddi_get_instance(devi))); 6817c478bd9Sstevel@tonic-gate if (pm_power_has_changed(dstatep->dip, 6827c478bd9Sstevel@tonic-gate 0, MINPWR) != DDI_SUCCESS) { 6837c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_NOTE, "%s%d: DDI_DETACH:" 6847c478bd9Sstevel@tonic-gate " pm_power_has_changed failed for" 6857c478bd9Sstevel@tonic-gate " comp 0 to level %d", 6867c478bd9Sstevel@tonic-gate ddi_node_name(devi), 6877c478bd9Sstevel@tonic-gate ddi_get_instance(devi), 6887c478bd9Sstevel@tonic-gate MINPWR)); 6897c478bd9Sstevel@tonic-gate dstatep->level[0] = level_tmp; 6907c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 6937c478bd9Sstevel@tonic-gate } 6947c478bd9Sstevel@tonic-gate } 6957c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 6967c478bd9Sstevel@tonic-gate } 6977c478bd9Sstevel@tonic-gate 6987c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 6997c478bd9Sstevel@tonic-gate "%s%d detaching: n_devs=%d n_minorcomps=%d isclone=%d", 7007c478bd9Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi), 7017c478bd9Sstevel@tonic-gate n_devs, n_minorcomps, isclone)); 7027c478bd9Sstevel@tonic-gate 7037c478bd9Sstevel@tonic-gate for (i = 0; i < NUMEVENTS; i++) { 7047c478bd9Sstevel@tonic-gate if (dstatep->gen_cb_ids[i]) { 7057c478bd9Sstevel@tonic-gate (void) ddi_remove_event_handler(dstatep->gen_cb_ids[i]); 7067c478bd9Sstevel@tonic-gate dstatep->gen_cb_ids[i] = NULL; 7077c478bd9Sstevel@tonic-gate } 7087c478bd9Sstevel@tonic-gate } 7097c478bd9Sstevel@tonic-gate 7107c478bd9Sstevel@tonic-gate ddi_prop_remove_all(devi); 7117c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 7127c478bd9Sstevel@tonic-gate if (dstatep->node_type) 7137c478bd9Sstevel@tonic-gate kmem_free(dstatep->node_type, 7147c478bd9Sstevel@tonic-gate strlen(dstatep->node_type) + 1); 7157c478bd9Sstevel@tonic-gate ddi_soft_state_free(dstates, instance); 7167c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7177c478bd9Sstevel@tonic-gate 7187c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 7197c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND", 7207c478bd9Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi))); 7217c478bd9Sstevel@tonic-gate 7227c478bd9Sstevel@tonic-gate instance = ddi_get_instance(devi); 7237c478bd9Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, instance); 7247c478bd9Sstevel@tonic-gate if (dstatep == NULL) { 7257c478bd9Sstevel@tonic-gate 7267c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 7277c478bd9Sstevel@tonic-gate } 7287c478bd9Sstevel@tonic-gate 7297c478bd9Sstevel@tonic-gate /* 7307c478bd9Sstevel@tonic-gate * fail the suspend if FAIL_SUSPEND_FLAG is set. 7317c478bd9Sstevel@tonic-gate * clear the FAIL_SUSPEND_FLAG flag 7327c478bd9Sstevel@tonic-gate */ 7337c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 7347c478bd9Sstevel@tonic-gate if (dstatep->flag & FAIL_SUSPEND_FLAG) { 7357c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND:" 7367c478bd9Sstevel@tonic-gate " FAIL_SUSPEND_FLAG is set," 7377c478bd9Sstevel@tonic-gate " fail suspend", 7387c478bd9Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi))); 7397c478bd9Sstevel@tonic-gate dstatep->flag &= ~FAIL_SUSPEND_FLAG; 7407c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 7417c478bd9Sstevel@tonic-gate } else { 7427c478bd9Sstevel@tonic-gate rv = DDI_SUCCESS; 7437c478bd9Sstevel@tonic-gate } 7447c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 7457c478bd9Sstevel@tonic-gate 7467c478bd9Sstevel@tonic-gate /* 7477c478bd9Sstevel@tonic-gate * Issue ddi_removing_power() to determine if the suspend 7487c478bd9Sstevel@tonic-gate * was initiated by either CPR or DR. If CPR, the system 7497c478bd9Sstevel@tonic-gate * will be powered OFF; if this driver has set the 7507c478bd9Sstevel@tonic-gate * NO_INVOL_FLAG, then refuse to suspend. If DR, power 7517c478bd9Sstevel@tonic-gate * will not be removed, thus allow the suspend. 7527c478bd9Sstevel@tonic-gate */ 7537c478bd9Sstevel@tonic-gate if (dstatep->flag & NO_INVOL_FLAG && 7547c478bd9Sstevel@tonic-gate dstatep->flag & PM_SUPPORTED_FLAG) { 7557c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND:" 7567c478bd9Sstevel@tonic-gate " check via ddi_removing_power()", 7577c478bd9Sstevel@tonic-gate ddi_node_name(devi), ddi_get_instance(devi))); 7587c478bd9Sstevel@tonic-gate 7597c478bd9Sstevel@tonic-gate rm_power = ddi_removing_power(dstatep->dip); 7607c478bd9Sstevel@tonic-gate 7617c478bd9Sstevel@tonic-gate if (rm_power < 0) { 7627c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_SUSPEND:" 7637c478bd9Sstevel@tonic-gate " ddi_removing_power() failed\n", 7647c478bd9Sstevel@tonic-gate ddi_node_name(devi), 7657c478bd9Sstevel@tonic-gate ddi_get_instance(devi)); 7667c478bd9Sstevel@tonic-gate } else if (rm_power == 1) { 7677c478bd9Sstevel@tonic-gate /* 7687c478bd9Sstevel@tonic-gate * CPR: power will be removed 7697c478bd9Sstevel@tonic-gate */ 7707c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND:\n\t" 7717c478bd9Sstevel@tonic-gate " CPR: POWER WILL BE REMOVED, THEREFORE" 7727c478bd9Sstevel@tonic-gate " REFUSE TO SUSPEND", ddi_node_name(devi), 7737c478bd9Sstevel@tonic-gate ddi_get_instance(devi))); 7747c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 7757c478bd9Sstevel@tonic-gate } else if (rm_power == 0) { 7767c478bd9Sstevel@tonic-gate /* 7777c478bd9Sstevel@tonic-gate * DR: power will not be removed 7787c478bd9Sstevel@tonic-gate */ 7797c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DDI_SUSPEND:\n\t" 7807c478bd9Sstevel@tonic-gate " DR: POWER WILL NOT BE REMOVED, THEREFORE" 7817c478bd9Sstevel@tonic-gate " ALLOW THE SUSPEND", ddi_node_name(devi), 7827c478bd9Sstevel@tonic-gate ddi_get_instance(devi))); 7837c478bd9Sstevel@tonic-gate rv = DDI_SUCCESS; 7847c478bd9Sstevel@tonic-gate } 7857c478bd9Sstevel@tonic-gate } 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate /* 7887c478bd9Sstevel@tonic-gate * power OFF via pm_power_has_changed() 7897c478bd9Sstevel@tonic-gate */ 7907c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 7917c478bd9Sstevel@tonic-gate if (dstatep->flag & PM_SUPPORTED_FLAG && 7927c478bd9Sstevel@tonic-gate !(dstatep->flag & NO_INVOL_FLAG)) { 7937c478bd9Sstevel@tonic-gate level_tmp = dstatep->level[0]; 7947c478bd9Sstevel@tonic-gate dstatep->level[0] = MINPWR; 7957c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 7967c478bd9Sstevel@tonic-gate "%s%d: DDI_SUSPEND: pm_power_has_changed comp 0" 7977c478bd9Sstevel@tonic-gate " level %d", ddi_node_name(devi), 7987c478bd9Sstevel@tonic-gate ddi_get_instance(devi), MINPWR)); 7997c478bd9Sstevel@tonic-gate if (pm_power_has_changed(dstatep->dip, 0, MINPWR) 8007c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 8017c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_SUSPEND:\n\t" 8027c478bd9Sstevel@tonic-gate "pm_power_has_changed failed for comp 0 to" 8037c478bd9Sstevel@tonic-gate " level %d\n", ddi_node_name(devi), 8047c478bd9Sstevel@tonic-gate ddi_get_instance(devi), MINPWR); 8057c478bd9Sstevel@tonic-gate dstatep->level[0] = level_tmp; 8067c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 8077c478bd9Sstevel@tonic-gate 8087c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8097c478bd9Sstevel@tonic-gate } 8107c478bd9Sstevel@tonic-gate } 8117c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 8127c478bd9Sstevel@tonic-gate 8137c478bd9Sstevel@tonic-gate return (rv); 8147c478bd9Sstevel@tonic-gate 8157c478bd9Sstevel@tonic-gate default: 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8187c478bd9Sstevel@tonic-gate } 8197c478bd9Sstevel@tonic-gate } 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate /* ARGSUSED */ 8227c478bd9Sstevel@tonic-gate static int 8237c478bd9Sstevel@tonic-gate gen_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 8247c478bd9Sstevel@tonic-gate { 8257c478bd9Sstevel@tonic-gate dev_t dev; 8267c478bd9Sstevel@tonic-gate int instance; 8277c478bd9Sstevel@tonic-gate 8287c478bd9Sstevel@tonic-gate if (infocmd != DDI_INFO_DEVT2INSTANCE) 8297c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8307c478bd9Sstevel@tonic-gate 8317c478bd9Sstevel@tonic-gate dev = (dev_t)arg; 8327c478bd9Sstevel@tonic-gate instance = MINOR_TO_INST(getminor(dev)); 8337c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)instance; 8347c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8397c478bd9Sstevel@tonic-gate static int 8407c478bd9Sstevel@tonic-gate gen_open(dev_t *devp, int flag, int otyp, cred_t *cred) 8417c478bd9Sstevel@tonic-gate { 8427c478bd9Sstevel@tonic-gate minor_t minor; 8437c478bd9Sstevel@tonic-gate struct dstate *dstatep; 8447c478bd9Sstevel@tonic-gate 8457c478bd9Sstevel@tonic-gate if (otyp != OTYP_BLK && otyp != OTYP_CHR) 8467c478bd9Sstevel@tonic-gate return (EINVAL); 8477c478bd9Sstevel@tonic-gate 8487c478bd9Sstevel@tonic-gate minor = getminor(*devp); 8497c478bd9Sstevel@tonic-gate if ((dstatep = ddi_get_soft_state(dstates, 8507c478bd9Sstevel@tonic-gate MINOR_TO_INST(minor))) == NULL) 8517c478bd9Sstevel@tonic-gate return (ENXIO); 8527c478bd9Sstevel@tonic-gate 8537c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 8547c478bd9Sstevel@tonic-gate dstatep->flag |= OPEN_FLAG; 8557c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 8567c478bd9Sstevel@tonic-gate 8577c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 8587c478bd9Sstevel@tonic-gate "%s%d open", 8597c478bd9Sstevel@tonic-gate dstatep->nodename, MINOR_TO_INST(minor))); 8607c478bd9Sstevel@tonic-gate 8617c478bd9Sstevel@tonic-gate return (0); 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate 8647c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8657c478bd9Sstevel@tonic-gate static int 8667c478bd9Sstevel@tonic-gate gen_close(dev_t dev, int flag, int otyp, cred_t *cred) 8677c478bd9Sstevel@tonic-gate { 8687c478bd9Sstevel@tonic-gate struct dstate *dstatep; 8697c478bd9Sstevel@tonic-gate minor_t minor = getminor(dev); 8707c478bd9Sstevel@tonic-gate 8717c478bd9Sstevel@tonic-gate if (otyp != OTYP_BLK && otyp != OTYP_CHR) 8727c478bd9Sstevel@tonic-gate return (EINVAL); 8737c478bd9Sstevel@tonic-gate 8747c478bd9Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, MINOR_TO_INST(minor)); 8757c478bd9Sstevel@tonic-gate 8767c478bd9Sstevel@tonic-gate if (dstatep == NULL) 8777c478bd9Sstevel@tonic-gate return (ENXIO); 8787c478bd9Sstevel@tonic-gate 8797c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 8807c478bd9Sstevel@tonic-gate dstatep->flag &= ~OPEN_FLAG; 8817c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 8827c478bd9Sstevel@tonic-gate 8837c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, 8847c478bd9Sstevel@tonic-gate "%s%d close", 8857c478bd9Sstevel@tonic-gate dstatep->nodename, MINOR_TO_INST(minor))); 8867c478bd9Sstevel@tonic-gate 8877c478bd9Sstevel@tonic-gate return (0); 8887c478bd9Sstevel@tonic-gate } 8897c478bd9Sstevel@tonic-gate 8907c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 8917c478bd9Sstevel@tonic-gate static int 8927c478bd9Sstevel@tonic-gate gen_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, int *rvalp) 8937c478bd9Sstevel@tonic-gate { 8947c478bd9Sstevel@tonic-gate struct dstate *dstatep; 8957c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie; 8967c478bd9Sstevel@tonic-gate int instance; 8977c478bd9Sstevel@tonic-gate int rval = 0; 8987c478bd9Sstevel@tonic-gate char *nodename; 8997c478bd9Sstevel@tonic-gate int i; 9007c478bd9Sstevel@tonic-gate struct devctl_iocdata *dcp; 9017c478bd9Sstevel@tonic-gate uint_t state; 9027c478bd9Sstevel@tonic-gate int ret; 9037c478bd9Sstevel@tonic-gate int level_tmp; 9047c478bd9Sstevel@tonic-gate 9057c478bd9Sstevel@tonic-gate instance = MINOR_TO_INST(getminor(dev)); 9067c478bd9Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, instance); 9077c478bd9Sstevel@tonic-gate nodename = dstatep->nodename; 9087c478bd9Sstevel@tonic-gate 9097c478bd9Sstevel@tonic-gate if (dstatep == NULL) 9107c478bd9Sstevel@tonic-gate return (ENXIO); 9117c478bd9Sstevel@tonic-gate 9127c478bd9Sstevel@tonic-gate /* 9137c478bd9Sstevel@tonic-gate * read devctl ioctl data 9147c478bd9Sstevel@tonic-gate */ 9157c478bd9Sstevel@tonic-gate if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 9167c478bd9Sstevel@tonic-gate return (EFAULT); 9177c478bd9Sstevel@tonic-gate 9187c478bd9Sstevel@tonic-gate switch (cmd) { 9197c478bd9Sstevel@tonic-gate case GENDRV_IOFAULT_SIMULATE: 9207c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, DDI_DEVI_FAULT_EVENT, 9217c478bd9Sstevel@tonic-gate &(cookie)) != NDI_SUCCESS) 9227c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 9237c478bd9Sstevel@tonic-gate 9247c478bd9Sstevel@tonic-gate return (ndi_post_event(dstatep->dip, dstatep->dip, cookie, 9257c478bd9Sstevel@tonic-gate NULL)); 9267c478bd9Sstevel@tonic-gate 9277c478bd9Sstevel@tonic-gate case GENDRV_NDI_EVENT_TEST: 9287c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, "pshot_dev_offline", 9297c478bd9Sstevel@tonic-gate &cookie) == NDI_SUCCESS) { 9307c478bd9Sstevel@tonic-gate (void) ndi_post_event(dstatep->dip, dstatep->dip, 9317c478bd9Sstevel@tonic-gate cookie, NULL); 9327c478bd9Sstevel@tonic-gate } 9337c478bd9Sstevel@tonic-gate 9347c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, "pshot_dev_reset", 9357c478bd9Sstevel@tonic-gate &cookie) == NDI_SUCCESS) { 9367c478bd9Sstevel@tonic-gate (void) ndi_post_event(dstatep->dip, dstatep->dip, 9377c478bd9Sstevel@tonic-gate cookie, NULL); 9387c478bd9Sstevel@tonic-gate } 9397c478bd9Sstevel@tonic-gate 9407c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_reset", 9417c478bd9Sstevel@tonic-gate &cookie) == NDI_SUCCESS) { 9427c478bd9Sstevel@tonic-gate (void) ndi_post_event(dstatep->dip, dstatep->dip, 9437c478bd9Sstevel@tonic-gate cookie, NULL); 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate 9467c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_quiesce", 9477c478bd9Sstevel@tonic-gate &cookie) == NDI_SUCCESS) { 9487c478bd9Sstevel@tonic-gate (void) ndi_post_event(dstatep->dip, dstatep->dip, 9497c478bd9Sstevel@tonic-gate cookie, NULL); 9507c478bd9Sstevel@tonic-gate } 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_unquiesce", 9537c478bd9Sstevel@tonic-gate &cookie) == NDI_SUCCESS) { 9547c478bd9Sstevel@tonic-gate (void) ndi_post_event(dstatep->dip, dstatep->dip, 9557c478bd9Sstevel@tonic-gate cookie, NULL); 9567c478bd9Sstevel@tonic-gate } 9577c478bd9Sstevel@tonic-gate 9587c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(dstatep->dip, "pshot_bus_test_post", 9597c478bd9Sstevel@tonic-gate &cookie) == NDI_SUCCESS) { 9607c478bd9Sstevel@tonic-gate (void) ndi_post_event(dstatep->dip, dstatep->dip, 9617c478bd9Sstevel@tonic-gate cookie, NULL); 9627c478bd9Sstevel@tonic-gate } 9637c478bd9Sstevel@tonic-gate 9647c478bd9Sstevel@tonic-gate break; 9657c478bd9Sstevel@tonic-gate 9667c478bd9Sstevel@tonic-gate case DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME: 9677c478bd9Sstevel@tonic-gate /* 9687c478bd9Sstevel@tonic-gate * Issue pm_power_has_changed() call on DDI_RESUME 9697c478bd9Sstevel@tonic-gate */ 9707c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 9717c478bd9Sstevel@tonic-gate dstatep->flag |= PWR_HAS_CHANGED_ON_RESUME_FLAG; 9727c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 9737c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d:" 9747c478bd9Sstevel@tonic-gate " DEVCTL_PM_PWR_HAS_CHANGED_ON_RESUME", nodename, 9757c478bd9Sstevel@tonic-gate instance)); 9767c478bd9Sstevel@tonic-gate 9777c478bd9Sstevel@tonic-gate break; 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate case DEVCTL_PM_FAIL_SUSPEND: 9807c478bd9Sstevel@tonic-gate /* 9817c478bd9Sstevel@tonic-gate * Fail the suspend attempt in DDI_SUSPEND 9827c478bd9Sstevel@tonic-gate */ 9837c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 9847c478bd9Sstevel@tonic-gate dstatep->flag |= FAIL_SUSPEND_FLAG; 9857c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 9867c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_FAIL_SUSPEND", 9877c478bd9Sstevel@tonic-gate nodename, instance)); 9887c478bd9Sstevel@tonic-gate 9897c478bd9Sstevel@tonic-gate break; 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate case DEVCTL_PM_PUP_WITH_PWR_HAS_CHANGED: 9927c478bd9Sstevel@tonic-gate /* 9937c478bd9Sstevel@tonic-gate * Use pm_power_has_changed() to power up comp 0 when 9947c478bd9Sstevel@tonic-gate * enforcing the comp 0 vs comp-not 0 dependency: 9957c478bd9Sstevel@tonic-gate * Power up comp 0 first, if request for comp-not-0 9967c478bd9Sstevel@tonic-gate * comes in. 9977c478bd9Sstevel@tonic-gate * Else, default to pm_raise_power(). 9987c478bd9Sstevel@tonic-gate */ 9997c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 10007c478bd9Sstevel@tonic-gate dstatep->flag |= PUP_WITH_PWR_HAS_CHANGED_FLAG; 10017c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 10027c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_PUP_WITH_PWR_HAS_CHANGED", 10037c478bd9Sstevel@tonic-gate nodename, instance)); 10047c478bd9Sstevel@tonic-gate 10057c478bd9Sstevel@tonic-gate break; 10067c478bd9Sstevel@tonic-gate 10077c478bd9Sstevel@tonic-gate case DEVCTL_PM_BUSY_COMP: 10087c478bd9Sstevel@tonic-gate /* 10097c478bd9Sstevel@tonic-gate * mark component 0 busy via a pm_busy_component() call. 10107c478bd9Sstevel@tonic-gate * update the busy[] array. 10117c478bd9Sstevel@tonic-gate */ 10127c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 10137c478bd9Sstevel@tonic-gate ++dstatep->busy[0]; 10147c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_BUSY_COMP: comp 0:" 10157c478bd9Sstevel@tonic-gate " busy=%d", nodename, instance, dstatep->busy[0])); 10167c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 10177c478bd9Sstevel@tonic-gate ret = pm_busy_component(dstatep->dip, 0); 10187c478bd9Sstevel@tonic-gate ASSERT(ret == DDI_SUCCESS); 10197c478bd9Sstevel@tonic-gate 10207c478bd9Sstevel@tonic-gate break; 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate case DEVCTL_PM_BUSY_COMP_TEST: 10237c478bd9Sstevel@tonic-gate /* 10247c478bd9Sstevel@tonic-gate * test busy state on component 0 10257c478bd9Sstevel@tonic-gate */ 10267c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 10277c478bd9Sstevel@tonic-gate state = dstatep->busy[0]; 10287c478bd9Sstevel@tonic-gate if (copyout(&state, dcp->cpyout_buf, 10297c478bd9Sstevel@tonic-gate sizeof (uint_t)) != 0) { 10307c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d:" 10317c478bd9Sstevel@tonic-gate " DEVCTL_PM_BUSY_COMP_TEST: copyout failed\n", 10327c478bd9Sstevel@tonic-gate nodename, instance); 10337c478bd9Sstevel@tonic-gate rval = EINVAL; 10347c478bd9Sstevel@tonic-gate } 10357c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_BUSY_COMP_TEST:" 10367c478bd9Sstevel@tonic-gate " comp 0 busy %d", 10377c478bd9Sstevel@tonic-gate nodename, instance, state)); 10387c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 10397c478bd9Sstevel@tonic-gate 10407c478bd9Sstevel@tonic-gate break; 10417c478bd9Sstevel@tonic-gate 10427c478bd9Sstevel@tonic-gate case DEVCTL_PM_IDLE_COMP: 10437c478bd9Sstevel@tonic-gate /* 10447c478bd9Sstevel@tonic-gate * mark component 0 idle via a pm_idle_component() call. 10457c478bd9Sstevel@tonic-gate * NOP if dstatep->busy[0] == 0. 10467c478bd9Sstevel@tonic-gate */ 10477c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 10487c478bd9Sstevel@tonic-gate if (dstatep->busy[0] > 0) { 10497c478bd9Sstevel@tonic-gate --dstatep->busy[0]; 10507c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_IDLE_COMP:" 10517c478bd9Sstevel@tonic-gate " comp 0: busy=%d", nodename, instance, 10527c478bd9Sstevel@tonic-gate dstatep->busy[0])); 10537c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 10547c478bd9Sstevel@tonic-gate ret = pm_idle_component(dstatep->dip, 0); 10557c478bd9Sstevel@tonic-gate ASSERT(ret == DDI_SUCCESS); 10567c478bd9Sstevel@tonic-gate } else { 10577c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 10587c478bd9Sstevel@tonic-gate } 10597c478bd9Sstevel@tonic-gate 10607c478bd9Sstevel@tonic-gate break; 10617c478bd9Sstevel@tonic-gate 10627c478bd9Sstevel@tonic-gate case DEVCTL_PM_PROM_PRINTF: 10637c478bd9Sstevel@tonic-gate (void) prom_printf("%s%d: PROM_PRINTF FROM GEN_DRV\n", 10647c478bd9Sstevel@tonic-gate nodename, instance); 10657c478bd9Sstevel@tonic-gate 10667c478bd9Sstevel@tonic-gate break; 10677c478bd9Sstevel@tonic-gate 10687c478bd9Sstevel@tonic-gate case DEVCTL_PM_RAISE_PWR: 10697c478bd9Sstevel@tonic-gate /* 10707c478bd9Sstevel@tonic-gate * power up both components to MAXPWR via 10717c478bd9Sstevel@tonic-gate * pm_raise_power() calls. this ioctl() cmd 10727c478bd9Sstevel@tonic-gate * assumes that the current level is 0 10737c478bd9Sstevel@tonic-gate */ 10747c478bd9Sstevel@tonic-gate for (i = 0; i < COMPONENTS; i++) { 10757c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_RAISE_PWR:" 10767c478bd9Sstevel@tonic-gate " comp %d old 0 new %d", 10777c478bd9Sstevel@tonic-gate nodename, instance, i, maxpwr[i])); 10787c478bd9Sstevel@tonic-gate if (pm_raise_power(dstatep->dip, 0, maxpwr[i]) 10797c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 10807c478bd9Sstevel@tonic-gate rval = EINVAL; 10817c478bd9Sstevel@tonic-gate } 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate break; 10857c478bd9Sstevel@tonic-gate 10867c478bd9Sstevel@tonic-gate case DEVCTL_PM_CHANGE_PWR_LOW: 10877c478bd9Sstevel@tonic-gate /* 10887c478bd9Sstevel@tonic-gate * power off both components via pm_power_has_changed() calls 10897c478bd9Sstevel@tonic-gate */ 10907c478bd9Sstevel@tonic-gate for (i = (COMPONENTS - 1); i >= 0; --i) { 10917c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_CHANGE_PWR_LOW:" 10927c478bd9Sstevel@tonic-gate " comp %d new 0", 10937c478bd9Sstevel@tonic-gate nodename, instance, i)); 10947c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 10957c478bd9Sstevel@tonic-gate level_tmp = dstatep->level[i]; 10967c478bd9Sstevel@tonic-gate dstatep->level[i] = 0; 10977c478bd9Sstevel@tonic-gate if (pm_power_has_changed(dstatep->dip, i, 0) 10987c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 10997c478bd9Sstevel@tonic-gate dstatep->level[i] = level_tmp; 11007c478bd9Sstevel@tonic-gate rval = EINVAL; 11017c478bd9Sstevel@tonic-gate } 11027c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 11037c478bd9Sstevel@tonic-gate } 11047c478bd9Sstevel@tonic-gate 11057c478bd9Sstevel@tonic-gate break; 11067c478bd9Sstevel@tonic-gate 11077c478bd9Sstevel@tonic-gate case DEVCTL_PM_CHANGE_PWR_HIGH: 11087c478bd9Sstevel@tonic-gate /* 11097c478bd9Sstevel@tonic-gate * power up both components to MAXPWR via 11107c478bd9Sstevel@tonic-gate * pm_power_has_changed() calls 11117c478bd9Sstevel@tonic-gate */ 11127c478bd9Sstevel@tonic-gate for (i = 0; i < COMPONENTS; i++) { 11137c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_CHANGE_PWR_HIGH:" 11147c478bd9Sstevel@tonic-gate " comp %d new %d", 11157c478bd9Sstevel@tonic-gate nodename, instance, i, maxpwr[i])); 11167c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 11177c478bd9Sstevel@tonic-gate level_tmp = dstatep->level[i]; 11187c478bd9Sstevel@tonic-gate dstatep->level[i] = maxpwr[i]; 11197c478bd9Sstevel@tonic-gate if (pm_power_has_changed(dstatep->dip, i, maxpwr[i]) 11207c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 11217c478bd9Sstevel@tonic-gate dstatep->level[i] = level_tmp; 11227c478bd9Sstevel@tonic-gate rval = EINVAL; 11237c478bd9Sstevel@tonic-gate } 11247c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 11257c478bd9Sstevel@tonic-gate } 11267c478bd9Sstevel@tonic-gate 11277c478bd9Sstevel@tonic-gate break; 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate case DEVCTL_PM_POWER: 11307c478bd9Sstevel@tonic-gate /* 11317c478bd9Sstevel@tonic-gate * test if the gen_drv_power() routine has been called, 11327c478bd9Sstevel@tonic-gate * then clear 11337c478bd9Sstevel@tonic-gate */ 11347c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 11357c478bd9Sstevel@tonic-gate state = (dstatep->flag & POWER_FLAG) ? 1 : 0; 11367c478bd9Sstevel@tonic-gate if (copyout(&state, dcp->cpyout_buf, 11377c478bd9Sstevel@tonic-gate sizeof (uint_t)) != 0) { 11387c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DEVCTL_PM_POWER:" 11397c478bd9Sstevel@tonic-gate " copyout failed\n", nodename, instance); 11407c478bd9Sstevel@tonic-gate rval = EINVAL; 11417c478bd9Sstevel@tonic-gate } 11427c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: %s POWER_FLAG: %d", 11437c478bd9Sstevel@tonic-gate nodename, instance, "DEVCTL_PM_POWER", state)); 11447c478bd9Sstevel@tonic-gate dstatep->flag &= ~POWER_FLAG; 11457c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 11467c478bd9Sstevel@tonic-gate break; 11477c478bd9Sstevel@tonic-gate 11487c478bd9Sstevel@tonic-gate case DEVCTL_PM_NO_LOWER_POWER: 11497c478bd9Sstevel@tonic-gate /* 11507c478bd9Sstevel@tonic-gate * issue to not invoke pm_lower_power() on detach 11517c478bd9Sstevel@tonic-gate */ 11527c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 11537c478bd9Sstevel@tonic-gate dstatep->flag &= ~LOWER_POWER_FLAG; 11547c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 11557c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: DEVCTL_PM_NO_LOWER_POWER", 11567c478bd9Sstevel@tonic-gate nodename, instance)); 11577c478bd9Sstevel@tonic-gate break; 11587c478bd9Sstevel@tonic-gate 11597c478bd9Sstevel@tonic-gate default: 11607c478bd9Sstevel@tonic-gate return (ENOTTY); 11617c478bd9Sstevel@tonic-gate } 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate return (rval); 11647c478bd9Sstevel@tonic-gate } 11657c478bd9Sstevel@tonic-gate 11667c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11677c478bd9Sstevel@tonic-gate static int 11687c478bd9Sstevel@tonic-gate gen_read(dev_t dev, struct uio *uiop, cred_t *credp) 11697c478bd9Sstevel@tonic-gate { 11707c478bd9Sstevel@tonic-gate return (0); 11717c478bd9Sstevel@tonic-gate } 11727c478bd9Sstevel@tonic-gate 11737c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 11747c478bd9Sstevel@tonic-gate static int 11757c478bd9Sstevel@tonic-gate gen_write(dev_t dev, struct uio *uiop, cred_t *credp) 11767c478bd9Sstevel@tonic-gate { 11777c478bd9Sstevel@tonic-gate return (0); 11787c478bd9Sstevel@tonic-gate } 11797c478bd9Sstevel@tonic-gate 11807c478bd9Sstevel@tonic-gate /*ARGSUSED0*/ 11817c478bd9Sstevel@tonic-gate static int 11827c478bd9Sstevel@tonic-gate gen_power(dev_info_t *dip, int cmpt, int level) 11837c478bd9Sstevel@tonic-gate { 11847c478bd9Sstevel@tonic-gate struct dstate *dstatep; 11857c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 11867c478bd9Sstevel@tonic-gate char *nodename = ddi_node_name(dip); 11877c478bd9Sstevel@tonic-gate int level_tmp; 11887c478bd9Sstevel@tonic-gate 11897c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: power: cmpt %d to level %d", 11907c478bd9Sstevel@tonic-gate nodename, instance, cmpt, level)); 11917c478bd9Sstevel@tonic-gate 11927c478bd9Sstevel@tonic-gate dstatep = ddi_get_soft_state(dstates, instance); 11937c478bd9Sstevel@tonic-gate if (dstatep == NULL) { 11947c478bd9Sstevel@tonic-gate 11957c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11967c478bd9Sstevel@tonic-gate } 11977c478bd9Sstevel@tonic-gate 11987c478bd9Sstevel@tonic-gate /* 11997c478bd9Sstevel@tonic-gate * Keep track of the power levels for both components 12007c478bd9Sstevel@tonic-gate * in the dstatep->comp[] array. 12017c478bd9Sstevel@tonic-gate * Set comp 0 to full level if non-zero comps 12027c478bd9Sstevel@tonic-gate * are being set to a higher, non-zero level. 12037c478bd9Sstevel@tonic-gate */ 12047c478bd9Sstevel@tonic-gate if (cmpt == 0) { 12057c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 12067c478bd9Sstevel@tonic-gate dstatep->level[cmpt] = level; 12077c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 12087c478bd9Sstevel@tonic-gate } else if (level > dstatep->level[cmpt] && level != 0 && 12097c478bd9Sstevel@tonic-gate dstatep->level[0] != COMP_0_MAXPWR) { 12107c478bd9Sstevel@tonic-gate /* 12117c478bd9Sstevel@tonic-gate * If component 0 is not at COMP_0_MAXPWR, and component 1 12127c478bd9Sstevel@tonic-gate * is being powered ON, invoke pm_raise_power() or 12137c478bd9Sstevel@tonic-gate * pm_power_has_changed() based on the 12147c478bd9Sstevel@tonic-gate * PUP_WITH_PWR_HAS_CHANGED_FLAG flag. 12157c478bd9Sstevel@tonic-gate * PUP_WITH_PWR_HAS_CHANGED_FLAG = FALSE by default, invoking 12167c478bd9Sstevel@tonic-gate * pm_raise_power(). 12177c478bd9Sstevel@tonic-gate */ 12187c478bd9Sstevel@tonic-gate if (!(dstatep->flag & PUP_WITH_PWR_HAS_CHANGED_FLAG)) { 12197c478bd9Sstevel@tonic-gate /* 12207c478bd9Sstevel@tonic-gate * first set comp 0 to level COMP_0_MAXPWR 12217c478bd9Sstevel@tonic-gate */ 12227c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: power: " 12237c478bd9Sstevel@tonic-gate "pm_raise_power: comp 0 to level %d", 12247c478bd9Sstevel@tonic-gate nodename, instance, COMP_0_MAXPWR)); 12257c478bd9Sstevel@tonic-gate if (pm_raise_power(dip, 0, COMP_0_MAXPWR) != 12267c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 12277c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 12287c478bd9Sstevel@tonic-gate "%s%d: power: pm_raise_power() " 12297c478bd9Sstevel@tonic-gate "failed: comp 0 to level %d\n", 12307c478bd9Sstevel@tonic-gate nodename, instance, COMP_0_MAXPWR); 12317c478bd9Sstevel@tonic-gate 12327c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 12337c478bd9Sstevel@tonic-gate 12347c478bd9Sstevel@tonic-gate } else { 12357c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 12367c478bd9Sstevel@tonic-gate dstatep->level[0] = COMP_0_MAXPWR; 12377c478bd9Sstevel@tonic-gate /* 12387c478bd9Sstevel@tonic-gate * now set the level on the non-zero comp 12397c478bd9Sstevel@tonic-gate */ 12407c478bd9Sstevel@tonic-gate dstatep->level[cmpt] = level; 12417c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 12427c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: power: " 12437c478bd9Sstevel@tonic-gate "comp %d to level %d", 12447c478bd9Sstevel@tonic-gate nodename, instance, cmpt, level)); 12457c478bd9Sstevel@tonic-gate } 12467c478bd9Sstevel@tonic-gate } else { 12477c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: power: " 12487c478bd9Sstevel@tonic-gate "pm_power_has_changed: comp 0 to level %d", 12497c478bd9Sstevel@tonic-gate nodename, instance, COMP_0_MAXPWR)); 12507c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 12517c478bd9Sstevel@tonic-gate level_tmp = dstatep->level[0]; 12527c478bd9Sstevel@tonic-gate dstatep->level[0] = COMP_0_MAXPWR; 12537c478bd9Sstevel@tonic-gate if (pm_power_has_changed(dip, 0, COMP_0_MAXPWR) != 12547c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 12557c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 12567c478bd9Sstevel@tonic-gate "%s%d: power: pm_power_has_changed() " 12577c478bd9Sstevel@tonic-gate "failed: comp 0 to level %d\n", 12587c478bd9Sstevel@tonic-gate nodename, instance, COMP_0_MAXPWR); 12597c478bd9Sstevel@tonic-gate dstatep->level[0] = level_tmp; 12607c478bd9Sstevel@tonic-gate } else { 12617c478bd9Sstevel@tonic-gate /* 12627c478bd9Sstevel@tonic-gate * now set the level on the non-zero comp 12637c478bd9Sstevel@tonic-gate */ 12647c478bd9Sstevel@tonic-gate GEN_DEBUG((CE_CONT, "%s%d: power:" 12657c478bd9Sstevel@tonic-gate " pm_power_has_changed: comp %d" 12667c478bd9Sstevel@tonic-gate " to level %d", nodename, instance, 12677c478bd9Sstevel@tonic-gate cmpt, level)); 12687c478bd9Sstevel@tonic-gate dstatep->level[cmpt] = level; 12697c478bd9Sstevel@tonic-gate } 12707c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 12717c478bd9Sstevel@tonic-gate } 12727c478bd9Sstevel@tonic-gate } else { 12737c478bd9Sstevel@tonic-gate mutex_enter(&dstatep->lock); 12747c478bd9Sstevel@tonic-gate dstatep->level[cmpt] = level; 12757c478bd9Sstevel@tonic-gate mutex_exit(&dstatep->lock); 12767c478bd9Sstevel@tonic-gate } 12777c478bd9Sstevel@tonic-gate 12787c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 12797c478bd9Sstevel@tonic-gate } 12807c478bd9Sstevel@tonic-gate 12817c478bd9Sstevel@tonic-gate 12827c478bd9Sstevel@tonic-gate /* 12837c478bd9Sstevel@tonic-gate * Create properties of various data types for testing devfs events. 12847c478bd9Sstevel@tonic-gate */ 12857c478bd9Sstevel@tonic-gate static int 12867c478bd9Sstevel@tonic-gate gen_create_properties(dev_info_t *devi) 12877c478bd9Sstevel@tonic-gate { 12887c478bd9Sstevel@tonic-gate int int_val = 3023; 12897c478bd9Sstevel@tonic-gate int int_array[] = { 3, 10, 304, 230, 4}; 12907c478bd9Sstevel@tonic-gate int64_t int64_val = 20; 12917c478bd9Sstevel@tonic-gate int64_t int64_array[] = { 12, 24, 36, 48}; 12927c478bd9Sstevel@tonic-gate char *string_val = "Dev_node_prop"; 12937c478bd9Sstevel@tonic-gate char *string_array[] = {"Dev_node_prop:0", 12947c478bd9Sstevel@tonic-gate "Dev_node_prop:1", "Dev_node_prop:2", "Dev_node_prop:3"}; 12957c478bd9Sstevel@tonic-gate uchar_t byte_array[] = { (uchar_t)0xaa, (uchar_t)0x55, 12967c478bd9Sstevel@tonic-gate (uchar_t)0x12, (uchar_t)0xcd }; 12977c478bd9Sstevel@tonic-gate char bytes[] = { (char)0x00, (char)0xef, (char)0xff }; 12987c478bd9Sstevel@tonic-gate 12997c478bd9Sstevel@tonic-gate if (ddi_prop_update_int(DDI_DEV_T_NONE, devi, "int", int_val) 13007c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) 13017c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate if (ddi_prop_update_int_array(DDI_DEV_T_NONE, devi, "int-array", 13047c478bd9Sstevel@tonic-gate int_array, sizeof (int_array) / sizeof (int)) != DDI_PROP_SUCCESS) 13057c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13067c478bd9Sstevel@tonic-gate 13077c478bd9Sstevel@tonic-gate if (ddi_prop_update_int64(DDI_DEV_T_NONE, devi, "int64", int64_val) 13087c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) 13097c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13107c478bd9Sstevel@tonic-gate 13117c478bd9Sstevel@tonic-gate if (ddi_prop_update_int64_array(DDI_DEV_T_NONE, devi, "int64-array", 13127c478bd9Sstevel@tonic-gate int64_array, sizeof (int64_array) / sizeof (int64_t)) 13137c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) 13147c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13157c478bd9Sstevel@tonic-gate 13167c478bd9Sstevel@tonic-gate if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, "string", string_val) 13177c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) 13187c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi, "string-array", 13217c478bd9Sstevel@tonic-gate string_array, sizeof (string_array) / sizeof (char *)) 13227c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) 13237c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13247c478bd9Sstevel@tonic-gate 13257c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP, 13267c478bd9Sstevel@tonic-gate "boolean", NULL, 0) != DDI_PROP_SUCCESS) 13277c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13287c478bd9Sstevel@tonic-gate 13297c478bd9Sstevel@tonic-gate if (ddi_prop_update_byte_array(DDI_DEV_T_NONE, devi, "byte-array", 13307c478bd9Sstevel@tonic-gate byte_array, sizeof (byte_array)) != DDI_PROP_SUCCESS) 13317c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13327c478bd9Sstevel@tonic-gate 13337c478bd9Sstevel@tonic-gate /* untyped property */ 13347c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP, "untyped", 13357c478bd9Sstevel@tonic-gate (caddr_t)bytes, sizeof (bytes)) != DDI_PROP_SUCCESS) 13367c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13377c478bd9Sstevel@tonic-gate 13387c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 13397c478bd9Sstevel@tonic-gate } 13407c478bd9Sstevel@tonic-gate 13417c478bd9Sstevel@tonic-gate static struct driver_minor_data { 13427c478bd9Sstevel@tonic-gate char *name; 13437c478bd9Sstevel@tonic-gate minor_t minor; 13447c478bd9Sstevel@tonic-gate int type; 13457c478bd9Sstevel@tonic-gate } disk_minor_data[] = { 13467c478bd9Sstevel@tonic-gate {"a", 0, S_IFBLK}, 13477c478bd9Sstevel@tonic-gate {"b", 1, S_IFBLK}, 13487c478bd9Sstevel@tonic-gate {"c", 2, S_IFBLK}, 13497c478bd9Sstevel@tonic-gate {"d", 3, S_IFBLK}, 13507c478bd9Sstevel@tonic-gate {"e", 4, S_IFBLK}, 13517c478bd9Sstevel@tonic-gate {"f", 5, S_IFBLK}, 13527c478bd9Sstevel@tonic-gate {"g", 6, S_IFBLK}, 13537c478bd9Sstevel@tonic-gate {"h", 7, S_IFBLK}, 13547c478bd9Sstevel@tonic-gate {"a,raw", 0, S_IFCHR}, 13557c478bd9Sstevel@tonic-gate {"b,raw", 1, S_IFCHR}, 13567c478bd9Sstevel@tonic-gate {"c,raw", 2, S_IFCHR}, 13577c478bd9Sstevel@tonic-gate {"d,raw", 3, S_IFCHR}, 13587c478bd9Sstevel@tonic-gate {"e,raw", 4, S_IFCHR}, 13597c478bd9Sstevel@tonic-gate {"f,raw", 5, S_IFCHR}, 13607c478bd9Sstevel@tonic-gate {"g,raw", 6, S_IFCHR}, 13617c478bd9Sstevel@tonic-gate {"h,raw", 7, S_IFCHR}, 13627c478bd9Sstevel@tonic-gate {0} 13637c478bd9Sstevel@tonic-gate }; 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate 13667c478bd9Sstevel@tonic-gate static struct driver_serial_minor_data { 13677c478bd9Sstevel@tonic-gate char *name; 13687c478bd9Sstevel@tonic-gate minor_t minor; 13697c478bd9Sstevel@tonic-gate int type; 13707c478bd9Sstevel@tonic-gate char *node_type; 13717c478bd9Sstevel@tonic-gate } serial_minor_data[] = { 13727c478bd9Sstevel@tonic-gate {"0", 0, S_IFCHR, "ddi_serial"}, 13737c478bd9Sstevel@tonic-gate {"1", 1, S_IFCHR, "ddi_serial"}, 13747c478bd9Sstevel@tonic-gate {"0,cu", 2, S_IFCHR, "ddi_serial:dialout"}, 13757c478bd9Sstevel@tonic-gate {"1,cu", 3, S_IFCHR, "ddi_serial:dialout"}, 13767c478bd9Sstevel@tonic-gate {0} 13777c478bd9Sstevel@tonic-gate }; 13787c478bd9Sstevel@tonic-gate 13797c478bd9Sstevel@tonic-gate 13807c478bd9Sstevel@tonic-gate static int 13817c478bd9Sstevel@tonic-gate gen_create_display(dev_info_t *devi) 13827c478bd9Sstevel@tonic-gate { 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(devi); 13857c478bd9Sstevel@tonic-gate char minor_name[15]; 13867c478bd9Sstevel@tonic-gate 13877c478bd9Sstevel@tonic-gate (void) sprintf(minor_name, "cgtwenty%d", instance); 13887c478bd9Sstevel@tonic-gate 13897c478bd9Sstevel@tonic-gate return (ddi_create_minor_node(devi, minor_name, S_IFCHR, 13907c478bd9Sstevel@tonic-gate INST_TO_MINOR(instance), DDI_NT_DISPLAY, NULL)); 13917c478bd9Sstevel@tonic-gate } 13927c478bd9Sstevel@tonic-gate 13937c478bd9Sstevel@tonic-gate static int 13947c478bd9Sstevel@tonic-gate gen_create_mn_disk_chan(dev_info_t *devi) 13957c478bd9Sstevel@tonic-gate { 13967c478bd9Sstevel@tonic-gate struct driver_minor_data *dmdp; 13977c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(devi); 13987c478bd9Sstevel@tonic-gate 13997c478bd9Sstevel@tonic-gate if (gen_create_properties(devi) != DDI_SUCCESS) 14007c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14017c478bd9Sstevel@tonic-gate 14027c478bd9Sstevel@tonic-gate for (dmdp = disk_minor_data; dmdp->name != NULL; dmdp++) { 14037c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, dmdp->name, dmdp->type, 14047c478bd9Sstevel@tonic-gate (INST_TO_MINOR(instance)) | dmdp->minor, 14057c478bd9Sstevel@tonic-gate DDI_NT_BLOCK_CHAN, NULL) != DDI_SUCCESS) { 14067c478bd9Sstevel@tonic-gate 14077c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14087c478bd9Sstevel@tonic-gate } 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate 14137c478bd9Sstevel@tonic-gate static uint_t 14147c478bd9Sstevel@tonic-gate atod(char *s) 14157c478bd9Sstevel@tonic-gate { 14167c478bd9Sstevel@tonic-gate uint_t val = 0; 14177c478bd9Sstevel@tonic-gate uint_t digit; 14187c478bd9Sstevel@tonic-gate 14197c478bd9Sstevel@tonic-gate while (*s) { 14207c478bd9Sstevel@tonic-gate if (*s >= '0' && *s <= '9') 14217c478bd9Sstevel@tonic-gate digit = *s++ - '0'; 14227c478bd9Sstevel@tonic-gate else 14237c478bd9Sstevel@tonic-gate break; 14247c478bd9Sstevel@tonic-gate val = (val * 10) + digit; 14257c478bd9Sstevel@tonic-gate } 14267c478bd9Sstevel@tonic-gate return (val); 14277c478bd9Sstevel@tonic-gate } 14287c478bd9Sstevel@tonic-gate 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate static int 14317c478bd9Sstevel@tonic-gate gen_create_mn_disk_wwn(dev_info_t *devi) 14327c478bd9Sstevel@tonic-gate { 14337c478bd9Sstevel@tonic-gate struct driver_minor_data *dmdp; 14347c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(devi); 14357c478bd9Sstevel@tonic-gate char *address = ddi_get_name_addr(devi); 14367c478bd9Sstevel@tonic-gate int target, lun; 14377c478bd9Sstevel@tonic-gate 14387c478bd9Sstevel@tonic-gate if (address[0] >= '0' && address[0] <= '9' && 14397c478bd9Sstevel@tonic-gate strchr(address, ',')) { 14407c478bd9Sstevel@tonic-gate target = atod(address); 14417c478bd9Sstevel@tonic-gate address = strchr(address, ','); 14427c478bd9Sstevel@tonic-gate lun = atod(++address); 14437c478bd9Sstevel@tonic-gate } else { /* this hack is for rm_stale_link() testing */ 14447c478bd9Sstevel@tonic-gate target = 10; 14457c478bd9Sstevel@tonic-gate lun = 5; 14467c478bd9Sstevel@tonic-gate } 14477c478bd9Sstevel@tonic-gate 14487c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP, 14497c478bd9Sstevel@tonic-gate "target", (caddr_t)&target, sizeof (int)) 14507c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 14517c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14527c478bd9Sstevel@tonic-gate } 14537c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, devi, DDI_PROP_CANSLEEP, 14547c478bd9Sstevel@tonic-gate "lun", (caddr_t)&lun, sizeof (int)) 14557c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 14567c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14577c478bd9Sstevel@tonic-gate } 14587c478bd9Sstevel@tonic-gate 14597c478bd9Sstevel@tonic-gate for (dmdp = disk_minor_data; dmdp->name != NULL; dmdp++) { 14607c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, dmdp->name, dmdp->type, 14617c478bd9Sstevel@tonic-gate (INST_TO_MINOR(instance)) | dmdp->minor, 14627c478bd9Sstevel@tonic-gate DDI_NT_BLOCK_WWN, NULL) != DDI_SUCCESS) { 14637c478bd9Sstevel@tonic-gate 14647c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14657c478bd9Sstevel@tonic-gate } 14667c478bd9Sstevel@tonic-gate } 14677c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 14687c478bd9Sstevel@tonic-gate } 14697c478bd9Sstevel@tonic-gate 14707c478bd9Sstevel@tonic-gate static int 14717c478bd9Sstevel@tonic-gate gen_create_mn_disk_cdrom(dev_info_t *devi) 14727c478bd9Sstevel@tonic-gate { 14737c478bd9Sstevel@tonic-gate struct driver_minor_data *dmdp; 14747c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(devi); 14757c478bd9Sstevel@tonic-gate 14767c478bd9Sstevel@tonic-gate for (dmdp = disk_minor_data; dmdp->name != NULL; dmdp++) { 14777c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, dmdp->name, dmdp->type, 14787c478bd9Sstevel@tonic-gate (INST_TO_MINOR(instance)) | dmdp->minor, 14797c478bd9Sstevel@tonic-gate DDI_NT_CD_CHAN, NULL) != DDI_SUCCESS) { 14807c478bd9Sstevel@tonic-gate 14817c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14827c478bd9Sstevel@tonic-gate } 14837c478bd9Sstevel@tonic-gate } 14847c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 14857c478bd9Sstevel@tonic-gate } 14867c478bd9Sstevel@tonic-gate 14877c478bd9Sstevel@tonic-gate static int 14887c478bd9Sstevel@tonic-gate gen_create_mn_disk_fd(dev_info_t *devi) 14897c478bd9Sstevel@tonic-gate { 14907c478bd9Sstevel@tonic-gate struct driver_minor_data *dmdp; 14917c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(devi); 14927c478bd9Sstevel@tonic-gate 14937c478bd9Sstevel@tonic-gate for (dmdp = disk_minor_data; dmdp->name != NULL; dmdp++) { 14947c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, dmdp->name, dmdp->type, 14957c478bd9Sstevel@tonic-gate (INST_TO_MINOR(instance)) | dmdp->minor, 14967c478bd9Sstevel@tonic-gate DDI_NT_BLOCK_CHAN, NULL) != DDI_SUCCESS) { 14977c478bd9Sstevel@tonic-gate 14987c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 14997c478bd9Sstevel@tonic-gate } 15007c478bd9Sstevel@tonic-gate } 15017c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 15027c478bd9Sstevel@tonic-gate } 15037c478bd9Sstevel@tonic-gate 15047c478bd9Sstevel@tonic-gate static int 15057c478bd9Sstevel@tonic-gate gen_create_serial(dev_info_t *devi) 15067c478bd9Sstevel@tonic-gate { 15077c478bd9Sstevel@tonic-gate struct driver_serial_minor_data *dmdp; 15087c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(devi); 15097c478bd9Sstevel@tonic-gate 15107c478bd9Sstevel@tonic-gate for (dmdp = serial_minor_data; dmdp->name != NULL; dmdp++) { 15117c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, dmdp->name, dmdp->type, 15127c478bd9Sstevel@tonic-gate (INST_TO_MINOR(instance)) | dmdp->minor, 15137c478bd9Sstevel@tonic-gate dmdp->node_type, NULL) != DDI_SUCCESS) { 15147c478bd9Sstevel@tonic-gate 15157c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15167c478bd9Sstevel@tonic-gate } 15177c478bd9Sstevel@tonic-gate } 15187c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 15197c478bd9Sstevel@tonic-gate } 15207c478bd9Sstevel@tonic-gate 15217c478bd9Sstevel@tonic-gate static int 15227c478bd9Sstevel@tonic-gate gen_create_net(dev_info_t *devi) 15237c478bd9Sstevel@tonic-gate { 15247c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(devi); 15257c478bd9Sstevel@tonic-gate char minorname[32]; 15267c478bd9Sstevel@tonic-gate 15277c478bd9Sstevel@tonic-gate if (gen_create_properties(devi) != DDI_SUCCESS) 15287c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15297c478bd9Sstevel@tonic-gate 15307c478bd9Sstevel@tonic-gate (void) snprintf(minorname, sizeof (minorname), "gen_drv%d", instance); 15317c478bd9Sstevel@tonic-gate return (ddi_create_minor_node(devi, minorname, S_IFCHR, 15327c478bd9Sstevel@tonic-gate INST_TO_MINOR(instance), DDI_NT_NET, 0)); 15337c478bd9Sstevel@tonic-gate } 15347c478bd9Sstevel@tonic-gate 15357c478bd9Sstevel@tonic-gate static int 15367c478bd9Sstevel@tonic-gate gen_create_minor_nodes(dev_info_t *devi, struct dstate *dstatep) 15377c478bd9Sstevel@tonic-gate { 15387c478bd9Sstevel@tonic-gate int rval = DDI_SUCCESS; 15397c478bd9Sstevel@tonic-gate char *node_name; 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate node_name = ddi_node_name(devi); 15427c478bd9Sstevel@tonic-gate 15437c478bd9Sstevel@tonic-gate if (strcmp(node_name, "disk_chan") == 0) { 15447c478bd9Sstevel@tonic-gate rval = gen_create_mn_disk_chan(devi); 15457c478bd9Sstevel@tonic-gate } else if (strcmp(node_name, "disk_wwn") == 0) { 15467c478bd9Sstevel@tonic-gate rval = gen_create_mn_disk_wwn(devi); 15477c478bd9Sstevel@tonic-gate } else if (strcmp(node_name, "disk_cdrom") == 0) { 15487c478bd9Sstevel@tonic-gate rval = gen_create_mn_disk_cdrom(devi); 15497c478bd9Sstevel@tonic-gate } else if (strcmp(node_name, "disk_fd") == 0) { 15507c478bd9Sstevel@tonic-gate rval = gen_create_mn_disk_fd(devi); 15517c478bd9Sstevel@tonic-gate } else if (strcmp(node_name, "cgtwenty") == 0) { 15527c478bd9Sstevel@tonic-gate rval = gen_create_display(devi); 15537c478bd9Sstevel@tonic-gate } else if (strcmp(node_name, "genzs") == 0) { 15547c478bd9Sstevel@tonic-gate rval = gen_create_serial(devi); 15557c478bd9Sstevel@tonic-gate } else if (strcmp(node_name, "net") == 0) { 15567c478bd9Sstevel@tonic-gate rval = gen_create_net(devi); 15577c478bd9Sstevel@tonic-gate } else { 15587c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(devi); 15597c478bd9Sstevel@tonic-gate char *node_type; 15607c478bd9Sstevel@tonic-gate 15617c478bd9Sstevel@tonic-gate /* 15627c478bd9Sstevel@tonic-gate * Solaris may directly hang the node_type off the minor node 15637c478bd9Sstevel@tonic-gate * (without making a copy). Since we free the node_type 15647c478bd9Sstevel@tonic-gate * property below we need to make a private copy to pass 15657c478bd9Sstevel@tonic-gate * to ddi_create_minor_node to avoid devinfo snapshot panics. 15667c478bd9Sstevel@tonic-gate * We store a pointer to our copy in dstate and free it in 15677c478bd9Sstevel@tonic-gate * gen_detach after the minor nodes have been deleted by 15687c478bd9Sstevel@tonic-gate * ddi_remove_minor_node. 15697c478bd9Sstevel@tonic-gate */ 15707c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 15717c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "node-type", &node_type) != 0) { 15727c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "couldn't get node-type\n"); 15737c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15747c478bd9Sstevel@tonic-gate } 15757c478bd9Sstevel@tonic-gate if (node_type) { 15767c478bd9Sstevel@tonic-gate dstatep->node_type = kmem_alloc( 15777c478bd9Sstevel@tonic-gate strlen(node_type) + 1, KM_SLEEP); 15787c478bd9Sstevel@tonic-gate (void) strcpy(dstatep->node_type, node_type); 15797c478bd9Sstevel@tonic-gate } 15807c478bd9Sstevel@tonic-gate ddi_prop_free(node_type); 15817c478bd9Sstevel@tonic-gate 15827c478bd9Sstevel@tonic-gate /* the minor name is the same as the node name */ 15837c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, node_name, S_IFCHR, 15847c478bd9Sstevel@tonic-gate (INST_TO_MINOR(instance)), dstatep->node_type, NULL) != 15857c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 15867c478bd9Sstevel@tonic-gate if (dstatep->node_type) { 15877c478bd9Sstevel@tonic-gate kmem_free(dstatep->node_type, 15887c478bd9Sstevel@tonic-gate strlen(dstatep->node_type) + 1); 15897c478bd9Sstevel@tonic-gate dstatep->node_type = NULL; 15907c478bd9Sstevel@tonic-gate } 15917c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15927c478bd9Sstevel@tonic-gate } 15937c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 15947c478bd9Sstevel@tonic-gate } 15957c478bd9Sstevel@tonic-gate 15967c478bd9Sstevel@tonic-gate if (rval != DDI_SUCCESS) { 15977c478bd9Sstevel@tonic-gate ddi_prop_remove_all(devi); 15987c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 15997c478bd9Sstevel@tonic-gate } 16007c478bd9Sstevel@tonic-gate 16017c478bd9Sstevel@tonic-gate return (rval); 16027c478bd9Sstevel@tonic-gate } 16037c478bd9Sstevel@tonic-gate 16047c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 16057c478bd9Sstevel@tonic-gate static void 16067c478bd9Sstevel@tonic-gate gen_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie, void *arg, 16077c478bd9Sstevel@tonic-gate void *impl_data) 16087c478bd9Sstevel@tonic-gate { 16097c478bd9Sstevel@tonic-gate if (gen_debug) 16107c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "gen_event_cb invoked"); 16117c478bd9Sstevel@tonic-gate 16127c478bd9Sstevel@tonic-gate } 1613