xref: /onnv-gate/usr/src/uts/common/io/hotplug/hpcsvc/hpcsvc.c (revision 0:68f95e015346)
1*0Sstevel@tonic-gate /*
2*0Sstevel@tonic-gate  * CDDL HEADER START
3*0Sstevel@tonic-gate  *
4*0Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*0Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*0Sstevel@tonic-gate  * with the License.
8*0Sstevel@tonic-gate  *
9*0Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*0Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*0Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*0Sstevel@tonic-gate  * and limitations under the License.
13*0Sstevel@tonic-gate  *
14*0Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*0Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*0Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*0Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*0Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*0Sstevel@tonic-gate  *
20*0Sstevel@tonic-gate  * CDDL HEADER END
21*0Sstevel@tonic-gate  */
22*0Sstevel@tonic-gate /*
23*0Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*0Sstevel@tonic-gate  * Use is subject to license terms.
25*0Sstevel@tonic-gate  */
26*0Sstevel@tonic-gate 
27*0Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*0Sstevel@tonic-gate 
29*0Sstevel@tonic-gate /*
30*0Sstevel@tonic-gate  * hot-plug services module
31*0Sstevel@tonic-gate  */
32*0Sstevel@tonic-gate 
33*0Sstevel@tonic-gate #include <sys/modctl.h>
34*0Sstevel@tonic-gate #include <sys/kmem.h>
35*0Sstevel@tonic-gate #include <sys/sunddi.h>
36*0Sstevel@tonic-gate #include <sys/sunndi.h>
37*0Sstevel@tonic-gate #include <sys/disp.h>
38*0Sstevel@tonic-gate #include <sys/stat.h>
39*0Sstevel@tonic-gate #include <sys/hotplug/hpcsvc.h>
40*0Sstevel@tonic-gate #include <sys/callb.h>
41*0Sstevel@tonic-gate 
42*0Sstevel@tonic-gate /*
43*0Sstevel@tonic-gate  * debug macros:
44*0Sstevel@tonic-gate  */
45*0Sstevel@tonic-gate #if defined(DEBUG)
46*0Sstevel@tonic-gate 
47*0Sstevel@tonic-gate int hpcsvc_debug = 0;
48*0Sstevel@tonic-gate 
49*0Sstevel@tonic-gate static void debug(char *, uintptr_t, uintptr_t, uintptr_t,
50*0Sstevel@tonic-gate 	uintptr_t, uintptr_t);
51*0Sstevel@tonic-gate 
52*0Sstevel@tonic-gate #define	DEBUG0(fmt)	\
53*0Sstevel@tonic-gate 	debug(fmt, 0, 0, 0, 0, 0);
54*0Sstevel@tonic-gate #define	DEBUG1(fmt, a1)	\
55*0Sstevel@tonic-gate 	debug(fmt, (uintptr_t)(a1), 0, 0, 0, 0);
56*0Sstevel@tonic-gate #define	DEBUG2(fmt, a1, a2)	\
57*0Sstevel@tonic-gate 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), 0, 0, 0);
58*0Sstevel@tonic-gate #define	DEBUG3(fmt, a1, a2, a3)	\
59*0Sstevel@tonic-gate 	debug(fmt, (uintptr_t)(a1), (uintptr_t)(a2), (uintptr_t)(a3), 0, 0);
60*0Sstevel@tonic-gate #else
61*0Sstevel@tonic-gate #define	DEBUG0(fmt)
62*0Sstevel@tonic-gate #define	DEBUG1(fmt, a1)
63*0Sstevel@tonic-gate #define	DEBUG2(fmt, a1, a2)
64*0Sstevel@tonic-gate #define	DEBUG3(fmt, a1, a2, a3)
65*0Sstevel@tonic-gate #endif
66*0Sstevel@tonic-gate 
67*0Sstevel@tonic-gate /*
68*0Sstevel@tonic-gate  * Definitions for the bus node registration list:
69*0Sstevel@tonic-gate  *
70*0Sstevel@tonic-gate  * The hot-plug service module maintains a linked list of items
71*0Sstevel@tonic-gate  * representing the device bus nodes that have been registered via
72*0Sstevel@tonic-gate  * hpc_nexus_register, or identified as candidates for registration
73*0Sstevel@tonic-gate  * by the bus argument to hpc_slot_register.
74*0Sstevel@tonic-gate  *
75*0Sstevel@tonic-gate  * The head of the linked listed is stored in hpc_bus_list_head. Insertions
76*0Sstevel@tonic-gate  * and removals from the list should be locked with mutex hpc_bus_mutex.
77*0Sstevel@tonic-gate  *
78*0Sstevel@tonic-gate  * Items in the list are allocated/freed with the macros hpc_alloc_bus_entry()
79*0Sstevel@tonic-gate  * and hpc_free_bus_entry().
80*0Sstevel@tonic-gate  *
81*0Sstevel@tonic-gate  * Each item in the list contains the following fields:
82*0Sstevel@tonic-gate  *
83*0Sstevel@tonic-gate  *	bus_dip - pointer to devinfo node of the registering bus
84*0Sstevel@tonic-gate  *
85*0Sstevel@tonic-gate  *	bus_name - device path name of the bus (ie /pci@1f,4000)
86*0Sstevel@tonic-gate  *
87*0Sstevel@tonic-gate  *	bus_callback - bus nexus driver callback function registered
88*0Sstevel@tonic-gate  *		with the bus
89*0Sstevel@tonic-gate  *
90*0Sstevel@tonic-gate  *	bus_registered - a boolean value which is true if the bus has
91*0Sstevel@tonic-gate  *		been registered with hpc_nexus_register, false otherwise
92*0Sstevel@tonic-gate  *
93*0Sstevel@tonic-gate  *	bus_mutex - mutex lock to be held while updating this list entry
94*0Sstevel@tonic-gate  *
95*0Sstevel@tonic-gate  *	bus_slot_list - linked list of the slots registered for this
96*0Sstevel@tonic-gate  *		bus node (see slot list details below)
97*0Sstevel@tonic-gate  *
98*0Sstevel@tonic-gate  *	bus_thread - kernel thread for running slot event handlers for
99*0Sstevel@tonic-gate  *		slots associated with this bus
100*0Sstevel@tonic-gate  *
101*0Sstevel@tonic-gate  *	bus_thread_cv - condition variable for synchronization between
102*0Sstevel@tonic-gate  *		the service routines and the thread for running slot
103*0Sstevel@tonic-gate  *		event handlers
104*0Sstevel@tonic-gate  *
105*0Sstevel@tonic-gate  *	bus_thread_exit - a boolean value used to instruct the thread
106*0Sstevel@tonic-gate  *		for invoking the slot event handlers to exit
107*0Sstevel@tonic-gate  *
108*0Sstevel@tonic-gate  *	bus_slot_event_list_head - the head of the linked list of instances
109*0Sstevel@tonic-gate  *		of slot event handlers to be run
110*0Sstevel@tonic-gate  *		handlers to be invoked
111*0Sstevel@tonic-gate  *
112*0Sstevel@tonic-gate  *	bus_next - pointer to next list entry
113*0Sstevel@tonic-gate  */
114*0Sstevel@tonic-gate 
115*0Sstevel@tonic-gate typedef struct hpc_bus_entry hpc_bus_entry_t;
116*0Sstevel@tonic-gate typedef struct hpc_slot_entry hpc_slot_entry_t;
117*0Sstevel@tonic-gate typedef struct hpc_event_entry hpc_event_entry_t;
118*0Sstevel@tonic-gate 
119*0Sstevel@tonic-gate struct hpc_event_entry {
120*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
121*0Sstevel@tonic-gate 	int event;
122*0Sstevel@tonic-gate 	hpc_event_entry_t *next;
123*0Sstevel@tonic-gate };
124*0Sstevel@tonic-gate 
125*0Sstevel@tonic-gate #define	hpc_alloc_event_entry()	\
126*0Sstevel@tonic-gate 	(hpc_event_entry_t *)kmem_zalloc(sizeof (hpc_event_entry_t), KM_SLEEP)
127*0Sstevel@tonic-gate 
128*0Sstevel@tonic-gate #define	hpc_free_event_entry(a)	\
129*0Sstevel@tonic-gate 	kmem_free((a), sizeof (hpc_event_entry_t))
130*0Sstevel@tonic-gate 
131*0Sstevel@tonic-gate struct hpc_bus_entry {
132*0Sstevel@tonic-gate 	dev_info_t *bus_dip;
133*0Sstevel@tonic-gate 	char bus_name[MAXPATHLEN + 1];
134*0Sstevel@tonic-gate 	boolean_t bus_registered;
135*0Sstevel@tonic-gate 	kmutex_t bus_mutex;
136*0Sstevel@tonic-gate 	int (* bus_callback)(dev_info_t *dip, hpc_slot_t hdl,
137*0Sstevel@tonic-gate 		hpc_slot_info_t *slot_info, int slot_state);
138*0Sstevel@tonic-gate 	hpc_slot_entry_t *bus_slot_list;
139*0Sstevel@tonic-gate 	kthread_t *bus_thread;
140*0Sstevel@tonic-gate 	kcondvar_t bus_thread_cv;
141*0Sstevel@tonic-gate 	boolean_t bus_thread_exit;
142*0Sstevel@tonic-gate 	hpc_event_entry_t *bus_slot_event_list_head;
143*0Sstevel@tonic-gate 	hpc_bus_entry_t *bus_next;
144*0Sstevel@tonic-gate };
145*0Sstevel@tonic-gate 
146*0Sstevel@tonic-gate #define	hpc_alloc_bus_entry()	\
147*0Sstevel@tonic-gate 	(hpc_bus_entry_t *)kmem_zalloc(sizeof (hpc_bus_entry_t), KM_SLEEP)
148*0Sstevel@tonic-gate 
149*0Sstevel@tonic-gate #define	hpc_free_bus_entry(a)	\
150*0Sstevel@tonic-gate 	kmem_free((a), sizeof (hpc_bus_entry_t))
151*0Sstevel@tonic-gate 
152*0Sstevel@tonic-gate 
153*0Sstevel@tonic-gate /*
154*0Sstevel@tonic-gate  * Definitions for the per-bus node slot registration list:
155*0Sstevel@tonic-gate  *
156*0Sstevel@tonic-gate  * For each bus node in the bus list, the hot-plug service module maintains
157*0Sstevel@tonic-gate  * a doubly linked link list of items representing the slots that have been
158*0Sstevel@tonic-gate  * registered (by hot-plug controllers) for that bus.
159*0Sstevel@tonic-gate  *
160*0Sstevel@tonic-gate  * The head of the linked listed is stored in bus_slot_list field of the bus
161*0Sstevel@tonic-gate  * node.  Insertions and removals from this list should locked with the mutex
162*0Sstevel@tonic-gate  * in the bus_mutex field of the bus node.
163*0Sstevel@tonic-gate  *
164*0Sstevel@tonic-gate  * Items in the list are allocated/freed with the macros hpc_alloc_slot_entry()
165*0Sstevel@tonic-gate  * and hpc_free_slot_entry().
166*0Sstevel@tonic-gate  *
167*0Sstevel@tonic-gate  * Each item in the list contains the following fields:
168*0Sstevel@tonic-gate  *
169*0Sstevel@tonic-gate  *	slot_handle - handle for slot (hpc_slot_t)
170*0Sstevel@tonic-gate  *
171*0Sstevel@tonic-gate  *	slot_info - information registered with the slot (hpc_slot_info_t)
172*0Sstevel@tonic-gate  *
173*0Sstevel@tonic-gate  *	slot_ops - ops vector registered with the slot (hpc_slot_ops_t)
174*0Sstevel@tonic-gate  *
175*0Sstevel@tonic-gate  *	slot_ops_arg - argument to be passed to ops routines (caddr_t)
176*0Sstevel@tonic-gate  *
177*0Sstevel@tonic-gate  *	slot_event_handler - handler registered for slot events
178*0Sstevel@tonic-gate  *
179*0Sstevel@tonic-gate  *	slot_event_handler_arg - argument to be passed to event handler
180*0Sstevel@tonic-gate  *
181*0Sstevel@tonic-gate  *	slot_event_mask - the set of events for which the event handler
182*0Sstevel@tonic-gate  *		gets invoked
183*0Sstevel@tonic-gate  *
184*0Sstevel@tonic-gate  *	slot_bus - pointer to bus node for the slot
185*0Sstevel@tonic-gate  *
186*0Sstevel@tonic-gate  *	slot_hpc_dip  -  devinfo node pointer to the HPC driver instance
187*0Sstevel@tonic-gate  *			 that controls this slot
188*0Sstevel@tonic-gate  *
189*0Sstevel@tonic-gate  *	slot_{prev,next} - point to {previous,next} node in the list
190*0Sstevel@tonic-gate  */
191*0Sstevel@tonic-gate 
192*0Sstevel@tonic-gate struct hpc_slot_entry {
193*0Sstevel@tonic-gate 	hpc_slot_t slot_handle;
194*0Sstevel@tonic-gate 	hpc_slot_info_t slot_info;	/* should be static & copied */
195*0Sstevel@tonic-gate 	hpc_slot_ops_t slot_ops;
196*0Sstevel@tonic-gate 	caddr_t slot_ops_arg;
197*0Sstevel@tonic-gate 	int (* slot_event_handler)(caddr_t, uint_t);
198*0Sstevel@tonic-gate 	caddr_t slot_event_handler_arg;
199*0Sstevel@tonic-gate 	uint_t slot_event_mask;
200*0Sstevel@tonic-gate 	hpc_bus_entry_t *slot_bus;
201*0Sstevel@tonic-gate 	dev_info_t *slot_hpc_dip;
202*0Sstevel@tonic-gate 	hpc_slot_entry_t *slot_next, *slot_prev;
203*0Sstevel@tonic-gate };
204*0Sstevel@tonic-gate 
205*0Sstevel@tonic-gate #define	hpc_alloc_slot_entry()	\
206*0Sstevel@tonic-gate 	(hpc_slot_entry_t *)kmem_zalloc(sizeof (hpc_slot_entry_t), KM_SLEEP)
207*0Sstevel@tonic-gate 
208*0Sstevel@tonic-gate #define	hpc_free_slot_entry(a)	\
209*0Sstevel@tonic-gate 	kmem_free((a), sizeof (hpc_slot_entry_t))
210*0Sstevel@tonic-gate 
211*0Sstevel@tonic-gate 
212*0Sstevel@tonic-gate /*
213*0Sstevel@tonic-gate  * Definitions for slot registration callback table.
214*0Sstevel@tonic-gate  */
215*0Sstevel@tonic-gate 
216*0Sstevel@tonic-gate typedef struct hpc_callback_entry hpc_callback_entry_t;
217*0Sstevel@tonic-gate 
218*0Sstevel@tonic-gate struct hpc_callback_entry {
219*0Sstevel@tonic-gate 	int (* callback)(dev_info_t *dip, hpc_slot_t hdl,
220*0Sstevel@tonic-gate 		hpc_slot_info_t *slot_info, int slot_state);
221*0Sstevel@tonic-gate 	dev_info_t *dip;
222*0Sstevel@tonic-gate 	hpc_slot_t hdl;
223*0Sstevel@tonic-gate 	hpc_slot_info_t *slot_info;
224*0Sstevel@tonic-gate 	int slot_state;
225*0Sstevel@tonic-gate 	hpc_callback_entry_t *next;
226*0Sstevel@tonic-gate };
227*0Sstevel@tonic-gate 
228*0Sstevel@tonic-gate #define	hpc_alloc_callback_entry()	\
229*0Sstevel@tonic-gate 	(hpc_callback_entry_t *)	\
230*0Sstevel@tonic-gate 		kmem_zalloc(sizeof (hpc_callback_entry_t), KM_SLEEP)
231*0Sstevel@tonic-gate 
232*0Sstevel@tonic-gate #define	hpc_free_callback_entry(a)	\
233*0Sstevel@tonic-gate 	kmem_free((a), sizeof (hpc_callback_entry_t))
234*0Sstevel@tonic-gate 
235*0Sstevel@tonic-gate 
236*0Sstevel@tonic-gate 
237*0Sstevel@tonic-gate /*
238*0Sstevel@tonic-gate  * Mutex lock for bus registration table and table head.
239*0Sstevel@tonic-gate  */
240*0Sstevel@tonic-gate static kmutex_t hpc_bus_mutex;
241*0Sstevel@tonic-gate static hpc_bus_entry_t *hpc_bus_list_head;
242*0Sstevel@tonic-gate 
243*0Sstevel@tonic-gate 
244*0Sstevel@tonic-gate /*
245*0Sstevel@tonic-gate  * Forward function declarations.
246*0Sstevel@tonic-gate  */
247*0Sstevel@tonic-gate static hpc_bus_entry_t *hpc_find_bus_by_name(char *name);
248*0Sstevel@tonic-gate static void hpc_slot_event_dispatcher(hpc_bus_entry_t *busp);
249*0Sstevel@tonic-gate 
250*0Sstevel@tonic-gate 
251*0Sstevel@tonic-gate /*
252*0Sstevel@tonic-gate  * loadable module definitions:
253*0Sstevel@tonic-gate  */
254*0Sstevel@tonic-gate extern struct mod_ops mod_miscops;
255*0Sstevel@tonic-gate 
256*0Sstevel@tonic-gate static struct modlmisc modlmisc = {
257*0Sstevel@tonic-gate 	&mod_miscops,	/* Type of module */
258*0Sstevel@tonic-gate 	"hot-plug controller services v%I%"
259*0Sstevel@tonic-gate };
260*0Sstevel@tonic-gate 
261*0Sstevel@tonic-gate static struct modlinkage modlinkage = {
262*0Sstevel@tonic-gate 	MODREV_1, (void *)&modlmisc, NULL
263*0Sstevel@tonic-gate };
264*0Sstevel@tonic-gate 
265*0Sstevel@tonic-gate int
266*0Sstevel@tonic-gate _init(void)
267*0Sstevel@tonic-gate {
268*0Sstevel@tonic-gate 	int e;
269*0Sstevel@tonic-gate 
270*0Sstevel@tonic-gate 	mutex_init(&hpc_bus_mutex, NULL, MUTEX_DRIVER, NULL);
271*0Sstevel@tonic-gate 
272*0Sstevel@tonic-gate 	/*
273*0Sstevel@tonic-gate 	 * Install the module.
274*0Sstevel@tonic-gate 	 */
275*0Sstevel@tonic-gate 	e = mod_install(&modlinkage);
276*0Sstevel@tonic-gate 	if (e != 0) {
277*0Sstevel@tonic-gate 		mutex_destroy(&hpc_bus_mutex);
278*0Sstevel@tonic-gate 	}
279*0Sstevel@tonic-gate 	return (e);
280*0Sstevel@tonic-gate }
281*0Sstevel@tonic-gate 
282*0Sstevel@tonic-gate int
283*0Sstevel@tonic-gate _fini(void)
284*0Sstevel@tonic-gate {
285*0Sstevel@tonic-gate 	int e;
286*0Sstevel@tonic-gate 
287*0Sstevel@tonic-gate 	e = mod_remove(&modlinkage);
288*0Sstevel@tonic-gate 	if (e == 0) {
289*0Sstevel@tonic-gate 		mutex_destroy(&hpc_bus_mutex);
290*0Sstevel@tonic-gate 	}
291*0Sstevel@tonic-gate 	return (e);
292*0Sstevel@tonic-gate }
293*0Sstevel@tonic-gate 
294*0Sstevel@tonic-gate int
295*0Sstevel@tonic-gate _info(struct modinfo *modinfop)
296*0Sstevel@tonic-gate {
297*0Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
298*0Sstevel@tonic-gate }
299*0Sstevel@tonic-gate 
300*0Sstevel@tonic-gate 
301*0Sstevel@tonic-gate 
302*0Sstevel@tonic-gate hpc_slot_ops_t *
303*0Sstevel@tonic-gate hpc_alloc_slot_ops(int flag)
304*0Sstevel@tonic-gate {
305*0Sstevel@tonic-gate 	hpc_slot_ops_t *ops;
306*0Sstevel@tonic-gate 
307*0Sstevel@tonic-gate 	ops = (hpc_slot_ops_t *)kmem_zalloc(sizeof (hpc_slot_ops_t), flag);
308*0Sstevel@tonic-gate 	return (ops);
309*0Sstevel@tonic-gate }
310*0Sstevel@tonic-gate 
311*0Sstevel@tonic-gate 
312*0Sstevel@tonic-gate void
313*0Sstevel@tonic-gate hpc_free_slot_ops(hpc_slot_ops_t *ops)
314*0Sstevel@tonic-gate {
315*0Sstevel@tonic-gate 	kmem_free((void *)ops, sizeof (hpc_slot_ops_t));
316*0Sstevel@tonic-gate }
317*0Sstevel@tonic-gate 
318*0Sstevel@tonic-gate 
319*0Sstevel@tonic-gate /*ARGSUSED2*/
320*0Sstevel@tonic-gate int
321*0Sstevel@tonic-gate hpc_nexus_register_bus(dev_info_t *dip,
322*0Sstevel@tonic-gate 	int (* callback)(dev_info_t *dip, hpc_slot_t hdl,
323*0Sstevel@tonic-gate 	hpc_slot_info_t *slot_info, int slot_state), uint_t flags)
324*0Sstevel@tonic-gate {
325*0Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
326*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
327*0Sstevel@tonic-gate 	char bus_path[MAXPATHLEN + 1];
328*0Sstevel@tonic-gate 
329*0Sstevel@tonic-gate 	DEBUG2("hpc_nexus_register_bus: %s%d",
330*0Sstevel@tonic-gate 	    ddi_node_name(dip), ddi_get_instance(dip));
331*0Sstevel@tonic-gate 	mutex_enter(&hpc_bus_mutex);
332*0Sstevel@tonic-gate 	(void) ddi_pathname(dip, bus_path);
333*0Sstevel@tonic-gate 	busp = hpc_find_bus_by_name(bus_path);
334*0Sstevel@tonic-gate 	if (busp == NULL) {
335*0Sstevel@tonic-gate 
336*0Sstevel@tonic-gate 		/*
337*0Sstevel@tonic-gate 		 * Initialize the new bus node and link it at the head
338*0Sstevel@tonic-gate 		 * of the bus list.
339*0Sstevel@tonic-gate 		 */
340*0Sstevel@tonic-gate 		DEBUG0("hpc_nexus_register_bus: not in bus list");
341*0Sstevel@tonic-gate 		busp = hpc_alloc_bus_entry();
342*0Sstevel@tonic-gate 		busp->bus_dip = dip;
343*0Sstevel@tonic-gate 		busp->bus_registered = B_TRUE;
344*0Sstevel@tonic-gate 		(void) strcpy(busp->bus_name, bus_path);
345*0Sstevel@tonic-gate 		mutex_init(&busp->bus_mutex, NULL, MUTEX_DRIVER, NULL);
346*0Sstevel@tonic-gate 		busp->bus_callback = callback;
347*0Sstevel@tonic-gate 		busp->bus_slot_list = NULL;
348*0Sstevel@tonic-gate 		busp->bus_next = hpc_bus_list_head;
349*0Sstevel@tonic-gate 		hpc_bus_list_head = busp;
350*0Sstevel@tonic-gate 
351*0Sstevel@tonic-gate 	} else {
352*0Sstevel@tonic-gate 
353*0Sstevel@tonic-gate 		/*
354*0Sstevel@tonic-gate 		 * The bus is in the bus list but isn't registered yet.
355*0Sstevel@tonic-gate 		 * Mark it as registered, and run the registration callbacks
356*0Sstevel@tonic-gate 		 * for it slots.
357*0Sstevel@tonic-gate 		 */
358*0Sstevel@tonic-gate 		DEBUG0("hpc_nexus_register_bus: in list, but not registered");
359*0Sstevel@tonic-gate 		mutex_enter(&busp->bus_mutex);
360*0Sstevel@tonic-gate 		if (busp->bus_registered == B_TRUE) {
361*0Sstevel@tonic-gate 			mutex_exit(&busp->bus_mutex);
362*0Sstevel@tonic-gate 			mutex_exit(&hpc_bus_mutex);
363*0Sstevel@tonic-gate 			return (HPC_ERR_BUS_DUPLICATE);
364*0Sstevel@tonic-gate 		}
365*0Sstevel@tonic-gate 		busp->bus_dip = dip;
366*0Sstevel@tonic-gate 		busp->bus_callback = callback;
367*0Sstevel@tonic-gate 		busp->bus_registered = B_TRUE;
368*0Sstevel@tonic-gate 
369*0Sstevel@tonic-gate 		mutex_exit(&busp->bus_mutex);
370*0Sstevel@tonic-gate 		mutex_exit(&hpc_bus_mutex);
371*0Sstevel@tonic-gate 		if (callback) {
372*0Sstevel@tonic-gate 			DEBUG0("hpc_nexus_register_bus: running callbacks");
373*0Sstevel@tonic-gate 			for (slotp = busp->bus_slot_list; slotp;
374*0Sstevel@tonic-gate 			    slotp = slotp->slot_next) {
375*0Sstevel@tonic-gate 				(void) callback(dip, slotp, &slotp->slot_info,
376*0Sstevel@tonic-gate 				    HPC_SLOT_ONLINE);
377*0Sstevel@tonic-gate 			}
378*0Sstevel@tonic-gate 		}
379*0Sstevel@tonic-gate 		return (HPC_SUCCESS);
380*0Sstevel@tonic-gate 	}
381*0Sstevel@tonic-gate 	mutex_exit(&hpc_bus_mutex);
382*0Sstevel@tonic-gate 	return (HPC_SUCCESS);
383*0Sstevel@tonic-gate }
384*0Sstevel@tonic-gate 
385*0Sstevel@tonic-gate 
386*0Sstevel@tonic-gate int
387*0Sstevel@tonic-gate hpc_nexus_unregister_bus(dev_info_t *dip)
388*0Sstevel@tonic-gate {
389*0Sstevel@tonic-gate 	hpc_bus_entry_t *busp, *busp_prev;
390*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
391*0Sstevel@tonic-gate 
392*0Sstevel@tonic-gate 	/*
393*0Sstevel@tonic-gate 	 * Search the list for the bus node and remove it.
394*0Sstevel@tonic-gate 	 */
395*0Sstevel@tonic-gate 	DEBUG2("hpc_nexus_unregister_bus: %s%d",
396*0Sstevel@tonic-gate 	    ddi_node_name(dip), ddi_get_instance(dip));
397*0Sstevel@tonic-gate 	mutex_enter(&hpc_bus_mutex);
398*0Sstevel@tonic-gate 	for (busp = hpc_bus_list_head; busp != NULL; busp_prev = busp,
399*0Sstevel@tonic-gate 	    busp = busp->bus_next) {
400*0Sstevel@tonic-gate 		if (busp->bus_dip == dip)
401*0Sstevel@tonic-gate 			break;
402*0Sstevel@tonic-gate 	}
403*0Sstevel@tonic-gate 	if (busp == NULL) {
404*0Sstevel@tonic-gate 		mutex_exit(&hpc_bus_mutex);
405*0Sstevel@tonic-gate 		return (HPC_ERR_BUS_NOTREGISTERED);
406*0Sstevel@tonic-gate 	}
407*0Sstevel@tonic-gate 
408*0Sstevel@tonic-gate 	/*
409*0Sstevel@tonic-gate 	 * If the bus has slots, mark the bus as unregistered, otherwise
410*0Sstevel@tonic-gate 	 * remove the bus entry from the list.
411*0Sstevel@tonic-gate 	 */
412*0Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
413*0Sstevel@tonic-gate 	if (busp->bus_slot_list == NULL) {
414*0Sstevel@tonic-gate 		if (busp == hpc_bus_list_head)
415*0Sstevel@tonic-gate 			hpc_bus_list_head = busp->bus_next;
416*0Sstevel@tonic-gate 		else
417*0Sstevel@tonic-gate 			busp_prev->bus_next = busp->bus_next;
418*0Sstevel@tonic-gate 		mutex_exit(&busp->bus_mutex);
419*0Sstevel@tonic-gate 		mutex_destroy(&busp->bus_mutex);
420*0Sstevel@tonic-gate 		hpc_free_bus_entry(busp);
421*0Sstevel@tonic-gate 		mutex_exit(&hpc_bus_mutex);
422*0Sstevel@tonic-gate 		return (HPC_SUCCESS);
423*0Sstevel@tonic-gate 	}
424*0Sstevel@tonic-gate 
425*0Sstevel@tonic-gate 	/*
426*0Sstevel@tonic-gate 	 * unregister event handlers for all the slots on this bus.
427*0Sstevel@tonic-gate 	 */
428*0Sstevel@tonic-gate 	for (slotp = busp->bus_slot_list; slotp != NULL;
429*0Sstevel@tonic-gate 		slotp = slotp->slot_next) {
430*0Sstevel@tonic-gate 		slotp->slot_event_handler = NULL;
431*0Sstevel@tonic-gate 		slotp->slot_event_handler_arg = NULL;
432*0Sstevel@tonic-gate 	}
433*0Sstevel@tonic-gate 	busp->bus_registered = B_FALSE;
434*0Sstevel@tonic-gate 	mutex_exit(&busp->bus_mutex);
435*0Sstevel@tonic-gate 	mutex_exit(&hpc_bus_mutex);
436*0Sstevel@tonic-gate 	return (HPC_SUCCESS);
437*0Sstevel@tonic-gate }
438*0Sstevel@tonic-gate 
439*0Sstevel@tonic-gate 
440*0Sstevel@tonic-gate /*ARGSUSED5*/
441*0Sstevel@tonic-gate int
442*0Sstevel@tonic-gate hpc_slot_register(dev_info_t *hpc_dip, char *bus, hpc_slot_info_t *infop,
443*0Sstevel@tonic-gate 	hpc_slot_t *handlep, hpc_slot_ops_t *opsp,
444*0Sstevel@tonic-gate 	caddr_t ops_arg, uint_t flags)
445*0Sstevel@tonic-gate {
446*0Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
447*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp, *slot_list_head;
448*0Sstevel@tonic-gate 	boolean_t run_callback = B_FALSE;
449*0Sstevel@tonic-gate 	int (* callback)(dev_info_t *dip, hpc_slot_t hdl,
450*0Sstevel@tonic-gate 		hpc_slot_info_t *slot_info, int slot_state);
451*0Sstevel@tonic-gate 	dev_info_t *dip;
452*0Sstevel@tonic-gate 	kthread_t *t;
453*0Sstevel@tonic-gate 
454*0Sstevel@tonic-gate 	/*
455*0Sstevel@tonic-gate 	 * Validate the arguments.
456*0Sstevel@tonic-gate 	 */
457*0Sstevel@tonic-gate 	DEBUG1("hpc_slot_register: %s", bus);
458*0Sstevel@tonic-gate 	if (handlep == NULL || infop == NULL || opsp == NULL || hpc_dip == NULL)
459*0Sstevel@tonic-gate 		return (HPC_ERR_INVALID);
460*0Sstevel@tonic-gate 
461*0Sstevel@tonic-gate 	/*
462*0Sstevel@tonic-gate 	 * The bus for the slot may or may not be in the bus list.  If it's
463*0Sstevel@tonic-gate 	 * not, we create a node for the bus in the bus list and mark it as
464*0Sstevel@tonic-gate 	 * not registered.
465*0Sstevel@tonic-gate 	 */
466*0Sstevel@tonic-gate 	mutex_enter(&hpc_bus_mutex);
467*0Sstevel@tonic-gate 	busp = hpc_find_bus_by_name(bus);
468*0Sstevel@tonic-gate 	if (busp == NULL) {
469*0Sstevel@tonic-gate 
470*0Sstevel@tonic-gate 		/*
471*0Sstevel@tonic-gate 		 * Initialize the new bus node and link it at the
472*0Sstevel@tonic-gate 		 * head of the bus list.
473*0Sstevel@tonic-gate 		 */
474*0Sstevel@tonic-gate 		DEBUG1("hpc_slot_register: %s not in bus list", bus);
475*0Sstevel@tonic-gate 		busp = hpc_alloc_bus_entry();
476*0Sstevel@tonic-gate 		busp->bus_registered = B_FALSE;
477*0Sstevel@tonic-gate 		(void) strcpy(busp->bus_name, bus);
478*0Sstevel@tonic-gate 		mutex_init(&busp->bus_mutex, NULL, MUTEX_DRIVER, NULL);
479*0Sstevel@tonic-gate 		busp->bus_slot_list = NULL;
480*0Sstevel@tonic-gate 		busp->bus_next = hpc_bus_list_head;
481*0Sstevel@tonic-gate 		hpc_bus_list_head = busp;
482*0Sstevel@tonic-gate 
483*0Sstevel@tonic-gate 	} else {
484*0Sstevel@tonic-gate 		if (busp->bus_registered == B_TRUE) {
485*0Sstevel@tonic-gate 			run_callback = B_TRUE;
486*0Sstevel@tonic-gate 			callback = busp->bus_callback;
487*0Sstevel@tonic-gate 			dip = busp->bus_dip;
488*0Sstevel@tonic-gate 		}
489*0Sstevel@tonic-gate 	}
490*0Sstevel@tonic-gate 
491*0Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
492*0Sstevel@tonic-gate 	slot_list_head = busp->bus_slot_list;
493*0Sstevel@tonic-gate 	if (slot_list_head == NULL) {
494*0Sstevel@tonic-gate 
495*0Sstevel@tonic-gate 		/*
496*0Sstevel@tonic-gate 		 * The slot list was empty, so this is the first slot
497*0Sstevel@tonic-gate 		 * registered for the bus.  Create a per-bus thread
498*0Sstevel@tonic-gate 		 * for running the slot event handlers.
499*0Sstevel@tonic-gate 		 */
500*0Sstevel@tonic-gate 		DEBUG0("hpc_slot_register: creating event callback thread");
501*0Sstevel@tonic-gate 		cv_init(&busp->bus_thread_cv, NULL, CV_DRIVER, NULL);
502*0Sstevel@tonic-gate 		busp->bus_thread_exit = B_FALSE;
503*0Sstevel@tonic-gate 		t = thread_create(NULL, 0, hpc_slot_event_dispatcher,
504*0Sstevel@tonic-gate 		    (caddr_t)busp, 0, &p0, TS_RUN, minclsyspri);
505*0Sstevel@tonic-gate 		busp->bus_thread = t;
506*0Sstevel@tonic-gate 	}
507*0Sstevel@tonic-gate 
508*0Sstevel@tonic-gate 	/*
509*0Sstevel@tonic-gate 	 * Create and initialize a new entry in the slot list for the bus.
510*0Sstevel@tonic-gate 	 */
511*0Sstevel@tonic-gate 	slotp = hpc_alloc_slot_entry();
512*0Sstevel@tonic-gate 	slotp->slot_handle = (hpc_slot_t)slotp;
513*0Sstevel@tonic-gate 	slotp->slot_info = *infop;
514*0Sstevel@tonic-gate 	slotp->slot_ops = *opsp;
515*0Sstevel@tonic-gate 	slotp->slot_ops_arg = ops_arg;
516*0Sstevel@tonic-gate 	slotp->slot_bus = busp;
517*0Sstevel@tonic-gate 	slotp->slot_hpc_dip = hpc_dip;
518*0Sstevel@tonic-gate 	slotp->slot_prev = NULL;
519*0Sstevel@tonic-gate 	busp->bus_slot_list = slotp;
520*0Sstevel@tonic-gate 	slotp->slot_next = slot_list_head;
521*0Sstevel@tonic-gate 	if (slot_list_head != NULL)
522*0Sstevel@tonic-gate 		slot_list_head->slot_prev = slotp;
523*0Sstevel@tonic-gate 	mutex_exit(&busp->bus_mutex);
524*0Sstevel@tonic-gate 	mutex_exit(&hpc_bus_mutex);
525*0Sstevel@tonic-gate 
526*0Sstevel@tonic-gate 	/*
527*0Sstevel@tonic-gate 	 * Return the handle to the caller prior to return to avoid recursion.
528*0Sstevel@tonic-gate 	 */
529*0Sstevel@tonic-gate 	*handlep = (hpc_slot_t)slotp;
530*0Sstevel@tonic-gate 
531*0Sstevel@tonic-gate 	/*
532*0Sstevel@tonic-gate 	 * If the bus was registered, we run the callback registered by
533*0Sstevel@tonic-gate 	 * the bus node.
534*0Sstevel@tonic-gate 	 */
535*0Sstevel@tonic-gate 	if (run_callback) {
536*0Sstevel@tonic-gate 		DEBUG0("hpc_slot_register: running callback");
537*0Sstevel@tonic-gate 
538*0Sstevel@tonic-gate 		(void) callback(dip, slotp, infop, HPC_SLOT_ONLINE);
539*0Sstevel@tonic-gate 	}
540*0Sstevel@tonic-gate 
541*0Sstevel@tonic-gate 	/*
542*0Sstevel@tonic-gate 	 * Keep hpc driver in memory
543*0Sstevel@tonic-gate 	 */
544*0Sstevel@tonic-gate 	(void) ndi_hold_driver(hpc_dip);
545*0Sstevel@tonic-gate 
546*0Sstevel@tonic-gate 	return (HPC_SUCCESS);
547*0Sstevel@tonic-gate }
548*0Sstevel@tonic-gate 
549*0Sstevel@tonic-gate 
550*0Sstevel@tonic-gate int
551*0Sstevel@tonic-gate hpc_slot_unregister(hpc_slot_t *handlep)
552*0Sstevel@tonic-gate {
553*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
554*0Sstevel@tonic-gate 	hpc_bus_entry_t *busp, *busp_prev;
555*0Sstevel@tonic-gate 	boolean_t run_callback;
556*0Sstevel@tonic-gate 	int (* callback)(dev_info_t *dip, hpc_slot_t hdl,
557*0Sstevel@tonic-gate 		hpc_slot_info_t *slot_info, int slot_state);
558*0Sstevel@tonic-gate 	int r;
559*0Sstevel@tonic-gate 	dev_info_t *dip;
560*0Sstevel@tonic-gate 	char *bus_name;
561*0Sstevel@tonic-gate 
562*0Sstevel@tonic-gate 	DEBUG0("hpc_slot_unregister:");
563*0Sstevel@tonic-gate 
564*0Sstevel@tonic-gate 	ASSERT(handlep != NULL);
565*0Sstevel@tonic-gate 
566*0Sstevel@tonic-gate 	/* validate the handle */
567*0Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)*handlep;
568*0Sstevel@tonic-gate 	if ((slotp == NULL) || slotp->slot_handle != *handlep)
569*0Sstevel@tonic-gate 		return (HPC_ERR_INVALID);
570*0Sstevel@tonic-gate 
571*0Sstevel@tonic-gate 	/*
572*0Sstevel@tonic-gate 	 * Get the bus list entry from the slot to grap the mutex for
573*0Sstevel@tonic-gate 	 * the slot list of the bus.
574*0Sstevel@tonic-gate 	 */
575*0Sstevel@tonic-gate 	mutex_enter(&hpc_bus_mutex);
576*0Sstevel@tonic-gate 	busp = slotp->slot_bus;
577*0Sstevel@tonic-gate 	DEBUG2("hpc_slot_unregister: handlep=%x, slotp=%x", handlep, slotp);
578*0Sstevel@tonic-gate 	if (busp == NULL) {
579*0Sstevel@tonic-gate 		mutex_exit(&hpc_bus_mutex);
580*0Sstevel@tonic-gate 		return (HPC_ERR_SLOT_NOTREGISTERED);
581*0Sstevel@tonic-gate 	}
582*0Sstevel@tonic-gate 
583*0Sstevel@tonic-gate 	/*
584*0Sstevel@tonic-gate 	 * Determine if we need to run the slot offline callback and
585*0Sstevel@tonic-gate 	 * save the data necessary to do so.
586*0Sstevel@tonic-gate 	 */
587*0Sstevel@tonic-gate 	callback = busp->bus_callback;
588*0Sstevel@tonic-gate 	run_callback = (busp->bus_registered == B_TRUE) && (callback != NULL);
589*0Sstevel@tonic-gate 	dip = busp->bus_dip;
590*0Sstevel@tonic-gate 	bus_name = busp->bus_name;
591*0Sstevel@tonic-gate 
592*0Sstevel@tonic-gate 	/*
593*0Sstevel@tonic-gate 	 * Run the slot offline callback if necessary.
594*0Sstevel@tonic-gate 	 */
595*0Sstevel@tonic-gate 	if (run_callback) {
596*0Sstevel@tonic-gate 		mutex_exit(&hpc_bus_mutex);
597*0Sstevel@tonic-gate 		DEBUG0("hpc_slot_unregister: running callback");
598*0Sstevel@tonic-gate 		r = callback(dip, (hpc_slot_t)slotp, &slotp->slot_info,
599*0Sstevel@tonic-gate 		    HPC_SLOT_OFFLINE);
600*0Sstevel@tonic-gate 		DEBUG1("hpc_slot_unregister: callback returned %x", r);
601*0Sstevel@tonic-gate 		if (r != HPC_SUCCESS)
602*0Sstevel@tonic-gate 			return (HPC_ERR_FAILED);
603*0Sstevel@tonic-gate 		mutex_enter(&hpc_bus_mutex);
604*0Sstevel@tonic-gate 	}
605*0Sstevel@tonic-gate 
606*0Sstevel@tonic-gate 	/*
607*0Sstevel@tonic-gate 	 * Remove the slot from list and free the memory associated with it.
608*0Sstevel@tonic-gate 	 */
609*0Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
610*0Sstevel@tonic-gate 	DEBUG1("hpc_slot_unregister: freeing slot, bus_slot_list=%x",
611*0Sstevel@tonic-gate 		busp->bus_slot_list);
612*0Sstevel@tonic-gate 	if (slotp->slot_prev != NULL)
613*0Sstevel@tonic-gate 		slotp->slot_prev->slot_next = slotp->slot_next;
614*0Sstevel@tonic-gate 	if (slotp->slot_next != NULL)
615*0Sstevel@tonic-gate 		slotp->slot_next->slot_prev = slotp->slot_prev;
616*0Sstevel@tonic-gate 	if (slotp == busp->bus_slot_list)
617*0Sstevel@tonic-gate 		busp->bus_slot_list = slotp->slot_next;
618*0Sstevel@tonic-gate 
619*0Sstevel@tonic-gate 	/*
620*0Sstevel@tonic-gate 	 * Release hold from slot registration
621*0Sstevel@tonic-gate 	 */
622*0Sstevel@tonic-gate 	ndi_rele_driver(slotp->slot_hpc_dip);
623*0Sstevel@tonic-gate 
624*0Sstevel@tonic-gate 	/* Free the memory associated with the slot entry structure */
625*0Sstevel@tonic-gate 	hpc_free_slot_entry(slotp);
626*0Sstevel@tonic-gate 
627*0Sstevel@tonic-gate 	/*
628*0Sstevel@tonic-gate 	 * If the slot list is empty then stop the event handler thread.
629*0Sstevel@tonic-gate 	 */
630*0Sstevel@tonic-gate 	if (busp->bus_slot_list == NULL) {
631*0Sstevel@tonic-gate 		DEBUG0("hpc_slot_unregister: stopping thread");
632*0Sstevel@tonic-gate 		busp->bus_thread_exit = B_TRUE;
633*0Sstevel@tonic-gate 		cv_signal(&busp->bus_thread_cv);
634*0Sstevel@tonic-gate 		DEBUG0("hpc_slot_unregister: waiting for thread to exit");
635*0Sstevel@tonic-gate 		cv_wait(&busp->bus_thread_cv, &busp->bus_mutex);
636*0Sstevel@tonic-gate 		DEBUG0("hpc_slot_unregister: thread exit");
637*0Sstevel@tonic-gate 		cv_destroy(&busp->bus_thread_cv);
638*0Sstevel@tonic-gate 	}
639*0Sstevel@tonic-gate 
640*0Sstevel@tonic-gate 	/*
641*0Sstevel@tonic-gate 	 * If the bus is unregistered and this is the last slot for this bus
642*0Sstevel@tonic-gate 	 * then remove the entry from the bus list.
643*0Sstevel@tonic-gate 	 */
644*0Sstevel@tonic-gate 	if (busp->bus_registered == B_FALSE && busp->bus_slot_list == NULL) {
645*0Sstevel@tonic-gate 		/* locate the previous entry in the bus list */
646*0Sstevel@tonic-gate 		for (busp = hpc_bus_list_head; busp != NULL; busp_prev = busp,
647*0Sstevel@tonic-gate 		    busp = busp->bus_next)
648*0Sstevel@tonic-gate 			if (strcmp(bus_name, busp->bus_name) == 0)
649*0Sstevel@tonic-gate 				break;
650*0Sstevel@tonic-gate 
651*0Sstevel@tonic-gate 		if (busp == hpc_bus_list_head)
652*0Sstevel@tonic-gate 			hpc_bus_list_head = busp->bus_next;
653*0Sstevel@tonic-gate 		else
654*0Sstevel@tonic-gate 			busp_prev->bus_next = busp->bus_next;
655*0Sstevel@tonic-gate 
656*0Sstevel@tonic-gate 		mutex_exit(&busp->bus_mutex);
657*0Sstevel@tonic-gate 		mutex_destroy(&busp->bus_mutex);
658*0Sstevel@tonic-gate 		hpc_free_bus_entry(busp);
659*0Sstevel@tonic-gate 	} else
660*0Sstevel@tonic-gate 		mutex_exit(&busp->bus_mutex);
661*0Sstevel@tonic-gate 	mutex_exit(&hpc_bus_mutex);
662*0Sstevel@tonic-gate 
663*0Sstevel@tonic-gate 	/*
664*0Sstevel@tonic-gate 	 * reset the slot handle.
665*0Sstevel@tonic-gate 	 */
666*0Sstevel@tonic-gate 	*handlep = NULL;
667*0Sstevel@tonic-gate 	return (HPC_SUCCESS);
668*0Sstevel@tonic-gate }
669*0Sstevel@tonic-gate 
670*0Sstevel@tonic-gate 
671*0Sstevel@tonic-gate int
672*0Sstevel@tonic-gate hpc_install_event_handler(hpc_slot_t handle, uint_t event_mask,
673*0Sstevel@tonic-gate 	int (*event_handler)(caddr_t, uint_t), caddr_t arg)
674*0Sstevel@tonic-gate {
675*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
676*0Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
677*0Sstevel@tonic-gate 
678*0Sstevel@tonic-gate 	DEBUG3("hpc_install_event_handler: handle=%x, mask=%x, arg=%x",
679*0Sstevel@tonic-gate 		handle, event_mask, arg);
680*0Sstevel@tonic-gate 	ASSERT((handle != NULL) && (event_handler != NULL));
681*0Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
682*0Sstevel@tonic-gate 	busp = slotp->slot_bus;
683*0Sstevel@tonic-gate 	ASSERT(slotp == slotp->slot_handle);
684*0Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
685*0Sstevel@tonic-gate 	slotp->slot_event_mask = event_mask;
686*0Sstevel@tonic-gate 	slotp->slot_event_handler = event_handler;
687*0Sstevel@tonic-gate 	slotp->slot_event_handler_arg = arg;
688*0Sstevel@tonic-gate 	mutex_exit(&busp->bus_mutex);
689*0Sstevel@tonic-gate 	return (HPC_SUCCESS);
690*0Sstevel@tonic-gate }
691*0Sstevel@tonic-gate 
692*0Sstevel@tonic-gate 
693*0Sstevel@tonic-gate int
694*0Sstevel@tonic-gate hpc_remove_event_handler(hpc_slot_t handle)
695*0Sstevel@tonic-gate {
696*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
697*0Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
698*0Sstevel@tonic-gate 
699*0Sstevel@tonic-gate 	DEBUG1("hpc_remove_event_handler: handle=%x", handle);
700*0Sstevel@tonic-gate 	ASSERT(handle != NULL);
701*0Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
702*0Sstevel@tonic-gate 	ASSERT(slotp == slotp->slot_handle);
703*0Sstevel@tonic-gate 	busp = slotp->slot_bus;
704*0Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
705*0Sstevel@tonic-gate 	slotp->slot_event_mask = 0;
706*0Sstevel@tonic-gate 	slotp->slot_event_handler = NULL;
707*0Sstevel@tonic-gate 	slotp->slot_event_handler_arg = NULL;
708*0Sstevel@tonic-gate 	mutex_exit(&busp->bus_mutex);
709*0Sstevel@tonic-gate 	return (HPC_SUCCESS);
710*0Sstevel@tonic-gate }
711*0Sstevel@tonic-gate 
712*0Sstevel@tonic-gate 
713*0Sstevel@tonic-gate /*ARGSUSED2*/
714*0Sstevel@tonic-gate int
715*0Sstevel@tonic-gate hpc_slot_event_notify(hpc_slot_t handle, uint_t event, uint_t flags)
716*0Sstevel@tonic-gate {
717*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
718*0Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
719*0Sstevel@tonic-gate 	hpc_event_entry_t *eventp;
720*0Sstevel@tonic-gate 
721*0Sstevel@tonic-gate 	DEBUG2("hpc_slot_event_notify: handle=%x event=%x", handle, event);
722*0Sstevel@tonic-gate 	ASSERT(handle != NULL);
723*0Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
724*0Sstevel@tonic-gate 	ASSERT(slotp == slotp->slot_handle);
725*0Sstevel@tonic-gate 
726*0Sstevel@tonic-gate 	if (slotp->slot_event_handler == NULL)
727*0Sstevel@tonic-gate 		return (HPC_EVENT_UNCLAIMED);
728*0Sstevel@tonic-gate 
729*0Sstevel@tonic-gate 	/*
730*0Sstevel@tonic-gate 	 * If the request is to handle the event synchronously, then call
731*0Sstevel@tonic-gate 	 * the event handler without queuing the event.
732*0Sstevel@tonic-gate 	 */
733*0Sstevel@tonic-gate 	if (flags == HPC_EVENT_SYNCHRONOUS) {
734*0Sstevel@tonic-gate 		caddr_t arg;
735*0Sstevel@tonic-gate 		int (* func)(caddr_t, uint_t);
736*0Sstevel@tonic-gate 
737*0Sstevel@tonic-gate 		func = slotp->slot_event_handler;
738*0Sstevel@tonic-gate 		arg = slotp->slot_event_handler_arg;
739*0Sstevel@tonic-gate 		return (func(arg, event));
740*0Sstevel@tonic-gate 	}
741*0Sstevel@tonic-gate 	/*
742*0Sstevel@tonic-gate 	 * Insert the event into the bus slot event handler list and
743*0Sstevel@tonic-gate 	 * signal the bus slot event handler dispatch thread.
744*0Sstevel@tonic-gate 	 */
745*0Sstevel@tonic-gate 	busp = slotp->slot_bus;
746*0Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
747*0Sstevel@tonic-gate 
748*0Sstevel@tonic-gate 	if (busp->bus_slot_event_list_head == NULL) {
749*0Sstevel@tonic-gate 		eventp = busp->bus_slot_event_list_head =
750*0Sstevel@tonic-gate 		    hpc_alloc_event_entry();
751*0Sstevel@tonic-gate 	} else {
752*0Sstevel@tonic-gate 		for (eventp = busp->bus_slot_event_list_head;
753*0Sstevel@tonic-gate 			    eventp->next != NULL; eventp = eventp->next)
754*0Sstevel@tonic-gate 			;
755*0Sstevel@tonic-gate 		eventp->next = hpc_alloc_event_entry();
756*0Sstevel@tonic-gate 		eventp = eventp->next;
757*0Sstevel@tonic-gate 	}
758*0Sstevel@tonic-gate 	eventp->slotp = slotp;
759*0Sstevel@tonic-gate 	eventp->event = event;
760*0Sstevel@tonic-gate 	eventp->next = NULL;
761*0Sstevel@tonic-gate 	DEBUG2("hpc_slot_event_notify: busp=%x event=%x", busp, event);
762*0Sstevel@tonic-gate 	cv_signal(&busp->bus_thread_cv);
763*0Sstevel@tonic-gate 	mutex_exit(&busp->bus_mutex);
764*0Sstevel@tonic-gate 	return (HPC_EVENT_CLAIMED);
765*0Sstevel@tonic-gate }
766*0Sstevel@tonic-gate 
767*0Sstevel@tonic-gate 
768*0Sstevel@tonic-gate int
769*0Sstevel@tonic-gate hpc_nexus_connect(hpc_slot_t handle, void *data, uint_t flags)
770*0Sstevel@tonic-gate {
771*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
772*0Sstevel@tonic-gate 
773*0Sstevel@tonic-gate 	ASSERT(handle != NULL);
774*0Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
775*0Sstevel@tonic-gate 	if (slotp->slot_ops.hpc_op_connect)
776*0Sstevel@tonic-gate 		return (slotp->slot_ops.hpc_op_connect(slotp->slot_ops_arg,
777*0Sstevel@tonic-gate 			handle, data, flags));
778*0Sstevel@tonic-gate 	return (HPC_ERR_FAILED);
779*0Sstevel@tonic-gate }
780*0Sstevel@tonic-gate 
781*0Sstevel@tonic-gate 
782*0Sstevel@tonic-gate int
783*0Sstevel@tonic-gate hpc_nexus_disconnect(hpc_slot_t handle, void *data, uint_t flags)
784*0Sstevel@tonic-gate {
785*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
786*0Sstevel@tonic-gate 
787*0Sstevel@tonic-gate 	ASSERT(handle != NULL);
788*0Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
789*0Sstevel@tonic-gate 	if (slotp->slot_ops.hpc_op_disconnect)
790*0Sstevel@tonic-gate 		return (slotp->slot_ops.hpc_op_disconnect(slotp->slot_ops_arg,
791*0Sstevel@tonic-gate 			handle, data, flags));
792*0Sstevel@tonic-gate 	return (HPC_ERR_FAILED);
793*0Sstevel@tonic-gate }
794*0Sstevel@tonic-gate 
795*0Sstevel@tonic-gate 
796*0Sstevel@tonic-gate int
797*0Sstevel@tonic-gate hpc_nexus_insert(hpc_slot_t handle, void *data, uint_t flags)
798*0Sstevel@tonic-gate {
799*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
800*0Sstevel@tonic-gate 
801*0Sstevel@tonic-gate 	ASSERT(handle != NULL);
802*0Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
803*0Sstevel@tonic-gate 	if (slotp->slot_ops.hpc_op_insert)
804*0Sstevel@tonic-gate 		return (slotp->slot_ops.hpc_op_insert(slotp->slot_ops_arg,
805*0Sstevel@tonic-gate 			handle, data, flags));
806*0Sstevel@tonic-gate 	return (HPC_ERR_FAILED);
807*0Sstevel@tonic-gate }
808*0Sstevel@tonic-gate 
809*0Sstevel@tonic-gate 
810*0Sstevel@tonic-gate int
811*0Sstevel@tonic-gate hpc_nexus_remove(hpc_slot_t handle, void *data, uint_t flags)
812*0Sstevel@tonic-gate {
813*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
814*0Sstevel@tonic-gate 
815*0Sstevel@tonic-gate 	ASSERT(handle != NULL);
816*0Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
817*0Sstevel@tonic-gate 	if (slotp->slot_ops.hpc_op_remove)
818*0Sstevel@tonic-gate 		return (slotp->slot_ops.hpc_op_remove(slotp->slot_ops_arg,
819*0Sstevel@tonic-gate 			handle, data, flags));
820*0Sstevel@tonic-gate 	return (HPC_ERR_FAILED);
821*0Sstevel@tonic-gate }
822*0Sstevel@tonic-gate 
823*0Sstevel@tonic-gate 
824*0Sstevel@tonic-gate int
825*0Sstevel@tonic-gate hpc_nexus_control(hpc_slot_t handle, int request, caddr_t arg)
826*0Sstevel@tonic-gate {
827*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
828*0Sstevel@tonic-gate 
829*0Sstevel@tonic-gate 	ASSERT(handle != NULL);
830*0Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)handle;
831*0Sstevel@tonic-gate 	if (slotp->slot_ops.hpc_op_control)
832*0Sstevel@tonic-gate 		return (slotp->slot_ops.hpc_op_control(slotp->slot_ops_arg,
833*0Sstevel@tonic-gate 			handle, request, arg));
834*0Sstevel@tonic-gate 	return (HPC_ERR_FAILED);
835*0Sstevel@tonic-gate }
836*0Sstevel@tonic-gate 
837*0Sstevel@tonic-gate /*
838*0Sstevel@tonic-gate  * The following function is run from the bus entries slot event handling
839*0Sstevel@tonic-gate  * thread.
840*0Sstevel@tonic-gate  */
841*0Sstevel@tonic-gate static void
842*0Sstevel@tonic-gate hpc_slot_event_dispatcher(hpc_bus_entry_t *busp)
843*0Sstevel@tonic-gate {
844*0Sstevel@tonic-gate 	hpc_event_entry_t *eventp;
845*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
846*0Sstevel@tonic-gate 	int event;
847*0Sstevel@tonic-gate 	caddr_t arg;
848*0Sstevel@tonic-gate 	int (* func)(caddr_t, uint_t);
849*0Sstevel@tonic-gate 	callb_cpr_t cprinfo;
850*0Sstevel@tonic-gate 
851*0Sstevel@tonic-gate 	/*
852*0Sstevel@tonic-gate 	 * The creator of this thread is waiting to be signaled that
853*0Sstevel@tonic-gate 	 * the thread has been started.
854*0Sstevel@tonic-gate 	 */
855*0Sstevel@tonic-gate 	DEBUG1("hpc_slot_event_dispatcher: busp=%x", busp);
856*0Sstevel@tonic-gate 
857*0Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &busp->bus_mutex, callb_generic_cpr,
858*0Sstevel@tonic-gate 	    "hpc_slot_event_dispatcher");
859*0Sstevel@tonic-gate 
860*0Sstevel@tonic-gate 	mutex_enter(&busp->bus_mutex);
861*0Sstevel@tonic-gate 	/*
862*0Sstevel@tonic-gate 	 * Wait for events to queue and then process them.
863*0Sstevel@tonic-gate 	 */
864*0Sstevel@tonic-gate 	for (;;) {
865*0Sstevel@tonic-gate 
866*0Sstevel@tonic-gate 		/*
867*0Sstevel@tonic-gate 		 * Note we only hold the mutex while determining
868*0Sstevel@tonic-gate 		 * the number of entries that have been added to
869*0Sstevel@tonic-gate 		 * the event list, while updating the event list
870*0Sstevel@tonic-gate 		 * after processing the event list entries.
871*0Sstevel@tonic-gate 		 */
872*0Sstevel@tonic-gate 		if (busp->bus_slot_event_list_head == NULL) {
873*0Sstevel@tonic-gate 			CALLB_CPR_SAFE_BEGIN(&cprinfo);
874*0Sstevel@tonic-gate 			cv_wait(&busp->bus_thread_cv, &busp->bus_mutex);
875*0Sstevel@tonic-gate 			CALLB_CPR_SAFE_END(&cprinfo, &busp->bus_mutex);
876*0Sstevel@tonic-gate 			if (busp->bus_thread_exit)
877*0Sstevel@tonic-gate 				break;
878*0Sstevel@tonic-gate 			continue;
879*0Sstevel@tonic-gate 		}
880*0Sstevel@tonic-gate 
881*0Sstevel@tonic-gate 		/*
882*0Sstevel@tonic-gate 		 * We have an event handler instance in the list to
883*0Sstevel@tonic-gate 		 * process.  Remove the head of the list, saving the
884*0Sstevel@tonic-gate 		 * information required to run the event handler.
885*0Sstevel@tonic-gate 		 * Then run the event handler while the bus mutex
886*0Sstevel@tonic-gate 		 * is released.
887*0Sstevel@tonic-gate 		 */
888*0Sstevel@tonic-gate 		eventp = busp->bus_slot_event_list_head;
889*0Sstevel@tonic-gate 		slotp = eventp->slotp;
890*0Sstevel@tonic-gate 		event = eventp->event;
891*0Sstevel@tonic-gate 		func = slotp->slot_event_handler;
892*0Sstevel@tonic-gate 		arg = slotp->slot_event_handler_arg;
893*0Sstevel@tonic-gate 		busp->bus_slot_event_list_head = eventp->next;
894*0Sstevel@tonic-gate 		hpc_free_event_entry(eventp);
895*0Sstevel@tonic-gate 		mutex_exit(&busp->bus_mutex);
896*0Sstevel@tonic-gate 		func(arg, event);
897*0Sstevel@tonic-gate 		mutex_enter(&busp->bus_mutex);
898*0Sstevel@tonic-gate 
899*0Sstevel@tonic-gate 		if (busp->bus_thread_exit)
900*0Sstevel@tonic-gate 			break;
901*0Sstevel@tonic-gate 	}
902*0Sstevel@tonic-gate 
903*0Sstevel@tonic-gate 	DEBUG0("hpc_slot_event_dispatcher: thread_exit");
904*0Sstevel@tonic-gate 	cv_signal(&busp->bus_thread_cv);
905*0Sstevel@tonic-gate 	CALLB_CPR_EXIT(&cprinfo);
906*0Sstevel@tonic-gate 	thread_exit();
907*0Sstevel@tonic-gate }
908*0Sstevel@tonic-gate 
909*0Sstevel@tonic-gate 
910*0Sstevel@tonic-gate static hpc_bus_entry_t *
911*0Sstevel@tonic-gate hpc_find_bus_by_name(char *path)
912*0Sstevel@tonic-gate {
913*0Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
914*0Sstevel@tonic-gate 
915*0Sstevel@tonic-gate 	for (busp = hpc_bus_list_head; busp != NULL; busp = busp->bus_next) {
916*0Sstevel@tonic-gate 		if (strcmp(path, busp->bus_name) == 0)
917*0Sstevel@tonic-gate 			break;
918*0Sstevel@tonic-gate 	}
919*0Sstevel@tonic-gate 	return (busp);
920*0Sstevel@tonic-gate }
921*0Sstevel@tonic-gate 
922*0Sstevel@tonic-gate boolean_t
923*0Sstevel@tonic-gate hpc_bus_registered(hpc_slot_t slot_hdl)
924*0Sstevel@tonic-gate {
925*0Sstevel@tonic-gate 	hpc_slot_entry_t *slotp;
926*0Sstevel@tonic-gate 	hpc_bus_entry_t *busp;
927*0Sstevel@tonic-gate 
928*0Sstevel@tonic-gate 	slotp = (hpc_slot_entry_t *)slot_hdl;
929*0Sstevel@tonic-gate 	busp = slotp->slot_bus;
930*0Sstevel@tonic-gate 	return (busp->bus_registered);
931*0Sstevel@tonic-gate }
932*0Sstevel@tonic-gate 
933*0Sstevel@tonic-gate 
934*0Sstevel@tonic-gate #ifdef DEBUG
935*0Sstevel@tonic-gate 
936*0Sstevel@tonic-gate extern void prom_printf(const char *, ...);
937*0Sstevel@tonic-gate 
938*0Sstevel@tonic-gate static void
939*0Sstevel@tonic-gate debug(char *fmt, uintptr_t a1, uintptr_t a2, uintptr_t a3,
940*0Sstevel@tonic-gate     uintptr_t a4, uintptr_t a5)
941*0Sstevel@tonic-gate {
942*0Sstevel@tonic-gate 	if (hpcsvc_debug != 0) {
943*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "hpcsvc: ");
944*0Sstevel@tonic-gate 		cmn_err(CE_CONT, fmt, a1, a2, a3, a4, a5);
945*0Sstevel@tonic-gate 		cmn_err(CE_CONT, "\n");
946*0Sstevel@tonic-gate 	}
947*0Sstevel@tonic-gate }
948*0Sstevel@tonic-gate #endif
949