xref: /illumos-gate/usr/src/uts/common/os/log_sysevent.c (revision 7c478bd95313f5f23a4c958a745db2134aa0324)
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 <sys/types.h>
30*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
31*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
32*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
33*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
34*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
35*7c478bd9Sstevel@tonic-gate #include <sys/vmem.h>
36*7c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
37*7c478bd9Sstevel@tonic-gate #include <sys/callb.h>
38*7c478bd9Sstevel@tonic-gate #include <sys/sysevent.h>
39*7c478bd9Sstevel@tonic-gate #include <sys/sysevent_impl.h>
40*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
41*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
42*7c478bd9Sstevel@tonic-gate #include <sys/disp.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
45*7c478bd9Sstevel@tonic-gate 
46*7c478bd9Sstevel@tonic-gate /* for doors */
47*7c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/door.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h>
52*7c478bd9Sstevel@tonic-gate 
53*7c478bd9Sstevel@tonic-gate /*
54*7c478bd9Sstevel@tonic-gate  * log_sysevent.c - Provides the interfaces for kernel event publication
55*7c478bd9Sstevel@tonic-gate  *			to the sysevent event daemon (syseventd).
56*7c478bd9Sstevel@tonic-gate  */
57*7c478bd9Sstevel@tonic-gate 
58*7c478bd9Sstevel@tonic-gate /*
59*7c478bd9Sstevel@tonic-gate  * Debug stuff
60*7c478bd9Sstevel@tonic-gate  */
61*7c478bd9Sstevel@tonic-gate static int log_event_debug = 0;
62*7c478bd9Sstevel@tonic-gate #define	LOG_DEBUG(args)  if (log_event_debug) cmn_err args
63*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
64*7c478bd9Sstevel@tonic-gate #define	LOG_DEBUG1(args)  if (log_event_debug > 1) cmn_err args
65*7c478bd9Sstevel@tonic-gate #else
66*7c478bd9Sstevel@tonic-gate #define	LOG_DEBUG1(args)
67*7c478bd9Sstevel@tonic-gate #endif
68*7c478bd9Sstevel@tonic-gate 
69*7c478bd9Sstevel@tonic-gate /*
70*7c478bd9Sstevel@tonic-gate  * Local static vars
71*7c478bd9Sstevel@tonic-gate  */
72*7c478bd9Sstevel@tonic-gate /* queue of event buffers sent to syseventd */
73*7c478bd9Sstevel@tonic-gate static log_eventq_t *log_eventq_sent = NULL;
74*7c478bd9Sstevel@tonic-gate 
75*7c478bd9Sstevel@tonic-gate /*
76*7c478bd9Sstevel@tonic-gate  * Count of event buffers in the queue
77*7c478bd9Sstevel@tonic-gate  */
78*7c478bd9Sstevel@tonic-gate int log_eventq_cnt = 0;
79*7c478bd9Sstevel@tonic-gate 
80*7c478bd9Sstevel@tonic-gate /* queue of event buffers awaiting delivery to syseventd */
81*7c478bd9Sstevel@tonic-gate static log_eventq_t *log_eventq_head = NULL;
82*7c478bd9Sstevel@tonic-gate static log_eventq_t *log_eventq_tail = NULL;
83*7c478bd9Sstevel@tonic-gate static uint64_t kernel_event_id = 0;
84*7c478bd9Sstevel@tonic-gate static int encoding = NV_ENCODE_NATIVE;
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate /* log event delivery flag */
87*7c478bd9Sstevel@tonic-gate #define	LOGEVENT_DELIVERY_OK	0	/* OK to deliver event buffers */
88*7c478bd9Sstevel@tonic-gate #define	LOGEVENT_DELIVERY_CONT	1	/* Continue to deliver event buffers */
89*7c478bd9Sstevel@tonic-gate #define	LOGEVENT_DELIVERY_HOLD	2	/* Hold delivering of event buffers */
90*7c478bd9Sstevel@tonic-gate 
91*7c478bd9Sstevel@tonic-gate /*
92*7c478bd9Sstevel@tonic-gate  * Tunable maximum event buffer queue size. Size depends on how many events
93*7c478bd9Sstevel@tonic-gate  * the queue must hold when syseventd is not available, for example during
94*7c478bd9Sstevel@tonic-gate  * system startup. Experience showed that more than 2000 events could be posted
95*7c478bd9Sstevel@tonic-gate  * due to correctable memory errors.
96*7c478bd9Sstevel@tonic-gate  */
97*7c478bd9Sstevel@tonic-gate int logevent_max_q_sz = 5000;
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate 
100*7c478bd9Sstevel@tonic-gate static int log_event_delivery = LOGEVENT_DELIVERY_HOLD;
101*7c478bd9Sstevel@tonic-gate static char *logevent_door_upcall_filename = NULL;
102*7c478bd9Sstevel@tonic-gate static int logevent_door_upcall_filename_size;
103*7c478bd9Sstevel@tonic-gate 
104*7c478bd9Sstevel@tonic-gate static door_handle_t event_door = NULL;		/* Door for upcalls */
105*7c478bd9Sstevel@tonic-gate 
106*7c478bd9Sstevel@tonic-gate /*
107*7c478bd9Sstevel@tonic-gate  * async thread-related variables
108*7c478bd9Sstevel@tonic-gate  *
109*7c478bd9Sstevel@tonic-gate  * eventq_head_mutex - synchronizes access to the kernel event queue
110*7c478bd9Sstevel@tonic-gate  *
111*7c478bd9Sstevel@tonic-gate  * eventq_sent_mutex - synchronizes access to the queue of event sents to
112*7c478bd9Sstevel@tonic-gate  *			userlevel
113*7c478bd9Sstevel@tonic-gate  *
114*7c478bd9Sstevel@tonic-gate  * log_event_cv - condition variable signaled when an event has arrived or
115*7c478bd9Sstevel@tonic-gate  *			userlevel ready to process event buffers
116*7c478bd9Sstevel@tonic-gate  *
117*7c478bd9Sstevel@tonic-gate  * async_thread - asynchronous event delivery thread to userlevel daemon.
118*7c478bd9Sstevel@tonic-gate  *
119*7c478bd9Sstevel@tonic-gate  * sysevent_upcall_status - status of the door upcall link
120*7c478bd9Sstevel@tonic-gate  */
121*7c478bd9Sstevel@tonic-gate static kmutex_t eventq_head_mutex;
122*7c478bd9Sstevel@tonic-gate static kmutex_t eventq_sent_mutex;
123*7c478bd9Sstevel@tonic-gate static kcondvar_t log_event_cv;
124*7c478bd9Sstevel@tonic-gate static kthread_id_t async_thread = NULL;
125*7c478bd9Sstevel@tonic-gate 
126*7c478bd9Sstevel@tonic-gate static kmutex_t event_qfull_mutex;
127*7c478bd9Sstevel@tonic-gate static kcondvar_t event_qfull_cv;
128*7c478bd9Sstevel@tonic-gate static int event_qfull_blocked = 0;
129*7c478bd9Sstevel@tonic-gate 
130*7c478bd9Sstevel@tonic-gate static int sysevent_upcall_status = -1;
131*7c478bd9Sstevel@tonic-gate static kmutex_t registered_channel_mutex;
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate /*
134*7c478bd9Sstevel@tonic-gate  * Indicates the syseventd daemon has begun taking events
135*7c478bd9Sstevel@tonic-gate  */
136*7c478bd9Sstevel@tonic-gate int sysevent_daemon_init = 0;
137*7c478bd9Sstevel@tonic-gate 
138*7c478bd9Sstevel@tonic-gate /*
139*7c478bd9Sstevel@tonic-gate  * Back-off delay when door_ki_upcall returns EAGAIN.  Typically
140*7c478bd9Sstevel@tonic-gate  * caused by the server process doing a forkall().  Since all threads
141*7c478bd9Sstevel@tonic-gate  * but the thread actually doing the forkall() need to be quiesced,
142*7c478bd9Sstevel@tonic-gate  * the fork may take some time.  The min/max pause are in units
143*7c478bd9Sstevel@tonic-gate  * of clock ticks.
144*7c478bd9Sstevel@tonic-gate  */
145*7c478bd9Sstevel@tonic-gate #define	LOG_EVENT_MIN_PAUSE	8
146*7c478bd9Sstevel@tonic-gate #define	LOG_EVENT_MAX_PAUSE	128
147*7c478bd9Sstevel@tonic-gate 
148*7c478bd9Sstevel@tonic-gate static kmutex_t	event_pause_mutex;
149*7c478bd9Sstevel@tonic-gate static kcondvar_t event_pause_cv;
150*7c478bd9Sstevel@tonic-gate static int event_pause_state = 0;
151*7c478bd9Sstevel@tonic-gate 
152*7c478bd9Sstevel@tonic-gate /*
153*7c478bd9Sstevel@tonic-gate  * log_event_upcall_lookup - Establish door connection with user event
154*7c478bd9Sstevel@tonic-gate  *				daemon (syseventd)
155*7c478bd9Sstevel@tonic-gate  */
156*7c478bd9Sstevel@tonic-gate static int
157*7c478bd9Sstevel@tonic-gate log_event_upcall_lookup()
158*7c478bd9Sstevel@tonic-gate {
159*7c478bd9Sstevel@tonic-gate 	int	error;
160*7c478bd9Sstevel@tonic-gate 
161*7c478bd9Sstevel@tonic-gate 	if (event_door) {	/* Release our previous hold (if any) */
162*7c478bd9Sstevel@tonic-gate 		door_ki_rele(event_door);
163*7c478bd9Sstevel@tonic-gate 	}
164*7c478bd9Sstevel@tonic-gate 
165*7c478bd9Sstevel@tonic-gate 	event_door = NULL;
166*7c478bd9Sstevel@tonic-gate 
167*7c478bd9Sstevel@tonic-gate 	/*
168*7c478bd9Sstevel@tonic-gate 	 * Locate the door used for upcalls
169*7c478bd9Sstevel@tonic-gate 	 */
170*7c478bd9Sstevel@tonic-gate 	if ((error =
171*7c478bd9Sstevel@tonic-gate 	    door_ki_open(logevent_door_upcall_filename, &event_door)) != 0) {
172*7c478bd9Sstevel@tonic-gate 		return (error);
173*7c478bd9Sstevel@tonic-gate 	}
174*7c478bd9Sstevel@tonic-gate 
175*7c478bd9Sstevel@tonic-gate 	return (0);
176*7c478bd9Sstevel@tonic-gate }
177*7c478bd9Sstevel@tonic-gate 
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
180*7c478bd9Sstevel@tonic-gate static void
181*7c478bd9Sstevel@tonic-gate log_event_busy_timeout(void *arg)
182*7c478bd9Sstevel@tonic-gate {
183*7c478bd9Sstevel@tonic-gate 	mutex_enter(&event_pause_mutex);
184*7c478bd9Sstevel@tonic-gate 	event_pause_state = 0;
185*7c478bd9Sstevel@tonic-gate 	cv_signal(&event_pause_cv);
186*7c478bd9Sstevel@tonic-gate 	mutex_exit(&event_pause_mutex);
187*7c478bd9Sstevel@tonic-gate }
188*7c478bd9Sstevel@tonic-gate 
189*7c478bd9Sstevel@tonic-gate static void
190*7c478bd9Sstevel@tonic-gate log_event_pause(int nticks)
191*7c478bd9Sstevel@tonic-gate {
192*7c478bd9Sstevel@tonic-gate 	timeout_id_t id;
193*7c478bd9Sstevel@tonic-gate 
194*7c478bd9Sstevel@tonic-gate 	/*
195*7c478bd9Sstevel@tonic-gate 	 * Only one use of log_event_pause at a time
196*7c478bd9Sstevel@tonic-gate 	 */
197*7c478bd9Sstevel@tonic-gate 	ASSERT(event_pause_state == 0);
198*7c478bd9Sstevel@tonic-gate 
199*7c478bd9Sstevel@tonic-gate 	event_pause_state = 1;
200*7c478bd9Sstevel@tonic-gate 	id = timeout(log_event_busy_timeout, NULL, nticks);
201*7c478bd9Sstevel@tonic-gate 	if (id != 0) {
202*7c478bd9Sstevel@tonic-gate 		mutex_enter(&event_pause_mutex);
203*7c478bd9Sstevel@tonic-gate 		while (event_pause_state)
204*7c478bd9Sstevel@tonic-gate 			cv_wait(&event_pause_cv, &event_pause_mutex);
205*7c478bd9Sstevel@tonic-gate 		mutex_exit(&event_pause_mutex);
206*7c478bd9Sstevel@tonic-gate 	}
207*7c478bd9Sstevel@tonic-gate 	event_pause_state = 0;
208*7c478bd9Sstevel@tonic-gate }
209*7c478bd9Sstevel@tonic-gate 
210*7c478bd9Sstevel@tonic-gate 
211*7c478bd9Sstevel@tonic-gate /*
212*7c478bd9Sstevel@tonic-gate  * log_event_upcall - Perform the upcall to syseventd for event buffer delivery.
213*7c478bd9Sstevel@tonic-gate  * 			Check for rebinding errors
214*7c478bd9Sstevel@tonic-gate  * 			This buffer is reused to by the syseventd door_return
215*7c478bd9Sstevel@tonic-gate  *			to hold the result code
216*7c478bd9Sstevel@tonic-gate  */
217*7c478bd9Sstevel@tonic-gate static int
218*7c478bd9Sstevel@tonic-gate log_event_upcall(log_event_upcall_arg_t *arg)
219*7c478bd9Sstevel@tonic-gate {
220*7c478bd9Sstevel@tonic-gate 	int error;
221*7c478bd9Sstevel@tonic-gate 	size_t size;
222*7c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
223*7c478bd9Sstevel@tonic-gate 	door_arg_t darg, save_arg;
224*7c478bd9Sstevel@tonic-gate 	int retry;
225*7c478bd9Sstevel@tonic-gate 	int neagain = 0;
226*7c478bd9Sstevel@tonic-gate 	int neintr = 0;
227*7c478bd9Sstevel@tonic-gate 	int nticks = LOG_EVENT_MIN_PAUSE;
228*7c478bd9Sstevel@tonic-gate 
229*7c478bd9Sstevel@tonic-gate 	/* Initialize door args */
230*7c478bd9Sstevel@tonic-gate 	ev = (sysevent_t *)&arg->buf;
231*7c478bd9Sstevel@tonic-gate 	size = sizeof (log_event_upcall_arg_t) + SE_PAYLOAD_SZ(ev);
232*7c478bd9Sstevel@tonic-gate 
233*7c478bd9Sstevel@tonic-gate 	darg.rbuf = (char *)arg;
234*7c478bd9Sstevel@tonic-gate 	darg.data_ptr = (char *)arg;
235*7c478bd9Sstevel@tonic-gate 	darg.rsize = size;
236*7c478bd9Sstevel@tonic-gate 	darg.data_size = size;
237*7c478bd9Sstevel@tonic-gate 	darg.desc_ptr = NULL;
238*7c478bd9Sstevel@tonic-gate 	darg.desc_num = 0;
239*7c478bd9Sstevel@tonic-gate 
240*7c478bd9Sstevel@tonic-gate 	if ((event_door == NULL) &&
241*7c478bd9Sstevel@tonic-gate 	    ((error = log_event_upcall_lookup()) != 0)) {
242*7c478bd9Sstevel@tonic-gate 		LOG_DEBUG((CE_CONT,
243*7c478bd9Sstevel@tonic-gate 		    "log_event_upcall: event_door error (%d)\n", error));
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate 		return (error);
246*7c478bd9Sstevel@tonic-gate 	}
247*7c478bd9Sstevel@tonic-gate 
248*7c478bd9Sstevel@tonic-gate 	LOG_DEBUG1((CE_CONT, "log_event_upcall: 0x%llx\n",
249*7c478bd9Sstevel@tonic-gate 	    (longlong_t)SE_SEQ((sysevent_t *)&arg->buf)));
250*7c478bd9Sstevel@tonic-gate 
251*7c478bd9Sstevel@tonic-gate 	save_arg = darg;
252*7c478bd9Sstevel@tonic-gate 	for (retry = 0; ; retry++) {
253*7c478bd9Sstevel@tonic-gate 		if ((error = door_ki_upcall(event_door, &darg)) == 0) {
254*7c478bd9Sstevel@tonic-gate 			break;
255*7c478bd9Sstevel@tonic-gate 		}
256*7c478bd9Sstevel@tonic-gate 		switch (error) {
257*7c478bd9Sstevel@tonic-gate 		case EINTR:
258*7c478bd9Sstevel@tonic-gate 			neintr++;
259*7c478bd9Sstevel@tonic-gate 			log_event_pause(2);
260*7c478bd9Sstevel@tonic-gate 			darg = save_arg;
261*7c478bd9Sstevel@tonic-gate 			break;
262*7c478bd9Sstevel@tonic-gate 		case EAGAIN:
263*7c478bd9Sstevel@tonic-gate 			/* cannot deliver upcall - process may be forking */
264*7c478bd9Sstevel@tonic-gate 			neagain++;
265*7c478bd9Sstevel@tonic-gate 			log_event_pause(nticks);
266*7c478bd9Sstevel@tonic-gate 			nticks <<= 1;
267*7c478bd9Sstevel@tonic-gate 			if (nticks > LOG_EVENT_MAX_PAUSE)
268*7c478bd9Sstevel@tonic-gate 				nticks = LOG_EVENT_MAX_PAUSE;
269*7c478bd9Sstevel@tonic-gate 			darg = save_arg;
270*7c478bd9Sstevel@tonic-gate 			break;
271*7c478bd9Sstevel@tonic-gate 		case EBADF:
272*7c478bd9Sstevel@tonic-gate 			LOG_DEBUG((CE_CONT, "log_event_upcall: rebinding\n"));
273*7c478bd9Sstevel@tonic-gate 			/* Server may have died. Try rebinding */
274*7c478bd9Sstevel@tonic-gate 			if ((error = log_event_upcall_lookup()) != 0) {
275*7c478bd9Sstevel@tonic-gate 				LOG_DEBUG((CE_CONT,
276*7c478bd9Sstevel@tonic-gate 				    "log_event_upcall: lookup error %d\n",
277*7c478bd9Sstevel@tonic-gate 				    error));
278*7c478bd9Sstevel@tonic-gate 				return (EBADF);
279*7c478bd9Sstevel@tonic-gate 			}
280*7c478bd9Sstevel@tonic-gate 			if (retry > 4) {
281*7c478bd9Sstevel@tonic-gate 				LOG_DEBUG((CE_CONT,
282*7c478bd9Sstevel@tonic-gate 					"log_event_upcall: ebadf\n"));
283*7c478bd9Sstevel@tonic-gate 				return (EBADF);
284*7c478bd9Sstevel@tonic-gate 			}
285*7c478bd9Sstevel@tonic-gate 			LOG_DEBUG((CE_CONT, "log_event_upcall: "
286*7c478bd9Sstevel@tonic-gate 				"retrying upcall after lookup\n"));
287*7c478bd9Sstevel@tonic-gate 			darg = save_arg;
288*7c478bd9Sstevel@tonic-gate 			break;
289*7c478bd9Sstevel@tonic-gate 		default:
290*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
291*7c478bd9Sstevel@tonic-gate 			    "log_event_upcall: door_ki_upcall error %d\n",
292*7c478bd9Sstevel@tonic-gate 			    error);
293*7c478bd9Sstevel@tonic-gate 			return (error);
294*7c478bd9Sstevel@tonic-gate 		}
295*7c478bd9Sstevel@tonic-gate 	}
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	if (neagain > 0 || neintr > 0) {
298*7c478bd9Sstevel@tonic-gate 		LOG_DEBUG((CE_CONT, "upcall: eagain=%d eintr=%d nticks=%d\n",
299*7c478bd9Sstevel@tonic-gate 			neagain, neintr, nticks));
300*7c478bd9Sstevel@tonic-gate 	}
301*7c478bd9Sstevel@tonic-gate 
302*7c478bd9Sstevel@tonic-gate 	LOG_DEBUG1((CE_CONT, "log_event_upcall:\n\t"
303*7c478bd9Sstevel@tonic-gate 		"error=%d rptr1=%p rptr2=%p dptr2=%p ret1=%x ret2=%x\n",
304*7c478bd9Sstevel@tonic-gate 		error, (void *)arg, (void *)darg.rbuf,
305*7c478bd9Sstevel@tonic-gate 		(void *)darg.data_ptr,
306*7c478bd9Sstevel@tonic-gate 		*((int *)(darg.rbuf)), *((int *)(darg.data_ptr))));
307*7c478bd9Sstevel@tonic-gate 
308*7c478bd9Sstevel@tonic-gate 	if (!error) {
309*7c478bd9Sstevel@tonic-gate 		/*
310*7c478bd9Sstevel@tonic-gate 		 * upcall was successfully executed. Check return code.
311*7c478bd9Sstevel@tonic-gate 		 */
312*7c478bd9Sstevel@tonic-gate 		error = *((int *)(darg.rbuf));
313*7c478bd9Sstevel@tonic-gate 	}
314*7c478bd9Sstevel@tonic-gate 
315*7c478bd9Sstevel@tonic-gate 	return (error);
316*7c478bd9Sstevel@tonic-gate }
317*7c478bd9Sstevel@tonic-gate 
318*7c478bd9Sstevel@tonic-gate /*
319*7c478bd9Sstevel@tonic-gate  * log_event_deliver - event delivery thread
320*7c478bd9Sstevel@tonic-gate  *			Deliver all events on the event queue to syseventd.
321*7c478bd9Sstevel@tonic-gate  *			If the daemon can not process events, stop event
322*7c478bd9Sstevel@tonic-gate  *			delivery and wait for an indication from the
323*7c478bd9Sstevel@tonic-gate  *			daemon to resume delivery.
324*7c478bd9Sstevel@tonic-gate  *
325*7c478bd9Sstevel@tonic-gate  *			Once all event buffers have been delivered, wait
326*7c478bd9Sstevel@tonic-gate  *			until there are more to deliver.
327*7c478bd9Sstevel@tonic-gate  */
328*7c478bd9Sstevel@tonic-gate static void
329*7c478bd9Sstevel@tonic-gate log_event_deliver()
330*7c478bd9Sstevel@tonic-gate {
331*7c478bd9Sstevel@tonic-gate 	log_eventq_t *q;
332*7c478bd9Sstevel@tonic-gate 	int upcall_err;
333*7c478bd9Sstevel@tonic-gate 	callb_cpr_t cprinfo;
334*7c478bd9Sstevel@tonic-gate 
335*7c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &eventq_head_mutex, callb_generic_cpr,
336*7c478bd9Sstevel@tonic-gate 				"logevent");
337*7c478bd9Sstevel@tonic-gate 
338*7c478bd9Sstevel@tonic-gate 	/*
339*7c478bd9Sstevel@tonic-gate 	 * eventq_head_mutex is exited (released) when there are no more
340*7c478bd9Sstevel@tonic-gate 	 * events to process from the eventq in cv_wait().
341*7c478bd9Sstevel@tonic-gate 	 */
342*7c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_head_mutex);
343*7c478bd9Sstevel@tonic-gate 
344*7c478bd9Sstevel@tonic-gate 	for (;;) {
345*7c478bd9Sstevel@tonic-gate 		LOG_DEBUG1((CE_CONT, "log_event_deliver: head = %p\n",
346*7c478bd9Sstevel@tonic-gate 		    (void *)log_eventq_head));
347*7c478bd9Sstevel@tonic-gate 
348*7c478bd9Sstevel@tonic-gate 		upcall_err = 0;
349*7c478bd9Sstevel@tonic-gate 		q = log_eventq_head;
350*7c478bd9Sstevel@tonic-gate 
351*7c478bd9Sstevel@tonic-gate 		while (q) {
352*7c478bd9Sstevel@tonic-gate 			log_eventq_t *next;
353*7c478bd9Sstevel@tonic-gate 
354*7c478bd9Sstevel@tonic-gate 			/*
355*7c478bd9Sstevel@tonic-gate 			 * Release event queue lock during upcall to
356*7c478bd9Sstevel@tonic-gate 			 * syseventd
357*7c478bd9Sstevel@tonic-gate 			 */
358*7c478bd9Sstevel@tonic-gate 			if (log_event_delivery == LOGEVENT_DELIVERY_HOLD) {
359*7c478bd9Sstevel@tonic-gate 				upcall_err = EAGAIN;
360*7c478bd9Sstevel@tonic-gate 				break;
361*7c478bd9Sstevel@tonic-gate 			}
362*7c478bd9Sstevel@tonic-gate 
363*7c478bd9Sstevel@tonic-gate 			mutex_exit(&eventq_head_mutex);
364*7c478bd9Sstevel@tonic-gate 			if ((upcall_err = log_event_upcall(&q->arg)) != 0) {
365*7c478bd9Sstevel@tonic-gate 				mutex_enter(&eventq_head_mutex);
366*7c478bd9Sstevel@tonic-gate 				break;
367*7c478bd9Sstevel@tonic-gate 			}
368*7c478bd9Sstevel@tonic-gate 
369*7c478bd9Sstevel@tonic-gate 			/*
370*7c478bd9Sstevel@tonic-gate 			 * We may be able to add entries to
371*7c478bd9Sstevel@tonic-gate 			 * the queue now.
372*7c478bd9Sstevel@tonic-gate 			 */
373*7c478bd9Sstevel@tonic-gate 			if (event_qfull_blocked > 0 &&
374*7c478bd9Sstevel@tonic-gate 			    log_eventq_cnt < logevent_max_q_sz) {
375*7c478bd9Sstevel@tonic-gate 				mutex_enter(&event_qfull_mutex);
376*7c478bd9Sstevel@tonic-gate 				if (event_qfull_blocked > 0) {
377*7c478bd9Sstevel@tonic-gate 					cv_signal(&event_qfull_cv);
378*7c478bd9Sstevel@tonic-gate 				}
379*7c478bd9Sstevel@tonic-gate 				mutex_exit(&event_qfull_mutex);
380*7c478bd9Sstevel@tonic-gate 			}
381*7c478bd9Sstevel@tonic-gate 
382*7c478bd9Sstevel@tonic-gate 			mutex_enter(&eventq_head_mutex);
383*7c478bd9Sstevel@tonic-gate 
384*7c478bd9Sstevel@tonic-gate 			/*
385*7c478bd9Sstevel@tonic-gate 			 * Daemon restart can cause entries to be moved from
386*7c478bd9Sstevel@tonic-gate 			 * the sent queue and put back on the event queue.
387*7c478bd9Sstevel@tonic-gate 			 * If this has occurred, replay event queue
388*7c478bd9Sstevel@tonic-gate 			 * processing from the new queue head.
389*7c478bd9Sstevel@tonic-gate 			 */
390*7c478bd9Sstevel@tonic-gate 			if (q != log_eventq_head) {
391*7c478bd9Sstevel@tonic-gate 				q = log_eventq_head;
392*7c478bd9Sstevel@tonic-gate 				LOG_DEBUG((CE_CONT, "log_event_deliver: "
393*7c478bd9Sstevel@tonic-gate 				    "door upcall/daemon restart race\n"));
394*7c478bd9Sstevel@tonic-gate 			} else {
395*7c478bd9Sstevel@tonic-gate 				/*
396*7c478bd9Sstevel@tonic-gate 				 * Move the event to the sent queue when a
397*7c478bd9Sstevel@tonic-gate 				 * successful delivery has been made.
398*7c478bd9Sstevel@tonic-gate 				 */
399*7c478bd9Sstevel@tonic-gate 				mutex_enter(&eventq_sent_mutex);
400*7c478bd9Sstevel@tonic-gate 				next = q->next;
401*7c478bd9Sstevel@tonic-gate 				q->next = log_eventq_sent;
402*7c478bd9Sstevel@tonic-gate 				log_eventq_sent = q;
403*7c478bd9Sstevel@tonic-gate 				q = next;
404*7c478bd9Sstevel@tonic-gate 				log_eventq_head = q;
405*7c478bd9Sstevel@tonic-gate 				log_eventq_cnt--;
406*7c478bd9Sstevel@tonic-gate 				if (q == NULL) {
407*7c478bd9Sstevel@tonic-gate 					ASSERT(log_eventq_cnt == 0);
408*7c478bd9Sstevel@tonic-gate 					log_eventq_tail = NULL;
409*7c478bd9Sstevel@tonic-gate 				}
410*7c478bd9Sstevel@tonic-gate 				mutex_exit(&eventq_sent_mutex);
411*7c478bd9Sstevel@tonic-gate 			}
412*7c478bd9Sstevel@tonic-gate 		}
413*7c478bd9Sstevel@tonic-gate 
414*7c478bd9Sstevel@tonic-gate 		switch (upcall_err) {
415*7c478bd9Sstevel@tonic-gate 		case 0:
416*7c478bd9Sstevel@tonic-gate 			/*
417*7c478bd9Sstevel@tonic-gate 			 * Success. The queue is empty.
418*7c478bd9Sstevel@tonic-gate 			 */
419*7c478bd9Sstevel@tonic-gate 			sysevent_upcall_status = 0;
420*7c478bd9Sstevel@tonic-gate 			break;
421*7c478bd9Sstevel@tonic-gate 		case EAGAIN:
422*7c478bd9Sstevel@tonic-gate 			/*
423*7c478bd9Sstevel@tonic-gate 			 * Delivery is on hold (but functional).
424*7c478bd9Sstevel@tonic-gate 			 */
425*7c478bd9Sstevel@tonic-gate 			sysevent_upcall_status = 0;
426*7c478bd9Sstevel@tonic-gate 			/*
427*7c478bd9Sstevel@tonic-gate 			 * If the user has already signaled for delivery
428*7c478bd9Sstevel@tonic-gate 			 * resumption, continue.  Otherwise, we wait until
429*7c478bd9Sstevel@tonic-gate 			 * we are signaled to continue.
430*7c478bd9Sstevel@tonic-gate 			 */
431*7c478bd9Sstevel@tonic-gate 			if (log_event_delivery == LOGEVENT_DELIVERY_CONT) {
432*7c478bd9Sstevel@tonic-gate 				log_event_delivery = LOGEVENT_DELIVERY_OK;
433*7c478bd9Sstevel@tonic-gate 				continue;
434*7c478bd9Sstevel@tonic-gate 			} else {
435*7c478bd9Sstevel@tonic-gate 				log_event_delivery = LOGEVENT_DELIVERY_HOLD;
436*7c478bd9Sstevel@tonic-gate 			}
437*7c478bd9Sstevel@tonic-gate 
438*7c478bd9Sstevel@tonic-gate 			LOG_DEBUG1((CE_CONT, "log_event_deliver: EAGAIN\n"));
439*7c478bd9Sstevel@tonic-gate 			break;
440*7c478bd9Sstevel@tonic-gate 		default:
441*7c478bd9Sstevel@tonic-gate 			LOG_DEBUG((CE_CONT, "log_event_deliver: "
442*7c478bd9Sstevel@tonic-gate 				"upcall err %d\n", upcall_err));
443*7c478bd9Sstevel@tonic-gate 			sysevent_upcall_status = upcall_err;
444*7c478bd9Sstevel@tonic-gate 			/*
445*7c478bd9Sstevel@tonic-gate 			 * Signal everyone waiting that transport is down
446*7c478bd9Sstevel@tonic-gate 			 */
447*7c478bd9Sstevel@tonic-gate 			if (event_qfull_blocked > 0) {
448*7c478bd9Sstevel@tonic-gate 				mutex_enter(&event_qfull_mutex);
449*7c478bd9Sstevel@tonic-gate 				if (event_qfull_blocked > 0) {
450*7c478bd9Sstevel@tonic-gate 					cv_broadcast(&event_qfull_cv);
451*7c478bd9Sstevel@tonic-gate 				}
452*7c478bd9Sstevel@tonic-gate 				mutex_exit(&event_qfull_mutex);
453*7c478bd9Sstevel@tonic-gate 			}
454*7c478bd9Sstevel@tonic-gate 			break;
455*7c478bd9Sstevel@tonic-gate 		}
456*7c478bd9Sstevel@tonic-gate 
457*7c478bd9Sstevel@tonic-gate 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
458*7c478bd9Sstevel@tonic-gate 		cv_wait(&log_event_cv, &eventq_head_mutex);
459*7c478bd9Sstevel@tonic-gate 		CALLB_CPR_SAFE_END(&cprinfo, &eventq_head_mutex);
460*7c478bd9Sstevel@tonic-gate 	}
461*7c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
462*7c478bd9Sstevel@tonic-gate }
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate /*
465*7c478bd9Sstevel@tonic-gate  * log_event_init - Allocate and initialize log_event data structures.
466*7c478bd9Sstevel@tonic-gate  */
467*7c478bd9Sstevel@tonic-gate void
468*7c478bd9Sstevel@tonic-gate log_event_init()
469*7c478bd9Sstevel@tonic-gate {
470*7c478bd9Sstevel@tonic-gate 	mutex_init(&eventq_head_mutex, NULL, MUTEX_DEFAULT, NULL);
471*7c478bd9Sstevel@tonic-gate 	mutex_init(&eventq_sent_mutex, NULL, MUTEX_DEFAULT, NULL);
472*7c478bd9Sstevel@tonic-gate 	cv_init(&log_event_cv, NULL, CV_DEFAULT, NULL);
473*7c478bd9Sstevel@tonic-gate 
474*7c478bd9Sstevel@tonic-gate 	mutex_init(&event_qfull_mutex, NULL, MUTEX_DEFAULT, NULL);
475*7c478bd9Sstevel@tonic-gate 	cv_init(&event_qfull_cv, NULL, CV_DEFAULT, NULL);
476*7c478bd9Sstevel@tonic-gate 
477*7c478bd9Sstevel@tonic-gate 	mutex_init(&event_pause_mutex, NULL, MUTEX_DEFAULT, NULL);
478*7c478bd9Sstevel@tonic-gate 	cv_init(&event_pause_cv, NULL, CV_DEFAULT, NULL);
479*7c478bd9Sstevel@tonic-gate 
480*7c478bd9Sstevel@tonic-gate 	mutex_init(&registered_channel_mutex, NULL, MUTEX_DEFAULT, NULL);
481*7c478bd9Sstevel@tonic-gate 	sysevent_evc_init();
482*7c478bd9Sstevel@tonic-gate }
483*7c478bd9Sstevel@tonic-gate 
484*7c478bd9Sstevel@tonic-gate /*
485*7c478bd9Sstevel@tonic-gate  * The following routines are used by kernel event publishers to
486*7c478bd9Sstevel@tonic-gate  * allocate, append and free event buffers
487*7c478bd9Sstevel@tonic-gate  */
488*7c478bd9Sstevel@tonic-gate /*
489*7c478bd9Sstevel@tonic-gate  * sysevent_alloc - Allocate new eventq struct.  This element contains
490*7c478bd9Sstevel@tonic-gate  *			an event buffer that will be used in a subsequent
491*7c478bd9Sstevel@tonic-gate  *			call to log_sysevent.
492*7c478bd9Sstevel@tonic-gate  */
493*7c478bd9Sstevel@tonic-gate sysevent_t *
494*7c478bd9Sstevel@tonic-gate sysevent_alloc(char *class, char *subclass, char *pub, int flag)
495*7c478bd9Sstevel@tonic-gate {
496*7c478bd9Sstevel@tonic-gate 	int payload_sz;
497*7c478bd9Sstevel@tonic-gate 	int class_sz, subclass_sz, pub_sz;
498*7c478bd9Sstevel@tonic-gate 	int aligned_class_sz, aligned_subclass_sz, aligned_pub_sz;
499*7c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
500*7c478bd9Sstevel@tonic-gate 	log_eventq_t *q;
501*7c478bd9Sstevel@tonic-gate 
502*7c478bd9Sstevel@tonic-gate 	ASSERT(class != NULL);
503*7c478bd9Sstevel@tonic-gate 	ASSERT(subclass != NULL);
504*7c478bd9Sstevel@tonic-gate 	ASSERT(pub != NULL);
505*7c478bd9Sstevel@tonic-gate 
506*7c478bd9Sstevel@tonic-gate 	/*
507*7c478bd9Sstevel@tonic-gate 	 * Calculate and reserve space for the class, subclass and
508*7c478bd9Sstevel@tonic-gate 	 * publisher strings in the event buffer
509*7c478bd9Sstevel@tonic-gate 	 */
510*7c478bd9Sstevel@tonic-gate 	class_sz = strlen(class) + 1;
511*7c478bd9Sstevel@tonic-gate 	subclass_sz = strlen(subclass) + 1;
512*7c478bd9Sstevel@tonic-gate 	pub_sz = strlen(pub) + 1;
513*7c478bd9Sstevel@tonic-gate 
514*7c478bd9Sstevel@tonic-gate 	ASSERT((class_sz <= MAX_CLASS_LEN) && (subclass_sz
515*7c478bd9Sstevel@tonic-gate 	    <= MAX_SUBCLASS_LEN) && (pub_sz <= MAX_PUB_LEN));
516*7c478bd9Sstevel@tonic-gate 
517*7c478bd9Sstevel@tonic-gate 	/* String sizes must be 64-bit aligned in the event buffer */
518*7c478bd9Sstevel@tonic-gate 	aligned_class_sz = SE_ALIGN(class_sz);
519*7c478bd9Sstevel@tonic-gate 	aligned_subclass_sz = SE_ALIGN(subclass_sz);
520*7c478bd9Sstevel@tonic-gate 	aligned_pub_sz = SE_ALIGN(pub_sz);
521*7c478bd9Sstevel@tonic-gate 
522*7c478bd9Sstevel@tonic-gate 	payload_sz = (aligned_class_sz - sizeof (uint64_t)) +
523*7c478bd9Sstevel@tonic-gate 		(aligned_subclass_sz - sizeof (uint64_t)) +
524*7c478bd9Sstevel@tonic-gate 		(aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t);
525*7c478bd9Sstevel@tonic-gate 
526*7c478bd9Sstevel@tonic-gate 	/*
527*7c478bd9Sstevel@tonic-gate 	 * Allocate event buffer plus additional sysevent queue
528*7c478bd9Sstevel@tonic-gate 	 * and payload overhead.
529*7c478bd9Sstevel@tonic-gate 	 */
530*7c478bd9Sstevel@tonic-gate 	q = kmem_zalloc(sizeof (log_eventq_t) + payload_sz, flag);
531*7c478bd9Sstevel@tonic-gate 	if (q == NULL) {
532*7c478bd9Sstevel@tonic-gate 		return (NULL);
533*7c478bd9Sstevel@tonic-gate 	}
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	/* Initialize the event buffer data */
536*7c478bd9Sstevel@tonic-gate 	ev = (sysevent_t *)&q->arg.buf;
537*7c478bd9Sstevel@tonic-gate 	SE_VERSION(ev) = SYS_EVENT_VERSION;
538*7c478bd9Sstevel@tonic-gate 	bcopy(class, SE_CLASS_NAME(ev), class_sz);
539*7c478bd9Sstevel@tonic-gate 
540*7c478bd9Sstevel@tonic-gate 	SE_SUBCLASS_OFF(ev) = SE_ALIGN(offsetof(sysevent_impl_t, se_class_name))
541*7c478bd9Sstevel@tonic-gate 		+ aligned_class_sz;
542*7c478bd9Sstevel@tonic-gate 	bcopy(subclass, SE_SUBCLASS_NAME(ev), subclass_sz);
543*7c478bd9Sstevel@tonic-gate 
544*7c478bd9Sstevel@tonic-gate 	SE_PUB_OFF(ev) = SE_SUBCLASS_OFF(ev) + aligned_subclass_sz;
545*7c478bd9Sstevel@tonic-gate 	bcopy(pub, SE_PUB_NAME(ev), pub_sz);
546*7c478bd9Sstevel@tonic-gate 
547*7c478bd9Sstevel@tonic-gate 	SE_ATTR_PTR(ev) = UINT64_C(0);
548*7c478bd9Sstevel@tonic-gate 	SE_PAYLOAD_SZ(ev) = payload_sz;
549*7c478bd9Sstevel@tonic-gate 
550*7c478bd9Sstevel@tonic-gate 	return (ev);
551*7c478bd9Sstevel@tonic-gate }
552*7c478bd9Sstevel@tonic-gate 
553*7c478bd9Sstevel@tonic-gate /*
554*7c478bd9Sstevel@tonic-gate  * sysevent_free - Free event buffer and any attribute data.
555*7c478bd9Sstevel@tonic-gate  */
556*7c478bd9Sstevel@tonic-gate void
557*7c478bd9Sstevel@tonic-gate sysevent_free(sysevent_t *ev)
558*7c478bd9Sstevel@tonic-gate {
559*7c478bd9Sstevel@tonic-gate 	log_eventq_t *q;
560*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
561*7c478bd9Sstevel@tonic-gate 
562*7c478bd9Sstevel@tonic-gate 	ASSERT(ev != NULL);
563*7c478bd9Sstevel@tonic-gate 	q = (log_eventq_t *)((caddr_t)ev - offsetof(log_eventq_t, arg.buf));
564*7c478bd9Sstevel@tonic-gate 	nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
565*7c478bd9Sstevel@tonic-gate 
566*7c478bd9Sstevel@tonic-gate 	if (nvl != NULL) {
567*7c478bd9Sstevel@tonic-gate 		size_t size = 0;
568*7c478bd9Sstevel@tonic-gate 		(void) nvlist_size(nvl, &size, encoding);
569*7c478bd9Sstevel@tonic-gate 		SE_PAYLOAD_SZ(ev) -= size;
570*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
571*7c478bd9Sstevel@tonic-gate 	}
572*7c478bd9Sstevel@tonic-gate 	kmem_free(q, sizeof (log_eventq_t) + SE_PAYLOAD_SZ(ev));
573*7c478bd9Sstevel@tonic-gate }
574*7c478bd9Sstevel@tonic-gate 
575*7c478bd9Sstevel@tonic-gate /*
576*7c478bd9Sstevel@tonic-gate  * free_packed_event - Free packed event buffer
577*7c478bd9Sstevel@tonic-gate  */
578*7c478bd9Sstevel@tonic-gate static void
579*7c478bd9Sstevel@tonic-gate free_packed_event(sysevent_t *ev)
580*7c478bd9Sstevel@tonic-gate {
581*7c478bd9Sstevel@tonic-gate 	log_eventq_t *q;
582*7c478bd9Sstevel@tonic-gate 
583*7c478bd9Sstevel@tonic-gate 	ASSERT(ev != NULL);
584*7c478bd9Sstevel@tonic-gate 	q = (log_eventq_t *)((caddr_t)ev - offsetof(log_eventq_t, arg.buf));
585*7c478bd9Sstevel@tonic-gate 
586*7c478bd9Sstevel@tonic-gate 	kmem_free(q, sizeof (log_eventq_t) + SE_PAYLOAD_SZ(ev));
587*7c478bd9Sstevel@tonic-gate }
588*7c478bd9Sstevel@tonic-gate 
589*7c478bd9Sstevel@tonic-gate /*
590*7c478bd9Sstevel@tonic-gate  * sysevent_add_attr - Add new attribute element to an event attribute list
591*7c478bd9Sstevel@tonic-gate  *			If attribute list is NULL, start a new list.
592*7c478bd9Sstevel@tonic-gate  */
593*7c478bd9Sstevel@tonic-gate int
594*7c478bd9Sstevel@tonic-gate sysevent_add_attr(sysevent_attr_list_t **ev_attr_list, char *name,
595*7c478bd9Sstevel@tonic-gate 	sysevent_value_t *se_value, int flag)
596*7c478bd9Sstevel@tonic-gate {
597*7c478bd9Sstevel@tonic-gate 	int error;
598*7c478bd9Sstevel@tonic-gate 	nvlist_t **nvlp = (nvlist_t **)ev_attr_list;
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 	if (nvlp == NULL || se_value == NULL) {
601*7c478bd9Sstevel@tonic-gate 		return (SE_EINVAL);
602*7c478bd9Sstevel@tonic-gate 	}
603*7c478bd9Sstevel@tonic-gate 
604*7c478bd9Sstevel@tonic-gate 	/*
605*7c478bd9Sstevel@tonic-gate 	 * attr_sz is composed of the value data size + the name data size +
606*7c478bd9Sstevel@tonic-gate 	 * any header data.  64-bit aligned.
607*7c478bd9Sstevel@tonic-gate 	 */
608*7c478bd9Sstevel@tonic-gate 	if (strlen(name) >= MAX_ATTR_NAME) {
609*7c478bd9Sstevel@tonic-gate 		return (SE_EINVAL);
610*7c478bd9Sstevel@tonic-gate 	}
611*7c478bd9Sstevel@tonic-gate 
612*7c478bd9Sstevel@tonic-gate 	/*
613*7c478bd9Sstevel@tonic-gate 	 * Allocate nvlist
614*7c478bd9Sstevel@tonic-gate 	 */
615*7c478bd9Sstevel@tonic-gate 	if ((*nvlp == NULL) &&
616*7c478bd9Sstevel@tonic-gate 	    (nvlist_alloc(nvlp, NV_UNIQUE_NAME_TYPE, flag) != 0))
617*7c478bd9Sstevel@tonic-gate 		return (SE_ENOMEM);
618*7c478bd9Sstevel@tonic-gate 
619*7c478bd9Sstevel@tonic-gate 	/* add the attribute */
620*7c478bd9Sstevel@tonic-gate 	switch (se_value->value_type) {
621*7c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_BYTE:
622*7c478bd9Sstevel@tonic-gate 		error = nvlist_add_byte(*ev_attr_list, name,
623*7c478bd9Sstevel@tonic-gate 		    se_value->value.sv_byte);
624*7c478bd9Sstevel@tonic-gate 		break;
625*7c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_INT16:
626*7c478bd9Sstevel@tonic-gate 		error = nvlist_add_int16(*ev_attr_list, name,
627*7c478bd9Sstevel@tonic-gate 		    se_value->value.sv_int16);
628*7c478bd9Sstevel@tonic-gate 		break;
629*7c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_UINT16:
630*7c478bd9Sstevel@tonic-gate 		error = nvlist_add_uint16(*ev_attr_list, name,
631*7c478bd9Sstevel@tonic-gate 		    se_value->value.sv_uint16);
632*7c478bd9Sstevel@tonic-gate 		break;
633*7c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_INT32:
634*7c478bd9Sstevel@tonic-gate 		error = nvlist_add_int32(*ev_attr_list, name,
635*7c478bd9Sstevel@tonic-gate 		    se_value->value.sv_int32);
636*7c478bd9Sstevel@tonic-gate 		break;
637*7c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_UINT32:
638*7c478bd9Sstevel@tonic-gate 		error = nvlist_add_uint32(*ev_attr_list, name,
639*7c478bd9Sstevel@tonic-gate 		    se_value->value.sv_uint32);
640*7c478bd9Sstevel@tonic-gate 		break;
641*7c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_INT64:
642*7c478bd9Sstevel@tonic-gate 		error = nvlist_add_int64(*ev_attr_list, name,
643*7c478bd9Sstevel@tonic-gate 		    se_value->value.sv_int64);
644*7c478bd9Sstevel@tonic-gate 		break;
645*7c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_UINT64:
646*7c478bd9Sstevel@tonic-gate 		error = nvlist_add_uint64(*ev_attr_list, name,
647*7c478bd9Sstevel@tonic-gate 		    se_value->value.sv_uint64);
648*7c478bd9Sstevel@tonic-gate 		break;
649*7c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_STRING:
650*7c478bd9Sstevel@tonic-gate 		if (strlen((char *)se_value->value.sv_string) >= MAX_STRING_SZ)
651*7c478bd9Sstevel@tonic-gate 			return (SE_EINVAL);
652*7c478bd9Sstevel@tonic-gate 		error = nvlist_add_string(*ev_attr_list, name,
653*7c478bd9Sstevel@tonic-gate 		    se_value->value.sv_string);
654*7c478bd9Sstevel@tonic-gate 		break;
655*7c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_BYTES:
656*7c478bd9Sstevel@tonic-gate 		if (se_value->value.sv_bytes.size > MAX_BYTE_ARRAY)
657*7c478bd9Sstevel@tonic-gate 			return (SE_EINVAL);
658*7c478bd9Sstevel@tonic-gate 		error = nvlist_add_byte_array(*ev_attr_list, name,
659*7c478bd9Sstevel@tonic-gate 		    se_value->value.sv_bytes.data,
660*7c478bd9Sstevel@tonic-gate 		    se_value->value.sv_bytes.size);
661*7c478bd9Sstevel@tonic-gate 		break;
662*7c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_TIME:
663*7c478bd9Sstevel@tonic-gate 		error = nvlist_add_hrtime(*ev_attr_list, name,
664*7c478bd9Sstevel@tonic-gate 		    se_value->value.sv_time);
665*7c478bd9Sstevel@tonic-gate 		break;
666*7c478bd9Sstevel@tonic-gate 	default:
667*7c478bd9Sstevel@tonic-gate 		return (SE_EINVAL);
668*7c478bd9Sstevel@tonic-gate 	}
669*7c478bd9Sstevel@tonic-gate 
670*7c478bd9Sstevel@tonic-gate 	return (error ? SE_ENOMEM : 0);
671*7c478bd9Sstevel@tonic-gate }
672*7c478bd9Sstevel@tonic-gate 
673*7c478bd9Sstevel@tonic-gate /*
674*7c478bd9Sstevel@tonic-gate  * sysevent_free_attr - Free an attribute list not associated with an
675*7c478bd9Sstevel@tonic-gate  *			event buffer.
676*7c478bd9Sstevel@tonic-gate  */
677*7c478bd9Sstevel@tonic-gate void
678*7c478bd9Sstevel@tonic-gate sysevent_free_attr(sysevent_attr_list_t *ev_attr_list)
679*7c478bd9Sstevel@tonic-gate {
680*7c478bd9Sstevel@tonic-gate 	nvlist_free((nvlist_t *)ev_attr_list);
681*7c478bd9Sstevel@tonic-gate }
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate /*
684*7c478bd9Sstevel@tonic-gate  * sysevent_attach_attributes - Attach an attribute list to an event buffer.
685*7c478bd9Sstevel@tonic-gate  *
686*7c478bd9Sstevel@tonic-gate  *	This data will be re-packed into contiguous memory when the event
687*7c478bd9Sstevel@tonic-gate  *	buffer is posted to log_sysevent.
688*7c478bd9Sstevel@tonic-gate  */
689*7c478bd9Sstevel@tonic-gate int
690*7c478bd9Sstevel@tonic-gate sysevent_attach_attributes(sysevent_t *ev, sysevent_attr_list_t *ev_attr_list)
691*7c478bd9Sstevel@tonic-gate {
692*7c478bd9Sstevel@tonic-gate 	size_t size = 0;
693*7c478bd9Sstevel@tonic-gate 
694*7c478bd9Sstevel@tonic-gate 	if (SE_ATTR_PTR(ev) != UINT64_C(0)) {
695*7c478bd9Sstevel@tonic-gate 		return (SE_EINVAL);
696*7c478bd9Sstevel@tonic-gate 	}
697*7c478bd9Sstevel@tonic-gate 
698*7c478bd9Sstevel@tonic-gate 	SE_ATTR_PTR(ev) = (uintptr_t)ev_attr_list;
699*7c478bd9Sstevel@tonic-gate 	(void) nvlist_size((nvlist_t *)ev_attr_list, &size, encoding);
700*7c478bd9Sstevel@tonic-gate 	SE_PAYLOAD_SZ(ev) += size;
701*7c478bd9Sstevel@tonic-gate 	SE_FLAG(ev) = 0;
702*7c478bd9Sstevel@tonic-gate 
703*7c478bd9Sstevel@tonic-gate 	return (0);
704*7c478bd9Sstevel@tonic-gate }
705*7c478bd9Sstevel@tonic-gate 
706*7c478bd9Sstevel@tonic-gate /*
707*7c478bd9Sstevel@tonic-gate  * sysevent_detach_attributes - Detach but don't free attribute list from the
708*7c478bd9Sstevel@tonic-gate  *				event buffer.
709*7c478bd9Sstevel@tonic-gate  */
710*7c478bd9Sstevel@tonic-gate void
711*7c478bd9Sstevel@tonic-gate sysevent_detach_attributes(sysevent_t *ev)
712*7c478bd9Sstevel@tonic-gate {
713*7c478bd9Sstevel@tonic-gate 	size_t size = 0;
714*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate 	if ((nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev)) == NULL) {
717*7c478bd9Sstevel@tonic-gate 		return;
718*7c478bd9Sstevel@tonic-gate 	}
719*7c478bd9Sstevel@tonic-gate 
720*7c478bd9Sstevel@tonic-gate 	SE_ATTR_PTR(ev) = UINT64_C(0);
721*7c478bd9Sstevel@tonic-gate 	(void) nvlist_size(nvl, &size, encoding);
722*7c478bd9Sstevel@tonic-gate 	SE_PAYLOAD_SZ(ev) -= size;
723*7c478bd9Sstevel@tonic-gate 	ASSERT(SE_PAYLOAD_SZ(ev) >= 0);
724*7c478bd9Sstevel@tonic-gate }
725*7c478bd9Sstevel@tonic-gate 
726*7c478bd9Sstevel@tonic-gate /*
727*7c478bd9Sstevel@tonic-gate  * sysevent_attr_name - Get name of attribute
728*7c478bd9Sstevel@tonic-gate  */
729*7c478bd9Sstevel@tonic-gate char *
730*7c478bd9Sstevel@tonic-gate sysevent_attr_name(sysevent_attr_t *attr)
731*7c478bd9Sstevel@tonic-gate {
732*7c478bd9Sstevel@tonic-gate 	if (attr == NULL) {
733*7c478bd9Sstevel@tonic-gate 		return (NULL);
734*7c478bd9Sstevel@tonic-gate 	}
735*7c478bd9Sstevel@tonic-gate 
736*7c478bd9Sstevel@tonic-gate 	return (nvpair_name(attr));
737*7c478bd9Sstevel@tonic-gate }
738*7c478bd9Sstevel@tonic-gate 
739*7c478bd9Sstevel@tonic-gate /*
740*7c478bd9Sstevel@tonic-gate  * sysevent_attr_type - Get type of attribute
741*7c478bd9Sstevel@tonic-gate  */
742*7c478bd9Sstevel@tonic-gate int
743*7c478bd9Sstevel@tonic-gate sysevent_attr_type(sysevent_attr_t *attr)
744*7c478bd9Sstevel@tonic-gate {
745*7c478bd9Sstevel@tonic-gate 	/*
746*7c478bd9Sstevel@tonic-gate 	 * The SE_DATA_TYPE_* are typedef'ed to be the
747*7c478bd9Sstevel@tonic-gate 	 * same value as DATA_TYPE_*
748*7c478bd9Sstevel@tonic-gate 	 */
749*7c478bd9Sstevel@tonic-gate 	return (nvpair_type((nvpair_t *)attr));
750*7c478bd9Sstevel@tonic-gate }
751*7c478bd9Sstevel@tonic-gate 
752*7c478bd9Sstevel@tonic-gate /*
753*7c478bd9Sstevel@tonic-gate  * Repack event buffer into contiguous memory
754*7c478bd9Sstevel@tonic-gate  */
755*7c478bd9Sstevel@tonic-gate static sysevent_t *
756*7c478bd9Sstevel@tonic-gate se_repack(sysevent_t *ev, int flag)
757*7c478bd9Sstevel@tonic-gate {
758*7c478bd9Sstevel@tonic-gate 	size_t copy_len;
759*7c478bd9Sstevel@tonic-gate 	caddr_t attr;
760*7c478bd9Sstevel@tonic-gate 	size_t size;
761*7c478bd9Sstevel@tonic-gate 	uint64_t attr_offset;
762*7c478bd9Sstevel@tonic-gate 	sysevent_t *copy;
763*7c478bd9Sstevel@tonic-gate 	log_eventq_t *qcopy;
764*7c478bd9Sstevel@tonic-gate 	sysevent_attr_list_t *nvl;
765*7c478bd9Sstevel@tonic-gate 
766*7c478bd9Sstevel@tonic-gate 	copy_len = sizeof (log_eventq_t) + SE_PAYLOAD_SZ(ev);
767*7c478bd9Sstevel@tonic-gate 	qcopy = kmem_zalloc(copy_len, flag);
768*7c478bd9Sstevel@tonic-gate 	if (qcopy == NULL) {
769*7c478bd9Sstevel@tonic-gate 		return (NULL);
770*7c478bd9Sstevel@tonic-gate 	}
771*7c478bd9Sstevel@tonic-gate 	copy = (sysevent_t *)&qcopy->arg.buf;
772*7c478bd9Sstevel@tonic-gate 
773*7c478bd9Sstevel@tonic-gate 	/*
774*7c478bd9Sstevel@tonic-gate 	 * Copy event header, class, subclass and publisher names
775*7c478bd9Sstevel@tonic-gate 	 * Set the attribute offset (in number of bytes) to contiguous
776*7c478bd9Sstevel@tonic-gate 	 * memory after the header.
777*7c478bd9Sstevel@tonic-gate 	 */
778*7c478bd9Sstevel@tonic-gate 
779*7c478bd9Sstevel@tonic-gate 	attr_offset = SE_ATTR_OFF(ev);
780*7c478bd9Sstevel@tonic-gate 
781*7c478bd9Sstevel@tonic-gate 	ASSERT((caddr_t)copy + attr_offset <= (caddr_t)copy + copy_len);
782*7c478bd9Sstevel@tonic-gate 
783*7c478bd9Sstevel@tonic-gate 	bcopy(ev, copy, attr_offset);
784*7c478bd9Sstevel@tonic-gate 
785*7c478bd9Sstevel@tonic-gate 	/* Check if attribute list exists */
786*7c478bd9Sstevel@tonic-gate 	if ((nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev)) == NULL) {
787*7c478bd9Sstevel@tonic-gate 		return (copy);
788*7c478bd9Sstevel@tonic-gate 	}
789*7c478bd9Sstevel@tonic-gate 
790*7c478bd9Sstevel@tonic-gate 	/*
791*7c478bd9Sstevel@tonic-gate 	 * Copy attribute data to contiguous memory
792*7c478bd9Sstevel@tonic-gate 	 */
793*7c478bd9Sstevel@tonic-gate 	attr = (char *)copy + attr_offset;
794*7c478bd9Sstevel@tonic-gate 	(void) nvlist_size(nvl, &size, encoding);
795*7c478bd9Sstevel@tonic-gate 	if (nvlist_pack(nvl, &attr, &size, encoding, flag) != 0) {
796*7c478bd9Sstevel@tonic-gate 		kmem_free(qcopy, copy_len);
797*7c478bd9Sstevel@tonic-gate 		return (NULL);
798*7c478bd9Sstevel@tonic-gate 	}
799*7c478bd9Sstevel@tonic-gate 	SE_ATTR_PTR(copy) = UINT64_C(0);
800*7c478bd9Sstevel@tonic-gate 	SE_FLAG(copy) = SE_PACKED_BUF;
801*7c478bd9Sstevel@tonic-gate 
802*7c478bd9Sstevel@tonic-gate 	return (copy);
803*7c478bd9Sstevel@tonic-gate }
804*7c478bd9Sstevel@tonic-gate 
805*7c478bd9Sstevel@tonic-gate /*
806*7c478bd9Sstevel@tonic-gate  * The sysevent registration provides a persistent and reliable database
807*7c478bd9Sstevel@tonic-gate  * for channel information for sysevent channel publishers and
808*7c478bd9Sstevel@tonic-gate  * subscribers.
809*7c478bd9Sstevel@tonic-gate  *
810*7c478bd9Sstevel@tonic-gate  * A channel is created and maintained by the kernel upon the first
811*7c478bd9Sstevel@tonic-gate  * SE_OPEN_REGISTRATION operation to log_sysevent_register().  Channel
812*7c478bd9Sstevel@tonic-gate  * event subscription information is updated as publishers or subscribers
813*7c478bd9Sstevel@tonic-gate  * perform subsequent operations (SE_BIND_REGISTRATION, SE_REGISTER,
814*7c478bd9Sstevel@tonic-gate  * SE_UNREGISTER and SE_UNBIND_REGISTRATION).
815*7c478bd9Sstevel@tonic-gate  *
816*7c478bd9Sstevel@tonic-gate  * For consistency, id's are assigned for every publisher or subscriber
817*7c478bd9Sstevel@tonic-gate  * bound to a particular channel.  The id's are used to constrain resources
818*7c478bd9Sstevel@tonic-gate  * and perform subscription lookup.
819*7c478bd9Sstevel@tonic-gate  *
820*7c478bd9Sstevel@tonic-gate  * Associated with each channel is a hashed list of the current subscriptions
821*7c478bd9Sstevel@tonic-gate  * based upon event class and subclasses.  A subscription contains a class name,
822*7c478bd9Sstevel@tonic-gate  * list of possible subclasses and an array of subscriber ids.  Subscriptions
823*7c478bd9Sstevel@tonic-gate  * are updated for every SE_REGISTER or SE_UNREGISTER operation.
824*7c478bd9Sstevel@tonic-gate  *
825*7c478bd9Sstevel@tonic-gate  * Channels are closed once the last subscriber or publisher performs a
826*7c478bd9Sstevel@tonic-gate  * SE_CLOSE_REGISTRATION operation.  All resources associated with the named
827*7c478bd9Sstevel@tonic-gate  * channel are freed upon last close.
828*7c478bd9Sstevel@tonic-gate  *
829*7c478bd9Sstevel@tonic-gate  * Locking:
830*7c478bd9Sstevel@tonic-gate  *	Every operation to log_sysevent() is protected by a single lock,
831*7c478bd9Sstevel@tonic-gate  *	registered_channel_mutex.  It is expected that the granularity of
832*7c478bd9Sstevel@tonic-gate  *	a single lock is sufficient given the frequency that updates will
833*7c478bd9Sstevel@tonic-gate  *	occur.
834*7c478bd9Sstevel@tonic-gate  *
835*7c478bd9Sstevel@tonic-gate  *	If this locking strategy proves to be too contentious, a per-hash
836*7c478bd9Sstevel@tonic-gate  *	or per-channel locking strategy may be implemented.
837*7c478bd9Sstevel@tonic-gate  */
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 
840*7c478bd9Sstevel@tonic-gate #define	CHANN_HASH(channel_name)	(hash_func(channel_name) \
841*7c478bd9Sstevel@tonic-gate 					% CHAN_HASH_SZ)
842*7c478bd9Sstevel@tonic-gate 
843*7c478bd9Sstevel@tonic-gate sysevent_channel_descriptor_t *registered_channels[CHAN_HASH_SZ];
844*7c478bd9Sstevel@tonic-gate static int channel_cnt;
845*7c478bd9Sstevel@tonic-gate static void remove_all_class(sysevent_channel_descriptor_t *chan,
846*7c478bd9Sstevel@tonic-gate 	uint32_t sub_id);
847*7c478bd9Sstevel@tonic-gate 
848*7c478bd9Sstevel@tonic-gate static uint32_t
849*7c478bd9Sstevel@tonic-gate hash_func(const char *s)
850*7c478bd9Sstevel@tonic-gate {
851*7c478bd9Sstevel@tonic-gate 	uint32_t result = 0;
852*7c478bd9Sstevel@tonic-gate 	uint_t g;
853*7c478bd9Sstevel@tonic-gate 
854*7c478bd9Sstevel@tonic-gate 	while (*s != '\0') {
855*7c478bd9Sstevel@tonic-gate 		result <<= 4;
856*7c478bd9Sstevel@tonic-gate 		result += (uint32_t)*s++;
857*7c478bd9Sstevel@tonic-gate 		g = result & 0xf0000000;
858*7c478bd9Sstevel@tonic-gate 		if (g != 0) {
859*7c478bd9Sstevel@tonic-gate 			result ^= g >> 24;
860*7c478bd9Sstevel@tonic-gate 			result ^= g;
861*7c478bd9Sstevel@tonic-gate 		}
862*7c478bd9Sstevel@tonic-gate 	}
863*7c478bd9Sstevel@tonic-gate 
864*7c478bd9Sstevel@tonic-gate 	return (result);
865*7c478bd9Sstevel@tonic-gate }
866*7c478bd9Sstevel@tonic-gate 
867*7c478bd9Sstevel@tonic-gate static sysevent_channel_descriptor_t *
868*7c478bd9Sstevel@tonic-gate get_channel(char *channel_name)
869*7c478bd9Sstevel@tonic-gate {
870*7c478bd9Sstevel@tonic-gate 	int hash_index;
871*7c478bd9Sstevel@tonic-gate 	sysevent_channel_descriptor_t *chan_list;
872*7c478bd9Sstevel@tonic-gate 
873*7c478bd9Sstevel@tonic-gate 	if (channel_name == NULL)
874*7c478bd9Sstevel@tonic-gate 		return (NULL);
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate 	/* Find channel descriptor */
877*7c478bd9Sstevel@tonic-gate 	hash_index = CHANN_HASH(channel_name);
878*7c478bd9Sstevel@tonic-gate 	chan_list = registered_channels[hash_index];
879*7c478bd9Sstevel@tonic-gate 	while (chan_list != NULL) {
880*7c478bd9Sstevel@tonic-gate 		if (strcmp(chan_list->scd_channel_name, channel_name) == 0) {
881*7c478bd9Sstevel@tonic-gate 			break;
882*7c478bd9Sstevel@tonic-gate 		} else {
883*7c478bd9Sstevel@tonic-gate 			chan_list = chan_list->scd_next;
884*7c478bd9Sstevel@tonic-gate 		}
885*7c478bd9Sstevel@tonic-gate 	}
886*7c478bd9Sstevel@tonic-gate 
887*7c478bd9Sstevel@tonic-gate 	return (chan_list);
888*7c478bd9Sstevel@tonic-gate }
889*7c478bd9Sstevel@tonic-gate 
890*7c478bd9Sstevel@tonic-gate static class_lst_t *
891*7c478bd9Sstevel@tonic-gate create_channel_registration(sysevent_channel_descriptor_t *chan,
892*7c478bd9Sstevel@tonic-gate     char *event_class, int index)
893*7c478bd9Sstevel@tonic-gate {
894*7c478bd9Sstevel@tonic-gate 	size_t class_len;
895*7c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
896*7c478bd9Sstevel@tonic-gate 
897*7c478bd9Sstevel@tonic-gate 	class_len = strlen(event_class) + 1;
898*7c478bd9Sstevel@tonic-gate 	c_list = kmem_zalloc(sizeof (class_lst_t), KM_SLEEP);
899*7c478bd9Sstevel@tonic-gate 	c_list->cl_name = kmem_zalloc(class_len, KM_SLEEP);
900*7c478bd9Sstevel@tonic-gate 	bcopy(event_class, c_list->cl_name, class_len);
901*7c478bd9Sstevel@tonic-gate 
902*7c478bd9Sstevel@tonic-gate 	c_list->cl_subclass_list =
903*7c478bd9Sstevel@tonic-gate 	    kmem_zalloc(sizeof (subclass_lst_t), KM_SLEEP);
904*7c478bd9Sstevel@tonic-gate 	c_list->cl_subclass_list->sl_name =
905*7c478bd9Sstevel@tonic-gate 	    kmem_zalloc(sizeof (EC_SUB_ALL), KM_SLEEP);
906*7c478bd9Sstevel@tonic-gate 	bcopy(EC_SUB_ALL, c_list->cl_subclass_list->sl_name,
907*7c478bd9Sstevel@tonic-gate 	    sizeof (EC_SUB_ALL));
908*7c478bd9Sstevel@tonic-gate 
909*7c478bd9Sstevel@tonic-gate 	c_list->cl_next = chan->scd_class_list_tbl[index];
910*7c478bd9Sstevel@tonic-gate 	chan->scd_class_list_tbl[index] = c_list;
911*7c478bd9Sstevel@tonic-gate 
912*7c478bd9Sstevel@tonic-gate 	return (c_list);
913*7c478bd9Sstevel@tonic-gate }
914*7c478bd9Sstevel@tonic-gate 
915*7c478bd9Sstevel@tonic-gate static void
916*7c478bd9Sstevel@tonic-gate free_channel_registration(sysevent_channel_descriptor_t *chan)
917*7c478bd9Sstevel@tonic-gate {
918*7c478bd9Sstevel@tonic-gate 	int i;
919*7c478bd9Sstevel@tonic-gate 	class_lst_t *clist, *next_clist;
920*7c478bd9Sstevel@tonic-gate 	subclass_lst_t *sclist, *next_sc;
921*7c478bd9Sstevel@tonic-gate 
922*7c478bd9Sstevel@tonic-gate 	for (i = 0; i <= CLASS_HASH_SZ; ++i) {
923*7c478bd9Sstevel@tonic-gate 
924*7c478bd9Sstevel@tonic-gate 		clist = chan->scd_class_list_tbl[i];
925*7c478bd9Sstevel@tonic-gate 		while (clist != NULL) {
926*7c478bd9Sstevel@tonic-gate 			sclist = clist->cl_subclass_list;
927*7c478bd9Sstevel@tonic-gate 			while (sclist != NULL) {
928*7c478bd9Sstevel@tonic-gate 				kmem_free(sclist->sl_name,
929*7c478bd9Sstevel@tonic-gate 				    strlen(sclist->sl_name) + 1);
930*7c478bd9Sstevel@tonic-gate 				next_sc = sclist->sl_next;
931*7c478bd9Sstevel@tonic-gate 				kmem_free(sclist, sizeof (subclass_lst_t));
932*7c478bd9Sstevel@tonic-gate 				sclist = next_sc;
933*7c478bd9Sstevel@tonic-gate 			}
934*7c478bd9Sstevel@tonic-gate 			kmem_free(clist->cl_name,
935*7c478bd9Sstevel@tonic-gate 			    strlen(clist->cl_name) + 1);
936*7c478bd9Sstevel@tonic-gate 			next_clist = clist->cl_next;
937*7c478bd9Sstevel@tonic-gate 			kmem_free(clist, sizeof (class_lst_t));
938*7c478bd9Sstevel@tonic-gate 			clist = next_clist;
939*7c478bd9Sstevel@tonic-gate 		}
940*7c478bd9Sstevel@tonic-gate 	}
941*7c478bd9Sstevel@tonic-gate 	chan->scd_class_list_tbl[0] = NULL;
942*7c478bd9Sstevel@tonic-gate }
943*7c478bd9Sstevel@tonic-gate 
944*7c478bd9Sstevel@tonic-gate static int
945*7c478bd9Sstevel@tonic-gate open_channel(char *channel_name)
946*7c478bd9Sstevel@tonic-gate {
947*7c478bd9Sstevel@tonic-gate 	int hash_index;
948*7c478bd9Sstevel@tonic-gate 	sysevent_channel_descriptor_t *chan, *chan_list;
949*7c478bd9Sstevel@tonic-gate 
950*7c478bd9Sstevel@tonic-gate 
951*7c478bd9Sstevel@tonic-gate 	if (channel_cnt > MAX_CHAN) {
952*7c478bd9Sstevel@tonic-gate 		return (-1);
953*7c478bd9Sstevel@tonic-gate 	}
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 	/* Find channel descriptor */
956*7c478bd9Sstevel@tonic-gate 	hash_index = CHANN_HASH(channel_name);
957*7c478bd9Sstevel@tonic-gate 	chan_list = registered_channels[hash_index];
958*7c478bd9Sstevel@tonic-gate 	while (chan_list != NULL) {
959*7c478bd9Sstevel@tonic-gate 		if (strcmp(chan_list->scd_channel_name, channel_name) == 0) {
960*7c478bd9Sstevel@tonic-gate 			chan_list->scd_ref_cnt++;
961*7c478bd9Sstevel@tonic-gate 			kmem_free(channel_name, strlen(channel_name) + 1);
962*7c478bd9Sstevel@tonic-gate 			return (0);
963*7c478bd9Sstevel@tonic-gate 		} else {
964*7c478bd9Sstevel@tonic-gate 			chan_list = chan_list->scd_next;
965*7c478bd9Sstevel@tonic-gate 		}
966*7c478bd9Sstevel@tonic-gate 	}
967*7c478bd9Sstevel@tonic-gate 
968*7c478bd9Sstevel@tonic-gate 
969*7c478bd9Sstevel@tonic-gate 	/* New channel descriptor */
970*7c478bd9Sstevel@tonic-gate 	chan = kmem_zalloc(sizeof (sysevent_channel_descriptor_t), KM_SLEEP);
971*7c478bd9Sstevel@tonic-gate 	chan->scd_channel_name = channel_name;
972*7c478bd9Sstevel@tonic-gate 
973*7c478bd9Sstevel@tonic-gate 	/*
974*7c478bd9Sstevel@tonic-gate 	 * Create subscriber ids in the range [1, MAX_SUBSCRIBERS).
975*7c478bd9Sstevel@tonic-gate 	 * Subscriber id 0 is never allocated, but is used as a reserved id
976*7c478bd9Sstevel@tonic-gate 	 * by libsysevent
977*7c478bd9Sstevel@tonic-gate 	 */
978*7c478bd9Sstevel@tonic-gate 	if ((chan->scd_subscriber_cache = vmem_create(channel_name, (void *)1,
979*7c478bd9Sstevel@tonic-gate 	    MAX_SUBSCRIBERS + 1, 1, NULL, NULL, NULL, 0,
980*7c478bd9Sstevel@tonic-gate 	    VM_NOSLEEP | VMC_IDENTIFIER)) == NULL) {
981*7c478bd9Sstevel@tonic-gate 		kmem_free(chan, sizeof (sysevent_channel_descriptor_t));
982*7c478bd9Sstevel@tonic-gate 		return (-1);
983*7c478bd9Sstevel@tonic-gate 	}
984*7c478bd9Sstevel@tonic-gate 	if ((chan->scd_publisher_cache = vmem_create(channel_name, (void *)1,
985*7c478bd9Sstevel@tonic-gate 	    MAX_PUBLISHERS + 1, 1, NULL, NULL, NULL, 0,
986*7c478bd9Sstevel@tonic-gate 	    VM_NOSLEEP | VMC_IDENTIFIER)) == NULL) {
987*7c478bd9Sstevel@tonic-gate 		vmem_destroy(chan->scd_subscriber_cache);
988*7c478bd9Sstevel@tonic-gate 		kmem_free(chan, sizeof (sysevent_channel_descriptor_t));
989*7c478bd9Sstevel@tonic-gate 		return (-1);
990*7c478bd9Sstevel@tonic-gate 	}
991*7c478bd9Sstevel@tonic-gate 
992*7c478bd9Sstevel@tonic-gate 	chan->scd_ref_cnt = 1;
993*7c478bd9Sstevel@tonic-gate 
994*7c478bd9Sstevel@tonic-gate 	(void) create_channel_registration(chan, EC_ALL, 0);
995*7c478bd9Sstevel@tonic-gate 
996*7c478bd9Sstevel@tonic-gate 	if (registered_channels[hash_index] != NULL)
997*7c478bd9Sstevel@tonic-gate 		chan->scd_next = registered_channels[hash_index];
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 	registered_channels[hash_index] = chan;
1000*7c478bd9Sstevel@tonic-gate 
1001*7c478bd9Sstevel@tonic-gate 	++channel_cnt;
1002*7c478bd9Sstevel@tonic-gate 
1003*7c478bd9Sstevel@tonic-gate 	return (0);
1004*7c478bd9Sstevel@tonic-gate }
1005*7c478bd9Sstevel@tonic-gate 
1006*7c478bd9Sstevel@tonic-gate static void
1007*7c478bd9Sstevel@tonic-gate close_channel(char *channel_name)
1008*7c478bd9Sstevel@tonic-gate {
1009*7c478bd9Sstevel@tonic-gate 	int hash_index;
1010*7c478bd9Sstevel@tonic-gate 	sysevent_channel_descriptor_t *chan, *prev_chan;
1011*7c478bd9Sstevel@tonic-gate 
1012*7c478bd9Sstevel@tonic-gate 	/* Find channel descriptor */
1013*7c478bd9Sstevel@tonic-gate 	hash_index = CHANN_HASH(channel_name);
1014*7c478bd9Sstevel@tonic-gate 	prev_chan = chan = registered_channels[hash_index];
1015*7c478bd9Sstevel@tonic-gate 
1016*7c478bd9Sstevel@tonic-gate 	while (chan != NULL) {
1017*7c478bd9Sstevel@tonic-gate 		if (strcmp(chan->scd_channel_name, channel_name) == 0) {
1018*7c478bd9Sstevel@tonic-gate 			break;
1019*7c478bd9Sstevel@tonic-gate 		} else {
1020*7c478bd9Sstevel@tonic-gate 			prev_chan = chan;
1021*7c478bd9Sstevel@tonic-gate 			chan = chan->scd_next;
1022*7c478bd9Sstevel@tonic-gate 		}
1023*7c478bd9Sstevel@tonic-gate 	}
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate 	if (chan == NULL)
1026*7c478bd9Sstevel@tonic-gate 		return;
1027*7c478bd9Sstevel@tonic-gate 
1028*7c478bd9Sstevel@tonic-gate 	chan->scd_ref_cnt--;
1029*7c478bd9Sstevel@tonic-gate 	if (chan->scd_ref_cnt > 0)
1030*7c478bd9Sstevel@tonic-gate 		return;
1031*7c478bd9Sstevel@tonic-gate 
1032*7c478bd9Sstevel@tonic-gate 	free_channel_registration(chan);
1033*7c478bd9Sstevel@tonic-gate 	vmem_destroy(chan->scd_subscriber_cache);
1034*7c478bd9Sstevel@tonic-gate 	vmem_destroy(chan->scd_publisher_cache);
1035*7c478bd9Sstevel@tonic-gate 	kmem_free(chan->scd_channel_name,
1036*7c478bd9Sstevel@tonic-gate 	    strlen(chan->scd_channel_name) + 1);
1037*7c478bd9Sstevel@tonic-gate 	if (registered_channels[hash_index] == chan)
1038*7c478bd9Sstevel@tonic-gate 		registered_channels[hash_index] = chan->scd_next;
1039*7c478bd9Sstevel@tonic-gate 	else
1040*7c478bd9Sstevel@tonic-gate 		prev_chan->scd_next = chan->scd_next;
1041*7c478bd9Sstevel@tonic-gate 	kmem_free(chan, sizeof (sysevent_channel_descriptor_t));
1042*7c478bd9Sstevel@tonic-gate 	--channel_cnt;
1043*7c478bd9Sstevel@tonic-gate }
1044*7c478bd9Sstevel@tonic-gate 
1045*7c478bd9Sstevel@tonic-gate static id_t
1046*7c478bd9Sstevel@tonic-gate bind_common(sysevent_channel_descriptor_t *chan, int type)
1047*7c478bd9Sstevel@tonic-gate {
1048*7c478bd9Sstevel@tonic-gate 	id_t id;
1049*7c478bd9Sstevel@tonic-gate 
1050*7c478bd9Sstevel@tonic-gate 	if (type == SUBSCRIBER) {
1051*7c478bd9Sstevel@tonic-gate 		id = (id_t)(uintptr_t)vmem_alloc(chan->scd_subscriber_cache, 1,
1052*7c478bd9Sstevel@tonic-gate 		    VM_NOSLEEP | VM_NEXTFIT);
1053*7c478bd9Sstevel@tonic-gate 		if (id <= 0 || id > MAX_SUBSCRIBERS)
1054*7c478bd9Sstevel@tonic-gate 			return (0);
1055*7c478bd9Sstevel@tonic-gate 		chan->scd_subscriber_ids[id] = 1;
1056*7c478bd9Sstevel@tonic-gate 	} else {
1057*7c478bd9Sstevel@tonic-gate 		id = (id_t)(uintptr_t)vmem_alloc(chan->scd_publisher_cache, 1,
1058*7c478bd9Sstevel@tonic-gate 		    VM_NOSLEEP | VM_NEXTFIT);
1059*7c478bd9Sstevel@tonic-gate 		if (id <= 0 || id > MAX_PUBLISHERS)
1060*7c478bd9Sstevel@tonic-gate 			return (0);
1061*7c478bd9Sstevel@tonic-gate 		chan->scd_publisher_ids[id] = 1;
1062*7c478bd9Sstevel@tonic-gate 	}
1063*7c478bd9Sstevel@tonic-gate 
1064*7c478bd9Sstevel@tonic-gate 	return (id);
1065*7c478bd9Sstevel@tonic-gate }
1066*7c478bd9Sstevel@tonic-gate 
1067*7c478bd9Sstevel@tonic-gate static int
1068*7c478bd9Sstevel@tonic-gate unbind_common(sysevent_channel_descriptor_t *chan, int type, id_t id)
1069*7c478bd9Sstevel@tonic-gate {
1070*7c478bd9Sstevel@tonic-gate 	if (type == SUBSCRIBER) {
1071*7c478bd9Sstevel@tonic-gate 		if (id <= 0 || id > MAX_SUBSCRIBERS)
1072*7c478bd9Sstevel@tonic-gate 			return (0);
1073*7c478bd9Sstevel@tonic-gate 		if (chan->scd_subscriber_ids[id] == 0)
1074*7c478bd9Sstevel@tonic-gate 			return (0);
1075*7c478bd9Sstevel@tonic-gate 		(void) remove_all_class(chan, id);
1076*7c478bd9Sstevel@tonic-gate 		chan->scd_subscriber_ids[id] = 0;
1077*7c478bd9Sstevel@tonic-gate 		vmem_free(chan->scd_subscriber_cache, (void *)(uintptr_t)id, 1);
1078*7c478bd9Sstevel@tonic-gate 	} else {
1079*7c478bd9Sstevel@tonic-gate 		if (id <= 0 || id > MAX_PUBLISHERS)
1080*7c478bd9Sstevel@tonic-gate 			return (0);
1081*7c478bd9Sstevel@tonic-gate 		if (chan->scd_publisher_ids[id] == 0)
1082*7c478bd9Sstevel@tonic-gate 			return (0);
1083*7c478bd9Sstevel@tonic-gate 		chan->scd_publisher_ids[id] = 0;
1084*7c478bd9Sstevel@tonic-gate 		vmem_free(chan->scd_publisher_cache, (void *)(uintptr_t)id, 1);
1085*7c478bd9Sstevel@tonic-gate 	}
1086*7c478bd9Sstevel@tonic-gate 
1087*7c478bd9Sstevel@tonic-gate 	return (1);
1088*7c478bd9Sstevel@tonic-gate }
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate static void
1091*7c478bd9Sstevel@tonic-gate release_id(sysevent_channel_descriptor_t *chan, int type, id_t id)
1092*7c478bd9Sstevel@tonic-gate {
1093*7c478bd9Sstevel@tonic-gate 	if (unbind_common(chan, type, id))
1094*7c478bd9Sstevel@tonic-gate 		close_channel(chan->scd_channel_name);
1095*7c478bd9Sstevel@tonic-gate }
1096*7c478bd9Sstevel@tonic-gate 
1097*7c478bd9Sstevel@tonic-gate static subclass_lst_t *
1098*7c478bd9Sstevel@tonic-gate find_subclass(class_lst_t *c_list, char *subclass)
1099*7c478bd9Sstevel@tonic-gate {
1100*7c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
1101*7c478bd9Sstevel@tonic-gate 
1102*7c478bd9Sstevel@tonic-gate 	if (c_list == NULL)
1103*7c478bd9Sstevel@tonic-gate 		return (NULL);
1104*7c478bd9Sstevel@tonic-gate 
1105*7c478bd9Sstevel@tonic-gate 	sc_list = c_list->cl_subclass_list;
1106*7c478bd9Sstevel@tonic-gate 
1107*7c478bd9Sstevel@tonic-gate 	while (sc_list != NULL) {
1108*7c478bd9Sstevel@tonic-gate 		if (strcmp(sc_list->sl_name, subclass) == 0) {
1109*7c478bd9Sstevel@tonic-gate 			return (sc_list);
1110*7c478bd9Sstevel@tonic-gate 		}
1111*7c478bd9Sstevel@tonic-gate 		sc_list = sc_list->sl_next;
1112*7c478bd9Sstevel@tonic-gate 	}
1113*7c478bd9Sstevel@tonic-gate 
1114*7c478bd9Sstevel@tonic-gate 	return (NULL);
1115*7c478bd9Sstevel@tonic-gate }
1116*7c478bd9Sstevel@tonic-gate 
1117*7c478bd9Sstevel@tonic-gate static void
1118*7c478bd9Sstevel@tonic-gate insert_subclass(class_lst_t *c_list, char **subclass_names,
1119*7c478bd9Sstevel@tonic-gate 	int subclass_num, uint32_t sub_id)
1120*7c478bd9Sstevel@tonic-gate {
1121*7c478bd9Sstevel@tonic-gate 	int i, subclass_sz;
1122*7c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
1123*7c478bd9Sstevel@tonic-gate 
1124*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < subclass_num; ++i) {
1125*7c478bd9Sstevel@tonic-gate 		if ((sc_list = find_subclass(c_list, subclass_names[i]))
1126*7c478bd9Sstevel@tonic-gate 		    != NULL) {
1127*7c478bd9Sstevel@tonic-gate 			sc_list->sl_num[sub_id] = 1;
1128*7c478bd9Sstevel@tonic-gate 		} else {
1129*7c478bd9Sstevel@tonic-gate 
1130*7c478bd9Sstevel@tonic-gate 			sc_list = kmem_zalloc(sizeof (subclass_lst_t),
1131*7c478bd9Sstevel@tonic-gate 			    KM_SLEEP);
1132*7c478bd9Sstevel@tonic-gate 			subclass_sz = strlen(subclass_names[i]) + 1;
1133*7c478bd9Sstevel@tonic-gate 			sc_list->sl_name = kmem_zalloc(subclass_sz, KM_SLEEP);
1134*7c478bd9Sstevel@tonic-gate 			bcopy(subclass_names[i], sc_list->sl_name,
1135*7c478bd9Sstevel@tonic-gate 			    subclass_sz);
1136*7c478bd9Sstevel@tonic-gate 
1137*7c478bd9Sstevel@tonic-gate 			sc_list->sl_num[sub_id] = 1;
1138*7c478bd9Sstevel@tonic-gate 
1139*7c478bd9Sstevel@tonic-gate 			sc_list->sl_next = c_list->cl_subclass_list;
1140*7c478bd9Sstevel@tonic-gate 			c_list->cl_subclass_list = sc_list;
1141*7c478bd9Sstevel@tonic-gate 		}
1142*7c478bd9Sstevel@tonic-gate 	}
1143*7c478bd9Sstevel@tonic-gate }
1144*7c478bd9Sstevel@tonic-gate 
1145*7c478bd9Sstevel@tonic-gate static class_lst_t *
1146*7c478bd9Sstevel@tonic-gate find_class(sysevent_channel_descriptor_t *chan, char *class_name)
1147*7c478bd9Sstevel@tonic-gate {
1148*7c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
1149*7c478bd9Sstevel@tonic-gate 
1150*7c478bd9Sstevel@tonic-gate 	c_list = chan->scd_class_list_tbl[CLASS_HASH(class_name)];
1151*7c478bd9Sstevel@tonic-gate 	while (c_list != NULL) {
1152*7c478bd9Sstevel@tonic-gate 		if (strcmp(class_name, c_list->cl_name) == 0)
1153*7c478bd9Sstevel@tonic-gate 			break;
1154*7c478bd9Sstevel@tonic-gate 		c_list = c_list->cl_next;
1155*7c478bd9Sstevel@tonic-gate 	}
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 	return (c_list);
1158*7c478bd9Sstevel@tonic-gate }
1159*7c478bd9Sstevel@tonic-gate 
1160*7c478bd9Sstevel@tonic-gate static void
1161*7c478bd9Sstevel@tonic-gate remove_all_class(sysevent_channel_descriptor_t *chan, uint32_t sub_id)
1162*7c478bd9Sstevel@tonic-gate {
1163*7c478bd9Sstevel@tonic-gate 	int i;
1164*7c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
1165*7c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
1166*7c478bd9Sstevel@tonic-gate 
1167*7c478bd9Sstevel@tonic-gate 	for (i = 0; i <= CLASS_HASH_SZ; ++i) {
1168*7c478bd9Sstevel@tonic-gate 
1169*7c478bd9Sstevel@tonic-gate 		c_list = chan->scd_class_list_tbl[i];
1170*7c478bd9Sstevel@tonic-gate 		while (c_list != NULL) {
1171*7c478bd9Sstevel@tonic-gate 			sc_list = c_list->cl_subclass_list;
1172*7c478bd9Sstevel@tonic-gate 			while (sc_list != NULL) {
1173*7c478bd9Sstevel@tonic-gate 				sc_list->sl_num[sub_id] = 0;
1174*7c478bd9Sstevel@tonic-gate 				sc_list = sc_list->sl_next;
1175*7c478bd9Sstevel@tonic-gate 			}
1176*7c478bd9Sstevel@tonic-gate 			c_list = c_list->cl_next;
1177*7c478bd9Sstevel@tonic-gate 		}
1178*7c478bd9Sstevel@tonic-gate 	}
1179*7c478bd9Sstevel@tonic-gate }
1180*7c478bd9Sstevel@tonic-gate 
1181*7c478bd9Sstevel@tonic-gate static void
1182*7c478bd9Sstevel@tonic-gate remove_class(sysevent_channel_descriptor_t *chan, uint32_t sub_id,
1183*7c478bd9Sstevel@tonic-gate 	char *class_name)
1184*7c478bd9Sstevel@tonic-gate {
1185*7c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
1186*7c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
1187*7c478bd9Sstevel@tonic-gate 
1188*7c478bd9Sstevel@tonic-gate 	if (strcmp(class_name, EC_ALL) == 0) {
1189*7c478bd9Sstevel@tonic-gate 		remove_all_class(chan, sub_id);
1190*7c478bd9Sstevel@tonic-gate 		return;
1191*7c478bd9Sstevel@tonic-gate 	}
1192*7c478bd9Sstevel@tonic-gate 
1193*7c478bd9Sstevel@tonic-gate 	if ((c_list = find_class(chan, class_name)) == NULL) {
1194*7c478bd9Sstevel@tonic-gate 		return;
1195*7c478bd9Sstevel@tonic-gate 	}
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate 	sc_list = c_list->cl_subclass_list;
1198*7c478bd9Sstevel@tonic-gate 	while (sc_list != NULL) {
1199*7c478bd9Sstevel@tonic-gate 		sc_list->sl_num[sub_id] = 0;
1200*7c478bd9Sstevel@tonic-gate 		sc_list = sc_list->sl_next;
1201*7c478bd9Sstevel@tonic-gate 	}
1202*7c478bd9Sstevel@tonic-gate }
1203*7c478bd9Sstevel@tonic-gate 
1204*7c478bd9Sstevel@tonic-gate static int
1205*7c478bd9Sstevel@tonic-gate insert_class(sysevent_channel_descriptor_t *chan, char *event_class,
1206*7c478bd9Sstevel@tonic-gate 	char **event_subclass_lst, int subclass_num, uint32_t sub_id)
1207*7c478bd9Sstevel@tonic-gate {
1208*7c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
1209*7c478bd9Sstevel@tonic-gate 
1210*7c478bd9Sstevel@tonic-gate 	if (strcmp(event_class, EC_ALL) == 0) {
1211*7c478bd9Sstevel@tonic-gate 		insert_subclass(chan->scd_class_list_tbl[0],
1212*7c478bd9Sstevel@tonic-gate 		    event_subclass_lst, 1, sub_id);
1213*7c478bd9Sstevel@tonic-gate 		return (0);
1214*7c478bd9Sstevel@tonic-gate 	}
1215*7c478bd9Sstevel@tonic-gate 
1216*7c478bd9Sstevel@tonic-gate 	if (strlen(event_class) + 1 > MAX_CLASS_LEN)
1217*7c478bd9Sstevel@tonic-gate 		return (-1);
1218*7c478bd9Sstevel@tonic-gate 
1219*7c478bd9Sstevel@tonic-gate 	/* New class, add to the registration cache */
1220*7c478bd9Sstevel@tonic-gate 	if ((c_list = find_class(chan, event_class)) == NULL) {
1221*7c478bd9Sstevel@tonic-gate 		c_list = create_channel_registration(chan, event_class,
1222*7c478bd9Sstevel@tonic-gate 		    CLASS_HASH(event_class));
1223*7c478bd9Sstevel@tonic-gate 	}
1224*7c478bd9Sstevel@tonic-gate 
1225*7c478bd9Sstevel@tonic-gate 	/* Update the subclass list */
1226*7c478bd9Sstevel@tonic-gate 	insert_subclass(c_list, event_subclass_lst, subclass_num, sub_id);
1227*7c478bd9Sstevel@tonic-gate 
1228*7c478bd9Sstevel@tonic-gate 	return (0);
1229*7c478bd9Sstevel@tonic-gate }
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate static int
1232*7c478bd9Sstevel@tonic-gate add_registration(sysevent_channel_descriptor_t *chan, uint32_t sub_id,
1233*7c478bd9Sstevel@tonic-gate 	char *nvlbuf, size_t nvlsize)
1234*7c478bd9Sstevel@tonic-gate {
1235*7c478bd9Sstevel@tonic-gate 	uint_t num_elem;
1236*7c478bd9Sstevel@tonic-gate 	char *event_class;
1237*7c478bd9Sstevel@tonic-gate 	char **event_list;
1238*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
1239*7c478bd9Sstevel@tonic-gate 	nvpair_t *nvpair = NULL;
1240*7c478bd9Sstevel@tonic-gate 
1241*7c478bd9Sstevel@tonic-gate 	if (nvlist_unpack(nvlbuf, nvlsize, &nvl, KM_SLEEP) != 0)
1242*7c478bd9Sstevel@tonic-gate 		return (-1);
1243*7c478bd9Sstevel@tonic-gate 
1244*7c478bd9Sstevel@tonic-gate 	if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) {
1245*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
1246*7c478bd9Sstevel@tonic-gate 		return (-1);
1247*7c478bd9Sstevel@tonic-gate 	}
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 	if ((event_class = nvpair_name(nvpair)) == NULL) {
1250*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
1251*7c478bd9Sstevel@tonic-gate 		return (-1);
1252*7c478bd9Sstevel@tonic-gate 	}
1253*7c478bd9Sstevel@tonic-gate 	if (nvpair_value_string_array(nvpair, &event_list,
1254*7c478bd9Sstevel@tonic-gate 	    &num_elem) != 0) {
1255*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
1256*7c478bd9Sstevel@tonic-gate 		return (-1);
1257*7c478bd9Sstevel@tonic-gate 	}
1258*7c478bd9Sstevel@tonic-gate 
1259*7c478bd9Sstevel@tonic-gate 	if (insert_class(chan, event_class, event_list, num_elem, sub_id) < 0) {
1260*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
1261*7c478bd9Sstevel@tonic-gate 		return (-1);
1262*7c478bd9Sstevel@tonic-gate 	}
1263*7c478bd9Sstevel@tonic-gate 
1264*7c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 	return (0);
1267*7c478bd9Sstevel@tonic-gate }
1268*7c478bd9Sstevel@tonic-gate 
1269*7c478bd9Sstevel@tonic-gate /*
1270*7c478bd9Sstevel@tonic-gate  * get_registration - Return the requested class hash chain
1271*7c478bd9Sstevel@tonic-gate  */
1272*7c478bd9Sstevel@tonic-gate static int
1273*7c478bd9Sstevel@tonic-gate get_registration(sysevent_channel_descriptor_t *chan, char *databuf,
1274*7c478bd9Sstevel@tonic-gate 	uint32_t *bufsz, uint32_t class_index)
1275*7c478bd9Sstevel@tonic-gate {
1276*7c478bd9Sstevel@tonic-gate 	int num_classes = 0;
1277*7c478bd9Sstevel@tonic-gate 	char *nvlbuf = NULL;
1278*7c478bd9Sstevel@tonic-gate 	size_t nvlsize;
1279*7c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
1280*7c478bd9Sstevel@tonic-gate 	class_lst_t *clist;
1281*7c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
1282*7c478bd9Sstevel@tonic-gate 
1283*7c478bd9Sstevel@tonic-gate 	if (class_index < 0 || class_index > CLASS_HASH_SZ)
1284*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1285*7c478bd9Sstevel@tonic-gate 
1286*7c478bd9Sstevel@tonic-gate 	if ((clist = chan->scd_class_list_tbl[class_index]) == NULL) {
1287*7c478bd9Sstevel@tonic-gate 		return (ENOENT);
1288*7c478bd9Sstevel@tonic-gate 	}
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&nvl, 0, 0) != 0) {
1291*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1292*7c478bd9Sstevel@tonic-gate 	}
1293*7c478bd9Sstevel@tonic-gate 
1294*7c478bd9Sstevel@tonic-gate 	while (clist != NULL) {
1295*7c478bd9Sstevel@tonic-gate 		if (nvlist_add_string(nvl, CLASS_NAME, clist->cl_name)
1296*7c478bd9Sstevel@tonic-gate 		    != 0) {
1297*7c478bd9Sstevel@tonic-gate 			nvlist_free(nvl);
1298*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
1299*7c478bd9Sstevel@tonic-gate 		}
1300*7c478bd9Sstevel@tonic-gate 
1301*7c478bd9Sstevel@tonic-gate 		sc_list = clist->cl_subclass_list;
1302*7c478bd9Sstevel@tonic-gate 		while (sc_list != NULL) {
1303*7c478bd9Sstevel@tonic-gate 			if (nvlist_add_byte_array(nvl, sc_list->sl_name,
1304*7c478bd9Sstevel@tonic-gate 			    sc_list->sl_num, MAX_SUBSCRIBERS) != 0) {
1305*7c478bd9Sstevel@tonic-gate 				nvlist_free(nvl);
1306*7c478bd9Sstevel@tonic-gate 				return (EFAULT);
1307*7c478bd9Sstevel@tonic-gate 			}
1308*7c478bd9Sstevel@tonic-gate 			sc_list = sc_list->sl_next;
1309*7c478bd9Sstevel@tonic-gate 		}
1310*7c478bd9Sstevel@tonic-gate 		num_classes++;
1311*7c478bd9Sstevel@tonic-gate 		clist = clist->cl_next;
1312*7c478bd9Sstevel@tonic-gate 	}
1313*7c478bd9Sstevel@tonic-gate 
1314*7c478bd9Sstevel@tonic-gate 	if (num_classes == 0) {
1315*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
1316*7c478bd9Sstevel@tonic-gate 		return (ENOENT);
1317*7c478bd9Sstevel@tonic-gate 	}
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate 	if (nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE,
1320*7c478bd9Sstevel@tonic-gate 	    KM_SLEEP)
1321*7c478bd9Sstevel@tonic-gate 	    != 0) {
1322*7c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
1323*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1324*7c478bd9Sstevel@tonic-gate 	}
1325*7c478bd9Sstevel@tonic-gate 
1326*7c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
1327*7c478bd9Sstevel@tonic-gate 
1328*7c478bd9Sstevel@tonic-gate 	if (nvlsize > *bufsz) {
1329*7c478bd9Sstevel@tonic-gate 		kmem_free(nvlbuf, nvlsize);
1330*7c478bd9Sstevel@tonic-gate 		*bufsz = nvlsize;
1331*7c478bd9Sstevel@tonic-gate 		return (EAGAIN);
1332*7c478bd9Sstevel@tonic-gate 	}
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 	bcopy(nvlbuf, databuf, nvlsize);
1335*7c478bd9Sstevel@tonic-gate 	kmem_free(nvlbuf, nvlsize);
1336*7c478bd9Sstevel@tonic-gate 
1337*7c478bd9Sstevel@tonic-gate 	return (0);
1338*7c478bd9Sstevel@tonic-gate }
1339*7c478bd9Sstevel@tonic-gate 
1340*7c478bd9Sstevel@tonic-gate /*
1341*7c478bd9Sstevel@tonic-gate  * log_sysevent_register - Register event subscriber for a particular
1342*7c478bd9Sstevel@tonic-gate  *		event channel.
1343*7c478bd9Sstevel@tonic-gate  */
1344*7c478bd9Sstevel@tonic-gate int
1345*7c478bd9Sstevel@tonic-gate log_sysevent_register(char *channel_name, char *udatabuf, se_pubsub_t *udata)
1346*7c478bd9Sstevel@tonic-gate {
1347*7c478bd9Sstevel@tonic-gate 	int error = 0;
1348*7c478bd9Sstevel@tonic-gate 	char *kchannel, *databuf = NULL;
1349*7c478bd9Sstevel@tonic-gate 	size_t bufsz;
1350*7c478bd9Sstevel@tonic-gate 	se_pubsub_t kdata;
1351*7c478bd9Sstevel@tonic-gate 	sysevent_channel_descriptor_t *chan;
1352*7c478bd9Sstevel@tonic-gate 
1353*7c478bd9Sstevel@tonic-gate 	if (copyin(udata, &kdata, sizeof (se_pubsub_t)) == -1) {
1354*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1355*7c478bd9Sstevel@tonic-gate 	}
1356*7c478bd9Sstevel@tonic-gate 	if (kdata.ps_channel_name_len == 0) {
1357*7c478bd9Sstevel@tonic-gate 		return (EINVAL);
1358*7c478bd9Sstevel@tonic-gate 	}
1359*7c478bd9Sstevel@tonic-gate 	kchannel = kmem_alloc(kdata.ps_channel_name_len, KM_SLEEP);
1360*7c478bd9Sstevel@tonic-gate 	if (copyin(channel_name, kchannel, kdata.ps_channel_name_len) == -1) {
1361*7c478bd9Sstevel@tonic-gate 		kmem_free(kchannel, kdata.ps_channel_name_len);
1362*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1363*7c478bd9Sstevel@tonic-gate 	}
1364*7c478bd9Sstevel@tonic-gate 	bufsz = kdata.ps_buflen;
1365*7c478bd9Sstevel@tonic-gate 	if (bufsz > 0) {
1366*7c478bd9Sstevel@tonic-gate 		databuf = kmem_alloc(bufsz, KM_SLEEP);
1367*7c478bd9Sstevel@tonic-gate 		if (copyin(udatabuf, databuf, bufsz) == -1) {
1368*7c478bd9Sstevel@tonic-gate 			kmem_free(kchannel, kdata.ps_channel_name_len);
1369*7c478bd9Sstevel@tonic-gate 			kmem_free(databuf, bufsz);
1370*7c478bd9Sstevel@tonic-gate 			return (EFAULT);
1371*7c478bd9Sstevel@tonic-gate 		}
1372*7c478bd9Sstevel@tonic-gate 	}
1373*7c478bd9Sstevel@tonic-gate 
1374*7c478bd9Sstevel@tonic-gate 	mutex_enter(&registered_channel_mutex);
1375*7c478bd9Sstevel@tonic-gate 	if (kdata.ps_op != SE_OPEN_REGISTRATION &&
1376*7c478bd9Sstevel@tonic-gate 	    kdata.ps_op != SE_CLOSE_REGISTRATION) {
1377*7c478bd9Sstevel@tonic-gate 		chan = get_channel(kchannel);
1378*7c478bd9Sstevel@tonic-gate 		if (chan == NULL) {
1379*7c478bd9Sstevel@tonic-gate 			mutex_exit(&registered_channel_mutex);
1380*7c478bd9Sstevel@tonic-gate 			kmem_free(kchannel, kdata.ps_channel_name_len);
1381*7c478bd9Sstevel@tonic-gate 			if (bufsz > 0)
1382*7c478bd9Sstevel@tonic-gate 				kmem_free(databuf, bufsz);
1383*7c478bd9Sstevel@tonic-gate 			return (ENOENT);
1384*7c478bd9Sstevel@tonic-gate 		}
1385*7c478bd9Sstevel@tonic-gate 	}
1386*7c478bd9Sstevel@tonic-gate 
1387*7c478bd9Sstevel@tonic-gate 	switch (kdata.ps_op) {
1388*7c478bd9Sstevel@tonic-gate 	case SE_OPEN_REGISTRATION:
1389*7c478bd9Sstevel@tonic-gate 		if (open_channel(kchannel) != 0) {
1390*7c478bd9Sstevel@tonic-gate 			error = ENOMEM;
1391*7c478bd9Sstevel@tonic-gate 			if (bufsz > 0)
1392*7c478bd9Sstevel@tonic-gate 				kmem_free(databuf, bufsz);
1393*7c478bd9Sstevel@tonic-gate 			kmem_free(kchannel, kdata.ps_channel_name_len);
1394*7c478bd9Sstevel@tonic-gate 		}
1395*7c478bd9Sstevel@tonic-gate 
1396*7c478bd9Sstevel@tonic-gate 		mutex_exit(&registered_channel_mutex);
1397*7c478bd9Sstevel@tonic-gate 		return (error);
1398*7c478bd9Sstevel@tonic-gate 	case SE_CLOSE_REGISTRATION:
1399*7c478bd9Sstevel@tonic-gate 		close_channel(kchannel);
1400*7c478bd9Sstevel@tonic-gate 		break;
1401*7c478bd9Sstevel@tonic-gate 	case SE_BIND_REGISTRATION:
1402*7c478bd9Sstevel@tonic-gate 		if ((kdata.ps_id = bind_common(chan, kdata.ps_type)) <= 0)
1403*7c478bd9Sstevel@tonic-gate 			error = EBUSY;
1404*7c478bd9Sstevel@tonic-gate 		break;
1405*7c478bd9Sstevel@tonic-gate 	case SE_UNBIND_REGISTRATION:
1406*7c478bd9Sstevel@tonic-gate 		(void) unbind_common(chan, kdata.ps_type, (id_t)kdata.ps_id);
1407*7c478bd9Sstevel@tonic-gate 		break;
1408*7c478bd9Sstevel@tonic-gate 	case SE_REGISTER:
1409*7c478bd9Sstevel@tonic-gate 		if (bufsz == 0) {
1410*7c478bd9Sstevel@tonic-gate 			error = EINVAL;
1411*7c478bd9Sstevel@tonic-gate 			break;
1412*7c478bd9Sstevel@tonic-gate 		}
1413*7c478bd9Sstevel@tonic-gate 		if (add_registration(chan, kdata.ps_id, databuf, bufsz) == -1)
1414*7c478bd9Sstevel@tonic-gate 			error = EINVAL;
1415*7c478bd9Sstevel@tonic-gate 		break;
1416*7c478bd9Sstevel@tonic-gate 	case SE_UNREGISTER:
1417*7c478bd9Sstevel@tonic-gate 		if (bufsz == 0) {
1418*7c478bd9Sstevel@tonic-gate 			error = EINVAL;
1419*7c478bd9Sstevel@tonic-gate 			break;
1420*7c478bd9Sstevel@tonic-gate 		}
1421*7c478bd9Sstevel@tonic-gate 		remove_class(chan, kdata.ps_id, databuf);
1422*7c478bd9Sstevel@tonic-gate 		break;
1423*7c478bd9Sstevel@tonic-gate 	case SE_CLEANUP:
1424*7c478bd9Sstevel@tonic-gate 		/* Cleanup the indicated subscriber or publisher */
1425*7c478bd9Sstevel@tonic-gate 		release_id(chan, kdata.ps_type, kdata.ps_id);
1426*7c478bd9Sstevel@tonic-gate 		break;
1427*7c478bd9Sstevel@tonic-gate 	case SE_GET_REGISTRATION:
1428*7c478bd9Sstevel@tonic-gate 		error = get_registration(chan, databuf,
1429*7c478bd9Sstevel@tonic-gate 		    &kdata.ps_buflen, kdata.ps_id);
1430*7c478bd9Sstevel@tonic-gate 		break;
1431*7c478bd9Sstevel@tonic-gate 	default:
1432*7c478bd9Sstevel@tonic-gate 		error = ENOTSUP;
1433*7c478bd9Sstevel@tonic-gate 	}
1434*7c478bd9Sstevel@tonic-gate 
1435*7c478bd9Sstevel@tonic-gate 	mutex_exit(&registered_channel_mutex);
1436*7c478bd9Sstevel@tonic-gate 
1437*7c478bd9Sstevel@tonic-gate 	kmem_free(kchannel, kdata.ps_channel_name_len);
1438*7c478bd9Sstevel@tonic-gate 
1439*7c478bd9Sstevel@tonic-gate 	if (bufsz > 0) {
1440*7c478bd9Sstevel@tonic-gate 		if (copyout(databuf, udatabuf, bufsz) == -1)
1441*7c478bd9Sstevel@tonic-gate 			error = EFAULT;
1442*7c478bd9Sstevel@tonic-gate 		kmem_free(databuf, bufsz);
1443*7c478bd9Sstevel@tonic-gate 	}
1444*7c478bd9Sstevel@tonic-gate 
1445*7c478bd9Sstevel@tonic-gate 	if (copyout(&kdata, udata, sizeof (se_pubsub_t)) == -1)
1446*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1447*7c478bd9Sstevel@tonic-gate 
1448*7c478bd9Sstevel@tonic-gate 	return (error);
1449*7c478bd9Sstevel@tonic-gate }
1450*7c478bd9Sstevel@tonic-gate 
1451*7c478bd9Sstevel@tonic-gate /*
1452*7c478bd9Sstevel@tonic-gate  * log_sysevent_copyout_data - Copyout event data to userland.
1453*7c478bd9Sstevel@tonic-gate  *			This is called from modctl(MODEVENTS, MODEVENTS_GETDATA)
1454*7c478bd9Sstevel@tonic-gate  *			The buffer size is always sufficient.
1455*7c478bd9Sstevel@tonic-gate  */
1456*7c478bd9Sstevel@tonic-gate int
1457*7c478bd9Sstevel@tonic-gate log_sysevent_copyout_data(sysevent_id_t *eid, size_t ubuflen, caddr_t ubuf)
1458*7c478bd9Sstevel@tonic-gate {
1459*7c478bd9Sstevel@tonic-gate 	int error = ENOENT;
1460*7c478bd9Sstevel@tonic-gate 	log_eventq_t *q;
1461*7c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
1462*7c478bd9Sstevel@tonic-gate 	sysevent_id_t eid_copy;
1463*7c478bd9Sstevel@tonic-gate 
1464*7c478bd9Sstevel@tonic-gate 	/*
1465*7c478bd9Sstevel@tonic-gate 	 * Copy eid
1466*7c478bd9Sstevel@tonic-gate 	 */
1467*7c478bd9Sstevel@tonic-gate 	if (copyin(eid, &eid_copy, sizeof (sysevent_id_t)) == -1) {
1468*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1469*7c478bd9Sstevel@tonic-gate 	}
1470*7c478bd9Sstevel@tonic-gate 
1471*7c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_sent_mutex);
1472*7c478bd9Sstevel@tonic-gate 	q = log_eventq_sent;
1473*7c478bd9Sstevel@tonic-gate 
1474*7c478bd9Sstevel@tonic-gate 	/*
1475*7c478bd9Sstevel@tonic-gate 	 * Search for event buffer on the sent queue with matching
1476*7c478bd9Sstevel@tonic-gate 	 * event identifier
1477*7c478bd9Sstevel@tonic-gate 	 */
1478*7c478bd9Sstevel@tonic-gate 	while (q) {
1479*7c478bd9Sstevel@tonic-gate 		ev = (sysevent_t *)&q->arg.buf;
1480*7c478bd9Sstevel@tonic-gate 
1481*7c478bd9Sstevel@tonic-gate 		if (SE_TIME(ev) != eid_copy.eid_ts ||
1482*7c478bd9Sstevel@tonic-gate 		    SE_SEQ(ev) != eid_copy.eid_seq) {
1483*7c478bd9Sstevel@tonic-gate 			q = q->next;
1484*7c478bd9Sstevel@tonic-gate 			continue;
1485*7c478bd9Sstevel@tonic-gate 		}
1486*7c478bd9Sstevel@tonic-gate 
1487*7c478bd9Sstevel@tonic-gate 		if (ubuflen < SE_SIZE(ev)) {
1488*7c478bd9Sstevel@tonic-gate 			error = EFAULT;
1489*7c478bd9Sstevel@tonic-gate 			break;
1490*7c478bd9Sstevel@tonic-gate 		}
1491*7c478bd9Sstevel@tonic-gate 		if (copyout(ev, ubuf, SE_SIZE(ev)) != 0) {
1492*7c478bd9Sstevel@tonic-gate 			error = EFAULT;
1493*7c478bd9Sstevel@tonic-gate 			LOG_DEBUG((CE_NOTE, "Unable to retrieve system event "
1494*7c478bd9Sstevel@tonic-gate 			    "0x%" PRIx64 " from queue: EFAULT\n",
1495*7c478bd9Sstevel@tonic-gate 			    eid->eid_seq));
1496*7c478bd9Sstevel@tonic-gate 		} else {
1497*7c478bd9Sstevel@tonic-gate 			error = 0;
1498*7c478bd9Sstevel@tonic-gate 		}
1499*7c478bd9Sstevel@tonic-gate 		break;
1500*7c478bd9Sstevel@tonic-gate 	}
1501*7c478bd9Sstevel@tonic-gate 
1502*7c478bd9Sstevel@tonic-gate 	mutex_exit(&eventq_sent_mutex);
1503*7c478bd9Sstevel@tonic-gate 
1504*7c478bd9Sstevel@tonic-gate 	return (error);
1505*7c478bd9Sstevel@tonic-gate }
1506*7c478bd9Sstevel@tonic-gate 
1507*7c478bd9Sstevel@tonic-gate /*
1508*7c478bd9Sstevel@tonic-gate  * log_sysevent_free_data - Free kernel copy of the event buffer identified
1509*7c478bd9Sstevel@tonic-gate  *			by eid (must have already been sent).  Called from
1510*7c478bd9Sstevel@tonic-gate  *			modctl(MODEVENTS, MODEVENTS_FREEDATA).
1511*7c478bd9Sstevel@tonic-gate  */
1512*7c478bd9Sstevel@tonic-gate int
1513*7c478bd9Sstevel@tonic-gate log_sysevent_free_data(sysevent_id_t *eid)
1514*7c478bd9Sstevel@tonic-gate {
1515*7c478bd9Sstevel@tonic-gate 	int error = ENOENT;
1516*7c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
1517*7c478bd9Sstevel@tonic-gate 	log_eventq_t *q, *prev = NULL;
1518*7c478bd9Sstevel@tonic-gate 	sysevent_id_t eid_copy;
1519*7c478bd9Sstevel@tonic-gate 
1520*7c478bd9Sstevel@tonic-gate 	/*
1521*7c478bd9Sstevel@tonic-gate 	 * Copy eid
1522*7c478bd9Sstevel@tonic-gate 	 */
1523*7c478bd9Sstevel@tonic-gate 	if (copyin(eid, &eid_copy, sizeof (sysevent_id_t)) == -1) {
1524*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1525*7c478bd9Sstevel@tonic-gate 	}
1526*7c478bd9Sstevel@tonic-gate 
1527*7c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_sent_mutex);
1528*7c478bd9Sstevel@tonic-gate 	q = log_eventq_sent;
1529*7c478bd9Sstevel@tonic-gate 
1530*7c478bd9Sstevel@tonic-gate 	/*
1531*7c478bd9Sstevel@tonic-gate 	 * Look for the event to be freed on the sent queue.  Due to delayed
1532*7c478bd9Sstevel@tonic-gate 	 * processing of the event, it may not be on the sent queue yet.
1533*7c478bd9Sstevel@tonic-gate 	 * It is up to the user to retry the free operation to ensure that the
1534*7c478bd9Sstevel@tonic-gate 	 * event is properly freed.
1535*7c478bd9Sstevel@tonic-gate 	 */
1536*7c478bd9Sstevel@tonic-gate 	while (q) {
1537*7c478bd9Sstevel@tonic-gate 		ev = (sysevent_t *)&q->arg.buf;
1538*7c478bd9Sstevel@tonic-gate 
1539*7c478bd9Sstevel@tonic-gate 		if (SE_TIME(ev) != eid_copy.eid_ts ||
1540*7c478bd9Sstevel@tonic-gate 		    SE_SEQ(ev) != eid_copy.eid_seq) {
1541*7c478bd9Sstevel@tonic-gate 			prev = q;
1542*7c478bd9Sstevel@tonic-gate 			q = q->next;
1543*7c478bd9Sstevel@tonic-gate 			continue;
1544*7c478bd9Sstevel@tonic-gate 		}
1545*7c478bd9Sstevel@tonic-gate 		/*
1546*7c478bd9Sstevel@tonic-gate 		 * Take it out of log_eventq_sent and free it
1547*7c478bd9Sstevel@tonic-gate 		 */
1548*7c478bd9Sstevel@tonic-gate 		if (prev) {
1549*7c478bd9Sstevel@tonic-gate 			prev->next = q->next;
1550*7c478bd9Sstevel@tonic-gate 		} else {
1551*7c478bd9Sstevel@tonic-gate 			log_eventq_sent = q->next;
1552*7c478bd9Sstevel@tonic-gate 		}
1553*7c478bd9Sstevel@tonic-gate 		free_packed_event(ev);
1554*7c478bd9Sstevel@tonic-gate 		error = 0;
1555*7c478bd9Sstevel@tonic-gate 		break;
1556*7c478bd9Sstevel@tonic-gate 	}
1557*7c478bd9Sstevel@tonic-gate 
1558*7c478bd9Sstevel@tonic-gate 	mutex_exit(&eventq_sent_mutex);
1559*7c478bd9Sstevel@tonic-gate 
1560*7c478bd9Sstevel@tonic-gate 	return (error);
1561*7c478bd9Sstevel@tonic-gate }
1562*7c478bd9Sstevel@tonic-gate 
1563*7c478bd9Sstevel@tonic-gate /*
1564*7c478bd9Sstevel@tonic-gate  * log_sysevent_flushq - Begin or resume event buffer delivery.  If neccessary,
1565*7c478bd9Sstevel@tonic-gate  *			create log_event_deliver thread or wake it up
1566*7c478bd9Sstevel@tonic-gate  */
1567*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1568*7c478bd9Sstevel@tonic-gate void
1569*7c478bd9Sstevel@tonic-gate log_sysevent_flushq(int cmd, uint_t flag)
1570*7c478bd9Sstevel@tonic-gate {
1571*7c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_head_mutex);
1572*7c478bd9Sstevel@tonic-gate 
1573*7c478bd9Sstevel@tonic-gate 	/*
1574*7c478bd9Sstevel@tonic-gate 	 * Start the event delivery thread
1575*7c478bd9Sstevel@tonic-gate 	 * Mark the upcall status as active since we should
1576*7c478bd9Sstevel@tonic-gate 	 * now be able to begin emptying the queue normally.
1577*7c478bd9Sstevel@tonic-gate 	 */
1578*7c478bd9Sstevel@tonic-gate 	if (!async_thread) {
1579*7c478bd9Sstevel@tonic-gate 		sysevent_upcall_status = 0;
1580*7c478bd9Sstevel@tonic-gate 		sysevent_daemon_init = 1;
1581*7c478bd9Sstevel@tonic-gate 		setup_ddi_poststartup();
1582*7c478bd9Sstevel@tonic-gate 		async_thread = thread_create(NULL, 0, log_event_deliver,
1583*7c478bd9Sstevel@tonic-gate 		    NULL, 0, &p0, TS_RUN, minclsyspri);
1584*7c478bd9Sstevel@tonic-gate 	}
1585*7c478bd9Sstevel@tonic-gate 
1586*7c478bd9Sstevel@tonic-gate 	log_event_delivery = LOGEVENT_DELIVERY_CONT;
1587*7c478bd9Sstevel@tonic-gate 	cv_signal(&log_event_cv);
1588*7c478bd9Sstevel@tonic-gate 	mutex_exit(&eventq_head_mutex);
1589*7c478bd9Sstevel@tonic-gate }
1590*7c478bd9Sstevel@tonic-gate 
1591*7c478bd9Sstevel@tonic-gate /*
1592*7c478bd9Sstevel@tonic-gate  * log_sysevent_filename - Called by syseventd via
1593*7c478bd9Sstevel@tonic-gate  *			modctl(MODEVENTS, MODEVENTS_SET_DOOR_UPCALL_FILENAME)
1594*7c478bd9Sstevel@tonic-gate  *			to subsequently bind the event_door.
1595*7c478bd9Sstevel@tonic-gate  *
1596*7c478bd9Sstevel@tonic-gate  *			This routine is called everytime syseventd (re)starts
1597*7c478bd9Sstevel@tonic-gate  *			and must therefore replay any events buffers that have
1598*7c478bd9Sstevel@tonic-gate  *			been sent but not freed.
1599*7c478bd9Sstevel@tonic-gate  *
1600*7c478bd9Sstevel@tonic-gate  *			Event buffer delivery begins after a call to
1601*7c478bd9Sstevel@tonic-gate  *			log_sysevent_flushq().
1602*7c478bd9Sstevel@tonic-gate  */
1603*7c478bd9Sstevel@tonic-gate int
1604*7c478bd9Sstevel@tonic-gate log_sysevent_filename(char *file)
1605*7c478bd9Sstevel@tonic-gate {
1606*7c478bd9Sstevel@tonic-gate 	/*
1607*7c478bd9Sstevel@tonic-gate 	 * Called serially by syseventd init code, no need to protect door
1608*7c478bd9Sstevel@tonic-gate 	 * data.
1609*7c478bd9Sstevel@tonic-gate 	 */
1610*7c478bd9Sstevel@tonic-gate 	/* Unbind old event door */
1611*7c478bd9Sstevel@tonic-gate 	if (logevent_door_upcall_filename) {
1612*7c478bd9Sstevel@tonic-gate 		kmem_free(logevent_door_upcall_filename,
1613*7c478bd9Sstevel@tonic-gate 			logevent_door_upcall_filename_size);
1614*7c478bd9Sstevel@tonic-gate 		if (event_door) {
1615*7c478bd9Sstevel@tonic-gate 			door_ki_rele(event_door);
1616*7c478bd9Sstevel@tonic-gate 			event_door = NULL;
1617*7c478bd9Sstevel@tonic-gate 		}
1618*7c478bd9Sstevel@tonic-gate 	}
1619*7c478bd9Sstevel@tonic-gate 	logevent_door_upcall_filename_size = strlen(file) + 1;
1620*7c478bd9Sstevel@tonic-gate 	logevent_door_upcall_filename = kmem_alloc(
1621*7c478bd9Sstevel@tonic-gate 		logevent_door_upcall_filename_size, KM_SLEEP);
1622*7c478bd9Sstevel@tonic-gate 	(void) strcpy(logevent_door_upcall_filename, file);
1623*7c478bd9Sstevel@tonic-gate 
1624*7c478bd9Sstevel@tonic-gate 	/*
1625*7c478bd9Sstevel@tonic-gate 	 * We are called when syseventd restarts. Move all sent, but
1626*7c478bd9Sstevel@tonic-gate 	 * not committed events from log_eventq_sent to log_eventq_head.
1627*7c478bd9Sstevel@tonic-gate 	 * Do it in proper order to maintain increasing event id.
1628*7c478bd9Sstevel@tonic-gate 	 */
1629*7c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_head_mutex);
1630*7c478bd9Sstevel@tonic-gate 
1631*7c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_sent_mutex);
1632*7c478bd9Sstevel@tonic-gate 	while (log_eventq_sent) {
1633*7c478bd9Sstevel@tonic-gate 		log_eventq_t *tmp = log_eventq_sent->next;
1634*7c478bd9Sstevel@tonic-gate 		log_eventq_sent->next = log_eventq_head;
1635*7c478bd9Sstevel@tonic-gate 		if (log_eventq_head == NULL) {
1636*7c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_cnt == 0);
1637*7c478bd9Sstevel@tonic-gate 			log_eventq_tail = log_eventq_sent;
1638*7c478bd9Sstevel@tonic-gate 			log_eventq_tail->next = NULL;
1639*7c478bd9Sstevel@tonic-gate 		} else if (log_eventq_head == log_eventq_tail) {
1640*7c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_cnt == 1);
1641*7c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_head->next == NULL);
1642*7c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_tail->next == NULL);
1643*7c478bd9Sstevel@tonic-gate 		}
1644*7c478bd9Sstevel@tonic-gate 		log_eventq_head = log_eventq_sent;
1645*7c478bd9Sstevel@tonic-gate 		log_eventq_sent = tmp;
1646*7c478bd9Sstevel@tonic-gate 		log_eventq_cnt++;
1647*7c478bd9Sstevel@tonic-gate 	}
1648*7c478bd9Sstevel@tonic-gate 	mutex_exit(&eventq_sent_mutex);
1649*7c478bd9Sstevel@tonic-gate 	mutex_exit(&eventq_head_mutex);
1650*7c478bd9Sstevel@tonic-gate 
1651*7c478bd9Sstevel@tonic-gate 	return (0);
1652*7c478bd9Sstevel@tonic-gate }
1653*7c478bd9Sstevel@tonic-gate 
1654*7c478bd9Sstevel@tonic-gate /*
1655*7c478bd9Sstevel@tonic-gate  * queue_sysevent - queue an event buffer
1656*7c478bd9Sstevel@tonic-gate  */
1657*7c478bd9Sstevel@tonic-gate static int
1658*7c478bd9Sstevel@tonic-gate queue_sysevent(sysevent_t *ev, sysevent_id_t *eid, int flag)
1659*7c478bd9Sstevel@tonic-gate {
1660*7c478bd9Sstevel@tonic-gate 	log_eventq_t *q;
1661*7c478bd9Sstevel@tonic-gate 
1662*7c478bd9Sstevel@tonic-gate 	ASSERT(flag == SE_SLEEP || flag == SE_NOSLEEP);
1663*7c478bd9Sstevel@tonic-gate 
1664*7c478bd9Sstevel@tonic-gate restart:
1665*7c478bd9Sstevel@tonic-gate 
1666*7c478bd9Sstevel@tonic-gate 	/* Max Q size exceeded */
1667*7c478bd9Sstevel@tonic-gate 	mutex_enter(&event_qfull_mutex);
1668*7c478bd9Sstevel@tonic-gate 	if (sysevent_daemon_init && log_eventq_cnt >= logevent_max_q_sz) {
1669*7c478bd9Sstevel@tonic-gate 		/*
1670*7c478bd9Sstevel@tonic-gate 		 * If queue full and transport down, return no transport
1671*7c478bd9Sstevel@tonic-gate 		 */
1672*7c478bd9Sstevel@tonic-gate 		if (sysevent_upcall_status != 0) {
1673*7c478bd9Sstevel@tonic-gate 			mutex_exit(&event_qfull_mutex);
1674*7c478bd9Sstevel@tonic-gate 			free_packed_event(ev);
1675*7c478bd9Sstevel@tonic-gate 			eid->eid_seq = UINT64_C(0);
1676*7c478bd9Sstevel@tonic-gate 			eid->eid_ts = INT64_C(0);
1677*7c478bd9Sstevel@tonic-gate 			return (SE_NO_TRANSPORT);
1678*7c478bd9Sstevel@tonic-gate 		}
1679*7c478bd9Sstevel@tonic-gate 		if (flag == SE_NOSLEEP) {
1680*7c478bd9Sstevel@tonic-gate 			mutex_exit(&event_qfull_mutex);
1681*7c478bd9Sstevel@tonic-gate 			free_packed_event(ev);
1682*7c478bd9Sstevel@tonic-gate 			eid->eid_seq = UINT64_C(0);
1683*7c478bd9Sstevel@tonic-gate 			eid->eid_ts = INT64_C(0);
1684*7c478bd9Sstevel@tonic-gate 			return (SE_EQSIZE);
1685*7c478bd9Sstevel@tonic-gate 		}
1686*7c478bd9Sstevel@tonic-gate 		event_qfull_blocked++;
1687*7c478bd9Sstevel@tonic-gate 		cv_wait(&event_qfull_cv, &event_qfull_mutex);
1688*7c478bd9Sstevel@tonic-gate 		event_qfull_blocked--;
1689*7c478bd9Sstevel@tonic-gate 		mutex_exit(&event_qfull_mutex);
1690*7c478bd9Sstevel@tonic-gate 		goto restart;
1691*7c478bd9Sstevel@tonic-gate 	}
1692*7c478bd9Sstevel@tonic-gate 	mutex_exit(&event_qfull_mutex);
1693*7c478bd9Sstevel@tonic-gate 
1694*7c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_head_mutex);
1695*7c478bd9Sstevel@tonic-gate 
1696*7c478bd9Sstevel@tonic-gate 	/* Time stamp and assign ID */
1697*7c478bd9Sstevel@tonic-gate 	SE_SEQ(ev) = eid->eid_seq = atomic_add_64_nv(&kernel_event_id,
1698*7c478bd9Sstevel@tonic-gate 		(uint64_t)1);
1699*7c478bd9Sstevel@tonic-gate 	SE_TIME(ev) = eid->eid_ts = gethrtime();
1700*7c478bd9Sstevel@tonic-gate 
1701*7c478bd9Sstevel@tonic-gate 	LOG_DEBUG1((CE_CONT, "log_sysevent: class=%d type=%d id=0x%llx\n",
1702*7c478bd9Sstevel@tonic-gate 	    SE_CLASS(ev), SE_SUBCLASS(ev), (longlong_t)SE_SEQ(ev)));
1703*7c478bd9Sstevel@tonic-gate 
1704*7c478bd9Sstevel@tonic-gate 	/*
1705*7c478bd9Sstevel@tonic-gate 	 * Put event on eventq
1706*7c478bd9Sstevel@tonic-gate 	 */
1707*7c478bd9Sstevel@tonic-gate 	q = (log_eventq_t *)((caddr_t)ev - offsetof(log_eventq_t, arg.buf));
1708*7c478bd9Sstevel@tonic-gate 	q->next = NULL;
1709*7c478bd9Sstevel@tonic-gate 	if (log_eventq_head == NULL) {
1710*7c478bd9Sstevel@tonic-gate 		ASSERT(log_eventq_cnt == 0);
1711*7c478bd9Sstevel@tonic-gate 		log_eventq_head = q;
1712*7c478bd9Sstevel@tonic-gate 		log_eventq_tail = q;
1713*7c478bd9Sstevel@tonic-gate 	} else {
1714*7c478bd9Sstevel@tonic-gate 		if (log_eventq_head == log_eventq_tail) {
1715*7c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_cnt == 1);
1716*7c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_head->next == NULL);
1717*7c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_tail->next == NULL);
1718*7c478bd9Sstevel@tonic-gate 		}
1719*7c478bd9Sstevel@tonic-gate 		log_eventq_tail->next = q;
1720*7c478bd9Sstevel@tonic-gate 		log_eventq_tail = q;
1721*7c478bd9Sstevel@tonic-gate 	}
1722*7c478bd9Sstevel@tonic-gate 	log_eventq_cnt++;
1723*7c478bd9Sstevel@tonic-gate 
1724*7c478bd9Sstevel@tonic-gate 	/* Signal event delivery thread */
1725*7c478bd9Sstevel@tonic-gate 	if (log_eventq_cnt == 1) {
1726*7c478bd9Sstevel@tonic-gate 		cv_signal(&log_event_cv);
1727*7c478bd9Sstevel@tonic-gate 	}
1728*7c478bd9Sstevel@tonic-gate 	mutex_exit(&eventq_head_mutex);
1729*7c478bd9Sstevel@tonic-gate 
1730*7c478bd9Sstevel@tonic-gate 	return (0);
1731*7c478bd9Sstevel@tonic-gate }
1732*7c478bd9Sstevel@tonic-gate 
1733*7c478bd9Sstevel@tonic-gate /*
1734*7c478bd9Sstevel@tonic-gate  * log_sysevent - kernel system event logger.
1735*7c478bd9Sstevel@tonic-gate  *
1736*7c478bd9Sstevel@tonic-gate  * Returns SE_ENOMEM if buf allocation failed or SE_EQSIZE if the
1737*7c478bd9Sstevel@tonic-gate  * maximum event queue size will be exceeded
1738*7c478bd9Sstevel@tonic-gate  * Returns 0 for successfully queued event buffer
1739*7c478bd9Sstevel@tonic-gate  */
1740*7c478bd9Sstevel@tonic-gate int
1741*7c478bd9Sstevel@tonic-gate log_sysevent(sysevent_t *ev, int flag, sysevent_id_t *eid)
1742*7c478bd9Sstevel@tonic-gate {
1743*7c478bd9Sstevel@tonic-gate 	sysevent_t *ev_copy;
1744*7c478bd9Sstevel@tonic-gate 	int rval;
1745*7c478bd9Sstevel@tonic-gate 
1746*7c478bd9Sstevel@tonic-gate 	ASSERT(flag == SE_SLEEP || flag == SE_NOSLEEP);
1747*7c478bd9Sstevel@tonic-gate 	ASSERT(!(flag == SE_SLEEP && servicing_interrupt()));
1748*7c478bd9Sstevel@tonic-gate 
1749*7c478bd9Sstevel@tonic-gate 	ev_copy = se_repack(ev, flag);
1750*7c478bd9Sstevel@tonic-gate 	if (ev_copy == NULL) {
1751*7c478bd9Sstevel@tonic-gate 		ASSERT(flag == SE_NOSLEEP);
1752*7c478bd9Sstevel@tonic-gate 		return (SE_ENOMEM);
1753*7c478bd9Sstevel@tonic-gate 	}
1754*7c478bd9Sstevel@tonic-gate 	rval = queue_sysevent(ev_copy, eid, flag);
1755*7c478bd9Sstevel@tonic-gate 	ASSERT(rval == 0 || rval == SE_ENOMEM || rval == SE_EQSIZE ||
1756*7c478bd9Sstevel@tonic-gate 		rval == SE_NO_TRANSPORT);
1757*7c478bd9Sstevel@tonic-gate 	ASSERT(!(flag == SE_SLEEP && (rval == SE_EQSIZE || rval == SE_ENOMEM)));
1758*7c478bd9Sstevel@tonic-gate 	return (rval);
1759*7c478bd9Sstevel@tonic-gate }
1760*7c478bd9Sstevel@tonic-gate 
1761*7c478bd9Sstevel@tonic-gate /*
1762*7c478bd9Sstevel@tonic-gate  * log_usr_sysevent - user system event logger
1763*7c478bd9Sstevel@tonic-gate  *			Private to devfsadm and accessible only via
1764*7c478bd9Sstevel@tonic-gate  *			modctl(MODEVENTS, MODEVENTS_POST_EVENT)
1765*7c478bd9Sstevel@tonic-gate  */
1766*7c478bd9Sstevel@tonic-gate int
1767*7c478bd9Sstevel@tonic-gate log_usr_sysevent(sysevent_t *ev, int ev_size, sysevent_id_t *eid)
1768*7c478bd9Sstevel@tonic-gate {
1769*7c478bd9Sstevel@tonic-gate 	int ret, copy_sz;
1770*7c478bd9Sstevel@tonic-gate 	sysevent_t *ev_copy;
1771*7c478bd9Sstevel@tonic-gate 	sysevent_id_t new_eid;
1772*7c478bd9Sstevel@tonic-gate 	log_eventq_t *qcopy;
1773*7c478bd9Sstevel@tonic-gate 
1774*7c478bd9Sstevel@tonic-gate 	copy_sz = ev_size + offsetof(log_eventq_t, arg) +
1775*7c478bd9Sstevel@tonic-gate 		offsetof(log_event_upcall_arg_t, buf);
1776*7c478bd9Sstevel@tonic-gate 	qcopy = kmem_zalloc(copy_sz, KM_SLEEP);
1777*7c478bd9Sstevel@tonic-gate 	ev_copy = (sysevent_t *)&qcopy->arg.buf;
1778*7c478bd9Sstevel@tonic-gate 
1779*7c478bd9Sstevel@tonic-gate 	/*
1780*7c478bd9Sstevel@tonic-gate 	 * Copy event
1781*7c478bd9Sstevel@tonic-gate 	 */
1782*7c478bd9Sstevel@tonic-gate 	if (copyin(ev, ev_copy, ev_size) == -1) {
1783*7c478bd9Sstevel@tonic-gate 		kmem_free(qcopy, copy_sz);
1784*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1785*7c478bd9Sstevel@tonic-gate 	}
1786*7c478bd9Sstevel@tonic-gate 
1787*7c478bd9Sstevel@tonic-gate 	if ((ret = queue_sysevent(ev_copy, &new_eid, SE_NOSLEEP)) != 0) {
1788*7c478bd9Sstevel@tonic-gate 		if (ret == SE_ENOMEM || ret == SE_EQSIZE)
1789*7c478bd9Sstevel@tonic-gate 			return (EAGAIN);
1790*7c478bd9Sstevel@tonic-gate 		else
1791*7c478bd9Sstevel@tonic-gate 			return (EIO);
1792*7c478bd9Sstevel@tonic-gate 	}
1793*7c478bd9Sstevel@tonic-gate 
1794*7c478bd9Sstevel@tonic-gate 	if (copyout(&new_eid, eid, sizeof (sysevent_id_t)) == -1) {
1795*7c478bd9Sstevel@tonic-gate 		return (EFAULT);
1796*7c478bd9Sstevel@tonic-gate 	}
1797*7c478bd9Sstevel@tonic-gate 
1798*7c478bd9Sstevel@tonic-gate 	return (0);
1799*7c478bd9Sstevel@tonic-gate }
1800*7c478bd9Sstevel@tonic-gate 
1801*7c478bd9Sstevel@tonic-gate 
1802*7c478bd9Sstevel@tonic-gate 
1803*7c478bd9Sstevel@tonic-gate int
1804*7c478bd9Sstevel@tonic-gate ddi_log_sysevent(
1805*7c478bd9Sstevel@tonic-gate 	dev_info_t		*dip,
1806*7c478bd9Sstevel@tonic-gate 	char			*vendor,
1807*7c478bd9Sstevel@tonic-gate 	char			*class,
1808*7c478bd9Sstevel@tonic-gate 	char			*subclass,
1809*7c478bd9Sstevel@tonic-gate 	nvlist_t		*attr_list,
1810*7c478bd9Sstevel@tonic-gate 	sysevent_id_t		*eidp,
1811*7c478bd9Sstevel@tonic-gate 	int			sleep_flag)
1812*7c478bd9Sstevel@tonic-gate {
1813*7c478bd9Sstevel@tonic-gate 	sysevent_attr_list_t	*list = (sysevent_attr_list_t *)attr_list;
1814*7c478bd9Sstevel@tonic-gate 	char			pubstr[32];
1815*7c478bd9Sstevel@tonic-gate 	sysevent_t		*event;
1816*7c478bd9Sstevel@tonic-gate 	sysevent_id_t		eid;
1817*7c478bd9Sstevel@tonic-gate 	const char		*drvname;
1818*7c478bd9Sstevel@tonic-gate 	char			*publisher;
1819*7c478bd9Sstevel@tonic-gate 	int			se_flag;
1820*7c478bd9Sstevel@tonic-gate 	int			rval;
1821*7c478bd9Sstevel@tonic-gate 	int			n;
1822*7c478bd9Sstevel@tonic-gate 
1823*7c478bd9Sstevel@tonic-gate 	if (sleep_flag == DDI_SLEEP && servicing_interrupt()) {
1824*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!ddi_log_syevent: driver %s%d - cannot queue "
1825*7c478bd9Sstevel@tonic-gate 			"event from interrupt context with sleep semantics\n",
1826*7c478bd9Sstevel@tonic-gate 			ddi_driver_name(dip), ddi_get_instance(dip));
1827*7c478bd9Sstevel@tonic-gate 		return (DDI_ECONTEXT);
1828*7c478bd9Sstevel@tonic-gate 	}
1829*7c478bd9Sstevel@tonic-gate 
1830*7c478bd9Sstevel@tonic-gate 	drvname = ddi_driver_name(dip);
1831*7c478bd9Sstevel@tonic-gate 	n = strlen(vendor) + strlen(drvname) + 7;
1832*7c478bd9Sstevel@tonic-gate 	if (n < sizeof (pubstr)) {
1833*7c478bd9Sstevel@tonic-gate 		publisher = pubstr;
1834*7c478bd9Sstevel@tonic-gate 	} else {
1835*7c478bd9Sstevel@tonic-gate 		publisher = kmem_alloc(n,
1836*7c478bd9Sstevel@tonic-gate 			(sleep_flag == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
1837*7c478bd9Sstevel@tonic-gate 		if (publisher == NULL) {
1838*7c478bd9Sstevel@tonic-gate 			return (DDI_ENOMEM);
1839*7c478bd9Sstevel@tonic-gate 		}
1840*7c478bd9Sstevel@tonic-gate 	}
1841*7c478bd9Sstevel@tonic-gate 	(void) strcpy(publisher, vendor);
1842*7c478bd9Sstevel@tonic-gate 	(void) strcat(publisher, ":kern:");
1843*7c478bd9Sstevel@tonic-gate 	(void) strcat(publisher, drvname);
1844*7c478bd9Sstevel@tonic-gate 
1845*7c478bd9Sstevel@tonic-gate 	se_flag = (sleep_flag == DDI_SLEEP) ? SE_SLEEP : SE_NOSLEEP;
1846*7c478bd9Sstevel@tonic-gate 	event = sysevent_alloc(class, subclass, publisher, se_flag);
1847*7c478bd9Sstevel@tonic-gate 
1848*7c478bd9Sstevel@tonic-gate 	if (publisher != pubstr) {
1849*7c478bd9Sstevel@tonic-gate 		kmem_free(publisher, n);
1850*7c478bd9Sstevel@tonic-gate 	}
1851*7c478bd9Sstevel@tonic-gate 
1852*7c478bd9Sstevel@tonic-gate 	if (event == NULL) {
1853*7c478bd9Sstevel@tonic-gate 		return (DDI_ENOMEM);
1854*7c478bd9Sstevel@tonic-gate 	}
1855*7c478bd9Sstevel@tonic-gate 
1856*7c478bd9Sstevel@tonic-gate 	if (list) {
1857*7c478bd9Sstevel@tonic-gate 		(void) sysevent_attach_attributes(event, list);
1858*7c478bd9Sstevel@tonic-gate 	}
1859*7c478bd9Sstevel@tonic-gate 
1860*7c478bd9Sstevel@tonic-gate 	rval = log_sysevent(event, se_flag, &eid);
1861*7c478bd9Sstevel@tonic-gate 	if (list) {
1862*7c478bd9Sstevel@tonic-gate 		sysevent_detach_attributes(event);
1863*7c478bd9Sstevel@tonic-gate 	}
1864*7c478bd9Sstevel@tonic-gate 	sysevent_free(event);
1865*7c478bd9Sstevel@tonic-gate 	if (rval == 0) {
1866*7c478bd9Sstevel@tonic-gate 		if (eidp) {
1867*7c478bd9Sstevel@tonic-gate 			eidp->eid_seq = eid.eid_seq;
1868*7c478bd9Sstevel@tonic-gate 			eidp->eid_ts = eid.eid_ts;
1869*7c478bd9Sstevel@tonic-gate 		}
1870*7c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
1871*7c478bd9Sstevel@tonic-gate 	}
1872*7c478bd9Sstevel@tonic-gate 	if (rval == SE_NO_TRANSPORT)
1873*7c478bd9Sstevel@tonic-gate 		return (DDI_ETRANSPORT);
1874*7c478bd9Sstevel@tonic-gate 
1875*7c478bd9Sstevel@tonic-gate 	ASSERT(rval == SE_ENOMEM || rval == SE_EQSIZE);
1876*7c478bd9Sstevel@tonic-gate 	return ((rval == SE_ENOMEM) ? DDI_ENOMEM : DDI_EBUSY);
1877*7c478bd9Sstevel@tonic-gate }
1878*7c478bd9Sstevel@tonic-gate 
1879*7c478bd9Sstevel@tonic-gate uint64_t
1880*7c478bd9Sstevel@tonic-gate log_sysevent_new_id()
1881*7c478bd9Sstevel@tonic-gate {
1882*7c478bd9Sstevel@tonic-gate 	return (atomic_add_64_nv(&kernel_event_id, (uint64_t)1));
1883*7c478bd9Sstevel@tonic-gate }
1884