10d63ce2bSvenki /*
20d63ce2bSvenki  * CDDL HEADER START
30d63ce2bSvenki  *
40d63ce2bSvenki  * The contents of this file are subject to the terms of the
50d63ce2bSvenki  * Common Development and Distribution License (the "License").
60d63ce2bSvenki  * You may not use this file except in compliance with the License.
70d63ce2bSvenki  *
80d63ce2bSvenki  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90d63ce2bSvenki  * or http://www.opensolaris.org/os/licensing.
100d63ce2bSvenki  * See the License for the specific language governing permissions
110d63ce2bSvenki  * and limitations under the License.
120d63ce2bSvenki  *
130d63ce2bSvenki  * When distributing Covered Code, include this CDDL HEADER in each
140d63ce2bSvenki  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150d63ce2bSvenki  * If applicable, add the following below this CDDL HEADER, with the
160d63ce2bSvenki  * fields enclosed by brackets "[]" replaced with your own identifying
170d63ce2bSvenki  * information: Portions Copyright [yyyy] [name of copyright owner]
180d63ce2bSvenki  *
190d63ce2bSvenki  * CDDL HEADER END
200d63ce2bSvenki  */
210d63ce2bSvenki 
220d63ce2bSvenki /*
23cb851c14Sfw  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
240d63ce2bSvenki  * Use is subject to license terms.
250d63ce2bSvenki  */
260d63ce2bSvenki 
27a90d965dSfw #include <pri.h>
280d63ce2bSvenki #include "priplugin.h"
290d63ce2bSvenki 
300d63ce2bSvenki #pragma init(priplugin_register)	/* place in .init section */
310d63ce2bSvenki 
32d2b9c676Sfw static md_t *mdp;
330d63ce2bSvenki 
34d2b9c676Sfw static mutex_t	rebuild_lock;
35d2b9c676Sfw static cond_t	rebuild_cv;
36d2b9c676Sfw 
37d2b9c676Sfw static thread_t pri_worker_thread_id, pri_reader_thread_id;
38d2b9c676Sfw static boolean_t all_thr_exit = B_FALSE;
39cb851c14Sfw static boolean_t event_caught = B_FALSE;
40d2b9c676Sfw 
41d2b9c676Sfw static void priplugin_init(void);
42d2b9c676Sfw static void priplugin_fini(void);
43a90d965dSfw static void
44a90d965dSfw event_handler(const char *ename, const void *earg, size_t size, void *cookie);
45d2b9c676Sfw static void *pri_worker_thread(void *arg);
46d2b9c676Sfw static void *pri_reader_thread(void *arg);
47d2b9c676Sfw static int remove_old_segments(picl_nodehdl_t node, void *args);
48d2b9c676Sfw 
490d63ce2bSvenki 
500d63ce2bSvenki picld_plugin_reg_t priplugin_reg = {
510d63ce2bSvenki 	PICLD_PLUGIN_VERSION_1,
520d63ce2bSvenki 	PICLD_PLUGIN_CRITICAL,
530d63ce2bSvenki 	"pri_plugin",
540d63ce2bSvenki 	priplugin_init,
550d63ce2bSvenki 	priplugin_fini
560d63ce2bSvenki };
570d63ce2bSvenki 
58d2b9c676Sfw static void
set_prop_info(ptree_propinfo_t * propinfo,int size,char * name,int type)590d63ce2bSvenki set_prop_info(ptree_propinfo_t *propinfo, int size, char *name, int type)
600d63ce2bSvenki {
610d63ce2bSvenki 	propinfo->version = PICLD_PLUGIN_VERSION_1;
620d63ce2bSvenki 	propinfo->read = NULL;
630d63ce2bSvenki 	propinfo->write = NULL;
640d63ce2bSvenki 	propinfo->piclinfo.type = type;
650d63ce2bSvenki 	propinfo->piclinfo.accessmode = PICL_READ;
660d63ce2bSvenki 	propinfo->piclinfo.size = size;
674c5e0fdeSvivek 	(void) strlcpy(propinfo->piclinfo.name, name,
680d63ce2bSvenki 	    sizeof (propinfo->piclinfo.name));
690d63ce2bSvenki }
700d63ce2bSvenki 
710d63ce2bSvenki boolean_t
prop_exists(picl_nodehdl_t node,char * name)720d63ce2bSvenki prop_exists(picl_nodehdl_t node, char *name)
730d63ce2bSvenki {
740d63ce2bSvenki 	int status;
750d63ce2bSvenki 	picl_prophdl_t proph;
760d63ce2bSvenki 
770d63ce2bSvenki 	status = ptree_get_prop_by_name(node, name, &proph);
780d63ce2bSvenki 	if (status == PICL_SUCCESS)
790d63ce2bSvenki 		return (B_TRUE);
800d63ce2bSvenki 	else
810d63ce2bSvenki 		return (B_FALSE);
820d63ce2bSvenki }
830d63ce2bSvenki 
840d63ce2bSvenki void
add_md_prop(picl_nodehdl_t node,int size,char * name,void * value,int type)850d63ce2bSvenki add_md_prop(picl_nodehdl_t node, int size, char *name, void* value, int type)
860d63ce2bSvenki {
870d63ce2bSvenki 	ptree_propinfo_t propinfo;
880d63ce2bSvenki 	picl_prophdl_t proph;
890d63ce2bSvenki 
900d63ce2bSvenki 	if (!prop_exists(node, name)) {
910d63ce2bSvenki 		set_prop_info(&propinfo, size, name, type);
920d63ce2bSvenki 
930d63ce2bSvenki 		(void) ptree_create_and_add_prop(node, &propinfo,
940d63ce2bSvenki 		    value, &proph);
950d63ce2bSvenki 	}
960d63ce2bSvenki }
970d63ce2bSvenki 
98d2b9c676Sfw /*ARGSUSED*/
99d2b9c676Sfw static int
remove_old_segments(picl_nodehdl_t node,void * args)100d2b9c676Sfw remove_old_segments(picl_nodehdl_t node, void *args)
1010d63ce2bSvenki {
1020d63ce2bSvenki 	int status;
1030d63ce2bSvenki 
104d2b9c676Sfw 	if ((status = ptree_delete_node(node)) == PICL_SUCCESS)
105d2b9c676Sfw 		ptree_destroy_node(node);
106d2b9c676Sfw 	else
107d2b9c676Sfw 		pri_debug(LOG_NOTICE, "remove_old_segments: can't delete "
108d2b9c676Sfw 		    "segment node: %s\n", picl_strerror(status));
109d2b9c676Sfw 
110d2b9c676Sfw 	return (PICL_WALK_CONTINUE);
111d2b9c676Sfw }
112d2b9c676Sfw 
113d2b9c676Sfw static void
priplugin_init(void)114d2b9c676Sfw priplugin_init(void)
115d2b9c676Sfw {
116d2b9c676Sfw 	int status;
117a90d965dSfw 
118a90d965dSfw 	pri_debug(LOG_NOTICE, "priplugin: mem tree and io label thread "
119a90d965dSfw 	    "being created; callbacks being registered\n");
120a90d965dSfw 
121d2b9c676Sfw 	all_thr_exit = B_FALSE;
122cb851c14Sfw 	event_caught = B_FALSE;
123a90d965dSfw 
124d2b9c676Sfw 	(void) mutex_init(&rebuild_lock, USYNC_THREAD, NULL);
125d2b9c676Sfw 	(void) cond_init(&rebuild_cv, USYNC_THREAD, NULL);
126d2b9c676Sfw 
127*ada2da53SToomas Soome 	if ((status = thr_create(NULL, 0, pri_worker_thread, NULL, THR_BOUND,
128d2b9c676Sfw 	    &pri_worker_thread_id)) < 0) {
129d2b9c676Sfw 		pri_debug(LOG_NOTICE, "priplugin: can't create worker thread: "
130d2b9c676Sfw 		    "%d\n", status);
131d2b9c676Sfw 		all_thr_exit = B_TRUE;
132d2b9c676Sfw 		(void) mutex_destroy(&rebuild_lock);
133d2b9c676Sfw 		(void) cond_destroy(&rebuild_cv);
134*ada2da53SToomas Soome 	} else if ((status = thr_create(NULL, 0, pri_reader_thread, NULL,
135d2b9c676Sfw 	    THR_BOUND, &pri_reader_thread_id)) < 0) {
136d2b9c676Sfw 		pri_debug(LOG_NOTICE, "priplugin: can't create reader thread: "
137a90d965dSfw 		    "%d\n", status);
138d2b9c676Sfw 		(void) mutex_lock(&rebuild_lock);
139d2b9c676Sfw 		all_thr_exit = B_TRUE;
140d2b9c676Sfw 		(void) cond_signal(&rebuild_cv);
141d2b9c676Sfw 		(void) mutex_unlock(&rebuild_lock);
142d2b9c676Sfw 		(void) thr_join(pri_worker_thread_id, NULL, NULL);
143d2b9c676Sfw 		(void) mutex_destroy(&rebuild_lock);
144d2b9c676Sfw 		(void) cond_destroy(&rebuild_cv);
145d2b9c676Sfw 	} else {
146d2b9c676Sfw 		pri_debug(LOG_NOTICE, "priplugin_init: worker and reader "
147d2b9c676Sfw 		    "threads created - registering event handlers\n");
148d2b9c676Sfw 		/*
149d2b9c676Sfw 		 * register event_handler for both "sysevent-device-added",
150d2b9c676Sfw 		 * "sysevent_device_removed", and for
151d2b9c676Sfw 		 * "sysevent-dr-app-state-change" PICL events
152d2b9c676Sfw 		 */
153d2b9c676Sfw 		(void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
154d2b9c676Sfw 		    event_handler, NULL);
155d2b9c676Sfw 		(void) ptree_register_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
156d2b9c676Sfw 		    event_handler, NULL);
157d2b9c676Sfw 		(void) ptree_register_handler(PICLEVENT_DR_AP_STATE_CHANGE,
158d2b9c676Sfw 		    event_handler, NULL);
159a90d965dSfw 	}
160a90d965dSfw }
161a90d965dSfw 
162d2b9c676Sfw /*
163d2b9c676Sfw  * This thread handles the main processing of PRI data.  It is woken
164d2b9c676Sfw  * up by either the event handler, to process a PICL event, or it is
165d2b9c676Sfw  * woken up by the PRI reader thread which has just fetched a new
166d2b9c676Sfw  * copy of the PRI.
167d2b9c676Sfw  */
168a90d965dSfw /*ARGSUSED*/
169a90d965dSfw static void *
pri_worker_thread(void * arg)170d2b9c676Sfw pri_worker_thread(void *arg)
171a90d965dSfw {
172a90d965dSfw 	int status;
173d2b9c676Sfw 	picl_nodehdl_t picl_root_node;
174a90d965dSfw 
175d2b9c676Sfw 	pri_debug(LOG_NOTICE, "pri_worker_thread: start\n");
176a90d965dSfw 
177d2b9c676Sfw 	(void) mutex_lock(&rebuild_lock);
178cb851c14Sfw 	/*LINTED E_FUNC_RET_MAYBE_IGNORED2*/
179d2b9c676Sfw 	while (1) {
180d2b9c676Sfw 		(void) cond_wait(&rebuild_cv, &rebuild_lock);
1810d63ce2bSvenki 
182d2b9c676Sfw 		if (all_thr_exit == B_TRUE) {
183d2b9c676Sfw 			(void) mutex_unlock(&rebuild_lock);
184d2b9c676Sfw 			pri_debug(LOG_NOTICE, "pri_worker_thread: time to "
185d2b9c676Sfw 			    "exit\n");
186d2b9c676Sfw 			break;
187d2b9c676Sfw 		}
1880d63ce2bSvenki 
189cb851c14Sfw 		/*
190cb851c14Sfw 		 * We don't get events for changes to system memory,
191cb851c14Sfw 		 * and we do not want to interfere with other plug-ins
192cb851c14Sfw 		 * by making changes to the picl tree.  So if we were
193cb851c14Sfw 		 * woken up by a thread then do not destroy and rebuild
194cb851c14Sfw 		 * the memory info.  Just go fix the labels.
195cb851c14Sfw 		 */
196cb851c14Sfw 		if (event_caught == B_FALSE) {
197cb851c14Sfw 			status = ptree_get_root(&picl_root_node);
198cb851c14Sfw 			if (status != PICL_SUCCESS) {
199cb851c14Sfw 				pri_debug(LOG_NOTICE, "pri_worker_thread: "
200cb851c14Sfw 				    "can't get picl tree root node: %s\n",
201cb851c14Sfw 				    picl_strerror(status));
202cb851c14Sfw 				continue;
203cb851c14Sfw 			}
204d2b9c676Sfw 
205cb851c14Sfw 			pri_debug(LOG_NOTICE, "pri_worker_thread: have root "
206cb851c14Sfw 			    "picl and PRI nodes\n");
207cb851c14Sfw 
208cb851c14Sfw 			status = ptree_walk_tree_by_class(picl_root_node,
209cb851c14Sfw 			    "memory-segment", NULL, remove_old_segments);
210cb851c14Sfw 			if (status != PICL_SUCCESS) {
211cb851c14Sfw 				pri_debug(LOG_NOTICE, "pri_worker_thread: "
212cb851c14Sfw 				    "can't remove old memory segments: \n",
213cb851c14Sfw 				    picl_strerror(status));
214cb851c14Sfw 			} else
215cb851c14Sfw 				pri_debug(LOG_NOTICE, "pri_worker_thread: "
216cb851c14Sfw 				    "old memory segments removed\n");
217cb851c14Sfw 
218cb851c14Sfw 			status = ptree_walk_tree_by_class(picl_root_node,
219cb851c14Sfw 			    "memory", (void *) mdp, add_mem_prop);
220cb851c14Sfw 			if (status != PICL_SUCCESS) {
221cb851c14Sfw 				pri_debug(LOG_NOTICE, "pri_worker_thread: "
222cb851c14Sfw 				    "memory segments walk failed: \n",
223cb851c14Sfw 				    picl_strerror(status));
224cb851c14Sfw 			} else
225cb851c14Sfw 				pri_debug(LOG_NOTICE, "pri_worker_thread: "
226cb851c14Sfw 				    "success walking memory node\n");
227d2b9c676Sfw 		} else
228cb851c14Sfw 			event_caught = B_FALSE;
2290d63ce2bSvenki 
230a90d965dSfw 		io_dev_addlabel(mdp);
231a90d965dSfw 	}
232d2b9c676Sfw 	pri_debug(LOG_NOTICE, "pri_worker_thread: exiting\n");
233d2b9c676Sfw 	return (NULL);
234d2b9c676Sfw }
2350d63ce2bSvenki 
236d2b9c676Sfw /*
237d2b9c676Sfw  * This thread camps out in the PRI driver, waiting for it to return
238d2b9c676Sfw  * the contents of a new PRI.  When the PRI is changed this thread
239d2b9c676Sfw  * reads that data and prepares it for processing by the worker thread.
240d2b9c676Sfw  * It then signals the worker thread to process the new PRI data.
241d2b9c676Sfw  */
242d2b9c676Sfw /*ARGSUSED*/
243d2b9c676Sfw static void *
pri_reader_thread(void * arg)244d2b9c676Sfw pri_reader_thread(void *arg)
245d2b9c676Sfw {
246d2b9c676Sfw 	uint64_t tok;
247d2b9c676Sfw 	int status, count;
2480d63ce2bSvenki 
249d2b9c676Sfw 	pri_debug(LOG_NOTICE, "pri_reader_thread: thread start\n");
250d2b9c676Sfw 
251d2b9c676Sfw 	if (pri_init() != 0) {
252d2b9c676Sfw 		pri_debug(LOG_NOTICE, "pri_reader_thread: pri_init failed\n");
253d2b9c676Sfw 		return (NULL);
254d2b9c676Sfw 	}
255d2b9c676Sfw 
256d2b9c676Sfw 	/*
257d2b9c676Sfw 	 * It's entirely possible that a new PRI may get pushed while
258d2b9c676Sfw 	 * the worker thread is processing the previous PRI.  We will
259d2b9c676Sfw 	 * wait until the worker is finished, then flush the old contents
260d2b9c676Sfw 	 * and wake up the worker again to process the new data.
261d2b9c676Sfw 	 */
262d2b9c676Sfw 	mdp = NULL;
263d2b9c676Sfw 	tok = 0;
264d2b9c676Sfw 	count = 0;
265cb851c14Sfw 	/*LINTED E_FUNC_RET_MAYBE_IGNORED2*/
266d2b9c676Sfw 	while (1) {
267d2b9c676Sfw 		/*
268d2b9c676Sfw 		 * The _fini() function will close the PRI's fd, which will
269d2b9c676Sfw 		 * cause this function to break out of waiting in the PRI
270d2b9c676Sfw 		 * driver and return an error.
271d2b9c676Sfw 		 */
272d2b9c676Sfw 		status = pri_devinit(&tok);
273d2b9c676Sfw 
274d2b9c676Sfw 		(void) mutex_lock(&rebuild_lock);
275d2b9c676Sfw 		if (all_thr_exit == B_TRUE) {
276d2b9c676Sfw 			(void) mutex_unlock(&rebuild_lock);
277d2b9c676Sfw 			pri_debug(LOG_NOTICE, "pri_reader_thread: time to "
278d2b9c676Sfw 			    "exit\n");
279d2b9c676Sfw 			break;
280d2b9c676Sfw 		}
281d2b9c676Sfw 
282d2b9c676Sfw 		/*
283d2b9c676Sfw 		 * Wait until the worker is idle before swapping in the
284d2b9c676Sfw 		 * new PRI contents, then signal the worker to process
285d2b9c676Sfw 		 * that new data.
286d2b9c676Sfw 		 */
287d2b9c676Sfw 		if (status == 0) {
288d2b9c676Sfw 			pri_debug(LOG_NOTICE, "pri_reader_thread: got PRI\n");
289d2b9c676Sfw 
290d2b9c676Sfw 			/* old buffer will be freed by pri_bufinit() */
291d2b9c676Sfw 			mdp = pri_bufinit(mdp);
292d2b9c676Sfw 			if (mdp != NULL) {
293d2b9c676Sfw 				(void) cond_signal(&rebuild_cv);
294d2b9c676Sfw 				count = 0;
295d2b9c676Sfw 			} else {
296d2b9c676Sfw 				pri_debug(LOG_NOTICE, "pri_reader_thread: "
297d2b9c676Sfw 				    "NULL mdp!\n");
298d2b9c676Sfw 				status = -1;
299d2b9c676Sfw 			}
300d2b9c676Sfw 		}
301d2b9c676Sfw 
302d2b9c676Sfw 		/*
303d2b9c676Sfw 		 * Try to handle SP resets or other unexplained errors
304d2b9c676Sfw 		 * from ds by closing down and re-opening the PRI driver.
305d2b9c676Sfw 		 */
306d2b9c676Sfw 		if (status == -1) {
307d2b9c676Sfw 			if (errno != 0) {
308d2b9c676Sfw 				pri_debug(LOG_NOTICE, "pri_reader_thread: "
309d2b9c676Sfw 				    "can't get PRI contents: %s\n",
310d2b9c676Sfw 				    strerror(errno));
311d2b9c676Sfw 			}
312d2b9c676Sfw 			if (++count > 6) {
313d2b9c676Sfw 				pri_debug(LOG_NOTICE, "pci_reader_thread: "
314d2b9c676Sfw 				    "can't process PRI data\n");
315d2b9c676Sfw 				(void) mutex_unlock(&rebuild_lock);
316d2b9c676Sfw 				break;
317d2b9c676Sfw 			}
318d2b9c676Sfw 			/* old buffer will be freed by pri_fini() */
319d2b9c676Sfw 			pri_fini();
320d2b9c676Sfw 			tok = 0;
321d2b9c676Sfw 			sleep(10);
322d2b9c676Sfw 			if (pri_init() != 0) {
323d2b9c676Sfw 				pri_debug(LOG_NOTICE, "pci_reader_thread: "
324d2b9c676Sfw 				    "can't reinitialize PRI driver\n");
325d2b9c676Sfw 				(void) mutex_unlock(&rebuild_lock);
326d2b9c676Sfw 				break;
327d2b9c676Sfw 			}
328d2b9c676Sfw 		}
329d2b9c676Sfw 		(void) mutex_unlock(&rebuild_lock);
330d2b9c676Sfw 	}
331a90d965dSfw 
332d2b9c676Sfw 	pri_debug(LOG_NOTICE, "pri_reader_thread: thread exiting\n");
333a90d965dSfw 	return (NULL);
3340d63ce2bSvenki }
3350d63ce2bSvenki 
336d2b9c676Sfw static void
priplugin_fini(void)3370d63ce2bSvenki priplugin_fini(void)
3380d63ce2bSvenki {
339d2b9c676Sfw 	pri_debug(LOG_NOTICE, "priplugin_fini: called\n");
340d2b9c676Sfw 
341d2b9c676Sfw 	if (all_thr_exit == B_TRUE)
342d2b9c676Sfw 		return;
343d2b9c676Sfw 
344d2b9c676Sfw 	/* unregister the event handlers */
345a90d965dSfw 	(void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_ADDED,
346a90d965dSfw 	    event_handler, NULL);
347d2b9c676Sfw 	(void) ptree_unregister_handler(PICLEVENT_SYSEVENT_DEVICE_REMOVED,
348d2b9c676Sfw 	    event_handler, NULL);
349a90d965dSfw 	(void) ptree_unregister_handler(PICLEVENT_DR_AP_STATE_CHANGE,
350a90d965dSfw 	    event_handler, NULL);
351d2b9c676Sfw 
352d2b9c676Sfw 	/*
353d2b9c676Sfw 	 * Set the exit flag to tell the worker thread to quit and wake
354d2b9c676Sfw 	 * up that thread.  Once that thread is reaped then pull the rug
355d2b9c676Sfw 	 * out from the PRI reader thread by calling pri_fini(), which
356d2b9c676Sfw 	 * closes the PRI fd.  That wakes the PRI reader thread and it
357d2b9c676Sfw 	 * will then exit as well.
358d2b9c676Sfw 	 */
359d2b9c676Sfw 	(void) mutex_lock(&rebuild_lock);
360d2b9c676Sfw 	all_thr_exit = B_TRUE;
361d2b9c676Sfw 	(void) cond_signal(&rebuild_cv);
362d2b9c676Sfw 	(void) mutex_unlock(&rebuild_lock);
363d2b9c676Sfw 
364d2b9c676Sfw 	(void) thr_join(pri_worker_thread_id, NULL, NULL);
365d2b9c676Sfw 
366d2b9c676Sfw 	pri_devfini(mdp);
367d2b9c676Sfw 	mdp = NULL;
368d2b9c676Sfw 	pri_fini();
369d2b9c676Sfw 	(void) thr_join(pri_reader_thread_id, NULL, NULL);
370d2b9c676Sfw 
371d2b9c676Sfw 	(void) mutex_destroy(&rebuild_lock);
372d2b9c676Sfw 	(void) cond_destroy(&rebuild_cv);
3730d63ce2bSvenki }
3740d63ce2bSvenki 
3750d63ce2bSvenki void
priplugin_register(void)3760d63ce2bSvenki priplugin_register(void)
3770d63ce2bSvenki {
3780d63ce2bSvenki 	picld_plugin_register(&priplugin_reg);
3790d63ce2bSvenki }
3800d63ce2bSvenki 
381a90d965dSfw /*
382a90d965dSfw  * Discovery event handler
383a90d965dSfw  * respond to the picl events:
384a90d965dSfw  *      PICLEVENT_SYSEVENT_DEVICE_ADDED
385d2b9c676Sfw  *      PICLEVENT_SYSEVENT_DEVICE_REMOVED
386a90d965dSfw  *      PICLEVENT_DR_AP_STATE_CHANGE
387a90d965dSfw  *
388a90d965dSfw  * We can't do much of anything fancy since the event data doesn't contain
389a90d965dSfw  * a nac for the device.  Nothing to do for remove - the devtree plug-in
390a90d965dSfw  * will have removed the node for us.  For add we have to go back and
391a90d965dSfw  * add labels again.
392a90d965dSfw  */
393a90d965dSfw static void
event_handler(const char * ename,const void * earg,size_t size,void * cookie)394a90d965dSfw event_handler(const char *ename, const void *earg, size_t size, void *cookie)
395a90d965dSfw {
396cb851c14Sfw 
397d2b9c676Sfw 	pri_debug(LOG_NOTICE, "pri: event_handler: caught event "
398d2b9c676Sfw 	    "%s\n", ename);
399a90d965dSfw 	if ((strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_ADDED) == 0) ||
400d2b9c676Sfw 	    (strcmp(ename, PICLEVENT_SYSEVENT_DEVICE_REMOVED) == 0) ||
401a90d965dSfw 	    (strcmp(ename, PICLEVENT_DR_AP_STATE_CHANGE) == 0)) {
402d2b9c676Sfw 		pri_debug(LOG_NOTICE, "pri: event_handler: handle event "
403d2b9c676Sfw 		    "%s; waking worker thread\n", ename);
404cb851c14Sfw 
405d2b9c676Sfw 		(void) mutex_lock(&rebuild_lock);
406d2b9c676Sfw 
407cb851c14Sfw 		if (all_thr_exit == B_FALSE) {
408cb851c14Sfw 			/*
409cb851c14Sfw 			 * Tell the worker thread to only re-examine the
410cb851c14Sfw 			 * IO device labels.
411cb851c14Sfw 			 */
412cb851c14Sfw 			event_caught = B_TRUE;
413d2b9c676Sfw 			(void) cond_signal(&rebuild_cv);
414cb851c14Sfw 		}
415d2b9c676Sfw 
416d2b9c676Sfw 		(void) mutex_unlock(&rebuild_lock);
417a90d965dSfw 	}
418a90d965dSfw }
419a90d965dSfw 
4200d63ce2bSvenki /*VARARGS2*/
4210d63ce2bSvenki void
pri_debug(int level,char * fmt,...)4220d63ce2bSvenki pri_debug(int level, char *fmt, ...)
4230d63ce2bSvenki {
4240d63ce2bSvenki #if (PRI_DEBUG != 0)
4250d63ce2bSvenki 	va_list	ap;
4260d63ce2bSvenki 
4270d63ce2bSvenki 	va_start(ap, fmt);
4280d63ce2bSvenki 	vsyslog(level, fmt, ap);
4290d63ce2bSvenki 	va_end(ap);
4300d63ce2bSvenki #endif
4310d63ce2bSvenki }
432