17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5e04145d0Seschrock  * Common Development and Distribution License (the "License").
6e04145d0Seschrock  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22f6e214c7SGavin Maltby  * Copyright (c) 2000, 2010, Oracle and/or its affiliates. All rights reserved.
23e5dc7eacSMarcel Telka  * Copyright 2013 Nexenta Systems, Inc.  All rights reserved.
24406fc510SToomas Soome  * Copyright 2016 Toomas Soome <tsoome@me.com>
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <sys/types.h>
287c478bd9Sstevel@tonic-gate #include <sys/errno.h>
297c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
307c478bd9Sstevel@tonic-gate #include <sys/debug.h>
317c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
327c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
337c478bd9Sstevel@tonic-gate #include <sys/vmem.h>
347c478bd9Sstevel@tonic-gate #include <sys/cmn_err.h>
357c478bd9Sstevel@tonic-gate #include <sys/callb.h>
367c478bd9Sstevel@tonic-gate #include <sys/sysevent.h>
377c478bd9Sstevel@tonic-gate #include <sys/sysevent_impl.h>
38406fc510SToomas Soome #include <sys/sysevent/dev.h>
397c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
408ae05c10SToomas Soome #include <sys/lofi_impl.h>
417c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
427c478bd9Sstevel@tonic-gate #include <sys/disp.h>
437c478bd9Sstevel@tonic-gate #include <sys/autoconf.h>
447c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
45e04145d0Seschrock #include <sys/sdt.h>
467c478bd9Sstevel@tonic-gate 
477c478bd9Sstevel@tonic-gate /* for doors */
487c478bd9Sstevel@tonic-gate #include <sys/pathname.h>
497c478bd9Sstevel@tonic-gate #include <sys/door.h>
507c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
517c478bd9Sstevel@tonic-gate #include <sys/cpuvar.h>
527c478bd9Sstevel@tonic-gate #include <sys/fs/snode.h>
537c478bd9Sstevel@tonic-gate 
547c478bd9Sstevel@tonic-gate /*
557c478bd9Sstevel@tonic-gate  * log_sysevent.c - Provides the interfaces for kernel event publication
567c478bd9Sstevel@tonic-gate  *			to the sysevent event daemon (syseventd).
577c478bd9Sstevel@tonic-gate  */
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate /*
607c478bd9Sstevel@tonic-gate  * Debug stuff
617c478bd9Sstevel@tonic-gate  */
627c478bd9Sstevel@tonic-gate static int log_event_debug = 0;
637c478bd9Sstevel@tonic-gate #define	LOG_DEBUG(args)  if (log_event_debug) cmn_err args
647c478bd9Sstevel@tonic-gate #ifdef DEBUG
657c478bd9Sstevel@tonic-gate #define	LOG_DEBUG1(args)  if (log_event_debug > 1) cmn_err args
667c478bd9Sstevel@tonic-gate #else
677c478bd9Sstevel@tonic-gate #define	LOG_DEBUG1(args)
687c478bd9Sstevel@tonic-gate #endif
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * Local static vars
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate /* queue of event buffers sent to syseventd */
747c478bd9Sstevel@tonic-gate static log_eventq_t *log_eventq_sent = NULL;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * Count of event buffers in the queue
787c478bd9Sstevel@tonic-gate  */
797c478bd9Sstevel@tonic-gate int log_eventq_cnt = 0;
807c478bd9Sstevel@tonic-gate 
817c478bd9Sstevel@tonic-gate /* queue of event buffers awaiting delivery to syseventd */
827c478bd9Sstevel@tonic-gate static log_eventq_t *log_eventq_head = NULL;
837c478bd9Sstevel@tonic-gate static log_eventq_t *log_eventq_tail = NULL;
847c478bd9Sstevel@tonic-gate static uint64_t kernel_event_id = 0;
857c478bd9Sstevel@tonic-gate static int encoding = NV_ENCODE_NATIVE;
867c478bd9Sstevel@tonic-gate 
877c478bd9Sstevel@tonic-gate /* log event delivery flag */
887c478bd9Sstevel@tonic-gate #define	LOGEVENT_DELIVERY_OK	0	/* OK to deliver event buffers */
897c478bd9Sstevel@tonic-gate #define	LOGEVENT_DELIVERY_CONT	1	/* Continue to deliver event buffers */
907c478bd9Sstevel@tonic-gate #define	LOGEVENT_DELIVERY_HOLD	2	/* Hold delivering of event buffers */
917c478bd9Sstevel@tonic-gate 
927c478bd9Sstevel@tonic-gate /*
937c478bd9Sstevel@tonic-gate  * Tunable maximum event buffer queue size. Size depends on how many events
947c478bd9Sstevel@tonic-gate  * the queue must hold when syseventd is not available, for example during
957c478bd9Sstevel@tonic-gate  * system startup. Experience showed that more than 2000 events could be posted
967c478bd9Sstevel@tonic-gate  * due to correctable memory errors.
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate int logevent_max_q_sz = 5000;
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate static int log_event_delivery = LOGEVENT_DELIVERY_HOLD;
102e5dc7eacSMarcel Telka static char logevent_door_upcall_filename[MAXPATHLEN];
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate static door_handle_t event_door = NULL;		/* Door for upcalls */
105e5dc7eacSMarcel Telka static kmutex_t event_door_mutex;		/* To protect event_door */
1067c478bd9Sstevel@tonic-gate 
1077c478bd9Sstevel@tonic-gate /*
1087c478bd9Sstevel@tonic-gate  * async thread-related variables
1097c478bd9Sstevel@tonic-gate  *
1107c478bd9Sstevel@tonic-gate  * eventq_head_mutex - synchronizes access to the kernel event queue
1117c478bd9Sstevel@tonic-gate  *
1127c478bd9Sstevel@tonic-gate  * eventq_sent_mutex - synchronizes access to the queue of event sents to
1137c478bd9Sstevel@tonic-gate  *			userlevel
1147c478bd9Sstevel@tonic-gate  *
1157c478bd9Sstevel@tonic-gate  * log_event_cv - condition variable signaled when an event has arrived or
1167c478bd9Sstevel@tonic-gate  *			userlevel ready to process event buffers
1177c478bd9Sstevel@tonic-gate  *
1187c478bd9Sstevel@tonic-gate  * async_thread - asynchronous event delivery thread to userlevel daemon.
1197c478bd9Sstevel@tonic-gate  *
1207c478bd9Sstevel@tonic-gate  * sysevent_upcall_status - status of the door upcall link
1217c478bd9Sstevel@tonic-gate  */
1227c478bd9Sstevel@tonic-gate static kmutex_t eventq_head_mutex;
1237c478bd9Sstevel@tonic-gate static kmutex_t eventq_sent_mutex;
1247c478bd9Sstevel@tonic-gate static kcondvar_t log_event_cv;
1257c478bd9Sstevel@tonic-gate static kthread_id_t async_thread = NULL;
1267c478bd9Sstevel@tonic-gate 
1277c478bd9Sstevel@tonic-gate static kmutex_t event_qfull_mutex;
1287c478bd9Sstevel@tonic-gate static kcondvar_t event_qfull_cv;
1297c478bd9Sstevel@tonic-gate static int event_qfull_blocked = 0;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate static int sysevent_upcall_status = -1;
1327c478bd9Sstevel@tonic-gate static kmutex_t registered_channel_mutex;
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate /*
1357c478bd9Sstevel@tonic-gate  * Indicates the syseventd daemon has begun taking events
1367c478bd9Sstevel@tonic-gate  */
1377c478bd9Sstevel@tonic-gate int sysevent_daemon_init = 0;
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate /*
1407c478bd9Sstevel@tonic-gate  * Back-off delay when door_ki_upcall returns EAGAIN.  Typically
1417c478bd9Sstevel@tonic-gate  * caused by the server process doing a forkall().  Since all threads
1427c478bd9Sstevel@tonic-gate  * but the thread actually doing the forkall() need to be quiesced,
1437c478bd9Sstevel@tonic-gate  * the fork may take some time.  The min/max pause are in units
1447c478bd9Sstevel@tonic-gate  * of clock ticks.
1457c478bd9Sstevel@tonic-gate  */
1467c478bd9Sstevel@tonic-gate #define	LOG_EVENT_MIN_PAUSE	8
1477c478bd9Sstevel@tonic-gate #define	LOG_EVENT_MAX_PAUSE	128
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate static kmutex_t	event_pause_mutex;
1507c478bd9Sstevel@tonic-gate static kcondvar_t event_pause_cv;
1517c478bd9Sstevel@tonic-gate static int event_pause_state = 0;
1527c478bd9Sstevel@tonic-gate 
1538ae05c10SToomas Soome /* Cached device links for lofi. */
1548ae05c10SToomas Soome lofi_nvl_t lofi_devlink_cache;
1558ae05c10SToomas Soome 
1567c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1577c478bd9Sstevel@tonic-gate static void
log_event_busy_timeout(void * arg)1587c478bd9Sstevel@tonic-gate log_event_busy_timeout(void *arg)
1597c478bd9Sstevel@tonic-gate {
1607c478bd9Sstevel@tonic-gate 	mutex_enter(&event_pause_mutex);
1617c478bd9Sstevel@tonic-gate 	event_pause_state = 0;
1627c478bd9Sstevel@tonic-gate 	cv_signal(&event_pause_cv);
1637c478bd9Sstevel@tonic-gate 	mutex_exit(&event_pause_mutex);
1647c478bd9Sstevel@tonic-gate }
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static void
log_event_pause(int nticks)1677c478bd9Sstevel@tonic-gate log_event_pause(int nticks)
1687c478bd9Sstevel@tonic-gate {
1697c478bd9Sstevel@tonic-gate 	timeout_id_t id;
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	/*
1727c478bd9Sstevel@tonic-gate 	 * Only one use of log_event_pause at a time
1737c478bd9Sstevel@tonic-gate 	 */
1747c478bd9Sstevel@tonic-gate 	ASSERT(event_pause_state == 0);
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 	event_pause_state = 1;
1777c478bd9Sstevel@tonic-gate 	id = timeout(log_event_busy_timeout, NULL, nticks);
1787c478bd9Sstevel@tonic-gate 	if (id != 0) {
1797c478bd9Sstevel@tonic-gate 		mutex_enter(&event_pause_mutex);
1807c478bd9Sstevel@tonic-gate 		while (event_pause_state)
1817c478bd9Sstevel@tonic-gate 			cv_wait(&event_pause_cv, &event_pause_mutex);
1827c478bd9Sstevel@tonic-gate 		mutex_exit(&event_pause_mutex);
1837c478bd9Sstevel@tonic-gate 	}
1847c478bd9Sstevel@tonic-gate 	event_pause_state = 0;
1857c478bd9Sstevel@tonic-gate }
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*
1897c478bd9Sstevel@tonic-gate  * log_event_upcall - Perform the upcall to syseventd for event buffer delivery.
1907c478bd9Sstevel@tonic-gate  * 			Check for rebinding errors
1917c478bd9Sstevel@tonic-gate  * 			This buffer is reused to by the syseventd door_return
1927c478bd9Sstevel@tonic-gate  *			to hold the result code
1937c478bd9Sstevel@tonic-gate  */
1947c478bd9Sstevel@tonic-gate static int
log_event_upcall(log_event_upcall_arg_t * arg)1957c478bd9Sstevel@tonic-gate log_event_upcall(log_event_upcall_arg_t *arg)
1967c478bd9Sstevel@tonic-gate {
1977c478bd9Sstevel@tonic-gate 	int error;
1987c478bd9Sstevel@tonic-gate 	size_t size;
1997c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
2007c478bd9Sstevel@tonic-gate 	door_arg_t darg, save_arg;
2017c478bd9Sstevel@tonic-gate 	int retry;
2027c478bd9Sstevel@tonic-gate 	int neagain = 0;
2037c478bd9Sstevel@tonic-gate 	int neintr = 0;
2047c478bd9Sstevel@tonic-gate 	int nticks = LOG_EVENT_MIN_PAUSE;
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate 	/* Initialize door args */
2077c478bd9Sstevel@tonic-gate 	ev = (sysevent_t *)&arg->buf;
2087c478bd9Sstevel@tonic-gate 	size = sizeof (log_event_upcall_arg_t) + SE_PAYLOAD_SZ(ev);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	darg.rbuf = (char *)arg;
2117c478bd9Sstevel@tonic-gate 	darg.data_ptr = (char *)arg;
2127c478bd9Sstevel@tonic-gate 	darg.rsize = size;
2137c478bd9Sstevel@tonic-gate 	darg.data_size = size;
2147c478bd9Sstevel@tonic-gate 	darg.desc_ptr = NULL;
2157c478bd9Sstevel@tonic-gate 	darg.desc_num = 0;
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	LOG_DEBUG1((CE_CONT, "log_event_upcall: 0x%llx\n",
2187c478bd9Sstevel@tonic-gate 	    (longlong_t)SE_SEQ((sysevent_t *)&arg->buf)));
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	save_arg = darg;
2217c478bd9Sstevel@tonic-gate 	for (retry = 0; ; retry++) {
222e5dc7eacSMarcel Telka 
223e5dc7eacSMarcel Telka 		mutex_enter(&event_door_mutex);
224e5dc7eacSMarcel Telka 		if (event_door == NULL) {
225e5dc7eacSMarcel Telka 			mutex_exit(&event_door_mutex);
226e5dc7eacSMarcel Telka 
227e5dc7eacSMarcel Telka 			return (EBADF);
228e5dc7eacSMarcel Telka 		}
229e5dc7eacSMarcel Telka 
230323a81d9Sjwadams 		if ((error = door_ki_upcall_limited(event_door, &darg, NULL,
231323a81d9Sjwadams 		    SIZE_MAX, 0)) == 0) {
232e5dc7eacSMarcel Telka 			mutex_exit(&event_door_mutex);
2337c478bd9Sstevel@tonic-gate 			break;
2347c478bd9Sstevel@tonic-gate 		}
235e5dc7eacSMarcel Telka 
236e5dc7eacSMarcel Telka 		/*
237e5dc7eacSMarcel Telka 		 * EBADF is handled outside the switch below because we need to
238e5dc7eacSMarcel Telka 		 * hold event_door_mutex a bit longer
239e5dc7eacSMarcel Telka 		 */
240e5dc7eacSMarcel Telka 		if (error == EBADF) {
241e5dc7eacSMarcel Telka 			/* Server died */
242e5dc7eacSMarcel Telka 			door_ki_rele(event_door);
243e5dc7eacSMarcel Telka 			event_door = NULL;
244e5dc7eacSMarcel Telka 
245e5dc7eacSMarcel Telka 			mutex_exit(&event_door_mutex);
246e5dc7eacSMarcel Telka 			return (error);
247e5dc7eacSMarcel Telka 		}
248e5dc7eacSMarcel Telka 
249e5dc7eacSMarcel Telka 		mutex_exit(&event_door_mutex);
250e5dc7eacSMarcel Telka 
251e5dc7eacSMarcel Telka 		/*
252e5dc7eacSMarcel Telka 		 * The EBADF case is already handled above with event_door_mutex
253e5dc7eacSMarcel Telka 		 * held
254e5dc7eacSMarcel Telka 		 */
2557c478bd9Sstevel@tonic-gate 		switch (error) {
2567c478bd9Sstevel@tonic-gate 		case EINTR:
2577c478bd9Sstevel@tonic-gate 			neintr++;
2587c478bd9Sstevel@tonic-gate 			log_event_pause(2);
2597c478bd9Sstevel@tonic-gate 			darg = save_arg;
2607c478bd9Sstevel@tonic-gate 			break;
2617c478bd9Sstevel@tonic-gate 		case EAGAIN:
2627c478bd9Sstevel@tonic-gate 			/* cannot deliver upcall - process may be forking */
2637c478bd9Sstevel@tonic-gate 			neagain++;
2647c478bd9Sstevel@tonic-gate 			log_event_pause(nticks);
2657c478bd9Sstevel@tonic-gate 			nticks <<= 1;
2667c478bd9Sstevel@tonic-gate 			if (nticks > LOG_EVENT_MAX_PAUSE)
2677c478bd9Sstevel@tonic-gate 				nticks = LOG_EVENT_MAX_PAUSE;
2687c478bd9Sstevel@tonic-gate 			darg = save_arg;
2697c478bd9Sstevel@tonic-gate 			break;
2707c478bd9Sstevel@tonic-gate 		default:
2717c478bd9Sstevel@tonic-gate 			cmn_err(CE_CONT,
2727c478bd9Sstevel@tonic-gate 			    "log_event_upcall: door_ki_upcall error %d\n",
2737c478bd9Sstevel@tonic-gate 			    error);
2747c478bd9Sstevel@tonic-gate 			return (error);
2757c478bd9Sstevel@tonic-gate 		}
2767c478bd9Sstevel@tonic-gate 	}
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	if (neagain > 0 || neintr > 0) {
2797c478bd9Sstevel@tonic-gate 		LOG_DEBUG((CE_CONT, "upcall: eagain=%d eintr=%d nticks=%d\n",
280f6e214c7SGavin Maltby 		    neagain, neintr, nticks));
2817c478bd9Sstevel@tonic-gate 	}
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	LOG_DEBUG1((CE_CONT, "log_event_upcall:\n\t"
284f6e214c7SGavin Maltby 	    "error=%d rptr1=%p rptr2=%p dptr2=%p ret1=%x ret2=%x\n",
285f6e214c7SGavin Maltby 	    error, (void *)arg, (void *)darg.rbuf,
286f6e214c7SGavin Maltby 	    (void *)darg.data_ptr,
287f6e214c7SGavin Maltby 	    *((int *)(darg.rbuf)), *((int *)(darg.data_ptr))));
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate 	if (!error) {
2907c478bd9Sstevel@tonic-gate 		/*
2917c478bd9Sstevel@tonic-gate 		 * upcall was successfully executed. Check return code.
2927c478bd9Sstevel@tonic-gate 		 */
2937c478bd9Sstevel@tonic-gate 		error = *((int *)(darg.rbuf));
2947c478bd9Sstevel@tonic-gate 	}
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	return (error);
2977c478bd9Sstevel@tonic-gate }
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate /*
3007c478bd9Sstevel@tonic-gate  * log_event_deliver - event delivery thread
3017c478bd9Sstevel@tonic-gate  *			Deliver all events on the event queue to syseventd.
3027c478bd9Sstevel@tonic-gate  *			If the daemon can not process events, stop event
3037c478bd9Sstevel@tonic-gate  *			delivery and wait for an indication from the
3047c478bd9Sstevel@tonic-gate  *			daemon to resume delivery.
3057c478bd9Sstevel@tonic-gate  *
3067c478bd9Sstevel@tonic-gate  *			Once all event buffers have been delivered, wait
3077c478bd9Sstevel@tonic-gate  *			until there are more to deliver.
3087c478bd9Sstevel@tonic-gate  */
3097c478bd9Sstevel@tonic-gate static void
log_event_deliver()3107c478bd9Sstevel@tonic-gate log_event_deliver()
3117c478bd9Sstevel@tonic-gate {
3127c478bd9Sstevel@tonic-gate 	log_eventq_t *q;
3137c478bd9Sstevel@tonic-gate 	int upcall_err;
3147c478bd9Sstevel@tonic-gate 	callb_cpr_t cprinfo;
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	CALLB_CPR_INIT(&cprinfo, &eventq_head_mutex, callb_generic_cpr,
317f6e214c7SGavin Maltby 	    "logevent");
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	/*
3207c478bd9Sstevel@tonic-gate 	 * eventq_head_mutex is exited (released) when there are no more
3217c478bd9Sstevel@tonic-gate 	 * events to process from the eventq in cv_wait().
3227c478bd9Sstevel@tonic-gate 	 */
3237c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_head_mutex);
3247c478bd9Sstevel@tonic-gate 
3257c478bd9Sstevel@tonic-gate 	for (;;) {
3267c478bd9Sstevel@tonic-gate 		LOG_DEBUG1((CE_CONT, "log_event_deliver: head = %p\n",
3277c478bd9Sstevel@tonic-gate 		    (void *)log_eventq_head));
3287c478bd9Sstevel@tonic-gate 
3297c478bd9Sstevel@tonic-gate 		upcall_err = 0;
3307c478bd9Sstevel@tonic-gate 		q = log_eventq_head;
3317c478bd9Sstevel@tonic-gate 
3327c478bd9Sstevel@tonic-gate 		while (q) {
3337c478bd9Sstevel@tonic-gate 			if (log_event_delivery == LOGEVENT_DELIVERY_HOLD) {
3347c478bd9Sstevel@tonic-gate 				upcall_err = EAGAIN;
3357c478bd9Sstevel@tonic-gate 				break;
3367c478bd9Sstevel@tonic-gate 			}
3377c478bd9Sstevel@tonic-gate 
338e5dc7eacSMarcel Telka 			log_event_delivery = LOGEVENT_DELIVERY_OK;
339e5dc7eacSMarcel Telka 
340e5dc7eacSMarcel Telka 			/*
341e5dc7eacSMarcel Telka 			 * Release event queue lock during upcall to
342e5dc7eacSMarcel Telka 			 * syseventd
343e5dc7eacSMarcel Telka 			 */
3447c478bd9Sstevel@tonic-gate 			mutex_exit(&eventq_head_mutex);
3457c478bd9Sstevel@tonic-gate 			if ((upcall_err = log_event_upcall(&q->arg)) != 0) {
3467c478bd9Sstevel@tonic-gate 				mutex_enter(&eventq_head_mutex);
3477c478bd9Sstevel@tonic-gate 				break;
3487c478bd9Sstevel@tonic-gate 			}
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 			/*
3517c478bd9Sstevel@tonic-gate 			 * We may be able to add entries to
3527c478bd9Sstevel@tonic-gate 			 * the queue now.
3537c478bd9Sstevel@tonic-gate 			 */
3547c478bd9Sstevel@tonic-gate 			if (event_qfull_blocked > 0 &&
3557c478bd9Sstevel@tonic-gate 			    log_eventq_cnt < logevent_max_q_sz) {
3567c478bd9Sstevel@tonic-gate 				mutex_enter(&event_qfull_mutex);
3577c478bd9Sstevel@tonic-gate 				if (event_qfull_blocked > 0) {
3587c478bd9Sstevel@tonic-gate 					cv_signal(&event_qfull_cv);
3597c478bd9Sstevel@tonic-gate 				}
3607c478bd9Sstevel@tonic-gate 				mutex_exit(&event_qfull_mutex);
3617c478bd9Sstevel@tonic-gate 			}
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 			mutex_enter(&eventq_head_mutex);
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 			/*
3667c478bd9Sstevel@tonic-gate 			 * Daemon restart can cause entries to be moved from
3677c478bd9Sstevel@tonic-gate 			 * the sent queue and put back on the event queue.
3687c478bd9Sstevel@tonic-gate 			 * If this has occurred, replay event queue
3697c478bd9Sstevel@tonic-gate 			 * processing from the new queue head.
3707c478bd9Sstevel@tonic-gate 			 */
3717c478bd9Sstevel@tonic-gate 			if (q != log_eventq_head) {
3727c478bd9Sstevel@tonic-gate 				q = log_eventq_head;
3737c478bd9Sstevel@tonic-gate 				LOG_DEBUG((CE_CONT, "log_event_deliver: "
3747c478bd9Sstevel@tonic-gate 				    "door upcall/daemon restart race\n"));
3757c478bd9Sstevel@tonic-gate 			} else {
376e5dc7eacSMarcel Telka 				log_eventq_t *next;
377e5dc7eacSMarcel Telka 
3787c478bd9Sstevel@tonic-gate 				/*
3797c478bd9Sstevel@tonic-gate 				 * Move the event to the sent queue when a
3807c478bd9Sstevel@tonic-gate 				 * successful delivery has been made.
3817c478bd9Sstevel@tonic-gate 				 */
3827c478bd9Sstevel@tonic-gate 				mutex_enter(&eventq_sent_mutex);
3837c478bd9Sstevel@tonic-gate 				next = q->next;
3847c478bd9Sstevel@tonic-gate 				q->next = log_eventq_sent;
3857c478bd9Sstevel@tonic-gate 				log_eventq_sent = q;
3867c478bd9Sstevel@tonic-gate 				q = next;
3877c478bd9Sstevel@tonic-gate 				log_eventq_head = q;
3887c478bd9Sstevel@tonic-gate 				log_eventq_cnt--;
3897c478bd9Sstevel@tonic-gate 				if (q == NULL) {
3907c478bd9Sstevel@tonic-gate 					ASSERT(log_eventq_cnt == 0);
3917c478bd9Sstevel@tonic-gate 					log_eventq_tail = NULL;
3927c478bd9Sstevel@tonic-gate 				}
3937c478bd9Sstevel@tonic-gate 				mutex_exit(&eventq_sent_mutex);
3947c478bd9Sstevel@tonic-gate 			}
3957c478bd9Sstevel@tonic-gate 		}
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate 		switch (upcall_err) {
3987c478bd9Sstevel@tonic-gate 		case 0:
3997c478bd9Sstevel@tonic-gate 			/*
4007c478bd9Sstevel@tonic-gate 			 * Success. The queue is empty.
4017c478bd9Sstevel@tonic-gate 			 */
4027c478bd9Sstevel@tonic-gate 			sysevent_upcall_status = 0;
4037c478bd9Sstevel@tonic-gate 			break;
4047c478bd9Sstevel@tonic-gate 		case EAGAIN:
4057c478bd9Sstevel@tonic-gate 			/*
4067c478bd9Sstevel@tonic-gate 			 * Delivery is on hold (but functional).
4077c478bd9Sstevel@tonic-gate 			 */
4087c478bd9Sstevel@tonic-gate 			sysevent_upcall_status = 0;
4097c478bd9Sstevel@tonic-gate 			/*
4107c478bd9Sstevel@tonic-gate 			 * If the user has already signaled for delivery
4117c478bd9Sstevel@tonic-gate 			 * resumption, continue.  Otherwise, we wait until
4127c478bd9Sstevel@tonic-gate 			 * we are signaled to continue.
4137c478bd9Sstevel@tonic-gate 			 */
414e5dc7eacSMarcel Telka 			if (log_event_delivery == LOGEVENT_DELIVERY_CONT)
4157c478bd9Sstevel@tonic-gate 				continue;
416e5dc7eacSMarcel Telka 			log_event_delivery = LOGEVENT_DELIVERY_HOLD;
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate 			LOG_DEBUG1((CE_CONT, "log_event_deliver: EAGAIN\n"));
4197c478bd9Sstevel@tonic-gate 			break;
4207c478bd9Sstevel@tonic-gate 		default:
4217c478bd9Sstevel@tonic-gate 			LOG_DEBUG((CE_CONT, "log_event_deliver: "
422f6e214c7SGavin Maltby 			    "upcall err %d\n", upcall_err));
4237c478bd9Sstevel@tonic-gate 			sysevent_upcall_status = upcall_err;
4247c478bd9Sstevel@tonic-gate 			/*
4257c478bd9Sstevel@tonic-gate 			 * Signal everyone waiting that transport is down
4267c478bd9Sstevel@tonic-gate 			 */
4277c478bd9Sstevel@tonic-gate 			if (event_qfull_blocked > 0) {
4287c478bd9Sstevel@tonic-gate 				mutex_enter(&event_qfull_mutex);
4297c478bd9Sstevel@tonic-gate 				if (event_qfull_blocked > 0) {
4307c478bd9Sstevel@tonic-gate 					cv_broadcast(&event_qfull_cv);
4317c478bd9Sstevel@tonic-gate 				}
4327c478bd9Sstevel@tonic-gate 				mutex_exit(&event_qfull_mutex);
4337c478bd9Sstevel@tonic-gate 			}
4347c478bd9Sstevel@tonic-gate 			break;
4357c478bd9Sstevel@tonic-gate 		}
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 		CALLB_CPR_SAFE_BEGIN(&cprinfo);
4387c478bd9Sstevel@tonic-gate 		cv_wait(&log_event_cv, &eventq_head_mutex);
4397c478bd9Sstevel@tonic-gate 		CALLB_CPR_SAFE_END(&cprinfo, &eventq_head_mutex);
4407c478bd9Sstevel@tonic-gate 	}
4417c478bd9Sstevel@tonic-gate 	/* NOTREACHED */
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate 
4448ae05c10SToomas Soome /*
4458ae05c10SToomas Soome  * Set up the nvlist based data cache. User by lofi to find
4468ae05c10SToomas Soome  * device name for mapped file.
4478ae05c10SToomas Soome  */
4488ae05c10SToomas Soome static void
lofi_nvl_init(lofi_nvl_t * cache)4498ae05c10SToomas Soome lofi_nvl_init(lofi_nvl_t *cache)
4508ae05c10SToomas Soome {
4518ae05c10SToomas Soome 	mutex_init(&cache->ln_lock, NULL, MUTEX_DRIVER, NULL);
4528ae05c10SToomas Soome 	cv_init(&cache->ln_cv, NULL, CV_DRIVER, NULL);
4538ae05c10SToomas Soome 	(void) nvlist_alloc(&cache->ln_data, NV_UNIQUE_NAME, KM_SLEEP);
4548ae05c10SToomas Soome }
4558ae05c10SToomas Soome 
4567c478bd9Sstevel@tonic-gate /*
4577c478bd9Sstevel@tonic-gate  * log_event_init - Allocate and initialize log_event data structures.
4587c478bd9Sstevel@tonic-gate  */
4597c478bd9Sstevel@tonic-gate void
log_event_init()4607c478bd9Sstevel@tonic-gate log_event_init()
4617c478bd9Sstevel@tonic-gate {
4628ae05c10SToomas Soome 	/* Set up devlink cache for lofi. */
4638ae05c10SToomas Soome 	lofi_nvl_init(&lofi_devlink_cache);
4648ae05c10SToomas Soome 
465e5dc7eacSMarcel Telka 	mutex_init(&event_door_mutex, NULL, MUTEX_DEFAULT, NULL);
466e5dc7eacSMarcel Telka 
4677c478bd9Sstevel@tonic-gate 	mutex_init(&eventq_head_mutex, NULL, MUTEX_DEFAULT, NULL);
4687c478bd9Sstevel@tonic-gate 	mutex_init(&eventq_sent_mutex, NULL, MUTEX_DEFAULT, NULL);
4697c478bd9Sstevel@tonic-gate 	cv_init(&log_event_cv, NULL, CV_DEFAULT, NULL);
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	mutex_init(&event_qfull_mutex, NULL, MUTEX_DEFAULT, NULL);
4727c478bd9Sstevel@tonic-gate 	cv_init(&event_qfull_cv, NULL, CV_DEFAULT, NULL);
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	mutex_init(&event_pause_mutex, NULL, MUTEX_DEFAULT, NULL);
4757c478bd9Sstevel@tonic-gate 	cv_init(&event_pause_cv, NULL, CV_DEFAULT, NULL);
4767c478bd9Sstevel@tonic-gate 
4777c478bd9Sstevel@tonic-gate 	mutex_init(&registered_channel_mutex, NULL, MUTEX_DEFAULT, NULL);
4787c478bd9Sstevel@tonic-gate 	sysevent_evc_init();
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate /*
4827c478bd9Sstevel@tonic-gate  * The following routines are used by kernel event publishers to
4837c478bd9Sstevel@tonic-gate  * allocate, append and free event buffers
4847c478bd9Sstevel@tonic-gate  */
4857c478bd9Sstevel@tonic-gate /*
4867c478bd9Sstevel@tonic-gate  * sysevent_alloc - Allocate new eventq struct.  This element contains
4877c478bd9Sstevel@tonic-gate  *			an event buffer that will be used in a subsequent
4887c478bd9Sstevel@tonic-gate  *			call to log_sysevent.
4897c478bd9Sstevel@tonic-gate  */
4907c478bd9Sstevel@tonic-gate sysevent_t *
sysevent_alloc(char * class,char * subclass,char * pub,int flag)4917c478bd9Sstevel@tonic-gate sysevent_alloc(char *class, char *subclass, char *pub, int flag)
4927c478bd9Sstevel@tonic-gate {
4937c478bd9Sstevel@tonic-gate 	int payload_sz;
4947c478bd9Sstevel@tonic-gate 	int class_sz, subclass_sz, pub_sz;
4957c478bd9Sstevel@tonic-gate 	int aligned_class_sz, aligned_subclass_sz, aligned_pub_sz;
4967c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
4977c478bd9Sstevel@tonic-gate 	log_eventq_t *q;
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate 	ASSERT(class != NULL);
5007c478bd9Sstevel@tonic-gate 	ASSERT(subclass != NULL);
5017c478bd9Sstevel@tonic-gate 	ASSERT(pub != NULL);
5027c478bd9Sstevel@tonic-gate 
5037c478bd9Sstevel@tonic-gate 	/*
5047c478bd9Sstevel@tonic-gate 	 * Calculate and reserve space for the class, subclass and
5057c478bd9Sstevel@tonic-gate 	 * publisher strings in the event buffer
5067c478bd9Sstevel@tonic-gate 	 */
5077c478bd9Sstevel@tonic-gate 	class_sz = strlen(class) + 1;
5087c478bd9Sstevel@tonic-gate 	subclass_sz = strlen(subclass) + 1;
5097c478bd9Sstevel@tonic-gate 	pub_sz = strlen(pub) + 1;
5107c478bd9Sstevel@tonic-gate 
5117c478bd9Sstevel@tonic-gate 	ASSERT((class_sz <= MAX_CLASS_LEN) && (subclass_sz
5127c478bd9Sstevel@tonic-gate 	    <= MAX_SUBCLASS_LEN) && (pub_sz <= MAX_PUB_LEN));
5137c478bd9Sstevel@tonic-gate 
5147c478bd9Sstevel@tonic-gate 	/* String sizes must be 64-bit aligned in the event buffer */
5157c478bd9Sstevel@tonic-gate 	aligned_class_sz = SE_ALIGN(class_sz);
5167c478bd9Sstevel@tonic-gate 	aligned_subclass_sz = SE_ALIGN(subclass_sz);
5177c478bd9Sstevel@tonic-gate 	aligned_pub_sz = SE_ALIGN(pub_sz);
5187c478bd9Sstevel@tonic-gate 
5197c478bd9Sstevel@tonic-gate 	payload_sz = (aligned_class_sz - sizeof (uint64_t)) +
520f6e214c7SGavin Maltby 	    (aligned_subclass_sz - sizeof (uint64_t)) +
521f6e214c7SGavin Maltby 	    (aligned_pub_sz - sizeof (uint64_t)) - sizeof (uint64_t);
5227c478bd9Sstevel@tonic-gate 
5237c478bd9Sstevel@tonic-gate 	/*
5247c478bd9Sstevel@tonic-gate 	 * Allocate event buffer plus additional sysevent queue
5257c478bd9Sstevel@tonic-gate 	 * and payload overhead.
5267c478bd9Sstevel@tonic-gate 	 */
5277c478bd9Sstevel@tonic-gate 	q = kmem_zalloc(sizeof (log_eventq_t) + payload_sz, flag);
5287c478bd9Sstevel@tonic-gate 	if (q == NULL) {
5297c478bd9Sstevel@tonic-gate 		return (NULL);
5307c478bd9Sstevel@tonic-gate 	}
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	/* Initialize the event buffer data */
5337c478bd9Sstevel@tonic-gate 	ev = (sysevent_t *)&q->arg.buf;
5347c478bd9Sstevel@tonic-gate 	SE_VERSION(ev) = SYS_EVENT_VERSION;
5357c478bd9Sstevel@tonic-gate 	bcopy(class, SE_CLASS_NAME(ev), class_sz);
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	SE_SUBCLASS_OFF(ev) = SE_ALIGN(offsetof(sysevent_impl_t, se_class_name))
5387c478bd9Sstevel@tonic-gate 		+ aligned_class_sz;
5397c478bd9Sstevel@tonic-gate 	bcopy(subclass, SE_SUBCLASS_NAME(ev), subclass_sz);
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 	SE_PUB_OFF(ev) = SE_SUBCLASS_OFF(ev) + aligned_subclass_sz;
5427c478bd9Sstevel@tonic-gate 	bcopy(pub, SE_PUB_NAME(ev), pub_sz);
5437c478bd9Sstevel@tonic-gate 
5447c478bd9Sstevel@tonic-gate 	SE_ATTR_PTR(ev) = UINT64_C(0);
5457c478bd9Sstevel@tonic-gate 	SE_PAYLOAD_SZ(ev) = payload_sz;
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	return (ev);
5487c478bd9Sstevel@tonic-gate }
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate /*
5517c478bd9Sstevel@tonic-gate  * sysevent_free - Free event buffer and any attribute data.
5527c478bd9Sstevel@tonic-gate  */
5537c478bd9Sstevel@tonic-gate void
sysevent_free(sysevent_t * ev)5547c478bd9Sstevel@tonic-gate sysevent_free(sysevent_t *ev)
5557c478bd9Sstevel@tonic-gate {
5567c478bd9Sstevel@tonic-gate 	log_eventq_t *q;
5577c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	ASSERT(ev != NULL);
5607c478bd9Sstevel@tonic-gate 	q = (log_eventq_t *)((caddr_t)ev - offsetof(log_eventq_t, arg.buf));
5617c478bd9Sstevel@tonic-gate 	nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev);
5627c478bd9Sstevel@tonic-gate 
5637c478bd9Sstevel@tonic-gate 	if (nvl != NULL) {
5647c478bd9Sstevel@tonic-gate 		size_t size = 0;
5657c478bd9Sstevel@tonic-gate 		(void) nvlist_size(nvl, &size, encoding);
5667c478bd9Sstevel@tonic-gate 		SE_PAYLOAD_SZ(ev) -= size;
5677c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
5687c478bd9Sstevel@tonic-gate 	}
5697c478bd9Sstevel@tonic-gate 	kmem_free(q, sizeof (log_eventq_t) + SE_PAYLOAD_SZ(ev));
5707c478bd9Sstevel@tonic-gate }
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate /*
5737c478bd9Sstevel@tonic-gate  * free_packed_event - Free packed event buffer
5747c478bd9Sstevel@tonic-gate  */
5757c478bd9Sstevel@tonic-gate static void
free_packed_event(sysevent_t * ev)5767c478bd9Sstevel@tonic-gate free_packed_event(sysevent_t *ev)
5777c478bd9Sstevel@tonic-gate {
5787c478bd9Sstevel@tonic-gate 	log_eventq_t *q;
5797c478bd9Sstevel@tonic-gate 
5807c478bd9Sstevel@tonic-gate 	ASSERT(ev != NULL);
5817c478bd9Sstevel@tonic-gate 	q = (log_eventq_t *)((caddr_t)ev - offsetof(log_eventq_t, arg.buf));
5827c478bd9Sstevel@tonic-gate 
5837c478bd9Sstevel@tonic-gate 	kmem_free(q, sizeof (log_eventq_t) + SE_PAYLOAD_SZ(ev));
5847c478bd9Sstevel@tonic-gate }
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate /*
5877c478bd9Sstevel@tonic-gate  * sysevent_add_attr - Add new attribute element to an event attribute list
5887c478bd9Sstevel@tonic-gate  *			If attribute list is NULL, start a new list.
5897c478bd9Sstevel@tonic-gate  */
5907c478bd9Sstevel@tonic-gate int
sysevent_add_attr(sysevent_attr_list_t ** ev_attr_list,char * name,sysevent_value_t * se_value,int flag)5917c478bd9Sstevel@tonic-gate sysevent_add_attr(sysevent_attr_list_t **ev_attr_list, char *name,
592406fc510SToomas Soome     sysevent_value_t *se_value, int flag)
5937c478bd9Sstevel@tonic-gate {
5947c478bd9Sstevel@tonic-gate 	int error;
5957c478bd9Sstevel@tonic-gate 	nvlist_t **nvlp = (nvlist_t **)ev_attr_list;
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	if (nvlp == NULL || se_value == NULL) {
5987c478bd9Sstevel@tonic-gate 		return (SE_EINVAL);
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	/*
6027c478bd9Sstevel@tonic-gate 	 * attr_sz is composed of the value data size + the name data size +
6037c478bd9Sstevel@tonic-gate 	 * any header data.  64-bit aligned.
6047c478bd9Sstevel@tonic-gate 	 */
6057c478bd9Sstevel@tonic-gate 	if (strlen(name) >= MAX_ATTR_NAME) {
6067c478bd9Sstevel@tonic-gate 		return (SE_EINVAL);
6077c478bd9Sstevel@tonic-gate 	}
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate 	/*
6107c478bd9Sstevel@tonic-gate 	 * Allocate nvlist
6117c478bd9Sstevel@tonic-gate 	 */
6127c478bd9Sstevel@tonic-gate 	if ((*nvlp == NULL) &&
6137c478bd9Sstevel@tonic-gate 	    (nvlist_alloc(nvlp, NV_UNIQUE_NAME_TYPE, flag) != 0))
6147c478bd9Sstevel@tonic-gate 		return (SE_ENOMEM);
6157c478bd9Sstevel@tonic-gate 
6167c478bd9Sstevel@tonic-gate 	/* add the attribute */
6177c478bd9Sstevel@tonic-gate 	switch (se_value->value_type) {
6187c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_BYTE:
6197c478bd9Sstevel@tonic-gate 		error = nvlist_add_byte(*ev_attr_list, name,
6207c478bd9Sstevel@tonic-gate 		    se_value->value.sv_byte);
6217c478bd9Sstevel@tonic-gate 		break;
6227c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_INT16:
6237c478bd9Sstevel@tonic-gate 		error = nvlist_add_int16(*ev_attr_list, name,
6247c478bd9Sstevel@tonic-gate 		    se_value->value.sv_int16);
6257c478bd9Sstevel@tonic-gate 		break;
6267c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_UINT16:
6277c478bd9Sstevel@tonic-gate 		error = nvlist_add_uint16(*ev_attr_list, name,
6287c478bd9Sstevel@tonic-gate 		    se_value->value.sv_uint16);
6297c478bd9Sstevel@tonic-gate 		break;
6307c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_INT32:
6317c478bd9Sstevel@tonic-gate 		error = nvlist_add_int32(*ev_attr_list, name,
6327c478bd9Sstevel@tonic-gate 		    se_value->value.sv_int32);
6337c478bd9Sstevel@tonic-gate 		break;
6347c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_UINT32:
6357c478bd9Sstevel@tonic-gate 		error = nvlist_add_uint32(*ev_attr_list, name,
6367c478bd9Sstevel@tonic-gate 		    se_value->value.sv_uint32);
6377c478bd9Sstevel@tonic-gate 		break;
6387c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_INT64:
6397c478bd9Sstevel@tonic-gate 		error = nvlist_add_int64(*ev_attr_list, name,
6407c478bd9Sstevel@tonic-gate 		    se_value->value.sv_int64);
6417c478bd9Sstevel@tonic-gate 		break;
6427c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_UINT64:
6437c478bd9Sstevel@tonic-gate 		error = nvlist_add_uint64(*ev_attr_list, name,
6447c478bd9Sstevel@tonic-gate 		    se_value->value.sv_uint64);
6457c478bd9Sstevel@tonic-gate 		break;
6467c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_STRING:
6477c478bd9Sstevel@tonic-gate 		if (strlen((char *)se_value->value.sv_string) >= MAX_STRING_SZ)
6487c478bd9Sstevel@tonic-gate 			return (SE_EINVAL);
6497c478bd9Sstevel@tonic-gate 		error = nvlist_add_string(*ev_attr_list, name,
6507c478bd9Sstevel@tonic-gate 		    se_value->value.sv_string);
6517c478bd9Sstevel@tonic-gate 		break;
6527c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_BYTES:
6537c478bd9Sstevel@tonic-gate 		if (se_value->value.sv_bytes.size > MAX_BYTE_ARRAY)
6547c478bd9Sstevel@tonic-gate 			return (SE_EINVAL);
6557c478bd9Sstevel@tonic-gate 		error = nvlist_add_byte_array(*ev_attr_list, name,
6567c478bd9Sstevel@tonic-gate 		    se_value->value.sv_bytes.data,
6577c478bd9Sstevel@tonic-gate 		    se_value->value.sv_bytes.size);
6587c478bd9Sstevel@tonic-gate 		break;
6597c478bd9Sstevel@tonic-gate 	case SE_DATA_TYPE_TIME:
6607c478bd9Sstevel@tonic-gate 		error = nvlist_add_hrtime(*ev_attr_list, name,
6617c478bd9Sstevel@tonic-gate 		    se_value->value.sv_time);
6627c478bd9Sstevel@tonic-gate 		break;
6637c478bd9Sstevel@tonic-gate 	default:
6647c478bd9Sstevel@tonic-gate 		return (SE_EINVAL);
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	return (error ? SE_ENOMEM : 0);
6687c478bd9Sstevel@tonic-gate }
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate /*
6717c478bd9Sstevel@tonic-gate  * sysevent_free_attr - Free an attribute list not associated with an
6727c478bd9Sstevel@tonic-gate  *			event buffer.
6737c478bd9Sstevel@tonic-gate  */
6747c478bd9Sstevel@tonic-gate void
sysevent_free_attr(sysevent_attr_list_t * ev_attr_list)6757c478bd9Sstevel@tonic-gate sysevent_free_attr(sysevent_attr_list_t *ev_attr_list)
6767c478bd9Sstevel@tonic-gate {
6777c478bd9Sstevel@tonic-gate 	nvlist_free((nvlist_t *)ev_attr_list);
6787c478bd9Sstevel@tonic-gate }
6797c478bd9Sstevel@tonic-gate 
6807c478bd9Sstevel@tonic-gate /*
6817c478bd9Sstevel@tonic-gate  * sysevent_attach_attributes - Attach an attribute list to an event buffer.
6827c478bd9Sstevel@tonic-gate  *
6837c478bd9Sstevel@tonic-gate  *	This data will be re-packed into contiguous memory when the event
6847c478bd9Sstevel@tonic-gate  *	buffer is posted to log_sysevent.
6857c478bd9Sstevel@tonic-gate  */
6867c478bd9Sstevel@tonic-gate int
sysevent_attach_attributes(sysevent_t * ev,sysevent_attr_list_t * ev_attr_list)6877c478bd9Sstevel@tonic-gate sysevent_attach_attributes(sysevent_t *ev, sysevent_attr_list_t *ev_attr_list)
6887c478bd9Sstevel@tonic-gate {
6897c478bd9Sstevel@tonic-gate 	size_t size = 0;
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	if (SE_ATTR_PTR(ev) != UINT64_C(0)) {
6927c478bd9Sstevel@tonic-gate 		return (SE_EINVAL);
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	SE_ATTR_PTR(ev) = (uintptr_t)ev_attr_list;
6967c478bd9Sstevel@tonic-gate 	(void) nvlist_size((nvlist_t *)ev_attr_list, &size, encoding);
6977c478bd9Sstevel@tonic-gate 	SE_PAYLOAD_SZ(ev) += size;
6987c478bd9Sstevel@tonic-gate 	SE_FLAG(ev) = 0;
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	return (0);
7017c478bd9Sstevel@tonic-gate }
7027c478bd9Sstevel@tonic-gate 
7037c478bd9Sstevel@tonic-gate /*
7047c478bd9Sstevel@tonic-gate  * sysevent_detach_attributes - Detach but don't free attribute list from the
7057c478bd9Sstevel@tonic-gate  *				event buffer.
7067c478bd9Sstevel@tonic-gate  */
7077c478bd9Sstevel@tonic-gate void
sysevent_detach_attributes(sysevent_t * ev)7087c478bd9Sstevel@tonic-gate sysevent_detach_attributes(sysevent_t *ev)
7097c478bd9Sstevel@tonic-gate {
7107c478bd9Sstevel@tonic-gate 	size_t size = 0;
7117c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate 	if ((nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev)) == NULL) {
7147c478bd9Sstevel@tonic-gate 		return;
7157c478bd9Sstevel@tonic-gate 	}
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate 	SE_ATTR_PTR(ev) = UINT64_C(0);
7187c478bd9Sstevel@tonic-gate 	(void) nvlist_size(nvl, &size, encoding);
7197c478bd9Sstevel@tonic-gate 	SE_PAYLOAD_SZ(ev) -= size;
7207c478bd9Sstevel@tonic-gate 	ASSERT(SE_PAYLOAD_SZ(ev) >= 0);
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate /*
7247c478bd9Sstevel@tonic-gate  * sysevent_attr_name - Get name of attribute
7257c478bd9Sstevel@tonic-gate  */
7267c478bd9Sstevel@tonic-gate char *
sysevent_attr_name(sysevent_attr_t * attr)7277c478bd9Sstevel@tonic-gate sysevent_attr_name(sysevent_attr_t *attr)
7287c478bd9Sstevel@tonic-gate {
7297c478bd9Sstevel@tonic-gate 	if (attr == NULL) {
7307c478bd9Sstevel@tonic-gate 		return (NULL);
7317c478bd9Sstevel@tonic-gate 	}
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	return (nvpair_name(attr));
7347c478bd9Sstevel@tonic-gate }
7357c478bd9Sstevel@tonic-gate 
7367c478bd9Sstevel@tonic-gate /*
7377c478bd9Sstevel@tonic-gate  * sysevent_attr_type - Get type of attribute
7387c478bd9Sstevel@tonic-gate  */
7397c478bd9Sstevel@tonic-gate int
sysevent_attr_type(sysevent_attr_t * attr)7407c478bd9Sstevel@tonic-gate sysevent_attr_type(sysevent_attr_t *attr)
7417c478bd9Sstevel@tonic-gate {
7427c478bd9Sstevel@tonic-gate 	/*
7437c478bd9Sstevel@tonic-gate 	 * The SE_DATA_TYPE_* are typedef'ed to be the
7447c478bd9Sstevel@tonic-gate 	 * same value as DATA_TYPE_*
7457c478bd9Sstevel@tonic-gate 	 */
7467c478bd9Sstevel@tonic-gate 	return (nvpair_type((nvpair_t *)attr));
7477c478bd9Sstevel@tonic-gate }
7487c478bd9Sstevel@tonic-gate 
7497c478bd9Sstevel@tonic-gate /*
7507c478bd9Sstevel@tonic-gate  * Repack event buffer into contiguous memory
7517c478bd9Sstevel@tonic-gate  */
7527c478bd9Sstevel@tonic-gate static sysevent_t *
se_repack(sysevent_t * ev,int flag)7537c478bd9Sstevel@tonic-gate se_repack(sysevent_t *ev, int flag)
7547c478bd9Sstevel@tonic-gate {
7557c478bd9Sstevel@tonic-gate 	size_t copy_len;
7567c478bd9Sstevel@tonic-gate 	caddr_t attr;
7577c478bd9Sstevel@tonic-gate 	size_t size;
7587c478bd9Sstevel@tonic-gate 	uint64_t attr_offset;
7597c478bd9Sstevel@tonic-gate 	sysevent_t *copy;
7607c478bd9Sstevel@tonic-gate 	log_eventq_t *qcopy;
7617c478bd9Sstevel@tonic-gate 	sysevent_attr_list_t *nvl;
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	copy_len = sizeof (log_eventq_t) + SE_PAYLOAD_SZ(ev);
7647c478bd9Sstevel@tonic-gate 	qcopy = kmem_zalloc(copy_len, flag);
7657c478bd9Sstevel@tonic-gate 	if (qcopy == NULL) {
7667c478bd9Sstevel@tonic-gate 		return (NULL);
7677c478bd9Sstevel@tonic-gate 	}
7687c478bd9Sstevel@tonic-gate 	copy = (sysevent_t *)&qcopy->arg.buf;
7697c478bd9Sstevel@tonic-gate 
7707c478bd9Sstevel@tonic-gate 	/*
7717c478bd9Sstevel@tonic-gate 	 * Copy event header, class, subclass and publisher names
7727c478bd9Sstevel@tonic-gate 	 * Set the attribute offset (in number of bytes) to contiguous
7737c478bd9Sstevel@tonic-gate 	 * memory after the header.
7747c478bd9Sstevel@tonic-gate 	 */
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	attr_offset = SE_ATTR_OFF(ev);
7777c478bd9Sstevel@tonic-gate 
7787c478bd9Sstevel@tonic-gate 	ASSERT((caddr_t)copy + attr_offset <= (caddr_t)copy + copy_len);
7797c478bd9Sstevel@tonic-gate 
7807c478bd9Sstevel@tonic-gate 	bcopy(ev, copy, attr_offset);
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate 	/* Check if attribute list exists */
7837c478bd9Sstevel@tonic-gate 	if ((nvl = (nvlist_t *)(uintptr_t)SE_ATTR_PTR(ev)) == NULL) {
7847c478bd9Sstevel@tonic-gate 		return (copy);
7857c478bd9Sstevel@tonic-gate 	}
7867c478bd9Sstevel@tonic-gate 
7877c478bd9Sstevel@tonic-gate 	/*
7887c478bd9Sstevel@tonic-gate 	 * Copy attribute data to contiguous memory
7897c478bd9Sstevel@tonic-gate 	 */
7907c478bd9Sstevel@tonic-gate 	attr = (char *)copy + attr_offset;
7917c478bd9Sstevel@tonic-gate 	(void) nvlist_size(nvl, &size, encoding);
7927c478bd9Sstevel@tonic-gate 	if (nvlist_pack(nvl, &attr, &size, encoding, flag) != 0) {
7937c478bd9Sstevel@tonic-gate 		kmem_free(qcopy, copy_len);
7947c478bd9Sstevel@tonic-gate 		return (NULL);
7957c478bd9Sstevel@tonic-gate 	}
7967c478bd9Sstevel@tonic-gate 	SE_ATTR_PTR(copy) = UINT64_C(0);
7977c478bd9Sstevel@tonic-gate 	SE_FLAG(copy) = SE_PACKED_BUF;
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	return (copy);
8007c478bd9Sstevel@tonic-gate }
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate /*
8037c478bd9Sstevel@tonic-gate  * The sysevent registration provides a persistent and reliable database
8047c478bd9Sstevel@tonic-gate  * for channel information for sysevent channel publishers and
8057c478bd9Sstevel@tonic-gate  * subscribers.
8067c478bd9Sstevel@tonic-gate  *
8077c478bd9Sstevel@tonic-gate  * A channel is created and maintained by the kernel upon the first
8087c478bd9Sstevel@tonic-gate  * SE_OPEN_REGISTRATION operation to log_sysevent_register().  Channel
8097c478bd9Sstevel@tonic-gate  * event subscription information is updated as publishers or subscribers
8107c478bd9Sstevel@tonic-gate  * perform subsequent operations (SE_BIND_REGISTRATION, SE_REGISTER,
8117c478bd9Sstevel@tonic-gate  * SE_UNREGISTER and SE_UNBIND_REGISTRATION).
8127c478bd9Sstevel@tonic-gate  *
8137c478bd9Sstevel@tonic-gate  * For consistency, id's are assigned for every publisher or subscriber
8147c478bd9Sstevel@tonic-gate  * bound to a particular channel.  The id's are used to constrain resources
8157c478bd9Sstevel@tonic-gate  * and perform subscription lookup.
8167c478bd9Sstevel@tonic-gate  *
8177c478bd9Sstevel@tonic-gate  * Associated with each channel is a hashed list of the current subscriptions
8187c478bd9Sstevel@tonic-gate  * based upon event class and subclasses.  A subscription contains a class name,
8197c478bd9Sstevel@tonic-gate  * list of possible subclasses and an array of subscriber ids.  Subscriptions
8207c478bd9Sstevel@tonic-gate  * are updated for every SE_REGISTER or SE_UNREGISTER operation.
8217c478bd9Sstevel@tonic-gate  *
8227c478bd9Sstevel@tonic-gate  * Channels are closed once the last subscriber or publisher performs a
8237c478bd9Sstevel@tonic-gate  * SE_CLOSE_REGISTRATION operation.  All resources associated with the named
8247c478bd9Sstevel@tonic-gate  * channel are freed upon last close.
8257c478bd9Sstevel@tonic-gate  *
8267c478bd9Sstevel@tonic-gate  * Locking:
8277c478bd9Sstevel@tonic-gate  *	Every operation to log_sysevent() is protected by a single lock,
8287c478bd9Sstevel@tonic-gate  *	registered_channel_mutex.  It is expected that the granularity of
8297c478bd9Sstevel@tonic-gate  *	a single lock is sufficient given the frequency that updates will
8307c478bd9Sstevel@tonic-gate  *	occur.
8317c478bd9Sstevel@tonic-gate  *
8327c478bd9Sstevel@tonic-gate  *	If this locking strategy proves to be too contentious, a per-hash
8337c478bd9Sstevel@tonic-gate  *	or per-channel locking strategy may be implemented.
8347c478bd9Sstevel@tonic-gate  */
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 
8377c478bd9Sstevel@tonic-gate #define	CHANN_HASH(channel_name)	(hash_func(channel_name) \
8387c478bd9Sstevel@tonic-gate 					% CHAN_HASH_SZ)
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate sysevent_channel_descriptor_t *registered_channels[CHAN_HASH_SZ];
8417c478bd9Sstevel@tonic-gate static int channel_cnt;
8427c478bd9Sstevel@tonic-gate static void remove_all_class(sysevent_channel_descriptor_t *chan,
8437c478bd9Sstevel@tonic-gate 	uint32_t sub_id);
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate static uint32_t
hash_func(const char * s)8467c478bd9Sstevel@tonic-gate hash_func(const char *s)
8477c478bd9Sstevel@tonic-gate {
8487c478bd9Sstevel@tonic-gate 	uint32_t result = 0;
8497c478bd9Sstevel@tonic-gate 	uint_t g;
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 	while (*s != '\0') {
8527c478bd9Sstevel@tonic-gate 		result <<= 4;
8537c478bd9Sstevel@tonic-gate 		result += (uint32_t)*s++;
8547c478bd9Sstevel@tonic-gate 		g = result & 0xf0000000;
8557c478bd9Sstevel@tonic-gate 		if (g != 0) {
8567c478bd9Sstevel@tonic-gate 			result ^= g >> 24;
8577c478bd9Sstevel@tonic-gate 			result ^= g;
8587c478bd9Sstevel@tonic-gate 		}
8597c478bd9Sstevel@tonic-gate 	}
8607c478bd9Sstevel@tonic-gate 
8617c478bd9Sstevel@tonic-gate 	return (result);
8627c478bd9Sstevel@tonic-gate }
8637c478bd9Sstevel@tonic-gate 
8647c478bd9Sstevel@tonic-gate static sysevent_channel_descriptor_t *
get_channel(char * channel_name)8657c478bd9Sstevel@tonic-gate get_channel(char *channel_name)
8667c478bd9Sstevel@tonic-gate {
8677c478bd9Sstevel@tonic-gate 	int hash_index;
8687c478bd9Sstevel@tonic-gate 	sysevent_channel_descriptor_t *chan_list;
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate 	if (channel_name == NULL)
8717c478bd9Sstevel@tonic-gate 		return (NULL);
8727c478bd9Sstevel@tonic-gate 
8737c478bd9Sstevel@tonic-gate 	/* Find channel descriptor */
8747c478bd9Sstevel@tonic-gate 	hash_index = CHANN_HASH(channel_name);
8757c478bd9Sstevel@tonic-gate 	chan_list = registered_channels[hash_index];
8767c478bd9Sstevel@tonic-gate 	while (chan_list != NULL) {
8777c478bd9Sstevel@tonic-gate 		if (strcmp(chan_list->scd_channel_name, channel_name) == 0) {
8787c478bd9Sstevel@tonic-gate 			break;
8797c478bd9Sstevel@tonic-gate 		} else {
8807c478bd9Sstevel@tonic-gate 			chan_list = chan_list->scd_next;
8817c478bd9Sstevel@tonic-gate 		}
8827c478bd9Sstevel@tonic-gate 	}
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	return (chan_list);
8857c478bd9Sstevel@tonic-gate }
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate static class_lst_t *
create_channel_registration(sysevent_channel_descriptor_t * chan,char * event_class,int index)8887c478bd9Sstevel@tonic-gate create_channel_registration(sysevent_channel_descriptor_t *chan,
8897c478bd9Sstevel@tonic-gate     char *event_class, int index)
8907c478bd9Sstevel@tonic-gate {
8917c478bd9Sstevel@tonic-gate 	size_t class_len;
8927c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	class_len = strlen(event_class) + 1;
8957c478bd9Sstevel@tonic-gate 	c_list = kmem_zalloc(sizeof (class_lst_t), KM_SLEEP);
8967c478bd9Sstevel@tonic-gate 	c_list->cl_name = kmem_zalloc(class_len, KM_SLEEP);
8977c478bd9Sstevel@tonic-gate 	bcopy(event_class, c_list->cl_name, class_len);
8987c478bd9Sstevel@tonic-gate 
8997c478bd9Sstevel@tonic-gate 	c_list->cl_subclass_list =
9007c478bd9Sstevel@tonic-gate 	    kmem_zalloc(sizeof (subclass_lst_t), KM_SLEEP);
9017c478bd9Sstevel@tonic-gate 	c_list->cl_subclass_list->sl_name =
9027c478bd9Sstevel@tonic-gate 	    kmem_zalloc(sizeof (EC_SUB_ALL), KM_SLEEP);
9037c478bd9Sstevel@tonic-gate 	bcopy(EC_SUB_ALL, c_list->cl_subclass_list->sl_name,
9047c478bd9Sstevel@tonic-gate 	    sizeof (EC_SUB_ALL));
9057c478bd9Sstevel@tonic-gate 
9067c478bd9Sstevel@tonic-gate 	c_list->cl_next = chan->scd_class_list_tbl[index];
9077c478bd9Sstevel@tonic-gate 	chan->scd_class_list_tbl[index] = c_list;
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	return (c_list);
9107c478bd9Sstevel@tonic-gate }
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate static void
free_channel_registration(sysevent_channel_descriptor_t * chan)9137c478bd9Sstevel@tonic-gate free_channel_registration(sysevent_channel_descriptor_t *chan)
9147c478bd9Sstevel@tonic-gate {
9157c478bd9Sstevel@tonic-gate 	int i;
9167c478bd9Sstevel@tonic-gate 	class_lst_t *clist, *next_clist;
9177c478bd9Sstevel@tonic-gate 	subclass_lst_t *sclist, *next_sc;
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	for (i = 0; i <= CLASS_HASH_SZ; ++i) {
9207c478bd9Sstevel@tonic-gate 
9217c478bd9Sstevel@tonic-gate 		clist = chan->scd_class_list_tbl[i];
9227c478bd9Sstevel@tonic-gate 		while (clist != NULL) {
9237c478bd9Sstevel@tonic-gate 			sclist = clist->cl_subclass_list;
9247c478bd9Sstevel@tonic-gate 			while (sclist != NULL) {
9257c478bd9Sstevel@tonic-gate 				kmem_free(sclist->sl_name,
9267c478bd9Sstevel@tonic-gate 				    strlen(sclist->sl_name) + 1);
9277c478bd9Sstevel@tonic-gate 				next_sc = sclist->sl_next;
9287c478bd9Sstevel@tonic-gate 				kmem_free(sclist, sizeof (subclass_lst_t));
9297c478bd9Sstevel@tonic-gate 				sclist = next_sc;
9307c478bd9Sstevel@tonic-gate 			}
9317c478bd9Sstevel@tonic-gate 			kmem_free(clist->cl_name,
9327c478bd9Sstevel@tonic-gate 			    strlen(clist->cl_name) + 1);
9337c478bd9Sstevel@tonic-gate 			next_clist = clist->cl_next;
9347c478bd9Sstevel@tonic-gate 			kmem_free(clist, sizeof (class_lst_t));
9357c478bd9Sstevel@tonic-gate 			clist = next_clist;
9367c478bd9Sstevel@tonic-gate 		}
9377c478bd9Sstevel@tonic-gate 	}
9387c478bd9Sstevel@tonic-gate 	chan->scd_class_list_tbl[0] = NULL;
9397c478bd9Sstevel@tonic-gate }
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate static int
open_channel(char * channel_name)9427c478bd9Sstevel@tonic-gate open_channel(char *channel_name)
9437c478bd9Sstevel@tonic-gate {
9447c478bd9Sstevel@tonic-gate 	int hash_index;
9457c478bd9Sstevel@tonic-gate 	sysevent_channel_descriptor_t *chan, *chan_list;
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 
9487c478bd9Sstevel@tonic-gate 	if (channel_cnt > MAX_CHAN) {
9497c478bd9Sstevel@tonic-gate 		return (-1);
9507c478bd9Sstevel@tonic-gate 	}
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	/* Find channel descriptor */
9537c478bd9Sstevel@tonic-gate 	hash_index = CHANN_HASH(channel_name);
9547c478bd9Sstevel@tonic-gate 	chan_list = registered_channels[hash_index];
9557c478bd9Sstevel@tonic-gate 	while (chan_list != NULL) {
9567c478bd9Sstevel@tonic-gate 		if (strcmp(chan_list->scd_channel_name, channel_name) == 0) {
9577c478bd9Sstevel@tonic-gate 			chan_list->scd_ref_cnt++;
9587c478bd9Sstevel@tonic-gate 			kmem_free(channel_name, strlen(channel_name) + 1);
9597c478bd9Sstevel@tonic-gate 			return (0);
9607c478bd9Sstevel@tonic-gate 		} else {
9617c478bd9Sstevel@tonic-gate 			chan_list = chan_list->scd_next;
9627c478bd9Sstevel@tonic-gate 		}
9637c478bd9Sstevel@tonic-gate 	}
9647c478bd9Sstevel@tonic-gate 
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	/* New channel descriptor */
9677c478bd9Sstevel@tonic-gate 	chan = kmem_zalloc(sizeof (sysevent_channel_descriptor_t), KM_SLEEP);
9687c478bd9Sstevel@tonic-gate 	chan->scd_channel_name = channel_name;
9697c478bd9Sstevel@tonic-gate 
9707c478bd9Sstevel@tonic-gate 	/*
9717c478bd9Sstevel@tonic-gate 	 * Create subscriber ids in the range [1, MAX_SUBSCRIBERS).
9727c478bd9Sstevel@tonic-gate 	 * Subscriber id 0 is never allocated, but is used as a reserved id
9737c478bd9Sstevel@tonic-gate 	 * by libsysevent
9747c478bd9Sstevel@tonic-gate 	 */
9757c478bd9Sstevel@tonic-gate 	if ((chan->scd_subscriber_cache = vmem_create(channel_name, (void *)1,
9767c478bd9Sstevel@tonic-gate 	    MAX_SUBSCRIBERS + 1, 1, NULL, NULL, NULL, 0,
9777c478bd9Sstevel@tonic-gate 	    VM_NOSLEEP | VMC_IDENTIFIER)) == NULL) {
9787c478bd9Sstevel@tonic-gate 		kmem_free(chan, sizeof (sysevent_channel_descriptor_t));
9797c478bd9Sstevel@tonic-gate 		return (-1);
9807c478bd9Sstevel@tonic-gate 	}
9817c478bd9Sstevel@tonic-gate 	if ((chan->scd_publisher_cache = vmem_create(channel_name, (void *)1,
9827c478bd9Sstevel@tonic-gate 	    MAX_PUBLISHERS + 1, 1, NULL, NULL, NULL, 0,
9837c478bd9Sstevel@tonic-gate 	    VM_NOSLEEP | VMC_IDENTIFIER)) == NULL) {
9847c478bd9Sstevel@tonic-gate 		vmem_destroy(chan->scd_subscriber_cache);
9857c478bd9Sstevel@tonic-gate 		kmem_free(chan, sizeof (sysevent_channel_descriptor_t));
9867c478bd9Sstevel@tonic-gate 		return (-1);
9877c478bd9Sstevel@tonic-gate 	}
9887c478bd9Sstevel@tonic-gate 
9897c478bd9Sstevel@tonic-gate 	chan->scd_ref_cnt = 1;
9907c478bd9Sstevel@tonic-gate 
9917c478bd9Sstevel@tonic-gate 	(void) create_channel_registration(chan, EC_ALL, 0);
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 	if (registered_channels[hash_index] != NULL)
9947c478bd9Sstevel@tonic-gate 		chan->scd_next = registered_channels[hash_index];
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	registered_channels[hash_index] = chan;
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	++channel_cnt;
9997c478bd9Sstevel@tonic-gate 
10007c478bd9Sstevel@tonic-gate 	return (0);
10017c478bd9Sstevel@tonic-gate }
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate static void
close_channel(char * channel_name)10047c478bd9Sstevel@tonic-gate close_channel(char *channel_name)
10057c478bd9Sstevel@tonic-gate {
10067c478bd9Sstevel@tonic-gate 	int hash_index;
10077c478bd9Sstevel@tonic-gate 	sysevent_channel_descriptor_t *chan, *prev_chan;
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	/* Find channel descriptor */
10107c478bd9Sstevel@tonic-gate 	hash_index = CHANN_HASH(channel_name);
10117c478bd9Sstevel@tonic-gate 	prev_chan = chan = registered_channels[hash_index];
10127c478bd9Sstevel@tonic-gate 
10137c478bd9Sstevel@tonic-gate 	while (chan != NULL) {
10147c478bd9Sstevel@tonic-gate 		if (strcmp(chan->scd_channel_name, channel_name) == 0) {
10157c478bd9Sstevel@tonic-gate 			break;
10167c478bd9Sstevel@tonic-gate 		} else {
10177c478bd9Sstevel@tonic-gate 			prev_chan = chan;
10187c478bd9Sstevel@tonic-gate 			chan = chan->scd_next;
10197c478bd9Sstevel@tonic-gate 		}
10207c478bd9Sstevel@tonic-gate 	}
10217c478bd9Sstevel@tonic-gate 
10227c478bd9Sstevel@tonic-gate 	if (chan == NULL)
10237c478bd9Sstevel@tonic-gate 		return;
10247c478bd9Sstevel@tonic-gate 
10257c478bd9Sstevel@tonic-gate 	chan->scd_ref_cnt--;
10267c478bd9Sstevel@tonic-gate 	if (chan->scd_ref_cnt > 0)
10277c478bd9Sstevel@tonic-gate 		return;
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	free_channel_registration(chan);
10307c478bd9Sstevel@tonic-gate 	vmem_destroy(chan->scd_subscriber_cache);
10317c478bd9Sstevel@tonic-gate 	vmem_destroy(chan->scd_publisher_cache);
10327c478bd9Sstevel@tonic-gate 	kmem_free(chan->scd_channel_name,
10337c478bd9Sstevel@tonic-gate 	    strlen(chan->scd_channel_name) + 1);
10347c478bd9Sstevel@tonic-gate 	if (registered_channels[hash_index] == chan)
10357c478bd9Sstevel@tonic-gate 		registered_channels[hash_index] = chan->scd_next;
10367c478bd9Sstevel@tonic-gate 	else
10377c478bd9Sstevel@tonic-gate 		prev_chan->scd_next = chan->scd_next;
10387c478bd9Sstevel@tonic-gate 	kmem_free(chan, sizeof (sysevent_channel_descriptor_t));
10397c478bd9Sstevel@tonic-gate 	--channel_cnt;
10407c478bd9Sstevel@tonic-gate }
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate static id_t
bind_common(sysevent_channel_descriptor_t * chan,int type)10437c478bd9Sstevel@tonic-gate bind_common(sysevent_channel_descriptor_t *chan, int type)
10447c478bd9Sstevel@tonic-gate {
10457c478bd9Sstevel@tonic-gate 	id_t id;
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	if (type == SUBSCRIBER) {
10487c478bd9Sstevel@tonic-gate 		id = (id_t)(uintptr_t)vmem_alloc(chan->scd_subscriber_cache, 1,
10497c478bd9Sstevel@tonic-gate 		    VM_NOSLEEP | VM_NEXTFIT);
10507c478bd9Sstevel@tonic-gate 		if (id <= 0 || id > MAX_SUBSCRIBERS)
10517c478bd9Sstevel@tonic-gate 			return (0);
10527c478bd9Sstevel@tonic-gate 		chan->scd_subscriber_ids[id] = 1;
10537c478bd9Sstevel@tonic-gate 	} else {
10547c478bd9Sstevel@tonic-gate 		id = (id_t)(uintptr_t)vmem_alloc(chan->scd_publisher_cache, 1,
10557c478bd9Sstevel@tonic-gate 		    VM_NOSLEEP | VM_NEXTFIT);
10567c478bd9Sstevel@tonic-gate 		if (id <= 0 || id > MAX_PUBLISHERS)
10577c478bd9Sstevel@tonic-gate 			return (0);
10587c478bd9Sstevel@tonic-gate 		chan->scd_publisher_ids[id] = 1;
10597c478bd9Sstevel@tonic-gate 	}
10607c478bd9Sstevel@tonic-gate 
10617c478bd9Sstevel@tonic-gate 	return (id);
10627c478bd9Sstevel@tonic-gate }
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate static int
unbind_common(sysevent_channel_descriptor_t * chan,int type,id_t id)10657c478bd9Sstevel@tonic-gate unbind_common(sysevent_channel_descriptor_t *chan, int type, id_t id)
10667c478bd9Sstevel@tonic-gate {
10677c478bd9Sstevel@tonic-gate 	if (type == SUBSCRIBER) {
10687c478bd9Sstevel@tonic-gate 		if (id <= 0 || id > MAX_SUBSCRIBERS)
10697c478bd9Sstevel@tonic-gate 			return (0);
10707c478bd9Sstevel@tonic-gate 		if (chan->scd_subscriber_ids[id] == 0)
10717c478bd9Sstevel@tonic-gate 			return (0);
10727c478bd9Sstevel@tonic-gate 		(void) remove_all_class(chan, id);
10737c478bd9Sstevel@tonic-gate 		chan->scd_subscriber_ids[id] = 0;
10747c478bd9Sstevel@tonic-gate 		vmem_free(chan->scd_subscriber_cache, (void *)(uintptr_t)id, 1);
10757c478bd9Sstevel@tonic-gate 	} else {
10767c478bd9Sstevel@tonic-gate 		if (id <= 0 || id > MAX_PUBLISHERS)
10777c478bd9Sstevel@tonic-gate 			return (0);
10787c478bd9Sstevel@tonic-gate 		if (chan->scd_publisher_ids[id] == 0)
10797c478bd9Sstevel@tonic-gate 			return (0);
10807c478bd9Sstevel@tonic-gate 		chan->scd_publisher_ids[id] = 0;
10817c478bd9Sstevel@tonic-gate 		vmem_free(chan->scd_publisher_cache, (void *)(uintptr_t)id, 1);
10827c478bd9Sstevel@tonic-gate 	}
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	return (1);
10857c478bd9Sstevel@tonic-gate }
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate static void
release_id(sysevent_channel_descriptor_t * chan,int type,id_t id)10887c478bd9Sstevel@tonic-gate release_id(sysevent_channel_descriptor_t *chan, int type, id_t id)
10897c478bd9Sstevel@tonic-gate {
10907c478bd9Sstevel@tonic-gate 	if (unbind_common(chan, type, id))
10917c478bd9Sstevel@tonic-gate 		close_channel(chan->scd_channel_name);
10927c478bd9Sstevel@tonic-gate }
10937c478bd9Sstevel@tonic-gate 
10947c478bd9Sstevel@tonic-gate static subclass_lst_t *
find_subclass(class_lst_t * c_list,char * subclass)10957c478bd9Sstevel@tonic-gate find_subclass(class_lst_t *c_list, char *subclass)
10967c478bd9Sstevel@tonic-gate {
10977c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	if (c_list == NULL)
11007c478bd9Sstevel@tonic-gate 		return (NULL);
11017c478bd9Sstevel@tonic-gate 
11027c478bd9Sstevel@tonic-gate 	sc_list = c_list->cl_subclass_list;
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	while (sc_list != NULL) {
11057c478bd9Sstevel@tonic-gate 		if (strcmp(sc_list->sl_name, subclass) == 0) {
11067c478bd9Sstevel@tonic-gate 			return (sc_list);
11077c478bd9Sstevel@tonic-gate 		}
11087c478bd9Sstevel@tonic-gate 		sc_list = sc_list->sl_next;
11097c478bd9Sstevel@tonic-gate 	}
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate 	return (NULL);
11127c478bd9Sstevel@tonic-gate }
11137c478bd9Sstevel@tonic-gate 
11147c478bd9Sstevel@tonic-gate static void
insert_subclass(class_lst_t * c_list,char ** subclass_names,int subclass_num,uint32_t sub_id)11157c478bd9Sstevel@tonic-gate insert_subclass(class_lst_t *c_list, char **subclass_names,
1116406fc510SToomas Soome     int subclass_num, uint32_t sub_id)
11177c478bd9Sstevel@tonic-gate {
11187c478bd9Sstevel@tonic-gate 	int i, subclass_sz;
11197c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 	for (i = 0; i < subclass_num; ++i) {
11227c478bd9Sstevel@tonic-gate 		if ((sc_list = find_subclass(c_list, subclass_names[i]))
11237c478bd9Sstevel@tonic-gate 		    != NULL) {
11247c478bd9Sstevel@tonic-gate 			sc_list->sl_num[sub_id] = 1;
11257c478bd9Sstevel@tonic-gate 		} else {
11267c478bd9Sstevel@tonic-gate 
11277c478bd9Sstevel@tonic-gate 			sc_list = kmem_zalloc(sizeof (subclass_lst_t),
11287c478bd9Sstevel@tonic-gate 			    KM_SLEEP);
11297c478bd9Sstevel@tonic-gate 			subclass_sz = strlen(subclass_names[i]) + 1;
11307c478bd9Sstevel@tonic-gate 			sc_list->sl_name = kmem_zalloc(subclass_sz, KM_SLEEP);
11317c478bd9Sstevel@tonic-gate 			bcopy(subclass_names[i], sc_list->sl_name,
11327c478bd9Sstevel@tonic-gate 			    subclass_sz);
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 			sc_list->sl_num[sub_id] = 1;
11357c478bd9Sstevel@tonic-gate 
11367c478bd9Sstevel@tonic-gate 			sc_list->sl_next = c_list->cl_subclass_list;
11377c478bd9Sstevel@tonic-gate 			c_list->cl_subclass_list = sc_list;
11387c478bd9Sstevel@tonic-gate 		}
11397c478bd9Sstevel@tonic-gate 	}
11407c478bd9Sstevel@tonic-gate }
11417c478bd9Sstevel@tonic-gate 
11427c478bd9Sstevel@tonic-gate static class_lst_t *
find_class(sysevent_channel_descriptor_t * chan,char * class_name)11437c478bd9Sstevel@tonic-gate find_class(sysevent_channel_descriptor_t *chan, char *class_name)
11447c478bd9Sstevel@tonic-gate {
11457c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
11467c478bd9Sstevel@tonic-gate 
11477c478bd9Sstevel@tonic-gate 	c_list = chan->scd_class_list_tbl[CLASS_HASH(class_name)];
11487c478bd9Sstevel@tonic-gate 	while (c_list != NULL) {
11497c478bd9Sstevel@tonic-gate 		if (strcmp(class_name, c_list->cl_name) == 0)
11507c478bd9Sstevel@tonic-gate 			break;
11517c478bd9Sstevel@tonic-gate 		c_list = c_list->cl_next;
11527c478bd9Sstevel@tonic-gate 	}
11537c478bd9Sstevel@tonic-gate 
11547c478bd9Sstevel@tonic-gate 	return (c_list);
11557c478bd9Sstevel@tonic-gate }
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate static void
remove_all_class(sysevent_channel_descriptor_t * chan,uint32_t sub_id)11587c478bd9Sstevel@tonic-gate remove_all_class(sysevent_channel_descriptor_t *chan, uint32_t sub_id)
11597c478bd9Sstevel@tonic-gate {
11607c478bd9Sstevel@tonic-gate 	int i;
11617c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
11627c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	for (i = 0; i <= CLASS_HASH_SZ; ++i) {
11657c478bd9Sstevel@tonic-gate 
11667c478bd9Sstevel@tonic-gate 		c_list = chan->scd_class_list_tbl[i];
11677c478bd9Sstevel@tonic-gate 		while (c_list != NULL) {
11687c478bd9Sstevel@tonic-gate 			sc_list = c_list->cl_subclass_list;
11697c478bd9Sstevel@tonic-gate 			while (sc_list != NULL) {
11707c478bd9Sstevel@tonic-gate 				sc_list->sl_num[sub_id] = 0;
11717c478bd9Sstevel@tonic-gate 				sc_list = sc_list->sl_next;
11727c478bd9Sstevel@tonic-gate 			}
11737c478bd9Sstevel@tonic-gate 			c_list = c_list->cl_next;
11747c478bd9Sstevel@tonic-gate 		}
11757c478bd9Sstevel@tonic-gate 	}
11767c478bd9Sstevel@tonic-gate }
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate static void
remove_class(sysevent_channel_descriptor_t * chan,uint32_t sub_id,char * class_name)11797c478bd9Sstevel@tonic-gate remove_class(sysevent_channel_descriptor_t *chan, uint32_t sub_id,
1180406fc510SToomas Soome     char *class_name)
11817c478bd9Sstevel@tonic-gate {
11827c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
11837c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
11847c478bd9Sstevel@tonic-gate 
11857c478bd9Sstevel@tonic-gate 	if (strcmp(class_name, EC_ALL) == 0) {
11867c478bd9Sstevel@tonic-gate 		remove_all_class(chan, sub_id);
11877c478bd9Sstevel@tonic-gate 		return;
11887c478bd9Sstevel@tonic-gate 	}
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate 	if ((c_list = find_class(chan, class_name)) == NULL) {
11917c478bd9Sstevel@tonic-gate 		return;
11927c478bd9Sstevel@tonic-gate 	}
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 	sc_list = c_list->cl_subclass_list;
11957c478bd9Sstevel@tonic-gate 	while (sc_list != NULL) {
11967c478bd9Sstevel@tonic-gate 		sc_list->sl_num[sub_id] = 0;
11977c478bd9Sstevel@tonic-gate 		sc_list = sc_list->sl_next;
11987c478bd9Sstevel@tonic-gate 	}
11997c478bd9Sstevel@tonic-gate }
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate static int
insert_class(sysevent_channel_descriptor_t * chan,char * event_class,char ** event_subclass_lst,int subclass_num,uint32_t sub_id)12027c478bd9Sstevel@tonic-gate insert_class(sysevent_channel_descriptor_t *chan, char *event_class,
1203406fc510SToomas Soome     char **event_subclass_lst, int subclass_num, uint32_t sub_id)
12047c478bd9Sstevel@tonic-gate {
12057c478bd9Sstevel@tonic-gate 	class_lst_t *c_list;
12067c478bd9Sstevel@tonic-gate 
12077c478bd9Sstevel@tonic-gate 	if (strcmp(event_class, EC_ALL) == 0) {
12087c478bd9Sstevel@tonic-gate 		insert_subclass(chan->scd_class_list_tbl[0],
12097c478bd9Sstevel@tonic-gate 		    event_subclass_lst, 1, sub_id);
12107c478bd9Sstevel@tonic-gate 		return (0);
12117c478bd9Sstevel@tonic-gate 	}
12127c478bd9Sstevel@tonic-gate 
12137c478bd9Sstevel@tonic-gate 	if (strlen(event_class) + 1 > MAX_CLASS_LEN)
12147c478bd9Sstevel@tonic-gate 		return (-1);
12157c478bd9Sstevel@tonic-gate 
12167c478bd9Sstevel@tonic-gate 	/* New class, add to the registration cache */
12177c478bd9Sstevel@tonic-gate 	if ((c_list = find_class(chan, event_class)) == NULL) {
12187c478bd9Sstevel@tonic-gate 		c_list = create_channel_registration(chan, event_class,
12197c478bd9Sstevel@tonic-gate 		    CLASS_HASH(event_class));
12207c478bd9Sstevel@tonic-gate 	}
12217c478bd9Sstevel@tonic-gate 
12227c478bd9Sstevel@tonic-gate 	/* Update the subclass list */
12237c478bd9Sstevel@tonic-gate 	insert_subclass(c_list, event_subclass_lst, subclass_num, sub_id);
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	return (0);
12267c478bd9Sstevel@tonic-gate }
12277c478bd9Sstevel@tonic-gate 
12287c478bd9Sstevel@tonic-gate static int
add_registration(sysevent_channel_descriptor_t * chan,uint32_t sub_id,char * nvlbuf,size_t nvlsize)12297c478bd9Sstevel@tonic-gate add_registration(sysevent_channel_descriptor_t *chan, uint32_t sub_id,
1230406fc510SToomas Soome     char *nvlbuf, size_t nvlsize)
12317c478bd9Sstevel@tonic-gate {
12327c478bd9Sstevel@tonic-gate 	uint_t num_elem;
12337c478bd9Sstevel@tonic-gate 	char *event_class;
12347c478bd9Sstevel@tonic-gate 	char **event_list;
12357c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
12367c478bd9Sstevel@tonic-gate 	nvpair_t *nvpair = NULL;
12377c478bd9Sstevel@tonic-gate 
12387c478bd9Sstevel@tonic-gate 	if (nvlist_unpack(nvlbuf, nvlsize, &nvl, KM_SLEEP) != 0)
12397c478bd9Sstevel@tonic-gate 		return (-1);
12407c478bd9Sstevel@tonic-gate 
12417c478bd9Sstevel@tonic-gate 	if ((nvpair = nvlist_next_nvpair(nvl, nvpair)) == NULL) {
12427c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
12437c478bd9Sstevel@tonic-gate 		return (-1);
12447c478bd9Sstevel@tonic-gate 	}
12457c478bd9Sstevel@tonic-gate 
12467c478bd9Sstevel@tonic-gate 	if ((event_class = nvpair_name(nvpair)) == NULL) {
12477c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
12487c478bd9Sstevel@tonic-gate 		return (-1);
12497c478bd9Sstevel@tonic-gate 	}
12507c478bd9Sstevel@tonic-gate 	if (nvpair_value_string_array(nvpair, &event_list,
12517c478bd9Sstevel@tonic-gate 	    &num_elem) != 0) {
12527c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
12537c478bd9Sstevel@tonic-gate 		return (-1);
12547c478bd9Sstevel@tonic-gate 	}
12557c478bd9Sstevel@tonic-gate 
12567c478bd9Sstevel@tonic-gate 	if (insert_class(chan, event_class, event_list, num_elem, sub_id) < 0) {
12577c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
12587c478bd9Sstevel@tonic-gate 		return (-1);
12597c478bd9Sstevel@tonic-gate 	}
12607c478bd9Sstevel@tonic-gate 
12617c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate 	return (0);
12647c478bd9Sstevel@tonic-gate }
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate /*
12677c478bd9Sstevel@tonic-gate  * get_registration - Return the requested class hash chain
12687c478bd9Sstevel@tonic-gate  */
12697c478bd9Sstevel@tonic-gate static int
get_registration(sysevent_channel_descriptor_t * chan,char * databuf,uint32_t * bufsz,uint32_t class_index)12707c478bd9Sstevel@tonic-gate get_registration(sysevent_channel_descriptor_t *chan, char *databuf,
1271406fc510SToomas Soome     uint32_t *bufsz, uint32_t class_index)
12727c478bd9Sstevel@tonic-gate {
12737c478bd9Sstevel@tonic-gate 	int num_classes = 0;
12747c478bd9Sstevel@tonic-gate 	char *nvlbuf = NULL;
12757c478bd9Sstevel@tonic-gate 	size_t nvlsize;
12767c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
12777c478bd9Sstevel@tonic-gate 	class_lst_t *clist;
12787c478bd9Sstevel@tonic-gate 	subclass_lst_t *sc_list;
12797c478bd9Sstevel@tonic-gate 
1280*3df2e8b2SRobert Mustacchi 	if (class_index > CLASS_HASH_SZ)
12817c478bd9Sstevel@tonic-gate 		return (EINVAL);
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	if ((clist = chan->scd_class_list_tbl[class_index]) == NULL) {
12847c478bd9Sstevel@tonic-gate 		return (ENOENT);
12857c478bd9Sstevel@tonic-gate 	}
12867c478bd9Sstevel@tonic-gate 
12877c478bd9Sstevel@tonic-gate 	if (nvlist_alloc(&nvl, 0, 0) != 0) {
12887c478bd9Sstevel@tonic-gate 		return (EFAULT);
12897c478bd9Sstevel@tonic-gate 	}
12907c478bd9Sstevel@tonic-gate 
12917c478bd9Sstevel@tonic-gate 	while (clist != NULL) {
12927c478bd9Sstevel@tonic-gate 		if (nvlist_add_string(nvl, CLASS_NAME, clist->cl_name)
12937c478bd9Sstevel@tonic-gate 		    != 0) {
12947c478bd9Sstevel@tonic-gate 			nvlist_free(nvl);
12957c478bd9Sstevel@tonic-gate 			return (EFAULT);
12967c478bd9Sstevel@tonic-gate 		}
12977c478bd9Sstevel@tonic-gate 
12987c478bd9Sstevel@tonic-gate 		sc_list = clist->cl_subclass_list;
12997c478bd9Sstevel@tonic-gate 		while (sc_list != NULL) {
13007c478bd9Sstevel@tonic-gate 			if (nvlist_add_byte_array(nvl, sc_list->sl_name,
13017c478bd9Sstevel@tonic-gate 			    sc_list->sl_num, MAX_SUBSCRIBERS) != 0) {
13027c478bd9Sstevel@tonic-gate 				nvlist_free(nvl);
13037c478bd9Sstevel@tonic-gate 				return (EFAULT);
13047c478bd9Sstevel@tonic-gate 			}
13057c478bd9Sstevel@tonic-gate 			sc_list = sc_list->sl_next;
13067c478bd9Sstevel@tonic-gate 		}
13077c478bd9Sstevel@tonic-gate 		num_classes++;
13087c478bd9Sstevel@tonic-gate 		clist = clist->cl_next;
13097c478bd9Sstevel@tonic-gate 	}
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	if (num_classes == 0) {
13127c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
13137c478bd9Sstevel@tonic-gate 		return (ENOENT);
13147c478bd9Sstevel@tonic-gate 	}
13157c478bd9Sstevel@tonic-gate 
13167c478bd9Sstevel@tonic-gate 	if (nvlist_pack(nvl, &nvlbuf, &nvlsize, NV_ENCODE_NATIVE,
13177c478bd9Sstevel@tonic-gate 	    KM_SLEEP)
13187c478bd9Sstevel@tonic-gate 	    != 0) {
13197c478bd9Sstevel@tonic-gate 		nvlist_free(nvl);
13207c478bd9Sstevel@tonic-gate 		return (EFAULT);
13217c478bd9Sstevel@tonic-gate 	}
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 	nvlist_free(nvl);
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 	if (nvlsize > *bufsz) {
13267c478bd9Sstevel@tonic-gate 		kmem_free(nvlbuf, nvlsize);
13277c478bd9Sstevel@tonic-gate 		*bufsz = nvlsize;
13287c478bd9Sstevel@tonic-gate 		return (EAGAIN);
13297c478bd9Sstevel@tonic-gate 	}
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 	bcopy(nvlbuf, databuf, nvlsize);
13327c478bd9Sstevel@tonic-gate 	kmem_free(nvlbuf, nvlsize);
13337c478bd9Sstevel@tonic-gate 
13347c478bd9Sstevel@tonic-gate 	return (0);
13357c478bd9Sstevel@tonic-gate }
13367c478bd9Sstevel@tonic-gate 
13377c478bd9Sstevel@tonic-gate /*
13387c478bd9Sstevel@tonic-gate  * log_sysevent_register - Register event subscriber for a particular
13397c478bd9Sstevel@tonic-gate  *		event channel.
13407c478bd9Sstevel@tonic-gate  */
13417c478bd9Sstevel@tonic-gate int
log_sysevent_register(char * channel_name,char * udatabuf,se_pubsub_t * udata)13427c478bd9Sstevel@tonic-gate log_sysevent_register(char *channel_name, char *udatabuf, se_pubsub_t *udata)
13437c478bd9Sstevel@tonic-gate {
13447c478bd9Sstevel@tonic-gate 	int error = 0;
13457c478bd9Sstevel@tonic-gate 	char *kchannel, *databuf = NULL;
13467c478bd9Sstevel@tonic-gate 	size_t bufsz;
13477c478bd9Sstevel@tonic-gate 	se_pubsub_t kdata;
1348c6f039c7SToomas Soome 	sysevent_channel_descriptor_t *chan = NULL;
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 	if (copyin(udata, &kdata, sizeof (se_pubsub_t)) == -1) {
13517c478bd9Sstevel@tonic-gate 		return (EFAULT);
13527c478bd9Sstevel@tonic-gate 	}
13537c478bd9Sstevel@tonic-gate 	if (kdata.ps_channel_name_len == 0) {
13547c478bd9Sstevel@tonic-gate 		return (EINVAL);
13557c478bd9Sstevel@tonic-gate 	}
13567c478bd9Sstevel@tonic-gate 	kchannel = kmem_alloc(kdata.ps_channel_name_len, KM_SLEEP);
13577c478bd9Sstevel@tonic-gate 	if (copyin(channel_name, kchannel, kdata.ps_channel_name_len) == -1) {
13587c478bd9Sstevel@tonic-gate 		kmem_free(kchannel, kdata.ps_channel_name_len);
13597c478bd9Sstevel@tonic-gate 		return (EFAULT);
13607c478bd9Sstevel@tonic-gate 	}
13617c478bd9Sstevel@tonic-gate 	bufsz = kdata.ps_buflen;
13627c478bd9Sstevel@tonic-gate 	if (bufsz > 0) {
13637c478bd9Sstevel@tonic-gate 		databuf = kmem_alloc(bufsz, KM_SLEEP);
13647c478bd9Sstevel@tonic-gate 		if (copyin(udatabuf, databuf, bufsz) == -1) {
13657c478bd9Sstevel@tonic-gate 			kmem_free(kchannel, kdata.ps_channel_name_len);
13667c478bd9Sstevel@tonic-gate 			kmem_free(databuf, bufsz);
13677c478bd9Sstevel@tonic-gate 			return (EFAULT);
13687c478bd9Sstevel@tonic-gate 		}
13697c478bd9Sstevel@tonic-gate 	}
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate 	mutex_enter(&registered_channel_mutex);
13727c478bd9Sstevel@tonic-gate 	if (kdata.ps_op != SE_OPEN_REGISTRATION &&
13737c478bd9Sstevel@tonic-gate 	    kdata.ps_op != SE_CLOSE_REGISTRATION) {
13747c478bd9Sstevel@tonic-gate 		chan = get_channel(kchannel);
13757c478bd9Sstevel@tonic-gate 		if (chan == NULL) {
13767c478bd9Sstevel@tonic-gate 			mutex_exit(&registered_channel_mutex);
13777c478bd9Sstevel@tonic-gate 			kmem_free(kchannel, kdata.ps_channel_name_len);
13787c478bd9Sstevel@tonic-gate 			if (bufsz > 0)
13797c478bd9Sstevel@tonic-gate 				kmem_free(databuf, bufsz);
13807c478bd9Sstevel@tonic-gate 			return (ENOENT);
13817c478bd9Sstevel@tonic-gate 		}
13827c478bd9Sstevel@tonic-gate 	}
13837c478bd9Sstevel@tonic-gate 
13847c478bd9Sstevel@tonic-gate 	switch (kdata.ps_op) {
13857c478bd9Sstevel@tonic-gate 	case SE_OPEN_REGISTRATION:
13867c478bd9Sstevel@tonic-gate 		if (open_channel(kchannel) != 0) {
13877c478bd9Sstevel@tonic-gate 			error = ENOMEM;
13887c478bd9Sstevel@tonic-gate 			if (bufsz > 0)
13897c478bd9Sstevel@tonic-gate 				kmem_free(databuf, bufsz);
13907c478bd9Sstevel@tonic-gate 			kmem_free(kchannel, kdata.ps_channel_name_len);
13917c478bd9Sstevel@tonic-gate 		}
13927c478bd9Sstevel@tonic-gate 
13937c478bd9Sstevel@tonic-gate 		mutex_exit(&registered_channel_mutex);
13947c478bd9Sstevel@tonic-gate 		return (error);
13957c478bd9Sstevel@tonic-gate 	case SE_CLOSE_REGISTRATION:
13967c478bd9Sstevel@tonic-gate 		close_channel(kchannel);
13977c478bd9Sstevel@tonic-gate 		break;
1398*3df2e8b2SRobert Mustacchi 	case SE_BIND_REGISTRATION: {
1399*3df2e8b2SRobert Mustacchi 		id_t id;
1400*3df2e8b2SRobert Mustacchi 
1401*3df2e8b2SRobert Mustacchi 		id = bind_common(chan, kdata.ps_type);
1402*3df2e8b2SRobert Mustacchi 		kdata.ps_id = (uint32_t)id;
1403*3df2e8b2SRobert Mustacchi 		if (id <= 0)
14047c478bd9Sstevel@tonic-gate 			error = EBUSY;
14057c478bd9Sstevel@tonic-gate 		break;
1406*3df2e8b2SRobert Mustacchi 	}
14077c478bd9Sstevel@tonic-gate 	case SE_UNBIND_REGISTRATION:
14087c478bd9Sstevel@tonic-gate 		(void) unbind_common(chan, kdata.ps_type, (id_t)kdata.ps_id);
14097c478bd9Sstevel@tonic-gate 		break;
14107c478bd9Sstevel@tonic-gate 	case SE_REGISTER:
14117c478bd9Sstevel@tonic-gate 		if (bufsz == 0) {
14127c478bd9Sstevel@tonic-gate 			error = EINVAL;
14137c478bd9Sstevel@tonic-gate 			break;
14147c478bd9Sstevel@tonic-gate 		}
14157c478bd9Sstevel@tonic-gate 		if (add_registration(chan, kdata.ps_id, databuf, bufsz) == -1)
14167c478bd9Sstevel@tonic-gate 			error = EINVAL;
14177c478bd9Sstevel@tonic-gate 		break;
14187c478bd9Sstevel@tonic-gate 	case SE_UNREGISTER:
14197c478bd9Sstevel@tonic-gate 		if (bufsz == 0) {
14207c478bd9Sstevel@tonic-gate 			error = EINVAL;
14217c478bd9Sstevel@tonic-gate 			break;
14227c478bd9Sstevel@tonic-gate 		}
14237c478bd9Sstevel@tonic-gate 		remove_class(chan, kdata.ps_id, databuf);
14247c478bd9Sstevel@tonic-gate 		break;
14257c478bd9Sstevel@tonic-gate 	case SE_CLEANUP:
14267c478bd9Sstevel@tonic-gate 		/* Cleanup the indicated subscriber or publisher */
14277c478bd9Sstevel@tonic-gate 		release_id(chan, kdata.ps_type, kdata.ps_id);
14287c478bd9Sstevel@tonic-gate 		break;
14297c478bd9Sstevel@tonic-gate 	case SE_GET_REGISTRATION:
14307c478bd9Sstevel@tonic-gate 		error = get_registration(chan, databuf,
14317c478bd9Sstevel@tonic-gate 		    &kdata.ps_buflen, kdata.ps_id);
14327c478bd9Sstevel@tonic-gate 		break;
14337c478bd9Sstevel@tonic-gate 	default:
14347c478bd9Sstevel@tonic-gate 		error = ENOTSUP;
14357c478bd9Sstevel@tonic-gate 	}
14367c478bd9Sstevel@tonic-gate 
14377c478bd9Sstevel@tonic-gate 	mutex_exit(&registered_channel_mutex);
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 	kmem_free(kchannel, kdata.ps_channel_name_len);
14407c478bd9Sstevel@tonic-gate 
14417c478bd9Sstevel@tonic-gate 	if (bufsz > 0) {
14427c478bd9Sstevel@tonic-gate 		if (copyout(databuf, udatabuf, bufsz) == -1)
14437c478bd9Sstevel@tonic-gate 			error = EFAULT;
14447c478bd9Sstevel@tonic-gate 		kmem_free(databuf, bufsz);
14457c478bd9Sstevel@tonic-gate 	}
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	if (copyout(&kdata, udata, sizeof (se_pubsub_t)) == -1)
14487c478bd9Sstevel@tonic-gate 		return (EFAULT);
14497c478bd9Sstevel@tonic-gate 
14507c478bd9Sstevel@tonic-gate 	return (error);
14517c478bd9Sstevel@tonic-gate }
14527c478bd9Sstevel@tonic-gate 
14537c478bd9Sstevel@tonic-gate /*
14547c478bd9Sstevel@tonic-gate  * log_sysevent_copyout_data - Copyout event data to userland.
14557c478bd9Sstevel@tonic-gate  *			This is called from modctl(MODEVENTS, MODEVENTS_GETDATA)
14567c478bd9Sstevel@tonic-gate  *			The buffer size is always sufficient.
14577c478bd9Sstevel@tonic-gate  */
14587c478bd9Sstevel@tonic-gate int
log_sysevent_copyout_data(sysevent_id_t * eid,size_t ubuflen,caddr_t ubuf)14597c478bd9Sstevel@tonic-gate log_sysevent_copyout_data(sysevent_id_t *eid, size_t ubuflen, caddr_t ubuf)
14607c478bd9Sstevel@tonic-gate {
14617c478bd9Sstevel@tonic-gate 	int error = ENOENT;
14627c478bd9Sstevel@tonic-gate 	log_eventq_t *q;
14637c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
14647c478bd9Sstevel@tonic-gate 	sysevent_id_t eid_copy;
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 	/*
14677c478bd9Sstevel@tonic-gate 	 * Copy eid
14687c478bd9Sstevel@tonic-gate 	 */
14697c478bd9Sstevel@tonic-gate 	if (copyin(eid, &eid_copy, sizeof (sysevent_id_t)) == -1) {
14707c478bd9Sstevel@tonic-gate 		return (EFAULT);
14717c478bd9Sstevel@tonic-gate 	}
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_sent_mutex);
14747c478bd9Sstevel@tonic-gate 	q = log_eventq_sent;
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate 	/*
14777c478bd9Sstevel@tonic-gate 	 * Search for event buffer on the sent queue with matching
14787c478bd9Sstevel@tonic-gate 	 * event identifier
14797c478bd9Sstevel@tonic-gate 	 */
14807c478bd9Sstevel@tonic-gate 	while (q) {
14817c478bd9Sstevel@tonic-gate 		ev = (sysevent_t *)&q->arg.buf;
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 		if (SE_TIME(ev) != eid_copy.eid_ts ||
14847c478bd9Sstevel@tonic-gate 		    SE_SEQ(ev) != eid_copy.eid_seq) {
14857c478bd9Sstevel@tonic-gate 			q = q->next;
14867c478bd9Sstevel@tonic-gate 			continue;
14877c478bd9Sstevel@tonic-gate 		}
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 		if (ubuflen < SE_SIZE(ev)) {
14907c478bd9Sstevel@tonic-gate 			error = EFAULT;
14917c478bd9Sstevel@tonic-gate 			break;
14927c478bd9Sstevel@tonic-gate 		}
14937c478bd9Sstevel@tonic-gate 		if (copyout(ev, ubuf, SE_SIZE(ev)) != 0) {
14947c478bd9Sstevel@tonic-gate 			error = EFAULT;
14957c478bd9Sstevel@tonic-gate 			LOG_DEBUG((CE_NOTE, "Unable to retrieve system event "
14967c478bd9Sstevel@tonic-gate 			    "0x%" PRIx64 " from queue: EFAULT\n",
14977c478bd9Sstevel@tonic-gate 			    eid->eid_seq));
14987c478bd9Sstevel@tonic-gate 		} else {
14997c478bd9Sstevel@tonic-gate 			error = 0;
15007c478bd9Sstevel@tonic-gate 		}
15017c478bd9Sstevel@tonic-gate 		break;
15027c478bd9Sstevel@tonic-gate 	}
15037c478bd9Sstevel@tonic-gate 
15047c478bd9Sstevel@tonic-gate 	mutex_exit(&eventq_sent_mutex);
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 	return (error);
15077c478bd9Sstevel@tonic-gate }
15087c478bd9Sstevel@tonic-gate 
15097c478bd9Sstevel@tonic-gate /*
15107c478bd9Sstevel@tonic-gate  * log_sysevent_free_data - Free kernel copy of the event buffer identified
15117c478bd9Sstevel@tonic-gate  *			by eid (must have already been sent).  Called from
15127c478bd9Sstevel@tonic-gate  *			modctl(MODEVENTS, MODEVENTS_FREEDATA).
15137c478bd9Sstevel@tonic-gate  */
15147c478bd9Sstevel@tonic-gate int
log_sysevent_free_data(sysevent_id_t * eid)15157c478bd9Sstevel@tonic-gate log_sysevent_free_data(sysevent_id_t *eid)
15167c478bd9Sstevel@tonic-gate {
15177c478bd9Sstevel@tonic-gate 	int error = ENOENT;
15187c478bd9Sstevel@tonic-gate 	sysevent_t *ev;
15197c478bd9Sstevel@tonic-gate 	log_eventq_t *q, *prev = NULL;
15207c478bd9Sstevel@tonic-gate 	sysevent_id_t eid_copy;
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 	/*
15237c478bd9Sstevel@tonic-gate 	 * Copy eid
15247c478bd9Sstevel@tonic-gate 	 */
15257c478bd9Sstevel@tonic-gate 	if (copyin(eid, &eid_copy, sizeof (sysevent_id_t)) == -1) {
15267c478bd9Sstevel@tonic-gate 		return (EFAULT);
15277c478bd9Sstevel@tonic-gate 	}
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_sent_mutex);
15307c478bd9Sstevel@tonic-gate 	q = log_eventq_sent;
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate 	/*
15337c478bd9Sstevel@tonic-gate 	 * Look for the event to be freed on the sent queue.  Due to delayed
15347c478bd9Sstevel@tonic-gate 	 * processing of the event, it may not be on the sent queue yet.
15357c478bd9Sstevel@tonic-gate 	 * It is up to the user to retry the free operation to ensure that the
15367c478bd9Sstevel@tonic-gate 	 * event is properly freed.
15377c478bd9Sstevel@tonic-gate 	 */
15387c478bd9Sstevel@tonic-gate 	while (q) {
15397c478bd9Sstevel@tonic-gate 		ev = (sysevent_t *)&q->arg.buf;
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 		if (SE_TIME(ev) != eid_copy.eid_ts ||
15427c478bd9Sstevel@tonic-gate 		    SE_SEQ(ev) != eid_copy.eid_seq) {
15437c478bd9Sstevel@tonic-gate 			prev = q;
15447c478bd9Sstevel@tonic-gate 			q = q->next;
15457c478bd9Sstevel@tonic-gate 			continue;
15467c478bd9Sstevel@tonic-gate 		}
15477c478bd9Sstevel@tonic-gate 		/*
15487c478bd9Sstevel@tonic-gate 		 * Take it out of log_eventq_sent and free it
15497c478bd9Sstevel@tonic-gate 		 */
15507c478bd9Sstevel@tonic-gate 		if (prev) {
15517c478bd9Sstevel@tonic-gate 			prev->next = q->next;
15527c478bd9Sstevel@tonic-gate 		} else {
15537c478bd9Sstevel@tonic-gate 			log_eventq_sent = q->next;
15547c478bd9Sstevel@tonic-gate 		}
15557c478bd9Sstevel@tonic-gate 		free_packed_event(ev);
15567c478bd9Sstevel@tonic-gate 		error = 0;
15577c478bd9Sstevel@tonic-gate 		break;
15587c478bd9Sstevel@tonic-gate 	}
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	mutex_exit(&eventq_sent_mutex);
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	return (error);
15637c478bd9Sstevel@tonic-gate }
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate /*
15667c478bd9Sstevel@tonic-gate  * log_sysevent_flushq - Begin or resume event buffer delivery.  If neccessary,
15677c478bd9Sstevel@tonic-gate  *			create log_event_deliver thread or wake it up
15687c478bd9Sstevel@tonic-gate  */
15697c478bd9Sstevel@tonic-gate /*ARGSUSED*/
15707c478bd9Sstevel@tonic-gate void
log_sysevent_flushq(int cmd,uint_t flag)15717c478bd9Sstevel@tonic-gate log_sysevent_flushq(int cmd, uint_t flag)
15727c478bd9Sstevel@tonic-gate {
15737c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_head_mutex);
15747c478bd9Sstevel@tonic-gate 
15757c478bd9Sstevel@tonic-gate 	/*
15767c478bd9Sstevel@tonic-gate 	 * Start the event delivery thread
15777c478bd9Sstevel@tonic-gate 	 * Mark the upcall status as active since we should
15787c478bd9Sstevel@tonic-gate 	 * now be able to begin emptying the queue normally.
15797c478bd9Sstevel@tonic-gate 	 */
15807c478bd9Sstevel@tonic-gate 	if (!async_thread) {
15817c478bd9Sstevel@tonic-gate 		sysevent_upcall_status = 0;
15827c478bd9Sstevel@tonic-gate 		sysevent_daemon_init = 1;
15837c478bd9Sstevel@tonic-gate 		setup_ddi_poststartup();
15847c478bd9Sstevel@tonic-gate 		async_thread = thread_create(NULL, 0, log_event_deliver,
15857c478bd9Sstevel@tonic-gate 		    NULL, 0, &p0, TS_RUN, minclsyspri);
15867c478bd9Sstevel@tonic-gate 	}
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 	log_event_delivery = LOGEVENT_DELIVERY_CONT;
15897c478bd9Sstevel@tonic-gate 	cv_signal(&log_event_cv);
15907c478bd9Sstevel@tonic-gate 	mutex_exit(&eventq_head_mutex);
15917c478bd9Sstevel@tonic-gate }
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate /*
15947c478bd9Sstevel@tonic-gate  * log_sysevent_filename - Called by syseventd via
15957c478bd9Sstevel@tonic-gate  *			modctl(MODEVENTS, MODEVENTS_SET_DOOR_UPCALL_FILENAME)
15967c478bd9Sstevel@tonic-gate  *			to subsequently bind the event_door.
15977c478bd9Sstevel@tonic-gate  *
15987c478bd9Sstevel@tonic-gate  *			This routine is called everytime syseventd (re)starts
15997c478bd9Sstevel@tonic-gate  *			and must therefore replay any events buffers that have
16007c478bd9Sstevel@tonic-gate  *			been sent but not freed.
16017c478bd9Sstevel@tonic-gate  *
16027c478bd9Sstevel@tonic-gate  *			Event buffer delivery begins after a call to
16037c478bd9Sstevel@tonic-gate  *			log_sysevent_flushq().
16047c478bd9Sstevel@tonic-gate  */
16057c478bd9Sstevel@tonic-gate int
log_sysevent_filename(char * file)16067c478bd9Sstevel@tonic-gate log_sysevent_filename(char *file)
16077c478bd9Sstevel@tonic-gate {
1608e5dc7eacSMarcel Telka 	mutex_enter(&event_door_mutex);
1609e5dc7eacSMarcel Telka 
1610e5dc7eacSMarcel Telka 	(void) strlcpy(logevent_door_upcall_filename, file,
1611e5dc7eacSMarcel Telka 	    sizeof (logevent_door_upcall_filename));
1612e5dc7eacSMarcel Telka 
16137c478bd9Sstevel@tonic-gate 	/* Unbind old event door */
1614e5dc7eacSMarcel Telka 	if (event_door != NULL)
1615e5dc7eacSMarcel Telka 		door_ki_rele(event_door);
1616e5dc7eacSMarcel Telka 	/* Establish door connection with user event daemon (syseventd) */
1617e5dc7eacSMarcel Telka 	if (door_ki_open(logevent_door_upcall_filename, &event_door) != 0)
1618e5dc7eacSMarcel Telka 		event_door = NULL;
1619e5dc7eacSMarcel Telka 
1620e5dc7eacSMarcel Telka 	mutex_exit(&event_door_mutex);
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate 	/*
16237c478bd9Sstevel@tonic-gate 	 * We are called when syseventd restarts. Move all sent, but
16247c478bd9Sstevel@tonic-gate 	 * not committed events from log_eventq_sent to log_eventq_head.
16257c478bd9Sstevel@tonic-gate 	 * Do it in proper order to maintain increasing event id.
16267c478bd9Sstevel@tonic-gate 	 */
16277c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_head_mutex);
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_sent_mutex);
16307c478bd9Sstevel@tonic-gate 	while (log_eventq_sent) {
16317c478bd9Sstevel@tonic-gate 		log_eventq_t *tmp = log_eventq_sent->next;
16327c478bd9Sstevel@tonic-gate 		log_eventq_sent->next = log_eventq_head;
16337c478bd9Sstevel@tonic-gate 		if (log_eventq_head == NULL) {
16347c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_cnt == 0);
16357c478bd9Sstevel@tonic-gate 			log_eventq_tail = log_eventq_sent;
16367c478bd9Sstevel@tonic-gate 			log_eventq_tail->next = NULL;
16377c478bd9Sstevel@tonic-gate 		} else if (log_eventq_head == log_eventq_tail) {
16387c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_cnt == 1);
16397c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_head->next == NULL);
16407c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_tail->next == NULL);
16417c478bd9Sstevel@tonic-gate 		}
16427c478bd9Sstevel@tonic-gate 		log_eventq_head = log_eventq_sent;
16437c478bd9Sstevel@tonic-gate 		log_eventq_sent = tmp;
16447c478bd9Sstevel@tonic-gate 		log_eventq_cnt++;
16457c478bd9Sstevel@tonic-gate 	}
16467c478bd9Sstevel@tonic-gate 	mutex_exit(&eventq_sent_mutex);
16477c478bd9Sstevel@tonic-gate 	mutex_exit(&eventq_head_mutex);
16487c478bd9Sstevel@tonic-gate 
16497c478bd9Sstevel@tonic-gate 	return (0);
16507c478bd9Sstevel@tonic-gate }
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate /*
16537c478bd9Sstevel@tonic-gate  * queue_sysevent - queue an event buffer
16547c478bd9Sstevel@tonic-gate  */
16557c478bd9Sstevel@tonic-gate static int
queue_sysevent(sysevent_t * ev,sysevent_id_t * eid,int flag)16567c478bd9Sstevel@tonic-gate queue_sysevent(sysevent_t *ev, sysevent_id_t *eid, int flag)
16577c478bd9Sstevel@tonic-gate {
16587c478bd9Sstevel@tonic-gate 	log_eventq_t *q;
16597c478bd9Sstevel@tonic-gate 
16607c478bd9Sstevel@tonic-gate 	ASSERT(flag == SE_SLEEP || flag == SE_NOSLEEP);
16617c478bd9Sstevel@tonic-gate 
1662e04145d0Seschrock 	DTRACE_SYSEVENT2(post, evch_bind_t *, NULL, sysevent_impl_t *, ev);
1663e04145d0Seschrock 
16647c478bd9Sstevel@tonic-gate restart:
16657c478bd9Sstevel@tonic-gate 
16667c478bd9Sstevel@tonic-gate 	/* Max Q size exceeded */
16677c478bd9Sstevel@tonic-gate 	mutex_enter(&event_qfull_mutex);
16687c478bd9Sstevel@tonic-gate 	if (sysevent_daemon_init && log_eventq_cnt >= logevent_max_q_sz) {
16697c478bd9Sstevel@tonic-gate 		/*
16707c478bd9Sstevel@tonic-gate 		 * If queue full and transport down, return no transport
16717c478bd9Sstevel@tonic-gate 		 */
16727c478bd9Sstevel@tonic-gate 		if (sysevent_upcall_status != 0) {
16737c478bd9Sstevel@tonic-gate 			mutex_exit(&event_qfull_mutex);
16747c478bd9Sstevel@tonic-gate 			free_packed_event(ev);
16757c478bd9Sstevel@tonic-gate 			eid->eid_seq = UINT64_C(0);
16767c478bd9Sstevel@tonic-gate 			eid->eid_ts = INT64_C(0);
16777c478bd9Sstevel@tonic-gate 			return (SE_NO_TRANSPORT);
16787c478bd9Sstevel@tonic-gate 		}
16797c478bd9Sstevel@tonic-gate 		if (flag == SE_NOSLEEP) {
16807c478bd9Sstevel@tonic-gate 			mutex_exit(&event_qfull_mutex);
16817c478bd9Sstevel@tonic-gate 			free_packed_event(ev);
16827c478bd9Sstevel@tonic-gate 			eid->eid_seq = UINT64_C(0);
16837c478bd9Sstevel@tonic-gate 			eid->eid_ts = INT64_C(0);
16847c478bd9Sstevel@tonic-gate 			return (SE_EQSIZE);
16857c478bd9Sstevel@tonic-gate 		}
16867c478bd9Sstevel@tonic-gate 		event_qfull_blocked++;
16877c478bd9Sstevel@tonic-gate 		cv_wait(&event_qfull_cv, &event_qfull_mutex);
16887c478bd9Sstevel@tonic-gate 		event_qfull_blocked--;
16897c478bd9Sstevel@tonic-gate 		mutex_exit(&event_qfull_mutex);
16907c478bd9Sstevel@tonic-gate 		goto restart;
16917c478bd9Sstevel@tonic-gate 	}
16927c478bd9Sstevel@tonic-gate 	mutex_exit(&event_qfull_mutex);
16937c478bd9Sstevel@tonic-gate 
16947c478bd9Sstevel@tonic-gate 	mutex_enter(&eventq_head_mutex);
16957c478bd9Sstevel@tonic-gate 
16967c478bd9Sstevel@tonic-gate 	/* Time stamp and assign ID */
16977c478bd9Sstevel@tonic-gate 	SE_SEQ(ev) = eid->eid_seq = atomic_add_64_nv(&kernel_event_id,
1698f6e214c7SGavin Maltby 	    (uint64_t)1);
16997c478bd9Sstevel@tonic-gate 	SE_TIME(ev) = eid->eid_ts = gethrtime();
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 	LOG_DEBUG1((CE_CONT, "log_sysevent: class=%d type=%d id=0x%llx\n",
17027c478bd9Sstevel@tonic-gate 	    SE_CLASS(ev), SE_SUBCLASS(ev), (longlong_t)SE_SEQ(ev)));
17037c478bd9Sstevel@tonic-gate 
17047c478bd9Sstevel@tonic-gate 	/*
17057c478bd9Sstevel@tonic-gate 	 * Put event on eventq
17067c478bd9Sstevel@tonic-gate 	 */
17077c478bd9Sstevel@tonic-gate 	q = (log_eventq_t *)((caddr_t)ev - offsetof(log_eventq_t, arg.buf));
17087c478bd9Sstevel@tonic-gate 	q->next = NULL;
17097c478bd9Sstevel@tonic-gate 	if (log_eventq_head == NULL) {
17107c478bd9Sstevel@tonic-gate 		ASSERT(log_eventq_cnt == 0);
17117c478bd9Sstevel@tonic-gate 		log_eventq_head = q;
17127c478bd9Sstevel@tonic-gate 		log_eventq_tail = q;
17137c478bd9Sstevel@tonic-gate 	} else {
17147c478bd9Sstevel@tonic-gate 		if (log_eventq_head == log_eventq_tail) {
17157c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_cnt == 1);
17167c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_head->next == NULL);
17177c478bd9Sstevel@tonic-gate 			ASSERT(log_eventq_tail->next == NULL);
17187c478bd9Sstevel@tonic-gate 		}
17197c478bd9Sstevel@tonic-gate 		log_eventq_tail->next = q;
17207c478bd9Sstevel@tonic-gate 		log_eventq_tail = q;
17217c478bd9Sstevel@tonic-gate 	}
17227c478bd9Sstevel@tonic-gate 	log_eventq_cnt++;
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 	/* Signal event delivery thread */
17257c478bd9Sstevel@tonic-gate 	if (log_eventq_cnt == 1) {
17267c478bd9Sstevel@tonic-gate 		cv_signal(&log_event_cv);
17277c478bd9Sstevel@tonic-gate 	}
17287c478bd9Sstevel@tonic-gate 	mutex_exit(&eventq_head_mutex);
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	return (0);
17317c478bd9Sstevel@tonic-gate }
17327c478bd9Sstevel@tonic-gate 
17337c478bd9Sstevel@tonic-gate /*
17347c478bd9Sstevel@tonic-gate  * log_sysevent - kernel system event logger.
17357c478bd9Sstevel@tonic-gate  *
17367c478bd9Sstevel@tonic-gate  * Returns SE_ENOMEM if buf allocation failed or SE_EQSIZE if the
17377c478bd9Sstevel@tonic-gate  * maximum event queue size will be exceeded
17387c478bd9Sstevel@tonic-gate  * Returns 0 for successfully queued event buffer
17397c478bd9Sstevel@tonic-gate  */
17407c478bd9Sstevel@tonic-gate int
log_sysevent(sysevent_t * ev,int flag,sysevent_id_t * eid)17417c478bd9Sstevel@tonic-gate log_sysevent(sysevent_t *ev, int flag, sysevent_id_t *eid)
17427c478bd9Sstevel@tonic-gate {
17437c478bd9Sstevel@tonic-gate 	sysevent_t *ev_copy;
17447c478bd9Sstevel@tonic-gate 	int rval;
17457c478bd9Sstevel@tonic-gate 
17467c478bd9Sstevel@tonic-gate 	ASSERT(flag == SE_SLEEP || flag == SE_NOSLEEP);
17477c478bd9Sstevel@tonic-gate 	ASSERT(!(flag == SE_SLEEP && servicing_interrupt()));
17487c478bd9Sstevel@tonic-gate 
17497c478bd9Sstevel@tonic-gate 	ev_copy = se_repack(ev, flag);
17507c478bd9Sstevel@tonic-gate 	if (ev_copy == NULL) {
17517c478bd9Sstevel@tonic-gate 		ASSERT(flag == SE_NOSLEEP);
17527c478bd9Sstevel@tonic-gate 		return (SE_ENOMEM);
17537c478bd9Sstevel@tonic-gate 	}
17547c478bd9Sstevel@tonic-gate 	rval = queue_sysevent(ev_copy, eid, flag);
17557c478bd9Sstevel@tonic-gate 	ASSERT(rval == 0 || rval == SE_ENOMEM || rval == SE_EQSIZE ||
1756f6e214c7SGavin Maltby 	    rval == SE_NO_TRANSPORT);
17577c478bd9Sstevel@tonic-gate 	ASSERT(!(flag == SE_SLEEP && (rval == SE_EQSIZE || rval == SE_ENOMEM)));
17587c478bd9Sstevel@tonic-gate 	return (rval);
17597c478bd9Sstevel@tonic-gate }
17607c478bd9Sstevel@tonic-gate 
1761406fc510SToomas Soome /*
1762406fc510SToomas Soome  * Publish EC_DEV_ADD and EC_DEV_REMOVE events from devfsadm to lofi.
1763406fc510SToomas Soome  * This interface is needed to pass device link names to the lofi driver,
1764406fc510SToomas Soome  * to be returned via ioctl() to the lofiadm command.
1765406fc510SToomas Soome  * The problem is, if lofiadm is executed in local zone, there is no
1766406fc510SToomas Soome  * mechanism to announce the device name from the /dev tree back to lofiadm,
1767406fc510SToomas Soome  * as sysevents are not accessible from local zone and devfsadmd is only
1768406fc510SToomas Soome  * running in global zone.
1769406fc510SToomas Soome  *
1770406fc510SToomas Soome  * Delayed/missed events are not fatal for lofi, as the device name returned
1771406fc510SToomas Soome  * to lofiadm is for information and can be re-queried with listing
1772406fc510SToomas Soome  * mappings with lofiadm command.
1773406fc510SToomas Soome  *
1774406fc510SToomas Soome  * Once we have a better method, this interface should be reworked.
1775406fc510SToomas Soome  */
1776406fc510SToomas Soome static void
notify_lofi(sysevent_t * ev)1777406fc510SToomas Soome notify_lofi(sysevent_t *ev)
1778406fc510SToomas Soome {
1779406fc510SToomas Soome 	nvlist_t *nvlist;
17808ae05c10SToomas Soome 	char name[10], *class, *driver;
17818ae05c10SToomas Soome 	int32_t instance;
1782406fc510SToomas Soome 
17838ae05c10SToomas Soome 	class = sysevent_get_class_name(ev);
17848ae05c10SToomas Soome 	if ((strcmp(EC_DEV_ADD, class) != 0) &&
17858ae05c10SToomas Soome 	    (strcmp(EC_DEV_REMOVE, class) != 0)) {
1786406fc510SToomas Soome 		return;
1787406fc510SToomas Soome 	}
1788406fc510SToomas Soome 
1789406fc510SToomas Soome 	(void) sysevent_get_attr_list(ev, &nvlist);
17908ae05c10SToomas Soome 	driver = fnvlist_lookup_string(nvlist, DEV_DRIVER_NAME);
17918ae05c10SToomas Soome 	instance = fnvlist_lookup_int32(nvlist, DEV_INSTANCE);
17928ae05c10SToomas Soome 
17938ae05c10SToomas Soome 	/* We are only interested about lofi. */
17948ae05c10SToomas Soome 	if (strcmp(driver, "lofi") != 0) {
17958ae05c10SToomas Soome 		fnvlist_free(nvlist);
17968ae05c10SToomas Soome 		return;
17978ae05c10SToomas Soome 	}
17988ae05c10SToomas Soome 
17998ae05c10SToomas Soome 	/*
18008ae05c10SToomas Soome 	 * insert or remove device info, then announce the change
18018ae05c10SToomas Soome 	 * via cv_broadcast.
18028ae05c10SToomas Soome 	 */
18038ae05c10SToomas Soome 	(void) snprintf(name, sizeof (name), "%d", instance);
18048ae05c10SToomas Soome 	mutex_enter(&lofi_devlink_cache.ln_lock);
18058ae05c10SToomas Soome 	if (strcmp(class, EC_DEV_ADD) == 0) {
18068ae05c10SToomas Soome 		fnvlist_add_nvlist(lofi_devlink_cache.ln_data, name, nvlist);
18078ae05c10SToomas Soome 	} else {
18088ae05c10SToomas Soome 		/* Can not use fnvlist_remove() as we can get ENOENT. */
18098ae05c10SToomas Soome 		(void) nvlist_remove_all(lofi_devlink_cache.ln_data, name);
18108ae05c10SToomas Soome 	}
18118ae05c10SToomas Soome 	cv_broadcast(&lofi_devlink_cache.ln_cv);
18128ae05c10SToomas Soome 	mutex_exit(&lofi_devlink_cache.ln_lock);
1813406fc510SToomas Soome 
18148ae05c10SToomas Soome 	fnvlist_free(nvlist);
1815406fc510SToomas Soome }
1816406fc510SToomas Soome 
18177c478bd9Sstevel@tonic-gate /*
18187c478bd9Sstevel@tonic-gate  * log_usr_sysevent - user system event logger
18197c478bd9Sstevel@tonic-gate  *			Private to devfsadm and accessible only via
18207c478bd9Sstevel@tonic-gate  *			modctl(MODEVENTS, MODEVENTS_POST_EVENT)
18217c478bd9Sstevel@tonic-gate  */
18227c478bd9Sstevel@tonic-gate int
log_usr_sysevent(sysevent_t * ev,int ev_size,sysevent_id_t * eid)18237c478bd9Sstevel@tonic-gate log_usr_sysevent(sysevent_t *ev, int ev_size, sysevent_id_t *eid)
18247c478bd9Sstevel@tonic-gate {
18257c478bd9Sstevel@tonic-gate 	int ret, copy_sz;
18267c478bd9Sstevel@tonic-gate 	sysevent_t *ev_copy;
18277c478bd9Sstevel@tonic-gate 	sysevent_id_t new_eid;
18287c478bd9Sstevel@tonic-gate 	log_eventq_t *qcopy;
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate 	copy_sz = ev_size + offsetof(log_eventq_t, arg) +
1831f6e214c7SGavin Maltby 	    offsetof(log_event_upcall_arg_t, buf);
18327c478bd9Sstevel@tonic-gate 	qcopy = kmem_zalloc(copy_sz, KM_SLEEP);
18337c478bd9Sstevel@tonic-gate 	ev_copy = (sysevent_t *)&qcopy->arg.buf;
18347c478bd9Sstevel@tonic-gate 
18357c478bd9Sstevel@tonic-gate 	/*
18367c478bd9Sstevel@tonic-gate 	 * Copy event
18377c478bd9Sstevel@tonic-gate 	 */
18387c478bd9Sstevel@tonic-gate 	if (copyin(ev, ev_copy, ev_size) == -1) {
18397c478bd9Sstevel@tonic-gate 		kmem_free(qcopy, copy_sz);
18407c478bd9Sstevel@tonic-gate 		return (EFAULT);
18417c478bd9Sstevel@tonic-gate 	}
18427c478bd9Sstevel@tonic-gate 
1843406fc510SToomas Soome 	notify_lofi(ev_copy);
1844406fc510SToomas Soome 
18457c478bd9Sstevel@tonic-gate 	if ((ret = queue_sysevent(ev_copy, &new_eid, SE_NOSLEEP)) != 0) {
18467c478bd9Sstevel@tonic-gate 		if (ret == SE_ENOMEM || ret == SE_EQSIZE)
18477c478bd9Sstevel@tonic-gate 			return (EAGAIN);
18487c478bd9Sstevel@tonic-gate 		else
18497c478bd9Sstevel@tonic-gate 			return (EIO);
18507c478bd9Sstevel@tonic-gate 	}
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate 	if (copyout(&new_eid, eid, sizeof (sysevent_id_t)) == -1) {
18537c478bd9Sstevel@tonic-gate 		return (EFAULT);
18547c478bd9Sstevel@tonic-gate 	}
18557c478bd9Sstevel@tonic-gate 
18567c478bd9Sstevel@tonic-gate 	return (0);
18577c478bd9Sstevel@tonic-gate }
18587c478bd9Sstevel@tonic-gate 
18597c478bd9Sstevel@tonic-gate 
18607c478bd9Sstevel@tonic-gate 
18617c478bd9Sstevel@tonic-gate int
ddi_log_sysevent(dev_info_t * dip,char * vendor,char * class,char * subclass,nvlist_t * attr_list,sysevent_id_t * eidp,int sleep_flag)18627c478bd9Sstevel@tonic-gate ddi_log_sysevent(
18637c478bd9Sstevel@tonic-gate 	dev_info_t		*dip,
18647c478bd9Sstevel@tonic-gate 	char			*vendor,
18657c478bd9Sstevel@tonic-gate 	char			*class,
18667c478bd9Sstevel@tonic-gate 	char			*subclass,
18677c478bd9Sstevel@tonic-gate 	nvlist_t		*attr_list,
18687c478bd9Sstevel@tonic-gate 	sysevent_id_t		*eidp,
18697c478bd9Sstevel@tonic-gate 	int			sleep_flag)
18707c478bd9Sstevel@tonic-gate {
18717c478bd9Sstevel@tonic-gate 	sysevent_attr_list_t	*list = (sysevent_attr_list_t *)attr_list;
18727c478bd9Sstevel@tonic-gate 	char			pubstr[32];
18737c478bd9Sstevel@tonic-gate 	sysevent_t		*event;
18747c478bd9Sstevel@tonic-gate 	sysevent_id_t		eid;
18757c478bd9Sstevel@tonic-gate 	const char		*drvname;
18767c478bd9Sstevel@tonic-gate 	char			*publisher;
18777c478bd9Sstevel@tonic-gate 	int			se_flag;
18787c478bd9Sstevel@tonic-gate 	int			rval;
18797c478bd9Sstevel@tonic-gate 	int			n;
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate 	if (sleep_flag == DDI_SLEEP && servicing_interrupt()) {
18827c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "!ddi_log_syevent: driver %s%d - cannot queue "
1883f6e214c7SGavin Maltby 		    "event from interrupt context with sleep semantics\n",
1884f6e214c7SGavin Maltby 		    ddi_driver_name(dip), ddi_get_instance(dip));
18857c478bd9Sstevel@tonic-gate 		return (DDI_ECONTEXT);
18867c478bd9Sstevel@tonic-gate 	}
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 	drvname = ddi_driver_name(dip);
18897c478bd9Sstevel@tonic-gate 	n = strlen(vendor) + strlen(drvname) + 7;
18907c478bd9Sstevel@tonic-gate 	if (n < sizeof (pubstr)) {
18917c478bd9Sstevel@tonic-gate 		publisher = pubstr;
18927c478bd9Sstevel@tonic-gate 	} else {
18937c478bd9Sstevel@tonic-gate 		publisher = kmem_alloc(n,
1894f6e214c7SGavin Maltby 		    (sleep_flag == DDI_SLEEP) ? KM_SLEEP : KM_NOSLEEP);
18957c478bd9Sstevel@tonic-gate 		if (publisher == NULL) {
18967c478bd9Sstevel@tonic-gate 			return (DDI_ENOMEM);
18977c478bd9Sstevel@tonic-gate 		}
18987c478bd9Sstevel@tonic-gate 	}
18997c478bd9Sstevel@tonic-gate 	(void) strcpy(publisher, vendor);
19007c478bd9Sstevel@tonic-gate 	(void) strcat(publisher, ":kern:");
19017c478bd9Sstevel@tonic-gate 	(void) strcat(publisher, drvname);
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate 	se_flag = (sleep_flag == DDI_SLEEP) ? SE_SLEEP : SE_NOSLEEP;
19047c478bd9Sstevel@tonic-gate 	event = sysevent_alloc(class, subclass, publisher, se_flag);
19057c478bd9Sstevel@tonic-gate 
19067c478bd9Sstevel@tonic-gate 	if (publisher != pubstr) {
19077c478bd9Sstevel@tonic-gate 		kmem_free(publisher, n);
19087c478bd9Sstevel@tonic-gate 	}
19097c478bd9Sstevel@tonic-gate 
19107c478bd9Sstevel@tonic-gate 	if (event == NULL) {
19117c478bd9Sstevel@tonic-gate 		return (DDI_ENOMEM);
19127c478bd9Sstevel@tonic-gate 	}
19137c478bd9Sstevel@tonic-gate 
19147c478bd9Sstevel@tonic-gate 	if (list) {
19157c478bd9Sstevel@tonic-gate 		(void) sysevent_attach_attributes(event, list);
19167c478bd9Sstevel@tonic-gate 	}
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 	rval = log_sysevent(event, se_flag, &eid);
19197c478bd9Sstevel@tonic-gate 	if (list) {
19207c478bd9Sstevel@tonic-gate 		sysevent_detach_attributes(event);
19217c478bd9Sstevel@tonic-gate 	}
19227c478bd9Sstevel@tonic-gate 	sysevent_free(event);
19237c478bd9Sstevel@tonic-gate 	if (rval == 0) {
19247c478bd9Sstevel@tonic-gate 		if (eidp) {
19257c478bd9Sstevel@tonic-gate 			eidp->eid_seq = eid.eid_seq;
19267c478bd9Sstevel@tonic-gate 			eidp->eid_ts = eid.eid_ts;
19277c478bd9Sstevel@tonic-gate 		}
19287c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
19297c478bd9Sstevel@tonic-gate 	}
19307c478bd9Sstevel@tonic-gate 	if (rval == SE_NO_TRANSPORT)
19317c478bd9Sstevel@tonic-gate 		return (DDI_ETRANSPORT);
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	ASSERT(rval == SE_ENOMEM || rval == SE_EQSIZE);
19347c478bd9Sstevel@tonic-gate 	return ((rval == SE_ENOMEM) ? DDI_ENOMEM : DDI_EBUSY);
19357c478bd9Sstevel@tonic-gate }
19367c478bd9Sstevel@tonic-gate 
19377c478bd9Sstevel@tonic-gate uint64_t
log_sysevent_new_id(void)1938f6e214c7SGavin Maltby log_sysevent_new_id(void)
19397c478bd9Sstevel@tonic-gate {
19407c478bd9Sstevel@tonic-gate 	return (atomic_add_64_nv(&kernel_event_id, (uint64_t)1));
19417c478bd9Sstevel@tonic-gate }
1942