1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2004 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate #include <stdio.h>
30*7c478bd9Sstevel@tonic-gate #include <stdlib.h>
31*7c478bd9Sstevel@tonic-gate #include <stropts.h>
32*7c478bd9Sstevel@tonic-gate #include <synch.h>
33*7c478bd9Sstevel@tonic-gate #include <thread.h>
34*7c478bd9Sstevel@tonic-gate #include <libsysevent.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/sysevent/eventdefs.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/sysevent/dev.h>
37*7c478bd9Sstevel@tonic-gate #include <errno.h>
38*7c478bd9Sstevel@tonic-gate #include <libgen.h>
39*7c478bd9Sstevel@tonic-gate #include <unistd.h>
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate #include "libdiskmgt.h"
42*7c478bd9Sstevel@tonic-gate #include "disks_private.h"
43*7c478bd9Sstevel@tonic-gate 
44*7c478bd9Sstevel@tonic-gate struct event_list {
45*7c478bd9Sstevel@tonic-gate 	struct event_list	*next;
46*7c478bd9Sstevel@tonic-gate 	nvlist_t		*event;
47*7c478bd9Sstevel@tonic-gate };
48*7c478bd9Sstevel@tonic-gate 
49*7c478bd9Sstevel@tonic-gate static struct event_list	*events = NULL;
50*7c478bd9Sstevel@tonic-gate static int			event_error = 0;
51*7c478bd9Sstevel@tonic-gate static int			event_break = 0;
52*7c478bd9Sstevel@tonic-gate static mutex_t			queue_lock;
53*7c478bd9Sstevel@tonic-gate static sema_t			semaphore;
54*7c478bd9Sstevel@tonic-gate 
55*7c478bd9Sstevel@tonic-gate /*
56*7c478bd9Sstevel@tonic-gate  * When we add a controller we get an add event for each drive on the
57*7c478bd9Sstevel@tonic-gate  * controller.  We don't want to walk the devtree for each drive since
58*7c478bd9Sstevel@tonic-gate  * we will get the same information each time.  So, the solution is to
59*7c478bd9Sstevel@tonic-gate  * wait for a few seconds for all of the add events to come in and then
60*7c478bd9Sstevel@tonic-gate  * do a single walk.  If an add event comes in after we start the walk, we
61*7c478bd9Sstevel@tonic-gate  * need to do another walk since we might have missed that drive.
62*7c478bd9Sstevel@tonic-gate  *
63*7c478bd9Sstevel@tonic-gate  * State: 0 - no walker; 1 - walker waiting; 2 - walker running
64*7c478bd9Sstevel@tonic-gate  *	0 -> 1; wait a few seconds
65*7c478bd9Sstevel@tonic-gate  *	1 -> 2; walking the devtree
66*7c478bd9Sstevel@tonic-gate  *	2 -> either 0 or 1 (see below)
67*7c478bd9Sstevel@tonic-gate  * While running (state 2), if event comes in, go back to waiting (state 1)
68*7c478bd9Sstevel@tonic-gate  * after the walk otherwise go back to none (state 0).
69*7c478bd9Sstevel@tonic-gate  *
70*7c478bd9Sstevel@tonic-gate  * walker_lock protects walker_state & events_pending
71*7c478bd9Sstevel@tonic-gate  */
72*7c478bd9Sstevel@tonic-gate #define	WALK_NONE		0
73*7c478bd9Sstevel@tonic-gate #define	WALK_WAITING		1
74*7c478bd9Sstevel@tonic-gate #define	WALK_RUNNING		2
75*7c478bd9Sstevel@tonic-gate #define	WALK_WAIT_TIME		60	/* wait 60 seconds */
76*7c478bd9Sstevel@tonic-gate 
77*7c478bd9Sstevel@tonic-gate static mutex_t			walker_lock;
78*7c478bd9Sstevel@tonic-gate static int			walker_state = WALK_NONE;
79*7c478bd9Sstevel@tonic-gate static int			events_pending = 0;
80*7c478bd9Sstevel@tonic-gate 
81*7c478bd9Sstevel@tonic-gate static int			sendevents = 0;
82*7c478bd9Sstevel@tonic-gate 
83*7c478bd9Sstevel@tonic-gate static void		add_event_to_queue(nvlist_t *event);
84*7c478bd9Sstevel@tonic-gate static void		cb_watch_events();
85*7c478bd9Sstevel@tonic-gate static void		event_handler(sysevent_t *ev);
86*7c478bd9Sstevel@tonic-gate static void		print_nvlist(char *prefix, nvlist_t *list);
87*7c478bd9Sstevel@tonic-gate static void		walk_devtree();
88*7c478bd9Sstevel@tonic-gate static void		walker(void *arg);
89*7c478bd9Sstevel@tonic-gate 
90*7c478bd9Sstevel@tonic-gate static void(*callback)(nvlist_t *, int) = NULL;
91*7c478bd9Sstevel@tonic-gate 
92*7c478bd9Sstevel@tonic-gate nvlist_t *
93*7c478bd9Sstevel@tonic-gate dm_get_event(int *errp)
94*7c478bd9Sstevel@tonic-gate {
95*7c478bd9Sstevel@tonic-gate 	nvlist_t *event = NULL;
96*7c478bd9Sstevel@tonic-gate 
97*7c478bd9Sstevel@tonic-gate 	*errp = 0;
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 	/* wait until there is an event in the queue */
100*7c478bd9Sstevel@tonic-gate 	/*CONSTCOND*/
101*7c478bd9Sstevel@tonic-gate 	while (1) {
102*7c478bd9Sstevel@tonic-gate 	    (void) sema_wait(&semaphore);
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate 	    if (event_break) {
105*7c478bd9Sstevel@tonic-gate 		event_break = 0;
106*7c478bd9Sstevel@tonic-gate 		*errp = EINTR;
107*7c478bd9Sstevel@tonic-gate 		break;
108*7c478bd9Sstevel@tonic-gate 	    }
109*7c478bd9Sstevel@tonic-gate 
110*7c478bd9Sstevel@tonic-gate 	    (void) mutex_lock(&queue_lock);
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate 	    /* first see if we ran out of memory since the last call */
113*7c478bd9Sstevel@tonic-gate 	    if (event_error != 0) {
114*7c478bd9Sstevel@tonic-gate 		*errp = event_error;
115*7c478bd9Sstevel@tonic-gate 		event_error = 0;
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate 	    } else if (events != NULL) {
118*7c478bd9Sstevel@tonic-gate 		struct event_list *tmpp;
119*7c478bd9Sstevel@tonic-gate 
120*7c478bd9Sstevel@tonic-gate 		event = events->event;
121*7c478bd9Sstevel@tonic-gate 		tmpp = events->next;
122*7c478bd9Sstevel@tonic-gate 		free(events);
123*7c478bd9Sstevel@tonic-gate 		events = tmpp;
124*7c478bd9Sstevel@tonic-gate 	    }
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate 	    (void) mutex_unlock(&queue_lock);
127*7c478bd9Sstevel@tonic-gate 
128*7c478bd9Sstevel@tonic-gate 	    if (*errp != 0 || event != NULL) {
129*7c478bd9Sstevel@tonic-gate 		break;
130*7c478bd9Sstevel@tonic-gate 	    }
131*7c478bd9Sstevel@tonic-gate 	}
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate 	return (event);
134*7c478bd9Sstevel@tonic-gate }
135*7c478bd9Sstevel@tonic-gate 
136*7c478bd9Sstevel@tonic-gate void
137*7c478bd9Sstevel@tonic-gate dm_init_event_queue(void (*cb)(nvlist_t *, int), int *errp)
138*7c478bd9Sstevel@tonic-gate {
139*7c478bd9Sstevel@tonic-gate 	if (sendevents == 1) {
140*7c478bd9Sstevel@tonic-gate 	    /* we were already initialized, see what changes to make */
141*7c478bd9Sstevel@tonic-gate 	    *errp = 0;
142*7c478bd9Sstevel@tonic-gate 	    if (cb != callback) {
143*7c478bd9Sstevel@tonic-gate 
144*7c478bd9Sstevel@tonic-gate 		callback = cb;
145*7c478bd9Sstevel@tonic-gate 		if (cb == NULL) {
146*7c478bd9Sstevel@tonic-gate 		    /* clearing the cb so shutdown the internal cb thread */
147*7c478bd9Sstevel@tonic-gate 		    event_break = 1;
148*7c478bd9Sstevel@tonic-gate 		    (void) sema_post(&semaphore);
149*7c478bd9Sstevel@tonic-gate 
150*7c478bd9Sstevel@tonic-gate 		} else {
151*7c478bd9Sstevel@tonic-gate 		    /* installing a cb; we didn't have one before */
152*7c478bd9Sstevel@tonic-gate 		    thread_t watch_thread;
153*7c478bd9Sstevel@tonic-gate 
154*7c478bd9Sstevel@tonic-gate 		    *errp = thr_create(NULL, NULL,
155*7c478bd9Sstevel@tonic-gate 			(void *(*)(void *))cb_watch_events, NULL, THR_DAEMON,
156*7c478bd9Sstevel@tonic-gate 			&watch_thread);
157*7c478bd9Sstevel@tonic-gate 		}
158*7c478bd9Sstevel@tonic-gate 	    }
159*7c478bd9Sstevel@tonic-gate 
160*7c478bd9Sstevel@tonic-gate 	} else {
161*7c478bd9Sstevel@tonic-gate 	    /* first time to initialize */
162*7c478bd9Sstevel@tonic-gate 	    sendevents = 1;
163*7c478bd9Sstevel@tonic-gate 
164*7c478bd9Sstevel@tonic-gate 	    *errp = sema_init(&semaphore, 0, USYNC_THREAD, NULL);
165*7c478bd9Sstevel@tonic-gate 	    if (*errp != 0) {
166*7c478bd9Sstevel@tonic-gate 		return;
167*7c478bd9Sstevel@tonic-gate 	    }
168*7c478bd9Sstevel@tonic-gate 
169*7c478bd9Sstevel@tonic-gate 	    if (cb != NULL) {
170*7c478bd9Sstevel@tonic-gate 		thread_t watch_thread;
171*7c478bd9Sstevel@tonic-gate 
172*7c478bd9Sstevel@tonic-gate 		callback = cb;
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate 		*errp = thr_create(NULL, NULL,
175*7c478bd9Sstevel@tonic-gate 		    (void *(*)(void *))cb_watch_events, NULL, THR_DAEMON,
176*7c478bd9Sstevel@tonic-gate 		    &watch_thread);
177*7c478bd9Sstevel@tonic-gate 	    }
178*7c478bd9Sstevel@tonic-gate 	}
179*7c478bd9Sstevel@tonic-gate }
180*7c478bd9Sstevel@tonic-gate 
181*7c478bd9Sstevel@tonic-gate void
182*7c478bd9Sstevel@tonic-gate events_new_event(char *name, int dtype, char *etype)
183*7c478bd9Sstevel@tonic-gate {
184*7c478bd9Sstevel@tonic-gate 	nvlist_t	*event = NULL;
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate 	if (!sendevents) {
187*7c478bd9Sstevel@tonic-gate 	    return;
188*7c478bd9Sstevel@tonic-gate 	}
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&event, NVATTRS, 0) != 0) {
191*7c478bd9Sstevel@tonic-gate 	    event = NULL;
192*7c478bd9Sstevel@tonic-gate 
193*7c478bd9Sstevel@tonic-gate 	} else {
194*7c478bd9Sstevel@tonic-gate 	    int	error = 0;
195*7c478bd9Sstevel@tonic-gate 
196*7c478bd9Sstevel@tonic-gate 	    if (name != NULL &&
197*7c478bd9Sstevel@tonic-gate 		nvlist_add_string(event, DM_EV_NAME, name) != 0) {
198*7c478bd9Sstevel@tonic-gate 		error = ENOMEM;
199*7c478bd9Sstevel@tonic-gate 	    }
200*7c478bd9Sstevel@tonic-gate 
201*7c478bd9Sstevel@tonic-gate 	    if (dtype != -1 &&
202*7c478bd9Sstevel@tonic-gate 		nvlist_add_uint32(event, DM_EV_DTYPE, dtype) != 0) {
203*7c478bd9Sstevel@tonic-gate 		error = ENOMEM;
204*7c478bd9Sstevel@tonic-gate 	    }
205*7c478bd9Sstevel@tonic-gate 
206*7c478bd9Sstevel@tonic-gate 	    if (nvlist_add_string(event, DM_EV_TYPE, etype) != 0) {
207*7c478bd9Sstevel@tonic-gate 		error = ENOMEM;
208*7c478bd9Sstevel@tonic-gate 	    }
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 	    if (error != 0) {
211*7c478bd9Sstevel@tonic-gate 		nvlist_free(event);
212*7c478bd9Sstevel@tonic-gate 		event = NULL;
213*7c478bd9Sstevel@tonic-gate 	    }
214*7c478bd9Sstevel@tonic-gate 	}
215*7c478bd9Sstevel@tonic-gate 
216*7c478bd9Sstevel@tonic-gate 	add_event_to_queue(event);
217*7c478bd9Sstevel@tonic-gate }
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate void
220*7c478bd9Sstevel@tonic-gate events_new_slice_event(char *dev, char *type)
221*7c478bd9Sstevel@tonic-gate {
222*7c478bd9Sstevel@tonic-gate 	events_new_event(basename(dev), DM_SLICE, type);
223*7c478bd9Sstevel@tonic-gate }
224*7c478bd9Sstevel@tonic-gate 
225*7c478bd9Sstevel@tonic-gate int
226*7c478bd9Sstevel@tonic-gate events_start_event_watcher()
227*7c478bd9Sstevel@tonic-gate {
228*7c478bd9Sstevel@tonic-gate 	sysevent_handle_t *shp;
229*7c478bd9Sstevel@tonic-gate 	const char *subclass_list[1];
230*7c478bd9Sstevel@tonic-gate 
231*7c478bd9Sstevel@tonic-gate 	/* Bind event handler and create subscriber handle */
232*7c478bd9Sstevel@tonic-gate 	shp = sysevent_bind_handle(event_handler);
233*7c478bd9Sstevel@tonic-gate 	if (shp == NULL) {
234*7c478bd9Sstevel@tonic-gate 	    if (dm_debug) {
235*7c478bd9Sstevel@tonic-gate 		/* keep going when we're debugging */
236*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "ERROR: bind failed %d\n", errno);
237*7c478bd9Sstevel@tonic-gate 		return (0);
238*7c478bd9Sstevel@tonic-gate 	    }
239*7c478bd9Sstevel@tonic-gate 	    return (errno);
240*7c478bd9Sstevel@tonic-gate 	}
241*7c478bd9Sstevel@tonic-gate 
242*7c478bd9Sstevel@tonic-gate 	subclass_list[0] = ESC_DISK;
243*7c478bd9Sstevel@tonic-gate 	if (sysevent_subscribe_event(shp, EC_DEV_ADD, subclass_list, 1) != 0) {
244*7c478bd9Sstevel@tonic-gate 	    if (dm_debug) {
245*7c478bd9Sstevel@tonic-gate 		/* keep going when we're debugging */
246*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "ERROR: subscribe failed\n");
247*7c478bd9Sstevel@tonic-gate 		return (0);
248*7c478bd9Sstevel@tonic-gate 	    }
249*7c478bd9Sstevel@tonic-gate 	    return (errno);
250*7c478bd9Sstevel@tonic-gate 	}
251*7c478bd9Sstevel@tonic-gate 	if (sysevent_subscribe_event(shp, EC_DEV_REMOVE, subclass_list, 1)
252*7c478bd9Sstevel@tonic-gate 	    != 0) {
253*7c478bd9Sstevel@tonic-gate 	    if (dm_debug) {
254*7c478bd9Sstevel@tonic-gate 		/* keep going when we're debugging */
255*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "ERROR: subscribe failed\n");
256*7c478bd9Sstevel@tonic-gate 		return (0);
257*7c478bd9Sstevel@tonic-gate 	    }
258*7c478bd9Sstevel@tonic-gate 	    return (errno);
259*7c478bd9Sstevel@tonic-gate 	}
260*7c478bd9Sstevel@tonic-gate 
261*7c478bd9Sstevel@tonic-gate 	return (0);
262*7c478bd9Sstevel@tonic-gate }
263*7c478bd9Sstevel@tonic-gate 
264*7c478bd9Sstevel@tonic-gate static void
265*7c478bd9Sstevel@tonic-gate add_event_to_queue(nvlist_t *event)
266*7c478bd9Sstevel@tonic-gate {
267*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&queue_lock);
268*7c478bd9Sstevel@tonic-gate 
269*7c478bd9Sstevel@tonic-gate 	if (event == NULL) {
270*7c478bd9Sstevel@tonic-gate 	    event_error = ENOMEM;
271*7c478bd9Sstevel@tonic-gate 	    (void) mutex_unlock(&queue_lock);
272*7c478bd9Sstevel@tonic-gate 	    return;
273*7c478bd9Sstevel@tonic-gate 	}
274*7c478bd9Sstevel@tonic-gate 
275*7c478bd9Sstevel@tonic-gate 	if (events == NULL) {
276*7c478bd9Sstevel@tonic-gate 
277*7c478bd9Sstevel@tonic-gate 	    events = (struct event_list *)malloc(sizeof (struct event_list));
278*7c478bd9Sstevel@tonic-gate 	    if (events == NULL) {
279*7c478bd9Sstevel@tonic-gate 		event_error = ENOMEM;
280*7c478bd9Sstevel@tonic-gate 		nvlist_free(event);
281*7c478bd9Sstevel@tonic-gate 	    } else {
282*7c478bd9Sstevel@tonic-gate 		events->next = NULL;
283*7c478bd9Sstevel@tonic-gate 		events->event = event;
284*7c478bd9Sstevel@tonic-gate 	    }
285*7c478bd9Sstevel@tonic-gate 
286*7c478bd9Sstevel@tonic-gate 	} else {
287*7c478bd9Sstevel@tonic-gate 	    /* already have events in the queue */
288*7c478bd9Sstevel@tonic-gate 	    struct event_list *ep;
289*7c478bd9Sstevel@tonic-gate 	    struct event_list *new_event;
290*7c478bd9Sstevel@tonic-gate 
291*7c478bd9Sstevel@tonic-gate 	    /* find the last element in the list */
292*7c478bd9Sstevel@tonic-gate 	    for (ep = events; ep->next != NULL; ep = ep->next);
293*7c478bd9Sstevel@tonic-gate 
294*7c478bd9Sstevel@tonic-gate 	    new_event = (struct event_list *)malloc(sizeof (struct event_list));
295*7c478bd9Sstevel@tonic-gate 	    if (new_event == NULL) {
296*7c478bd9Sstevel@tonic-gate 		event_error = ENOMEM;
297*7c478bd9Sstevel@tonic-gate 		nvlist_free(event);
298*7c478bd9Sstevel@tonic-gate 	    } else {
299*7c478bd9Sstevel@tonic-gate 		new_event->next = NULL;
300*7c478bd9Sstevel@tonic-gate 		new_event->event = event;
301*7c478bd9Sstevel@tonic-gate 		ep->next = new_event;
302*7c478bd9Sstevel@tonic-gate 	    }
303*7c478bd9Sstevel@tonic-gate 	}
304*7c478bd9Sstevel@tonic-gate 
305*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&queue_lock);
306*7c478bd9Sstevel@tonic-gate 
307*7c478bd9Sstevel@tonic-gate 	(void) sema_post(&semaphore);
308*7c478bd9Sstevel@tonic-gate }
309*7c478bd9Sstevel@tonic-gate 
310*7c478bd9Sstevel@tonic-gate static void
311*7c478bd9Sstevel@tonic-gate cb_watch_events()
312*7c478bd9Sstevel@tonic-gate {
313*7c478bd9Sstevel@tonic-gate 	nvlist_t	*event;
314*7c478bd9Sstevel@tonic-gate 	int		error;
315*7c478bd9Sstevel@tonic-gate 
316*7c478bd9Sstevel@tonic-gate 	/*CONSTCOND*/
317*7c478bd9Sstevel@tonic-gate 	while (1) {
318*7c478bd9Sstevel@tonic-gate 	    event = dm_get_event(&error);
319*7c478bd9Sstevel@tonic-gate 	    if (callback == NULL) {
320*7c478bd9Sstevel@tonic-gate 		/* end the thread */
321*7c478bd9Sstevel@tonic-gate 		return;
322*7c478bd9Sstevel@tonic-gate 	    }
323*7c478bd9Sstevel@tonic-gate 	    callback(event, error);
324*7c478bd9Sstevel@tonic-gate 	}
325*7c478bd9Sstevel@tonic-gate }
326*7c478bd9Sstevel@tonic-gate 
327*7c478bd9Sstevel@tonic-gate static void
328*7c478bd9Sstevel@tonic-gate event_handler(sysevent_t *ev)
329*7c478bd9Sstevel@tonic-gate {
330*7c478bd9Sstevel@tonic-gate 	char		*class_name;
331*7c478bd9Sstevel@tonic-gate 	char		*pub;
332*7c478bd9Sstevel@tonic-gate 
333*7c478bd9Sstevel@tonic-gate 	class_name = sysevent_get_class_name(ev);
334*7c478bd9Sstevel@tonic-gate 	if (dm_debug) {
335*7c478bd9Sstevel@tonic-gate 	    (void) fprintf(stderr, "****EVENT: %s %s ", class_name,
336*7c478bd9Sstevel@tonic-gate 		sysevent_get_subclass_name(ev));
337*7c478bd9Sstevel@tonic-gate 	    if ((pub = sysevent_get_pub_name(ev)) != NULL) {
338*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s\n", pub);
339*7c478bd9Sstevel@tonic-gate 		free(pub);
340*7c478bd9Sstevel@tonic-gate 	    } else {
341*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "\n");
342*7c478bd9Sstevel@tonic-gate 	    }
343*7c478bd9Sstevel@tonic-gate 	}
344*7c478bd9Sstevel@tonic-gate 
345*7c478bd9Sstevel@tonic-gate 	if (libdiskmgt_str_eq(class_name, EC_DEV_ADD)) {
346*7c478bd9Sstevel@tonic-gate 	    /* batch up the adds into a single devtree walk */
347*7c478bd9Sstevel@tonic-gate 	    walk_devtree();
348*7c478bd9Sstevel@tonic-gate 
349*7c478bd9Sstevel@tonic-gate 	} else if (libdiskmgt_str_eq(class_name, EC_DEV_REMOVE)) {
350*7c478bd9Sstevel@tonic-gate 	    nvlist_t	*nvlist = NULL;
351*7c478bd9Sstevel@tonic-gate 	    char	*dev_name = NULL;
352*7c478bd9Sstevel@tonic-gate 
353*7c478bd9Sstevel@tonic-gate 	    (void) sysevent_get_attr_list(ev, &nvlist);
354*7c478bd9Sstevel@tonic-gate 	    if (nvlist != NULL) {
355*7c478bd9Sstevel@tonic-gate 		(void) nvlist_lookup_string(nvlist, DEV_NAME, &dev_name);
356*7c478bd9Sstevel@tonic-gate 
357*7c478bd9Sstevel@tonic-gate 		if (dm_debug) {
358*7c478bd9Sstevel@tonic-gate 		    print_nvlist("**** ", nvlist);
359*7c478bd9Sstevel@tonic-gate 		}
360*7c478bd9Sstevel@tonic-gate 	    }
361*7c478bd9Sstevel@tonic-gate 
362*7c478bd9Sstevel@tonic-gate 	    if (dev_name != NULL) {
363*7c478bd9Sstevel@tonic-gate 		cache_update(DM_EV_DISK_DELETE, dev_name);
364*7c478bd9Sstevel@tonic-gate 	    }
365*7c478bd9Sstevel@tonic-gate 
366*7c478bd9Sstevel@tonic-gate 	    if (nvlist != NULL) {
367*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvlist);
368*7c478bd9Sstevel@tonic-gate 	    }
369*7c478bd9Sstevel@tonic-gate 	}
370*7c478bd9Sstevel@tonic-gate }
371*7c478bd9Sstevel@tonic-gate 
372*7c478bd9Sstevel@tonic-gate /*
373*7c478bd9Sstevel@tonic-gate  * This is a debugging function only.
374*7c478bd9Sstevel@tonic-gate  */
375*7c478bd9Sstevel@tonic-gate static void
376*7c478bd9Sstevel@tonic-gate print_nvlist(char *prefix, nvlist_t *list)
377*7c478bd9Sstevel@tonic-gate {
378*7c478bd9Sstevel@tonic-gate 	nvpair_t	*nvp;
379*7c478bd9Sstevel@tonic-gate 
380*7c478bd9Sstevel@tonic-gate 	nvp = nvlist_next_nvpair(list, NULL);
381*7c478bd9Sstevel@tonic-gate 	while (nvp != NULL) {
382*7c478bd9Sstevel@tonic-gate 	    char	*attrname;
383*7c478bd9Sstevel@tonic-gate 	    char	*str;
384*7c478bd9Sstevel@tonic-gate 	    uint32_t	ui32;
385*7c478bd9Sstevel@tonic-gate 	    uint64_t	ui64;
386*7c478bd9Sstevel@tonic-gate 	    char	**str_array;
387*7c478bd9Sstevel@tonic-gate 	    uint_t	cnt;
388*7c478bd9Sstevel@tonic-gate 	    int		i;
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate 	    attrname = nvpair_name(nvp);
391*7c478bd9Sstevel@tonic-gate 	    switch (nvpair_type(nvp)) {
392*7c478bd9Sstevel@tonic-gate 	    case DATA_TYPE_STRING:
393*7c478bd9Sstevel@tonic-gate 		(void) nvpair_value_string(nvp, &str);
394*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s%s: %s\n", prefix, attrname, str);
395*7c478bd9Sstevel@tonic-gate 		break;
396*7c478bd9Sstevel@tonic-gate 
397*7c478bd9Sstevel@tonic-gate 	    case DATA_TYPE_STRING_ARRAY:
398*7c478bd9Sstevel@tonic-gate 		(void) nvpair_value_string_array(nvp, &str_array, &cnt);
399*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s%s:\n", prefix, attrname);
400*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < cnt; i++) {
401*7c478bd9Sstevel@tonic-gate 		    (void) fprintf(stderr, "%s    %s\n", prefix, str_array[i]);
402*7c478bd9Sstevel@tonic-gate 		}
403*7c478bd9Sstevel@tonic-gate 		break;
404*7c478bd9Sstevel@tonic-gate 
405*7c478bd9Sstevel@tonic-gate 	    case DATA_TYPE_UINT32:
406*7c478bd9Sstevel@tonic-gate 		(void) nvpair_value_uint32(nvp, &ui32);
407*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s%s: %u\n", prefix, attrname, ui32);
408*7c478bd9Sstevel@tonic-gate 		break;
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate 	    case DATA_TYPE_UINT64:
411*7c478bd9Sstevel@tonic-gate 		(void) nvpair_value_uint64(nvp, &ui64);
412*7c478bd9Sstevel@tonic-gate #ifdef _LP64
413*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s%s: %lu\n", prefix, attrname, ui64);
414*7c478bd9Sstevel@tonic-gate #else
415*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s%s: %llu\n", prefix, attrname, ui64);
416*7c478bd9Sstevel@tonic-gate #endif
417*7c478bd9Sstevel@tonic-gate 		break;
418*7c478bd9Sstevel@tonic-gate 
419*7c478bd9Sstevel@tonic-gate 
420*7c478bd9Sstevel@tonic-gate 	    case DATA_TYPE_BOOLEAN:
421*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s%s: true\n", prefix, attrname);
422*7c478bd9Sstevel@tonic-gate 		break;
423*7c478bd9Sstevel@tonic-gate 
424*7c478bd9Sstevel@tonic-gate 	    default:
425*7c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s%s: UNSUPPORTED TYPE\n", prefix,
426*7c478bd9Sstevel@tonic-gate 		    attrname);
427*7c478bd9Sstevel@tonic-gate 		break;
428*7c478bd9Sstevel@tonic-gate 	    }
429*7c478bd9Sstevel@tonic-gate 
430*7c478bd9Sstevel@tonic-gate 	    nvp = nvlist_next_nvpair(list, nvp);
431*7c478bd9Sstevel@tonic-gate 	}
432*7c478bd9Sstevel@tonic-gate }
433*7c478bd9Sstevel@tonic-gate 
434*7c478bd9Sstevel@tonic-gate /*
435*7c478bd9Sstevel@tonic-gate  * Batch up the adds into a single devtree walk.  We can get a bunch of
436*7c478bd9Sstevel@tonic-gate  * adds when we add a controller since we will get an add event for each
437*7c478bd9Sstevel@tonic-gate  * drive.
438*7c478bd9Sstevel@tonic-gate  */
439*7c478bd9Sstevel@tonic-gate static void
440*7c478bd9Sstevel@tonic-gate walk_devtree()
441*7c478bd9Sstevel@tonic-gate {
442*7c478bd9Sstevel@tonic-gate 	thread_t	walk_thread;
443*7c478bd9Sstevel@tonic-gate 
444*7c478bd9Sstevel@tonic-gate 	(void) mutex_lock(&walker_lock);
445*7c478bd9Sstevel@tonic-gate 
446*7c478bd9Sstevel@tonic-gate 	switch (walker_state) {
447*7c478bd9Sstevel@tonic-gate 	case WALK_NONE:
448*7c478bd9Sstevel@tonic-gate 	    if (thr_create(NULL, NULL, (void *(*)(void *))walker, NULL,
449*7c478bd9Sstevel@tonic-gate 		THR_DAEMON, &walk_thread) == 0) {
450*7c478bd9Sstevel@tonic-gate 		walker_state = WALK_WAITING;
451*7c478bd9Sstevel@tonic-gate 	    }
452*7c478bd9Sstevel@tonic-gate 	    break;
453*7c478bd9Sstevel@tonic-gate 
454*7c478bd9Sstevel@tonic-gate 	case WALK_WAITING:
455*7c478bd9Sstevel@tonic-gate 	    /* absorb the event and do nothing */
456*7c478bd9Sstevel@tonic-gate 	    break;
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate 	case WALK_RUNNING:
459*7c478bd9Sstevel@tonic-gate 	    events_pending = 1;
460*7c478bd9Sstevel@tonic-gate 	    break;
461*7c478bd9Sstevel@tonic-gate 	}
462*7c478bd9Sstevel@tonic-gate 
463*7c478bd9Sstevel@tonic-gate 	(void) mutex_unlock(&walker_lock);
464*7c478bd9Sstevel@tonic-gate }
465*7c478bd9Sstevel@tonic-gate 
466*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
467*7c478bd9Sstevel@tonic-gate static void
468*7c478bd9Sstevel@tonic-gate walker(void *arg)
469*7c478bd9Sstevel@tonic-gate {
470*7c478bd9Sstevel@tonic-gate 	int	walk_again = 0;
471*7c478bd9Sstevel@tonic-gate 
472*7c478bd9Sstevel@tonic-gate 	do {
473*7c478bd9Sstevel@tonic-gate 	    /* start by wating for a few seconds to absorb extra events */
474*7c478bd9Sstevel@tonic-gate 	    (void) sleep(WALK_WAIT_TIME);
475*7c478bd9Sstevel@tonic-gate 
476*7c478bd9Sstevel@tonic-gate 	    (void) mutex_lock(&walker_lock);
477*7c478bd9Sstevel@tonic-gate 	    walker_state = WALK_RUNNING;
478*7c478bd9Sstevel@tonic-gate 	    (void) mutex_unlock(&walker_lock);
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	    cache_update(DM_EV_DISK_ADD, NULL);
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate 	    (void) mutex_lock(&walker_lock);
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate 	    if (events_pending) {
485*7c478bd9Sstevel@tonic-gate 		events_pending = 0;
486*7c478bd9Sstevel@tonic-gate 		walker_state = WALK_WAITING;
487*7c478bd9Sstevel@tonic-gate 		walk_again = 1;
488*7c478bd9Sstevel@tonic-gate 	    } else {
489*7c478bd9Sstevel@tonic-gate 		walker_state = WALK_NONE;
490*7c478bd9Sstevel@tonic-gate 		walk_again = 0;
491*7c478bd9Sstevel@tonic-gate 	    }
492*7c478bd9Sstevel@tonic-gate 
493*7c478bd9Sstevel@tonic-gate 	    (void) mutex_unlock(&walker_lock);
494*7c478bd9Sstevel@tonic-gate 
495*7c478bd9Sstevel@tonic-gate 	} while (walk_again);
496*7c478bd9Sstevel@tonic-gate }
497