xref: /illumos-gate/usr/src/cmd/fm/fmd/common/fmd_subr.c (revision 53f3aea0)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
524db4641Seschrock  * Common Development and Distribution License (the "License").
624db4641Seschrock  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
21d9638e54Smws 
227c478bd9Sstevel@tonic-gate /*
23*53f3aea0SRoger A. Faulkner  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <atomic.h>
287c478bd9Sstevel@tonic-gate #include <alloca.h>
297c478bd9Sstevel@tonic-gate #include <syslog.h>
307c478bd9Sstevel@tonic-gate #include <strings.h>
317c478bd9Sstevel@tonic-gate #include <unistd.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <stdarg.h>
347c478bd9Sstevel@tonic-gate #include <stdio.h>
357c478bd9Sstevel@tonic-gate #include <exacct.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #include <fmd_subr.h>
381bbdaf51Srobj #include <fmd_conf.h>
397c478bd9Sstevel@tonic-gate #include <fmd_error.h>
407c478bd9Sstevel@tonic-gate #include <fmd_thread.h>
417c478bd9Sstevel@tonic-gate #include <fmd_protocol.h>
427c478bd9Sstevel@tonic-gate #include <fmd_event.h>
437c478bd9Sstevel@tonic-gate #include <fmd_dispq.h>
447c478bd9Sstevel@tonic-gate #include <fmd_log.h>
457c478bd9Sstevel@tonic-gate 
467c478bd9Sstevel@tonic-gate #include <fmd.h>
477c478bd9Sstevel@tonic-gate 
487c478bd9Sstevel@tonic-gate int
fmd_assert(const char * expr,const char * file,int line)497c478bd9Sstevel@tonic-gate fmd_assert(const char *expr, const char *file, int line)
507c478bd9Sstevel@tonic-gate {
517c478bd9Sstevel@tonic-gate 	fmd_panic("\"%s\", line %d: assertion failed: %s\n", file, line, expr);
527c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
537c478bd9Sstevel@tonic-gate 	return (0);
547c478bd9Sstevel@tonic-gate }
557c478bd9Sstevel@tonic-gate 
567c478bd9Sstevel@tonic-gate /*
577c478bd9Sstevel@tonic-gate  * To implement a reasonable panic() equivalent for fmd, we atomically bump a
587c478bd9Sstevel@tonic-gate  * global counter of calls to fmd_vpanic() and attempt to print a panic message
597c478bd9Sstevel@tonic-gate  * to stderr and dump core as a result of raising SIGABRT.  This function must
607c478bd9Sstevel@tonic-gate  * not attempt to grab any locks so that it can be called from any fmd code.
617c478bd9Sstevel@tonic-gate  */
627c478bd9Sstevel@tonic-gate void
fmd_vpanic(const char * format,va_list ap)637c478bd9Sstevel@tonic-gate fmd_vpanic(const char *format, va_list ap)
647c478bd9Sstevel@tonic-gate {
657c478bd9Sstevel@tonic-gate 	int oserr = errno;
667c478bd9Sstevel@tonic-gate 	pthread_t tid = pthread_self();
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate 	fmd_thread_t *tp;
697c478bd9Sstevel@tonic-gate 	char msg[BUFSIZ];
707c478bd9Sstevel@tonic-gate 	size_t len;
717c478bd9Sstevel@tonic-gate 
727c478bd9Sstevel@tonic-gate 	/*
737c478bd9Sstevel@tonic-gate 	 * If this is not the first call to fmd_vpanic(), then check d_panictid
747c478bd9Sstevel@tonic-gate 	 * to see if we are the panic thread.  If so, then proceed directly to
757c478bd9Sstevel@tonic-gate 	 * abort() because we have recursively panicked.  If not, then pause()
767c478bd9Sstevel@tonic-gate 	 * indefinitely waiting for the panic thread to terminate the daemon.
777c478bd9Sstevel@tonic-gate 	 */
787c478bd9Sstevel@tonic-gate 	if (atomic_add_32_nv(&fmd.d_panicrefs, 1) != 1) {
797c478bd9Sstevel@tonic-gate 		while (fmd.d_panictid != tid)
807c478bd9Sstevel@tonic-gate 			(void) pause();
817c478bd9Sstevel@tonic-gate 		goto abort;
827c478bd9Sstevel@tonic-gate 	}
837c478bd9Sstevel@tonic-gate 
847c478bd9Sstevel@tonic-gate 	/*
857c478bd9Sstevel@tonic-gate 	 * Use fmd.d_pid != 0 as a cheap test to see if fmd.d_key is valid
867c478bd9Sstevel@tonic-gate 	 * (i.e. we're after fmd_create() and before fmd_destroy()).
877c478bd9Sstevel@tonic-gate 	 */
887c478bd9Sstevel@tonic-gate 	if (fmd.d_pid != 0 && (tp = pthread_getspecific(fmd.d_key)) != NULL)
897c478bd9Sstevel@tonic-gate 		(void) tp->thr_trfunc(tp->thr_trdata, FMD_DBG_ERR, format, ap);
907c478bd9Sstevel@tonic-gate 
917c478bd9Sstevel@tonic-gate 	fmd.d_panicstr = msg;
927c478bd9Sstevel@tonic-gate 	fmd.d_panictid = tid;
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate 	(void) snprintf(msg, sizeof (msg), "%s: ABORT: ",
957c478bd9Sstevel@tonic-gate 	    fmd.d_pname ? fmd.d_pname : "fmd");
967c478bd9Sstevel@tonic-gate 
977c478bd9Sstevel@tonic-gate 	len = strlen(msg);
987c478bd9Sstevel@tonic-gate 	(void) vsnprintf(msg + len, sizeof (msg) - len, format, ap);
997c478bd9Sstevel@tonic-gate 
1007c478bd9Sstevel@tonic-gate 	if (strchr(format, '\n') == NULL) {
1017c478bd9Sstevel@tonic-gate 		len = strlen(msg);
1027c478bd9Sstevel@tonic-gate 		(void) snprintf(msg + len, sizeof (msg) - len, ": %s\n",
1037c478bd9Sstevel@tonic-gate 		    fmd_strerror(oserr));
1047c478bd9Sstevel@tonic-gate 	}
1057c478bd9Sstevel@tonic-gate 
1067c478bd9Sstevel@tonic-gate 	(void) write(STDERR_FILENO, msg, strlen(msg));
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate abort:
1097c478bd9Sstevel@tonic-gate 	abort();
1107c478bd9Sstevel@tonic-gate 	_exit(FMD_EXIT_ERROR);
1117c478bd9Sstevel@tonic-gate }
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate /*PRINTFLIKE1*/
1147c478bd9Sstevel@tonic-gate void
fmd_panic(const char * format,...)1157c478bd9Sstevel@tonic-gate fmd_panic(const char *format, ...)
1167c478bd9Sstevel@tonic-gate {
1177c478bd9Sstevel@tonic-gate 	va_list ap;
1187c478bd9Sstevel@tonic-gate 
1197c478bd9Sstevel@tonic-gate 	va_start(ap, format);
1207c478bd9Sstevel@tonic-gate 	fmd_vpanic(format, ap);
1217c478bd9Sstevel@tonic-gate 	va_end(ap);
1227c478bd9Sstevel@tonic-gate }
1237c478bd9Sstevel@tonic-gate 
1247c478bd9Sstevel@tonic-gate void
fmd_verror(int err,const char * format,va_list ap)1257c478bd9Sstevel@tonic-gate fmd_verror(int err, const char *format, va_list ap)
1267c478bd9Sstevel@tonic-gate {
1277c478bd9Sstevel@tonic-gate 	int oserr = errno;
1287c478bd9Sstevel@tonic-gate 	fmd_thread_t *tp;
1297c478bd9Sstevel@tonic-gate 	nvlist_t *nvl;
1307c478bd9Sstevel@tonic-gate 	fmd_event_t *e;
1317c478bd9Sstevel@tonic-gate 	char *class;
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	if ((tp = pthread_getspecific(fmd.d_key)) != NULL) {
1347c478bd9Sstevel@tonic-gate 		(void) tp->thr_trfunc(tp->thr_trdata, FMD_DBG_ERR, format, ap);
1357c478bd9Sstevel@tonic-gate 		tp->thr_errdepth++;
1367c478bd9Sstevel@tonic-gate 	}
1377c478bd9Sstevel@tonic-gate 
1387c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_lock(&fmd.d_err_lock);
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate 	if (fmd.d_errstats != NULL && err >= EFMD_UNKNOWN && err < EFMD_END)
1417c478bd9Sstevel@tonic-gate 		fmd.d_errstats[err - EFMD_UNKNOWN].fmds_value.ui64++;
1427c478bd9Sstevel@tonic-gate 
1437c478bd9Sstevel@tonic-gate 	if (fmd.d_fg || !fmd.d_running) {
1447c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s: ", fmd.d_pname);
1457c478bd9Sstevel@tonic-gate 		(void) vfprintf(stderr, format, ap);
1467c478bd9Sstevel@tonic-gate 
1477c478bd9Sstevel@tonic-gate 		if (strchr(format, '\n') == NULL)
1487c478bd9Sstevel@tonic-gate 			(void) fprintf(stderr, ": %s\n", fmd_strerror(oserr));
1497c478bd9Sstevel@tonic-gate 	}
1507c478bd9Sstevel@tonic-gate 
1517c478bd9Sstevel@tonic-gate 	(void) pthread_mutex_unlock(&fmd.d_err_lock);
1527c478bd9Sstevel@tonic-gate 
1537c478bd9Sstevel@tonic-gate 	/*
1547c478bd9Sstevel@tonic-gate 	 * If we are at error nesting level one and running in the background,
1557c478bd9Sstevel@tonic-gate 	 * log the error as an ereport to our own log and dispatch it.  If the
1567c478bd9Sstevel@tonic-gate 	 * FMD_LF_BUSY flag is set, we can't attempt to log the event because
1577c478bd9Sstevel@tonic-gate 	 * a replay is running and we will deadlock on ourself in log_append.
1587c478bd9Sstevel@tonic-gate 	 */
15924db4641Seschrock 	if (!fmd.d_fg && fmd.d_running &&
16024db4641Seschrock 	    tp != NULL && tp->thr_errdepth == 1 &&
1617c478bd9Sstevel@tonic-gate 	    (nvl = fmd_protocol_fmderror(err, format, ap)) != NULL) {
1627c478bd9Sstevel@tonic-gate 
1637c478bd9Sstevel@tonic-gate 		(void) nvlist_lookup_string(nvl, FM_CLASS, &class);
1647c478bd9Sstevel@tonic-gate 		e = fmd_event_create(FMD_EVT_PROTOCOL, FMD_HRT_NOW, nvl, class);
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 		(void) pthread_rwlock_rdlock(&fmd.d_log_lock);
1677c478bd9Sstevel@tonic-gate 		if (!(fmd.d_errlog->log_flags & FMD_LF_BUSY))
1687c478bd9Sstevel@tonic-gate 			fmd_log_append(fmd.d_errlog, e, NULL);
1697c478bd9Sstevel@tonic-gate 		(void) pthread_rwlock_unlock(&fmd.d_log_lock);
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 		fmd_dispq_dispatch(fmd.d_disp, e, class);
1727c478bd9Sstevel@tonic-gate 	}
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	if (tp != NULL)
1757c478bd9Sstevel@tonic-gate 		tp->thr_errdepth--;
1767c478bd9Sstevel@tonic-gate 
1771bbdaf51Srobj 	if (err == EFMD_EXIT) {
1781bbdaf51Srobj 		int core = 0;
1791bbdaf51Srobj 
1801bbdaf51Srobj 		(void) fmd_conf_getprop(fmd.d_conf, "core", &core);
1811bbdaf51Srobj 		if (core)
1821bbdaf51Srobj 			fmd_panic("forcing core dump at user request\n");
1831bbdaf51Srobj 
1847c478bd9Sstevel@tonic-gate 		exit(FMD_EXIT_ERROR);
1851bbdaf51Srobj 	}
1867c478bd9Sstevel@tonic-gate }
1877c478bd9Sstevel@tonic-gate 
1887c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
1897c478bd9Sstevel@tonic-gate void
fmd_error(int err,const char * format,...)1907c478bd9Sstevel@tonic-gate fmd_error(int err, const char *format, ...)
1917c478bd9Sstevel@tonic-gate {
1927c478bd9Sstevel@tonic-gate 	va_list ap;
1937c478bd9Sstevel@tonic-gate 
1947c478bd9Sstevel@tonic-gate 	va_start(ap, format);
1957c478bd9Sstevel@tonic-gate 	fmd_verror(err, format, ap);
1967c478bd9Sstevel@tonic-gate 	va_end(ap);
1977c478bd9Sstevel@tonic-gate }
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate void
fmd_vdprintf(int mask,const char * format,va_list ap)2007c478bd9Sstevel@tonic-gate fmd_vdprintf(int mask, const char *format, va_list ap)
2017c478bd9Sstevel@tonic-gate {
2027c478bd9Sstevel@tonic-gate 	fmd_thread_t *tp;
2037c478bd9Sstevel@tonic-gate 	char *msg;
2047c478bd9Sstevel@tonic-gate 	size_t len;
2057c478bd9Sstevel@tonic-gate 	char c;
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	if (!(fmd.d_fmd_debug & mask))
2087c478bd9Sstevel@tonic-gate 		return; /* none of the specified modes are enabled */
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	if ((tp = pthread_getspecific(fmd.d_key)) != NULL)
2117c478bd9Sstevel@tonic-gate 		(void) tp->thr_trfunc(tp->thr_trdata, mask, format, ap);
2127c478bd9Sstevel@tonic-gate 
2137c478bd9Sstevel@tonic-gate 	if (fmd.d_fmd_dbout == 0)
2147c478bd9Sstevel@tonic-gate 		return; /* no debugging output sinks are enabled */
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	len = vsnprintf(&c, 1, format, ap);
2177c478bd9Sstevel@tonic-gate 	msg = alloca(len + 2);
2187c478bd9Sstevel@tonic-gate 	(void) vsnprintf(msg, len + 1, format, ap);
2197c478bd9Sstevel@tonic-gate 
2207c478bd9Sstevel@tonic-gate 	if (msg[len - 1] != '\n')
2217c478bd9Sstevel@tonic-gate 		(void) strcpy(&msg[len], "\n");
2227c478bd9Sstevel@tonic-gate 
2237c478bd9Sstevel@tonic-gate 	if (fmd.d_fmd_dbout & FMD_DBOUT_STDERR) {
2247c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_lock(&fmd.d_err_lock);
2257c478bd9Sstevel@tonic-gate 		(void) fprintf(stderr, "%s DEBUG: %s", fmd.d_pname, msg);
2267c478bd9Sstevel@tonic-gate 		(void) pthread_mutex_unlock(&fmd.d_err_lock);
2277c478bd9Sstevel@tonic-gate 	}
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate 	if (fmd.d_fmd_dbout & FMD_DBOUT_SYSLOG) {
2307c478bd9Sstevel@tonic-gate 		syslog(LOG_DEBUG | LOG_DAEMON,
2317c478bd9Sstevel@tonic-gate 		    "%s DEBUG: %s", fmd.d_pname, msg);
2327c478bd9Sstevel@tonic-gate 	}
2337c478bd9Sstevel@tonic-gate }
2347c478bd9Sstevel@tonic-gate 
2357c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
2367c478bd9Sstevel@tonic-gate void
fmd_dprintf(int mask,const char * format,...)2377c478bd9Sstevel@tonic-gate fmd_dprintf(int mask, const char *format, ...)
2387c478bd9Sstevel@tonic-gate {
2397c478bd9Sstevel@tonic-gate 	va_list ap;
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	va_start(ap, format);
2427c478bd9Sstevel@tonic-gate 	fmd_vdprintf(mask, format, ap);
2437c478bd9Sstevel@tonic-gate 	va_end(ap);
2447c478bd9Sstevel@tonic-gate }
2457c478bd9Sstevel@tonic-gate 
2467c478bd9Sstevel@tonic-gate /*
2477c478bd9Sstevel@tonic-gate  * The fmd_trace.c routines set tr_file and tr_line to NULL and 0 respectively.
2487c478bd9Sstevel@tonic-gate  * If they are invoked from a macro (see <fmd_subr.h>) this tail function is
2497c478bd9Sstevel@tonic-gate  * called as part of the TRACE() macro to fill in these fields from the cpp
2507c478bd9Sstevel@tonic-gate  * macro values for __FILE__ and __LINE__.  No locking is needed because all
2517c478bd9Sstevel@tonic-gate  * trace buffers are allocated separately for each fmd thread.
2527c478bd9Sstevel@tonic-gate  */
2537c478bd9Sstevel@tonic-gate void
fmd_trace_cpp(void * ptr,const char * file,int line)2547c478bd9Sstevel@tonic-gate fmd_trace_cpp(void *ptr, const char *file, int line)
2557c478bd9Sstevel@tonic-gate {
2567c478bd9Sstevel@tonic-gate 	fmd_tracerec_t *trp = ptr;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	if (trp != NULL) {
2597c478bd9Sstevel@tonic-gate 		trp->tr_file = file;
2607c478bd9Sstevel@tonic-gate 		trp->tr_line = line;
2617c478bd9Sstevel@tonic-gate 	}
2627c478bd9Sstevel@tonic-gate }
2637c478bd9Sstevel@tonic-gate 
2647c478bd9Sstevel@tonic-gate /*
2657c478bd9Sstevel@tonic-gate  * The fmd_trace() function is the wrapper for the tracing routines provided in
2667c478bd9Sstevel@tonic-gate  * fmd_trace.c.  It is invoked by the TRACE() macro in <fmd_subr.h>, and uses
2677c478bd9Sstevel@tonic-gate  * the per-thread trace buffer set up in fmd_thread.c to trace debugging info.
2687c478bd9Sstevel@tonic-gate  */
2697c478bd9Sstevel@tonic-gate /*PRINTFLIKE2*/
2707c478bd9Sstevel@tonic-gate void *
fmd_trace(uint_t tag,const char * format,...)271d9638e54Smws fmd_trace(uint_t tag, const char *format, ...)
2727c478bd9Sstevel@tonic-gate {
2737c478bd9Sstevel@tonic-gate 	fmd_thread_t *tp = pthread_getspecific(fmd.d_key);
2747c478bd9Sstevel@tonic-gate 	va_list ap;
2757c478bd9Sstevel@tonic-gate 	void *trp;
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate 	if (tp == NULL)
2787c478bd9Sstevel@tonic-gate 		return (NULL); /* drop trace record if not ready yet */
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate 	va_start(ap, format);
2817c478bd9Sstevel@tonic-gate 	trp = tp->thr_trfunc(tp->thr_trdata, tag, format, ap);
2827c478bd9Sstevel@tonic-gate 	va_end(ap);
2837c478bd9Sstevel@tonic-gate 
2847c478bd9Sstevel@tonic-gate 	return (trp);
2857c478bd9Sstevel@tonic-gate }
2867c478bd9Sstevel@tonic-gate 
2877c478bd9Sstevel@tonic-gate const char *
fmd_ea_strerror(int err)2887c478bd9Sstevel@tonic-gate fmd_ea_strerror(int err)
2897c478bd9Sstevel@tonic-gate {
2907c478bd9Sstevel@tonic-gate 	switch (err) {
2917c478bd9Sstevel@tonic-gate 	case EXR_OK:		return ("no exacct error");
2927c478bd9Sstevel@tonic-gate 	case EXR_SYSCALL_FAIL:	return (fmd_strerror(errno));
2937c478bd9Sstevel@tonic-gate 	case EXR_CORRUPT_FILE:	return ("file corruption detected");
2947c478bd9Sstevel@tonic-gate 	case EXR_EOF:		return ("end-of-file reached");
2957c478bd9Sstevel@tonic-gate 	case EXR_NO_CREATOR:	return ("creator tag mismatch");
2967c478bd9Sstevel@tonic-gate 	case EXR_INVALID_BUF:	return ("invalid unpack buffer");
2977c478bd9Sstevel@tonic-gate 	case EXR_NOTSUPP:	return ("exacct operation not supported");
2987c478bd9Sstevel@tonic-gate 	case EXR_UNKN_VERSION:	return ("unsupported exacct file version");
2997c478bd9Sstevel@tonic-gate 	case EXR_INVALID_OBJ:	return ("invalid exacct object");
3007c478bd9Sstevel@tonic-gate 	default:		return ("unknown exacct error");
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate }
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate /*
3057c478bd9Sstevel@tonic-gate  * Create a local ENA value for fmd-generated ereports.  We use ENA Format 1
3067c478bd9Sstevel@tonic-gate  * with the low bits of gethrtime() and pthread_self() as the processor ID.
3077c478bd9Sstevel@tonic-gate  */
3087c478bd9Sstevel@tonic-gate uint64_t
fmd_ena(void)3097c478bd9Sstevel@tonic-gate fmd_ena(void)
3107c478bd9Sstevel@tonic-gate {
3117c478bd9Sstevel@tonic-gate 	hrtime_t hrt = fmd_time_gethrtime();
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 	return ((uint64_t)((FM_ENA_FMT1 & ENA_FORMAT_MASK) |
3147c478bd9Sstevel@tonic-gate 	    ((pthread_self() << ENA_FMT1_CPUID_SHFT) & ENA_FMT1_CPUID_MASK) |
3157c478bd9Sstevel@tonic-gate 	    ((hrt << ENA_FMT1_TIME_SHFT) & ENA_FMT1_TIME_MASK)));
3167c478bd9Sstevel@tonic-gate }
317d9638e54Smws 
318d9638e54Smws /*
319d9638e54Smws  * fmd_ntz32() computes the number of trailing zeroes.  The algorithm here is
320d9638e54Smws  * from "Hacker's Delight" by Henry Warren, Jr.
321d9638e54Smws  */
322d9638e54Smws uint32_t
fmd_ntz32(uint32_t x)323d9638e54Smws fmd_ntz32(uint32_t x)
324d9638e54Smws {
325d9638e54Smws 	uint_t n = 1;
326d9638e54Smws 
327d9638e54Smws 	if (x == 0)
328d9638e54Smws 		return (32);
329d9638e54Smws 
330d9638e54Smws 	if ((x & 0xFFFF) == 0) {
331d9638e54Smws 		n += 16;
332d9638e54Smws 		x >>= 16;
333d9638e54Smws 	}
334d9638e54Smws 
335d9638e54Smws 	if ((x & 0xFF) == 0) {
336d9638e54Smws 		n += 8;
337d9638e54Smws 		x >>= 8;
338d9638e54Smws 	}
339d9638e54Smws 
340d9638e54Smws 	if ((x & 0xF) == 0) {
341d9638e54Smws 		n += 4;
342d9638e54Smws 		x >>= 4;
343d9638e54Smws 	}
344d9638e54Smws 
345d9638e54Smws 	if ((x & 0x3) == 0) {
346d9638e54Smws 		n += 2;
347d9638e54Smws 		x >>= 2;
348d9638e54Smws 	}
349d9638e54Smws 
350d9638e54Smws 	return (n - (x & 1));
351d9638e54Smws }
352