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