xref: /onnv-gate/usr/src/uts/common/io/hotplug/hpcsvc/hpcsvc.c (revision 7862:f8b6a07acfd6)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7862SRichard.Bean@Sun.COM  * Common Development and Distribution License (the "License").
6*7862SRichard.Bean@Sun.COM  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
22*7862SRichard.Bean@Sun.COM  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate  * hot-plug services module
280Sstevel@tonic-gate  */
290Sstevel@tonic-gate 
300Sstevel@tonic-gate #include <sys/modctl.h>
310Sstevel@tonic-gate #include <sys/kmem.h>
320Sstevel@tonic-gate #include <sys/sunddi.h>
330Sstevel@tonic-gate #include <sys/sunndi.h>
340Sstevel@tonic-gate #include <sys/disp.h>
350Sstevel@tonic-gate #include <sys/stat.h>
360Sstevel@tonic-gate #include <sys/hotplug/hpcsvc.h>
370Sstevel@tonic-gate #include <sys/callb.h>
380Sstevel@tonic-gate 
390Sstevel@tonic-gate /*
400Sstevel@tonic-gate  * debug macros:
410Sstevel@tonic-gate  */
420Sstevel@tonic-gate #if defined(DEBUG)
430Sstevel@tonic-gate 
440Sstevel@tonic-gate int hpcsvc_debug = 0;
450Sstevel@tonic-gate 
460Sstevel@tonic-gate static void debug(char *, uintptr_t, uintptr_t, uintptr_t,
470Sstevel@tonic-gate 	uintptr_t, uintptr_t);
480Sstevel@tonic-gate 
490Sstevel@tonic-gate #define	DEBUG0(fmt)	\
500Sstevel@tonic-gate 	debug(fmt, 0, 0, 0, 0, 0);
510Sstevel@tonic-gate #define	DEBUG1(fmt, a1)	\
520Sstevel@tonic-gate 	debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
530Sstevel@tonic-gate #define	DEBUG2(fmt, a1, a2)	\
540Sstevel@tonic-gate 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
550Sstevel@tonic-gate #define	DEBUG3(fmt, a1, a2, a3)	\
560Sstevel@tonic-gate 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), (uintptr_t)(a3), 0, 0);
570Sstevel@tonic-gate #else
580Sstevel@tonic-gate #define	DEBUG0(fmt)
590Sstevel@tonic-gate #define	DEBUG1(fmt, a1)
600Sstevel@tonic-gate #define	DEBUG2(fmt, a1, a2)
610Sstevel@tonic-gate #define	DEBUG3(fmt, a1, a2, a3)
620Sstevel@tonic-gate #endif
630Sstevel@tonic-gate 
640Sstevel@tonic-gate /*
650Sstevel@tonic-gate  * Definitions for the bus node registration list:
660Sstevel@tonic-gate  *
670Sstevel@tonic-gate  * The hot-plug service module maintains a linked list of items
680Sstevel@tonic-gate  * representing the device bus nodes that have been registered via
690Sstevel@tonic-gate  * hpc_nexus_register, or identified as candidates for registration
700Sstevel@tonic-gate  * by the bus argument to hpc_slot_register.
710Sstevel@tonic-gate  *
720Sstevel@tonic-gate  * The head of the linked listed is stored in hpc_bus_list_head. Insertions
730Sstevel@tonic-gate  * and removals from the list should be locked with mutex hpc_bus_mutex.
740Sstevel@tonic-gate  *
750Sstevel@tonic-gate  * Items in the list are allocated/freed with the macros hpc_alloc_bus_entry()
760Sstevel@tonic-gate  * and hpc_free_bus_entry().
770Sstevel@tonic-gate  *
780Sstevel@tonic-gate  * Each item in the list contains the following fields:
790Sstevel@tonic-gate  *
800Sstevel@tonic-gate  *	bus_dip - pointer to devinfo node of the registering bus
810Sstevel@tonic-gate  *
820Sstevel@tonic-gate  *	bus_name - device path name of the bus (ie /pci@1f,4000)
830Sstevel@tonic-gate  *
840Sstevel@tonic-gate  *	bus_callback - bus nexus driver callback function registered
850Sstevel@tonic-gate  *		with the bus
860Sstevel@tonic-gate  *
870Sstevel@tonic-gate  *	bus_registered - a boolean value which is true if the bus has
880Sstevel@tonic-gate  *		been registered with hpc_nexus_register, false otherwise
890Sstevel@tonic-gate  *
900Sstevel@tonic-gate  *	bus_mutex - mutex lock to be held while updating this list entry
910Sstevel@tonic-gate  *
920Sstevel@tonic-gate  *	bus_slot_list - linked list of the slots registered for this
930Sstevel@tonic-gate  *		bus node (see slot list details below)
940Sstevel@tonic-gate  *
950Sstevel@tonic-gate  *	bus_thread - kernel thread for running slot event handlers for
960Sstevel@tonic-gate  *		slots associated with this bus
970Sstevel@tonic-gate  *
980Sstevel@tonic-gate  *	bus_thread_cv - condition variable for synchronization between
990Sstevel@tonic-gate  *		the service routines and the thread for running slot
1000Sstevel@tonic-gate  *		event handlers
1010Sstevel@tonic-gate  *
1020Sstevel@tonic-gate  *	bus_thread_exit - a boolean value used to instruct the thread
1030Sstevel@tonic-gate  *		for invoking the slot event handlers to exit
1040Sstevel@tonic-gate  *
1050Sstevel@tonic-gate  *	bus_slot_event_list_head - the head of the linked list of instances
1060Sstevel@tonic-gate  *		of slot event handlers to be run
1070Sstevel@tonic-gate  *		handlers to be invoked
1080Sstevel@tonic-gate  *
1090Sstevel@tonic-gate  *	bus_next - pointer to next list entry
1100Sstevel@tonic-gate  */
1110Sstevel@tonic-gate 
1120Sstevel@tonic-gate typedef struct hpc_bus_entry hpc_bus_entry_t;
1130Sstevel@tonic-gate typedef struct hpc_slot_entry hpc_slot_entry_t;
1140Sstevel@tonic-gate typedef struct hpc_event_entry hpc_event_entry_t;
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate struct hpc_event_entry {
1170Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
1180Sstevel@tonic-gate 	int event;
1190Sstevel@tonic-gate 	hpc_event_entry_t *next;
1200Sstevel@tonic-gate };
1210Sstevel@tonic-gate 
1220Sstevel@tonic-gate #define	hpc_alloc_event_entry()	\
1230Sstevel@tonic-gate 	(hpc_event_entry_t *)kmem_zalloc(sizeof (hpc_event_entry_t), KM_SLEEP)
1240Sstevel@tonic-gate 
1250Sstevel@tonic-gate #define	hpc_free_event_entry(a)	\
1260Sstevel@tonic-gate 	kmem_free((a), sizeof (hpc_event_entry_t))
1270Sstevel@tonic-gate 
1280Sstevel@tonic-gate struct hpc_bus_entry {
1290Sstevel@tonic-gate 	dev_info_t *bus_dip;
1300Sstevel@tonic-gate 	char bus_name[MAXPATHLEN + 1];
1310Sstevel@tonic-gate 	boolean_t bus_registered;
1320Sstevel@tonic-gate 	kmutex_t bus_mutex;
1330Sstevel@tonic-gate 	int (* bus_callback)(dev_info_t *dip, hpc_slot_t hdl,
1340Sstevel@tonic-gate 		hpc_slot_info_t *slot_info, int slot_state);
1350Sstevel@tonic-gate 	hpc_slot_entry_t *bus_slot_list;
1360Sstevel@tonic-gate 	kthread_t *bus_thread;
1370Sstevel@tonic-gate 	kcondvar_t bus_thread_cv;
1380Sstevel@tonic-gate 	boolean_t bus_thread_exit;
1390Sstevel@tonic-gate 	hpc_event_entry_t *bus_slot_event_list_head;
1400Sstevel@tonic-gate 	hpc_bus_entry_t *bus_next;
1410Sstevel@tonic-gate };
1420Sstevel@tonic-gate 
1430Sstevel@tonic-gate #define	hpc_alloc_bus_entry()	\
1440Sstevel@tonic-gate 	(hpc_bus_entry_t *)kmem_zalloc(sizeof (hpc_bus_entry_t), KM_SLEEP)
1450Sstevel@tonic-gate 
1460Sstevel@tonic-gate #define	hpc_free_bus_entry(a)	\
1470Sstevel@tonic-gate 	kmem_free((a), sizeof (hpc_bus_entry_t))
1480Sstevel@tonic-gate 
1490Sstevel@tonic-gate 
1500Sstevel@tonic-gate /*
1510Sstevel@tonic-gate  * Definitions for the per-bus node slot registration list:
1520Sstevel@tonic-gate  *
1530Sstevel@tonic-gate  * For each bus node in the bus list, the hot-plug service module maintains
1540Sstevel@tonic-gate  * a doubly linked link list of items representing the slots that have been
1550Sstevel@tonic-gate  * registered (by hot-plug controllers) for that bus.
1560Sstevel@tonic-gate  *
1570Sstevel@tonic-gate  * The head of the linked listed is stored in bus_slot_list field of the bus
1580Sstevel@tonic-gate  * node.  Insertions and removals from this list should locked with the mutex
1590Sstevel@tonic-gate  * in the bus_mutex field of the bus node.
1600Sstevel@tonic-gate  *
1610Sstevel@tonic-gate  * Items in the list are allocated/freed with the macros hpc_alloc_slot_entry()
1620Sstevel@tonic-gate  * and hpc_free_slot_entry().
1630Sstevel@tonic-gate  *
1640Sstevel@tonic-gate  * Each item in the list contains the following fields:
1650Sstevel@tonic-gate  *
1660Sstevel@tonic-gate  *	slot_handle - handle for slot (hpc_slot_t)
1670Sstevel@tonic-gate  *
1680Sstevel@tonic-gate  *	slot_info - information registered with the slot (hpc_slot_info_t)
1690Sstevel@tonic-gate  *
1700Sstevel@tonic-gate  *	slot_ops - ops vector registered with the slot (hpc_slot_ops_t)
1710Sstevel@tonic-gate  *
1720Sstevel@tonic-gate  *	slot_ops_arg - argument to be passed to ops routines (caddr_t)
1730Sstevel@tonic-gate  *
1740Sstevel@tonic-gate  *	slot_event_handler - handler registered for slot events
1750Sstevel@tonic-gate  *
1760Sstevel@tonic-gate  *	slot_event_handler_arg - argument to be passed to event handler
1770Sstevel@tonic-gate  *
1780Sstevel@tonic-gate  *	slot_event_mask - the set of events for which the event handler
1790Sstevel@tonic-gate  *		gets invoked
1800Sstevel@tonic-gate  *
1810Sstevel@tonic-gate  *	slot_bus - pointer to bus node for the slot
1820Sstevel@tonic-gate  *
1830Sstevel@tonic-gate  *	slot_hpc_dip  -  devinfo node pointer to the HPC driver instance
1840Sstevel@tonic-gate  *			 that controls this slot
1850Sstevel@tonic-gate  *
1860Sstevel@tonic-gate  *	slot_{prev,next} - point to {previous,next} node in the list
1870Sstevel@tonic-gate  */
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate struct hpc_slot_entry {
1900Sstevel@tonic-gate 	hpc_slot_t slot_handle;
1910Sstevel@tonic-gate 	hpc_slot_info_t slot_info;	/* should be static & copied */
1920Sstevel@tonic-gate 	hpc_slot_ops_t slot_ops;
1930Sstevel@tonic-gate 	caddr_t slot_ops_arg;
1940Sstevel@tonic-gate 	int (* slot_event_handler)(caddr_t, uint_t);
1950Sstevel@tonic-gate 	caddr_t slot_event_handler_arg;
1960Sstevel@tonic-gate 	uint_t slot_event_mask;
1970Sstevel@tonic-gate 	hpc_bus_entry_t *slot_bus;
1980Sstevel@tonic-gate 	dev_info_t *slot_hpc_dip;
1990Sstevel@tonic-gate 	hpc_slot_entry_t *slot_next, *slot_prev;
2000Sstevel@tonic-gate };
2010Sstevel@tonic-gate 
2020Sstevel@tonic-gate #define	hpc_alloc_slot_entry()	\
2030Sstevel@tonic-gate 	(hpc_slot_entry_t *)kmem_zalloc(sizeof (hpc_slot_entry_t), KM_SLEEP)
2040Sstevel@tonic-gate 
2050Sstevel@tonic-gate #define	hpc_free_slot_entry(a)	\
2060Sstevel@tonic-gate 	kmem_free((a), sizeof (hpc_slot_entry_t))
2070Sstevel@tonic-gate 
2080Sstevel@tonic-gate 
2090Sstevel@tonic-gate /*
2100Sstevel@tonic-gate  * Definitions for slot registration callback table.
2110Sstevel@tonic-gate  */
2120Sstevel@tonic-gate 
2130Sstevel@tonic-gate typedef struct hpc_callback_entry hpc_callback_entry_t;
2140Sstevel@tonic-gate 
2150Sstevel@tonic-gate struct hpc_callback_entry {
2160Sstevel@tonic-gate 	int (* callback)(dev_info_t *dip, hpc_slot_t hdl,
2170Sstevel@tonic-gate 		hpc_slot_info_t *slot_info, int slot_state);
2180Sstevel@tonic-gate 	dev_info_t *dip;
2190Sstevel@tonic-gate 	hpc_slot_t hdl;
2200Sstevel@tonic-gate 	hpc_slot_info_t *slot_info;
2210Sstevel@tonic-gate 	int slot_state;
2220Sstevel@tonic-gate 	hpc_callback_entry_t *next;
2230Sstevel@tonic-gate };
2240Sstevel@tonic-gate 
2250Sstevel@tonic-gate #define	hpc_alloc_callback_entry()	\
2260Sstevel@tonic-gate 	(hpc_callback_entry_t *)	\
2270Sstevel@tonic-gate 		kmem_zalloc(sizeof (hpc_callback_entry_t), KM_SLEEP)
2280Sstevel@tonic-gate 
2290Sstevel@tonic-gate #define	hpc_free_callback_entry(a)	\
2300Sstevel@tonic-gate 	kmem_free((a), sizeof (hpc_callback_entry_t))
2310Sstevel@tonic-gate 
2320Sstevel@tonic-gate 
2330Sstevel@tonic-gate 
2340Sstevel@tonic-gate /*
2350Sstevel@tonic-gate  * Mutex lock for bus registration table and table head.
2360Sstevel@tonic-gate  */
2370Sstevel@tonic-gate static kmutex_t hpc_bus_mutex;
2380Sstevel@tonic-gate static hpc_bus_entry_t *hpc_bus_list_head;
2390Sstevel@tonic-gate 
2400Sstevel@tonic-gate 
2410Sstevel@tonic-gate /*
2420Sstevel@tonic-gate  * Forward function declarations.
2430Sstevel@tonic-gate  */
2440Sstevel@tonic-gate static hpc_bus_entry_t *hpc_find_bus_by_name(char *name);
2450Sstevel@tonic-gate static void hpc_slot_event_dispatcher(hpc_bus_entry_t *busp);
2460Sstevel@tonic-gate 
2470Sstevel@tonic-gate 
2480Sstevel@tonic-gate /*
2490Sstevel@tonic-gate  * loadable module definitions:
2500Sstevel@tonic-gate  */
2510Sstevel@tonic-gate extern struct mod_ops mod_miscops;
2520Sstevel@tonic-gate 
2530Sstevel@tonic-gate static struct modlmisc modlmisc = {
2540Sstevel@tonic-gate 	&mod_miscops,	/* Type of module */
255*7862SRichard.Bean@Sun.COM 	"hot-plug controller services"
2560Sstevel@tonic-gate };
2570Sstevel@tonic-gate 
2580Sstevel@tonic-gate static struct modlinkage modlinkage = {
2590Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
2600Sstevel@tonic-gate };
2610Sstevel@tonic-gate 
2620Sstevel@tonic-gate int
_init(void)2630Sstevel@tonic-gate _init(void)
2640Sstevel@tonic-gate {
2650Sstevel@tonic-gate 	int e;
2660Sstevel@tonic-gate 
2670Sstevel@tonic-gate 	mutex_init(&hpc_bus_mutex, NULL, MUTEX_DRIVER, NULL);
2680Sstevel@tonic-gate 
2690Sstevel@tonic-gate 	/*
2700Sstevel@tonic-gate 	 * Install the module.
2710Sstevel@tonic-gate 	 */
2720Sstevel@tonic-gate 	e = mod_install(&modlinkage);
2730Sstevel@tonic-gate 	if (e != 0) {
2740Sstevel@tonic-gate 		mutex_destroy(&hpc_bus_mutex);
2750Sstevel@tonic-gate 	}
2760Sstevel@tonic-gate 	return (e);
2770Sstevel@tonic-gate }
2780Sstevel@tonic-gate 
2790Sstevel@tonic-gate int
_fini(void)2800Sstevel@tonic-gate _fini(void)
2810Sstevel@tonic-gate {
2820Sstevel@tonic-gate 	int e;
2830Sstevel@tonic-gate 
2840Sstevel@tonic-gate 	e = mod_remove(&modlinkage);
2850Sstevel@tonic-gate 	if (e == 0) {
2860Sstevel@tonic-gate 		mutex_destroy(&hpc_bus_mutex);
2870Sstevel@tonic-gate 	}
2880Sstevel@tonic-gate 	return (e);
2890Sstevel@tonic-gate }
2900Sstevel@tonic-gate 
2910Sstevel@tonic-gate int
_info(struct modinfo * modinfop)2920Sstevel@tonic-gate _info(struct modinfo *modinfop)
2930Sstevel@tonic-gate {
2940Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
2950Sstevel@tonic-gate }
2960Sstevel@tonic-gate 
2970Sstevel@tonic-gate 
2980Sstevel@tonic-gate 
2990Sstevel@tonic-gate hpc_slot_ops_t *
hpc_alloc_slot_ops(int flag)3000Sstevel@tonic-gate hpc_alloc_slot_ops(int flag)
3010Sstevel@tonic-gate {
3020Sstevel@tonic-gate 	hpc_slot_ops_t *ops;
3030Sstevel@tonic-gate 
3040Sstevel@tonic-gate 	ops = (hpc_slot_ops_t *)kmem_zalloc(sizeof (hpc_slot_ops_t), flag);
3050Sstevel@tonic-gate 	return (ops);
3060Sstevel@tonic-gate }
3070Sstevel@tonic-gate 
3080Sstevel@tonic-gate 
3090Sstevel@tonic-gate void
hpc_free_slot_ops(hpc_slot_ops_t * ops)3100Sstevel@tonic-gate hpc_free_slot_ops(hpc_slot_ops_t *ops)
3110Sstevel@tonic-gate {
3120Sstevel@tonic-gate 	kmem_free((void *)ops, sizeof (hpc_slot_ops_t));
3130Sstevel@tonic-gate }
3140Sstevel@tonic-gate 
3150Sstevel@tonic-gate 
3160Sstevel@tonic-gate /*ARGSUSED2*/
3170Sstevel@tonic-gate int
hpc_nexus_register_bus(dev_info_t * dip,int (* callback)(dev_info_t * dip,hpc_slot_t hdl,hpc_slot_info_t * slot_info,int slot_state),uint_t flags)3180Sstevel@tonic-gate hpc_nexus_register_bus(dev_info_t *dip,
3190Sstevel@tonic-gate 	int (* callback)(dev_info_t *dip, hpc_slot_t hdl,
3200Sstevel@tonic-gate 	hpc_slot_info_t *slot_info, int slot_state), uint_t flags)
3210Sstevel@tonic-gate {
3220Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
3230Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
3240Sstevel@tonic-gate 	char bus_path[MAXPATHLEN + 1];
3250Sstevel@tonic-gate 
3260Sstevel@tonic-gate 	DEBUG2("hpc_nexus_register_bus: %s%d",
3270Sstevel@tonic-gate 	    ddi_node_name(dip), ddi_get_instance(dip));
3280Sstevel@tonic-gate 	mutex_enter(&hpc_bus_mutex);
3290Sstevel@tonic-gate 	(void) ddi_pathname(dip, bus_path);
3300Sstevel@tonic-gate 	busp = hpc_find_bus_by_name(bus_path);
3310Sstevel@tonic-gate 	if (busp == NULL) {
3320Sstevel@tonic-gate 
3330Sstevel@tonic-gate 		/*
3340Sstevel@tonic-gate 		 * Initialize the new bus node and link it at the head
3350Sstevel@tonic-gate 		 * of the bus list.
3360Sstevel@tonic-gate 		 */
3370Sstevel@tonic-gate 		DEBUG0("hpc_nexus_register_bus: not in bus list");
3380Sstevel@tonic-gate 		busp = hpc_alloc_bus_entry();
3390Sstevel@tonic-gate 		busp->bus_dip = dip;
3400Sstevel@tonic-gate 		busp->bus_registered = B_TRUE;
3410Sstevel@tonic-gate 		(void) strcpy(busp->bus_name, bus_path);
3420Sstevel@tonic-gate 		mutex_init(&busp->bus_mutex, NULL, MUTEX_DRIVER, NULL);
3430Sstevel@tonic-gate 		busp->bus_callback = callback;
3440Sstevel@tonic-gate 		busp->bus_slot_list = NULL;
3450Sstevel@tonic-gate 		busp->bus_next = hpc_bus_list_head;
3460Sstevel@tonic-gate 		hpc_bus_list_head = busp;
3470Sstevel@tonic-gate 
3480Sstevel@tonic-gate 	} else {
3490Sstevel@tonic-gate 
3500Sstevel@tonic-gate 		/*
3510Sstevel@tonic-gate 		 * The bus is in the bus list but isn't registered yet.
3520Sstevel@tonic-gate 		 * Mark it as registered, and run the registration callbacks
3530Sstevel@tonic-gate 		 * for it slots.
3540Sstevel@tonic-gate 		 */
3550Sstevel@tonic-gate 		DEBUG0("hpc_nexus_register_bus: in list, but not registered");
3560Sstevel@tonic-gate 		mutex_enter(&busp->bus_mutex);
3570Sstevel@tonic-gate 		if (busp->bus_registered == B_TRUE) {
3580Sstevel@tonic-gate 			mutex_exit(&busp->bus_mutex);
3590Sstevel@tonic-gate 			mutex_exit(&hpc_bus_mutex);
3600Sstevel@tonic-gate 			return (HPC_ERR_BUS_DUPLICATE);
3610Sstevel@tonic-gate 		}
3620Sstevel@tonic-gate 		busp->bus_dip = dip;
3630Sstevel@tonic-gate 		busp->bus_callback = callback;
3640Sstevel@tonic-gate 		busp->bus_registered = B_TRUE;
3650Sstevel@tonic-gate 
3660Sstevel@tonic-gate 		mutex_exit(&busp->bus_mutex);
3670Sstevel@tonic-gate 		mutex_exit(&hpc_bus_mutex);
3680Sstevel@tonic-gate 		if (callback) {
3690Sstevel@tonic-gate 			DEBUG0("hpc_nexus_register_bus: running callbacks");
3700Sstevel@tonic-gate 			for (slotp = busp->bus_slot_list; slotp;
3710Sstevel@tonic-gate 			    slotp = slotp->slot_next) {
3720Sstevel@tonic-gate 				(void) callback(dip, slotp, &slotp->slot_info,
3730Sstevel@tonic-gate 				    HPC_SLOT_ONLINE);
3740Sstevel@tonic-gate 			}
3750Sstevel@tonic-gate 		}
3760Sstevel@tonic-gate 		return (HPC_SUCCESS);
3770Sstevel@tonic-gate 	}
3780Sstevel@tonic-gate 	mutex_exit(&hpc_bus_mutex);
3790Sstevel@tonic-gate 	return (HPC_SUCCESS);
3800Sstevel@tonic-gate }
3810Sstevel@tonic-gate 
3820Sstevel@tonic-gate 
3830Sstevel@tonic-gate int
hpc_nexus_unregister_bus(dev_info_t * dip)3840Sstevel@tonic-gate hpc_nexus_unregister_bus(dev_info_t *dip)
3850Sstevel@tonic-gate {
3860Sstevel@tonic-gate 	hpc_bus_entry_t *busp, *busp_prev;
3870Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate 	/*
3900Sstevel@tonic-gate 	 * Search the list for the bus node and remove it.
3910Sstevel@tonic-gate 	 */
3920Sstevel@tonic-gate 	DEBUG2("hpc_nexus_unregister_bus: %s%d",
3930Sstevel@tonic-gate 	    ddi_node_name(dip), ddi_get_instance(dip));
3940Sstevel@tonic-gate 	mutex_enter(&hpc_bus_mutex);
3950Sstevel@tonic-gate 	for (busp = hpc_bus_list_head; busp != NULL; busp_prev = busp,
3960Sstevel@tonic-gate 	    busp = busp->bus_next) {
3970Sstevel@tonic-gate 		if (busp->bus_dip == dip)
3980Sstevel@tonic-gate 			break;
3990Sstevel@tonic-gate 	}
4000Sstevel@tonic-gate 	if (busp == NULL) {
4010Sstevel@tonic-gate 		mutex_exit(&hpc_bus_mutex);
4020Sstevel@tonic-gate 		return (HPC_ERR_BUS_NOTREGISTERED);
4030Sstevel@tonic-gate 	}
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate 	/*
4060Sstevel@tonic-gate 	 * If the bus has slots, mark the bus as unregistered, otherwise
4070Sstevel@tonic-gate 	 * remove the bus entry from the list.
4080Sstevel@tonic-gate 	 */
4090Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
4100Sstevel@tonic-gate 	if (busp->bus_slot_list == NULL) {
4110Sstevel@tonic-gate 		if (busp == hpc_bus_list_head)
4120Sstevel@tonic-gate 			hpc_bus_list_head = busp->bus_next;
4130Sstevel@tonic-gate 		else
4140Sstevel@tonic-gate 			busp_prev->bus_next = busp->bus_next;
4150Sstevel@tonic-gate 		mutex_exit(&busp->bus_mutex);
4160Sstevel@tonic-gate 		mutex_destroy(&busp->bus_mutex);
4170Sstevel@tonic-gate 		hpc_free_bus_entry(busp);
4180Sstevel@tonic-gate 		mutex_exit(&hpc_bus_mutex);
4190Sstevel@tonic-gate 		return (HPC_SUCCESS);
4200Sstevel@tonic-gate 	}
4210Sstevel@tonic-gate 
4220Sstevel@tonic-gate 	/*
4230Sstevel@tonic-gate 	 * unregister event handlers for all the slots on this bus.
4240Sstevel@tonic-gate 	 */
4250Sstevel@tonic-gate 	for (slotp = busp->bus_slot_list; slotp != NULL;
4260Sstevel@tonic-gate 		slotp = slotp->slot_next) {
4270Sstevel@tonic-gate 		slotp->slot_event_handler = NULL;
4280Sstevel@tonic-gate 		slotp->slot_event_handler_arg = NULL;
4290Sstevel@tonic-gate 	}
4300Sstevel@tonic-gate 	busp->bus_registered = B_FALSE;
4310Sstevel@tonic-gate 	mutex_exit(&busp->bus_mutex);
4320Sstevel@tonic-gate 	mutex_exit(&hpc_bus_mutex);
4330Sstevel@tonic-gate 	return (HPC_SUCCESS);
4340Sstevel@tonic-gate }
4350Sstevel@tonic-gate 
4360Sstevel@tonic-gate 
4370Sstevel@tonic-gate /*ARGSUSED5*/
4380Sstevel@tonic-gate int
hpc_slot_register(dev_info_t * hpc_dip,char * bus,hpc_slot_info_t * infop,hpc_slot_t * handlep,hpc_slot_ops_t * opsp,caddr_t ops_arg,uint_t flags)4390Sstevel@tonic-gate hpc_slot_register(dev_info_t *hpc_dip, char *bus, hpc_slot_info_t *infop,
4400Sstevel@tonic-gate 	hpc_slot_t *handlep, hpc_slot_ops_t *opsp,
4410Sstevel@tonic-gate 	caddr_t ops_arg, uint_t flags)
4420Sstevel@tonic-gate {
4430Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
4440Sstevel@tonic-gate 	hpc_slot_entry_t *slotp, *slot_list_head;
4450Sstevel@tonic-gate 	boolean_t run_callback = B_FALSE;
4460Sstevel@tonic-gate 	int (* callback)(dev_info_t *dip, hpc_slot_t hdl,
4470Sstevel@tonic-gate 		hpc_slot_info_t *slot_info, int slot_state);
4480Sstevel@tonic-gate 	dev_info_t *dip;
4490Sstevel@tonic-gate 	kthread_t *t;
4500Sstevel@tonic-gate 
4510Sstevel@tonic-gate 	/*
4520Sstevel@tonic-gate 	 * Validate the arguments.
4530Sstevel@tonic-gate 	 */
4540Sstevel@tonic-gate 	DEBUG1("hpc_slot_register: %s", bus);
4550Sstevel@tonic-gate 	if (handlep == NULL || infop == NULL || opsp == NULL || hpc_dip == NULL)
4560Sstevel@tonic-gate 		return (HPC_ERR_INVALID);
4570Sstevel@tonic-gate 
4580Sstevel@tonic-gate 	/*
4590Sstevel@tonic-gate 	 * The bus for the slot may or may not be in the bus list.  If it's
4600Sstevel@tonic-gate 	 * not, we create a node for the bus in the bus list and mark it as
4610Sstevel@tonic-gate 	 * not registered.
4620Sstevel@tonic-gate 	 */
4630Sstevel@tonic-gate 	mutex_enter(&hpc_bus_mutex);
4640Sstevel@tonic-gate 	busp = hpc_find_bus_by_name(bus);
4650Sstevel@tonic-gate 	if (busp == NULL) {
4660Sstevel@tonic-gate 
4670Sstevel@tonic-gate 		/*
4680Sstevel@tonic-gate 		 * Initialize the new bus node and link it at the
4690Sstevel@tonic-gate 		 * head of the bus list.
4700Sstevel@tonic-gate 		 */
4710Sstevel@tonic-gate 		DEBUG1("hpc_slot_register: %s not in bus list", bus);
4720Sstevel@tonic-gate 		busp = hpc_alloc_bus_entry();
4730Sstevel@tonic-gate 		busp->bus_registered = B_FALSE;
4740Sstevel@tonic-gate 		(void) strcpy(busp->bus_name, bus);
4750Sstevel@tonic-gate 		mutex_init(&busp->bus_mutex, NULL, MUTEX_DRIVER, NULL);
4760Sstevel@tonic-gate 		busp->bus_slot_list = NULL;
4770Sstevel@tonic-gate 		busp->bus_next = hpc_bus_list_head;
4780Sstevel@tonic-gate 		hpc_bus_list_head = busp;
4790Sstevel@tonic-gate 
4800Sstevel@tonic-gate 	} else {
4810Sstevel@tonic-gate 		if (busp->bus_registered == B_TRUE) {
4820Sstevel@tonic-gate 			run_callback = B_TRUE;
4830Sstevel@tonic-gate 			callback = busp->bus_callback;
4840Sstevel@tonic-gate 			dip = busp->bus_dip;
4850Sstevel@tonic-gate 		}
4860Sstevel@tonic-gate 	}
4870Sstevel@tonic-gate 
4880Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
4890Sstevel@tonic-gate 	slot_list_head = busp->bus_slot_list;
4900Sstevel@tonic-gate 	if (slot_list_head == NULL) {
4910Sstevel@tonic-gate 
4920Sstevel@tonic-gate 		/*
4930Sstevel@tonic-gate 		 * The slot list was empty, so this is the first slot
4940Sstevel@tonic-gate 		 * registered for the bus.  Create a per-bus thread
4950Sstevel@tonic-gate 		 * for running the slot event handlers.
4960Sstevel@tonic-gate 		 */
4970Sstevel@tonic-gate 		DEBUG0("hpc_slot_register: creating event callback thread");
4980Sstevel@tonic-gate 		cv_init(&busp->bus_thread_cv, NULL, CV_DRIVER, NULL);
4990Sstevel@tonic-gate 		busp->bus_thread_exit = B_FALSE;
5000Sstevel@tonic-gate 		t = thread_create(NULL, 0, hpc_slot_event_dispatcher,
5010Sstevel@tonic-gate 		    (caddr_t)busp, 0, &p0, TS_RUN, minclsyspri);
5020Sstevel@tonic-gate 		busp->bus_thread = t;
5030Sstevel@tonic-gate 	}
5040Sstevel@tonic-gate 
5050Sstevel@tonic-gate 	/*
5060Sstevel@tonic-gate 	 * Create and initialize a new entry in the slot list for the bus.
5070Sstevel@tonic-gate 	 */
5080Sstevel@tonic-gate 	slotp = hpc_alloc_slot_entry();
5090Sstevel@tonic-gate 	slotp->slot_handle = (hpc_slot_t)slotp;
5100Sstevel@tonic-gate 	slotp->slot_info = *infop;
5110Sstevel@tonic-gate 	slotp->slot_ops = *opsp;
5120Sstevel@tonic-gate 	slotp->slot_ops_arg = ops_arg;
5130Sstevel@tonic-gate 	slotp->slot_bus = busp;
5140Sstevel@tonic-gate 	slotp->slot_hpc_dip = hpc_dip;
5150Sstevel@tonic-gate 	slotp->slot_prev = NULL;
5160Sstevel@tonic-gate 	busp->bus_slot_list = slotp;
5170Sstevel@tonic-gate 	slotp->slot_next = slot_list_head;
5180Sstevel@tonic-gate 	if (slot_list_head != NULL)
5190Sstevel@tonic-gate 		slot_list_head->slot_prev = slotp;
5200Sstevel@tonic-gate 	mutex_exit(&busp->bus_mutex);
5210Sstevel@tonic-gate 	mutex_exit(&hpc_bus_mutex);
5220Sstevel@tonic-gate 
5230Sstevel@tonic-gate 	/*
5240Sstevel@tonic-gate 	 * Return the handle to the caller prior to return to avoid recursion.
5250Sstevel@tonic-gate 	 */
5260Sstevel@tonic-gate 	*handlep = (hpc_slot_t)slotp;
5270Sstevel@tonic-gate 
5280Sstevel@tonic-gate 	/*
5290Sstevel@tonic-gate 	 * If the bus was registered, we run the callback registered by
5300Sstevel@tonic-gate 	 * the bus node.
5310Sstevel@tonic-gate 	 */
5320Sstevel@tonic-gate 	if (run_callback) {
5330Sstevel@tonic-gate 		DEBUG0("hpc_slot_register: running callback");
5340Sstevel@tonic-gate 
5350Sstevel@tonic-gate 		(void) callback(dip, slotp, infop, HPC_SLOT_ONLINE);
5360Sstevel@tonic-gate 	}
5370Sstevel@tonic-gate 
5380Sstevel@tonic-gate 	/*
5390Sstevel@tonic-gate 	 * Keep hpc driver in memory
5400Sstevel@tonic-gate 	 */
5410Sstevel@tonic-gate 	(void) ndi_hold_driver(hpc_dip);
5420Sstevel@tonic-gate 
5430Sstevel@tonic-gate 	return (HPC_SUCCESS);
5440Sstevel@tonic-gate }
5450Sstevel@tonic-gate 
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate int
hpc_slot_unregister(hpc_slot_t * handlep)5480Sstevel@tonic-gate hpc_slot_unregister(hpc_slot_t *handlep)
5490Sstevel@tonic-gate {
5500Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
5510Sstevel@tonic-gate 	hpc_bus_entry_t *busp, *busp_prev;
5520Sstevel@tonic-gate 	boolean_t run_callback;
5530Sstevel@tonic-gate 	int (* callback)(dev_info_t *dip, hpc_slot_t hdl,
5540Sstevel@tonic-gate 		hpc_slot_info_t *slot_info, int slot_state);
5550Sstevel@tonic-gate 	int r;
5560Sstevel@tonic-gate 	dev_info_t *dip;
5570Sstevel@tonic-gate 	char *bus_name;
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	DEBUG0("hpc_slot_unregister:");
5600Sstevel@tonic-gate 
5610Sstevel@tonic-gate 	ASSERT(handlep != NULL);
5620Sstevel@tonic-gate 
5630Sstevel@tonic-gate 	/* validate the handle */
5640Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)*handlep;
5650Sstevel@tonic-gate 	if ((slotp == NULL) || slotp->slot_handle != *handlep)
5660Sstevel@tonic-gate 		return (HPC_ERR_INVALID);
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	/*
5690Sstevel@tonic-gate 	 * Get the bus list entry from the slot to grap the mutex for
5700Sstevel@tonic-gate 	 * the slot list of the bus.
5710Sstevel@tonic-gate 	 */
5720Sstevel@tonic-gate 	mutex_enter(&hpc_bus_mutex);
5730Sstevel@tonic-gate 	busp = slotp->slot_bus;
5740Sstevel@tonic-gate 	DEBUG2("hpc_slot_unregister: handlep=%x, slotp=%x", handlep, slotp);
5750Sstevel@tonic-gate 	if (busp == NULL) {
5760Sstevel@tonic-gate 		mutex_exit(&hpc_bus_mutex);
5770Sstevel@tonic-gate 		return (HPC_ERR_SLOT_NOTREGISTERED);
5780Sstevel@tonic-gate 	}
5790Sstevel@tonic-gate 
5800Sstevel@tonic-gate 	/*
5810Sstevel@tonic-gate 	 * Determine if we need to run the slot offline callback and
5820Sstevel@tonic-gate 	 * save the data necessary to do so.
5830Sstevel@tonic-gate 	 */
5840Sstevel@tonic-gate 	callback = busp->bus_callback;
5850Sstevel@tonic-gate 	run_callback = (busp->bus_registered == B_TRUE) && (callback != NULL);
5860Sstevel@tonic-gate 	dip = busp->bus_dip;
5870Sstevel@tonic-gate 	bus_name = busp->bus_name;
5880Sstevel@tonic-gate 
5890Sstevel@tonic-gate 	/*
5900Sstevel@tonic-gate 	 * Run the slot offline callback if necessary.
5910Sstevel@tonic-gate 	 */
5920Sstevel@tonic-gate 	if (run_callback) {
5930Sstevel@tonic-gate 		mutex_exit(&hpc_bus_mutex);
5940Sstevel@tonic-gate 		DEBUG0("hpc_slot_unregister: running callback");
5950Sstevel@tonic-gate 		r = callback(dip, (hpc_slot_t)slotp, &slotp->slot_info,
5960Sstevel@tonic-gate 		    HPC_SLOT_OFFLINE);
5970Sstevel@tonic-gate 		DEBUG1("hpc_slot_unregister: callback returned %x", r);
5980Sstevel@tonic-gate 		if (r != HPC_SUCCESS)
5990Sstevel@tonic-gate 			return (HPC_ERR_FAILED);
6000Sstevel@tonic-gate 		mutex_enter(&hpc_bus_mutex);
6010Sstevel@tonic-gate 	}
6020Sstevel@tonic-gate 
6030Sstevel@tonic-gate 	/*
6040Sstevel@tonic-gate 	 * Remove the slot from list and free the memory associated with it.
6050Sstevel@tonic-gate 	 */
6060Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
6070Sstevel@tonic-gate 	DEBUG1("hpc_slot_unregister: freeing slot, bus_slot_list=%x",
6080Sstevel@tonic-gate 		busp->bus_slot_list);
6090Sstevel@tonic-gate 	if (slotp->slot_prev != NULL)
6100Sstevel@tonic-gate 		slotp->slot_prev->slot_next = slotp->slot_next;
6110Sstevel@tonic-gate 	if (slotp->slot_next != NULL)
6120Sstevel@tonic-gate 		slotp->slot_next->slot_prev = slotp->slot_prev;
6130Sstevel@tonic-gate 	if (slotp == busp->bus_slot_list)
6140Sstevel@tonic-gate 		busp->bus_slot_list = slotp->slot_next;
6150Sstevel@tonic-gate 
6160Sstevel@tonic-gate 	/*
6170Sstevel@tonic-gate 	 * Release hold from slot registration
6180Sstevel@tonic-gate 	 */
6190Sstevel@tonic-gate 	ndi_rele_driver(slotp->slot_hpc_dip);
6200Sstevel@tonic-gate 
6210Sstevel@tonic-gate 	/* Free the memory associated with the slot entry structure */
6220Sstevel@tonic-gate 	hpc_free_slot_entry(slotp);
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	/*
6250Sstevel@tonic-gate 	 * If the slot list is empty then stop the event handler thread.
6260Sstevel@tonic-gate 	 */
6270Sstevel@tonic-gate 	if (busp->bus_slot_list == NULL) {
6280Sstevel@tonic-gate 		DEBUG0("hpc_slot_unregister: stopping thread");
6290Sstevel@tonic-gate 		busp->bus_thread_exit = B_TRUE;
6300Sstevel@tonic-gate 		cv_signal(&busp->bus_thread_cv);
6310Sstevel@tonic-gate 		DEBUG0("hpc_slot_unregister: waiting for thread to exit");
6320Sstevel@tonic-gate 		cv_wait(&busp->bus_thread_cv, &busp->bus_mutex);
6330Sstevel@tonic-gate 		DEBUG0("hpc_slot_unregister: thread exit");
6340Sstevel@tonic-gate 		cv_destroy(&busp->bus_thread_cv);
6350Sstevel@tonic-gate 	}
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 	/*
6380Sstevel@tonic-gate 	 * If the bus is unregistered and this is the last slot for this bus
6390Sstevel@tonic-gate 	 * then remove the entry from the bus list.
6400Sstevel@tonic-gate 	 */
6410Sstevel@tonic-gate 	if (busp->bus_registered == B_FALSE && busp->bus_slot_list == NULL) {
6420Sstevel@tonic-gate 		/* locate the previous entry in the bus list */
6430Sstevel@tonic-gate 		for (busp = hpc_bus_list_head; busp != NULL; busp_prev = busp,
6440Sstevel@tonic-gate 		    busp = busp->bus_next)
6450Sstevel@tonic-gate 			if (strcmp(bus_name, busp->bus_name) == 0)
6460Sstevel@tonic-gate 				break;
6470Sstevel@tonic-gate 
6480Sstevel@tonic-gate 		if (busp == hpc_bus_list_head)
6490Sstevel@tonic-gate 			hpc_bus_list_head = busp->bus_next;
6500Sstevel@tonic-gate 		else
6510Sstevel@tonic-gate 			busp_prev->bus_next = busp->bus_next;
6520Sstevel@tonic-gate 
6530Sstevel@tonic-gate 		mutex_exit(&busp->bus_mutex);
6540Sstevel@tonic-gate 		mutex_destroy(&busp->bus_mutex);
6550Sstevel@tonic-gate 		hpc_free_bus_entry(busp);
6560Sstevel@tonic-gate 	} else
6570Sstevel@tonic-gate 		mutex_exit(&busp->bus_mutex);
6580Sstevel@tonic-gate 	mutex_exit(&hpc_bus_mutex);
6590Sstevel@tonic-gate 
6600Sstevel@tonic-gate 	/*
6610Sstevel@tonic-gate 	 * reset the slot handle.
6620Sstevel@tonic-gate 	 */
6630Sstevel@tonic-gate 	*handlep = NULL;
6640Sstevel@tonic-gate 	return (HPC_SUCCESS);
6650Sstevel@tonic-gate }
6660Sstevel@tonic-gate 
6670Sstevel@tonic-gate 
6680Sstevel@tonic-gate int
hpc_install_event_handler(hpc_slot_t handle,uint_t event_mask,int (* event_handler)(caddr_t,uint_t),caddr_t arg)6690Sstevel@tonic-gate hpc_install_event_handler(hpc_slot_t handle, uint_t event_mask,
6700Sstevel@tonic-gate 	int (*event_handler)(caddr_t, uint_t), caddr_t arg)
6710Sstevel@tonic-gate {
6720Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
6730Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
6740Sstevel@tonic-gate 
6750Sstevel@tonic-gate 	DEBUG3("hpc_install_event_handler: handle=%x, mask=%x, arg=%x",
6760Sstevel@tonic-gate 		handle, event_mask, arg);
6770Sstevel@tonic-gate 	ASSERT((handle != NULL) && (event_handler != NULL));
6780Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
6790Sstevel@tonic-gate 	busp = slotp->slot_bus;
6800Sstevel@tonic-gate 	ASSERT(slotp == slotp->slot_handle);
6810Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
6820Sstevel@tonic-gate 	slotp->slot_event_mask = event_mask;
6830Sstevel@tonic-gate 	slotp->slot_event_handler = event_handler;
6840Sstevel@tonic-gate 	slotp->slot_event_handler_arg = arg;
6850Sstevel@tonic-gate 	mutex_exit(&busp->bus_mutex);
6860Sstevel@tonic-gate 	return (HPC_SUCCESS);
6870Sstevel@tonic-gate }
6880Sstevel@tonic-gate 
6890Sstevel@tonic-gate 
6900Sstevel@tonic-gate int
hpc_remove_event_handler(hpc_slot_t handle)6910Sstevel@tonic-gate hpc_remove_event_handler(hpc_slot_t handle)
6920Sstevel@tonic-gate {
6930Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
6940Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	DEBUG1("hpc_remove_event_handler: handle=%x", handle);
6970Sstevel@tonic-gate 	ASSERT(handle != NULL);
6980Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
6990Sstevel@tonic-gate 	ASSERT(slotp == slotp->slot_handle);
7000Sstevel@tonic-gate 	busp = slotp->slot_bus;
7010Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
7020Sstevel@tonic-gate 	slotp->slot_event_mask = 0;
7030Sstevel@tonic-gate 	slotp->slot_event_handler = NULL;
7040Sstevel@tonic-gate 	slotp->slot_event_handler_arg = NULL;
7050Sstevel@tonic-gate 	mutex_exit(&busp->bus_mutex);
7060Sstevel@tonic-gate 	return (HPC_SUCCESS);
7070Sstevel@tonic-gate }
7080Sstevel@tonic-gate 
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate /*ARGSUSED2*/
7110Sstevel@tonic-gate int
hpc_slot_event_notify(hpc_slot_t handle,uint_t event,uint_t flags)7120Sstevel@tonic-gate hpc_slot_event_notify(hpc_slot_t handle, uint_t event, uint_t flags)
7130Sstevel@tonic-gate {
7140Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
7150Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
7160Sstevel@tonic-gate 	hpc_event_entry_t *eventp;
7170Sstevel@tonic-gate 
7180Sstevel@tonic-gate 	DEBUG2("hpc_slot_event_notify: handle=%x event=%x", handle, event);
7190Sstevel@tonic-gate 	ASSERT(handle != NULL);
7200Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
7210Sstevel@tonic-gate 	ASSERT(slotp == slotp->slot_handle);
7220Sstevel@tonic-gate 
7230Sstevel@tonic-gate 	if (slotp->slot_event_handler == NULL)
7240Sstevel@tonic-gate 		return (HPC_EVENT_UNCLAIMED);
7250Sstevel@tonic-gate 
7260Sstevel@tonic-gate 	/*
7270Sstevel@tonic-gate 	 * If the request is to handle the event synchronously, then call
7280Sstevel@tonic-gate 	 * the event handler without queuing the event.
7290Sstevel@tonic-gate 	 */
7300Sstevel@tonic-gate 	if (flags == HPC_EVENT_SYNCHRONOUS) {
7310Sstevel@tonic-gate 		caddr_t arg;
7320Sstevel@tonic-gate 		int (* func)(caddr_t, uint_t);
7330Sstevel@tonic-gate 
7340Sstevel@tonic-gate 		func = slotp->slot_event_handler;
7350Sstevel@tonic-gate 		arg = slotp->slot_event_handler_arg;
7360Sstevel@tonic-gate 		return (func(arg, event));
7370Sstevel@tonic-gate 	}
7380Sstevel@tonic-gate 	/*
7390Sstevel@tonic-gate 	 * Insert the event into the bus slot event handler list and
7400Sstevel@tonic-gate 	 * signal the bus slot event handler dispatch thread.
7410Sstevel@tonic-gate 	 */
7420Sstevel@tonic-gate 	busp = slotp->slot_bus;
7430Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
7440Sstevel@tonic-gate 
7450Sstevel@tonic-gate 	if (busp->bus_slot_event_list_head == NULL) {
7460Sstevel@tonic-gate 		eventp = busp->bus_slot_event_list_head =
7470Sstevel@tonic-gate 		    hpc_alloc_event_entry();
7480Sstevel@tonic-gate 	} else {
7490Sstevel@tonic-gate 		for (eventp = busp->bus_slot_event_list_head;
7500Sstevel@tonic-gate 			    eventp->next != NULL; eventp = eventp->next)
7510Sstevel@tonic-gate 			;
7520Sstevel@tonic-gate 		eventp->next = hpc_alloc_event_entry();
7530Sstevel@tonic-gate 		eventp = eventp->next;
7540Sstevel@tonic-gate 	}
7550Sstevel@tonic-gate 	eventp->slotp = slotp;
7560Sstevel@tonic-gate 	eventp->event = event;
7570Sstevel@tonic-gate 	eventp->next = NULL;
7580Sstevel@tonic-gate 	DEBUG2("hpc_slot_event_notify: busp=%x event=%x", busp, event);
7590Sstevel@tonic-gate 	cv_signal(&busp->bus_thread_cv);
7600Sstevel@tonic-gate 	mutex_exit(&busp->bus_mutex);
7610Sstevel@tonic-gate 	return (HPC_EVENT_CLAIMED);
7620Sstevel@tonic-gate }
7630Sstevel@tonic-gate 
7640Sstevel@tonic-gate 
7650Sstevel@tonic-gate int
hpc_nexus_connect(hpc_slot_t handle,void * data,uint_t flags)7660Sstevel@tonic-gate hpc_nexus_connect(hpc_slot_t handle, void *data, uint_t flags)
7670Sstevel@tonic-gate {
7680Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
7690Sstevel@tonic-gate 
7700Sstevel@tonic-gate 	ASSERT(handle != NULL);
7710Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
7720Sstevel@tonic-gate 	if (slotp->slot_ops.hpc_op_connect)
7730Sstevel@tonic-gate 		return (slotp->slot_ops.hpc_op_connect(slotp->slot_ops_arg,
7740Sstevel@tonic-gate 			handle, data, flags));
7750Sstevel@tonic-gate 	return (HPC_ERR_FAILED);
7760Sstevel@tonic-gate }
7770Sstevel@tonic-gate 
7780Sstevel@tonic-gate 
7790Sstevel@tonic-gate int
hpc_nexus_disconnect(hpc_slot_t handle,void * data,uint_t flags)7800Sstevel@tonic-gate hpc_nexus_disconnect(hpc_slot_t handle, void *data, uint_t flags)
7810Sstevel@tonic-gate {
7820Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
7830Sstevel@tonic-gate 
7840Sstevel@tonic-gate 	ASSERT(handle != NULL);
7850Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
7860Sstevel@tonic-gate 	if (slotp->slot_ops.hpc_op_disconnect)
7870Sstevel@tonic-gate 		return (slotp->slot_ops.hpc_op_disconnect(slotp->slot_ops_arg,
7880Sstevel@tonic-gate 			handle, data, flags));
7890Sstevel@tonic-gate 	return (HPC_ERR_FAILED);
7900Sstevel@tonic-gate }
7910Sstevel@tonic-gate 
7920Sstevel@tonic-gate 
7930Sstevel@tonic-gate int
hpc_nexus_insert(hpc_slot_t handle,void * data,uint_t flags)7940Sstevel@tonic-gate hpc_nexus_insert(hpc_slot_t handle, void *data, uint_t flags)
7950Sstevel@tonic-gate {
7960Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
7970Sstevel@tonic-gate 
7980Sstevel@tonic-gate 	ASSERT(handle != NULL);
7990Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
8000Sstevel@tonic-gate 	if (slotp->slot_ops.hpc_op_insert)
8010Sstevel@tonic-gate 		return (slotp->slot_ops.hpc_op_insert(slotp->slot_ops_arg,
8020Sstevel@tonic-gate 			handle, data, flags));
8030Sstevel@tonic-gate 	return (HPC_ERR_FAILED);
8040Sstevel@tonic-gate }
8050Sstevel@tonic-gate 
8060Sstevel@tonic-gate 
8070Sstevel@tonic-gate int
hpc_nexus_remove(hpc_slot_t handle,void * data,uint_t flags)8080Sstevel@tonic-gate hpc_nexus_remove(hpc_slot_t handle, void *data, uint_t flags)
8090Sstevel@tonic-gate {
8100Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate 	ASSERT(handle != NULL);
8130Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
8140Sstevel@tonic-gate 	if (slotp->slot_ops.hpc_op_remove)
8150Sstevel@tonic-gate 		return (slotp->slot_ops.hpc_op_remove(slotp->slot_ops_arg,
8160Sstevel@tonic-gate 			handle, data, flags));
8170Sstevel@tonic-gate 	return (HPC_ERR_FAILED);
8180Sstevel@tonic-gate }
8190Sstevel@tonic-gate 
8200Sstevel@tonic-gate 
8210Sstevel@tonic-gate int
hpc_nexus_control(hpc_slot_t handle,int request,caddr_t arg)8220Sstevel@tonic-gate hpc_nexus_control(hpc_slot_t handle, int request, caddr_t arg)
8230Sstevel@tonic-gate {
8240Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
8250Sstevel@tonic-gate 
8260Sstevel@tonic-gate 	ASSERT(handle != NULL);
8270Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
8280Sstevel@tonic-gate 	if (slotp->slot_ops.hpc_op_control)
8290Sstevel@tonic-gate 		return (slotp->slot_ops.hpc_op_control(slotp->slot_ops_arg,
8300Sstevel@tonic-gate 			handle, request, arg));
8310Sstevel@tonic-gate 	return (HPC_ERR_FAILED);
8320Sstevel@tonic-gate }
8330Sstevel@tonic-gate 
8340Sstevel@tonic-gate /*
8350Sstevel@tonic-gate  * The following function is run from the bus entries slot event handling
8360Sstevel@tonic-gate  * thread.
8370Sstevel@tonic-gate  */
8380Sstevel@tonic-gate static void
hpc_slot_event_dispatcher(hpc_bus_entry_t * busp)8390Sstevel@tonic-gate hpc_slot_event_dispatcher(hpc_bus_entry_t *busp)
8400Sstevel@tonic-gate {
8410Sstevel@tonic-gate 	hpc_event_entry_t *eventp;
8420Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
8430Sstevel@tonic-gate 	int event;
8440Sstevel@tonic-gate 	caddr_t arg;
8450Sstevel@tonic-gate 	int (* func)(caddr_t, uint_t);
8460Sstevel@tonic-gate 	callb_cpr_t cprinfo;
8470Sstevel@tonic-gate 
8480Sstevel@tonic-gate 	/*
8490Sstevel@tonic-gate 	 * The creator of this thread is waiting to be signaled that
8500Sstevel@tonic-gate 	 * the thread has been started.
8510Sstevel@tonic-gate 	 */
8520Sstevel@tonic-gate 	DEBUG1("hpc_slot_event_dispatcher: busp=%x", busp);
8530Sstevel@tonic-gate 
8540Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &busp->bus_mutex, callb_generic_cpr,
8550Sstevel@tonic-gate 	    "hpc_slot_event_dispatcher");
8560Sstevel@tonic-gate 
8570Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
8580Sstevel@tonic-gate 	/*
8590Sstevel@tonic-gate 	 * Wait for events to queue and then process them.
8600Sstevel@tonic-gate 	 */
8610Sstevel@tonic-gate 	for (;;) {
8620Sstevel@tonic-gate 
8630Sstevel@tonic-gate 		/*
8640Sstevel@tonic-gate 		 * Note we only hold the mutex while determining
8650Sstevel@tonic-gate 		 * the number of entries that have been added to
8660Sstevel@tonic-gate 		 * the event list, while updating the event list
8670Sstevel@tonic-gate 		 * after processing the event list entries.
8680Sstevel@tonic-gate 		 */
8690Sstevel@tonic-gate 		if (busp->bus_slot_event_list_head == NULL) {
8700Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
8710Sstevel@tonic-gate 			cv_wait(&busp->bus_thread_cv, &busp->bus_mutex);
8720Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(&cprinfo, &busp->bus_mutex);
8730Sstevel@tonic-gate 			if (busp->bus_thread_exit)
8740Sstevel@tonic-gate 				break;
8750Sstevel@tonic-gate 			continue;
8760Sstevel@tonic-gate 		}
8770Sstevel@tonic-gate 
8780Sstevel@tonic-gate 		/*
8790Sstevel@tonic-gate 		 * We have an event handler instance in the list to
8800Sstevel@tonic-gate 		 * process.  Remove the head of the list, saving the
8810Sstevel@tonic-gate 		 * information required to run the event handler.
8820Sstevel@tonic-gate 		 * Then run the event handler while the bus mutex
8830Sstevel@tonic-gate 		 * is released.
8840Sstevel@tonic-gate 		 */
8850Sstevel@tonic-gate 		eventp = busp->bus_slot_event_list_head;
8860Sstevel@tonic-gate 		slotp = eventp->slotp;
8870Sstevel@tonic-gate 		event = eventp->event;
8880Sstevel@tonic-gate 		func = slotp->slot_event_handler;
8890Sstevel@tonic-gate 		arg = slotp->slot_event_handler_arg;
8900Sstevel@tonic-gate 		busp->bus_slot_event_list_head = eventp->next;
8910Sstevel@tonic-gate 		hpc_free_event_entry(eventp);
8920Sstevel@tonic-gate 		mutex_exit(&busp->bus_mutex);
8930Sstevel@tonic-gate 		func(arg, event);
8940Sstevel@tonic-gate 		mutex_enter(&busp->bus_mutex);
8950Sstevel@tonic-gate 
8960Sstevel@tonic-gate 		if (busp->bus_thread_exit)
8970Sstevel@tonic-gate 			break;
8980Sstevel@tonic-gate 	}
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	DEBUG0("hpc_slot_event_dispatcher: thread_exit");
9010Sstevel@tonic-gate 	cv_signal(&busp->bus_thread_cv);
9020Sstevel@tonic-gate 	CALLB_CPR_EXIT(&cprinfo);
9030Sstevel@tonic-gate 	thread_exit();
9040Sstevel@tonic-gate }
9050Sstevel@tonic-gate 
9060Sstevel@tonic-gate 
9070Sstevel@tonic-gate static hpc_bus_entry_t *
hpc_find_bus_by_name(char * path)9080Sstevel@tonic-gate hpc_find_bus_by_name(char *path)
9090Sstevel@tonic-gate {
9100Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
9110Sstevel@tonic-gate 
9120Sstevel@tonic-gate 	for (busp = hpc_bus_list_head; busp != NULL; busp = busp->bus_next) {
9130Sstevel@tonic-gate 		if (strcmp(path, busp->bus_name) == 0)
9140Sstevel@tonic-gate 			break;
9150Sstevel@tonic-gate 	}
9160Sstevel@tonic-gate 	return (busp);
9170Sstevel@tonic-gate }
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate boolean_t
hpc_bus_registered(hpc_slot_t slot_hdl)9200Sstevel@tonic-gate hpc_bus_registered(hpc_slot_t slot_hdl)
9210Sstevel@tonic-gate {
9220Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
9230Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
9240Sstevel@tonic-gate 
9250Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)slot_hdl;
9260Sstevel@tonic-gate 	busp = slotp->slot_bus;
9270Sstevel@tonic-gate 	return (busp->bus_registered);
9280Sstevel@tonic-gate }
9290Sstevel@tonic-gate 
9300Sstevel@tonic-gate 
9310Sstevel@tonic-gate #ifdef DEBUG
9320Sstevel@tonic-gate 
9330Sstevel@tonic-gate extern void prom_printf(const char *, ...);
9340Sstevel@tonic-gate 
9350Sstevel@tonic-gate static void
debug(char * fmt,uintptr_t a1,uintptr_t a2,uintptr_t a3,uintptr_t a4,uintptr_t a5)9360Sstevel@tonic-gate debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
9370Sstevel@tonic-gate     uintptr_t a4, uintptr_t a5)
9380Sstevel@tonic-gate {
9390Sstevel@tonic-gate 	if (hpcsvc_debug != 0) {
9400Sstevel@tonic-gate 		cmn_err(CE_CONT, "hpcsvc: ");
9410Sstevel@tonic-gate 		cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
9420Sstevel@tonic-gate 		cmn_err(CE_CONT, "\n");
9430Sstevel@tonic-gate 	}
9440Sstevel@tonic-gate }
9450Sstevel@tonic-gate #endif
946