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 57c478bd9Sstevel@tonic-gate * Common Development and Distribution License, Version 1.0 only 67c478bd9Sstevel@tonic-gate * (the "License"). You may not use this file except in compliance 77c478bd9Sstevel@tonic-gate * with the License. 87c478bd9Sstevel@tonic-gate * 97c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 107c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 117c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 127c478bd9Sstevel@tonic-gate * and limitations under the License. 137c478bd9Sstevel@tonic-gate * 147c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 157c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 167c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 177c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 187c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 197c478bd9Sstevel@tonic-gate * 207c478bd9Sstevel@tonic-gate * CDDL HEADER END 217c478bd9Sstevel@tonic-gate */ 227c478bd9Sstevel@tonic-gate /* 237c478bd9Sstevel@tonic-gate * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 247c478bd9Sstevel@tonic-gate * Use is subject to license terms. 257c478bd9Sstevel@tonic-gate */ 267c478bd9Sstevel@tonic-gate 277c478bd9Sstevel@tonic-gate /* 287c478bd9Sstevel@tonic-gate * pseudo bus nexus driver 297c478bd9Sstevel@tonic-gate * hotplug framework test facility 307c478bd9Sstevel@tonic-gate */ 317c478bd9Sstevel@tonic-gate #pragma ident "%Z%%M% %I% %E% SMI" 327c478bd9Sstevel@tonic-gate 337c478bd9Sstevel@tonic-gate /* 347c478bd9Sstevel@tonic-gate * The pshot driver can be used to exercise the i/o framework together 357c478bd9Sstevel@tonic-gate * with devfs by configuring an arbitrarily complex device tree. 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * The pshot driver is rooted at /devices/pshot. The following commands 387c478bd9Sstevel@tonic-gate * illustrate the operation of devfs together with pshot's bus_config. 397c478bd9Sstevel@tonic-gate * The first command demonstrates that, like the magician showing there's 407c478bd9Sstevel@tonic-gate * nothing up his sleeve, /devices/pshot is empty. The second command 417c478bd9Sstevel@tonic-gate * conjures up a branch of pshot nodes. Note that pshot's bus_config is 427c478bd9Sstevel@tonic-gate * called sequentially by devfs for each node, as part of the pathname 437c478bd9Sstevel@tonic-gate * resolution, and that each pshot node is fully configured and 447c478bd9Sstevel@tonic-gate * attached before that node's bus_config is called to configure the 457c478bd9Sstevel@tonic-gate * next child down the tree. The final result is a "disk" node configured 467c478bd9Sstevel@tonic-gate * at the bottom of the named hierarchy of pshot nodes. 477c478bd9Sstevel@tonic-gate * 487c478bd9Sstevel@tonic-gate * # 497c478bd9Sstevel@tonic-gate * # ls /devices/pshot 507c478bd9Sstevel@tonic-gate * # 517c478bd9Sstevel@tonic-gate * # ls -ld /devices/pshot/pshot@0/pshot@1/pshot@2/disk@3,0 527c478bd9Sstevel@tonic-gate * drwxr-xr-x 2 root sys 512 Feb 6 15:10 537c478bd9Sstevel@tonic-gate * /devices/pshot/pshot@0/pshot@1/pshot@2/disk@3,0 547c478bd9Sstevel@tonic-gate * 557c478bd9Sstevel@tonic-gate * pshot supports some unique behaviors as aids for test error cases. 567c478bd9Sstevel@tonic-gate * 577c478bd9Sstevel@tonic-gate * Match these special address formats to behavior: 587c478bd9Sstevel@tonic-gate * 597c478bd9Sstevel@tonic-gate * err.* - induce bus_config error 607c478bd9Sstevel@tonic-gate * delay - induce 1 second of bus_config delay time 617c478bd9Sstevel@tonic-gate * delay,n - induce n seconds of bus_config delay time 627c478bd9Sstevel@tonic-gate * wait - induce 1 second of bus_config wait time 637c478bd9Sstevel@tonic-gate * wait,n - induce n seconds of bus_config wait time 647c478bd9Sstevel@tonic-gate * failinit.* - induce error at INITCHILD 657c478bd9Sstevel@tonic-gate * failprobe.* - induce error at probe 667c478bd9Sstevel@tonic-gate * failattach.* - induce error at attach 677c478bd9Sstevel@tonic-gate */ 687c478bd9Sstevel@tonic-gate 697c478bd9Sstevel@tonic-gate #if defined(lint) && !defined(DEBUG) 707c478bd9Sstevel@tonic-gate #define DEBUG 1 717c478bd9Sstevel@tonic-gate #endif 727c478bd9Sstevel@tonic-gate 737c478bd9Sstevel@tonic-gate #include <sys/types.h> 747c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h> 757c478bd9Sstevel@tonic-gate #include <sys/conf.h> 767c478bd9Sstevel@tonic-gate #include <sys/ddi_impldefs.h> 777c478bd9Sstevel@tonic-gate #include <sys/autoconf.h> 787c478bd9Sstevel@tonic-gate #include <sys/open.h> 797c478bd9Sstevel@tonic-gate #include <sys/stat.h> 807c478bd9Sstevel@tonic-gate #include <sys/file.h> 817c478bd9Sstevel@tonic-gate #include <sys/errno.h> 827c478bd9Sstevel@tonic-gate #include <sys/systm.h> 837c478bd9Sstevel@tonic-gate #include <sys/modctl.h> 847c478bd9Sstevel@tonic-gate #include <sys/kmem.h> 857c478bd9Sstevel@tonic-gate #include <sys/ddi.h> 867c478bd9Sstevel@tonic-gate #include <sys/sunddi.h> 877c478bd9Sstevel@tonic-gate #include <sys/sunndi.h> 887c478bd9Sstevel@tonic-gate #include <sys/devctl.h> 897c478bd9Sstevel@tonic-gate #include <sys/disp.h> 907c478bd9Sstevel@tonic-gate #include <sys/utsname.h> 917c478bd9Sstevel@tonic-gate #include <sys/pshot.h> 927c478bd9Sstevel@tonic-gate #include <sys/debug.h> 937c478bd9Sstevel@tonic-gate 947c478bd9Sstevel@tonic-gate static int pshot_log = 0; 957c478bd9Sstevel@tonic-gate static int pshot_devctl_debug = 0; 967c478bd9Sstevel@tonic-gate static int pshot_debug_busy = 0; 977c478bd9Sstevel@tonic-gate 987c478bd9Sstevel@tonic-gate static void *pshot_softstatep; 997c478bd9Sstevel@tonic-gate 1007c478bd9Sstevel@tonic-gate static int pshot_prop_autoattach; 1017c478bd9Sstevel@tonic-gate 1027c478bd9Sstevel@tonic-gate #define MAXPWR 3 1037c478bd9Sstevel@tonic-gate 1047c478bd9Sstevel@tonic-gate 1057c478bd9Sstevel@tonic-gate /* 1067c478bd9Sstevel@tonic-gate * device configuration data 1077c478bd9Sstevel@tonic-gate */ 1087c478bd9Sstevel@tonic-gate 1097c478bd9Sstevel@tonic-gate /* should keep in sync with current release */ 1107c478bd9Sstevel@tonic-gate static struct { 1117c478bd9Sstevel@tonic-gate char *name; 1127c478bd9Sstevel@tonic-gate char *val; 1137c478bd9Sstevel@tonic-gate } pshot_nodetypes[] = { 1147c478bd9Sstevel@tonic-gate {"DDI_NT_SERIAL", DDI_NT_SERIAL}, 1157c478bd9Sstevel@tonic-gate {"DDI_NT_SERIAL_MB", DDI_NT_SERIAL_MB}, 1167c478bd9Sstevel@tonic-gate {"DDI_NT_SERIAL_DO", DDI_NT_SERIAL_DO}, 1177c478bd9Sstevel@tonic-gate {"DDI_NT_SERIAL_MB_DO", DDI_NT_SERIAL_MB_DO}, 1187c478bd9Sstevel@tonic-gate {"DDI_NT_SERIAL_LOMCON", DDI_NT_SERIAL_LOMCON}, 1197c478bd9Sstevel@tonic-gate {"DDI_NT_BLOCK", DDI_NT_BLOCK}, 1207c478bd9Sstevel@tonic-gate {"DDI_NT_BLOCK_CHAN", DDI_NT_BLOCK_CHAN}, 1217c478bd9Sstevel@tonic-gate {"DDI_NT_BLOCK_WWN", DDI_NT_BLOCK_WWN}, 1227c478bd9Sstevel@tonic-gate {"DDI_NT_CD", DDI_NT_CD}, 1237c478bd9Sstevel@tonic-gate {"DDI_NT_CD_CHAN", DDI_NT_CD_CHAN}, 1247c478bd9Sstevel@tonic-gate {"DDI_NT_FD", DDI_NT_FD}, 1257c478bd9Sstevel@tonic-gate {"DDI_NT_ENCLOSURE", DDI_NT_ENCLOSURE}, 1267c478bd9Sstevel@tonic-gate {"DDI_NT_SCSI_ENCLOSURE", DDI_NT_SCSI_ENCLOSURE}, 1277c478bd9Sstevel@tonic-gate {"DDI_NT_TAPE", DDI_NT_TAPE}, 1287c478bd9Sstevel@tonic-gate {"DDI_NT_NET", DDI_NT_NET}, 1297c478bd9Sstevel@tonic-gate {"DDI_NT_DISPLAY", DDI_NT_DISPLAY}, 1307c478bd9Sstevel@tonic-gate {"DDI_PSEUDO", DDI_PSEUDO}, 1317c478bd9Sstevel@tonic-gate {"DDI_NT_AUDIO", DDI_NT_AUDIO}, 1327c478bd9Sstevel@tonic-gate {"DDI_NT_MOUSE", DDI_NT_MOUSE}, 1337c478bd9Sstevel@tonic-gate {"DDI_NT_KEYBOARD", DDI_NT_KEYBOARD}, 1347c478bd9Sstevel@tonic-gate {"DDI_NT_PARALLEL", DDI_NT_PARALLEL}, 1357c478bd9Sstevel@tonic-gate {"DDI_NT_PRINTER", DDI_NT_PRINTER}, 1367c478bd9Sstevel@tonic-gate {"DDI_NT_UGEN", DDI_NT_UGEN}, 1377c478bd9Sstevel@tonic-gate {"DDI_NT_NEXUS", DDI_NT_NEXUS}, 1387c478bd9Sstevel@tonic-gate {"DDI_NT_SCSI_NEXUS", DDI_NT_SCSI_NEXUS}, 1397c478bd9Sstevel@tonic-gate {"DDI_NT_ATTACHMENT_POINT", DDI_NT_ATTACHMENT_POINT}, 1407c478bd9Sstevel@tonic-gate {"DDI_NT_SCSI_ATTACHMENT_POINT", DDI_NT_SCSI_ATTACHMENT_POINT}, 1417c478bd9Sstevel@tonic-gate {"DDI_NT_PCI_ATTACHMENT_POINT", DDI_NT_PCI_ATTACHMENT_POINT}, 1427c478bd9Sstevel@tonic-gate {"DDI_NT_SBD_ATTACHMENT_POINT", DDI_NT_SBD_ATTACHMENT_POINT}, 1437c478bd9Sstevel@tonic-gate {"DDI_NT_FC_ATTACHMENT_POINT", DDI_NT_FC_ATTACHMENT_POINT}, 1447c478bd9Sstevel@tonic-gate {"DDI_NT_USB_ATTACHMENT_POINT", DDI_NT_USB_ATTACHMENT_POINT}, 1457c478bd9Sstevel@tonic-gate {"DDI_NT_BLOCK_FABRIC", DDI_NT_BLOCK_FABRIC}, 1467c478bd9Sstevel@tonic-gate {"DDI_NT_SMARTCARD_READER", DDI_NT_SMARTCARD_READER}, 1477c478bd9Sstevel@tonic-gate {"DDI_NT_AV_ASYNC", DDI_NT_AV_ASYNC}, 1487c478bd9Sstevel@tonic-gate {"DDI_NT_AV_ISOCH", DDI_NT_AV_ISOCH}, 1497c478bd9Sstevel@tonic-gate { NULL, NULL } 1507c478bd9Sstevel@tonic-gate }; 1517c478bd9Sstevel@tonic-gate 1527c478bd9Sstevel@tonic-gate /* Node name */ 1537c478bd9Sstevel@tonic-gate static char *pshot_compat_diskname = "cdisk"; 1547c478bd9Sstevel@tonic-gate 1557c478bd9Sstevel@tonic-gate /* Compatible names... */ 1567c478bd9Sstevel@tonic-gate static char *pshot_compat_psramdisks[] = { 1577c478bd9Sstevel@tonic-gate "psramhead", 1587c478bd9Sstevel@tonic-gate "psramrom", 1597c478bd9Sstevel@tonic-gate "psramdisk", 1607c478bd9Sstevel@tonic-gate "psramd", 1617c478bd9Sstevel@tonic-gate "psramwhat" 1627c478bd9Sstevel@tonic-gate }; 1637c478bd9Sstevel@tonic-gate 1647c478bd9Sstevel@tonic-gate /* 1657c478bd9Sstevel@tonic-gate * devices "natively" supported by pshot (i.e. included with SUNWiotu) 1667c478bd9Sstevel@tonic-gate * used to initialize pshot_devices with 1677c478bd9Sstevel@tonic-gate */ 1687c478bd9Sstevel@tonic-gate static pshot_device_t pshot_stock_devices[] = { 1697c478bd9Sstevel@tonic-gate {"disk", DDI_NT_BLOCK, "gen_drv"}, 1707c478bd9Sstevel@tonic-gate {"disk_chan", DDI_NT_BLOCK_CHAN, "gen_drv"}, 1717c478bd9Sstevel@tonic-gate {"disk_wwn", DDI_NT_BLOCK_WWN, "gen_drv"}, 1727c478bd9Sstevel@tonic-gate {"disk_cdrom", DDI_NT_CD, "gen_drv"}, 1737c478bd9Sstevel@tonic-gate {"disk_cdrom.chan", DDI_NT_CD_CHAN, "gen_drv"}, 1747c478bd9Sstevel@tonic-gate /* Note: use bad_drv to force attach errors */ 1757c478bd9Sstevel@tonic-gate {"disk_fd", DDI_NT_FD, "bad_drv"}, 1767c478bd9Sstevel@tonic-gate {"tape", DDI_NT_TAPE, "gen_drv"}, 1777c478bd9Sstevel@tonic-gate {"net", DDI_NT_NET, "gen_drv"}, 1787c478bd9Sstevel@tonic-gate {"display", DDI_NT_DISPLAY, "gen_drv"}, 1797c478bd9Sstevel@tonic-gate {"pseudo", DDI_PSEUDO, "gen_drv"}, 1807c478bd9Sstevel@tonic-gate {"audio", DDI_NT_AUDIO, "gen_drv"}, 1817c478bd9Sstevel@tonic-gate {"mouse", DDI_NT_MOUSE, "gen_drv"}, 1827c478bd9Sstevel@tonic-gate {"keyboard", DDI_NT_KEYBOARD, "gen_drv"}, 1837c478bd9Sstevel@tonic-gate {"nexus", DDI_NT_NEXUS, "pshot"} 1847c478bd9Sstevel@tonic-gate }; 1857c478bd9Sstevel@tonic-gate #define PSHOT_N_STOCK_DEVICES \ 1867c478bd9Sstevel@tonic-gate (sizeof (pshot_stock_devices) / sizeof (pshot_device_t)) 1877c478bd9Sstevel@tonic-gate 1887c478bd9Sstevel@tonic-gate static pshot_device_t *pshot_devices = NULL; 1897c478bd9Sstevel@tonic-gate static size_t pshot_devices_len = 0; 1907c478bd9Sstevel@tonic-gate 1917c478bd9Sstevel@tonic-gate /* protects <pshot_devices>, <pshot_devices_len> */ 1927c478bd9Sstevel@tonic-gate static kmutex_t pshot_devices_lock; 1937c478bd9Sstevel@tonic-gate 1947c478bd9Sstevel@tonic-gate 1957c478bd9Sstevel@tonic-gate /* 1967c478bd9Sstevel@tonic-gate * event testing 1977c478bd9Sstevel@tonic-gate */ 1987c478bd9Sstevel@tonic-gate 1997c478bd9Sstevel@tonic-gate static ndi_event_definition_t pshot_ndi_event_defs[] = { 2007c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_OFFLINE, PSHOT_EVENT_NAME_DEV_OFFLINE, 2017c478bd9Sstevel@tonic-gate EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL }, 2027c478bd9Sstevel@tonic-gate 2037c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_DEV_RESET, PSHOT_EVENT_NAME_DEV_RESET, 2047c478bd9Sstevel@tonic-gate EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT }, 2057c478bd9Sstevel@tonic-gate 2067c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_BUS_RESET, PSHOT_EVENT_NAME_BUS_RESET, 2077c478bd9Sstevel@tonic-gate EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL }, 2087c478bd9Sstevel@tonic-gate 2097c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_BUS_QUIESCE, PSHOT_EVENT_NAME_BUS_QUIESCE, 2107c478bd9Sstevel@tonic-gate EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL }, 2117c478bd9Sstevel@tonic-gate 2127c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_BUS_UNQUIESCE, PSHOT_EVENT_NAME_BUS_UNQUIESCE, 2137c478bd9Sstevel@tonic-gate EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL }, 2147c478bd9Sstevel@tonic-gate 2157c478bd9Sstevel@tonic-gate { PSHOT_EVENT_TAG_TEST_POST, PSHOT_EVENT_NAME_BUS_TEST_POST, 2167c478bd9Sstevel@tonic-gate EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT } 2177c478bd9Sstevel@tonic-gate }; 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate 2207c478bd9Sstevel@tonic-gate #define PSHOT_N_NDI_EVENTS \ 2217c478bd9Sstevel@tonic-gate (sizeof (pshot_ndi_event_defs) / sizeof (ndi_event_definition_t)) 2227c478bd9Sstevel@tonic-gate 2237c478bd9Sstevel@tonic-gate #ifdef DEBUG 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate static ndi_event_definition_t pshot_test_events[] = { 2267c478bd9Sstevel@tonic-gate { 10, "test event 0", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL }, 2277c478bd9Sstevel@tonic-gate { 11, "test event 1", EPL_KERNEL, NDI_EVENT_POST_TO_TGT }, 2287c478bd9Sstevel@tonic-gate { 12, "test event 2", EPL_INTERRUPT, NDI_EVENT_POST_TO_TGT }, 2297c478bd9Sstevel@tonic-gate { 13, "test event 3", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL }, 2307c478bd9Sstevel@tonic-gate { 14, "test event 4", EPL_KERNEL, NDI_EVENT_POST_TO_ALL}, 2317c478bd9Sstevel@tonic-gate { 15, "test event 5", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL }, 2327c478bd9Sstevel@tonic-gate { 16, "test event 6", EPL_KERNEL, NDI_EVENT_POST_TO_ALL }, 2337c478bd9Sstevel@tonic-gate { 17, "test event 7", EPL_INTERRUPT, NDI_EVENT_POST_TO_ALL } 2347c478bd9Sstevel@tonic-gate }; 2357c478bd9Sstevel@tonic-gate 2367c478bd9Sstevel@tonic-gate static ndi_event_definition_t pshot_test_events_high[] = { 2377c478bd9Sstevel@tonic-gate { 20, "test event high 0", EPL_HIGHLEVEL, NDI_EVENT_POST_TO_ALL} 2387c478bd9Sstevel@tonic-gate }; 2397c478bd9Sstevel@tonic-gate 2407c478bd9Sstevel@tonic-gate #define PSHOT_N_TEST_EVENTS \ 2417c478bd9Sstevel@tonic-gate (sizeof (pshot_test_events)/sizeof (ndi_event_definition_t)) 2427c478bd9Sstevel@tonic-gate #endif 2437c478bd9Sstevel@tonic-gate 2447c478bd9Sstevel@tonic-gate struct register_events { 2457c478bd9Sstevel@tonic-gate char *event_name; 2467c478bd9Sstevel@tonic-gate ddi_eventcookie_t event_cookie; 2477c478bd9Sstevel@tonic-gate void (*event_callback) 2487c478bd9Sstevel@tonic-gate (dev_info_t *, 2497c478bd9Sstevel@tonic-gate ddi_eventcookie_t, 2507c478bd9Sstevel@tonic-gate void *arg, 2517c478bd9Sstevel@tonic-gate void *impldata); 2527c478bd9Sstevel@tonic-gate ddi_callback_id_t cb_id; 2537c478bd9Sstevel@tonic-gate }; 2547c478bd9Sstevel@tonic-gate 2557c478bd9Sstevel@tonic-gate struct register_events pshot_register_events[] = { 2567c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_DEV_OFFLINE, 0, pshot_event_cb, 0 }, 2577c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_DEV_RESET, 0, pshot_event_cb, 0 }, 2587c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_RESET, 0, pshot_event_cb, 0 }, 2597c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_QUIESCE, 0, pshot_event_cb, 0 }, 2607c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_UNQUIESCE, 0, pshot_event_cb, 0 }, 2617c478bd9Sstevel@tonic-gate { PSHOT_EVENT_NAME_BUS_TEST_POST, 0, pshot_event_cb, 0 } 2627c478bd9Sstevel@tonic-gate }; 2637c478bd9Sstevel@tonic-gate 2647c478bd9Sstevel@tonic-gate #define PSHOT_N_DDI_EVENTS \ 2657c478bd9Sstevel@tonic-gate (sizeof (pshot_register_events) / sizeof (struct register_events)) 2667c478bd9Sstevel@tonic-gate 2677c478bd9Sstevel@tonic-gate 2687c478bd9Sstevel@tonic-gate #ifdef DEBUG 2697c478bd9Sstevel@tonic-gate 2707c478bd9Sstevel@tonic-gate static struct register_events pshot_register_test[] = { 2717c478bd9Sstevel@tonic-gate { "test event 0", 0, pshot_event_cb_test, 0}, 2727c478bd9Sstevel@tonic-gate { "test event 1", 0, pshot_event_cb_test, 0}, 2737c478bd9Sstevel@tonic-gate { "test event 2", 0, pshot_event_cb_test, 0}, 2747c478bd9Sstevel@tonic-gate { "test event 3", 0, pshot_event_cb_test, 0}, 2757c478bd9Sstevel@tonic-gate { "test event 4", 0, pshot_event_cb_test, 0}, 2767c478bd9Sstevel@tonic-gate { "test event 5", 0, pshot_event_cb_test, 0}, 2777c478bd9Sstevel@tonic-gate { "test event 6", 0, pshot_event_cb_test, 0}, 2787c478bd9Sstevel@tonic-gate { "test event 7", 0, pshot_event_cb_test, 0} 2797c478bd9Sstevel@tonic-gate }; 2807c478bd9Sstevel@tonic-gate 2817c478bd9Sstevel@tonic-gate 2827c478bd9Sstevel@tonic-gate static struct register_events pshot_register_high_test[] = { 2837c478bd9Sstevel@tonic-gate {"test event high 0", 0, pshot_event_cb_test, 0} 2847c478bd9Sstevel@tonic-gate }; 2857c478bd9Sstevel@tonic-gate 2867c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 2877c478bd9Sstevel@tonic-gate 2887c478bd9Sstevel@tonic-gate static struct { 2897c478bd9Sstevel@tonic-gate int ioctl_int; 2907c478bd9Sstevel@tonic-gate char *ioctl_char; 2917c478bd9Sstevel@tonic-gate } pshot_devctls[] = { 2927c478bd9Sstevel@tonic-gate {DEVCTL_DEVICE_GETSTATE, "DEVCTL_DEVICE_GETSTATE"}, 2937c478bd9Sstevel@tonic-gate {DEVCTL_DEVICE_ONLINE, "DEVCTL_DEVICE_ONLINE"}, 2947c478bd9Sstevel@tonic-gate {DEVCTL_DEVICE_OFFLINE, "DEVCTL_DEVICE_OFFLINE"}, 2957c478bd9Sstevel@tonic-gate {DEVCTL_DEVICE_REMOVE, "DEVCTL_DEVICE_REMOVE"}, 2967c478bd9Sstevel@tonic-gate {DEVCTL_BUS_GETSTATE, "DEVCTL_BUS_GETSTATE"}, 2977c478bd9Sstevel@tonic-gate {DEVCTL_BUS_DEV_CREATE, "DEVCTL_BUS_DEV_CREATE"}, 2987c478bd9Sstevel@tonic-gate {DEVCTL_BUS_RESET, "DEVCTL_BUS_RESET"}, 2997c478bd9Sstevel@tonic-gate {DEVCTL_BUS_RESETALL, "DEVCTL_BUS_RESETALL"}, 3007c478bd9Sstevel@tonic-gate {0, NULL} 3017c478bd9Sstevel@tonic-gate }; 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate static struct bus_ops pshot_bus_ops = { 3047c478bd9Sstevel@tonic-gate BUSO_REV, /* busops_rev */ 3057c478bd9Sstevel@tonic-gate nullbusmap, /* bus_map */ 3067c478bd9Sstevel@tonic-gate NULL, /* bus_get_intrspec */ 3077c478bd9Sstevel@tonic-gate NULL, /* bus_add_interspec */ 3087c478bd9Sstevel@tonic-gate NULL, /* bus_remove_interspec */ 3097c478bd9Sstevel@tonic-gate i_ddi_map_fault, /* bus_map_fault */ 310*b1dd958fScth ddi_dma_map, /* bus_dma_map */ 311*b1dd958fScth ddi_dma_allochdl, /* bus_dma_allochdl */ 312*b1dd958fScth ddi_dma_freehdl, /* bus_dma_freehdl */ 313*b1dd958fScth ddi_dma_bindhdl, /* bus_dma_bindhdl */ 314*b1dd958fScth ddi_dma_unbindhdl, /* bus_dma_unbindhdl */ 315*b1dd958fScth ddi_dma_flush, /* bus_dma_flush */ 316*b1dd958fScth ddi_dma_win, /* bus_dma_win */ 317*b1dd958fScth ddi_dma_mctl, /* bus_dma_ctl */ 3187c478bd9Sstevel@tonic-gate pshot_ctl, /* bus_ctl */ 3197c478bd9Sstevel@tonic-gate ddi_bus_prop_op, /* bus_prop_op */ 3207c478bd9Sstevel@tonic-gate pshot_get_eventcookie, /* bus_get_eventcookie */ 3217c478bd9Sstevel@tonic-gate pshot_add_eventcall, /* bus_add_eventcall */ 3227c478bd9Sstevel@tonic-gate pshot_remove_eventcall, /* bus_remove_event */ 3237c478bd9Sstevel@tonic-gate pshot_post_event, /* bus_post_event */ 3247c478bd9Sstevel@tonic-gate NULL, /* bus_intr_ctl */ 3257c478bd9Sstevel@tonic-gate pshot_bus_config, /* bus_config */ 3267c478bd9Sstevel@tonic-gate pshot_bus_unconfig, /* bus_unconfig */ 3277c478bd9Sstevel@tonic-gate NULL, /* bus_fm_init */ 3287c478bd9Sstevel@tonic-gate NULL, /* bus_fm_fini */ 3297c478bd9Sstevel@tonic-gate NULL, /* bus_fm_access_enter */ 3307c478bd9Sstevel@tonic-gate NULL, /* bus_fm_access_exit */ 3317c478bd9Sstevel@tonic-gate pshot_bus_power, /* bus_power */ 3327c478bd9Sstevel@tonic-gate pshot_bus_introp /* bus_intr_op */ 3337c478bd9Sstevel@tonic-gate }; 3347c478bd9Sstevel@tonic-gate 3357c478bd9Sstevel@tonic-gate static struct cb_ops pshot_cb_ops = { 3367c478bd9Sstevel@tonic-gate pshot_open, /* open */ 3377c478bd9Sstevel@tonic-gate pshot_close, /* close */ 3387c478bd9Sstevel@tonic-gate nodev, /* strategy */ 3397c478bd9Sstevel@tonic-gate nodev, /* print */ 3407c478bd9Sstevel@tonic-gate nodev, /* dump */ 3417c478bd9Sstevel@tonic-gate nodev, /* read */ 3427c478bd9Sstevel@tonic-gate nodev, /* write */ 3437c478bd9Sstevel@tonic-gate pshot_ioctl, /* ioctl */ 3447c478bd9Sstevel@tonic-gate nodev, /* devmap */ 3457c478bd9Sstevel@tonic-gate nodev, /* mmap */ 3467c478bd9Sstevel@tonic-gate nodev, /* segmap */ 3477c478bd9Sstevel@tonic-gate nochpoll, /* poll */ 3487c478bd9Sstevel@tonic-gate ddi_prop_op, /* prop_op */ 3497c478bd9Sstevel@tonic-gate NULL, /* streamtab */ 3507c478bd9Sstevel@tonic-gate D_NEW | D_MP | D_HOTPLUG, /* flags */ 3517c478bd9Sstevel@tonic-gate CB_REV, /* cb_rev */ 3527c478bd9Sstevel@tonic-gate nodev, /* aread */ 3537c478bd9Sstevel@tonic-gate nodev, /* awrite */ 3547c478bd9Sstevel@tonic-gate }; 3557c478bd9Sstevel@tonic-gate 3567c478bd9Sstevel@tonic-gate static struct dev_ops pshot_ops = { 3577c478bd9Sstevel@tonic-gate DEVO_REV, /* devo_rev, */ 3587c478bd9Sstevel@tonic-gate 0, /* refcnt */ 3597c478bd9Sstevel@tonic-gate pshot_info, /* getinfo */ 3607c478bd9Sstevel@tonic-gate nulldev, /* identify */ 3617c478bd9Sstevel@tonic-gate pshot_probe, /* probe */ 3627c478bd9Sstevel@tonic-gate pshot_attach, /* attach */ 3637c478bd9Sstevel@tonic-gate pshot_detach, /* detach */ 3647c478bd9Sstevel@tonic-gate nodev, /* reset */ 3657c478bd9Sstevel@tonic-gate &pshot_cb_ops, /* driver operations */ 3667c478bd9Sstevel@tonic-gate &pshot_bus_ops, /* bus operations */ 3677c478bd9Sstevel@tonic-gate pshot_power /* power */ 3687c478bd9Sstevel@tonic-gate 3697c478bd9Sstevel@tonic-gate }; 3707c478bd9Sstevel@tonic-gate 3717c478bd9Sstevel@tonic-gate 3727c478bd9Sstevel@tonic-gate /* 3737c478bd9Sstevel@tonic-gate * Module linkage information for the kernel. 3747c478bd9Sstevel@tonic-gate */ 3757c478bd9Sstevel@tonic-gate static struct modldrv modldrv = { 3767c478bd9Sstevel@tonic-gate &mod_driverops, 3777c478bd9Sstevel@tonic-gate "pshotnex %I%", 3787c478bd9Sstevel@tonic-gate &pshot_ops, 3797c478bd9Sstevel@tonic-gate }; 3807c478bd9Sstevel@tonic-gate 3817c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = { 3827c478bd9Sstevel@tonic-gate MODREV_1, &modldrv, NULL 3837c478bd9Sstevel@tonic-gate }; 3847c478bd9Sstevel@tonic-gate 3857c478bd9Sstevel@tonic-gate 3867c478bd9Sstevel@tonic-gate /* 3877c478bd9Sstevel@tonic-gate * pshot_devices is set up on the first attach and destroyed on fini 3887c478bd9Sstevel@tonic-gate * 3897c478bd9Sstevel@tonic-gate * therefore PSHOT_PROP_DEV* properties may be set just for the root device, 3907c478bd9Sstevel@tonic-gate * instead of being set globably, in pshot.conf by specifying the properties 3917c478bd9Sstevel@tonic-gate * on a single line in the form: 3927c478bd9Sstevel@tonic-gate * name="pshot" parent="/" <dev props ..> 3937c478bd9Sstevel@tonic-gate * to unclutter a device tree snapshot. 3947c478bd9Sstevel@tonic-gate * this of course produces a long single line that may wrap around several 3957c478bd9Sstevel@tonic-gate * times on screen 3967c478bd9Sstevel@tonic-gate */ 3977c478bd9Sstevel@tonic-gate 3987c478bd9Sstevel@tonic-gate int 3997c478bd9Sstevel@tonic-gate _init(void) 4007c478bd9Sstevel@tonic-gate { 4017c478bd9Sstevel@tonic-gate int rv; 4027c478bd9Sstevel@tonic-gate 4037c478bd9Sstevel@tonic-gate rv = ddi_soft_state_init(&pshot_softstatep, sizeof (pshot_t), 0); 4047c478bd9Sstevel@tonic-gate 4057c478bd9Sstevel@tonic-gate if (rv != DDI_SUCCESS) 4067c478bd9Sstevel@tonic-gate return (rv); 4077c478bd9Sstevel@tonic-gate 4087c478bd9Sstevel@tonic-gate mutex_init(&pshot_devices_lock, NULL, MUTEX_DRIVER, NULL); 4097c478bd9Sstevel@tonic-gate pshot_devices = NULL; 4107c478bd9Sstevel@tonic-gate pshot_devices_len = 0; 4117c478bd9Sstevel@tonic-gate 4127c478bd9Sstevel@tonic-gate if ((rv = mod_install(&modlinkage)) != 0) { 4137c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&pshot_softstatep); 4147c478bd9Sstevel@tonic-gate mutex_destroy(&pshot_devices_lock); 4157c478bd9Sstevel@tonic-gate } 4167c478bd9Sstevel@tonic-gate return (rv); 4177c478bd9Sstevel@tonic-gate } 4187c478bd9Sstevel@tonic-gate 4197c478bd9Sstevel@tonic-gate int 4207c478bd9Sstevel@tonic-gate _fini(void) 4217c478bd9Sstevel@tonic-gate { 4227c478bd9Sstevel@tonic-gate int rv; 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate if ((rv = mod_remove(&modlinkage)) != 0) 4257c478bd9Sstevel@tonic-gate return (rv); 4267c478bd9Sstevel@tonic-gate 4277c478bd9Sstevel@tonic-gate ddi_soft_state_fini(&pshot_softstatep); 4287c478bd9Sstevel@tonic-gate mutex_destroy(&pshot_devices_lock); 4297c478bd9Sstevel@tonic-gate if (pshot_devices) 4307c478bd9Sstevel@tonic-gate pshot_devices_free(pshot_devices, pshot_devices_len); 4317c478bd9Sstevel@tonic-gate return (0); 4327c478bd9Sstevel@tonic-gate } 4337c478bd9Sstevel@tonic-gate 4347c478bd9Sstevel@tonic-gate int 4357c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop) 4367c478bd9Sstevel@tonic-gate { 4377c478bd9Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop)); 4387c478bd9Sstevel@tonic-gate } 4397c478bd9Sstevel@tonic-gate 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4427c478bd9Sstevel@tonic-gate static int 4437c478bd9Sstevel@tonic-gate pshot_probe(dev_info_t *devi) 4447c478bd9Sstevel@tonic-gate { 4457c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(devi); 4467c478bd9Sstevel@tonic-gate char *bus_addr; 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate /* 4497c478bd9Sstevel@tonic-gate * Hook for tests to force probe fail 4507c478bd9Sstevel@tonic-gate */ 4517c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 0, "bus-addr", 4527c478bd9Sstevel@tonic-gate &bus_addr) == DDI_PROP_SUCCESS) { 4537c478bd9Sstevel@tonic-gate if (strncmp(bus_addr, "failprobe", 9) == 0) { 4547c478bd9Sstevel@tonic-gate if (pshot_debug) 4557c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: " 4567c478bd9Sstevel@tonic-gate "%s forced probe failure\n", 4577c478bd9Sstevel@tonic-gate instance, bus_addr); 4587c478bd9Sstevel@tonic-gate ddi_prop_free(bus_addr); 4597c478bd9Sstevel@tonic-gate return (DDI_PROBE_FAILURE); 4607c478bd9Sstevel@tonic-gate } 4617c478bd9Sstevel@tonic-gate ddi_prop_free(bus_addr); 4627c478bd9Sstevel@tonic-gate } 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate return (DDI_PROBE_SUCCESS); 4657c478bd9Sstevel@tonic-gate } 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate 4687c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 4697c478bd9Sstevel@tonic-gate static int 4707c478bd9Sstevel@tonic-gate pshot_info(dev_info_t *dip, ddi_info_cmd_t infocmd, void *arg, void **result) 4717c478bd9Sstevel@tonic-gate { 4727c478bd9Sstevel@tonic-gate int instance; 4737c478bd9Sstevel@tonic-gate minor_t minor; 4747c478bd9Sstevel@tonic-gate pshot_t *pshot; 4757c478bd9Sstevel@tonic-gate 4767c478bd9Sstevel@tonic-gate minor = getminor((dev_t)arg); 4777c478bd9Sstevel@tonic-gate instance = pshot_minor_decode_inst(minor); 4787c478bd9Sstevel@tonic-gate switch (infocmd) { 4797c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO: 4807c478bd9Sstevel@tonic-gate pshot = ddi_get_soft_state(pshot_softstatep, instance); 4817c478bd9Sstevel@tonic-gate if (pshot == NULL) { 4827c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot_info: get soft state failed " 4837c478bd9Sstevel@tonic-gate "on minor %u, instance %d", minor, instance); 4847c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4857c478bd9Sstevel@tonic-gate } 4867c478bd9Sstevel@tonic-gate *result = (void *)pshot->dip; 4877c478bd9Sstevel@tonic-gate break; 4887c478bd9Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE: 4897c478bd9Sstevel@tonic-gate *result = (void *)(uintptr_t)instance; 4907c478bd9Sstevel@tonic-gate break; 4917c478bd9Sstevel@tonic-gate default: 4927c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot_info: unrecognized cmd 0x%x on " 4937c478bd9Sstevel@tonic-gate "minor %u, instance %d", infocmd, minor, instance); 4947c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 4957c478bd9Sstevel@tonic-gate } 4967c478bd9Sstevel@tonic-gate 4977c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 4987c478bd9Sstevel@tonic-gate } 4997c478bd9Sstevel@tonic-gate 5007c478bd9Sstevel@tonic-gate 5017c478bd9Sstevel@tonic-gate static int 5027c478bd9Sstevel@tonic-gate pshot_attach(dev_info_t *devi, ddi_attach_cmd_t cmd) 5037c478bd9Sstevel@tonic-gate { 5047c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(devi); 5057c478bd9Sstevel@tonic-gate pshot_t *pshot; 5067c478bd9Sstevel@tonic-gate int rval, i; 5077c478bd9Sstevel@tonic-gate int prop_flags = DDI_PROP_DONTPASS | DDI_PROP_NOTPROM; 5087c478bd9Sstevel@tonic-gate char *bus_addr; 5097c478bd9Sstevel@tonic-gate char *pm_comp[] = { 5107c478bd9Sstevel@tonic-gate "NAME=bus", 5117c478bd9Sstevel@tonic-gate "0=B3", 5127c478bd9Sstevel@tonic-gate "1=B2", 5137c478bd9Sstevel@tonic-gate "2=B1", 5147c478bd9Sstevel@tonic-gate "3=B0"}; 5157c478bd9Sstevel@tonic-gate char *pm_hw_state = {"needs-suspend-resume"}; 5167c478bd9Sstevel@tonic-gate 5177c478bd9Sstevel@tonic-gate pshot_prop_autoattach = ddi_prop_get_int(DDI_DEV_T_ANY, devi, 5187c478bd9Sstevel@tonic-gate prop_flags, "autoattach", 0); 5197c478bd9Sstevel@tonic-gate 5207c478bd9Sstevel@tonic-gate switch (cmd) { 5217c478bd9Sstevel@tonic-gate 5227c478bd9Sstevel@tonic-gate case DDI_ATTACH: 5237c478bd9Sstevel@tonic-gate if (pshot_debug) 5247c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "attach: %s%d/pshot%d\n", 5257c478bd9Sstevel@tonic-gate ddi_get_name(ddi_get_parent(devi)), 5267c478bd9Sstevel@tonic-gate ddi_get_instance(ddi_get_parent(devi)), 5277c478bd9Sstevel@tonic-gate instance); 5287c478bd9Sstevel@tonic-gate 5297c478bd9Sstevel@tonic-gate /* 5307c478bd9Sstevel@tonic-gate * Hook for tests to force attach fail 5317c478bd9Sstevel@tonic-gate */ 5327c478bd9Sstevel@tonic-gate if ((ddi_prop_lookup_string(DDI_DEV_T_ANY, devi, 0, "bus-addr", 5337c478bd9Sstevel@tonic-gate &bus_addr) == DDI_PROP_SUCCESS) && bus_addr != NULL) { 5347c478bd9Sstevel@tonic-gate if (strncmp(bus_addr, "failattach", 10) == 0) { 5357c478bd9Sstevel@tonic-gate if (pshot_debug) 5367c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: " 5377c478bd9Sstevel@tonic-gate "%s forced attach failure\n", 5387c478bd9Sstevel@tonic-gate instance, bus_addr); 5397c478bd9Sstevel@tonic-gate ddi_prop_free(bus_addr); 5407c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5417c478bd9Sstevel@tonic-gate } 5427c478bd9Sstevel@tonic-gate ddi_prop_free(bus_addr); 5437c478bd9Sstevel@tonic-gate } 5447c478bd9Sstevel@tonic-gate 5457c478bd9Sstevel@tonic-gate /* 5467c478bd9Sstevel@tonic-gate * minor nodes setup 5477c478bd9Sstevel@tonic-gate */ 5487c478bd9Sstevel@tonic-gate if (ddi_soft_state_zalloc(pshot_softstatep, instance) != 5497c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 5507c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 5517c478bd9Sstevel@tonic-gate } 5527c478bd9Sstevel@tonic-gate pshot = ddi_get_soft_state(pshot_softstatep, instance); 5537c478bd9Sstevel@tonic-gate pshot->dip = devi; 5547c478bd9Sstevel@tonic-gate pshot->instance = instance; 5557c478bd9Sstevel@tonic-gate mutex_init(&pshot->lock, NULL, MUTEX_DRIVER, NULL); 5567c478bd9Sstevel@tonic-gate 5577c478bd9Sstevel@tonic-gate /* set each minor, then create on dip all together */ 5587c478bd9Sstevel@tonic-gate 5597c478bd9Sstevel@tonic-gate i = PSHOT_NODENUM_DEVCTL; 5607c478bd9Sstevel@tonic-gate pshot->nodes[i].pshot = pshot; 5617c478bd9Sstevel@tonic-gate pshot->nodes[i].minor = pshot_minor_encode(instance, i); 5627c478bd9Sstevel@tonic-gate (void) strncpy(pshot->nodes[i].name, PSHOT_NODENAME_DEVCTL, 5637c478bd9Sstevel@tonic-gate PSHOT_MAX_MINOR_NAMELEN); 5647c478bd9Sstevel@tonic-gate 5657c478bd9Sstevel@tonic-gate i = PSHOT_NODENUM_TESTCTL; 5667c478bd9Sstevel@tonic-gate pshot->nodes[i].pshot = pshot; 5677c478bd9Sstevel@tonic-gate pshot->nodes[i].minor = pshot_minor_encode(instance, i); 5687c478bd9Sstevel@tonic-gate (void) strncpy(pshot->nodes[i].name, PSHOT_NODENAME_TESTCTL, 5697c478bd9Sstevel@tonic-gate PSHOT_MAX_MINOR_NAMELEN); 5707c478bd9Sstevel@tonic-gate 5717c478bd9Sstevel@tonic-gate /* this assumes contiguous a filling */ 5727c478bd9Sstevel@tonic-gate for (i = 0; i <= PSHOT_MAX_NODENUM; i++) { 5737c478bd9Sstevel@tonic-gate if (ddi_create_minor_node(devi, pshot->nodes[i].name, 5747c478bd9Sstevel@tonic-gate S_IFCHR, pshot->nodes[i].minor, DDI_NT_NEXUS, 0) != 5757c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 5767c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "attach: cannot create " 5777c478bd9Sstevel@tonic-gate "minor %s", pshot->nodes[i].name); 5787c478bd9Sstevel@tonic-gate goto FAIL_ATTACH; 5797c478bd9Sstevel@tonic-gate } 5807c478bd9Sstevel@tonic-gate } 5817c478bd9Sstevel@tonic-gate 5827c478bd9Sstevel@tonic-gate /* 5837c478bd9Sstevel@tonic-gate * pshot_devices setup 5847c478bd9Sstevel@tonic-gate */ 5857c478bd9Sstevel@tonic-gate if (pshot_devices_setup(devi)) { 5867c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "attach: pshot devices setup " 5877c478bd9Sstevel@tonic-gate "failed"); 5887c478bd9Sstevel@tonic-gate goto FAIL_ATTACH; 5897c478bd9Sstevel@tonic-gate } 5907c478bd9Sstevel@tonic-gate 5917c478bd9Sstevel@tonic-gate /* 5927c478bd9Sstevel@tonic-gate * events setup 5937c478bd9Sstevel@tonic-gate */ 5947c478bd9Sstevel@tonic-gate for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) { 5957c478bd9Sstevel@tonic-gate rval = ddi_get_eventcookie(devi, 5967c478bd9Sstevel@tonic-gate pshot_register_events[i].event_name, 5977c478bd9Sstevel@tonic-gate &pshot_register_events[i].event_cookie); 5987c478bd9Sstevel@tonic-gate 5997c478bd9Sstevel@tonic-gate if (pshot_debug) 6007c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: event=%s:" 6017c478bd9Sstevel@tonic-gate "ddi_get_eventcookie rval=%d\n", 6027c478bd9Sstevel@tonic-gate instance, 6037c478bd9Sstevel@tonic-gate pshot_register_events[i].event_name, rval); 6047c478bd9Sstevel@tonic-gate 6057c478bd9Sstevel@tonic-gate if (rval == DDI_SUCCESS) { 6067c478bd9Sstevel@tonic-gate rval = ddi_add_event_handler(devi, 6077c478bd9Sstevel@tonic-gate pshot_register_events[i].event_cookie, 6087c478bd9Sstevel@tonic-gate pshot_register_events[i].event_callback, 6097c478bd9Sstevel@tonic-gate (void *)pshot, 6107c478bd9Sstevel@tonic-gate &pshot->callback_cache[i]); 6117c478bd9Sstevel@tonic-gate 6127c478bd9Sstevel@tonic-gate if (pshot_debug) 6137c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: event=%s: " 6147c478bd9Sstevel@tonic-gate "ddi_add_event_handler rval=%d\n", 6157c478bd9Sstevel@tonic-gate instance, 6167c478bd9Sstevel@tonic-gate pshot_register_events[i].event_name, 6177c478bd9Sstevel@tonic-gate rval); 6187c478bd9Sstevel@tonic-gate } 6197c478bd9Sstevel@tonic-gate } 6207c478bd9Sstevel@tonic-gate 6217c478bd9Sstevel@tonic-gate #ifdef DEBUG 6227c478bd9Sstevel@tonic-gate if (pshot_event_test_enable) { 6237c478bd9Sstevel@tonic-gate pshot_event_test((void *)pshot); 6247c478bd9Sstevel@tonic-gate (void) timeout(pshot_event_test_post_one, (void *)pshot, 6257c478bd9Sstevel@tonic-gate instance * drv_usectohz(60000000)); 6267c478bd9Sstevel@tonic-gate } 6277c478bd9Sstevel@tonic-gate #endif 6287c478bd9Sstevel@tonic-gate 6297c478bd9Sstevel@tonic-gate /* 6307c478bd9Sstevel@tonic-gate * allocate an ndi event handle 6317c478bd9Sstevel@tonic-gate */ 6327c478bd9Sstevel@tonic-gate if (ndi_event_alloc_hdl(devi, NULL, &pshot->ndi_event_hdl, 6337c478bd9Sstevel@tonic-gate NDI_SLEEP) != NDI_SUCCESS) { 6347c478bd9Sstevel@tonic-gate goto FAIL_ATTACH; 6357c478bd9Sstevel@tonic-gate } 6367c478bd9Sstevel@tonic-gate 6377c478bd9Sstevel@tonic-gate pshot->ndi_events.ndi_events_version = NDI_EVENTS_REV1; 6387c478bd9Sstevel@tonic-gate pshot->ndi_events.ndi_n_events = PSHOT_N_NDI_EVENTS; 6397c478bd9Sstevel@tonic-gate pshot->ndi_events.ndi_event_defs = pshot_ndi_event_defs; 6407c478bd9Sstevel@tonic-gate 6417c478bd9Sstevel@tonic-gate if (ndi_event_bind_set(pshot->ndi_event_hdl, &pshot->ndi_events, 6427c478bd9Sstevel@tonic-gate NDI_SLEEP) != NDI_SUCCESS) { 6437c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d bind set failed\n", 6447c478bd9Sstevel@tonic-gate instance); 6457c478bd9Sstevel@tonic-gate } 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate /* 6487c478bd9Sstevel@tonic-gate * setup a test for nexus auto-attach iff we are 6497c478bd9Sstevel@tonic-gate * a second level pshot node (parent == /SUNW,pshot) 6507c478bd9Sstevel@tonic-gate * enable by setting "autoattach=1" in pshot.conf 6517c478bd9Sstevel@tonic-gate */ 6527c478bd9Sstevel@tonic-gate if ((PARENT_IS_PSHOT(devi)) && (pshot_prop_autoattach != 0) && 6537c478bd9Sstevel@tonic-gate (ddi_get_instance(ddi_get_parent(devi))) == 0) 6547c478bd9Sstevel@tonic-gate pshot_setup_autoattach(devi); 6557c478bd9Sstevel@tonic-gate 6567c478bd9Sstevel@tonic-gate /* 6577c478bd9Sstevel@tonic-gate * initialize internal state to idle: busy = 0, 6587c478bd9Sstevel@tonic-gate * power level = -1 6597c478bd9Sstevel@tonic-gate */ 6607c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 6617c478bd9Sstevel@tonic-gate pshot->busy = 0; 6627c478bd9Sstevel@tonic-gate pshot->busy_ioctl = 0; 6637c478bd9Sstevel@tonic-gate pshot->level = -1; 6647c478bd9Sstevel@tonic-gate pshot->state &= ~STRICT_PARENT; 6657c478bd9Sstevel@tonic-gate pshot->state |= PM_SUPPORTED; 6667c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate /* 6697c478bd9Sstevel@tonic-gate * Create the "pm-want-child-notification?" property 6707c478bd9Sstevel@tonic-gate * for the root node /devices/pshot 6717c478bd9Sstevel@tonic-gate */ 6727c478bd9Sstevel@tonic-gate if (instance == 0) { 6737c478bd9Sstevel@tonic-gate if (pshot_debug) { 6747c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:\n\t" 6757c478bd9Sstevel@tonic-gate " create the" 6767c478bd9Sstevel@tonic-gate " \"pm-want-child-notification?\" property" 6777c478bd9Sstevel@tonic-gate " for the root node\n", instance); 6787c478bd9Sstevel@tonic-gate } 6797c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, devi, 0, 6807c478bd9Sstevel@tonic-gate "pm-want-child-notification?", NULL, 0) 6817c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 6827c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d:\n\t" 6837c478bd9Sstevel@tonic-gate " unable to create the" 6847c478bd9Sstevel@tonic-gate " \"pm-want-child-notification?\"" 6857c478bd9Sstevel@tonic-gate " property", ddi_get_name(devi), 6867c478bd9Sstevel@tonic-gate ddi_get_instance(devi)); 6877c478bd9Sstevel@tonic-gate 6887c478bd9Sstevel@tonic-gate goto FAIL_ATTACH; 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate 6927c478bd9Sstevel@tonic-gate /* 6937c478bd9Sstevel@tonic-gate * Check if the pm-want-child-notification? property was 6947c478bd9Sstevel@tonic-gate * created in pshot_bus_config_setup_nexus() by the parent. 6957c478bd9Sstevel@tonic-gate * Set the STRICT_PARENT flag if not. 6967c478bd9Sstevel@tonic-gate */ 6977c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, devi, 6987c478bd9Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 6997c478bd9Sstevel@tonic-gate "pm-want-child-notification?") != 1) { 7007c478bd9Sstevel@tonic-gate if (pshot_debug) { 7017c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:" 7027c478bd9Sstevel@tonic-gate " STRICT PARENT\n", instance); 7037c478bd9Sstevel@tonic-gate } 7047c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 7057c478bd9Sstevel@tonic-gate pshot->state |= STRICT_PARENT; 7067c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 7077c478bd9Sstevel@tonic-gate } else { 7087c478bd9Sstevel@tonic-gate if (pshot_debug) { 7097c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:" 7107c478bd9Sstevel@tonic-gate " INVOLVED PARENT\n", instance); 7117c478bd9Sstevel@tonic-gate } 7127c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 7137c478bd9Sstevel@tonic-gate pshot->state &= ~STRICT_PARENT; 7147c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 7157c478bd9Sstevel@tonic-gate } 7167c478bd9Sstevel@tonic-gate 7177c478bd9Sstevel@tonic-gate /* 7187c478bd9Sstevel@tonic-gate * create the pm-components property: one component 7197c478bd9Sstevel@tonic-gate * with 4 power levels. 7207c478bd9Sstevel@tonic-gate * - skip for pshot@XXX,nopm and pshot@XXX,nopm_strict: 7217c478bd9Sstevel@tonic-gate * "no-pm-components" property 7227c478bd9Sstevel@tonic-gate */ 7237c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, devi, 7247c478bd9Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 7257c478bd9Sstevel@tonic-gate "no-pm-components") == 0) { 7267c478bd9Sstevel@tonic-gate if (pshot_debug) { 7277c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:" 7287c478bd9Sstevel@tonic-gate " create the \"pm_components\" property\n", 7297c478bd9Sstevel@tonic-gate instance); 7307c478bd9Sstevel@tonic-gate } 7317c478bd9Sstevel@tonic-gate if (ddi_prop_update_string_array(DDI_DEV_T_NONE, devi, 7327c478bd9Sstevel@tonic-gate "pm-components", pm_comp, 5) != DDI_PROP_SUCCESS) { 7337c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t" 7347c478bd9Sstevel@tonic-gate " unable to create the \"pm-components\"" 7357c478bd9Sstevel@tonic-gate " property", ddi_get_name(devi), 7367c478bd9Sstevel@tonic-gate ddi_get_instance(devi)); 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate goto FAIL_ATTACH; 7397c478bd9Sstevel@tonic-gate } 7407c478bd9Sstevel@tonic-gate } else { 7417c478bd9Sstevel@tonic-gate if (pshot_debug) { 7427c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:" 7437c478bd9Sstevel@tonic-gate " NO-PM_COMPONENTS PARENT\n", instance); 7447c478bd9Sstevel@tonic-gate } 7457c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 7467c478bd9Sstevel@tonic-gate pshot->state &= ~PM_SUPPORTED; 7477c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 7487c478bd9Sstevel@tonic-gate } 7497c478bd9Sstevel@tonic-gate 7507c478bd9Sstevel@tonic-gate /* 7517c478bd9Sstevel@tonic-gate * create the property needed to get DDI_SUSPEND 7527c478bd9Sstevel@tonic-gate * and DDI_RESUME calls 7537c478bd9Sstevel@tonic-gate */ 7547c478bd9Sstevel@tonic-gate if (pshot_debug) { 7557c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:" 7567c478bd9Sstevel@tonic-gate " create pm-hardware-state property\n", 7577c478bd9Sstevel@tonic-gate instance); 7587c478bd9Sstevel@tonic-gate } 7597c478bd9Sstevel@tonic-gate if (ddi_prop_update_string(DDI_DEV_T_NONE, devi, 7607c478bd9Sstevel@tonic-gate "pm-hardware-state", pm_hw_state) != DDI_PROP_SUCCESS) { 7617c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_ATTACH:\n\t" 7627c478bd9Sstevel@tonic-gate " unable to create the \"pm-hardware-state\"" 7637c478bd9Sstevel@tonic-gate " property", ddi_get_name(devi), 7647c478bd9Sstevel@tonic-gate ddi_get_instance(devi)); 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate goto FAIL_ATTACH; 7677c478bd9Sstevel@tonic-gate } 7687c478bd9Sstevel@tonic-gate 7697c478bd9Sstevel@tonic-gate /* 7707c478bd9Sstevel@tonic-gate * set power level to max via pm_raise_power(), 7717c478bd9Sstevel@tonic-gate * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm) 7727c478bd9Sstevel@tonic-gate */ 7737c478bd9Sstevel@tonic-gate if (pshot->state & PM_SUPPORTED) { 7747c478bd9Sstevel@tonic-gate if (pshot_debug) { 7757c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_ATTACH:" 7767c478bd9Sstevel@tonic-gate " raise power to MAXPWR\n", instance); 7777c478bd9Sstevel@tonic-gate } 7787c478bd9Sstevel@tonic-gate if (pm_raise_power(pshot->dip, 0, MAXPWR) != 7797c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 7807c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_ATTACH:" 7817c478bd9Sstevel@tonic-gate " pm_raise_power failed", 7827c478bd9Sstevel@tonic-gate ddi_get_name(devi), 7837c478bd9Sstevel@tonic-gate ddi_get_instance(devi)); 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate goto FAIL_ATTACH; 7867c478bd9Sstevel@tonic-gate 7877c478bd9Sstevel@tonic-gate } 7887c478bd9Sstevel@tonic-gate } 7897c478bd9Sstevel@tonic-gate 7907c478bd9Sstevel@tonic-gate if (pshot_log) 7917c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d attached\n", instance); 7927c478bd9Sstevel@tonic-gate ddi_report_dev(devi); 7937c478bd9Sstevel@tonic-gate 7947c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 7957c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 7967c478bd9Sstevel@tonic-gate FAIL_ATTACH: 7977c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 7987c478bd9Sstevel@tonic-gate mutex_destroy(&pshot->lock); 7997c478bd9Sstevel@tonic-gate ddi_soft_state_free(pshot_softstatep, instance); 8007c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8017c478bd9Sstevel@tonic-gate 8027c478bd9Sstevel@tonic-gate case DDI_RESUME: 8037c478bd9Sstevel@tonic-gate if (pshot_debug) { 8047c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_RESUME: resuming\n", 8057c478bd9Sstevel@tonic-gate instance); 8067c478bd9Sstevel@tonic-gate } 8077c478bd9Sstevel@tonic-gate pshot = ddi_get_soft_state(pshot_softstatep, instance); 8087c478bd9Sstevel@tonic-gate 8097c478bd9Sstevel@tonic-gate /* 8107c478bd9Sstevel@tonic-gate * set power level to max via pm_raise_power(), 8117c478bd9Sstevel@tonic-gate * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm) 8127c478bd9Sstevel@tonic-gate */ 8137c478bd9Sstevel@tonic-gate if (pshot->state & PM_SUPPORTED) { 8147c478bd9Sstevel@tonic-gate if (pshot_debug) { 8157c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_RESUME:" 8167c478bd9Sstevel@tonic-gate " raise power to MAXPWR\n", instance); 8177c478bd9Sstevel@tonic-gate } 8187c478bd9Sstevel@tonic-gate if (pm_raise_power(pshot->dip, 0, MAXPWR) != 8197c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 8207c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_RESUME:" 8217c478bd9Sstevel@tonic-gate " pm_raise_power failed", 8227c478bd9Sstevel@tonic-gate ddi_get_name(devi), 8237c478bd9Sstevel@tonic-gate ddi_get_instance(devi)); 8247c478bd9Sstevel@tonic-gate } 8257c478bd9Sstevel@tonic-gate } 8267c478bd9Sstevel@tonic-gate 8277c478bd9Sstevel@tonic-gate if (pshot_debug) { 8287c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_RESUME: resumed\n", 8297c478bd9Sstevel@tonic-gate instance); 8307c478bd9Sstevel@tonic-gate } 8317c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 8327c478bd9Sstevel@tonic-gate 8337c478bd9Sstevel@tonic-gate default: 8347c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8357c478bd9Sstevel@tonic-gate } 8367c478bd9Sstevel@tonic-gate } 8377c478bd9Sstevel@tonic-gate 8387c478bd9Sstevel@tonic-gate static int 8397c478bd9Sstevel@tonic-gate pshot_detach(dev_info_t *devi, ddi_detach_cmd_t cmd) 8407c478bd9Sstevel@tonic-gate { 8417c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(devi); 8427c478bd9Sstevel@tonic-gate int i, rval; 8437c478bd9Sstevel@tonic-gate pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance); 8447c478bd9Sstevel@tonic-gate int level_tmp; 8457c478bd9Sstevel@tonic-gate 8467c478bd9Sstevel@tonic-gate if (pshot == NULL) 8477c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8487c478bd9Sstevel@tonic-gate 8497c478bd9Sstevel@tonic-gate switch (cmd) { 8507c478bd9Sstevel@tonic-gate 8517c478bd9Sstevel@tonic-gate case DDI_DETACH: 8527c478bd9Sstevel@tonic-gate if (pshot_debug) 8537c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_DETACH\n", instance); 8547c478bd9Sstevel@tonic-gate /* 8557c478bd9Sstevel@tonic-gate * power off component 0 8567c478bd9Sstevel@tonic-gate * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm) 8577c478bd9Sstevel@tonic-gate */ 8587c478bd9Sstevel@tonic-gate if (pshot->state & PM_SUPPORTED) { 8597c478bd9Sstevel@tonic-gate if (pshot_debug) { 8607c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_DETACH:" 8617c478bd9Sstevel@tonic-gate " power off\n", instance); 8627c478bd9Sstevel@tonic-gate } 8637c478bd9Sstevel@tonic-gate if (pm_lower_power(pshot->dip, 0, 0) != DDI_SUCCESS) { 8647c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: DDI_DETACH:\n\t" 8657c478bd9Sstevel@tonic-gate "pm_lower_power failed for comp 0 to" 8667c478bd9Sstevel@tonic-gate " level 0", ddi_get_name(devi), 8677c478bd9Sstevel@tonic-gate ddi_get_instance(devi)); 8687c478bd9Sstevel@tonic-gate 8697c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8707c478bd9Sstevel@tonic-gate } 8717c478bd9Sstevel@tonic-gate 8727c478bd9Sstevel@tonic-gate /* 8737c478bd9Sstevel@tonic-gate * Check if the power level is actually OFF. 8747c478bd9Sstevel@tonic-gate * Issue pm_power_has_changed if not. 8757c478bd9Sstevel@tonic-gate */ 8767c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 8777c478bd9Sstevel@tonic-gate if (pshot->level != 0) { 8787c478bd9Sstevel@tonic-gate if (pshot_debug) { 8797c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "pshot%d:" 8807c478bd9Sstevel@tonic-gate " DDI_DETACH: power off via" 8817c478bd9Sstevel@tonic-gate " pm_power_has_changed instead\n", 8827c478bd9Sstevel@tonic-gate instance); 8837c478bd9Sstevel@tonic-gate } 8847c478bd9Sstevel@tonic-gate level_tmp = pshot->level; 8857c478bd9Sstevel@tonic-gate pshot->level = 0; 8867c478bd9Sstevel@tonic-gate if (pm_power_has_changed(pshot->dip, 0, 0) != 8877c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 8887c478bd9Sstevel@tonic-gate if (pshot_debug) { 8897c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "pshot%d:" 8907c478bd9Sstevel@tonic-gate " DDI_DETACH:" 8917c478bd9Sstevel@tonic-gate " pm_power_has_changed" 8927c478bd9Sstevel@tonic-gate " failed\n", instance); 8937c478bd9Sstevel@tonic-gate } 8947c478bd9Sstevel@tonic-gate pshot->level = level_tmp; 8957c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 8967c478bd9Sstevel@tonic-gate 8977c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 8987c478bd9Sstevel@tonic-gate } 8997c478bd9Sstevel@tonic-gate } 9007c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 9017c478bd9Sstevel@tonic-gate } 9027c478bd9Sstevel@tonic-gate 9037c478bd9Sstevel@tonic-gate for (i = 0; i < PSHOT_N_DDI_EVENTS; i++) { 9047c478bd9Sstevel@tonic-gate if (pshot->callback_cache[i] != NULL) { 9057c478bd9Sstevel@tonic-gate rval = ddi_remove_event_handler( 9067c478bd9Sstevel@tonic-gate pshot->callback_cache[i]); 9077c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 9087c478bd9Sstevel@tonic-gate } 9097c478bd9Sstevel@tonic-gate } 9107c478bd9Sstevel@tonic-gate 9117c478bd9Sstevel@tonic-gate #ifdef DEBUG 9127c478bd9Sstevel@tonic-gate for (i = 0; i < PSHOT_N_TEST_EVENTS; i++) { 9137c478bd9Sstevel@tonic-gate if (pshot->test_callback_cache[i] != NULL) { 9147c478bd9Sstevel@tonic-gate rval = ddi_remove_event_handler( 9157c478bd9Sstevel@tonic-gate pshot->test_callback_cache[i]); 9167c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 9177c478bd9Sstevel@tonic-gate } 9187c478bd9Sstevel@tonic-gate } 9197c478bd9Sstevel@tonic-gate #endif 9207c478bd9Sstevel@tonic-gate rval = ndi_event_free_hdl(pshot->ndi_event_hdl); 9217c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 9227c478bd9Sstevel@tonic-gate 9237c478bd9Sstevel@tonic-gate if (pshot_log) 9247c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d detached\n", instance); 9257c478bd9Sstevel@tonic-gate 9267c478bd9Sstevel@tonic-gate ddi_remove_minor_node(devi, NULL); 9277c478bd9Sstevel@tonic-gate mutex_destroy(&pshot->lock); 9287c478bd9Sstevel@tonic-gate ddi_soft_state_free(pshot_softstatep, instance); 9297c478bd9Sstevel@tonic-gate break; 9307c478bd9Sstevel@tonic-gate 9317c478bd9Sstevel@tonic-gate case DDI_SUSPEND: 9327c478bd9Sstevel@tonic-gate if (pshot_debug) 9337c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_SUSPEND\n", instance); 9347c478bd9Sstevel@tonic-gate /* 9357c478bd9Sstevel@tonic-gate * fail the suspend if FAIL_SUSPEND_FLAG is set. 9367c478bd9Sstevel@tonic-gate * clear the FAIL_SUSPEND_FLAG flag 9377c478bd9Sstevel@tonic-gate */ 9387c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 9397c478bd9Sstevel@tonic-gate if (pshot->state & FAIL_SUSPEND_FLAG) { 9407c478bd9Sstevel@tonic-gate if (pshot_debug) { 9417c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d:" 9427c478bd9Sstevel@tonic-gate " FAIL_SUSPEND_FLAG set, fail suspend\n", 9437c478bd9Sstevel@tonic-gate ddi_get_instance(devi)); 9447c478bd9Sstevel@tonic-gate } 9457c478bd9Sstevel@tonic-gate pshot->state &= ~FAIL_SUSPEND_FLAG; 9467c478bd9Sstevel@tonic-gate rval = DDI_FAILURE; 9477c478bd9Sstevel@tonic-gate } else { 9487c478bd9Sstevel@tonic-gate rval = DDI_SUCCESS; 9497c478bd9Sstevel@tonic-gate } 9507c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 9517c478bd9Sstevel@tonic-gate 9527c478bd9Sstevel@tonic-gate /* 9537c478bd9Sstevel@tonic-gate * power OFF via pm_power_has_changed 9547c478bd9Sstevel@tonic-gate */ 9557c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 9567c478bd9Sstevel@tonic-gate if (pshot->state & PM_SUPPORTED) { 9577c478bd9Sstevel@tonic-gate if (pshot_debug) { 9587c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DDI_SUSPEND:" 9597c478bd9Sstevel@tonic-gate " power off via pm_power_has_changed\n", 9607c478bd9Sstevel@tonic-gate instance); 9617c478bd9Sstevel@tonic-gate } 9627c478bd9Sstevel@tonic-gate level_tmp = pshot->level; 9637c478bd9Sstevel@tonic-gate pshot->level = 0; 9647c478bd9Sstevel@tonic-gate if (pm_power_has_changed(pshot->dip, 0, 0) != 9657c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 9667c478bd9Sstevel@tonic-gate if (pshot_debug) { 9677c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "pshot%d:" 9687c478bd9Sstevel@tonic-gate " DDI_SUSPEND:" 9697c478bd9Sstevel@tonic-gate " pm_power_has_changed failed\n", 9707c478bd9Sstevel@tonic-gate instance); 9717c478bd9Sstevel@tonic-gate } 9727c478bd9Sstevel@tonic-gate pshot->level = level_tmp; 9737c478bd9Sstevel@tonic-gate rval = DDI_FAILURE; 9747c478bd9Sstevel@tonic-gate } 9757c478bd9Sstevel@tonic-gate } 9767c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 9777c478bd9Sstevel@tonic-gate return (rval); 9787c478bd9Sstevel@tonic-gate 9797c478bd9Sstevel@tonic-gate default: 9807c478bd9Sstevel@tonic-gate break; 9817c478bd9Sstevel@tonic-gate } 9827c478bd9Sstevel@tonic-gate 9837c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 9847c478bd9Sstevel@tonic-gate } 9857c478bd9Sstevel@tonic-gate 9867c478bd9Sstevel@tonic-gate 9877c478bd9Sstevel@tonic-gate /* 9887c478bd9Sstevel@tonic-gate * returns number of bits to represent <val> 9897c478bd9Sstevel@tonic-gate */ 9907c478bd9Sstevel@tonic-gate static size_t 9917c478bd9Sstevel@tonic-gate pshot_numbits(size_t val) 9927c478bd9Sstevel@tonic-gate { 9937c478bd9Sstevel@tonic-gate size_t bitcnt; 9947c478bd9Sstevel@tonic-gate 9957c478bd9Sstevel@tonic-gate if (val == 0) 9967c478bd9Sstevel@tonic-gate return (0); 9977c478bd9Sstevel@tonic-gate for (bitcnt = 1; 1 << bitcnt < val; bitcnt++) 9987c478bd9Sstevel@tonic-gate ; 9997c478bd9Sstevel@tonic-gate return (bitcnt); 10007c478bd9Sstevel@tonic-gate } 10017c478bd9Sstevel@tonic-gate 10027c478bd9Sstevel@tonic-gate /* 10037c478bd9Sstevel@tonic-gate * returns a minor number encoded with instance <inst> and an index <nodenum> 10047c478bd9Sstevel@tonic-gate * that identifies the minor node for this instance 10057c478bd9Sstevel@tonic-gate */ 10067c478bd9Sstevel@tonic-gate static minor_t 10077c478bd9Sstevel@tonic-gate pshot_minor_encode(int inst, minor_t nodenum) 10087c478bd9Sstevel@tonic-gate { 10097c478bd9Sstevel@tonic-gate return (((minor_t)inst << PSHOT_NODENUM_BITS()) | 10107c478bd9Sstevel@tonic-gate (((1 << PSHOT_NODENUM_BITS()) - 1) & nodenum)); 10117c478bd9Sstevel@tonic-gate } 10127c478bd9Sstevel@tonic-gate 10137c478bd9Sstevel@tonic-gate /* 10147c478bd9Sstevel@tonic-gate * returns instance of <minor> 10157c478bd9Sstevel@tonic-gate */ 10167c478bd9Sstevel@tonic-gate static int 10177c478bd9Sstevel@tonic-gate pshot_minor_decode_inst(minor_t minor) 10187c478bd9Sstevel@tonic-gate { 10197c478bd9Sstevel@tonic-gate return (minor >> PSHOT_NODENUM_BITS()); 10207c478bd9Sstevel@tonic-gate } 10217c478bd9Sstevel@tonic-gate 10227c478bd9Sstevel@tonic-gate /* 10237c478bd9Sstevel@tonic-gate * returns node number indexing a minor node for the instance in <minor> 10247c478bd9Sstevel@tonic-gate */ 10257c478bd9Sstevel@tonic-gate static minor_t 10267c478bd9Sstevel@tonic-gate pshot_minor_decode_nodenum(minor_t minor) 10277c478bd9Sstevel@tonic-gate { 10287c478bd9Sstevel@tonic-gate return (minor & ((1 << PSHOT_NODENUM_BITS()) - 1)); 10297c478bd9Sstevel@tonic-gate } 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate 10327c478bd9Sstevel@tonic-gate /* 10337c478bd9Sstevel@tonic-gate * pshot_bus_introp: pshot convert an interrupt number to an 10347c478bd9Sstevel@tonic-gate * interrupt. NO OP for pseudo drivers. 10357c478bd9Sstevel@tonic-gate */ 10367c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 10377c478bd9Sstevel@tonic-gate static int 10387c478bd9Sstevel@tonic-gate pshot_bus_introp(dev_info_t *dip, dev_info_t *rdip, ddi_intr_op_t intr_op, 10397c478bd9Sstevel@tonic-gate ddi_intr_handle_impl_t *hdlp, void *result) 10407c478bd9Sstevel@tonic-gate { 10417c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10427c478bd9Sstevel@tonic-gate } 10437c478bd9Sstevel@tonic-gate static int 10447c478bd9Sstevel@tonic-gate pshot_ctl(dev_info_t *dip, dev_info_t *rdip, 10457c478bd9Sstevel@tonic-gate ddi_ctl_enum_t ctlop, void *arg, void *result) 10467c478bd9Sstevel@tonic-gate { 10477c478bd9Sstevel@tonic-gate int instance; 10487c478bd9Sstevel@tonic-gate pshot_t *pshot; 10497c478bd9Sstevel@tonic-gate char *childname; 10507c478bd9Sstevel@tonic-gate int childinstance; 10517c478bd9Sstevel@tonic-gate char *name; 10527c478bd9Sstevel@tonic-gate int circ; 10537c478bd9Sstevel@tonic-gate struct attachspec *as; 10547c478bd9Sstevel@tonic-gate struct detachspec *ds; 10557c478bd9Sstevel@tonic-gate int rval = DDI_SUCCESS; 10567c478bd9Sstevel@tonic-gate int no_pm_components_child; 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate name = ddi_get_name(dip); 10597c478bd9Sstevel@tonic-gate instance = ddi_get_instance(dip); 10607c478bd9Sstevel@tonic-gate pshot = ddi_get_soft_state(pshot_softstatep, instance); 10617c478bd9Sstevel@tonic-gate if (pshot == NULL) { 10627c478bd9Sstevel@tonic-gate return (ENXIO); 10637c478bd9Sstevel@tonic-gate } 10647c478bd9Sstevel@tonic-gate 10657c478bd9Sstevel@tonic-gate switch (ctlop) { 10667c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTDEV: 10677c478bd9Sstevel@tonic-gate if (rdip == (dev_info_t *)0) 10687c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 10697c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "?pshot-device: %s%d\n", 10707c478bd9Sstevel@tonic-gate ddi_get_name(rdip), ddi_get_instance(rdip)); 10717c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 10727c478bd9Sstevel@tonic-gate 10737c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INITCHILD: 10747c478bd9Sstevel@tonic-gate { 10757c478bd9Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)arg; 10767c478bd9Sstevel@tonic-gate 10777c478bd9Sstevel@tonic-gate if (pshot_debug) { 10787c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "initchild %s%d/%s%d state 0x%x\n", 10797c478bd9Sstevel@tonic-gate ddi_get_name(dip), ddi_get_instance(dip), 10807c478bd9Sstevel@tonic-gate ddi_node_name(child), ddi_get_instance(child), 10817c478bd9Sstevel@tonic-gate DEVI(child)->devi_state); 10827c478bd9Sstevel@tonic-gate } 10837c478bd9Sstevel@tonic-gate 10847c478bd9Sstevel@tonic-gate return (pshot_initchild(dip, child)); 10857c478bd9Sstevel@tonic-gate } 10867c478bd9Sstevel@tonic-gate 10877c478bd9Sstevel@tonic-gate case DDI_CTLOPS_UNINITCHILD: 10887c478bd9Sstevel@tonic-gate { 10897c478bd9Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)arg; 10907c478bd9Sstevel@tonic-gate 10917c478bd9Sstevel@tonic-gate if (pshot_debug) { 10927c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "uninitchild %s%d/%s%d state 0x%x\n", 10937c478bd9Sstevel@tonic-gate ddi_get_name(dip), ddi_get_instance(dip), 10947c478bd9Sstevel@tonic-gate ddi_node_name(child), ddi_get_instance(child), 10957c478bd9Sstevel@tonic-gate DEVI(child)->devi_state); 10967c478bd9Sstevel@tonic-gate } 10977c478bd9Sstevel@tonic-gate 10987c478bd9Sstevel@tonic-gate return (pshot_uninitchild(dip, child)); 10997c478bd9Sstevel@tonic-gate } 11007c478bd9Sstevel@tonic-gate 11017c478bd9Sstevel@tonic-gate case DDI_CTLOPS_DMAPMAPC: 11027c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REPORTINT: 11037c478bd9Sstevel@tonic-gate case DDI_CTLOPS_REGSIZE: 11047c478bd9Sstevel@tonic-gate case DDI_CTLOPS_NREGS: 11057c478bd9Sstevel@tonic-gate case DDI_CTLOPS_NINTRS: 11067c478bd9Sstevel@tonic-gate case DDI_CTLOPS_SIDDEV: 11077c478bd9Sstevel@tonic-gate case DDI_CTLOPS_SLAVEONLY: 11087c478bd9Sstevel@tonic-gate case DDI_CTLOPS_AFFINITY: 11097c478bd9Sstevel@tonic-gate case DDI_CTLOPS_INTR_HILEVEL: 11107c478bd9Sstevel@tonic-gate case DDI_CTLOPS_XLATE_INTRS: 11117c478bd9Sstevel@tonic-gate case DDI_CTLOPS_POKE: 11127c478bd9Sstevel@tonic-gate case DDI_CTLOPS_PEEK: 11137c478bd9Sstevel@tonic-gate /* 11147c478bd9Sstevel@tonic-gate * These ops correspond to functions that "shouldn't" be called 11157c478bd9Sstevel@tonic-gate * by a pseudo driver. So we whine when we're called. 11167c478bd9Sstevel@tonic-gate */ 11177c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: invalid op (%d) from %s%d\n", 11187c478bd9Sstevel@tonic-gate ddi_get_name(dip), ddi_get_instance(dip), 11197c478bd9Sstevel@tonic-gate ctlop, ddi_get_name(rdip), ddi_get_instance(rdip)); 11207c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 11217c478bd9Sstevel@tonic-gate 11227c478bd9Sstevel@tonic-gate case DDI_CTLOPS_ATTACH: 11237c478bd9Sstevel@tonic-gate { 11247c478bd9Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)rdip; 11257c478bd9Sstevel@tonic-gate childname = ddi_node_name(child); 11267c478bd9Sstevel@tonic-gate childinstance = ddi_get_instance(child); 11277c478bd9Sstevel@tonic-gate as = (struct attachspec *)arg; 11287c478bd9Sstevel@tonic-gate 11297c478bd9Sstevel@tonic-gate no_pm_components_child = 0; 11307c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, child, 11317c478bd9Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 11327c478bd9Sstevel@tonic-gate "no-pm-components") == 1) { 11337c478bd9Sstevel@tonic-gate no_pm_components_child = 1; 11347c478bd9Sstevel@tonic-gate } 11357c478bd9Sstevel@tonic-gate if (pshot_debug) { 11367c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: ctl_attach %s%d [%d]\n", 11377c478bd9Sstevel@tonic-gate name, instance, childname, childinstance, 11387c478bd9Sstevel@tonic-gate no_pm_components_child); 11397c478bd9Sstevel@tonic-gate } 11407c478bd9Sstevel@tonic-gate 11417c478bd9Sstevel@tonic-gate ndi_devi_enter(dip, &circ); 11427c478bd9Sstevel@tonic-gate 11437c478bd9Sstevel@tonic-gate switch (as->when) { 11447c478bd9Sstevel@tonic-gate case DDI_PRE: 11457c478bd9Sstevel@tonic-gate /* 11467c478bd9Sstevel@tonic-gate * Mark nexus busy before a child attaches. 11477c478bd9Sstevel@tonic-gate * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm 11487c478bd9Sstevel@tonic-gate * - pshot@XXX,nopm_strict) 11497c478bd9Sstevel@tonic-gate */ 11507c478bd9Sstevel@tonic-gate if (!(pshot->state & PM_SUPPORTED)) 11517c478bd9Sstevel@tonic-gate break; 11527c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 11537c478bd9Sstevel@tonic-gate ++(pshot->busy); 11547c478bd9Sstevel@tonic-gate if (pshot_debug_busy) { 11557c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d:" 11567c478bd9Sstevel@tonic-gate " ctl_attach_pre: busy for %s%d:" 11577c478bd9Sstevel@tonic-gate " busy = %d\n", name, instance, 11587c478bd9Sstevel@tonic-gate childname, childinstance, 11597c478bd9Sstevel@tonic-gate pshot->busy); 11607c478bd9Sstevel@tonic-gate } 11617c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 11627c478bd9Sstevel@tonic-gate rval = pm_busy_component(dip, 0); 11637c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 11647c478bd9Sstevel@tonic-gate break; 11657c478bd9Sstevel@tonic-gate case DDI_POST: 11667c478bd9Sstevel@tonic-gate /* 11677c478bd9Sstevel@tonic-gate * Mark nexus idle after a child attaches. 11687c478bd9Sstevel@tonic-gate * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm). 11697c478bd9Sstevel@tonic-gate * - also skip if this is not a stict parent and 11707c478bd9Sstevel@tonic-gate * - the child is a tape device or a no-pm-components 11717c478bd9Sstevel@tonic-gate * - nexus node. 11727c478bd9Sstevel@tonic-gate */ 11737c478bd9Sstevel@tonic-gate if (!(pshot->state & PM_SUPPORTED) || 11747c478bd9Sstevel@tonic-gate (strcmp(childname, "tape") == 0 && 11757c478bd9Sstevel@tonic-gate !(pshot->state & STRICT_PARENT)) || 11767c478bd9Sstevel@tonic-gate no_pm_components_child) 11777c478bd9Sstevel@tonic-gate break; 11787c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 11797c478bd9Sstevel@tonic-gate ASSERT(pshot->busy > 0); 11807c478bd9Sstevel@tonic-gate --pshot->busy; 11817c478bd9Sstevel@tonic-gate if (pshot_debug_busy) { 11827c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d:" 11837c478bd9Sstevel@tonic-gate " ctl_attach_post: idle for %s%d:" 11847c478bd9Sstevel@tonic-gate " busy = %d\n", name, instance, 11857c478bd9Sstevel@tonic-gate childname, childinstance, 11867c478bd9Sstevel@tonic-gate pshot->busy); 11877c478bd9Sstevel@tonic-gate } 11887c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 11897c478bd9Sstevel@tonic-gate rval = pm_idle_component(dip, 0); 11907c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 11917c478bd9Sstevel@tonic-gate break; 11927c478bd9Sstevel@tonic-gate } 11937c478bd9Sstevel@tonic-gate 11947c478bd9Sstevel@tonic-gate ndi_devi_exit(dip, circ); 11957c478bd9Sstevel@tonic-gate 11967c478bd9Sstevel@tonic-gate return (rval); 11977c478bd9Sstevel@tonic-gate } 11987c478bd9Sstevel@tonic-gate case DDI_CTLOPS_BTOP: 11997c478bd9Sstevel@tonic-gate case DDI_CTLOPS_BTOPR: 12007c478bd9Sstevel@tonic-gate case DDI_CTLOPS_DETACH: 12017c478bd9Sstevel@tonic-gate { 12027c478bd9Sstevel@tonic-gate dev_info_t *child = (dev_info_t *)rdip; 12037c478bd9Sstevel@tonic-gate childname = ddi_node_name(child); 12047c478bd9Sstevel@tonic-gate childinstance = ddi_get_instance(child); 12057c478bd9Sstevel@tonic-gate ds = (struct detachspec *)arg; 12067c478bd9Sstevel@tonic-gate 12077c478bd9Sstevel@tonic-gate no_pm_components_child = 0; 12087c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, child, 12097c478bd9Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 12107c478bd9Sstevel@tonic-gate "no-pm-components") == 1) { 12117c478bd9Sstevel@tonic-gate no_pm_components_child = 1; 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate if (pshot_debug) { 12147c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 12157c478bd9Sstevel@tonic-gate "%s%d: ctl_detach %s%d [%d]\n", 12167c478bd9Sstevel@tonic-gate name, instance, childname, childinstance, 12177c478bd9Sstevel@tonic-gate no_pm_components_child); 12187c478bd9Sstevel@tonic-gate } 12197c478bd9Sstevel@tonic-gate 12207c478bd9Sstevel@tonic-gate ndi_devi_enter(dip, &circ); 12217c478bd9Sstevel@tonic-gate 12227c478bd9Sstevel@tonic-gate switch (ds->when) { 12237c478bd9Sstevel@tonic-gate case DDI_PRE: 12247c478bd9Sstevel@tonic-gate /* 12257c478bd9Sstevel@tonic-gate * Mark nexus busy before a child detaches. 12267c478bd9Sstevel@tonic-gate * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm 12277c478bd9Sstevel@tonic-gate * - pshot@XXX,nopm_strict), or if the child is a 12287c478bd9Sstevel@tonic-gate * - no-pm-components nexus node. 12297c478bd9Sstevel@tonic-gate */ 12307c478bd9Sstevel@tonic-gate if (!(pshot->state & PM_SUPPORTED) || 12317c478bd9Sstevel@tonic-gate (strcmp(childname, "tape") == 0 && 12327c478bd9Sstevel@tonic-gate !(pshot->state & STRICT_PARENT)) || 12337c478bd9Sstevel@tonic-gate no_pm_components_child) 12347c478bd9Sstevel@tonic-gate break; 12357c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 12367c478bd9Sstevel@tonic-gate ++(pshot->busy); 12377c478bd9Sstevel@tonic-gate if (pshot_debug_busy) { 12387c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d:" 12397c478bd9Sstevel@tonic-gate " ctl_detach_pre: busy for %s%d:" 12407c478bd9Sstevel@tonic-gate " busy = %d\n", name, instance, 12417c478bd9Sstevel@tonic-gate childname, childinstance, 12427c478bd9Sstevel@tonic-gate pshot->busy); 12437c478bd9Sstevel@tonic-gate } 12447c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 12457c478bd9Sstevel@tonic-gate rval = pm_busy_component(dip, 0); 12467c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 12477c478bd9Sstevel@tonic-gate 12487c478bd9Sstevel@tonic-gate break; 12497c478bd9Sstevel@tonic-gate case DDI_POST: 12507c478bd9Sstevel@tonic-gate /* 12517c478bd9Sstevel@tonic-gate * Mark nexus idle after a child detaches. 12527c478bd9Sstevel@tonic-gate * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm) 12537c478bd9Sstevel@tonic-gate */ 12547c478bd9Sstevel@tonic-gate if (!(pshot->state & PM_SUPPORTED)) 12557c478bd9Sstevel@tonic-gate break; 12567c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 12577c478bd9Sstevel@tonic-gate ASSERT(pshot->busy > 0); 12587c478bd9Sstevel@tonic-gate --pshot->busy; 12597c478bd9Sstevel@tonic-gate if (pshot_debug_busy) { 12607c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d:" 12617c478bd9Sstevel@tonic-gate " ctl_detach_post: idle for %s%d:" 12627c478bd9Sstevel@tonic-gate " busy = %d\n", name, instance, 12637c478bd9Sstevel@tonic-gate childname, childinstance, 12647c478bd9Sstevel@tonic-gate pshot->busy); 12657c478bd9Sstevel@tonic-gate } 12667c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 12677c478bd9Sstevel@tonic-gate rval = pm_idle_component(dip, 0); 12687c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 12697c478bd9Sstevel@tonic-gate 12707c478bd9Sstevel@tonic-gate /* 12717c478bd9Sstevel@tonic-gate * Mark the driver idle if the NO_INVOL_FLAG 12727c478bd9Sstevel@tonic-gate * is set. This is needed to make sure the 12737c478bd9Sstevel@tonic-gate * parent is idle after the child detaches 12747c478bd9Sstevel@tonic-gate * without calling pm_lower_power(). 12757c478bd9Sstevel@tonic-gate * Clear the NO_INVOL_FLAG. 12767c478bd9Sstevel@tonic-gate * - also mark idle if a tape device has detached 12777c478bd9Sstevel@tonic-gate */ 12787c478bd9Sstevel@tonic-gate if (!(pshot->state & NO_INVOL_FLAG)) 12797c478bd9Sstevel@tonic-gate break; 12807c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 12817c478bd9Sstevel@tonic-gate ASSERT(pshot->busy > 0); 12827c478bd9Sstevel@tonic-gate --pshot->busy; 12837c478bd9Sstevel@tonic-gate if (pshot_debug_busy) { 12847c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d:" 12857c478bd9Sstevel@tonic-gate " ctl_detach_post: NO_INVOL:" 12867c478bd9Sstevel@tonic-gate " idle for %s%d: busy = %d\n", 12877c478bd9Sstevel@tonic-gate name, instance, childname, 12887c478bd9Sstevel@tonic-gate childinstance, pshot->busy); 12897c478bd9Sstevel@tonic-gate } 12907c478bd9Sstevel@tonic-gate pshot->state &= ~NO_INVOL_FLAG; 12917c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 12927c478bd9Sstevel@tonic-gate rval = pm_idle_component(dip, 0); 12937c478bd9Sstevel@tonic-gate ASSERT(rval == DDI_SUCCESS); 12947c478bd9Sstevel@tonic-gate 12957c478bd9Sstevel@tonic-gate break; 12967c478bd9Sstevel@tonic-gate } 12977c478bd9Sstevel@tonic-gate 12987c478bd9Sstevel@tonic-gate ndi_devi_exit(dip, circ); 12997c478bd9Sstevel@tonic-gate 13007c478bd9Sstevel@tonic-gate return (rval); 13017c478bd9Sstevel@tonic-gate } 13027c478bd9Sstevel@tonic-gate 13037c478bd9Sstevel@tonic-gate case DDI_CTLOPS_DVMAPAGESIZE: 13047c478bd9Sstevel@tonic-gate case DDI_CTLOPS_IOMIN: 13057c478bd9Sstevel@tonic-gate case DDI_CTLOPS_PTOB: 13067c478bd9Sstevel@tonic-gate default: 13077c478bd9Sstevel@tonic-gate /* 13087c478bd9Sstevel@tonic-gate * The ops that we pass up (default). We pass up memory 13097c478bd9Sstevel@tonic-gate * allocation oriented ops that we receive - these may be 13107c478bd9Sstevel@tonic-gate * associated with pseudo HBA drivers below us with target 13117c478bd9Sstevel@tonic-gate * drivers below them that use ddi memory allocation 13127c478bd9Sstevel@tonic-gate * interfaces like scsi_alloc_consistent_buf. 13137c478bd9Sstevel@tonic-gate */ 13147c478bd9Sstevel@tonic-gate return (ddi_ctlops(dip, rdip, ctlop, arg, result)); 13157c478bd9Sstevel@tonic-gate } 13167c478bd9Sstevel@tonic-gate } 13177c478bd9Sstevel@tonic-gate 13187c478bd9Sstevel@tonic-gate /*ARGSUSED0*/ 13197c478bd9Sstevel@tonic-gate static int 13207c478bd9Sstevel@tonic-gate pshot_power(dev_info_t *dip, int cmpt, int level) 13217c478bd9Sstevel@tonic-gate { 13227c478bd9Sstevel@tonic-gate pshot_t *pshot; 13237c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 13247c478bd9Sstevel@tonic-gate char *name = ddi_node_name(dip); 13257c478bd9Sstevel@tonic-gate int circ; 13267c478bd9Sstevel@tonic-gate int rv; 13277c478bd9Sstevel@tonic-gate 13287c478bd9Sstevel@tonic-gate pshot = ddi_get_soft_state(pshot_softstatep, instance); 13297c478bd9Sstevel@tonic-gate if (pshot == NULL) { 13307c478bd9Sstevel@tonic-gate 13317c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13327c478bd9Sstevel@tonic-gate } 13337c478bd9Sstevel@tonic-gate 13347c478bd9Sstevel@tonic-gate ndi_devi_enter(dip, &circ); 13357c478bd9Sstevel@tonic-gate 13367c478bd9Sstevel@tonic-gate /* 13377c478bd9Sstevel@tonic-gate * set POWER_FLAG when power() is called. 13387c478bd9Sstevel@tonic-gate * ioctl(DEVCT_PM_POWER) is a clear on read call. 13397c478bd9Sstevel@tonic-gate */ 13407c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 13417c478bd9Sstevel@tonic-gate pshot->state |= POWER_FLAG; 13427c478bd9Sstevel@tonic-gate /* 13437c478bd9Sstevel@tonic-gate * refuse to power OFF if the component is busy 13447c478bd9Sstevel@tonic-gate */ 13457c478bd9Sstevel@tonic-gate if (pshot->busy != 0 && pshot->level > level) { 13467c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d: power: REFUSING POWER LEVEL CHANGE" 13477c478bd9Sstevel@tonic-gate " (%d->%d), DEVICE NOT IDLE: busy = %d", 13487c478bd9Sstevel@tonic-gate name, instance, pshot->level, level, pshot->busy); 13497c478bd9Sstevel@tonic-gate rv = DDI_FAILURE; 13507c478bd9Sstevel@tonic-gate } else { 13517c478bd9Sstevel@tonic-gate if (pshot_debug) { 13527c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: power: comp %d (%d->%d)\n", 13537c478bd9Sstevel@tonic-gate name, instance, cmpt, pshot->level, level); 13547c478bd9Sstevel@tonic-gate } 13557c478bd9Sstevel@tonic-gate pshot->level = level; 13567c478bd9Sstevel@tonic-gate rv = DDI_SUCCESS; 13577c478bd9Sstevel@tonic-gate } 13587c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 13597c478bd9Sstevel@tonic-gate 13607c478bd9Sstevel@tonic-gate ndi_devi_exit(dip, circ); 13617c478bd9Sstevel@tonic-gate 13627c478bd9Sstevel@tonic-gate return (rv); 13637c478bd9Sstevel@tonic-gate } 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate /*ARGSUSED0*/ 13667c478bd9Sstevel@tonic-gate static int 13677c478bd9Sstevel@tonic-gate pshot_bus_power(dev_info_t *dip, void *impl_arg, pm_bus_power_op_t op, 13687c478bd9Sstevel@tonic-gate void *arg, void *result) 13697c478bd9Sstevel@tonic-gate 13707c478bd9Sstevel@tonic-gate { 13717c478bd9Sstevel@tonic-gate int ret; 13727c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 13737c478bd9Sstevel@tonic-gate char *name = ddi_node_name(dip); 13747c478bd9Sstevel@tonic-gate pshot_t *pshot; 13757c478bd9Sstevel@tonic-gate pm_bp_child_pwrchg_t *bpc; 13767c478bd9Sstevel@tonic-gate pm_bp_nexus_pwrup_t bpn; 13777c478bd9Sstevel@tonic-gate pm_bp_has_changed_t *bphc; 13787c478bd9Sstevel@tonic-gate int pwrup_res; 13797c478bd9Sstevel@tonic-gate int ret_failed = 0; 13807c478bd9Sstevel@tonic-gate int pwrup_res_failed = 0; 13817c478bd9Sstevel@tonic-gate 13827c478bd9Sstevel@tonic-gate pshot = ddi_get_soft_state(pshot_softstatep, instance); 13837c478bd9Sstevel@tonic-gate if (pshot == NULL) { 13847c478bd9Sstevel@tonic-gate 13857c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 13867c478bd9Sstevel@tonic-gate } 13877c478bd9Sstevel@tonic-gate 13887c478bd9Sstevel@tonic-gate switch (op) { 13897c478bd9Sstevel@tonic-gate case BUS_POWER_PRE_NOTIFICATION: 13907c478bd9Sstevel@tonic-gate bpc = (pm_bp_child_pwrchg_t *)arg; 13917c478bd9Sstevel@tonic-gate if (pshot_debug) { 13927c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: pre_bus_power:" 13937c478bd9Sstevel@tonic-gate " %s%d comp %d (%d->%d)\n", 13947c478bd9Sstevel@tonic-gate name, instance, ddi_node_name(bpc->bpc_dip), 13957c478bd9Sstevel@tonic-gate ddi_get_instance(bpc->bpc_dip), 13967c478bd9Sstevel@tonic-gate bpc->bpc_comp, bpc->bpc_olevel, 13977c478bd9Sstevel@tonic-gate bpc->bpc_nlevel); 13987c478bd9Sstevel@tonic-gate } 13997c478bd9Sstevel@tonic-gate 14007c478bd9Sstevel@tonic-gate /* 14017c478bd9Sstevel@tonic-gate * mark parent busy if old_level is either -1 or 0, 14027c478bd9Sstevel@tonic-gate * and new level is == MAXPWR 14037c478bd9Sstevel@tonic-gate * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm) 14047c478bd9Sstevel@tonic-gate */ 14057c478bd9Sstevel@tonic-gate if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR && 14067c478bd9Sstevel@tonic-gate bpc->bpc_olevel <= 0) && (pshot->state & PM_SUPPORTED)) { 14077c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 14087c478bd9Sstevel@tonic-gate ++(pshot->busy); 14097c478bd9Sstevel@tonic-gate if (pshot_debug_busy) { 14107c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 14117c478bd9Sstevel@tonic-gate "%s%d: pre_bus_power:" 14127c478bd9Sstevel@tonic-gate " busy parent for %s%d (%d->%d): " 14137c478bd9Sstevel@tonic-gate " busy = %d\n", 14147c478bd9Sstevel@tonic-gate name, instance, 14157c478bd9Sstevel@tonic-gate ddi_node_name(bpc->bpc_dip), 14167c478bd9Sstevel@tonic-gate ddi_get_instance(bpc->bpc_dip), 14177c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, 14187c478bd9Sstevel@tonic-gate pshot->busy); 14197c478bd9Sstevel@tonic-gate } 14207c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 14217c478bd9Sstevel@tonic-gate ret = pm_busy_component(dip, 0); 14227c478bd9Sstevel@tonic-gate ASSERT(ret == DDI_SUCCESS); 14237c478bd9Sstevel@tonic-gate } 14247c478bd9Sstevel@tonic-gate 14257c478bd9Sstevel@tonic-gate /* 14267c478bd9Sstevel@tonic-gate * if new_level > 0, power up parent, if not already at 14277c478bd9Sstevel@tonic-gate * MAXPWR, via pm_busop_bus_power 14287c478bd9Sstevel@tonic-gate * - skip for the no-pm nexus (pshot@XXX,nopm) 14297c478bd9Sstevel@tonic-gate */ 14307c478bd9Sstevel@tonic-gate if (bpc->bpc_comp == 0 && bpc->bpc_nlevel > 0 && 14317c478bd9Sstevel@tonic-gate pshot->level < MAXPWR && (pshot->state & PM_SUPPORTED)) { 14327c478bd9Sstevel@tonic-gate /* 14337c478bd9Sstevel@tonic-gate * stuff the bpn struct 14347c478bd9Sstevel@tonic-gate */ 14357c478bd9Sstevel@tonic-gate bpn.bpn_comp = 0; 14367c478bd9Sstevel@tonic-gate bpn.bpn_level = MAXPWR; 14377c478bd9Sstevel@tonic-gate bpn.bpn_private = bpc->bpc_private; 14387c478bd9Sstevel@tonic-gate bpn.bpn_dip = dip; 14397c478bd9Sstevel@tonic-gate 14407c478bd9Sstevel@tonic-gate /* 14417c478bd9Sstevel@tonic-gate * ask pm to power parent up 14427c478bd9Sstevel@tonic-gate */ 14437c478bd9Sstevel@tonic-gate if (pshot_debug) { 14447c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: pre_bus_power:" 14457c478bd9Sstevel@tonic-gate " pm_busop_bus_power on parent for %s%d" 14467c478bd9Sstevel@tonic-gate " (%d->%d): enter", name, instance, 14477c478bd9Sstevel@tonic-gate ddi_node_name(bpc->bpc_dip), 14487c478bd9Sstevel@tonic-gate ddi_get_instance(bpc->bpc_dip), 14497c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel); 14507c478bd9Sstevel@tonic-gate } 14517c478bd9Sstevel@tonic-gate ret = pm_busop_bus_power(dip, impl_arg, 14527c478bd9Sstevel@tonic-gate BUS_POWER_NEXUS_PWRUP, (void *)&bpn, 14537c478bd9Sstevel@tonic-gate (void *)&pwrup_res); 14547c478bd9Sstevel@tonic-gate 14557c478bd9Sstevel@tonic-gate /* 14567c478bd9Sstevel@tonic-gate * check the return status individually, 14577c478bd9Sstevel@tonic-gate * idle parent and exit if either failed. 14587c478bd9Sstevel@tonic-gate */ 14597c478bd9Sstevel@tonic-gate if (ret != DDI_SUCCESS) { 14607c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 14617c478bd9Sstevel@tonic-gate "%s%d: pre_bus_power:" 14627c478bd9Sstevel@tonic-gate " pm_busop_bus_power FAILED (ret) FOR" 14637c478bd9Sstevel@tonic-gate " %s%d (%d->%d)", 14647c478bd9Sstevel@tonic-gate name, instance, 14657c478bd9Sstevel@tonic-gate ddi_node_name(bpc->bpc_dip), 14667c478bd9Sstevel@tonic-gate ddi_get_instance(bpc->bpc_dip), 14677c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel); 14687c478bd9Sstevel@tonic-gate ret_failed = 1; 14697c478bd9Sstevel@tonic-gate } 14707c478bd9Sstevel@tonic-gate if (pwrup_res != DDI_SUCCESS) { 14717c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 14727c478bd9Sstevel@tonic-gate "%s%d: pre_bus_power:" 14737c478bd9Sstevel@tonic-gate " pm_busop_bus_power FAILED (pwrup_res)" 14747c478bd9Sstevel@tonic-gate " FOR %s%d (%d->%d)", 14757c478bd9Sstevel@tonic-gate name, instance, 14767c478bd9Sstevel@tonic-gate ddi_node_name(bpc->bpc_dip), 14777c478bd9Sstevel@tonic-gate ddi_get_instance(bpc->bpc_dip), 14787c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel); 14797c478bd9Sstevel@tonic-gate pwrup_res_failed = 1; 14807c478bd9Sstevel@tonic-gate } 14817c478bd9Sstevel@tonic-gate if (ret_failed || pwrup_res_failed) { 14827c478bd9Sstevel@tonic-gate /* 14837c478bd9Sstevel@tonic-gate * decrement the busy count if it 14847c478bd9Sstevel@tonic-gate * had been incremented. 14857c478bd9Sstevel@tonic-gate */ 14867c478bd9Sstevel@tonic-gate if ((bpc->bpc_comp == 0 && 14877c478bd9Sstevel@tonic-gate bpc->bpc_nlevel == MAXPWR && 14887c478bd9Sstevel@tonic-gate bpc->bpc_olevel <= 0) && 14897c478bd9Sstevel@tonic-gate (pshot->state & PM_SUPPORTED)) { 14907c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 14917c478bd9Sstevel@tonic-gate ASSERT(pshot->busy > 0); 14927c478bd9Sstevel@tonic-gate --(pshot->busy); 14937c478bd9Sstevel@tonic-gate if (pshot_debug_busy) { 14947c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d:" 14957c478bd9Sstevel@tonic-gate " pm_busop_bus_power" 14967c478bd9Sstevel@tonic-gate " failed: idle parent for" 14977c478bd9Sstevel@tonic-gate " %s%d (%d->%d):" 14987c478bd9Sstevel@tonic-gate " busy = %d\n", 14997c478bd9Sstevel@tonic-gate name, instance, 15007c478bd9Sstevel@tonic-gate ddi_node_name( 15017c478bd9Sstevel@tonic-gate bpc->bpc_dip), 15027c478bd9Sstevel@tonic-gate ddi_get_instance( 15037c478bd9Sstevel@tonic-gate bpc->bpc_dip), 15047c478bd9Sstevel@tonic-gate bpc->bpc_olevel, 15057c478bd9Sstevel@tonic-gate bpc->bpc_nlevel, 15067c478bd9Sstevel@tonic-gate pshot->busy); 15077c478bd9Sstevel@tonic-gate } 15087c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 15097c478bd9Sstevel@tonic-gate ret = pm_idle_component(dip, 0); 15107c478bd9Sstevel@tonic-gate ASSERT(ret == DDI_SUCCESS); 15117c478bd9Sstevel@tonic-gate } 15127c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 15137c478bd9Sstevel@tonic-gate 15147c478bd9Sstevel@tonic-gate } else { 15157c478bd9Sstevel@tonic-gate if (pshot_debug) { 15167c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 15177c478bd9Sstevel@tonic-gate "%s%d: pre_bus_power:" 15187c478bd9Sstevel@tonic-gate " pm_busop_bus_power on parent" 15197c478bd9Sstevel@tonic-gate " for %s%d (%d->%d)\n", 15207c478bd9Sstevel@tonic-gate name, instance, 15217c478bd9Sstevel@tonic-gate ddi_node_name(bpc->bpc_dip), 15227c478bd9Sstevel@tonic-gate ddi_get_instance(bpc->bpc_dip), 15237c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel); 15247c478bd9Sstevel@tonic-gate } 15257c478bd9Sstevel@tonic-gate } 15267c478bd9Sstevel@tonic-gate } 15277c478bd9Sstevel@tonic-gate break; 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate case BUS_POWER_POST_NOTIFICATION: 15307c478bd9Sstevel@tonic-gate bpc = (pm_bp_child_pwrchg_t *)arg; 15317c478bd9Sstevel@tonic-gate if (pshot_debug) { 15327c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: post_bus_power:" 15337c478bd9Sstevel@tonic-gate " %s%d comp %d (%d->%d) result %d\n", 15347c478bd9Sstevel@tonic-gate name, instance, ddi_node_name(bpc->bpc_dip), 15357c478bd9Sstevel@tonic-gate ddi_get_instance(bpc->bpc_dip), 15367c478bd9Sstevel@tonic-gate bpc->bpc_comp, bpc->bpc_olevel, 15377c478bd9Sstevel@tonic-gate bpc->bpc_nlevel, *(int *)result); 15387c478bd9Sstevel@tonic-gate } 15397c478bd9Sstevel@tonic-gate 15407c478bd9Sstevel@tonic-gate /* 15417c478bd9Sstevel@tonic-gate * handle pm_busop_bus_power() failure case. 15427c478bd9Sstevel@tonic-gate * mark parent idle if had been marked busy. 15437c478bd9Sstevel@tonic-gate * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm) 15447c478bd9Sstevel@tonic-gate */ 15457c478bd9Sstevel@tonic-gate if (*(int *)result != DDI_SUCCESS) { 15467c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 15477c478bd9Sstevel@tonic-gate "pshot%d: post_bus_power_failed:" 15487c478bd9Sstevel@tonic-gate " pm_busop_bus_power FAILED FOR %s%d (%d->%d)", 15497c478bd9Sstevel@tonic-gate instance, ddi_node_name(bpc->bpc_dip), 15507c478bd9Sstevel@tonic-gate ddi_get_instance(bpc->bpc_dip), 15517c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel); 15527c478bd9Sstevel@tonic-gate 15537c478bd9Sstevel@tonic-gate if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == MAXPWR && 15547c478bd9Sstevel@tonic-gate bpc->bpc_olevel <= 0) && 15557c478bd9Sstevel@tonic-gate (pshot->state & PM_SUPPORTED)) { 15567c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 15577c478bd9Sstevel@tonic-gate ASSERT(pshot->busy > 0); 15587c478bd9Sstevel@tonic-gate --(pshot->busy); 15597c478bd9Sstevel@tonic-gate if (pshot_debug_busy) { 15607c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d:" 15617c478bd9Sstevel@tonic-gate " post_bus_power_failed:" 15627c478bd9Sstevel@tonic-gate " idle parent for %s%d" 15637c478bd9Sstevel@tonic-gate " (%d->%d): busy = %d\n", 15647c478bd9Sstevel@tonic-gate name, instance, 15657c478bd9Sstevel@tonic-gate ddi_node_name(bpc->bpc_dip), 15667c478bd9Sstevel@tonic-gate ddi_get_instance(bpc->bpc_dip), 15677c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, 15687c478bd9Sstevel@tonic-gate pshot->busy); 15697c478bd9Sstevel@tonic-gate } 15707c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 15717c478bd9Sstevel@tonic-gate ret = pm_idle_component(dip, 0); 15727c478bd9Sstevel@tonic-gate ASSERT(ret == DDI_SUCCESS); 15737c478bd9Sstevel@tonic-gate } 15747c478bd9Sstevel@tonic-gate } 15757c478bd9Sstevel@tonic-gate 15767c478bd9Sstevel@tonic-gate /* 15777c478bd9Sstevel@tonic-gate * Mark nexus idle when a child's comp 0 15787c478bd9Sstevel@tonic-gate * is set to level 0 from level 1, 2, or 3 only. 15797c478bd9Sstevel@tonic-gate * And only if result arg == DDI_SUCCESS. 15807c478bd9Sstevel@tonic-gate * This will leave the parent busy when the child 15817c478bd9Sstevel@tonic-gate * does not call pm_lower_power() on detach after 15827c478bd9Sstevel@tonic-gate * unsetting the NO_LOWER_POWER flag. 15837c478bd9Sstevel@tonic-gate * If so, need to notify the parent to mark itself 15847c478bd9Sstevel@tonic-gate * idle anyway, else the no-involumtary-power-cycles 15857c478bd9Sstevel@tonic-gate * test cases will report false passes! 15867c478bd9Sstevel@tonic-gate * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm) 15877c478bd9Sstevel@tonic-gate */ 15887c478bd9Sstevel@tonic-gate if ((bpc->bpc_comp == 0 && bpc->bpc_nlevel == 0 && 15897c478bd9Sstevel@tonic-gate !(bpc->bpc_olevel <= 0) && 15907c478bd9Sstevel@tonic-gate *(int *)result == DDI_SUCCESS) && 15917c478bd9Sstevel@tonic-gate (pshot->state & PM_SUPPORTED)) { 15927c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 15937c478bd9Sstevel@tonic-gate ASSERT(pshot->busy > 0); 15947c478bd9Sstevel@tonic-gate --(pshot->busy); 15957c478bd9Sstevel@tonic-gate if (pshot_debug_busy) { 15967c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 15977c478bd9Sstevel@tonic-gate "%s%d: post_bus_power:" 15987c478bd9Sstevel@tonic-gate " idle parent for %s%d (%d->%d):" 15997c478bd9Sstevel@tonic-gate " busy = %d\n", name, instance, 16007c478bd9Sstevel@tonic-gate ddi_node_name(bpc->bpc_dip), 16017c478bd9Sstevel@tonic-gate ddi_get_instance(bpc->bpc_dip), 16027c478bd9Sstevel@tonic-gate bpc->bpc_olevel, bpc->bpc_nlevel, 16037c478bd9Sstevel@tonic-gate pshot->busy); 16047c478bd9Sstevel@tonic-gate } 16057c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 16067c478bd9Sstevel@tonic-gate ret = pm_idle_component(dip, 0); 16077c478bd9Sstevel@tonic-gate ASSERT(ret == DDI_SUCCESS); 16087c478bd9Sstevel@tonic-gate } 16097c478bd9Sstevel@tonic-gate break; 16107c478bd9Sstevel@tonic-gate 16117c478bd9Sstevel@tonic-gate case BUS_POWER_HAS_CHANGED: 16127c478bd9Sstevel@tonic-gate bphc = (pm_bp_has_changed_t *)arg; 16137c478bd9Sstevel@tonic-gate if (pshot_debug) { 16147c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "%s%d: has_changed_bus_power:" 16157c478bd9Sstevel@tonic-gate " %s%d comp %d (%d->%d) result %d\n", 16167c478bd9Sstevel@tonic-gate name, instance, ddi_node_name(bphc->bphc_dip), 16177c478bd9Sstevel@tonic-gate ddi_get_instance(bphc->bphc_dip), 16187c478bd9Sstevel@tonic-gate bphc->bphc_comp, bphc->bphc_olevel, 16197c478bd9Sstevel@tonic-gate bphc->bphc_nlevel, *(int *)result); 16207c478bd9Sstevel@tonic-gate } 16217c478bd9Sstevel@tonic-gate 16227c478bd9Sstevel@tonic-gate /* 16237c478bd9Sstevel@tonic-gate * Mark nexus idle when a child's comp 0 16247c478bd9Sstevel@tonic-gate * is set to level 0 from levels 1, 2, or 3 only. 16257c478bd9Sstevel@tonic-gate * 16267c478bd9Sstevel@tonic-gate * If powering up child leaf/nexus nodes via 16277c478bd9Sstevel@tonic-gate * pm_power_has_changed() calls, first issue 16287c478bd9Sstevel@tonic-gate * DEVCTL_PM_BUSY_COMP ioctl to mark parent busy 16297c478bd9Sstevel@tonic-gate * before powering the parent up, then power up the 16307c478bd9Sstevel@tonic-gate * child node. 16317c478bd9Sstevel@tonic-gate * - skip if PM_SUPPORTED is not set (pshot@XXX,nopm) 16327c478bd9Sstevel@tonic-gate */ 16337c478bd9Sstevel@tonic-gate if ((bphc->bphc_comp == 0 && bphc->bphc_nlevel == 0 && 16347c478bd9Sstevel@tonic-gate !(bphc->bphc_olevel <= 0)) && 16357c478bd9Sstevel@tonic-gate pshot->state & PM_SUPPORTED) { 16367c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 16377c478bd9Sstevel@tonic-gate ASSERT(pshot->busy > 0); 16387c478bd9Sstevel@tonic-gate --(pshot->busy); 16397c478bd9Sstevel@tonic-gate if (pshot_debug_busy) { 16407c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 16417c478bd9Sstevel@tonic-gate "%s%d: has_changed_bus_power:" 16427c478bd9Sstevel@tonic-gate " idle parent for %s%d (%d->%d):" 16437c478bd9Sstevel@tonic-gate " busy = %d\n", name, instance, 16447c478bd9Sstevel@tonic-gate ddi_node_name(bphc->bphc_dip), 16457c478bd9Sstevel@tonic-gate ddi_get_instance(bphc->bphc_dip), 16467c478bd9Sstevel@tonic-gate bphc->bphc_olevel, 16477c478bd9Sstevel@tonic-gate bphc->bphc_nlevel, pshot->busy); 16487c478bd9Sstevel@tonic-gate } 16497c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 16507c478bd9Sstevel@tonic-gate ret = pm_idle_component(dip, 0); 16517c478bd9Sstevel@tonic-gate ASSERT(ret == DDI_SUCCESS); 16527c478bd9Sstevel@tonic-gate } 16537c478bd9Sstevel@tonic-gate break; 16547c478bd9Sstevel@tonic-gate 16557c478bd9Sstevel@tonic-gate default: 16567c478bd9Sstevel@tonic-gate return (pm_busop_bus_power(dip, impl_arg, op, arg, result)); 16577c478bd9Sstevel@tonic-gate 16587c478bd9Sstevel@tonic-gate } 16597c478bd9Sstevel@tonic-gate 16607c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 16617c478bd9Sstevel@tonic-gate } 16627c478bd9Sstevel@tonic-gate 16637c478bd9Sstevel@tonic-gate static int 16647c478bd9Sstevel@tonic-gate pshot_initchild(dev_info_t *dip, dev_info_t *child) 16657c478bd9Sstevel@tonic-gate { 16667c478bd9Sstevel@tonic-gate char name[64]; 16677c478bd9Sstevel@tonic-gate char *bus_addr; 16687c478bd9Sstevel@tonic-gate char *c_nodename; 16697c478bd9Sstevel@tonic-gate int bus_id; 16707c478bd9Sstevel@tonic-gate dev_info_t *enum_child; 16717c478bd9Sstevel@tonic-gate int enum_base; 16727c478bd9Sstevel@tonic-gate int enum_extent; 16737c478bd9Sstevel@tonic-gate 16747c478bd9Sstevel@tonic-gate 16757c478bd9Sstevel@tonic-gate /* check for bus_enum node */ 16767c478bd9Sstevel@tonic-gate 16777c478bd9Sstevel@tonic-gate #ifdef NOT_USED 16787c478bd9Sstevel@tonic-gate if (impl_ddi_merge_child(child) != DDI_SUCCESS) 16797c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 16807c478bd9Sstevel@tonic-gate #endif 16817c478bd9Sstevel@tonic-gate 16827c478bd9Sstevel@tonic-gate enum_base = ddi_prop_get_int(DDI_DEV_T_ANY, child, DDI_PROP_DONTPASS, 16837c478bd9Sstevel@tonic-gate "busid_ebase", 0); 16847c478bd9Sstevel@tonic-gate 16857c478bd9Sstevel@tonic-gate enum_extent = ddi_prop_get_int(DDI_DEV_T_ANY, child, 16867c478bd9Sstevel@tonic-gate DDI_PROP_DONTPASS, "busid_range", 0); 16877c478bd9Sstevel@tonic-gate 16887c478bd9Sstevel@tonic-gate /* 16897c478bd9Sstevel@tonic-gate * bus enumeration node 16907c478bd9Sstevel@tonic-gate */ 16917c478bd9Sstevel@tonic-gate if ((enum_base != 0) && (enum_extent != 0)) { 16927c478bd9Sstevel@tonic-gate c_nodename = ddi_node_name(child); 16937c478bd9Sstevel@tonic-gate bus_id = enum_base; 16947c478bd9Sstevel@tonic-gate for (; bus_id < enum_extent; bus_id++) { 16957c478bd9Sstevel@tonic-gate if (ndi_devi_alloc(dip, c_nodename, DEVI_PSEUDO_NODEID, 16967c478bd9Sstevel@tonic-gate &enum_child) != NDI_SUCCESS) 16977c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 16987c478bd9Sstevel@tonic-gate 16997c478bd9Sstevel@tonic-gate (void) sprintf(name, "%d", bus_id); 17007c478bd9Sstevel@tonic-gate if (ndi_prop_update_string(DDI_DEV_T_NONE, enum_child, 17017c478bd9Sstevel@tonic-gate "bus-addr", name) != DDI_PROP_SUCCESS) { 17027c478bd9Sstevel@tonic-gate (void) ndi_devi_free(enum_child); 17037c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 17047c478bd9Sstevel@tonic-gate } 17057c478bd9Sstevel@tonic-gate 17067c478bd9Sstevel@tonic-gate if (ndi_devi_online(enum_child, 0) != 17077c478bd9Sstevel@tonic-gate DDI_SUCCESS) { 17087c478bd9Sstevel@tonic-gate (void) ndi_devi_free(enum_child); 17097c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 17107c478bd9Sstevel@tonic-gate } 17117c478bd9Sstevel@tonic-gate } 17127c478bd9Sstevel@tonic-gate /* 17137c478bd9Sstevel@tonic-gate * fail the enumeration node itself 17147c478bd9Sstevel@tonic-gate */ 17157c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 17167c478bd9Sstevel@tonic-gate } 17177c478bd9Sstevel@tonic-gate 17187c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, child, 0, "bus-addr", 17197c478bd9Sstevel@tonic-gate &bus_addr) != DDI_PROP_SUCCESS) { 17207c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot_initchild: bus-addr not defined (%s)", 17217c478bd9Sstevel@tonic-gate ddi_node_name(child)); 17227c478bd9Sstevel@tonic-gate return (DDI_NOT_WELL_FORMED); 17237c478bd9Sstevel@tonic-gate } 17247c478bd9Sstevel@tonic-gate 17257c478bd9Sstevel@tonic-gate if (strlen(bus_addr) == 0) { 17267c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot_initchild: NULL bus-addr (%s)", 17277c478bd9Sstevel@tonic-gate ddi_node_name(child)); 17287c478bd9Sstevel@tonic-gate ddi_prop_free(bus_addr); 17297c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 17307c478bd9Sstevel@tonic-gate } 17317c478bd9Sstevel@tonic-gate 17327c478bd9Sstevel@tonic-gate if (strncmp(bus_addr, "failinit", 8) == 0) { 17337c478bd9Sstevel@tonic-gate if (pshot_debug) 17347c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 17357c478bd9Sstevel@tonic-gate "pshot%d: %s forced INITCHILD failure\n", 17367c478bd9Sstevel@tonic-gate ddi_get_instance(dip), bus_addr); 17377c478bd9Sstevel@tonic-gate ddi_prop_free(bus_addr); 17387c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 17397c478bd9Sstevel@tonic-gate } 17407c478bd9Sstevel@tonic-gate 17417c478bd9Sstevel@tonic-gate if (pshot_log) { 17427c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "initchild %s%d/%s@%s\n", 17437c478bd9Sstevel@tonic-gate ddi_get_name(dip), ddi_get_instance(dip), 17447c478bd9Sstevel@tonic-gate ddi_node_name(child), bus_addr); 17457c478bd9Sstevel@tonic-gate } 17467c478bd9Sstevel@tonic-gate 17477c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, bus_addr); 17487c478bd9Sstevel@tonic-gate ddi_prop_free(bus_addr); 17497c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 17507c478bd9Sstevel@tonic-gate } 17517c478bd9Sstevel@tonic-gate 17527c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 17537c478bd9Sstevel@tonic-gate static int 17547c478bd9Sstevel@tonic-gate pshot_uninitchild(dev_info_t *dip, dev_info_t *child) 17557c478bd9Sstevel@tonic-gate { 17567c478bd9Sstevel@tonic-gate ddi_set_name_addr(child, NULL); 17577c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 17587c478bd9Sstevel@tonic-gate } 17597c478bd9Sstevel@tonic-gate 17607c478bd9Sstevel@tonic-gate 17617c478bd9Sstevel@tonic-gate /* 17627c478bd9Sstevel@tonic-gate * devctl IOCTL support 17637c478bd9Sstevel@tonic-gate */ 17647c478bd9Sstevel@tonic-gate /* ARGSUSED */ 17657c478bd9Sstevel@tonic-gate static int 17667c478bd9Sstevel@tonic-gate pshot_open(dev_t *devp, int flags, int otyp, cred_t *credp) 17677c478bd9Sstevel@tonic-gate { 17687c478bd9Sstevel@tonic-gate int instance; 17697c478bd9Sstevel@tonic-gate pshot_t *pshot; 17707c478bd9Sstevel@tonic-gate 17717c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) 17727c478bd9Sstevel@tonic-gate return (EINVAL); 17737c478bd9Sstevel@tonic-gate 17747c478bd9Sstevel@tonic-gate instance = pshot_minor_decode_inst(getminor(*devp)); 17757c478bd9Sstevel@tonic-gate if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL) 17767c478bd9Sstevel@tonic-gate return (ENXIO); 17777c478bd9Sstevel@tonic-gate 17787c478bd9Sstevel@tonic-gate /* 17797c478bd9Sstevel@tonic-gate * Access is currently determined on a per-instance basis. 17807c478bd9Sstevel@tonic-gate * If we want per-node, then need to add state and lock members to 17817c478bd9Sstevel@tonic-gate * pshot_minor_t 17827c478bd9Sstevel@tonic-gate */ 17837c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 17847c478bd9Sstevel@tonic-gate if (((flags & FEXCL) && (pshot->state & IS_OPEN)) || 17857c478bd9Sstevel@tonic-gate (!(flags & FEXCL) && (pshot->state & IS_OPEN_EXCL))) { 17867c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 17877c478bd9Sstevel@tonic-gate return (EBUSY); 17887c478bd9Sstevel@tonic-gate } 17897c478bd9Sstevel@tonic-gate pshot->state |= IS_OPEN; 17907c478bd9Sstevel@tonic-gate if (flags & FEXCL) 17917c478bd9Sstevel@tonic-gate pshot->state |= IS_OPEN_EXCL; 17927c478bd9Sstevel@tonic-gate 17937c478bd9Sstevel@tonic-gate if (pshot_debug) 17947c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d open\n", instance); 17957c478bd9Sstevel@tonic-gate 17967c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 17977c478bd9Sstevel@tonic-gate return (0); 17987c478bd9Sstevel@tonic-gate } 17997c478bd9Sstevel@tonic-gate 18007c478bd9Sstevel@tonic-gate /* 18017c478bd9Sstevel@tonic-gate * pshot_close 18027c478bd9Sstevel@tonic-gate */ 18037c478bd9Sstevel@tonic-gate /* ARGSUSED */ 18047c478bd9Sstevel@tonic-gate static int 18057c478bd9Sstevel@tonic-gate pshot_close(dev_t dev, int flag, int otyp, cred_t *credp) 18067c478bd9Sstevel@tonic-gate { 18077c478bd9Sstevel@tonic-gate int instance; 18087c478bd9Sstevel@tonic-gate pshot_t *pshot; 18097c478bd9Sstevel@tonic-gate 18107c478bd9Sstevel@tonic-gate if (otyp != OTYP_CHR) 18117c478bd9Sstevel@tonic-gate return (EINVAL); 18127c478bd9Sstevel@tonic-gate 18137c478bd9Sstevel@tonic-gate instance = pshot_minor_decode_inst(getminor(dev)); 18147c478bd9Sstevel@tonic-gate if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL) 18157c478bd9Sstevel@tonic-gate return (ENXIO); 18167c478bd9Sstevel@tonic-gate 18177c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 18187c478bd9Sstevel@tonic-gate pshot->state &= ~(IS_OPEN | IS_OPEN_EXCL); 18197c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 18207c478bd9Sstevel@tonic-gate if (pshot_debug) 18217c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d closed\n", instance); 18227c478bd9Sstevel@tonic-gate return (0); 18237c478bd9Sstevel@tonic-gate } 18247c478bd9Sstevel@tonic-gate 18257c478bd9Sstevel@tonic-gate 18267c478bd9Sstevel@tonic-gate /* 18277c478bd9Sstevel@tonic-gate * pshot_ioctl: redirects to appropriate command handler based on various 18287c478bd9Sstevel@tonic-gate * criteria 18297c478bd9Sstevel@tonic-gate */ 18307c478bd9Sstevel@tonic-gate /* ARGSUSED */ 18317c478bd9Sstevel@tonic-gate static int 18327c478bd9Sstevel@tonic-gate pshot_ioctl(dev_t dev, int cmd, intptr_t arg, int mode, cred_t *credp, 18337c478bd9Sstevel@tonic-gate int *rvalp) 18347c478bd9Sstevel@tonic-gate { 18357c478bd9Sstevel@tonic-gate pshot_t *pshot; 18367c478bd9Sstevel@tonic-gate int instance; 18377c478bd9Sstevel@tonic-gate minor_t nodenum; 18387c478bd9Sstevel@tonic-gate char *nodename; 18397c478bd9Sstevel@tonic-gate 18407c478bd9Sstevel@tonic-gate instance = pshot_minor_decode_inst(getminor(dev)); 18417c478bd9Sstevel@tonic-gate if ((pshot = ddi_get_soft_state(pshot_softstatep, instance)) == NULL) 18427c478bd9Sstevel@tonic-gate return (ENXIO); 18437c478bd9Sstevel@tonic-gate 18447c478bd9Sstevel@tonic-gate nodenum = pshot_minor_decode_nodenum(getminor(dev)); 18457c478bd9Sstevel@tonic-gate nodename = pshot->nodes[nodenum].name; 18467c478bd9Sstevel@tonic-gate 18477c478bd9Sstevel@tonic-gate if (pshot_debug) 18487c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 18497c478bd9Sstevel@tonic-gate "pshot%d ioctl: dev=%p, cmd=%x, arg=%p, mode=%x\n", 18507c478bd9Sstevel@tonic-gate instance, (void *)dev, cmd, (void *)arg, mode); 18517c478bd9Sstevel@tonic-gate 18527c478bd9Sstevel@tonic-gate if (strcmp(nodename, PSHOT_NODENAME_DEVCTL) == 0) 18537c478bd9Sstevel@tonic-gate return (pshot_devctl(pshot, nodenum, cmd, arg, mode, credp, 18547c478bd9Sstevel@tonic-gate rvalp)); 18557c478bd9Sstevel@tonic-gate 18567c478bd9Sstevel@tonic-gate if (strcmp(nodename, PSHOT_NODENAME_TESTCTL) == 0) 18577c478bd9Sstevel@tonic-gate return (pshot_testctl(pshot, nodenum, cmd, arg, mode, credp, 18587c478bd9Sstevel@tonic-gate rvalp)); 18597c478bd9Sstevel@tonic-gate 18607c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot_ioctl: unmatched nodename on minor %u", 18617c478bd9Sstevel@tonic-gate pshot->nodes[nodenum].minor); 18627c478bd9Sstevel@tonic-gate return (ENXIO); 18637c478bd9Sstevel@tonic-gate } 18647c478bd9Sstevel@tonic-gate 18657c478bd9Sstevel@tonic-gate 18667c478bd9Sstevel@tonic-gate /* 18677c478bd9Sstevel@tonic-gate * pshot_devctl: handle DEVCTL operations 18687c478bd9Sstevel@tonic-gate */ 18697c478bd9Sstevel@tonic-gate /* ARGSUSED */ 18707c478bd9Sstevel@tonic-gate static int 18717c478bd9Sstevel@tonic-gate pshot_devctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode, 18727c478bd9Sstevel@tonic-gate cred_t *credp, int *rvalp) 18737c478bd9Sstevel@tonic-gate { 18747c478bd9Sstevel@tonic-gate dev_info_t *self; 18757c478bd9Sstevel@tonic-gate dev_info_t *child = NULL; 18767c478bd9Sstevel@tonic-gate struct devctl_iocdata *dcp; 18777c478bd9Sstevel@tonic-gate uint_t state; 18787c478bd9Sstevel@tonic-gate int rv = 0; 18797c478bd9Sstevel@tonic-gate uint_t flags; 18807c478bd9Sstevel@tonic-gate int instance; 18817c478bd9Sstevel@tonic-gate int i; 18827c478bd9Sstevel@tonic-gate int ret; 18837c478bd9Sstevel@tonic-gate 18847c478bd9Sstevel@tonic-gate self = pshot->dip; 18857c478bd9Sstevel@tonic-gate 18867c478bd9Sstevel@tonic-gate flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0; 18877c478bd9Sstevel@tonic-gate instance = pshot->instance; 18887c478bd9Sstevel@tonic-gate 18897c478bd9Sstevel@tonic-gate /* 18907c478bd9Sstevel@tonic-gate * We can use the generic implementation for these ioctls 18917c478bd9Sstevel@tonic-gate */ 18927c478bd9Sstevel@tonic-gate for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) { 18937c478bd9Sstevel@tonic-gate if (pshot_devctls[i].ioctl_int == cmd) { 18947c478bd9Sstevel@tonic-gate if (pshot_debug) 18957c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl: %s", 18967c478bd9Sstevel@tonic-gate instance, pshot_devctls[i].ioctl_char); 18977c478bd9Sstevel@tonic-gate } 18987c478bd9Sstevel@tonic-gate } 18997c478bd9Sstevel@tonic-gate switch (cmd) { 19007c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_GETSTATE: 19017c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_ONLINE: 19027c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_OFFLINE: 19037c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_REMOVE: 19047c478bd9Sstevel@tonic-gate case DEVCTL_BUS_GETSTATE: 19057c478bd9Sstevel@tonic-gate case DEVCTL_BUS_DEV_CREATE: 19067c478bd9Sstevel@tonic-gate rv = ndi_devctl_ioctl(self, cmd, arg, mode, flags); 19077c478bd9Sstevel@tonic-gate if (pshot_debug && rv != 0) { 19087c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d ndi_devctl_ioctl:" 19097c478bd9Sstevel@tonic-gate " failed, rv = %d", instance, rv); 19107c478bd9Sstevel@tonic-gate } 19117c478bd9Sstevel@tonic-gate 19127c478bd9Sstevel@tonic-gate return (rv); 19137c478bd9Sstevel@tonic-gate } 19147c478bd9Sstevel@tonic-gate 19157c478bd9Sstevel@tonic-gate /* 19167c478bd9Sstevel@tonic-gate * read devctl ioctl data 19177c478bd9Sstevel@tonic-gate */ 19187c478bd9Sstevel@tonic-gate if (ndi_dc_allochdl((void *)arg, &dcp) != NDI_SUCCESS) 19197c478bd9Sstevel@tonic-gate return (EFAULT); 19207c478bd9Sstevel@tonic-gate 19217c478bd9Sstevel@tonic-gate switch (cmd) { 19227c478bd9Sstevel@tonic-gate 19237c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_RESET: 19247c478bd9Sstevel@tonic-gate if (pshot_debug) 19257c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 19267c478bd9Sstevel@tonic-gate " DEVCTL_DEVICE_RESET\n", instance); 19277c478bd9Sstevel@tonic-gate rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET, 19287c478bd9Sstevel@tonic-gate child, (void *)self); 19297c478bd9Sstevel@tonic-gate ASSERT(rv == NDI_SUCCESS); 19307c478bd9Sstevel@tonic-gate break; 19317c478bd9Sstevel@tonic-gate 19327c478bd9Sstevel@tonic-gate case DEVCTL_BUS_QUIESCE: 19337c478bd9Sstevel@tonic-gate if (pshot_debug) 19347c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 19357c478bd9Sstevel@tonic-gate " DEVCTL_BUS_QUIESCE\n", instance); 19367c478bd9Sstevel@tonic-gate if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) { 19377c478bd9Sstevel@tonic-gate if (state == BUS_QUIESCED) { 19387c478bd9Sstevel@tonic-gate break; 19397c478bd9Sstevel@tonic-gate } 19407c478bd9Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_QUIESCED); 19417c478bd9Sstevel@tonic-gate } 19427c478bd9Sstevel@tonic-gate rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE, 19437c478bd9Sstevel@tonic-gate child, (void *)self); 19447c478bd9Sstevel@tonic-gate ASSERT(rv == NDI_SUCCESS); 19457c478bd9Sstevel@tonic-gate 19467c478bd9Sstevel@tonic-gate break; 19477c478bd9Sstevel@tonic-gate 19487c478bd9Sstevel@tonic-gate case DEVCTL_BUS_UNQUIESCE: 19497c478bd9Sstevel@tonic-gate if (pshot_debug) 19507c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 19517c478bd9Sstevel@tonic-gate " DEVCTL_BUS_UNQUIESCE\n", instance); 19527c478bd9Sstevel@tonic-gate if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) { 19537c478bd9Sstevel@tonic-gate if (state == BUS_ACTIVE) { 19547c478bd9Sstevel@tonic-gate break; 19557c478bd9Sstevel@tonic-gate } 19567c478bd9Sstevel@tonic-gate } 19577c478bd9Sstevel@tonic-gate 19587c478bd9Sstevel@tonic-gate /* 19597c478bd9Sstevel@tonic-gate * quiesce the bus through bus-specific means 19607c478bd9Sstevel@tonic-gate */ 19617c478bd9Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_ACTIVE); 19627c478bd9Sstevel@tonic-gate rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE, 19637c478bd9Sstevel@tonic-gate child, (void *)self); 19647c478bd9Sstevel@tonic-gate ASSERT(rv == NDI_SUCCESS); 19657c478bd9Sstevel@tonic-gate break; 19667c478bd9Sstevel@tonic-gate 19677c478bd9Sstevel@tonic-gate case DEVCTL_BUS_RESET: 19687c478bd9Sstevel@tonic-gate case DEVCTL_BUS_RESETALL: 19697c478bd9Sstevel@tonic-gate /* 19707c478bd9Sstevel@tonic-gate * no reset support for the pseudo bus 19717c478bd9Sstevel@tonic-gate * but if there were.... 19727c478bd9Sstevel@tonic-gate */ 19737c478bd9Sstevel@tonic-gate rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET, 19747c478bd9Sstevel@tonic-gate child, (void *)self); 19757c478bd9Sstevel@tonic-gate ASSERT(rv == NDI_SUCCESS); 19767c478bd9Sstevel@tonic-gate break; 19777c478bd9Sstevel@tonic-gate 19787c478bd9Sstevel@tonic-gate /* 19797c478bd9Sstevel@tonic-gate * PM related ioctls 19807c478bd9Sstevel@tonic-gate */ 19817c478bd9Sstevel@tonic-gate case DEVCTL_PM_BUSY_COMP: 19827c478bd9Sstevel@tonic-gate /* 19837c478bd9Sstevel@tonic-gate * mark component 0 busy. 19847c478bd9Sstevel@tonic-gate * Keep track of ioctl updates to the busy count 19857c478bd9Sstevel@tonic-gate * via pshot->busy_ioctl. 19867c478bd9Sstevel@tonic-gate */ 19877c478bd9Sstevel@tonic-gate if (pshot_debug) { 19887c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 19897c478bd9Sstevel@tonic-gate " DEVCTL_PM_BUSY_COMP\n", instance); 19907c478bd9Sstevel@tonic-gate } 19917c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 19927c478bd9Sstevel@tonic-gate ++(pshot->busy); 19937c478bd9Sstevel@tonic-gate ++(pshot->busy_ioctl); 19947c478bd9Sstevel@tonic-gate if (pshot_debug_busy) { 19957c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d:" 19967c478bd9Sstevel@tonic-gate " DEVCTL_PM_BUSY_COMP comp 0 busy" 19977c478bd9Sstevel@tonic-gate " %d busy_ioctl %d\n", instance, pshot->busy, 19987c478bd9Sstevel@tonic-gate pshot->busy_ioctl); 19997c478bd9Sstevel@tonic-gate } 20007c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 20017c478bd9Sstevel@tonic-gate ret = pm_busy_component(pshot->dip, 0); 20027c478bd9Sstevel@tonic-gate ASSERT(ret == DDI_SUCCESS); 20037c478bd9Sstevel@tonic-gate 20047c478bd9Sstevel@tonic-gate break; 20057c478bd9Sstevel@tonic-gate 20067c478bd9Sstevel@tonic-gate case DEVCTL_PM_BUSY_COMP_TEST: 20077c478bd9Sstevel@tonic-gate /* 20087c478bd9Sstevel@tonic-gate * test bus's busy state 20097c478bd9Sstevel@tonic-gate */ 20107c478bd9Sstevel@tonic-gate if (pshot_debug) { 20117c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 20127c478bd9Sstevel@tonic-gate " DEVCTL_PM_BUSY_COMP_TEST\n", instance); 20137c478bd9Sstevel@tonic-gate } 20147c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 20157c478bd9Sstevel@tonic-gate state = pshot->busy; 20167c478bd9Sstevel@tonic-gate if (copyout(&state, dcp->cpyout_buf, 20177c478bd9Sstevel@tonic-gate sizeof (uint_t)) != 0) { 20187c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot%d devctl:" 20197c478bd9Sstevel@tonic-gate " DEVCTL_PM_BUSY_COMP_TEST: copyout failed", 20207c478bd9Sstevel@tonic-gate instance); 20217c478bd9Sstevel@tonic-gate rv = EINVAL; 20227c478bd9Sstevel@tonic-gate } 20237c478bd9Sstevel@tonic-gate if (pshot_debug_busy) { 20247c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_BUSY_COMP_TEST:" 20257c478bd9Sstevel@tonic-gate " comp 0 busy %d busy_ioctl %d\n", instance, 20267c478bd9Sstevel@tonic-gate state, pshot->busy_ioctl); 20277c478bd9Sstevel@tonic-gate } 20287c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 20297c478bd9Sstevel@tonic-gate break; 20307c478bd9Sstevel@tonic-gate 20317c478bd9Sstevel@tonic-gate case DEVCTL_PM_IDLE_COMP: 20327c478bd9Sstevel@tonic-gate /* 20337c478bd9Sstevel@tonic-gate * mark component 0 idle. 20347c478bd9Sstevel@tonic-gate * NOP if pshot->busy_ioctl <= 0. 20357c478bd9Sstevel@tonic-gate */ 20367c478bd9Sstevel@tonic-gate if (pshot_debug) { 20377c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 20387c478bd9Sstevel@tonic-gate " DEVCTL_PM_IDLE_COMP\n", instance); 20397c478bd9Sstevel@tonic-gate } 20407c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 20417c478bd9Sstevel@tonic-gate if (pshot->busy_ioctl > 0) { 20427c478bd9Sstevel@tonic-gate ASSERT(pshot->busy > 0); 20437c478bd9Sstevel@tonic-gate --(pshot->busy); 20447c478bd9Sstevel@tonic-gate --(pshot->busy_ioctl); 20457c478bd9Sstevel@tonic-gate if (pshot_debug_busy) { 20467c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d:" 20477c478bd9Sstevel@tonic-gate " DEVCTL_PM_IDLE_COM: comp 0" 20487c478bd9Sstevel@tonic-gate " busy %d busy_ioctl %d\n", instance, 20497c478bd9Sstevel@tonic-gate pshot->busy, pshot->busy_ioctl); 20507c478bd9Sstevel@tonic-gate } 20517c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 20527c478bd9Sstevel@tonic-gate ret = pm_idle_component(pshot->dip, 0); 20537c478bd9Sstevel@tonic-gate ASSERT(ret == DDI_SUCCESS); 20547c478bd9Sstevel@tonic-gate 20557c478bd9Sstevel@tonic-gate } else { 20567c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 20577c478bd9Sstevel@tonic-gate } 20587c478bd9Sstevel@tonic-gate break; 20597c478bd9Sstevel@tonic-gate 20607c478bd9Sstevel@tonic-gate case DEVCTL_PM_RAISE_PWR: 20617c478bd9Sstevel@tonic-gate /* 20627c478bd9Sstevel@tonic-gate * raise component 0 to full power level MAXPWR via a 20637c478bd9Sstevel@tonic-gate * pm_raise_power() call 20647c478bd9Sstevel@tonic-gate */ 20657c478bd9Sstevel@tonic-gate if (pshot_debug) { 20667c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 20677c478bd9Sstevel@tonic-gate " DEVCTL_PM_RAISE_PWR\n", instance); 20687c478bd9Sstevel@tonic-gate } 20697c478bd9Sstevel@tonic-gate if (pm_raise_power(pshot->dip, 0, MAXPWR) != DDI_SUCCESS) { 20707c478bd9Sstevel@tonic-gate rv = EINVAL; 20717c478bd9Sstevel@tonic-gate } else { 20727c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 20737c478bd9Sstevel@tonic-gate if (pshot_debug) { 20747c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d:" 20757c478bd9Sstevel@tonic-gate " DEVCTL_PM_RAISE_POWER: comp 0" 20767c478bd9Sstevel@tonic-gate " to level %d\n", instance, pshot->level); 20777c478bd9Sstevel@tonic-gate } 20787c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 20797c478bd9Sstevel@tonic-gate } 20807c478bd9Sstevel@tonic-gate break; 20817c478bd9Sstevel@tonic-gate 20827c478bd9Sstevel@tonic-gate case DEVCTL_PM_LOWER_PWR: 20837c478bd9Sstevel@tonic-gate /* 20847c478bd9Sstevel@tonic-gate * pm_lower_power() call for negative testing 20857c478bd9Sstevel@tonic-gate * expected to fail. 20867c478bd9Sstevel@tonic-gate */ 20877c478bd9Sstevel@tonic-gate if (pshot_debug) { 20887c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 20897c478bd9Sstevel@tonic-gate " DEVCTL_PM_LOWER_PWR\n", instance); 20907c478bd9Sstevel@tonic-gate } 20917c478bd9Sstevel@tonic-gate if (pm_lower_power(pshot->dip, 0, 0) != DDI_SUCCESS) { 20927c478bd9Sstevel@tonic-gate rv = EINVAL; 20937c478bd9Sstevel@tonic-gate } else { 20947c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 20957c478bd9Sstevel@tonic-gate if (pshot_debug) { 20967c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d:" 20977c478bd9Sstevel@tonic-gate " DEVCTL_PM_LOWER_POWER comp 0" 20987c478bd9Sstevel@tonic-gate " to level %d\n", instance, pshot->level); 20997c478bd9Sstevel@tonic-gate } 21007c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 21017c478bd9Sstevel@tonic-gate } 21027c478bd9Sstevel@tonic-gate break; 21037c478bd9Sstevel@tonic-gate 21047c478bd9Sstevel@tonic-gate case DEVCTL_PM_CHANGE_PWR_LOW: 21057c478bd9Sstevel@tonic-gate /* 21067c478bd9Sstevel@tonic-gate * inform the PM framework that component 0 has changed 21077c478bd9Sstevel@tonic-gate * power level to 0 via a pm_power_has_changed() call 21087c478bd9Sstevel@tonic-gate */ 21097c478bd9Sstevel@tonic-gate if (pshot_debug) { 21107c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 21117c478bd9Sstevel@tonic-gate " DEVCTL_PM_CHANGE_PWR_LOW\n", instance); 21127c478bd9Sstevel@tonic-gate } 21137c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 21147c478bd9Sstevel@tonic-gate pshot->level = 0; 21157c478bd9Sstevel@tonic-gate if (pm_power_has_changed(pshot->dip, 0, 0) != DDI_SUCCESS) { 21167c478bd9Sstevel@tonic-gate rv = EINVAL; 21177c478bd9Sstevel@tonic-gate } else { 21187c478bd9Sstevel@tonic-gate if (pshot_debug) { 21197c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d:" 21207c478bd9Sstevel@tonic-gate " DEVCTL_PM_CHANGE_PWR_LOW comp 0 to" 21217c478bd9Sstevel@tonic-gate " level %d\n", instance, pshot->level); 21227c478bd9Sstevel@tonic-gate } 21237c478bd9Sstevel@tonic-gate } 21247c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 21257c478bd9Sstevel@tonic-gate break; 21267c478bd9Sstevel@tonic-gate 21277c478bd9Sstevel@tonic-gate case DEVCTL_PM_CHANGE_PWR_HIGH: 21287c478bd9Sstevel@tonic-gate /* 21297c478bd9Sstevel@tonic-gate * inform the PM framework that component 0 has changed 21307c478bd9Sstevel@tonic-gate * power level to MAXPWR via a pm_power_has_changed() call 21317c478bd9Sstevel@tonic-gate */ 21327c478bd9Sstevel@tonic-gate if (pshot_debug) { 21337c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 21347c478bd9Sstevel@tonic-gate " DEVCTL_PM_CHANGE_PWR_HIGH\n", instance); 21357c478bd9Sstevel@tonic-gate } 21367c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 21377c478bd9Sstevel@tonic-gate pshot->level = MAXPWR; 21387c478bd9Sstevel@tonic-gate if (pm_power_has_changed(pshot->dip, 0, MAXPWR) 21397c478bd9Sstevel@tonic-gate != DDI_SUCCESS) { 21407c478bd9Sstevel@tonic-gate rv = EINVAL; 21417c478bd9Sstevel@tonic-gate } else { 21427c478bd9Sstevel@tonic-gate if (pshot_debug) { 21437c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d:" 21447c478bd9Sstevel@tonic-gate " DEVCTL_PM_CHANGE_PWR_HIGH comp 0 to" 21457c478bd9Sstevel@tonic-gate " level %d\n", instance, pshot->level); 21467c478bd9Sstevel@tonic-gate } 21477c478bd9Sstevel@tonic-gate } 21487c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 21497c478bd9Sstevel@tonic-gate break; 21507c478bd9Sstevel@tonic-gate 21517c478bd9Sstevel@tonic-gate case DEVCTL_PM_POWER: 21527c478bd9Sstevel@tonic-gate /* 21537c478bd9Sstevel@tonic-gate * test if the pshot_power() routine has been called, 21547c478bd9Sstevel@tonic-gate * then clear 21557c478bd9Sstevel@tonic-gate */ 21567c478bd9Sstevel@tonic-gate if (pshot_debug) { 21577c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 21587c478bd9Sstevel@tonic-gate " DEVCTL_PM_POWER\n", instance); 21597c478bd9Sstevel@tonic-gate } 21607c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 21617c478bd9Sstevel@tonic-gate state = (pshot->state & POWER_FLAG) ? 1 : 0; 21627c478bd9Sstevel@tonic-gate if (copyout(&state, dcp->cpyout_buf, 21637c478bd9Sstevel@tonic-gate sizeof (uint_t)) != 0) { 21647c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot%d devctl:" 21657c478bd9Sstevel@tonic-gate " DEVCTL_PM_POWER: copyout failed", 21667c478bd9Sstevel@tonic-gate instance); 21677c478bd9Sstevel@tonic-gate rv = EINVAL; 21687c478bd9Sstevel@tonic-gate } 21697c478bd9Sstevel@tonic-gate if (pshot_debug) { 21707c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_POWER:" 21717c478bd9Sstevel@tonic-gate " POWER_FLAG = %d\n", instance, state); 21727c478bd9Sstevel@tonic-gate } 21737c478bd9Sstevel@tonic-gate pshot->state &= ~POWER_FLAG; 21747c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 21757c478bd9Sstevel@tonic-gate break; 21767c478bd9Sstevel@tonic-gate 21777c478bd9Sstevel@tonic-gate case DEVCTL_PM_FAIL_SUSPEND: 21787c478bd9Sstevel@tonic-gate /* 21797c478bd9Sstevel@tonic-gate * fail DDI_SUSPEND 21807c478bd9Sstevel@tonic-gate */ 21817c478bd9Sstevel@tonic-gate if (pshot_debug) { 21827c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 21837c478bd9Sstevel@tonic-gate " DEVCTL_PM_FAIL_SUSPEND\n", instance); 21847c478bd9Sstevel@tonic-gate } 21857c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 21867c478bd9Sstevel@tonic-gate pshot->state |= FAIL_SUSPEND_FLAG; 21877c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 21887c478bd9Sstevel@tonic-gate if (pshot_debug) { 21897c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: DEVCTL_PM_FAIL_SUSPEND\n", 21907c478bd9Sstevel@tonic-gate instance); 21917c478bd9Sstevel@tonic-gate } 21927c478bd9Sstevel@tonic-gate break; 21937c478bd9Sstevel@tonic-gate 21947c478bd9Sstevel@tonic-gate case DEVCTL_PM_BUS_STRICT_TEST: 21957c478bd9Sstevel@tonic-gate /* 21967c478bd9Sstevel@tonic-gate * test the STRICT_PARENT flag: 21977c478bd9Sstevel@tonic-gate * set => STRICT PARENT 21987c478bd9Sstevel@tonic-gate * not set => INVOLVED PARENT 21997c478bd9Sstevel@tonic-gate */ 22007c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 22017c478bd9Sstevel@tonic-gate state = (pshot->state & STRICT_PARENT) ? 1 : 0; 22027c478bd9Sstevel@tonic-gate if (copyout(&state, dcp->cpyout_buf, 22037c478bd9Sstevel@tonic-gate sizeof (uint_t)) != 0) { 22047c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot%d devctl:" 22057c478bd9Sstevel@tonic-gate " DEVCTL_PM_BUS_STRICT_TEST: copyout failed", 22067c478bd9Sstevel@tonic-gate instance); 22077c478bd9Sstevel@tonic-gate rv = EINVAL; 22087c478bd9Sstevel@tonic-gate } 22097c478bd9Sstevel@tonic-gate if (pshot_debug) { 22107c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 22117c478bd9Sstevel@tonic-gate " DEVCTL_PM_BUS_STRICT_TEST: type = %s\n", 22127c478bd9Sstevel@tonic-gate instance, ((state == 0) ? "INVOLVED" : "STRICT")); 22137c478bd9Sstevel@tonic-gate } 22147c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 22157c478bd9Sstevel@tonic-gate break; 22167c478bd9Sstevel@tonic-gate 22177c478bd9Sstevel@tonic-gate case DEVCTL_PM_BUS_NO_INVOL: 22187c478bd9Sstevel@tonic-gate /* 22197c478bd9Sstevel@tonic-gate * Set the NO_INVOL_FLAG flag to 22207c478bd9Sstevel@tonic-gate * notify the driver that the child will not 22217c478bd9Sstevel@tonic-gate * call pm_lower_power() on detach. 22227c478bd9Sstevel@tonic-gate * The driver needs to mark itself idle twice 22237c478bd9Sstevel@tonic-gate * during DDI_CTLOPS_DETACH (post). 22247c478bd9Sstevel@tonic-gate */ 22257c478bd9Sstevel@tonic-gate if (pshot_debug) { 22267c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl:" 22277c478bd9Sstevel@tonic-gate " DEVCTL_PM_BUS_NO_INVOL\n", instance); 22287c478bd9Sstevel@tonic-gate } 22297c478bd9Sstevel@tonic-gate mutex_enter(&pshot->lock); 22307c478bd9Sstevel@tonic-gate pshot->state |= NO_INVOL_FLAG; 22317c478bd9Sstevel@tonic-gate mutex_exit(&pshot->lock); 22327c478bd9Sstevel@tonic-gate break; 22337c478bd9Sstevel@tonic-gate 22347c478bd9Sstevel@tonic-gate default: 22357c478bd9Sstevel@tonic-gate rv = ENOTTY; 22367c478bd9Sstevel@tonic-gate } 22377c478bd9Sstevel@tonic-gate 22387c478bd9Sstevel@tonic-gate ndi_dc_freehdl(dcp); 22397c478bd9Sstevel@tonic-gate return (rv); 22407c478bd9Sstevel@tonic-gate } 22417c478bd9Sstevel@tonic-gate 22427c478bd9Sstevel@tonic-gate 22437c478bd9Sstevel@tonic-gate /* 22447c478bd9Sstevel@tonic-gate * pshot_testctl: handle other test operations 22457c478bd9Sstevel@tonic-gate * - If <cmd> is a DEVCTL cmd, then <arg> is a dev_t indicating which 22467c478bd9Sstevel@tonic-gate * child to direct the DEVCTL to, if applicable; 22477c478bd9Sstevel@tonic-gate * furthermore, any cmd here can be sent by layered ioctls (unlike 22487c478bd9Sstevel@tonic-gate * those to pshot_devctl() which must come from userland) 22497c478bd9Sstevel@tonic-gate */ 22507c478bd9Sstevel@tonic-gate /* ARGSUSED */ 22517c478bd9Sstevel@tonic-gate static int 22527c478bd9Sstevel@tonic-gate pshot_testctl(pshot_t *pshot, minor_t nodenum, int cmd, intptr_t arg, int mode, 22537c478bd9Sstevel@tonic-gate cred_t *credp, int *rvalp) 22547c478bd9Sstevel@tonic-gate { 22557c478bd9Sstevel@tonic-gate dev_info_t *self; 22567c478bd9Sstevel@tonic-gate dev_info_t *child = NULL; 22577c478bd9Sstevel@tonic-gate uint_t state; 22587c478bd9Sstevel@tonic-gate int rv = 0; 22597c478bd9Sstevel@tonic-gate int instance; 22607c478bd9Sstevel@tonic-gate int i; 22617c478bd9Sstevel@tonic-gate 22627c478bd9Sstevel@tonic-gate /* uint_t flags; */ 22637c478bd9Sstevel@tonic-gate 22647c478bd9Sstevel@tonic-gate /* flags = (pshot_devctl_debug) ? NDI_DEVI_DEBUG : 0; */ 22657c478bd9Sstevel@tonic-gate self = pshot->dip; 22667c478bd9Sstevel@tonic-gate instance = pshot->instance; 22677c478bd9Sstevel@tonic-gate 22687c478bd9Sstevel@tonic-gate if (cmd & DEVCTL_IOC) { 22697c478bd9Sstevel@tonic-gate child = e_ddi_hold_devi_by_dev((dev_t)arg, 0); 22707c478bd9Sstevel@tonic-gate } 22717c478bd9Sstevel@tonic-gate 22727c478bd9Sstevel@tonic-gate for (i = 0; pshot_devctls[i].ioctl_int != 0; i++) { 22737c478bd9Sstevel@tonic-gate if (pshot_devctls[i].ioctl_int == cmd) { 22747c478bd9Sstevel@tonic-gate if (pshot_debug) 22757c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d devctl: %s", 22767c478bd9Sstevel@tonic-gate instance, pshot_devctls[i].ioctl_char); 22777c478bd9Sstevel@tonic-gate } 22787c478bd9Sstevel@tonic-gate } 22797c478bd9Sstevel@tonic-gate switch (cmd) { 22807c478bd9Sstevel@tonic-gate case DEVCTL_DEVICE_RESET: 22817c478bd9Sstevel@tonic-gate if (pshot_debug) 22827c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d testctl:" 22837c478bd9Sstevel@tonic-gate " DEVCTL_PM_POWER\n", instance); 22847c478bd9Sstevel@tonic-gate rv = pshot_event(pshot, PSHOT_EVENT_TAG_DEV_RESET, 22857c478bd9Sstevel@tonic-gate child, (void *)self); 22867c478bd9Sstevel@tonic-gate ASSERT(rv == NDI_SUCCESS); 22877c478bd9Sstevel@tonic-gate break; 22887c478bd9Sstevel@tonic-gate 22897c478bd9Sstevel@tonic-gate case DEVCTL_BUS_QUIESCE: 22907c478bd9Sstevel@tonic-gate if (pshot_debug) 22917c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d testctl:" 22927c478bd9Sstevel@tonic-gate " DEVCTL_PM_POWER\n", instance); 22937c478bd9Sstevel@tonic-gate if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) { 22947c478bd9Sstevel@tonic-gate if (state == BUS_QUIESCED) { 22957c478bd9Sstevel@tonic-gate break; 22967c478bd9Sstevel@tonic-gate } 22977c478bd9Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_QUIESCED); 22987c478bd9Sstevel@tonic-gate } 22997c478bd9Sstevel@tonic-gate rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_QUIESCE, 23007c478bd9Sstevel@tonic-gate child, (void *)self); 23017c478bd9Sstevel@tonic-gate ASSERT(rv == NDI_SUCCESS); 23027c478bd9Sstevel@tonic-gate 23037c478bd9Sstevel@tonic-gate break; 23047c478bd9Sstevel@tonic-gate 23057c478bd9Sstevel@tonic-gate case DEVCTL_BUS_UNQUIESCE: 23067c478bd9Sstevel@tonic-gate if (pshot_debug) 23077c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d testctl:" 23087c478bd9Sstevel@tonic-gate " DEVCTL_PM_POWER\n", instance); 23097c478bd9Sstevel@tonic-gate if (ndi_get_bus_state(self, &state) == NDI_SUCCESS) { 23107c478bd9Sstevel@tonic-gate if (state == BUS_ACTIVE) { 23117c478bd9Sstevel@tonic-gate break; 23127c478bd9Sstevel@tonic-gate } 23137c478bd9Sstevel@tonic-gate } 23147c478bd9Sstevel@tonic-gate 23157c478bd9Sstevel@tonic-gate /* 23167c478bd9Sstevel@tonic-gate * quiesce the bus through bus-specific means 23177c478bd9Sstevel@tonic-gate */ 23187c478bd9Sstevel@tonic-gate (void) ndi_set_bus_state(self, BUS_ACTIVE); 23197c478bd9Sstevel@tonic-gate rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_UNQUIESCE, 23207c478bd9Sstevel@tonic-gate child, (void *)self); 23217c478bd9Sstevel@tonic-gate ASSERT(rv == NDI_SUCCESS); 23227c478bd9Sstevel@tonic-gate break; 23237c478bd9Sstevel@tonic-gate 23247c478bd9Sstevel@tonic-gate case DEVCTL_BUS_RESET: 23257c478bd9Sstevel@tonic-gate case DEVCTL_BUS_RESETALL: 23267c478bd9Sstevel@tonic-gate /* 23277c478bd9Sstevel@tonic-gate * no reset support for the pseudo bus 23287c478bd9Sstevel@tonic-gate * but if there were.... 23297c478bd9Sstevel@tonic-gate */ 23307c478bd9Sstevel@tonic-gate rv = pshot_event(pshot, PSHOT_EVENT_TAG_BUS_RESET, 23317c478bd9Sstevel@tonic-gate child, (void *)self); 23327c478bd9Sstevel@tonic-gate ASSERT(rv == NDI_SUCCESS); 23337c478bd9Sstevel@tonic-gate break; 23347c478bd9Sstevel@tonic-gate 23357c478bd9Sstevel@tonic-gate default: 23367c478bd9Sstevel@tonic-gate rv = ENOTTY; 23377c478bd9Sstevel@tonic-gate } 23387c478bd9Sstevel@tonic-gate 23397c478bd9Sstevel@tonic-gate if (child != NULL) 23407c478bd9Sstevel@tonic-gate ddi_release_devi(child); 23417c478bd9Sstevel@tonic-gate return (rv); 23427c478bd9Sstevel@tonic-gate } 23437c478bd9Sstevel@tonic-gate 23447c478bd9Sstevel@tonic-gate 23457c478bd9Sstevel@tonic-gate static int 23467c478bd9Sstevel@tonic-gate pshot_get_eventcookie(dev_info_t *dip, dev_info_t *rdip, 23477c478bd9Sstevel@tonic-gate char *eventname, ddi_eventcookie_t *event_cookiep) 23487c478bd9Sstevel@tonic-gate { 23497c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 23507c478bd9Sstevel@tonic-gate pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance); 23517c478bd9Sstevel@tonic-gate 23527c478bd9Sstevel@tonic-gate if (pshot_debug) 23537c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: " 23547c478bd9Sstevel@tonic-gate "pshot_get_eventcookie:\n\t" 23557c478bd9Sstevel@tonic-gate "dip = 0x%p rdip = 0x%p (%s/%d) eventname = %s\n", 23567c478bd9Sstevel@tonic-gate instance, (void *)dip, (void *)rdip, 23577c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_instance(rdip), 23587c478bd9Sstevel@tonic-gate eventname); 23597c478bd9Sstevel@tonic-gate 23607c478bd9Sstevel@tonic-gate 23617c478bd9Sstevel@tonic-gate return (ndi_event_retrieve_cookie(pshot->ndi_event_hdl, 23627c478bd9Sstevel@tonic-gate rdip, eventname, event_cookiep, NDI_EVENT_NOPASS)); 23637c478bd9Sstevel@tonic-gate } 23647c478bd9Sstevel@tonic-gate 23657c478bd9Sstevel@tonic-gate static int 23667c478bd9Sstevel@tonic-gate pshot_add_eventcall(dev_info_t *dip, dev_info_t *rdip, 23677c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie, 23687c478bd9Sstevel@tonic-gate void (*callback)(), void *arg, ddi_callback_id_t *cb_id) 23697c478bd9Sstevel@tonic-gate { 23707c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 23717c478bd9Sstevel@tonic-gate pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance); 23727c478bd9Sstevel@tonic-gate 23737c478bd9Sstevel@tonic-gate if (pshot_debug) 23747c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: " 23757c478bd9Sstevel@tonic-gate "pshot_add_eventcall:\n\t" 23767c478bd9Sstevel@tonic-gate "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n\t" 23777c478bd9Sstevel@tonic-gate "cb = 0x%p, arg = 0x%p\n", 23787c478bd9Sstevel@tonic-gate instance, (void *)dip, (void *)rdip, 23797c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_instance(rdip), (void *)cookie, 23807c478bd9Sstevel@tonic-gate NDI_EVENT_NAME(cookie), (void *)callback, arg); 23817c478bd9Sstevel@tonic-gate 23827c478bd9Sstevel@tonic-gate /* add callback to our event handle */ 23837c478bd9Sstevel@tonic-gate return (ndi_event_add_callback(pshot->ndi_event_hdl, rdip, 23847c478bd9Sstevel@tonic-gate cookie, callback, arg, NDI_SLEEP, cb_id)); 23857c478bd9Sstevel@tonic-gate } 23867c478bd9Sstevel@tonic-gate 23877c478bd9Sstevel@tonic-gate static int 23887c478bd9Sstevel@tonic-gate pshot_remove_eventcall(dev_info_t *dip, ddi_callback_id_t cb_id) 23897c478bd9Sstevel@tonic-gate { 23907c478bd9Sstevel@tonic-gate 23917c478bd9Sstevel@tonic-gate ndi_event_callbacks_t *cb = (ndi_event_callbacks_t *)cb_id; 23927c478bd9Sstevel@tonic-gate 23937c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 23947c478bd9Sstevel@tonic-gate pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance); 23957c478bd9Sstevel@tonic-gate 23967c478bd9Sstevel@tonic-gate ASSERT(cb); 23977c478bd9Sstevel@tonic-gate 23987c478bd9Sstevel@tonic-gate if (pshot_debug) 23997c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: " 24007c478bd9Sstevel@tonic-gate "pshot_remove_eventcall:\n\t" 24017c478bd9Sstevel@tonic-gate "dip = 0x%p rdip = 0x%p (%s%d)\n\tcookie = 0x%p (%s)\n", 24027c478bd9Sstevel@tonic-gate instance, (void *)dip, (void *)cb->ndi_evtcb_dip, 24037c478bd9Sstevel@tonic-gate ddi_node_name(cb->ndi_evtcb_dip), 24047c478bd9Sstevel@tonic-gate ddi_get_instance(cb->ndi_evtcb_dip), (void *)cb->ndi_evtcb_cookie, 24057c478bd9Sstevel@tonic-gate NDI_EVENT_NAME(cb->ndi_evtcb_cookie)); 24067c478bd9Sstevel@tonic-gate 24077c478bd9Sstevel@tonic-gate return (ndi_event_remove_callback(pshot->ndi_event_hdl, cb_id)); 24087c478bd9Sstevel@tonic-gate } 24097c478bd9Sstevel@tonic-gate 24107c478bd9Sstevel@tonic-gate static int 24117c478bd9Sstevel@tonic-gate pshot_post_event(dev_info_t *dip, dev_info_t *rdip, 24127c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie, void *impl_data) 24137c478bd9Sstevel@tonic-gate { 24147c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(dip); 24157c478bd9Sstevel@tonic-gate pshot_t *pshot = ddi_get_soft_state(pshot_softstatep, instance); 24167c478bd9Sstevel@tonic-gate 24177c478bd9Sstevel@tonic-gate if (pshot_debug) { 24187c478bd9Sstevel@tonic-gate if (rdip) { 24197c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: " 24207c478bd9Sstevel@tonic-gate "pshot_post_event:\n\t" 24217c478bd9Sstevel@tonic-gate "dip = 0x%p rdip = 0x%p (%s%d\n\t" 24227c478bd9Sstevel@tonic-gate "cookie = 0x%p (%s)\n\tbus_impl = 0x%p\n", 24237c478bd9Sstevel@tonic-gate instance, (void *)dip, (void *)rdip, 24247c478bd9Sstevel@tonic-gate ddi_node_name(rdip), ddi_get_instance(rdip), (void *)cookie, 24257c478bd9Sstevel@tonic-gate NDI_EVENT_NAME(cookie), impl_data); 24267c478bd9Sstevel@tonic-gate } else { 24277c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: " 24287c478bd9Sstevel@tonic-gate "pshot_post_event:\n\t" 24297c478bd9Sstevel@tonic-gate "dip = 0x%p cookie = 0x%p (%s) bus_impl = 0x%p\n", 24307c478bd9Sstevel@tonic-gate instance, (void *)dip, (void *)cookie, 24317c478bd9Sstevel@tonic-gate NDI_EVENT_NAME(cookie), impl_data); 24327c478bd9Sstevel@tonic-gate } 24337c478bd9Sstevel@tonic-gate } 24347c478bd9Sstevel@tonic-gate 24357c478bd9Sstevel@tonic-gate /* run callbacks for this event */ 24367c478bd9Sstevel@tonic-gate return (ndi_event_run_callbacks(pshot->ndi_event_hdl, rdip, 24377c478bd9Sstevel@tonic-gate cookie, impl_data)); 24387c478bd9Sstevel@tonic-gate } 24397c478bd9Sstevel@tonic-gate 24407c478bd9Sstevel@tonic-gate /* 24417c478bd9Sstevel@tonic-gate * the nexus driver will generate events 24427c478bd9Sstevel@tonic-gate * that need to go to children 24437c478bd9Sstevel@tonic-gate */ 24447c478bd9Sstevel@tonic-gate static int 24457c478bd9Sstevel@tonic-gate pshot_event(pshot_t *pshot, int event_tag, dev_info_t *child, 24467c478bd9Sstevel@tonic-gate void *bus_impldata) 24477c478bd9Sstevel@tonic-gate { 24487c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie = ndi_event_tag_to_cookie( 24497c478bd9Sstevel@tonic-gate pshot->ndi_event_hdl, event_tag); 24507c478bd9Sstevel@tonic-gate 24517c478bd9Sstevel@tonic-gate if (pshot_debug) { 24527c478bd9Sstevel@tonic-gate if (child) { 24537c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: " 24547c478bd9Sstevel@tonic-gate "pshot_event: event_tag = 0x%x (%s)\n\t" 24557c478bd9Sstevel@tonic-gate "child = 0x%p (%s%d) bus_impl = 0x%p (%s%d)\n", 24567c478bd9Sstevel@tonic-gate pshot->instance, event_tag, 24577c478bd9Sstevel@tonic-gate ndi_event_tag_to_name(pshot->ndi_event_hdl, event_tag), 24587c478bd9Sstevel@tonic-gate (void *)child, ddi_node_name(child), 24597c478bd9Sstevel@tonic-gate ddi_get_instance(child), bus_impldata, 24607c478bd9Sstevel@tonic-gate ddi_node_name((dev_info_t *)bus_impldata), 24617c478bd9Sstevel@tonic-gate ddi_get_instance((dev_info_t *)bus_impldata)); 24627c478bd9Sstevel@tonic-gate } else { 24637c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: " 24647c478bd9Sstevel@tonic-gate "pshot_event: event_tag = 0x%x (%s)\n\t" 24657c478bd9Sstevel@tonic-gate "child = NULL, bus_impl = 0x%p (%s%d)\n", 24667c478bd9Sstevel@tonic-gate pshot->instance, event_tag, 24677c478bd9Sstevel@tonic-gate ndi_event_tag_to_name(pshot->ndi_event_hdl, event_tag), 24687c478bd9Sstevel@tonic-gate bus_impldata, 24697c478bd9Sstevel@tonic-gate ddi_node_name((dev_info_t *)bus_impldata), 24707c478bd9Sstevel@tonic-gate ddi_get_instance((dev_info_t *)bus_impldata)); 24717c478bd9Sstevel@tonic-gate } 24727c478bd9Sstevel@tonic-gate } 24737c478bd9Sstevel@tonic-gate 24747c478bd9Sstevel@tonic-gate return (ndi_event_run_callbacks(pshot->ndi_event_hdl, 24757c478bd9Sstevel@tonic-gate child, cookie, bus_impldata)); 24767c478bd9Sstevel@tonic-gate } 24777c478bd9Sstevel@tonic-gate 24787c478bd9Sstevel@tonic-gate 24797c478bd9Sstevel@tonic-gate /* 24807c478bd9Sstevel@tonic-gate * the pshot driver event notification callback 24817c478bd9Sstevel@tonic-gate */ 24827c478bd9Sstevel@tonic-gate static void 24837c478bd9Sstevel@tonic-gate pshot_event_cb(dev_info_t *dip, ddi_eventcookie_t cookie, 24847c478bd9Sstevel@tonic-gate void *arg, void *bus_impldata) 24857c478bd9Sstevel@tonic-gate { 24867c478bd9Sstevel@tonic-gate pshot_t *pshot = (pshot_t *)arg; 24877c478bd9Sstevel@tonic-gate int event_tag; 24887c478bd9Sstevel@tonic-gate 24897c478bd9Sstevel@tonic-gate /* look up the event */ 24907c478bd9Sstevel@tonic-gate event_tag = NDI_EVENT_TAG(cookie); 24917c478bd9Sstevel@tonic-gate 24927c478bd9Sstevel@tonic-gate if (pshot_debug) { 24937c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: " 24947c478bd9Sstevel@tonic-gate "pshot_event_cb:\n\t" 24957c478bd9Sstevel@tonic-gate "dip = 0x%p cookie = 0x%p (%s), tag = 0x%x\n\t" 24967c478bd9Sstevel@tonic-gate "arg = 0x%p bus_impl = 0x%p (%s%d)\n", 24977c478bd9Sstevel@tonic-gate pshot->instance, (void *)dip, (void *)cookie, 24987c478bd9Sstevel@tonic-gate NDI_EVENT_NAME(cookie), event_tag, arg, bus_impldata, 24997c478bd9Sstevel@tonic-gate ddi_node_name((dev_info_t *)bus_impldata), 25007c478bd9Sstevel@tonic-gate ddi_get_instance((dev_info_t *)bus_impldata)); 25017c478bd9Sstevel@tonic-gate } 25027c478bd9Sstevel@tonic-gate 25037c478bd9Sstevel@tonic-gate switch (event_tag) { 25047c478bd9Sstevel@tonic-gate case PSHOT_EVENT_TAG_OFFLINE: 25057c478bd9Sstevel@tonic-gate case PSHOT_EVENT_TAG_BUS_RESET: 25067c478bd9Sstevel@tonic-gate case PSHOT_EVENT_TAG_BUS_QUIESCE: 25077c478bd9Sstevel@tonic-gate case PSHOT_EVENT_TAG_BUS_UNQUIESCE: 25087c478bd9Sstevel@tonic-gate /* notify all subscribers of the this event */ 25097c478bd9Sstevel@tonic-gate (void) ndi_event_run_callbacks(pshot->ndi_event_hdl, 25107c478bd9Sstevel@tonic-gate NULL, cookie, bus_impldata); 25117c478bd9Sstevel@tonic-gate if (pshot_debug) { 25127c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: event=%s\n\t" 25137c478bd9Sstevel@tonic-gate "pshot_event_cb\n", pshot->instance, 25147c478bd9Sstevel@tonic-gate NDI_EVENT_NAME(cookie)); 25157c478bd9Sstevel@tonic-gate } 25167c478bd9Sstevel@tonic-gate /*FALLTHRU*/ 25177c478bd9Sstevel@tonic-gate case PSHOT_EVENT_TAG_TEST_POST: 25187c478bd9Sstevel@tonic-gate case PSHOT_EVENT_TAG_DEV_RESET: 25197c478bd9Sstevel@tonic-gate default: 25207c478bd9Sstevel@tonic-gate return; 25217c478bd9Sstevel@tonic-gate } 25227c478bd9Sstevel@tonic-gate } 25237c478bd9Sstevel@tonic-gate 25247c478bd9Sstevel@tonic-gate static int 25257c478bd9Sstevel@tonic-gate pshot_bus_config(dev_info_t *parent, uint_t flags, 25267c478bd9Sstevel@tonic-gate ddi_bus_config_op_t op, void *arg, dev_info_t **childp) 25277c478bd9Sstevel@tonic-gate { 25287c478bd9Sstevel@tonic-gate int rval; 25297c478bd9Sstevel@tonic-gate char *devname; 25307c478bd9Sstevel@tonic-gate char *devstr, *cname, *caddr; 25317c478bd9Sstevel@tonic-gate int devstrlen; 25327c478bd9Sstevel@tonic-gate int circ; 25337c478bd9Sstevel@tonic-gate pshot_t *pshot; 25347c478bd9Sstevel@tonic-gate int instance = ddi_get_instance(parent); 25357c478bd9Sstevel@tonic-gate 25367c478bd9Sstevel@tonic-gate if (pshot_debug) { 25377c478bd9Sstevel@tonic-gate flags |= NDI_DEVI_DEBUG; 25387c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 25397c478bd9Sstevel@tonic-gate "pshot%d: bus_config %s flags=0x%x\n", 25407c478bd9Sstevel@tonic-gate ddi_get_instance(parent), 25417c478bd9Sstevel@tonic-gate (op == BUS_CONFIG_ONE) ? (char *)arg : "", flags); 25427c478bd9Sstevel@tonic-gate } 25437c478bd9Sstevel@tonic-gate 25447c478bd9Sstevel@tonic-gate pshot = ddi_get_soft_state(pshot_softstatep, instance); 25457c478bd9Sstevel@tonic-gate if (pshot == NULL) { 25467c478bd9Sstevel@tonic-gate 25477c478bd9Sstevel@tonic-gate return (NDI_FAILURE); 25487c478bd9Sstevel@tonic-gate } 25497c478bd9Sstevel@tonic-gate 25507c478bd9Sstevel@tonic-gate /* 25517c478bd9Sstevel@tonic-gate * Hold the nexus across the bus_config 25527c478bd9Sstevel@tonic-gate */ 25537c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 25547c478bd9Sstevel@tonic-gate 25557c478bd9Sstevel@tonic-gate switch (op) { 25567c478bd9Sstevel@tonic-gate case BUS_CONFIG_ONE: 25577c478bd9Sstevel@tonic-gate 25587c478bd9Sstevel@tonic-gate /* 25597c478bd9Sstevel@tonic-gate * lookup and hold child device, create if not found 25607c478bd9Sstevel@tonic-gate */ 25617c478bd9Sstevel@tonic-gate devname = (char *)arg; 25627c478bd9Sstevel@tonic-gate devstrlen = strlen(devname) + 1; 25637c478bd9Sstevel@tonic-gate devstr = i_ddi_strdup(devname, KM_SLEEP); 25647c478bd9Sstevel@tonic-gate i_ddi_parse_name(devstr, &cname, &caddr, NULL); 25657c478bd9Sstevel@tonic-gate 25667c478bd9Sstevel@tonic-gate /* 25677c478bd9Sstevel@tonic-gate * The framework ensures that the node has 25687c478bd9Sstevel@tonic-gate * a name but each nexus is responsible for 25697c478bd9Sstevel@tonic-gate * the bus address name space. This driver 25707c478bd9Sstevel@tonic-gate * requires that a bus address be specified, 25717c478bd9Sstevel@tonic-gate * as will most nexus drivers. 25727c478bd9Sstevel@tonic-gate */ 25737c478bd9Sstevel@tonic-gate ASSERT(cname && strlen(cname) > 0); 25747c478bd9Sstevel@tonic-gate if (caddr == NULL || strlen(caddr) == 0) { 25757c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, 25767c478bd9Sstevel@tonic-gate "pshot%d: malformed name %s (no bus address)", 25777c478bd9Sstevel@tonic-gate ddi_get_instance(parent), devname); 25787c478bd9Sstevel@tonic-gate kmem_free(devstr, devstrlen); 25797c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 25807c478bd9Sstevel@tonic-gate return (NDI_FAILURE); 25817c478bd9Sstevel@tonic-gate } 25827c478bd9Sstevel@tonic-gate 25837c478bd9Sstevel@tonic-gate /* 25847c478bd9Sstevel@tonic-gate * Handle a few special cases for testing purposes 25857c478bd9Sstevel@tonic-gate */ 25867c478bd9Sstevel@tonic-gate rval = pshot_bus_config_test_specials(parent, 25877c478bd9Sstevel@tonic-gate devname, cname, caddr); 25887c478bd9Sstevel@tonic-gate 25897c478bd9Sstevel@tonic-gate if (rval == NDI_SUCCESS) { 25907c478bd9Sstevel@tonic-gate /* 25917c478bd9Sstevel@tonic-gate * Set up either a leaf or nexus device 25927c478bd9Sstevel@tonic-gate */ 25937c478bd9Sstevel@tonic-gate if (strcmp(cname, "pshot") == 0) { 25947c478bd9Sstevel@tonic-gate rval = pshot_bus_config_setup_nexus(parent, 25957c478bd9Sstevel@tonic-gate cname, caddr); 25967c478bd9Sstevel@tonic-gate } else { 25977c478bd9Sstevel@tonic-gate rval = pshot_bus_config_setup_leaf(parent, 25987c478bd9Sstevel@tonic-gate cname, caddr); 25997c478bd9Sstevel@tonic-gate } 26007c478bd9Sstevel@tonic-gate } 26017c478bd9Sstevel@tonic-gate 26027c478bd9Sstevel@tonic-gate kmem_free(devstr, devstrlen); 26037c478bd9Sstevel@tonic-gate break; 26047c478bd9Sstevel@tonic-gate 26057c478bd9Sstevel@tonic-gate case BUS_CONFIG_DRIVER: 26067c478bd9Sstevel@tonic-gate rval = NDI_FAILURE; 26077c478bd9Sstevel@tonic-gate break; 26087c478bd9Sstevel@tonic-gate 26097c478bd9Sstevel@tonic-gate case BUS_CONFIG_ALL: 26107c478bd9Sstevel@tonic-gate rval = NDI_SUCCESS; 26117c478bd9Sstevel@tonic-gate break; 26127c478bd9Sstevel@tonic-gate 26137c478bd9Sstevel@tonic-gate default: 26147c478bd9Sstevel@tonic-gate rval = NDI_FAILURE; 26157c478bd9Sstevel@tonic-gate break; 26167c478bd9Sstevel@tonic-gate } 26177c478bd9Sstevel@tonic-gate 26187c478bd9Sstevel@tonic-gate if (rval == NDI_SUCCESS) 26197c478bd9Sstevel@tonic-gate rval = ndi_busop_bus_config(parent, flags, op, arg, childp, 0); 26207c478bd9Sstevel@tonic-gate 26217c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 26227c478bd9Sstevel@tonic-gate 26237c478bd9Sstevel@tonic-gate if (pshot_debug) 26247c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: bus_config %s\n", 26257c478bd9Sstevel@tonic-gate ddi_get_instance(parent), 26267c478bd9Sstevel@tonic-gate (rval == NDI_SUCCESS) ? "ok" : "failed"); 26277c478bd9Sstevel@tonic-gate 26287c478bd9Sstevel@tonic-gate return (rval); 26297c478bd9Sstevel@tonic-gate } 26307c478bd9Sstevel@tonic-gate 26317c478bd9Sstevel@tonic-gate static int 26327c478bd9Sstevel@tonic-gate pshot_bus_unconfig(dev_info_t *parent, uint_t flags, 26337c478bd9Sstevel@tonic-gate ddi_bus_config_op_t op, void *arg) 26347c478bd9Sstevel@tonic-gate { 26357c478bd9Sstevel@tonic-gate major_t major; 26367c478bd9Sstevel@tonic-gate int rval = NDI_SUCCESS; 26377c478bd9Sstevel@tonic-gate int circ; 26387c478bd9Sstevel@tonic-gate 26397c478bd9Sstevel@tonic-gate if (pshot_debug) { 26407c478bd9Sstevel@tonic-gate flags |= NDI_DEVI_DEBUG; 26417c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 26427c478bd9Sstevel@tonic-gate "pshot%d: bus_unconfig %s flags=0x%x\n", 26437c478bd9Sstevel@tonic-gate ddi_get_instance(parent), 26447c478bd9Sstevel@tonic-gate (op == BUS_UNCONFIG_ONE) ? (char *)arg : "", flags); 26457c478bd9Sstevel@tonic-gate } 26467c478bd9Sstevel@tonic-gate 26477c478bd9Sstevel@tonic-gate /* 26487c478bd9Sstevel@tonic-gate * Hold the nexus across the bus_unconfig 26497c478bd9Sstevel@tonic-gate */ 26507c478bd9Sstevel@tonic-gate ndi_devi_enter(parent, &circ); 26517c478bd9Sstevel@tonic-gate 26527c478bd9Sstevel@tonic-gate switch (op) { 26537c478bd9Sstevel@tonic-gate case BUS_UNCONFIG_ONE: 26547c478bd9Sstevel@tonic-gate /* 26557c478bd9Sstevel@tonic-gate * Nothing special required here 26567c478bd9Sstevel@tonic-gate */ 26577c478bd9Sstevel@tonic-gate if (pshot_debug) { 26587c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: bus_unconfig:" 26597c478bd9Sstevel@tonic-gate " BUS_UNCONFIG_ONE\n", ddi_get_instance(parent)); 26607c478bd9Sstevel@tonic-gate } 26617c478bd9Sstevel@tonic-gate break; 26627c478bd9Sstevel@tonic-gate 26637c478bd9Sstevel@tonic-gate case BUS_UNCONFIG_DRIVER: 26647c478bd9Sstevel@tonic-gate if (pshot_debug > 0) { 26657c478bd9Sstevel@tonic-gate major = (major_t)(uintptr_t)arg; 26667c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 26677c478bd9Sstevel@tonic-gate "pshot%d: BUS_UNCONFIG_DRIVER: %s\n", 26687c478bd9Sstevel@tonic-gate ddi_get_instance(parent), 26697c478bd9Sstevel@tonic-gate ddi_major_to_name(major)); 26707c478bd9Sstevel@tonic-gate } 26717c478bd9Sstevel@tonic-gate break; 26727c478bd9Sstevel@tonic-gate 26737c478bd9Sstevel@tonic-gate case BUS_UNCONFIG_ALL: 26747c478bd9Sstevel@tonic-gate if (pshot_debug) { 26757c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: bus_unconfig:" 26767c478bd9Sstevel@tonic-gate " BUS_UNCONFIG_ALL\n", ddi_get_instance(parent)); 26777c478bd9Sstevel@tonic-gate } 26787c478bd9Sstevel@tonic-gate break; 26797c478bd9Sstevel@tonic-gate 26807c478bd9Sstevel@tonic-gate default: 26817c478bd9Sstevel@tonic-gate if (pshot_debug) { 26827c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: bus_unconfig: DEFAULT\n", 26837c478bd9Sstevel@tonic-gate ddi_get_instance(parent)); 26847c478bd9Sstevel@tonic-gate } 26857c478bd9Sstevel@tonic-gate rval = NDI_FAILURE; 26867c478bd9Sstevel@tonic-gate } 26877c478bd9Sstevel@tonic-gate 26887c478bd9Sstevel@tonic-gate if (rval == NDI_SUCCESS) 26897c478bd9Sstevel@tonic-gate rval = ndi_busop_bus_unconfig(parent, flags, op, arg); 26907c478bd9Sstevel@tonic-gate 26917c478bd9Sstevel@tonic-gate ndi_devi_exit(parent, circ); 26927c478bd9Sstevel@tonic-gate 26937c478bd9Sstevel@tonic-gate if (pshot_debug) 26947c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: bus_unconfig %s\n", 26957c478bd9Sstevel@tonic-gate ddi_get_instance(parent), 26967c478bd9Sstevel@tonic-gate (rval == NDI_SUCCESS) ? "ok" : "failed"); 26977c478bd9Sstevel@tonic-gate 26987c478bd9Sstevel@tonic-gate return (rval); 26997c478bd9Sstevel@tonic-gate } 27007c478bd9Sstevel@tonic-gate 27017c478bd9Sstevel@tonic-gate static dev_info_t * 27027c478bd9Sstevel@tonic-gate pshot_findchild(dev_info_t *pdip, char *cname, char *caddr) 27037c478bd9Sstevel@tonic-gate { 27047c478bd9Sstevel@tonic-gate dev_info_t *dip; 27057c478bd9Sstevel@tonic-gate char *addr; 27067c478bd9Sstevel@tonic-gate 27077c478bd9Sstevel@tonic-gate ASSERT(cname != NULL && caddr != NULL); 27087c478bd9Sstevel@tonic-gate ASSERT(DEVI_BUSY_OWNED(pdip)); 27097c478bd9Sstevel@tonic-gate 27107c478bd9Sstevel@tonic-gate for (dip = ddi_get_child(pdip); dip != NULL; 27117c478bd9Sstevel@tonic-gate dip = ddi_get_next_sibling(dip)) { 27127c478bd9Sstevel@tonic-gate if (strcmp(cname, ddi_node_name(dip)) != 0) 27137c478bd9Sstevel@tonic-gate continue; 27147c478bd9Sstevel@tonic-gate 27157c478bd9Sstevel@tonic-gate if ((addr = ddi_get_name_addr(dip)) == NULL) { 27167c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string(DDI_DEV_T_ANY, dip, 0, 27177c478bd9Sstevel@tonic-gate "bus-addr", &addr) == DDI_PROP_SUCCESS) { 27187c478bd9Sstevel@tonic-gate if (strcmp(caddr, addr) == 0) { 27197c478bd9Sstevel@tonic-gate ddi_prop_free(addr); 27207c478bd9Sstevel@tonic-gate return (dip); 27217c478bd9Sstevel@tonic-gate } 27227c478bd9Sstevel@tonic-gate ddi_prop_free(addr); 27237c478bd9Sstevel@tonic-gate } 27247c478bd9Sstevel@tonic-gate } else { 27257c478bd9Sstevel@tonic-gate if (strcmp(caddr, addr) == 0) 27267c478bd9Sstevel@tonic-gate return (dip); 27277c478bd9Sstevel@tonic-gate } 27287c478bd9Sstevel@tonic-gate } 27297c478bd9Sstevel@tonic-gate 27307c478bd9Sstevel@tonic-gate return (NULL); 27317c478bd9Sstevel@tonic-gate } 27327c478bd9Sstevel@tonic-gate 27337c478bd9Sstevel@tonic-gate static void 27347c478bd9Sstevel@tonic-gate pshot_nexus_properties(dev_info_t *parent, dev_info_t *child, char *cname, 27357c478bd9Sstevel@tonic-gate char *caddr) 27367c478bd9Sstevel@tonic-gate { 27377c478bd9Sstevel@tonic-gate char *extension; 27387c478bd9Sstevel@tonic-gate 27397c478bd9Sstevel@tonic-gate /* 2740*b1dd958fScth * extract the address extension 27417c478bd9Sstevel@tonic-gate */ 27427c478bd9Sstevel@tonic-gate extension = strstr(caddr, ","); 27437c478bd9Sstevel@tonic-gate if (extension != NULL) { 27447c478bd9Sstevel@tonic-gate ++extension; 27457c478bd9Sstevel@tonic-gate } else { 27467c478bd9Sstevel@tonic-gate extension = "null"; 27477c478bd9Sstevel@tonic-gate } 27487c478bd9Sstevel@tonic-gate 27497c478bd9Sstevel@tonic-gate /* 27507c478bd9Sstevel@tonic-gate * Create the "pm-want-child-notification?" property for all 27517c478bd9Sstevel@tonic-gate * nodes that do not have the "pm_strict" or "nopm_strict" 27527c478bd9Sstevel@tonic-gate * extension 27537c478bd9Sstevel@tonic-gate */ 27547c478bd9Sstevel@tonic-gate if (strcmp(extension, "pm_strict") != 0 && 27557c478bd9Sstevel@tonic-gate strcmp(extension, "nopm_strict") != 0) { 27567c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, child, 27577c478bd9Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 27587c478bd9Sstevel@tonic-gate "pm-want-child-notification?") == 0) { 27597c478bd9Sstevel@tonic-gate if (pshot_debug) { 27607c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d:" 27617c478bd9Sstevel@tonic-gate " nexus_properties:\n\tcreate the" 27627c478bd9Sstevel@tonic-gate " \"pm-want-child-notification?\"" 27637c478bd9Sstevel@tonic-gate " property for %s@%s\n", 27647c478bd9Sstevel@tonic-gate ddi_get_instance(parent), cname, caddr); 27657c478bd9Sstevel@tonic-gate } 27667c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, child, 0, 27677c478bd9Sstevel@tonic-gate "pm-want-child-notification?", NULL, 0) 27687c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 27697c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot%d:" 27707c478bd9Sstevel@tonic-gate " nexus_properties:\n\tunable to create" 27717c478bd9Sstevel@tonic-gate " the \"pm-want-child-notification?\"" 27727c478bd9Sstevel@tonic-gate " property for %s@%s", 27737c478bd9Sstevel@tonic-gate ddi_get_instance(parent), cname, caddr); 27747c478bd9Sstevel@tonic-gate } 27757c478bd9Sstevel@tonic-gate } 27767c478bd9Sstevel@tonic-gate } 27777c478bd9Sstevel@tonic-gate 27787c478bd9Sstevel@tonic-gate /* 27797c478bd9Sstevel@tonic-gate * Create the "no-pm-components" property for all nodes 27807c478bd9Sstevel@tonic-gate * with extension "nopm" or "nopm_strict" 27817c478bd9Sstevel@tonic-gate */ 27827c478bd9Sstevel@tonic-gate if (strcmp(extension, "nopm") == 0 || 27837c478bd9Sstevel@tonic-gate strcmp(extension, "nopm_strict") == 0) { 27847c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, child, 27857c478bd9Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 27867c478bd9Sstevel@tonic-gate "no-pm-components") == 0) { 27877c478bd9Sstevel@tonic-gate if (pshot_debug) { 27887c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d:" 27897c478bd9Sstevel@tonic-gate " nexus_properties:\n\tcreate the" 27907c478bd9Sstevel@tonic-gate " \"no-pm-components\"" 27917c478bd9Sstevel@tonic-gate " property for %s@%s\n", 27927c478bd9Sstevel@tonic-gate ddi_get_instance(parent), cname, caddr); 27937c478bd9Sstevel@tonic-gate } 27947c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, child, 0, 27957c478bd9Sstevel@tonic-gate "no-pm-components", NULL, 0) 27967c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 27977c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot%d:" 27987c478bd9Sstevel@tonic-gate " nexus_properties:\n\tunable to create" 27997c478bd9Sstevel@tonic-gate " the \"no-pm-components\"" 28007c478bd9Sstevel@tonic-gate " property for %s@%s", 28017c478bd9Sstevel@tonic-gate ddi_get_instance(parent), cname, caddr); 28027c478bd9Sstevel@tonic-gate } 28037c478bd9Sstevel@tonic-gate } 28047c478bd9Sstevel@tonic-gate } 28057c478bd9Sstevel@tonic-gate } 28067c478bd9Sstevel@tonic-gate 28077c478bd9Sstevel@tonic-gate static void 28087c478bd9Sstevel@tonic-gate pshot_leaf_properties(dev_info_t *parent, dev_info_t *child, char *cname, 28097c478bd9Sstevel@tonic-gate char *caddr) 28107c478bd9Sstevel@tonic-gate { 28117c478bd9Sstevel@tonic-gate char *extension; 28127c478bd9Sstevel@tonic-gate 28137c478bd9Sstevel@tonic-gate /* 2814*b1dd958fScth * extract the address extension 28157c478bd9Sstevel@tonic-gate */ 28167c478bd9Sstevel@tonic-gate extension = strstr(caddr, ","); 28177c478bd9Sstevel@tonic-gate if (extension != NULL) { 28187c478bd9Sstevel@tonic-gate ++extension; 28197c478bd9Sstevel@tonic-gate } else { 28207c478bd9Sstevel@tonic-gate extension = "null"; 28217c478bd9Sstevel@tonic-gate } 28227c478bd9Sstevel@tonic-gate 28237c478bd9Sstevel@tonic-gate /* 28247c478bd9Sstevel@tonic-gate * Create the "no-involuntary-power-cycles" property for 28257c478bd9Sstevel@tonic-gate * all leaf nodes with extension "no_invol" 28267c478bd9Sstevel@tonic-gate */ 28277c478bd9Sstevel@tonic-gate if (strcmp(extension, "no_invol") == 0) { 28287c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, child, 28297c478bd9Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 28307c478bd9Sstevel@tonic-gate "no-involuntary-power-cycles") == 0) { 28317c478bd9Sstevel@tonic-gate if (pshot_debug) { 28327c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d:" 28337c478bd9Sstevel@tonic-gate " leaf_properties:\n\tcreate the" 28347c478bd9Sstevel@tonic-gate " \"no-involuntary-power-cycles\"" 28357c478bd9Sstevel@tonic-gate " property for %s@%s\n", 28367c478bd9Sstevel@tonic-gate ddi_get_instance(parent), cname, caddr); 28377c478bd9Sstevel@tonic-gate } 28387c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, child, 28397c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, 28407c478bd9Sstevel@tonic-gate "no-involuntary-power-cycles", NULL, 0) 28417c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 28427c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot%d:" 28437c478bd9Sstevel@tonic-gate " leaf_properties:\n\tunable to create the" 28447c478bd9Sstevel@tonic-gate " \"no-involuntary-power-cycles\"" 28457c478bd9Sstevel@tonic-gate " property for %s@%s", 28467c478bd9Sstevel@tonic-gate ddi_get_instance(parent), cname, caddr); 28477c478bd9Sstevel@tonic-gate } 28487c478bd9Sstevel@tonic-gate } 28497c478bd9Sstevel@tonic-gate } 28507c478bd9Sstevel@tonic-gate 28517c478bd9Sstevel@tonic-gate /* 28527c478bd9Sstevel@tonic-gate * Create the "dependency-property" property for all leaf 28537c478bd9Sstevel@tonic-gate * nodes with extension "dep_prop" 28547c478bd9Sstevel@tonic-gate * to be used with the PM_ADD_DEPENDENT_PROPERTY ioctl 28557c478bd9Sstevel@tonic-gate */ 28567c478bd9Sstevel@tonic-gate if (strcmp(extension, "dep_prop") == 0) { 28577c478bd9Sstevel@tonic-gate if (ddi_prop_exists(DDI_DEV_T_ANY, child, 28587c478bd9Sstevel@tonic-gate (DDI_PROP_DONTPASS | DDI_PROP_NOTPROM), 28597c478bd9Sstevel@tonic-gate "dependency-property") == 0) { 28607c478bd9Sstevel@tonic-gate if (pshot_debug) { 28617c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d:" 28627c478bd9Sstevel@tonic-gate " leaf_properties:\n\tcreate the" 28637c478bd9Sstevel@tonic-gate " \"dependency-property\"" 28647c478bd9Sstevel@tonic-gate " property for %s@%s\n", 28657c478bd9Sstevel@tonic-gate ddi_get_instance(parent), cname, caddr); 28667c478bd9Sstevel@tonic-gate } 28677c478bd9Sstevel@tonic-gate if (ddi_prop_create(DDI_DEV_T_NONE, child, 28687c478bd9Sstevel@tonic-gate DDI_PROP_CANSLEEP, "dependency-property", NULL, 0) 28697c478bd9Sstevel@tonic-gate != DDI_PROP_SUCCESS) { 28707c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot%d:" 28717c478bd9Sstevel@tonic-gate " leaf_properties:\n\tunable to create the" 28727c478bd9Sstevel@tonic-gate " \"dependency-property\" property for" 28737c478bd9Sstevel@tonic-gate " %s@%s", ddi_get_instance(parent), 28747c478bd9Sstevel@tonic-gate cname, caddr); 28757c478bd9Sstevel@tonic-gate } 28767c478bd9Sstevel@tonic-gate } 28777c478bd9Sstevel@tonic-gate } 28787c478bd9Sstevel@tonic-gate } 28797c478bd9Sstevel@tonic-gate 28807c478bd9Sstevel@tonic-gate /* 28817c478bd9Sstevel@tonic-gate * BUS_CONFIG_ONE: setup a child nexus instance. 28827c478bd9Sstevel@tonic-gate */ 28837c478bd9Sstevel@tonic-gate static int 28847c478bd9Sstevel@tonic-gate pshot_bus_config_setup_nexus(dev_info_t *parent, char *cname, char *caddr) 28857c478bd9Sstevel@tonic-gate { 28867c478bd9Sstevel@tonic-gate dev_info_t *child; 28877c478bd9Sstevel@tonic-gate int rval; 28887c478bd9Sstevel@tonic-gate 28897c478bd9Sstevel@tonic-gate ASSERT(parent != 0); 28907c478bd9Sstevel@tonic-gate ASSERT(cname != NULL); 28917c478bd9Sstevel@tonic-gate ASSERT(caddr != NULL); 28927c478bd9Sstevel@tonic-gate 28937c478bd9Sstevel@tonic-gate child = pshot_findchild(parent, cname, caddr); 28947c478bd9Sstevel@tonic-gate if (child) { 28957c478bd9Sstevel@tonic-gate if (pshot_debug) { 28967c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 28977c478bd9Sstevel@tonic-gate "pshot%d: bus_config one %s@%s found\n", 28987c478bd9Sstevel@tonic-gate ddi_get_instance(parent), cname, caddr); 28997c478bd9Sstevel@tonic-gate } 29007c478bd9Sstevel@tonic-gate /* 29017c478bd9Sstevel@tonic-gate * create the "pm-want-child-notification?" property 29027c478bd9Sstevel@tonic-gate * for this child, if it doesn't already exist 29037c478bd9Sstevel@tonic-gate */ 29047c478bd9Sstevel@tonic-gate (void) pshot_nexus_properties(parent, child, cname, caddr); 29057c478bd9Sstevel@tonic-gate 29067c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 29077c478bd9Sstevel@tonic-gate } 29087c478bd9Sstevel@tonic-gate 29097c478bd9Sstevel@tonic-gate ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child); 29107c478bd9Sstevel@tonic-gate ASSERT(child != NULL); 29117c478bd9Sstevel@tonic-gate 29127c478bd9Sstevel@tonic-gate if (ndi_prop_update_string(DDI_DEV_T_NONE, child, 29137c478bd9Sstevel@tonic-gate "bus-addr", caddr) != DDI_PROP_SUCCESS) { 29147c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot%d: _prop_update %s@%s failed", 29157c478bd9Sstevel@tonic-gate ddi_get_instance(parent), cname, caddr); 29167c478bd9Sstevel@tonic-gate (void) ndi_devi_free(child); 29177c478bd9Sstevel@tonic-gate return (NDI_FAILURE); 29187c478bd9Sstevel@tonic-gate } 29197c478bd9Sstevel@tonic-gate 29207c478bd9Sstevel@tonic-gate rval = ndi_devi_bind_driver(child, 0); 29217c478bd9Sstevel@tonic-gate if (rval != NDI_SUCCESS) { 29227c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot%d: bind_driver %s failed", 29237c478bd9Sstevel@tonic-gate ddi_get_instance(parent), cname); 29247c478bd9Sstevel@tonic-gate (void) ndi_devi_free(child); 29257c478bd9Sstevel@tonic-gate return (NDI_FAILURE); 29267c478bd9Sstevel@tonic-gate } 29277c478bd9Sstevel@tonic-gate 29287c478bd9Sstevel@tonic-gate /* 29297c478bd9Sstevel@tonic-gate * create the "pm-want-child-notification?" property 29307c478bd9Sstevel@tonic-gate */ 29317c478bd9Sstevel@tonic-gate (void) pshot_nexus_properties(parent, child, cname, caddr); 29327c478bd9Sstevel@tonic-gate 29337c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 29347c478bd9Sstevel@tonic-gate } 29357c478bd9Sstevel@tonic-gate 29367c478bd9Sstevel@tonic-gate /* 29377c478bd9Sstevel@tonic-gate * BUS_CONFIG_ONE: setup a child leaf device instance. 29387c478bd9Sstevel@tonic-gate * for testing purposes, we will create nodes of a variety of types. 29397c478bd9Sstevel@tonic-gate */ 29407c478bd9Sstevel@tonic-gate static int 29417c478bd9Sstevel@tonic-gate pshot_bus_config_setup_leaf(dev_info_t *parent, char *cname, char *caddr) 29427c478bd9Sstevel@tonic-gate { 29437c478bd9Sstevel@tonic-gate dev_info_t *child; 29447c478bd9Sstevel@tonic-gate char *compat_name; 29457c478bd9Sstevel@tonic-gate char *nodetype; 29467c478bd9Sstevel@tonic-gate int rval; 29477c478bd9Sstevel@tonic-gate int i; 29487c478bd9Sstevel@tonic-gate 29497c478bd9Sstevel@tonic-gate ASSERT(parent != 0); 29507c478bd9Sstevel@tonic-gate ASSERT(cname != NULL); 29517c478bd9Sstevel@tonic-gate ASSERT(caddr != NULL); 29527c478bd9Sstevel@tonic-gate 29537c478bd9Sstevel@tonic-gate /* 29547c478bd9Sstevel@tonic-gate * if we already have a node with this name, return it 29557c478bd9Sstevel@tonic-gate */ 29567c478bd9Sstevel@tonic-gate if ((child = pshot_findchild(parent, cname, caddr)) != NULL) { 29577c478bd9Sstevel@tonic-gate /* 29587c478bd9Sstevel@tonic-gate * create the "no-involuntary-power-cycles" or 29597c478bd9Sstevel@tonic-gate * the "dependency-property" property, if they 29607c478bd9Sstevel@tonic-gate * don't already exit 29617c478bd9Sstevel@tonic-gate */ 29627c478bd9Sstevel@tonic-gate (void) pshot_leaf_properties(parent, child, cname, caddr); 29637c478bd9Sstevel@tonic-gate 29647c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 29657c478bd9Sstevel@tonic-gate } 29667c478bd9Sstevel@tonic-gate 29677c478bd9Sstevel@tonic-gate ndi_devi_alloc_sleep(parent, cname, DEVI_SID_NODEID, &child); 29687c478bd9Sstevel@tonic-gate ASSERT(child != NULL); 29697c478bd9Sstevel@tonic-gate 29707c478bd9Sstevel@tonic-gate if (ndi_prop_update_string(DDI_DEV_T_NONE, child, "bus-addr", 29717c478bd9Sstevel@tonic-gate caddr) != DDI_PROP_SUCCESS) { 29727c478bd9Sstevel@tonic-gate (void) ndi_devi_free(child); 29737c478bd9Sstevel@tonic-gate return (NDI_FAILURE); 29747c478bd9Sstevel@tonic-gate } 29757c478bd9Sstevel@tonic-gate 29767c478bd9Sstevel@tonic-gate /* 29777c478bd9Sstevel@tonic-gate * test compatible naming 29787c478bd9Sstevel@tonic-gate * if the child nodename is "cdisk", attach the list of compatible 29797c478bd9Sstevel@tonic-gate * named disks 29807c478bd9Sstevel@tonic-gate */ 29817c478bd9Sstevel@tonic-gate if (strcmp(cname, pshot_compat_diskname) == 0) { 29827c478bd9Sstevel@tonic-gate if ((ndi_prop_update_string_array(DDI_DEV_T_NONE, 29837c478bd9Sstevel@tonic-gate child, "compatible", (char **)pshot_compat_psramdisks, 29847c478bd9Sstevel@tonic-gate 5)) != DDI_PROP_SUCCESS) { 29857c478bd9Sstevel@tonic-gate (void) ndi_devi_free(child); 29867c478bd9Sstevel@tonic-gate return (NDI_FAILURE); 29877c478bd9Sstevel@tonic-gate } 29887c478bd9Sstevel@tonic-gate } else { 29897c478bd9Sstevel@tonic-gate for (i = 0; i < pshot_devices_len && pshot_devices[i].name; 29907c478bd9Sstevel@tonic-gate i++) { 29917c478bd9Sstevel@tonic-gate if (strcmp(cname, pshot_devices[i].name) == 0) { 29927c478bd9Sstevel@tonic-gate compat_name = pshot_devices[i].compat; 29937c478bd9Sstevel@tonic-gate nodetype = pshot_devices[i].nodetype; 29947c478bd9Sstevel@tonic-gate if (pshot_debug) { 29957c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: %s %s %s\n", 29967c478bd9Sstevel@tonic-gate ddi_get_instance(parent), cname, 29977c478bd9Sstevel@tonic-gate compat_name, nodetype); 29987c478bd9Sstevel@tonic-gate } 29997c478bd9Sstevel@tonic-gate if ((ndi_prop_update_string_array( 30007c478bd9Sstevel@tonic-gate DDI_DEV_T_NONE, child, "compatible", 30017c478bd9Sstevel@tonic-gate &compat_name, 1)) != DDI_PROP_SUCCESS) { 30027c478bd9Sstevel@tonic-gate (void) ndi_devi_free(child); 30037c478bd9Sstevel@tonic-gate return (NDI_FAILURE); 30047c478bd9Sstevel@tonic-gate } 30057c478bd9Sstevel@tonic-gate if ((ndi_prop_update_string( 30067c478bd9Sstevel@tonic-gate DDI_DEV_T_NONE, child, "node-type", 30077c478bd9Sstevel@tonic-gate nodetype)) != DDI_PROP_SUCCESS) { 30087c478bd9Sstevel@tonic-gate (void) ndi_devi_free(child); 30097c478bd9Sstevel@tonic-gate return (NDI_FAILURE); 30107c478bd9Sstevel@tonic-gate } 30117c478bd9Sstevel@tonic-gate } 30127c478bd9Sstevel@tonic-gate } 30137c478bd9Sstevel@tonic-gate } 30147c478bd9Sstevel@tonic-gate 30157c478bd9Sstevel@tonic-gate rval = ndi_devi_bind_driver(child, 0); 30167c478bd9Sstevel@tonic-gate if (rval != NDI_SUCCESS) { 30177c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot%d: bind_driver %s failed", 30187c478bd9Sstevel@tonic-gate ddi_get_instance(parent), cname); 30197c478bd9Sstevel@tonic-gate (void) ndi_devi_free(child); 30207c478bd9Sstevel@tonic-gate return (NDI_FAILURE); 30217c478bd9Sstevel@tonic-gate } 30227c478bd9Sstevel@tonic-gate 30237c478bd9Sstevel@tonic-gate /* 30247c478bd9Sstevel@tonic-gate * create the "no-involuntary-power-cycles" or 30257c478bd9Sstevel@tonic-gate * the "dependency-property" property 30267c478bd9Sstevel@tonic-gate */ 30277c478bd9Sstevel@tonic-gate (void) pshot_leaf_properties(parent, child, cname, caddr); 30287c478bd9Sstevel@tonic-gate 30297c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 30307c478bd9Sstevel@tonic-gate } 30317c478bd9Sstevel@tonic-gate 30327c478bd9Sstevel@tonic-gate /* 30337c478bd9Sstevel@tonic-gate * Handle some special cases for testing bus_config via pshot 30347c478bd9Sstevel@tonic-gate * 30357c478bd9Sstevel@tonic-gate * Match these special address formats to behavior: 30367c478bd9Sstevel@tonic-gate * 30377c478bd9Sstevel@tonic-gate * err.* - induce bus_config error 30387c478bd9Sstevel@tonic-gate * delay - induce 1 second of bus_config delay time 30397c478bd9Sstevel@tonic-gate * delay,n - induce n seconds of bus_config delay time 30407c478bd9Sstevel@tonic-gate * wait - induce 1 second of bus_config wait time 30417c478bd9Sstevel@tonic-gate * wait,n - induce n seconds of bus_config wait time 30427c478bd9Sstevel@tonic-gate * failinit.* - induce error at INITCHILD 30437c478bd9Sstevel@tonic-gate * failprobe.* - induce error at probe 30447c478bd9Sstevel@tonic-gate * failattach.* - induce error at attach 30457c478bd9Sstevel@tonic-gate */ 30467c478bd9Sstevel@tonic-gate /*ARGSUSED*/ 30477c478bd9Sstevel@tonic-gate static int 30487c478bd9Sstevel@tonic-gate pshot_bus_config_test_specials(dev_info_t *parent, char *devname, 30497c478bd9Sstevel@tonic-gate char *cname, char *caddr) 30507c478bd9Sstevel@tonic-gate { 30517c478bd9Sstevel@tonic-gate char *p; 30527c478bd9Sstevel@tonic-gate int n; 30537c478bd9Sstevel@tonic-gate 30547c478bd9Sstevel@tonic-gate if (strncmp(caddr, "err", 3) == 0) { 30557c478bd9Sstevel@tonic-gate if (pshot_debug) 30567c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 30577c478bd9Sstevel@tonic-gate "pshot%d: %s forced failure\n", 30587c478bd9Sstevel@tonic-gate ddi_get_instance(parent), devname); 30597c478bd9Sstevel@tonic-gate return (NDI_FAILURE); 30607c478bd9Sstevel@tonic-gate } 30617c478bd9Sstevel@tonic-gate 30627c478bd9Sstevel@tonic-gate /* 30637c478bd9Sstevel@tonic-gate * The delay and wait strings have the same effect. 30647c478bd9Sstevel@tonic-gate * The "wait[,]" support should be removed once the 30657c478bd9Sstevel@tonic-gate * devfs test suites are fixed. 30667c478bd9Sstevel@tonic-gate * NOTE: delay should not be called from interrupt context 30677c478bd9Sstevel@tonic-gate */ 30687c478bd9Sstevel@tonic-gate ASSERT(!servicing_interrupt()); 30697c478bd9Sstevel@tonic-gate 30707c478bd9Sstevel@tonic-gate if (strncmp(caddr, "delay,", 6) == 0) { 30717c478bd9Sstevel@tonic-gate p = caddr+6; 30727c478bd9Sstevel@tonic-gate n = stoi(&p); 30737c478bd9Sstevel@tonic-gate if (*p != 0) 30747c478bd9Sstevel@tonic-gate n = 1; 30757c478bd9Sstevel@tonic-gate if (pshot_debug) 30767c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 30777c478bd9Sstevel@tonic-gate "pshot%d: %s delay %d second\n", 30787c478bd9Sstevel@tonic-gate ddi_get_instance(parent), devname, n); 30797c478bd9Sstevel@tonic-gate delay(n * drv_usectohz(1000000)); 30807c478bd9Sstevel@tonic-gate } else if (strncmp(caddr, "delay", 5) == 0) { 30817c478bd9Sstevel@tonic-gate if (pshot_debug) 30827c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 30837c478bd9Sstevel@tonic-gate "pshot%d: %s delay 1 second\n", 30847c478bd9Sstevel@tonic-gate ddi_get_instance(parent), devname); 30857c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 30867c478bd9Sstevel@tonic-gate } else if (strncmp(caddr, "wait,", 5) == 0) { 30877c478bd9Sstevel@tonic-gate p = caddr+5; 30887c478bd9Sstevel@tonic-gate n = stoi(&p); 30897c478bd9Sstevel@tonic-gate if (*p != 0) 30907c478bd9Sstevel@tonic-gate n = 1; 30917c478bd9Sstevel@tonic-gate if (pshot_debug) 30927c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 30937c478bd9Sstevel@tonic-gate "pshot%d: %s wait %d second\n", 30947c478bd9Sstevel@tonic-gate ddi_get_instance(parent), devname, n); 30957c478bd9Sstevel@tonic-gate delay(n * drv_usectohz(1000000)); 30967c478bd9Sstevel@tonic-gate } else if (strncmp(caddr, "wait", 4) == 0) { 30977c478bd9Sstevel@tonic-gate if (pshot_debug) 30987c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, 30997c478bd9Sstevel@tonic-gate "pshot%d: %s wait 1 second\n", 31007c478bd9Sstevel@tonic-gate ddi_get_instance(parent), devname); 31017c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 31027c478bd9Sstevel@tonic-gate } 31037c478bd9Sstevel@tonic-gate 31047c478bd9Sstevel@tonic-gate return (NDI_SUCCESS); 31057c478bd9Sstevel@tonic-gate } 31067c478bd9Sstevel@tonic-gate 31077c478bd9Sstevel@tonic-gate /* 31087c478bd9Sstevel@tonic-gate * translate nodetype name to actual value 31097c478bd9Sstevel@tonic-gate */ 31107c478bd9Sstevel@tonic-gate static char * 31117c478bd9Sstevel@tonic-gate pshot_str2nt(char *str) 31127c478bd9Sstevel@tonic-gate { 31137c478bd9Sstevel@tonic-gate int i; 31147c478bd9Sstevel@tonic-gate 31157c478bd9Sstevel@tonic-gate for (i = 0; pshot_nodetypes[i].name; i++) { 31167c478bd9Sstevel@tonic-gate if (strcmp(pshot_nodetypes[i].name, str) == 0) 31177c478bd9Sstevel@tonic-gate return (pshot_nodetypes[i].val); 31187c478bd9Sstevel@tonic-gate } 31197c478bd9Sstevel@tonic-gate return (NULL); 31207c478bd9Sstevel@tonic-gate } 31217c478bd9Sstevel@tonic-gate 31227c478bd9Sstevel@tonic-gate /* 31237c478bd9Sstevel@tonic-gate * grows array pointed to by <dstp>, with <src> data 31247c478bd9Sstevel@tonic-gate * <dstlen> = # elements of the original <*dstp> 31257c478bd9Sstevel@tonic-gate * <srclen> = # elements of <src> 31267c478bd9Sstevel@tonic-gate * 31277c478bd9Sstevel@tonic-gate * on success, returns 0 and a pointer to the new array through <dstp> with 31287c478bd9Sstevel@tonic-gate * <srclen> + <dstlen> number of elements; 31297c478bd9Sstevel@tonic-gate * else returns non-zero 31307c478bd9Sstevel@tonic-gate * 31317c478bd9Sstevel@tonic-gate * a NULL <*dstp> is OK (a NULL <dstp> is not) and so is a zero <dstlen> 31327c478bd9Sstevel@tonic-gate */ 31337c478bd9Sstevel@tonic-gate static int 31347c478bd9Sstevel@tonic-gate pshot_devices_grow(pshot_device_t **dstp, size_t dstlen, 31357c478bd9Sstevel@tonic-gate const pshot_device_t *src, size_t srclen) 31367c478bd9Sstevel@tonic-gate { 31377c478bd9Sstevel@tonic-gate size_t i; 31387c478bd9Sstevel@tonic-gate pshot_device_t *newdst; 31397c478bd9Sstevel@tonic-gate 31407c478bd9Sstevel@tonic-gate newdst = kmem_alloc((srclen + dstlen) * sizeof (*src), 31417c478bd9Sstevel@tonic-gate KM_SLEEP); 31427c478bd9Sstevel@tonic-gate 31437c478bd9Sstevel@tonic-gate /* keep old pointers and dup new ones */ 31447c478bd9Sstevel@tonic-gate if (*dstp) 31457c478bd9Sstevel@tonic-gate bcopy(*dstp, newdst, dstlen * sizeof (*src)); 31467c478bd9Sstevel@tonic-gate for (i = 0; i < srclen; i++) { 31477c478bd9Sstevel@tonic-gate newdst[i + dstlen].name = 31487c478bd9Sstevel@tonic-gate i_ddi_strdup(src[i].name, KM_SLEEP); 31497c478bd9Sstevel@tonic-gate 31507c478bd9Sstevel@tonic-gate newdst[i + dstlen].nodetype = 31517c478bd9Sstevel@tonic-gate i_ddi_strdup(src[i].nodetype, KM_SLEEP); 31527c478bd9Sstevel@tonic-gate 31537c478bd9Sstevel@tonic-gate newdst[i + dstlen].compat = 31547c478bd9Sstevel@tonic-gate i_ddi_strdup(src[i].compat, KM_SLEEP); 31557c478bd9Sstevel@tonic-gate } 31567c478bd9Sstevel@tonic-gate 31577c478bd9Sstevel@tonic-gate /* do last */ 31587c478bd9Sstevel@tonic-gate if (*dstp) 31597c478bd9Sstevel@tonic-gate kmem_free(*dstp, dstlen * sizeof (*src)); 31607c478bd9Sstevel@tonic-gate *dstp = newdst; 31617c478bd9Sstevel@tonic-gate return (0); 31627c478bd9Sstevel@tonic-gate } 31637c478bd9Sstevel@tonic-gate 31647c478bd9Sstevel@tonic-gate /* 31657c478bd9Sstevel@tonic-gate * free a pshot_device_t array <dp> with <len> elements 31667c478bd9Sstevel@tonic-gate * null pointers within the elements are ok 31677c478bd9Sstevel@tonic-gate */ 31687c478bd9Sstevel@tonic-gate static void 31697c478bd9Sstevel@tonic-gate pshot_devices_free(pshot_device_t *dp, size_t len) 31707c478bd9Sstevel@tonic-gate { 31717c478bd9Sstevel@tonic-gate size_t i; 31727c478bd9Sstevel@tonic-gate 31737c478bd9Sstevel@tonic-gate for (i = 0; i < len; i++) { 31747c478bd9Sstevel@tonic-gate if (dp[i].name) 31757c478bd9Sstevel@tonic-gate kmem_free(dp[i].name, strlen(dp[i].name) + 1); 31767c478bd9Sstevel@tonic-gate if (dp[i].nodetype) 31777c478bd9Sstevel@tonic-gate kmem_free(dp[i].nodetype, strlen(dp[i].nodetype) + 1); 31787c478bd9Sstevel@tonic-gate if (dp[i].compat) 31797c478bd9Sstevel@tonic-gate kmem_free(dp[i].compat, strlen(dp[i].compat) + 1); 31807c478bd9Sstevel@tonic-gate } 31817c478bd9Sstevel@tonic-gate kmem_free(dp, len * sizeof (*dp)); 31827c478bd9Sstevel@tonic-gate } 31837c478bd9Sstevel@tonic-gate 31847c478bd9Sstevel@tonic-gate /* 31857c478bd9Sstevel@tonic-gate * returns an array of pshot_device_t parsed from <dip>'s properties 31867c478bd9Sstevel@tonic-gate * 31877c478bd9Sstevel@tonic-gate * property structure (i.e. pshot.conf) for pshot: 31887c478bd9Sstevel@tonic-gate * 31897c478bd9Sstevel@tonic-gate * corresponding | pshot_device_t array elements 31907c478bd9Sstevel@tonic-gate * pshot_device_t | 31917c478bd9Sstevel@tonic-gate * member by prop name | [0] [1] [2] 31927c478bd9Sstevel@tonic-gate * ----------------------|--------------|-------------|----------------------- 31937c478bd9Sstevel@tonic-gate * <PSHOT_PROP_DEVNAME> ="disk", "tape", "testdev"; 31947c478bd9Sstevel@tonic-gate * <PSHOT_PROP_DEVNT> ="DDI_NT_BLOCK","DDI_NT_TAPE","ddi_testdev_nodetype"; 31957c478bd9Sstevel@tonic-gate * <PSHOT_PROP_DEVCOMPAT>="testdrv", "testdrv", "testdrv"; 31967c478bd9Sstevel@tonic-gate * 31977c478bd9Sstevel@tonic-gate * 31987c478bd9Sstevel@tonic-gate * if any of these properties are specified, then: 31997c478bd9Sstevel@tonic-gate * - all the members must be specified 32007c478bd9Sstevel@tonic-gate * - the number of elements for each string array property must be the same 32017c478bd9Sstevel@tonic-gate * - no empty strings allowed 32027c478bd9Sstevel@tonic-gate * - nodetypes (PSHOT_PROP_DEVNT) must be the nodetype name as specified in 32037c478bd9Sstevel@tonic-gate * sys/sunddi.h 32047c478bd9Sstevel@tonic-gate * 32057c478bd9Sstevel@tonic-gate * NOTE: the pshot_nodetypes[] table should be kept in sync with the list 32067c478bd9Sstevel@tonic-gate * of ddi nodetypes. It's not normally critical to always be in sync so 32077c478bd9Sstevel@tonic-gate * keeping this up-to-date can usually be done "on-demand". 32087c478bd9Sstevel@tonic-gate * 32097c478bd9Sstevel@tonic-gate * if <flags> & PSHOT_DEV_ANYNT, then custom nodetype strings are allowed. 32107c478bd9Sstevel@tonic-gate * these will be duplicated verbatim 32117c478bd9Sstevel@tonic-gate */ 32127c478bd9Sstevel@tonic-gate static pshot_device_t * 32137c478bd9Sstevel@tonic-gate pshot_devices_from_props(dev_info_t *dip, size_t *lenp, int flags) 32147c478bd9Sstevel@tonic-gate { 32157c478bd9Sstevel@tonic-gate pshot_device_t *devarr = NULL; 32167c478bd9Sstevel@tonic-gate char **name_arr = NULL, **nt_arr = NULL, **compat_arr = NULL; 32177c478bd9Sstevel@tonic-gate uint_t name_arr_len, nt_arr_len, compat_arr_len; 32187c478bd9Sstevel@tonic-gate uint_t i; 32197c478bd9Sstevel@tonic-gate char *str; 32207c478bd9Sstevel@tonic-gate 32217c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0, 32227c478bd9Sstevel@tonic-gate PSHOT_PROP_DEVNAME, &name_arr, &name_arr_len) != 32237c478bd9Sstevel@tonic-gate DDI_PROP_SUCCESS) 32247c478bd9Sstevel@tonic-gate name_arr = NULL; 32257c478bd9Sstevel@tonic-gate 32267c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0, 32277c478bd9Sstevel@tonic-gate PSHOT_PROP_DEVNT, &nt_arr, &nt_arr_len) != 32287c478bd9Sstevel@tonic-gate DDI_PROP_SUCCESS) 32297c478bd9Sstevel@tonic-gate nt_arr = NULL; 32307c478bd9Sstevel@tonic-gate 32317c478bd9Sstevel@tonic-gate if (ddi_prop_lookup_string_array(DDI_DEV_T_ANY, dip, 0, 32327c478bd9Sstevel@tonic-gate PSHOT_PROP_DEVCOMPAT, &compat_arr, &compat_arr_len) != 32337c478bd9Sstevel@tonic-gate DDI_PROP_SUCCESS) 32347c478bd9Sstevel@tonic-gate compat_arr = NULL; 32357c478bd9Sstevel@tonic-gate 32367c478bd9Sstevel@tonic-gate /* 32377c478bd9Sstevel@tonic-gate * warn about any incorrect usage, if specified 32387c478bd9Sstevel@tonic-gate */ 32397c478bd9Sstevel@tonic-gate if (!(name_arr || nt_arr || compat_arr)) 32407c478bd9Sstevel@tonic-gate return (NULL); 32417c478bd9Sstevel@tonic-gate 32427c478bd9Sstevel@tonic-gate if (!(name_arr && nt_arr && compat_arr) || 32437c478bd9Sstevel@tonic-gate (name_arr_len != nt_arr_len) || 32447c478bd9Sstevel@tonic-gate (name_arr_len != compat_arr_len)) 32457c478bd9Sstevel@tonic-gate goto FAIL; 32467c478bd9Sstevel@tonic-gate 32477c478bd9Sstevel@tonic-gate for (i = 0; i < name_arr_len; i++) { 32487c478bd9Sstevel@tonic-gate if (*name_arr[i] == '\0' || 32497c478bd9Sstevel@tonic-gate *nt_arr[i] == '\0' || 32507c478bd9Sstevel@tonic-gate *compat_arr[i] == '\0') 32517c478bd9Sstevel@tonic-gate goto FAIL; 32527c478bd9Sstevel@tonic-gate } 32537c478bd9Sstevel@tonic-gate 32547c478bd9Sstevel@tonic-gate devarr = kmem_zalloc(name_arr_len * sizeof (*devarr), KM_SLEEP); 32557c478bd9Sstevel@tonic-gate for (i = 0; i < name_arr_len; i++) { 32567c478bd9Sstevel@tonic-gate devarr[i].name = i_ddi_strdup(name_arr[i], KM_SLEEP); 32577c478bd9Sstevel@tonic-gate devarr[i].compat = i_ddi_strdup(compat_arr[i], KM_SLEEP); 32587c478bd9Sstevel@tonic-gate 32597c478bd9Sstevel@tonic-gate if ((str = pshot_str2nt(nt_arr[i])) == NULL) 32607c478bd9Sstevel@tonic-gate if (flags & PSHOT_DEV_ANYNT) 32617c478bd9Sstevel@tonic-gate str = nt_arr[i]; 32627c478bd9Sstevel@tonic-gate else 32637c478bd9Sstevel@tonic-gate goto FAIL; 32647c478bd9Sstevel@tonic-gate devarr[i].nodetype = i_ddi_strdup(str, KM_SLEEP); 32657c478bd9Sstevel@tonic-gate } 32667c478bd9Sstevel@tonic-gate ddi_prop_free(name_arr); 32677c478bd9Sstevel@tonic-gate ddi_prop_free(nt_arr); 32687c478bd9Sstevel@tonic-gate ddi_prop_free(compat_arr); 32697c478bd9Sstevel@tonic-gate 32707c478bd9Sstevel@tonic-gate /* set <*lenp> ONLY on success */ 32717c478bd9Sstevel@tonic-gate *lenp = name_arr_len; 32727c478bd9Sstevel@tonic-gate 32737c478bd9Sstevel@tonic-gate return (devarr); 32747c478bd9Sstevel@tonic-gate /*NOTREACHED*/ 32757c478bd9Sstevel@tonic-gate FAIL: 32767c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "malformed device specification property"); 32777c478bd9Sstevel@tonic-gate if (name_arr) 32787c478bd9Sstevel@tonic-gate ddi_prop_free(name_arr); 32797c478bd9Sstevel@tonic-gate if (nt_arr) 32807c478bd9Sstevel@tonic-gate ddi_prop_free(nt_arr); 32817c478bd9Sstevel@tonic-gate if (compat_arr) 32827c478bd9Sstevel@tonic-gate ddi_prop_free(compat_arr); 32837c478bd9Sstevel@tonic-gate if (devarr) 32847c478bd9Sstevel@tonic-gate pshot_devices_free(devarr, name_arr_len); 32857c478bd9Sstevel@tonic-gate return (NULL); 32867c478bd9Sstevel@tonic-gate } 32877c478bd9Sstevel@tonic-gate 32887c478bd9Sstevel@tonic-gate /* 32897c478bd9Sstevel@tonic-gate * if global <pshot_devices> was not set up already (i.e. is NULL): 32907c478bd9Sstevel@tonic-gate * sets up global <pshot_devices> and <pshot_devices_len>, 32917c478bd9Sstevel@tonic-gate * using device properties from <dip> and global <pshot_stock_devices>. 32927c478bd9Sstevel@tonic-gate * device properties, if any, overrides pshot_stock_devices. 32937c478bd9Sstevel@tonic-gate * 32947c478bd9Sstevel@tonic-gate * returns 0 on success (or if pshot_devices already set up) 32957c478bd9Sstevel@tonic-gate * 32967c478bd9Sstevel@tonic-gate * INTERNAL LOCKING: <pshot_devices_lock> 32977c478bd9Sstevel@tonic-gate */ 32987c478bd9Sstevel@tonic-gate static int 32997c478bd9Sstevel@tonic-gate pshot_devices_setup(dev_info_t *dip) 33007c478bd9Sstevel@tonic-gate { 33017c478bd9Sstevel@tonic-gate pshot_device_t *newdevs = NULL; 33027c478bd9Sstevel@tonic-gate size_t newdevs_len = 0; 33037c478bd9Sstevel@tonic-gate int rv = 0; 33047c478bd9Sstevel@tonic-gate 33057c478bd9Sstevel@tonic-gate mutex_enter(&pshot_devices_lock); 33067c478bd9Sstevel@tonic-gate if (pshot_devices != NULL) 33077c478bd9Sstevel@tonic-gate goto FAIL; 33087c478bd9Sstevel@tonic-gate 33097c478bd9Sstevel@tonic-gate ASSERT(pshot_devices_len == 0); 33107c478bd9Sstevel@tonic-gate 33117c478bd9Sstevel@tonic-gate newdevs = pshot_devices_from_props(dip, &newdevs_len, PSHOT_DEV_ANYNT); 33127c478bd9Sstevel@tonic-gate rv = pshot_devices_grow(&newdevs, newdevs_len, pshot_stock_devices, 33137c478bd9Sstevel@tonic-gate PSHOT_N_STOCK_DEVICES); 33147c478bd9Sstevel@tonic-gate if (rv != 0) { 33157c478bd9Sstevel@tonic-gate cmn_err(CE_WARN, "pshot_devices_setup: pshot_devices_grow " 33167c478bd9Sstevel@tonic-gate "failed"); 33177c478bd9Sstevel@tonic-gate goto FAIL; 33187c478bd9Sstevel@tonic-gate } 33197c478bd9Sstevel@tonic-gate newdevs_len += PSHOT_N_STOCK_DEVICES; 33207c478bd9Sstevel@tonic-gate 33217c478bd9Sstevel@tonic-gate pshot_devices = newdevs; 33227c478bd9Sstevel@tonic-gate pshot_devices_len = newdevs_len; 33237c478bd9Sstevel@tonic-gate rv = 0; 33247c478bd9Sstevel@tonic-gate FAIL: 33257c478bd9Sstevel@tonic-gate if (rv && newdevs) 33267c478bd9Sstevel@tonic-gate pshot_devices_free(newdevs, newdevs_len); 33277c478bd9Sstevel@tonic-gate mutex_exit(&pshot_devices_lock); 33287c478bd9Sstevel@tonic-gate return (rv); 33297c478bd9Sstevel@tonic-gate } 33307c478bd9Sstevel@tonic-gate 33317c478bd9Sstevel@tonic-gate 33327c478bd9Sstevel@tonic-gate #ifdef NOTNEEDED 33337c478bd9Sstevel@tonic-gate /* ARGSUSED */ 33347c478bd9Sstevel@tonic-gate static int 33357c478bd9Sstevel@tonic-gate pshot_probe_family(dev_info_t *self, ddi_probe_method_t probe_how, 33367c478bd9Sstevel@tonic-gate dev_info_t **return_dip) 33377c478bd9Sstevel@tonic-gate { 33387c478bd9Sstevel@tonic-gate char name[64]; 33397c478bd9Sstevel@tonic-gate uint_t bus_id; 33407c478bd9Sstevel@tonic-gate dev_info_t *child; 33417c478bd9Sstevel@tonic-gate 33427c478bd9Sstevel@tonic-gate for (bus_id = 10; bus_id < 20; bus_id++) { 33437c478bd9Sstevel@tonic-gate (void) sprintf(name, "%d", bus_id); 33447c478bd9Sstevel@tonic-gate if ((ndi_devi_alloc(self, "psramd", DEVI_SID_NODEID, 33457c478bd9Sstevel@tonic-gate &child)) != NDI_SUCCESS) { 33467c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 33477c478bd9Sstevel@tonic-gate } 33487c478bd9Sstevel@tonic-gate 33497c478bd9Sstevel@tonic-gate if (ndi_prop_update_string(DDI_DEV_T_NONE, child, 33507c478bd9Sstevel@tonic-gate "bus-addr", name) != DDI_PROP_SUCCESS) { 33517c478bd9Sstevel@tonic-gate (void) ndi_devi_free(child); 33527c478bd9Sstevel@tonic-gate if (return_dip != NULL) 33537c478bd9Sstevel@tonic-gate *return_dip = (dev_info_t *)NULL; 33547c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 33557c478bd9Sstevel@tonic-gate } 33567c478bd9Sstevel@tonic-gate 33577c478bd9Sstevel@tonic-gate if (ndi_devi_online(child, 0) != NDI_SUCCESS) { 33587c478bd9Sstevel@tonic-gate return (DDI_FAILURE); 33597c478bd9Sstevel@tonic-gate } 33607c478bd9Sstevel@tonic-gate } 33617c478bd9Sstevel@tonic-gate return (DDI_SUCCESS); 33627c478bd9Sstevel@tonic-gate } 33637c478bd9Sstevel@tonic-gate 33647c478bd9Sstevel@tonic-gate static int 33657c478bd9Sstevel@tonic-gate strtoi(char *str) 33667c478bd9Sstevel@tonic-gate { 33677c478bd9Sstevel@tonic-gate int c; 33687c478bd9Sstevel@tonic-gate int val; 33697c478bd9Sstevel@tonic-gate 33707c478bd9Sstevel@tonic-gate for (val = 0, c = *str++; c >= '0' && c <= '9'; c = *str++) { 33717c478bd9Sstevel@tonic-gate val *= 10; 33727c478bd9Sstevel@tonic-gate val += c - '0'; 33737c478bd9Sstevel@tonic-gate } 33747c478bd9Sstevel@tonic-gate return (val); 33757c478bd9Sstevel@tonic-gate } 33767c478bd9Sstevel@tonic-gate 33777c478bd9Sstevel@tonic-gate struct m_to_reg { 33787c478bd9Sstevel@tonic-gate char *mc; 33797c478bd9Sstevel@tonic-gate int n_regs; 33807c478bd9Sstevel@tonic-gate int regs[3]; 33817c478bd9Sstevel@tonic-gate }; 33827c478bd9Sstevel@tonic-gate 33837c478bd9Sstevel@tonic-gate struct m_to_reg m_regspecs[] = { 33847c478bd9Sstevel@tonic-gate {"sun4c", 3, {0xf, 0x6000000, 0x20}}, 33857c478bd9Sstevel@tonic-gate {"sun4d", 3, {0xf, 0x6000000, 0x20}}, 33867c478bd9Sstevel@tonic-gate {"sun4m", 3, {0xf, 0x6000000, 0x20}}, 33877c478bd9Sstevel@tonic-gate {"sun4u", 3, {0xf, 0x6000000, 0x20}}, 33887c478bd9Sstevel@tonic-gate {"i86pc", 3, {0xf, 0x6000000, 0x20}}, 33897c478bd9Sstevel@tonic-gate {NULL, 0, {0, 0, 0}}, 33907c478bd9Sstevel@tonic-gate }; 3391*b1dd958fScth #endif 33927c478bd9Sstevel@tonic-gate 33937c478bd9Sstevel@tonic-gate static void 33947c478bd9Sstevel@tonic-gate pshot_setup_autoattach(dev_info_t *devi) 33957c478bd9Sstevel@tonic-gate { 33967c478bd9Sstevel@tonic-gate dev_info_t *l1child, *l2child; 33977c478bd9Sstevel@tonic-gate int rv; 33987c478bd9Sstevel@tonic-gate 33997c478bd9Sstevel@tonic-gate rv = ndi_devi_alloc(devi, "pshot", DEVI_SID_NODEID, &l1child); 34007c478bd9Sstevel@tonic-gate if (rv == NDI_SUCCESS) { 34017c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child, 34027c478bd9Sstevel@tonic-gate "bus-addr", "0"); 34037c478bd9Sstevel@tonic-gate rv = ndi_devi_alloc(l1child, "port", DEVI_SID_NODEID, 34047c478bd9Sstevel@tonic-gate &l2child); 34057c478bd9Sstevel@tonic-gate if (rv == NDI_SUCCESS) 34067c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, 34077c478bd9Sstevel@tonic-gate l2child, "bus-addr", "99"); 34087c478bd9Sstevel@tonic-gate } 34097c478bd9Sstevel@tonic-gate 34107c478bd9Sstevel@tonic-gate rv = ndi_devi_alloc(devi, "port", DEVI_SID_NODEID, &l1child); 34117c478bd9Sstevel@tonic-gate if (rv == NDI_SUCCESS) 34127c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child, 34137c478bd9Sstevel@tonic-gate "bus-addr", "99"); 34147c478bd9Sstevel@tonic-gate 34157c478bd9Sstevel@tonic-gate rv = ndi_devi_alloc(devi, "gen_drv", DEVI_SID_NODEID, &l1child); 34167c478bd9Sstevel@tonic-gate if (rv == NDI_SUCCESS) 34177c478bd9Sstevel@tonic-gate (void) ndi_prop_update_string(DDI_DEV_T_NONE, l1child, 34187c478bd9Sstevel@tonic-gate "bus-addr", "99"); 34197c478bd9Sstevel@tonic-gate 34207c478bd9Sstevel@tonic-gate rv = ndi_devi_alloc(devi, "no_driver", DEVI_SID_NODEID, &l1child); 34217c478bd9Sstevel@tonic-gate if (rv == NDI_SUCCESS) 34227c478bd9Sstevel@tonic-gate (void) ndi_devi_alloc(l1child, "no_driver", DEVI_SID_NODEID, 34237c478bd9Sstevel@tonic-gate &l2child); 34247c478bd9Sstevel@tonic-gate } 34257c478bd9Sstevel@tonic-gate 34267c478bd9Sstevel@tonic-gate #ifdef PRUNE_SNUBS 34277c478bd9Sstevel@tonic-gate 34287c478bd9Sstevel@tonic-gate #define PRUNE_THIS_NODE(d) (((d)->devi_node_name != NULL) && \ 34297c478bd9Sstevel@tonic-gate (DEVI_PROM_NODE((d)->devi_nodeid)) && \ 34307c478bd9Sstevel@tonic-gate ((d)->devi_addr == NULL)) 34317c478bd9Sstevel@tonic-gate /* 34327c478bd9Sstevel@tonic-gate * test code to remove OBP nodes that have not attached 34337c478bd9Sstevel@tonic-gate */ 34347c478bd9Sstevel@tonic-gate static void 34357c478bd9Sstevel@tonic-gate prune_snubs(const char *name) 34367c478bd9Sstevel@tonic-gate { 34377c478bd9Sstevel@tonic-gate struct dev_info *nex_dip, *cdip, *cndip; 34387c478bd9Sstevel@tonic-gate int maj; 34397c478bd9Sstevel@tonic-gate int rv; 34407c478bd9Sstevel@tonic-gate 34417c478bd9Sstevel@tonic-gate maj = ddi_name_to_major((char *)name); 34427c478bd9Sstevel@tonic-gate if (maj != -1) { 34437c478bd9Sstevel@tonic-gate nex_dip = (struct dev_info *)devnamesp[maj].dn_head; 34447c478bd9Sstevel@tonic-gate while (nex_dip != NULL) { 34457c478bd9Sstevel@tonic-gate cndip = ddi_get_child(nex_dip); 34467c478bd9Sstevel@tonic-gate while ((cdip = cndip) != NULL) { 34477c478bd9Sstevel@tonic-gate cndip = cdip->devi_sibling; 34487c478bd9Sstevel@tonic-gate if (PRUNE_THIS_NODE(cdip)) { 34497c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 34507c478bd9Sstevel@tonic-gate "parent %s@%s pruning node %s", 34517c478bd9Sstevel@tonic-gate nex_dip->devi_node_name, 34527c478bd9Sstevel@tonic-gate nex_dip->devi_addr, 34537c478bd9Sstevel@tonic-gate cdip->devi_node_name); 34547c478bd9Sstevel@tonic-gate rv = ndi_devi_offline(cdip, 34557c478bd9Sstevel@tonic-gate NDI_DEVI_REMOVE); 34567c478bd9Sstevel@tonic-gate if (rv != NDI_SUCCESS) 34577c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, 34587c478bd9Sstevel@tonic-gate "failed to prune node, " 34597c478bd9Sstevel@tonic-gate "err %d", rv); 34607c478bd9Sstevel@tonic-gate } 34617c478bd9Sstevel@tonic-gate } 34627c478bd9Sstevel@tonic-gate nex_dip = nex_dip->devi_next; 34637c478bd9Sstevel@tonic-gate } 34647c478bd9Sstevel@tonic-gate } 34657c478bd9Sstevel@tonic-gate } 34667c478bd9Sstevel@tonic-gate 34677c478bd9Sstevel@tonic-gate #endif /* PRUBE_SNUBS */ 34687c478bd9Sstevel@tonic-gate 34697c478bd9Sstevel@tonic-gate #ifdef KERNEL_DEVICE_TREE_WALKER 34707c478bd9Sstevel@tonic-gate static kthread_id_t pwt; 34717c478bd9Sstevel@tonic-gate static kmutex_t pwl; 34727c478bd9Sstevel@tonic-gate static kcondvar_t pwcv; 34737c478bd9Sstevel@tonic-gate 34747c478bd9Sstevel@tonic-gate static void 34757c478bd9Sstevel@tonic-gate pshot_walk_tree() 34767c478bd9Sstevel@tonic-gate { 34777c478bd9Sstevel@tonic-gate static int pshot_devnode(dev_info_t *dip, void * arg); 34787c478bd9Sstevel@tonic-gate 34797c478bd9Sstevel@tonic-gate dev_info_t *root = ddi_root_node(); 34807c478bd9Sstevel@tonic-gate ddi_walk_devs(root, pshot_devnode, NULL); 34817c478bd9Sstevel@tonic-gate } 34827c478bd9Sstevel@tonic-gate 34837c478bd9Sstevel@tonic-gate static void 34847c478bd9Sstevel@tonic-gate pshot_walk_thread() 34857c478bd9Sstevel@tonic-gate { 34867c478bd9Sstevel@tonic-gate static void pshot_timeout(void *arg); 34877c478bd9Sstevel@tonic-gate static kthread_id_t pwt; 34887c478bd9Sstevel@tonic-gate 34897c478bd9Sstevel@tonic-gate pwt = curthread; 34907c478bd9Sstevel@tonic-gate mutex_init(&pwl, NULL, MUTEX_DRIVER, NULL); 34917c478bd9Sstevel@tonic-gate cv_init(&pwcv, NULL, CV_DRIVER, NULL); 34927c478bd9Sstevel@tonic-gate 34937c478bd9Sstevel@tonic-gate while (1) { 34947c478bd9Sstevel@tonic-gate pshot_walk_tree(); 34957c478bd9Sstevel@tonic-gate mutex_enter(&pwl); 34967c478bd9Sstevel@tonic-gate (void) timeout(pshot_timeout, NULL, 5 * drv_usectohz(1000000)); 34977c478bd9Sstevel@tonic-gate cv_wait(&pwcv, &pwl); 34987c478bd9Sstevel@tonic-gate mutex_exit(&pwl); 34997c478bd9Sstevel@tonic-gate } 35007c478bd9Sstevel@tonic-gate } 35017c478bd9Sstevel@tonic-gate 35027c478bd9Sstevel@tonic-gate static void 35037c478bd9Sstevel@tonic-gate pshot_timeout(void *arg) 35047c478bd9Sstevel@tonic-gate { 35057c478bd9Sstevel@tonic-gate mutex_enter(&pwl); 35067c478bd9Sstevel@tonic-gate cv_signal(&pwcv); 35077c478bd9Sstevel@tonic-gate mutex_exit(&pwl); 35087c478bd9Sstevel@tonic-gate } 35097c478bd9Sstevel@tonic-gate 35107c478bd9Sstevel@tonic-gate static int 35117c478bd9Sstevel@tonic-gate pshot_devnode(dev_info_t *dip, void *arg) 35127c478bd9Sstevel@tonic-gate { 35137c478bd9Sstevel@tonic-gate dev_info_t *f_dip; 35147c478bd9Sstevel@tonic-gate 35157c478bd9Sstevel@tonic-gate if (dip != ddi_root_node()) { 35167c478bd9Sstevel@tonic-gate f_dip = ndi_devi_find((dev_info_t *)DEVI(dip)->devi_parent, 35177c478bd9Sstevel@tonic-gate DEVI(dip)->devi_node_name, DEVI(dip)->devi_addr); 35187c478bd9Sstevel@tonic-gate if (f_dip != dip) { 35197c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "!pshot_devnode: failed lookup" 35207c478bd9Sstevel@tonic-gate "node (%s/%s@%s)\n", 35217c478bd9Sstevel@tonic-gate DEVI(DEVI(dip)->devi_parent)->devi_node_name, 35227c478bd9Sstevel@tonic-gate (DEVI(dip)->devi_node_name ? 35237c478bd9Sstevel@tonic-gate DEVI(dip)->devi_node_name : "NULL"), 35247c478bd9Sstevel@tonic-gate (DEVI(dip)->devi_addr ? DEVI(dip)->devi_addr : "NULL")); 35257c478bd9Sstevel@tonic-gate } 35267c478bd9Sstevel@tonic-gate } 35277c478bd9Sstevel@tonic-gate return (DDI_WALK_CONTINUE); 35287c478bd9Sstevel@tonic-gate } 35297c478bd9Sstevel@tonic-gate #endif /* KERNEL_DEVICE_TREE_WALKER */ 35307c478bd9Sstevel@tonic-gate 35317c478bd9Sstevel@tonic-gate #ifdef DEBUG 35327c478bd9Sstevel@tonic-gate static void 35337c478bd9Sstevel@tonic-gate pshot_event_cb_test(dev_info_t *dip, ddi_eventcookie_t cookie, 35347c478bd9Sstevel@tonic-gate void *arg, void *bus_impldata) 35357c478bd9Sstevel@tonic-gate { 35367c478bd9Sstevel@tonic-gate pshot_t *softstate = (pshot_t *)arg; 35377c478bd9Sstevel@tonic-gate int event_tag; 35387c478bd9Sstevel@tonic-gate 35397c478bd9Sstevel@tonic-gate /* look up the event */ 35407c478bd9Sstevel@tonic-gate event_tag = NDI_EVENT_TAG(cookie); 35417c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot_event_cb_test:\n\t" 35427c478bd9Sstevel@tonic-gate "dip = 0x%p cookie = 0x%p (%s), tag = %d\n\t" 35437c478bd9Sstevel@tonic-gate "arg = 0x%p bus_impl = 0x%p\n", 35447c478bd9Sstevel@tonic-gate (void *)dip, (void *)cookie, NDI_EVENT_NAME(cookie), 35457c478bd9Sstevel@tonic-gate event_tag, (void *)softstate, (void *)bus_impldata); 35467c478bd9Sstevel@tonic-gate 35477c478bd9Sstevel@tonic-gate } 35487c478bd9Sstevel@tonic-gate 35497c478bd9Sstevel@tonic-gate static void 35507c478bd9Sstevel@tonic-gate pshot_event_test(void *arg) 35517c478bd9Sstevel@tonic-gate { 35527c478bd9Sstevel@tonic-gate pshot_t *pshot = (pshot_t *)arg; 35537c478bd9Sstevel@tonic-gate ndi_event_hdl_t hdl; 35547c478bd9Sstevel@tonic-gate ndi_event_set_t events; 35557c478bd9Sstevel@tonic-gate int i, rval; 35567c478bd9Sstevel@tonic-gate 35577c478bd9Sstevel@tonic-gate (void) ndi_event_alloc_hdl(pshot->dip, NULL, &hdl, NDI_SLEEP); 35587c478bd9Sstevel@tonic-gate 35597c478bd9Sstevel@tonic-gate events.ndi_events_version = NDI_EVENTS_REV1; 35607c478bd9Sstevel@tonic-gate events.ndi_n_events = PSHOT_N_TEST_EVENTS; 35617c478bd9Sstevel@tonic-gate events.ndi_event_defs = pshot_test_events; 35627c478bd9Sstevel@tonic-gate 35637c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: binding set of 8 events\n"); 35647c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 35657c478bd9Sstevel@tonic-gate rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP); 35667c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval); 35677c478bd9Sstevel@tonic-gate 35687c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n"); 35697c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 35707c478bd9Sstevel@tonic-gate rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP); 35717c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval); 35727c478bd9Sstevel@tonic-gate 35737c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: unbinding all events\n"); 35747c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 35757c478bd9Sstevel@tonic-gate rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP); 35767c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval); 35777c478bd9Sstevel@tonic-gate 35787c478bd9Sstevel@tonic-gate 35797c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: binding one highlevel event\n"); 35807c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 35817c478bd9Sstevel@tonic-gate events.ndi_n_events = 1; 35827c478bd9Sstevel@tonic-gate events.ndi_event_defs = pshot_test_events_high; 35837c478bd9Sstevel@tonic-gate rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP); 35847c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval); 35857c478bd9Sstevel@tonic-gate 35867c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n"); 35877c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 35887c478bd9Sstevel@tonic-gate events.ndi_n_events = PSHOT_N_TEST_EVENTS; 35897c478bd9Sstevel@tonic-gate events.ndi_event_defs = pshot_test_events; 35907c478bd9Sstevel@tonic-gate rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP); 35917c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval); 35927c478bd9Sstevel@tonic-gate 35937c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n"); 35947c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 35957c478bd9Sstevel@tonic-gate events.ndi_n_events = 1; 35967c478bd9Sstevel@tonic-gate events.ndi_event_defs = pshot_test_events_high; 35977c478bd9Sstevel@tonic-gate rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP); 35987c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval); 35997c478bd9Sstevel@tonic-gate 36007c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: binding one highlevel event\n"); 36017c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36027c478bd9Sstevel@tonic-gate events.ndi_n_events = 1; 36037c478bd9Sstevel@tonic-gate events.ndi_event_defs = pshot_test_events_high; 36047c478bd9Sstevel@tonic-gate rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP); 36057c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval); 36067c478bd9Sstevel@tonic-gate 36077c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: unbinding one highlevel event\n"); 36087c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36097c478bd9Sstevel@tonic-gate events.ndi_n_events = 1; 36107c478bd9Sstevel@tonic-gate events.ndi_event_defs = pshot_test_events_high; 36117c478bd9Sstevel@tonic-gate rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP); 36127c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval); 36137c478bd9Sstevel@tonic-gate 36147c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: binding the same set of 8 events\n"); 36157c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36167c478bd9Sstevel@tonic-gate events.ndi_n_events = PSHOT_N_TEST_EVENTS; 36177c478bd9Sstevel@tonic-gate events.ndi_event_defs = pshot_test_events; 36187c478bd9Sstevel@tonic-gate rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP); 36197c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval); 36207c478bd9Sstevel@tonic-gate 36217c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: unbinding first 2 events\n"); 36227c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36237c478bd9Sstevel@tonic-gate events.ndi_n_events = 2; 36247c478bd9Sstevel@tonic-gate events.ndi_event_defs = pshot_test_events; 36257c478bd9Sstevel@tonic-gate rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP); 36267c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval); 36277c478bd9Sstevel@tonic-gate 36287c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: unbinding first 2 events again\n"); 36297c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36307c478bd9Sstevel@tonic-gate events.ndi_n_events = 2; 36317c478bd9Sstevel@tonic-gate events.ndi_event_defs = pshot_test_events; 36327c478bd9Sstevel@tonic-gate rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP); 36337c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval); 36347c478bd9Sstevel@tonic-gate 36357c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: unbinding middle 2 events\n"); 36367c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36377c478bd9Sstevel@tonic-gate events.ndi_n_events = 2; 36387c478bd9Sstevel@tonic-gate events.ndi_event_defs = &pshot_test_events[4]; 36397c478bd9Sstevel@tonic-gate rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP); 36407c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval); 36417c478bd9Sstevel@tonic-gate 36427c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: binding those 2 events back\n"); 36437c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36447c478bd9Sstevel@tonic-gate events.ndi_n_events = 2; 36457c478bd9Sstevel@tonic-gate events.ndi_event_defs = &pshot_test_events[4]; 36467c478bd9Sstevel@tonic-gate rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP); 36477c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval); 36487c478bd9Sstevel@tonic-gate 36497c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: unbinding 2 events\n"); 36507c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36517c478bd9Sstevel@tonic-gate events.ndi_n_events = 2; 36527c478bd9Sstevel@tonic-gate events.ndi_event_defs = &pshot_test_events[4]; 36537c478bd9Sstevel@tonic-gate rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP); 36547c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval); 36557c478bd9Sstevel@tonic-gate 36567c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: unbinding all events\n"); 36577c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36587c478bd9Sstevel@tonic-gate events.ndi_n_events = PSHOT_N_TEST_EVENTS; 36597c478bd9Sstevel@tonic-gate events.ndi_event_defs = pshot_test_events; 36607c478bd9Sstevel@tonic-gate rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP); 36617c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval); 36627c478bd9Sstevel@tonic-gate 36637c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: unbinding 1 event\n"); 36647c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36657c478bd9Sstevel@tonic-gate events.ndi_n_events = 1; 36667c478bd9Sstevel@tonic-gate events.ndi_event_defs = &pshot_test_events[2]; 36677c478bd9Sstevel@tonic-gate rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP); 36687c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval); 36697c478bd9Sstevel@tonic-gate 36707c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: unbinding 1 event\n"); 36717c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36727c478bd9Sstevel@tonic-gate events.ndi_n_events = 1; 36737c478bd9Sstevel@tonic-gate events.ndi_event_defs = &pshot_test_events[3]; 36747c478bd9Sstevel@tonic-gate rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP); 36757c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval); 36767c478bd9Sstevel@tonic-gate 36777c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: unbinding 1 event\n"); 36787c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36797c478bd9Sstevel@tonic-gate events.ndi_n_events = 1; 36807c478bd9Sstevel@tonic-gate events.ndi_event_defs = &pshot_test_events[6]; 36817c478bd9Sstevel@tonic-gate rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP); 36827c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval); 36837c478bd9Sstevel@tonic-gate 36847c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: unbinding 1 event\n"); 36857c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36867c478bd9Sstevel@tonic-gate events.ndi_n_events = 1; 36877c478bd9Sstevel@tonic-gate events.ndi_event_defs = &pshot_test_events[7]; 36887c478bd9Sstevel@tonic-gate rval = ndi_event_unbind_set(hdl, &events, NDI_SLEEP); 36897c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_unbind_set rval = %d\n", rval); 36907c478bd9Sstevel@tonic-gate 36917c478bd9Sstevel@tonic-gate events.ndi_n_events = PSHOT_N_TEST_EVENTS; 36927c478bd9Sstevel@tonic-gate events.ndi_event_defs = pshot_test_events; 36937c478bd9Sstevel@tonic-gate 36947c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: binding set of 8 events\n"); 36957c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 36967c478bd9Sstevel@tonic-gate rval = ndi_event_bind_set(hdl, &events, NDI_SLEEP); 36977c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: ndi_event_bind_set rval = %d\n", rval); 36987c478bd9Sstevel@tonic-gate 36997c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: adding 8 callbacks\n"); 37007c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 37017c478bd9Sstevel@tonic-gate for (i = 0; i < 8; i++) { 37027c478bd9Sstevel@tonic-gate rval = ndi_event_add_callback(hdl, pshot->dip, 37037c478bd9Sstevel@tonic-gate ndi_event_tag_to_cookie(hdl, 37047c478bd9Sstevel@tonic-gate pshot_test_events[i].ndi_event_tag), 37057c478bd9Sstevel@tonic-gate pshot_event_cb_test, 37067c478bd9Sstevel@tonic-gate (void *)(uintptr_t)pshot_test_events[i].ndi_event_tag, 37077c478bd9Sstevel@tonic-gate NDI_SLEEP, &pshot->test_callback_cache[i]); 37087c478bd9Sstevel@tonic-gate ASSERT(rval == NDI_SUCCESS); 37097c478bd9Sstevel@tonic-gate } 37107c478bd9Sstevel@tonic-gate 37117c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: event callbacks\n"); 37127c478bd9Sstevel@tonic-gate 37137c478bd9Sstevel@tonic-gate for (i = 10; i < 18; i++) { 37147c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i); 37157c478bd9Sstevel@tonic-gate 37167c478bd9Sstevel@tonic-gate rval = ndi_event_run_callbacks(hdl, pshot->dip, cookie, 37177c478bd9Sstevel@tonic-gate (void *)hdl); 37187c478bd9Sstevel@tonic-gate 37197c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n", 37207c478bd9Sstevel@tonic-gate i, rval); 37217c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 37227c478bd9Sstevel@tonic-gate } 37237c478bd9Sstevel@tonic-gate 37247c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: redo event callbacks\n"); 37257c478bd9Sstevel@tonic-gate 37267c478bd9Sstevel@tonic-gate for (i = 10; i < 18; i++) { 37277c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie = ndi_event_tag_to_cookie(hdl, i); 37287c478bd9Sstevel@tonic-gate 37297c478bd9Sstevel@tonic-gate rval = ndi_event_run_callbacks(hdl, 37307c478bd9Sstevel@tonic-gate pshot->dip, cookie, (void *)hdl); 37317c478bd9Sstevel@tonic-gate 37327c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: callback, tag=%d rval=%d\n", 37337c478bd9Sstevel@tonic-gate i, rval); 37347c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 37357c478bd9Sstevel@tonic-gate } 37367c478bd9Sstevel@tonic-gate 37377c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: removing 8 callbacks\n"); 37387c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 37397c478bd9Sstevel@tonic-gate 37407c478bd9Sstevel@tonic-gate for (i = 0; i < 8; i++) { 37417c478bd9Sstevel@tonic-gate (void) ndi_event_remove_callback(hdl, 37427c478bd9Sstevel@tonic-gate pshot->test_callback_cache[i]); 37437c478bd9Sstevel@tonic-gate 37447c478bd9Sstevel@tonic-gate pshot->test_callback_cache[i] = 0; 37457c478bd9Sstevel@tonic-gate } 37467c478bd9Sstevel@tonic-gate 37477c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot: freeing handle with bound set\n"); 37487c478bd9Sstevel@tonic-gate delay(drv_usectohz(1000000)); 37497c478bd9Sstevel@tonic-gate 37507c478bd9Sstevel@tonic-gate rval = ndi_event_free_hdl(hdl); 37517c478bd9Sstevel@tonic-gate 37527c478bd9Sstevel@tonic-gate ASSERT(rval == NDI_SUCCESS); 37537c478bd9Sstevel@tonic-gate 37547c478bd9Sstevel@tonic-gate } 37557c478bd9Sstevel@tonic-gate 37567c478bd9Sstevel@tonic-gate void 37577c478bd9Sstevel@tonic-gate pshot_event_test_post_one(void *arg) 37587c478bd9Sstevel@tonic-gate { 37597c478bd9Sstevel@tonic-gate pshot_t *pshot = (pshot_t *)arg; 37607c478bd9Sstevel@tonic-gate int rval; 37617c478bd9Sstevel@tonic-gate ddi_eventcookie_t cookie; 37627c478bd9Sstevel@tonic-gate 37637c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: pshot_event_post_one event\n", 37647c478bd9Sstevel@tonic-gate pshot->instance); 37657c478bd9Sstevel@tonic-gate 37667c478bd9Sstevel@tonic-gate if (ddi_get_eventcookie(pshot->dip, PSHOT_EVENT_NAME_BUS_TEST_POST, 37677c478bd9Sstevel@tonic-gate &cookie) != DDI_SUCCESS) { 37687c478bd9Sstevel@tonic-gate cmn_err(CE_NOTE, "pshot_bus_test_post cookie not found"); 37697c478bd9Sstevel@tonic-gate return; 37707c478bd9Sstevel@tonic-gate } 37717c478bd9Sstevel@tonic-gate 37727c478bd9Sstevel@tonic-gate rval = ndi_post_event(pshot->dip, pshot->dip, cookie, NULL); 37737c478bd9Sstevel@tonic-gate 37747c478bd9Sstevel@tonic-gate cmn_err(CE_CONT, "pshot%d: pshot_event_post_one rval=%d\n", 37757c478bd9Sstevel@tonic-gate pshot->instance, rval); 37767c478bd9Sstevel@tonic-gate 37777c478bd9Sstevel@tonic-gate (void) timeout(pshot_event_test_post_one, (void *)pshot, 37787c478bd9Sstevel@tonic-gate pshot->instance * drv_usectohz(60000000)); 37797c478bd9Sstevel@tonic-gate 37807c478bd9Sstevel@tonic-gate } 37817c478bd9Sstevel@tonic-gate #endif /* DEBUG */ 3782