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
5*5f25dc2aSgavinm  * Common Development and Distribution License (the "License").
6*5f25dc2aSgavinm  * 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  */
21*5f25dc2aSgavinm 
227c478bd9Sstevel@tonic-gate /*
237aec1d6eScindi  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  * fme.c -- fault management exercise module
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * this module provides the simulated fault management exercise.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <stdio.h>
347c478bd9Sstevel@tonic-gate #include <stdlib.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <strings.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate #include <alloca.h>
397c478bd9Sstevel@tonic-gate #include <libnvpair.h>
407c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h>
417c478bd9Sstevel@tonic-gate #include <fm/fmd_api.h>
427c478bd9Sstevel@tonic-gate #include "alloc.h"
437c478bd9Sstevel@tonic-gate #include "out.h"
447c478bd9Sstevel@tonic-gate #include "stats.h"
457c478bd9Sstevel@tonic-gate #include "stable.h"
467c478bd9Sstevel@tonic-gate #include "literals.h"
477c478bd9Sstevel@tonic-gate #include "lut.h"
487c478bd9Sstevel@tonic-gate #include "tree.h"
497c478bd9Sstevel@tonic-gate #include "ptree.h"
507c478bd9Sstevel@tonic-gate #include "itree.h"
517c478bd9Sstevel@tonic-gate #include "ipath.h"
527c478bd9Sstevel@tonic-gate #include "fme.h"
537c478bd9Sstevel@tonic-gate #include "evnv.h"
547c478bd9Sstevel@tonic-gate #include "eval.h"
557c478bd9Sstevel@tonic-gate #include "config.h"
567c478bd9Sstevel@tonic-gate #include "platform.h"
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* imported from eft.c... */
597c478bd9Sstevel@tonic-gate extern char *Autoclose;
607aec1d6eScindi extern int Dupclose;
617c478bd9Sstevel@tonic-gate extern hrtime_t Hesitate;
627c478bd9Sstevel@tonic-gate extern nv_alloc_t Eft_nv_hdl;
630cc1f05eSjrutt extern int Max_fme;
647aec1d6eScindi extern fmd_hdl_t *Hdl;
657aec1d6eScindi 
667aec1d6eScindi static int Istat_need_save;
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate /* fme under construction is global so we can free it on module abort */
697c478bd9Sstevel@tonic-gate static struct fme *Nfmep;
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate static const char *Undiag_reason;
727c478bd9Sstevel@tonic-gate 
737c478bd9Sstevel@tonic-gate static int Nextid = 0;
747c478bd9Sstevel@tonic-gate 
750cc1f05eSjrutt static int Open_fme_count = 0;	/* Count of open FMEs */
760cc1f05eSjrutt 
777c478bd9Sstevel@tonic-gate /* list of fault management exercises underway */
787c478bd9Sstevel@tonic-gate static struct fme {
797c478bd9Sstevel@tonic-gate 	struct fme *next;		/* next exercise */
807c478bd9Sstevel@tonic-gate 	unsigned long long ull;		/* time when fme was created */
817c478bd9Sstevel@tonic-gate 	int id;				/* FME id */
827c478bd9Sstevel@tonic-gate 	struct cfgdata *cfgdata;	/* full configuration data */
837c478bd9Sstevel@tonic-gate 	struct lut *eventtree;		/* propagation tree for this FME */
847c478bd9Sstevel@tonic-gate 	/*
857c478bd9Sstevel@tonic-gate 	 * The initial error report that created this FME is kept in
867c478bd9Sstevel@tonic-gate 	 * two forms.  e0 points to the instance tree node and is used
877c478bd9Sstevel@tonic-gate 	 * by fme_eval() as the starting point for the inference
887c478bd9Sstevel@tonic-gate 	 * algorithm.  e0r is the event handle FMD passed to us when
897c478bd9Sstevel@tonic-gate 	 * the ereport first arrived and is used when setting timers,
907c478bd9Sstevel@tonic-gate 	 * which are always relative to the time of this initial
917c478bd9Sstevel@tonic-gate 	 * report.
927c478bd9Sstevel@tonic-gate 	 */
937c478bd9Sstevel@tonic-gate 	struct event *e0;
947c478bd9Sstevel@tonic-gate 	fmd_event_t *e0r;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	id_t    timer;			/* for setting an fmd time-out */
977c478bd9Sstevel@tonic-gate 	id_t	htid;			/* for setting hesitation timer */
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	struct event *ecurrent;		/* ereport under consideration */
1007c478bd9Sstevel@tonic-gate 	struct event *suspects;		/* current suspect list */
1017c478bd9Sstevel@tonic-gate 	struct event *psuspects;	/* previous suspect list */
1027c478bd9Sstevel@tonic-gate 	int nsuspects;			/* count of suspects */
1037c478bd9Sstevel@tonic-gate 	int nonfault;			/* zero if all suspects T_FAULT */
1047c478bd9Sstevel@tonic-gate 	int posted_suspects;		/* true if we've posted a diagnosis */
1057c478bd9Sstevel@tonic-gate 	int hesitated;			/* true if we hesitated */
1067c478bd9Sstevel@tonic-gate 	int uniqobs;			/* number of unique events observed */
1077c478bd9Sstevel@tonic-gate 	int peek;			/* just peeking, don't track suspects */
1080cc1f05eSjrutt 	int overflow;			/* true if overflow FME */
1097c478bd9Sstevel@tonic-gate 	enum fme_state {
1107c478bd9Sstevel@tonic-gate 		FME_NOTHING = 5000,	/* not evaluated yet */
1117c478bd9Sstevel@tonic-gate 		FME_WAIT,		/* need to wait for more info */
1127c478bd9Sstevel@tonic-gate 		FME_CREDIBLE,		/* suspect list is credible */
1137aec1d6eScindi 		FME_DISPROVED,		/* no valid suspects found */
1147aec1d6eScindi 		FME_DEFERRED		/* don't know yet (k-count not met) */
1157c478bd9Sstevel@tonic-gate 	} state;
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate 	unsigned long long pull;	/* time passed since created */
1187c478bd9Sstevel@tonic-gate 	unsigned long long wull;	/* wait until this time for re-eval */
1197c478bd9Sstevel@tonic-gate 	struct event *observations;	/* observation list */
1207c478bd9Sstevel@tonic-gate 	struct lut *globals;		/* values of global variables */
1217c478bd9Sstevel@tonic-gate 	/* fmd interfacing */
1227c478bd9Sstevel@tonic-gate 	fmd_hdl_t *hdl;			/* handle for talking with fmd */
1237c478bd9Sstevel@tonic-gate 	fmd_case_t *fmcase;		/* what fmd 'case' we associate with */
1247c478bd9Sstevel@tonic-gate 	/* stats */
1257c478bd9Sstevel@tonic-gate 	struct stats *Rcount;
1267c478bd9Sstevel@tonic-gate 	struct stats *Hcallcount;
1277c478bd9Sstevel@tonic-gate 	struct stats *Rcallcount;
1287c478bd9Sstevel@tonic-gate 	struct stats *Ccallcount;
1297c478bd9Sstevel@tonic-gate 	struct stats *Ecallcount;
1307c478bd9Sstevel@tonic-gate 	struct stats *Tcallcount;
1317c478bd9Sstevel@tonic-gate 	struct stats *Marrowcount;
1327c478bd9Sstevel@tonic-gate 	struct stats *diags;
1337c478bd9Sstevel@tonic-gate } *FMElist, *EFMElist, *ClosedFMEs;
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate static struct case_list {
1367c478bd9Sstevel@tonic-gate 	fmd_case_t *fmcase;
1377c478bd9Sstevel@tonic-gate 	struct case_list *next;
1387c478bd9Sstevel@tonic-gate } *Undiagablecaselist;
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate static void fme_eval(struct fme *fmep, fmd_event_t *ffep);
1417c478bd9Sstevel@tonic-gate static enum fme_state hypothesise(struct fme *fmep, struct event *ep,
1427aec1d6eScindi 	unsigned long long at_latest_by, unsigned long long *pdelay);
1437c478bd9Sstevel@tonic-gate static struct node *eventprop_lookup(struct event *ep, const char *propname);
1447c478bd9Sstevel@tonic-gate static struct node *pathstring2epnamenp(char *path);
1457c478bd9Sstevel@tonic-gate static void publish_undiagnosable(fmd_hdl_t *hdl, fmd_event_t *ffep);
1467c478bd9Sstevel@tonic-gate static void restore_suspects(struct fme *fmep);
1477c478bd9Sstevel@tonic-gate static void save_suspects(struct fme *fmep);
1487c478bd9Sstevel@tonic-gate static void destroy_fme(struct fme *f);
1497c478bd9Sstevel@tonic-gate static void fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep,
1507c478bd9Sstevel@tonic-gate     const char *eventstring, const struct ipath *ipp, nvlist_t *nvl);
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate static struct fme *
1537c478bd9Sstevel@tonic-gate alloc_fme(void)
1547c478bd9Sstevel@tonic-gate {
1557c478bd9Sstevel@tonic-gate 	struct fme *fmep;
1567c478bd9Sstevel@tonic-gate 
1577c478bd9Sstevel@tonic-gate 	fmep = MALLOC(sizeof (*fmep));
1587c478bd9Sstevel@tonic-gate 	bzero(fmep, sizeof (*fmep));
1597c478bd9Sstevel@tonic-gate 	return (fmep);
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate 
1627c478bd9Sstevel@tonic-gate /*
1637c478bd9Sstevel@tonic-gate  * fme_ready -- called when all initialization of the FME (except for
1647c478bd9Sstevel@tonic-gate  *	stats) has completed successfully.  Adds the fme to global lists
1657c478bd9Sstevel@tonic-gate  *	and establishes its stats.
1667c478bd9Sstevel@tonic-gate  */
1677c478bd9Sstevel@tonic-gate static struct fme *
1687c478bd9Sstevel@tonic-gate fme_ready(struct fme *fmep)
1697c478bd9Sstevel@tonic-gate {
1707c478bd9Sstevel@tonic-gate 	char nbuf[100];
1717c478bd9Sstevel@tonic-gate 
1727c478bd9Sstevel@tonic-gate 	Nfmep = NULL;	/* don't need to free this on module abort now */
1737c478bd9Sstevel@tonic-gate 
1747c478bd9Sstevel@tonic-gate 	if (EFMElist) {
1757c478bd9Sstevel@tonic-gate 		EFMElist->next = fmep;
1767c478bd9Sstevel@tonic-gate 		EFMElist = fmep;
1777c478bd9Sstevel@tonic-gate 	} else
1787c478bd9Sstevel@tonic-gate 		FMElist = EFMElist = fmep;
1797c478bd9Sstevel@tonic-gate 
1807c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Rcount", fmep->id);
1817c478bd9Sstevel@tonic-gate 	fmep->Rcount = stats_new_counter(nbuf, "ereports received", 0);
1827c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Hcall", fmep->id);
1837c478bd9Sstevel@tonic-gate 	fmep->Hcallcount = stats_new_counter(nbuf, "calls to hypothesise()", 1);
1847c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Rcall", fmep->id);
1857c478bd9Sstevel@tonic-gate 	fmep->Rcallcount = stats_new_counter(nbuf,
1867c478bd9Sstevel@tonic-gate 	    "calls to requirements_test()", 1);
1877c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Ccall", fmep->id);
1887c478bd9Sstevel@tonic-gate 	fmep->Ccallcount = stats_new_counter(nbuf, "calls to causes_test()", 1);
1897c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Ecall", fmep->id);
1907c478bd9Sstevel@tonic-gate 	fmep->Ecallcount =
1917c478bd9Sstevel@tonic-gate 	    stats_new_counter(nbuf, "calls to effects_test()", 1);
1927c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Tcall", fmep->id);
1937c478bd9Sstevel@tonic-gate 	fmep->Tcallcount = stats_new_counter(nbuf, "calls to triggered()", 1);
1947c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Marrow", fmep->id);
1957c478bd9Sstevel@tonic-gate 	fmep->Marrowcount = stats_new_counter(nbuf,
1967c478bd9Sstevel@tonic-gate 	    "arrows marked by mark_arrows()", 1);
1977c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.diags", fmep->id);
1987c478bd9Sstevel@tonic-gate 	fmep->diags = stats_new_counter(nbuf, "suspect lists diagnosed", 0);
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB2, "newfme: config snapshot contains...");
2017c478bd9Sstevel@tonic-gate 	config_print(O_ALTFP|O_VERB2, fmep->cfgdata->cooked);
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate 	return (fmep);
2047c478bd9Sstevel@tonic-gate }
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate static struct fme *
2077c478bd9Sstevel@tonic-gate newfme(const char *e0class, const struct ipath *e0ipp)
2087c478bd9Sstevel@tonic-gate {
2097c478bd9Sstevel@tonic-gate 	struct cfgdata *cfgdata;
2107c478bd9Sstevel@tonic-gate 
2117c478bd9Sstevel@tonic-gate 	if ((cfgdata = config_snapshot()) == NULL) {
2127c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "newfme: NULL configuration");
2137c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_NOCONF;
2147c478bd9Sstevel@tonic-gate 		return (NULL);
2157c478bd9Sstevel@tonic-gate 	}
2167c478bd9Sstevel@tonic-gate 
2177c478bd9Sstevel@tonic-gate 	Nfmep = alloc_fme();
2187c478bd9Sstevel@tonic-gate 
2197c478bd9Sstevel@tonic-gate 	Nfmep->id = Nextid++;
2207c478bd9Sstevel@tonic-gate 	Nfmep->cfgdata = cfgdata;
2217c478bd9Sstevel@tonic-gate 	Nfmep->posted_suspects = 0;
2227c478bd9Sstevel@tonic-gate 	Nfmep->uniqobs = 0;
2237c478bd9Sstevel@tonic-gate 	Nfmep->state = FME_NOTHING;
2247c478bd9Sstevel@tonic-gate 	Nfmep->pull = 0ULL;
2250cc1f05eSjrutt 	Nfmep->overflow = 0;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	Nfmep->fmcase = NULL;
2287c478bd9Sstevel@tonic-gate 	Nfmep->hdl = NULL;
2297c478bd9Sstevel@tonic-gate 
2307c478bd9Sstevel@tonic-gate 	if ((Nfmep->eventtree = itree_create(cfgdata->cooked)) == NULL) {
2317c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "newfme: NULL instance tree");
2327c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_INSTFAIL;
2337c478bd9Sstevel@tonic-gate 		config_free(cfgdata);
2347c478bd9Sstevel@tonic-gate 		FREE(Nfmep);
2357c478bd9Sstevel@tonic-gate 		Nfmep = NULL;
2367c478bd9Sstevel@tonic-gate 		return (NULL);
2377c478bd9Sstevel@tonic-gate 	}
2387c478bd9Sstevel@tonic-gate 
2397c478bd9Sstevel@tonic-gate 	itree_ptree(O_ALTFP|O_VERB2, Nfmep->eventtree);
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate 	if ((Nfmep->e0 =
2427c478bd9Sstevel@tonic-gate 	    itree_lookup(Nfmep->eventtree, e0class, e0ipp)) == NULL) {
2437c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "newfme: e0 not in instance tree");
2447c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_BADEVENTI;
2457c478bd9Sstevel@tonic-gate 		itree_free(Nfmep->eventtree);
2467c478bd9Sstevel@tonic-gate 		config_free(cfgdata);
2477c478bd9Sstevel@tonic-gate 		FREE(Nfmep);
2487c478bd9Sstevel@tonic-gate 		Nfmep = NULL;
2497c478bd9Sstevel@tonic-gate 		return (NULL);
2507c478bd9Sstevel@tonic-gate 	}
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate 	return (fme_ready(Nfmep));
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate void
2567c478bd9Sstevel@tonic-gate fme_fini(void)
2577c478bd9Sstevel@tonic-gate {
2587c478bd9Sstevel@tonic-gate 	struct fme *sfp, *fp;
2597c478bd9Sstevel@tonic-gate 	struct case_list *ucasep, *nextcasep;
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate 	ucasep = Undiagablecaselist;
2627c478bd9Sstevel@tonic-gate 	while (ucasep != NULL) {
2637c478bd9Sstevel@tonic-gate 		nextcasep = ucasep->next;
2647c478bd9Sstevel@tonic-gate 		FREE(ucasep);
2657c478bd9Sstevel@tonic-gate 		ucasep = nextcasep;
2667c478bd9Sstevel@tonic-gate 	}
2677c478bd9Sstevel@tonic-gate 	Undiagablecaselist = NULL;
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate 	/* clean up closed fmes */
2707c478bd9Sstevel@tonic-gate 	fp = ClosedFMEs;
2717c478bd9Sstevel@tonic-gate 	while (fp != NULL) {
2727c478bd9Sstevel@tonic-gate 		sfp = fp->next;
2737c478bd9Sstevel@tonic-gate 		destroy_fme(fp);
2747c478bd9Sstevel@tonic-gate 		fp = sfp;
2757c478bd9Sstevel@tonic-gate 	}
2767c478bd9Sstevel@tonic-gate 	ClosedFMEs = NULL;
2777c478bd9Sstevel@tonic-gate 
2787c478bd9Sstevel@tonic-gate 	fp = FMElist;
2797c478bd9Sstevel@tonic-gate 	while (fp != NULL) {
2807c478bd9Sstevel@tonic-gate 		sfp = fp->next;
2817c478bd9Sstevel@tonic-gate 		destroy_fme(fp);
2827c478bd9Sstevel@tonic-gate 		fp = sfp;
2837c478bd9Sstevel@tonic-gate 	}
2847c478bd9Sstevel@tonic-gate 	FMElist = EFMElist = NULL;
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate 	/* if we were in the middle of creating an fme, free it now */
2877c478bd9Sstevel@tonic-gate 	if (Nfmep) {
2887c478bd9Sstevel@tonic-gate 		destroy_fme(Nfmep);
2897c478bd9Sstevel@tonic-gate 		Nfmep = NULL;
2907c478bd9Sstevel@tonic-gate 	}
2917c478bd9Sstevel@tonic-gate }
2927c478bd9Sstevel@tonic-gate 
2937c478bd9Sstevel@tonic-gate /*
2947c478bd9Sstevel@tonic-gate  * Allocated space for a buffer name.  20 bytes allows for
2957c478bd9Sstevel@tonic-gate  * a ridiculous 9,999,999 unique observations.
2967c478bd9Sstevel@tonic-gate  */
2977c478bd9Sstevel@tonic-gate #define	OBBUFNMSZ 20
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate /*
3007c478bd9Sstevel@tonic-gate  *  serialize_observation
3017c478bd9Sstevel@tonic-gate  *
3027c478bd9Sstevel@tonic-gate  *  Create a recoverable version of the current observation
3037c478bd9Sstevel@tonic-gate  *  (f->ecurrent).  We keep a serialized version of each unique
3047c478bd9Sstevel@tonic-gate  *  observation in order that we may resume correctly the fme in the
3057c478bd9Sstevel@tonic-gate  *  correct state if eft or fmd crashes and we're restarted.
3067c478bd9Sstevel@tonic-gate  */
3077c478bd9Sstevel@tonic-gate static void
3087c478bd9Sstevel@tonic-gate serialize_observation(struct fme *fp, const char *cls, const struct ipath *ipp)
3097c478bd9Sstevel@tonic-gate {
3107c478bd9Sstevel@tonic-gate 	size_t pkdlen;
3117c478bd9Sstevel@tonic-gate 	char tmpbuf[OBBUFNMSZ];
3127c478bd9Sstevel@tonic-gate 	char *pkd = NULL;
3137c478bd9Sstevel@tonic-gate 	char *estr;
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 	(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", fp->uniqobs);
3167c478bd9Sstevel@tonic-gate 	estr = ipath2str(cls, ipp);
3177c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, tmpbuf, strlen(estr) + 1);
3187c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, tmpbuf, (void *)estr,
3197c478bd9Sstevel@tonic-gate 	    strlen(estr) + 1);
3207c478bd9Sstevel@tonic-gate 	FREE(estr);
3217c478bd9Sstevel@tonic-gate 
3227c478bd9Sstevel@tonic-gate 	if (fp->ecurrent != NULL && fp->ecurrent->nvp != NULL) {
3237c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf,
3247c478bd9Sstevel@tonic-gate 		    OBBUFNMSZ, "observed%d.nvp", fp->uniqobs);
3257c478bd9Sstevel@tonic-gate 		if (nvlist_xpack(fp->ecurrent->nvp,
3267c478bd9Sstevel@tonic-gate 		    &pkd, &pkdlen, NV_ENCODE_XDR, &Eft_nv_hdl) != 0)
3277c478bd9Sstevel@tonic-gate 			out(O_DIE|O_SYS, "pack of observed nvl failed");
3287c478bd9Sstevel@tonic-gate 		fmd_buf_create(fp->hdl, fp->fmcase, tmpbuf, pkdlen);
3297c478bd9Sstevel@tonic-gate 		fmd_buf_write(fp->hdl, fp->fmcase, tmpbuf, (void *)pkd, pkdlen);
3307c478bd9Sstevel@tonic-gate 		FREE(pkd);
3317c478bd9Sstevel@tonic-gate 	}
3327c478bd9Sstevel@tonic-gate 
3337c478bd9Sstevel@tonic-gate 	fp->uniqobs++;
3347c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_NOBS, (void *)&fp->uniqobs,
3357c478bd9Sstevel@tonic-gate 	    sizeof (fp->uniqobs));
3367c478bd9Sstevel@tonic-gate }
3377c478bd9Sstevel@tonic-gate 
3387c478bd9Sstevel@tonic-gate /*
3397c478bd9Sstevel@tonic-gate  *  init_fme_bufs -- We keep several bits of state about an fme for
3407c478bd9Sstevel@tonic-gate  *	use if eft or fmd crashes and we're restarted.
3417c478bd9Sstevel@tonic-gate  */
3427c478bd9Sstevel@tonic-gate static void
3437c478bd9Sstevel@tonic-gate init_fme_bufs(struct fme *fp)
3447c478bd9Sstevel@tonic-gate {
3457c478bd9Sstevel@tonic-gate 	size_t cfglen = fp->cfgdata->nextfree - fp->cfgdata->begin;
3467c478bd9Sstevel@tonic-gate 
3477c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_CFGLEN, sizeof (cfglen));
3487c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_CFGLEN, (void *)&cfglen,
3497c478bd9Sstevel@tonic-gate 	    sizeof (cfglen));
3507c478bd9Sstevel@tonic-gate 	if (cfglen != 0) {
3517c478bd9Sstevel@tonic-gate 		fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_CFG, cfglen);
3527c478bd9Sstevel@tonic-gate 		fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_CFG,
3537c478bd9Sstevel@tonic-gate 		    fp->cfgdata->begin, cfglen);
3547c478bd9Sstevel@tonic-gate 	}
3557c478bd9Sstevel@tonic-gate 
3567c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_PULL, sizeof (fp->pull));
3577c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_PULL, (void *)&fp->pull,
3587c478bd9Sstevel@tonic-gate 	    sizeof (fp->pull));
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_ID, sizeof (fp->id));
3617c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_ID, (void *)&fp->id,
3627c478bd9Sstevel@tonic-gate 	    sizeof (fp->id));
3637c478bd9Sstevel@tonic-gate 
3647c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_NOBS, sizeof (fp->uniqobs));
3657c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_NOBS, (void *)&fp->uniqobs,
3667c478bd9Sstevel@tonic-gate 	    sizeof (fp->uniqobs));
3677c478bd9Sstevel@tonic-gate 
3687c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_POSTD,
3697c478bd9Sstevel@tonic-gate 	    sizeof (fp->posted_suspects));
3707c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_POSTD,
3717c478bd9Sstevel@tonic-gate 	    (void *)&fp->posted_suspects, sizeof (fp->posted_suspects));
3727c478bd9Sstevel@tonic-gate }
3737c478bd9Sstevel@tonic-gate 
3747c478bd9Sstevel@tonic-gate static void
3757c478bd9Sstevel@tonic-gate destroy_fme_bufs(struct fme *fp)
3767c478bd9Sstevel@tonic-gate {
3777c478bd9Sstevel@tonic-gate 	char tmpbuf[OBBUFNMSZ];
3787c478bd9Sstevel@tonic-gate 	int o;
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_CFGLEN);
3817c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_CFG);
3827c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_PULL);
3837c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_ID);
3847c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_POSTD);
3857c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_NOBS);
3867c478bd9Sstevel@tonic-gate 
3877c478bd9Sstevel@tonic-gate 	for (o = 0; o < fp->uniqobs; o++) {
3887c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", o);
3897c478bd9Sstevel@tonic-gate 		fmd_buf_destroy(fp->hdl, fp->fmcase, tmpbuf);
3907c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d.nvp", o);
3917c478bd9Sstevel@tonic-gate 		fmd_buf_destroy(fp->hdl, fp->fmcase, tmpbuf);
3927c478bd9Sstevel@tonic-gate 	}
3937c478bd9Sstevel@tonic-gate }
3947c478bd9Sstevel@tonic-gate 
3957c478bd9Sstevel@tonic-gate /*
3967c478bd9Sstevel@tonic-gate  * reconstitute_observations -- convert a case's serialized observations
3977c478bd9Sstevel@tonic-gate  *	back into struct events.  Returns zero if all observations are
3987c478bd9Sstevel@tonic-gate  *	successfully reconstituted.
3997c478bd9Sstevel@tonic-gate  */
4007c478bd9Sstevel@tonic-gate static int
4017c478bd9Sstevel@tonic-gate reconstitute_observations(struct fme *fmep)
4027c478bd9Sstevel@tonic-gate {
4037c478bd9Sstevel@tonic-gate 	struct event *ep;
4047c478bd9Sstevel@tonic-gate 	struct node *epnamenp = NULL;
4057c478bd9Sstevel@tonic-gate 	size_t pkdlen;
4067c478bd9Sstevel@tonic-gate 	char *pkd = NULL;
4077c478bd9Sstevel@tonic-gate 	char *tmpbuf = alloca(OBBUFNMSZ);
4087c478bd9Sstevel@tonic-gate 	char *sepptr;
4097c478bd9Sstevel@tonic-gate 	char *estr;
4107c478bd9Sstevel@tonic-gate 	int ocnt;
4117c478bd9Sstevel@tonic-gate 	int elen;
4127c478bd9Sstevel@tonic-gate 
4137c478bd9Sstevel@tonic-gate 	for (ocnt = 0; ocnt < fmep->uniqobs; ocnt++) {
4147c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", ocnt);
4157c478bd9Sstevel@tonic-gate 		elen = fmd_buf_size(fmep->hdl, fmep->fmcase, tmpbuf);
4167c478bd9Sstevel@tonic-gate 		if (elen == 0) {
4177c478bd9Sstevel@tonic-gate 			out(O_ALTFP,
4187c478bd9Sstevel@tonic-gate 			    "reconstitute_observation: no %s buffer found.",
4197c478bd9Sstevel@tonic-gate 			    tmpbuf);
4207c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_MISSINGOBS;
4217c478bd9Sstevel@tonic-gate 			break;
4227c478bd9Sstevel@tonic-gate 		}
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 		estr = MALLOC(elen);
4257c478bd9Sstevel@tonic-gate 		fmd_buf_read(fmep->hdl, fmep->fmcase, tmpbuf, estr, elen);
4267c478bd9Sstevel@tonic-gate 		sepptr = strchr(estr, '@');
4277c478bd9Sstevel@tonic-gate 		if (sepptr == NULL) {
4287c478bd9Sstevel@tonic-gate 			out(O_ALTFP,
4297c478bd9Sstevel@tonic-gate 			    "reconstitute_observation: %s: "
4307c478bd9Sstevel@tonic-gate 			    "missing @ separator in %s.",
4317c478bd9Sstevel@tonic-gate 			    tmpbuf, estr);
4327c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_MISSINGPATH;
4337c478bd9Sstevel@tonic-gate 			FREE(estr);
4347c478bd9Sstevel@tonic-gate 			break;
4357c478bd9Sstevel@tonic-gate 		}
4367c478bd9Sstevel@tonic-gate 
4377c478bd9Sstevel@tonic-gate 		*sepptr = '\0';
4387c478bd9Sstevel@tonic-gate 		if ((epnamenp = pathstring2epnamenp(sepptr + 1)) == NULL) {
4397c478bd9Sstevel@tonic-gate 			out(O_ALTFP,
4407c478bd9Sstevel@tonic-gate 			    "reconstitute_observation: %s: "
4417c478bd9Sstevel@tonic-gate 			    "trouble converting path string \"%s\" "
4427c478bd9Sstevel@tonic-gate 			    "to internal representation.",
4437c478bd9Sstevel@tonic-gate 			    tmpbuf, sepptr + 1);
4447c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_MISSINGPATH;
4457c478bd9Sstevel@tonic-gate 			FREE(estr);
4467c478bd9Sstevel@tonic-gate 			break;
4477c478bd9Sstevel@tonic-gate 		}
4487c478bd9Sstevel@tonic-gate 
4497c478bd9Sstevel@tonic-gate 		/* construct the event */
4507c478bd9Sstevel@tonic-gate 		ep = itree_lookup(fmep->eventtree,
4517c478bd9Sstevel@tonic-gate 		    stable(estr), ipath(epnamenp));
4527c478bd9Sstevel@tonic-gate 		if (ep == NULL) {
4537c478bd9Sstevel@tonic-gate 			out(O_ALTFP,
4547c478bd9Sstevel@tonic-gate 			    "reconstitute_observation: %s: "
4557c478bd9Sstevel@tonic-gate 			    "lookup of  \"%s\" in itree failed.",
4567c478bd9Sstevel@tonic-gate 			    tmpbuf, ipath2str(estr, ipath(epnamenp)));
4577c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_BADOBS;
4587c478bd9Sstevel@tonic-gate 			tree_free(epnamenp);
4597c478bd9Sstevel@tonic-gate 			FREE(estr);
4607c478bd9Sstevel@tonic-gate 			break;
4617c478bd9Sstevel@tonic-gate 		}
4627c478bd9Sstevel@tonic-gate 		tree_free(epnamenp);
4637c478bd9Sstevel@tonic-gate 
4647c478bd9Sstevel@tonic-gate 		/*
4657c478bd9Sstevel@tonic-gate 		 * We may or may not have a saved nvlist for the observation
4667c478bd9Sstevel@tonic-gate 		 */
4677c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d.nvp", ocnt);
4687c478bd9Sstevel@tonic-gate 		pkdlen = fmd_buf_size(fmep->hdl, fmep->fmcase, tmpbuf);
4697c478bd9Sstevel@tonic-gate 		if (pkdlen != 0) {
4707c478bd9Sstevel@tonic-gate 			pkd = MALLOC(pkdlen);
4717c478bd9Sstevel@tonic-gate 			fmd_buf_read(fmep->hdl,
4727c478bd9Sstevel@tonic-gate 			    fmep->fmcase, tmpbuf, pkd, pkdlen);
4737aec1d6eScindi 			ASSERT(ep->nvp == NULL);
4747c478bd9Sstevel@tonic-gate 			if (nvlist_xunpack(pkd,
4757c478bd9Sstevel@tonic-gate 			    pkdlen, &ep->nvp, &Eft_nv_hdl) != 0)
4767c478bd9Sstevel@tonic-gate 				out(O_DIE|O_SYS, "pack of observed nvl failed");
4777c478bd9Sstevel@tonic-gate 			FREE(pkd);
4787c478bd9Sstevel@tonic-gate 		}
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate 		if (ocnt == 0)
4817c478bd9Sstevel@tonic-gate 			fmep->e0 = ep;
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 		FREE(estr);
4847c478bd9Sstevel@tonic-gate 		fmep->ecurrent = ep;
4857c478bd9Sstevel@tonic-gate 		ep->count++;
4867c478bd9Sstevel@tonic-gate 
4877c478bd9Sstevel@tonic-gate 		/* link it into list of observations seen */
4887c478bd9Sstevel@tonic-gate 		ep->observations = fmep->observations;
4897c478bd9Sstevel@tonic-gate 		fmep->observations = ep;
4907c478bd9Sstevel@tonic-gate 	}
4917c478bd9Sstevel@tonic-gate 
4927c478bd9Sstevel@tonic-gate 	if (ocnt == fmep->uniqobs) {
4937c478bd9Sstevel@tonic-gate 		(void) fme_ready(fmep);
4947c478bd9Sstevel@tonic-gate 		return (0);
4957c478bd9Sstevel@tonic-gate 	}
4967c478bd9Sstevel@tonic-gate 
4977c478bd9Sstevel@tonic-gate 	return (1);
4987c478bd9Sstevel@tonic-gate }
4997c478bd9Sstevel@tonic-gate 
5007c478bd9Sstevel@tonic-gate /*
5017c478bd9Sstevel@tonic-gate  * restart_fme -- called during eft initialization.  Reconstitutes
5027c478bd9Sstevel@tonic-gate  *	an in-progress fme.
5037c478bd9Sstevel@tonic-gate  */
5047c478bd9Sstevel@tonic-gate void
5057c478bd9Sstevel@tonic-gate fme_restart(fmd_hdl_t *hdl, fmd_case_t *inprogress)
5067c478bd9Sstevel@tonic-gate {
5077c478bd9Sstevel@tonic-gate 	nvlist_t *defect;
5087c478bd9Sstevel@tonic-gate 	struct case_list *bad;
5097c478bd9Sstevel@tonic-gate 	struct fme *fmep;
5107c478bd9Sstevel@tonic-gate 	struct cfgdata *cfgdata = NULL;
5117c478bd9Sstevel@tonic-gate 	size_t rawsz;
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	fmep = alloc_fme();
5147c478bd9Sstevel@tonic-gate 	fmep->fmcase = inprogress;
5157c478bd9Sstevel@tonic-gate 	fmep->hdl = hdl;
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate 	if (fmd_buf_size(hdl, inprogress, WOBUF_CFGLEN) != sizeof (size_t)) {
5187c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: No config data");
5197c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGINFO;
5207c478bd9Sstevel@tonic-gate 		goto badcase;
5217c478bd9Sstevel@tonic-gate 	}
5227c478bd9Sstevel@tonic-gate 	fmd_buf_read(hdl, inprogress, WOBUF_CFGLEN, (void *)&rawsz,
5237c478bd9Sstevel@tonic-gate 	    sizeof (size_t));
5247c478bd9Sstevel@tonic-gate 
5257c478bd9Sstevel@tonic-gate 	if ((fmep->e0r = fmd_case_getprincipal(hdl, inprogress)) == NULL) {
5267c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: No event zero");
5277c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGZERO;
5287c478bd9Sstevel@tonic-gate 		goto badcase;
5297c478bd9Sstevel@tonic-gate 	}
5307c478bd9Sstevel@tonic-gate 
5317c478bd9Sstevel@tonic-gate 	cfgdata = MALLOC(sizeof (struct cfgdata));
5327c478bd9Sstevel@tonic-gate 	cfgdata->cooked = NULL;
5337c478bd9Sstevel@tonic-gate 	cfgdata->devcache = NULL;
5347c478bd9Sstevel@tonic-gate 	cfgdata->cpucache = NULL;
5357c478bd9Sstevel@tonic-gate 	cfgdata->refcnt = 1;
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	if (rawsz > 0) {
5387c478bd9Sstevel@tonic-gate 		if (fmd_buf_size(hdl, inprogress, WOBUF_CFG) != rawsz) {
5397c478bd9Sstevel@tonic-gate 			out(O_ALTFP, "restart_fme: Config data size mismatch");
5407c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_CFGMISMATCH;
5417c478bd9Sstevel@tonic-gate 			goto badcase;
5427c478bd9Sstevel@tonic-gate 		}
5437c478bd9Sstevel@tonic-gate 		cfgdata->begin = MALLOC(rawsz);
5447c478bd9Sstevel@tonic-gate 		cfgdata->end = cfgdata->nextfree = cfgdata->begin + rawsz;
5457c478bd9Sstevel@tonic-gate 		fmd_buf_read(hdl,
5467c478bd9Sstevel@tonic-gate 		    inprogress, WOBUF_CFG, cfgdata->begin, rawsz);
5477c478bd9Sstevel@tonic-gate 	} else {
5487c478bd9Sstevel@tonic-gate 		cfgdata->begin = cfgdata->end = cfgdata->nextfree = NULL;
5497c478bd9Sstevel@tonic-gate 	}
5507c478bd9Sstevel@tonic-gate 	fmep->cfgdata = cfgdata;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	config_cook(cfgdata);
5537c478bd9Sstevel@tonic-gate 	if ((fmep->eventtree = itree_create(cfgdata->cooked)) == NULL) {
5547c478bd9Sstevel@tonic-gate 		/* case not properly saved or irretrievable */
5557c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: NULL instance tree");
5567c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_INSTFAIL;
5577c478bd9Sstevel@tonic-gate 		goto badcase;
5587c478bd9Sstevel@tonic-gate 	}
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate 	itree_ptree(O_ALTFP|O_VERB2, fmep->eventtree);
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	if (fmd_buf_size(hdl, inprogress, WOBUF_PULL) == 0) {
5637c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: no saved wait time");
5647c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGINFO;
5657c478bd9Sstevel@tonic-gate 		goto badcase;
5667c478bd9Sstevel@tonic-gate 	} else {
5677c478bd9Sstevel@tonic-gate 		fmd_buf_read(hdl, inprogress, WOBUF_PULL, (void *)&fmep->pull,
5687c478bd9Sstevel@tonic-gate 		    sizeof (fmep->pull));
5697c478bd9Sstevel@tonic-gate 	}
5707c478bd9Sstevel@tonic-gate 
5717c478bd9Sstevel@tonic-gate 	if (fmd_buf_size(hdl, inprogress, WOBUF_POSTD) == 0) {
5727c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: no saved posted status");
5737c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGINFO;
5747c478bd9Sstevel@tonic-gate 		goto badcase;
5757c478bd9Sstevel@tonic-gate 	} else {
5767c478bd9Sstevel@tonic-gate 		fmd_buf_read(hdl, inprogress, WOBUF_POSTD,
5777c478bd9Sstevel@tonic-gate 		    (void *)&fmep->posted_suspects,
5787c478bd9Sstevel@tonic-gate 		    sizeof (fmep->posted_suspects));
5797c478bd9Sstevel@tonic-gate 	}
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	if (fmd_buf_size(hdl, inprogress, WOBUF_ID) == 0) {
5827c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: no saved id");
5837c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGINFO;
5847c478bd9Sstevel@tonic-gate 		goto badcase;
5857c478bd9Sstevel@tonic-gate 	} else {
5867c478bd9Sstevel@tonic-gate 		fmd_buf_read(hdl, inprogress, WOBUF_ID, (void *)&fmep->id,
5877c478bd9Sstevel@tonic-gate 		    sizeof (fmep->id));
5887c478bd9Sstevel@tonic-gate 	}
5897c478bd9Sstevel@tonic-gate 	if (Nextid <= fmep->id)
5907c478bd9Sstevel@tonic-gate 		Nextid = fmep->id + 1;
5917c478bd9Sstevel@tonic-gate 
5927c478bd9Sstevel@tonic-gate 	if (fmd_buf_size(hdl, inprogress, WOBUF_NOBS) == 0) {
5937c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: no count of observations");
5947c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGINFO;
5957c478bd9Sstevel@tonic-gate 		goto badcase;
5967c478bd9Sstevel@tonic-gate 	} else {
5977c478bd9Sstevel@tonic-gate 		fmd_buf_read(hdl, inprogress, WOBUF_NOBS,
5987c478bd9Sstevel@tonic-gate 		    (void *)&fmep->uniqobs, sizeof (fmep->uniqobs));
5997c478bd9Sstevel@tonic-gate 	}
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate 	if (reconstitute_observations(fmep) != 0)
6027c478bd9Sstevel@tonic-gate 		goto badcase;
6037c478bd9Sstevel@tonic-gate 
6040cc1f05eSjrutt 	Open_fme_count++;
6050cc1f05eSjrutt 
6067c478bd9Sstevel@tonic-gate 	/* give the diagnosis algorithm a shot at the new FME state */
6077c478bd9Sstevel@tonic-gate 	fme_eval(fmep, NULL);
6087c478bd9Sstevel@tonic-gate 	return;
6097c478bd9Sstevel@tonic-gate 
6107c478bd9Sstevel@tonic-gate badcase:
6117c478bd9Sstevel@tonic-gate 	if (fmep->eventtree != NULL)
6127c478bd9Sstevel@tonic-gate 		itree_free(fmep->eventtree);
6137c478bd9Sstevel@tonic-gate 	config_free(cfgdata);
6147c478bd9Sstevel@tonic-gate 	destroy_fme_bufs(fmep);
6157c478bd9Sstevel@tonic-gate 	FREE(fmep);
6167c478bd9Sstevel@tonic-gate 
6177c478bd9Sstevel@tonic-gate 	/*
6187c478bd9Sstevel@tonic-gate 	 * Since we're unable to restart the case, add it to the undiagable
6197c478bd9Sstevel@tonic-gate 	 * list and solve and close it as appropriate.
6207c478bd9Sstevel@tonic-gate 	 */
6217c478bd9Sstevel@tonic-gate 	bad = MALLOC(sizeof (struct case_list));
6227c478bd9Sstevel@tonic-gate 	bad->next = NULL;
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	if (Undiagablecaselist != NULL)
6257c478bd9Sstevel@tonic-gate 		bad->next = Undiagablecaselist;
6267c478bd9Sstevel@tonic-gate 	Undiagablecaselist = bad;
6277c478bd9Sstevel@tonic-gate 	bad->fmcase = inprogress;
6287c478bd9Sstevel@tonic-gate 
6297c478bd9Sstevel@tonic-gate 	out(O_ALTFP, "[case %s (unable to restart), ",
6307c478bd9Sstevel@tonic-gate 	    fmd_case_uuid(hdl, bad->fmcase));
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	if (fmd_case_solved(hdl, bad->fmcase)) {
6337c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "already solved, ");
6347c478bd9Sstevel@tonic-gate 	} else {
6357c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "solving, ");
6367c478bd9Sstevel@tonic-gate 		defect = fmd_nvl_create_fault(hdl, UNDIAGNOSABLE_DEFECT, 100,
6377c478bd9Sstevel@tonic-gate 		    NULL, NULL, NULL);
6387c478bd9Sstevel@tonic-gate 		if (Undiag_reason != NULL)
6397c478bd9Sstevel@tonic-gate 			(void) nvlist_add_string(defect,
6407c478bd9Sstevel@tonic-gate 			    UNDIAG_REASON, Undiag_reason);
6417c478bd9Sstevel@tonic-gate 		fmd_case_add_suspect(hdl, bad->fmcase, defect);
6427c478bd9Sstevel@tonic-gate 		fmd_case_solve(hdl, bad->fmcase);
6437c478bd9Sstevel@tonic-gate 	}
6447c478bd9Sstevel@tonic-gate 
6457c478bd9Sstevel@tonic-gate 	if (fmd_case_closed(hdl, bad->fmcase)) {
6467c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "already closed ]");
6477c478bd9Sstevel@tonic-gate 	} else {
6487c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "closing ]");
6497c478bd9Sstevel@tonic-gate 		fmd_case_close(hdl, bad->fmcase);
6507c478bd9Sstevel@tonic-gate 	}
6517c478bd9Sstevel@tonic-gate }
6527c478bd9Sstevel@tonic-gate 
6537aec1d6eScindi /*ARGSUSED*/
6547aec1d6eScindi static void
6557aec1d6eScindi globals_destructor(void *left, void *right, void *arg)
6567aec1d6eScindi {
6577aec1d6eScindi 	struct evalue *evp = (struct evalue *)right;
6587aec1d6eScindi 	if (evp->t == NODEPTR)
6597aec1d6eScindi 		tree_free((struct node *)evp->v);
6607aec1d6eScindi 	evp->v = NULL;
6617aec1d6eScindi 	FREE(evp);
6627aec1d6eScindi }
6637aec1d6eScindi 
6647c478bd9Sstevel@tonic-gate void
6657c478bd9Sstevel@tonic-gate destroy_fme(struct fme *f)
6667c478bd9Sstevel@tonic-gate {
6677c478bd9Sstevel@tonic-gate 	stats_delete(f->Rcount);
6687c478bd9Sstevel@tonic-gate 	stats_delete(f->Hcallcount);
6697c478bd9Sstevel@tonic-gate 	stats_delete(f->Rcallcount);
6707c478bd9Sstevel@tonic-gate 	stats_delete(f->Ccallcount);
6717c478bd9Sstevel@tonic-gate 	stats_delete(f->Ecallcount);
6727c478bd9Sstevel@tonic-gate 	stats_delete(f->Tcallcount);
6737c478bd9Sstevel@tonic-gate 	stats_delete(f->Marrowcount);
6747c478bd9Sstevel@tonic-gate 	stats_delete(f->diags);
6757c478bd9Sstevel@tonic-gate 
6767c478bd9Sstevel@tonic-gate 	itree_free(f->eventtree);
6777c478bd9Sstevel@tonic-gate 	config_free(f->cfgdata);
6787aec1d6eScindi 	lut_free(f->globals, globals_destructor, NULL);
6797c478bd9Sstevel@tonic-gate 	FREE(f);
6807c478bd9Sstevel@tonic-gate }
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate static const char *
6837c478bd9Sstevel@tonic-gate fme_state2str(enum fme_state s)
6847c478bd9Sstevel@tonic-gate {
6857c478bd9Sstevel@tonic-gate 	switch (s) {
6867c478bd9Sstevel@tonic-gate 	case FME_NOTHING:	return ("NOTHING");
6877c478bd9Sstevel@tonic-gate 	case FME_WAIT:		return ("WAIT");
6887c478bd9Sstevel@tonic-gate 	case FME_CREDIBLE:	return ("CREDIBLE");
6897c478bd9Sstevel@tonic-gate 	case FME_DISPROVED:	return ("DISPROVED");
6907aec1d6eScindi 	case FME_DEFERRED:	return ("DEFERRED");
6917c478bd9Sstevel@tonic-gate 	default:		return ("UNKNOWN");
6927c478bd9Sstevel@tonic-gate 	}
6937c478bd9Sstevel@tonic-gate }
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate static int
6967c478bd9Sstevel@tonic-gate is_problem(enum nametype t)
6977c478bd9Sstevel@tonic-gate {
6987c478bd9Sstevel@tonic-gate 	return (t == N_FAULT || t == N_DEFECT || t == N_UPSET);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate static int
7027c478bd9Sstevel@tonic-gate is_fault(enum nametype t)
7037c478bd9Sstevel@tonic-gate {
7047c478bd9Sstevel@tonic-gate 	return (t == N_FAULT);
7057c478bd9Sstevel@tonic-gate }
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate static int
7087c478bd9Sstevel@tonic-gate is_defect(enum nametype t)
7097c478bd9Sstevel@tonic-gate {
7107c478bd9Sstevel@tonic-gate 	return (t == N_DEFECT);
7117c478bd9Sstevel@tonic-gate }
7127c478bd9Sstevel@tonic-gate 
7137c478bd9Sstevel@tonic-gate static int
7147c478bd9Sstevel@tonic-gate is_upset(enum nametype t)
7157c478bd9Sstevel@tonic-gate {
7167c478bd9Sstevel@tonic-gate 	return (t == N_UPSET);
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate static void
7207c478bd9Sstevel@tonic-gate fme_print(int flags, struct fme *fmep)
7217c478bd9Sstevel@tonic-gate {
7227c478bd9Sstevel@tonic-gate 	struct event *ep;
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	out(flags, "Fault Management Exercise %d", fmep->id);
7257c478bd9Sstevel@tonic-gate 	out(flags, "\t       State: %s", fme_state2str(fmep->state));
7267c478bd9Sstevel@tonic-gate 	out(flags|O_NONL, "\t  Start time: ");
7277c478bd9Sstevel@tonic-gate 	ptree_timeval(flags|O_NONL, &fmep->ull);
7287c478bd9Sstevel@tonic-gate 	out(flags, NULL);
7297c478bd9Sstevel@tonic-gate 	if (fmep->wull) {
7307c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, "\t   Wait time: ");
7317c478bd9Sstevel@tonic-gate 		ptree_timeval(flags|O_NONL, &fmep->wull);
7327c478bd9Sstevel@tonic-gate 		out(flags, NULL);
7337c478bd9Sstevel@tonic-gate 	}
7347c478bd9Sstevel@tonic-gate 	out(flags|O_NONL, "\t          E0: ");
7357c478bd9Sstevel@tonic-gate 	if (fmep->e0)
7367c478bd9Sstevel@tonic-gate 		itree_pevent_brief(flags|O_NONL, fmep->e0);
7377c478bd9Sstevel@tonic-gate 	else
7387c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, "NULL");
7397c478bd9Sstevel@tonic-gate 	out(flags, NULL);
7407c478bd9Sstevel@tonic-gate 	out(flags|O_NONL, "\tObservations:");
7417c478bd9Sstevel@tonic-gate 	for (ep = fmep->observations; ep; ep = ep->observations) {
7427c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, " ");
7437c478bd9Sstevel@tonic-gate 		itree_pevent_brief(flags|O_NONL, ep);
7447c478bd9Sstevel@tonic-gate 	}
7457c478bd9Sstevel@tonic-gate 	out(flags, NULL);
7467c478bd9Sstevel@tonic-gate 	out(flags|O_NONL, "\tSuspect list:");
7477c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = ep->suspects) {
7487c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, " ");
7497c478bd9Sstevel@tonic-gate 		itree_pevent_brief(flags|O_NONL, ep);
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 	out(flags, NULL);
7527c478bd9Sstevel@tonic-gate 	out(flags|O_VERB2, "\t        Tree:");
7537c478bd9Sstevel@tonic-gate 	itree_ptree(flags|O_VERB2, fmep->eventtree);
7547c478bd9Sstevel@tonic-gate }
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate static struct node *
7577c478bd9Sstevel@tonic-gate pathstring2epnamenp(char *path)
7587c478bd9Sstevel@tonic-gate {
7597c478bd9Sstevel@tonic-gate 	char *sep = "/";
7607c478bd9Sstevel@tonic-gate 	struct node *ret;
7617c478bd9Sstevel@tonic-gate 	char *ptr;
7627c478bd9Sstevel@tonic-gate 
7637c478bd9Sstevel@tonic-gate 	if ((ptr = strtok(path, sep)) == NULL)
7647c478bd9Sstevel@tonic-gate 		out(O_DIE, "pathstring2epnamenp: invalid empty class");
7657c478bd9Sstevel@tonic-gate 
7667c478bd9Sstevel@tonic-gate 	ret = tree_iname(stable(ptr), NULL, 0);
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	while ((ptr = strtok(NULL, sep)) != NULL)
7697c478bd9Sstevel@tonic-gate 		ret = tree_name_append(ret,
7707c478bd9Sstevel@tonic-gate 		    tree_iname(stable(ptr), NULL, 0));
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	return (ret);
7737c478bd9Sstevel@tonic-gate }
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate /*
7767c478bd9Sstevel@tonic-gate  * for a given upset sp, increment the corresponding SERD engine.  if the
7777c478bd9Sstevel@tonic-gate  * SERD engine trips, return the ename and ipp of the resulting ereport.
7787c478bd9Sstevel@tonic-gate  * returns true if engine tripped and *enamep and *ippp were filled in.
7797c478bd9Sstevel@tonic-gate  */
7807c478bd9Sstevel@tonic-gate static int
7817aec1d6eScindi serd_eval(struct fme *fmep, fmd_hdl_t *hdl, fmd_event_t *ffep,
7827aec1d6eScindi     fmd_case_t *fmcase, struct event *sp, const char **enamep,
7837aec1d6eScindi     const struct ipath **ippp)
7847c478bd9Sstevel@tonic-gate {
7857c478bd9Sstevel@tonic-gate 	struct node *serdinst;
7867c478bd9Sstevel@tonic-gate 	char *serdname;
7877aec1d6eScindi 	struct node *nid;
7887c478bd9Sstevel@tonic-gate 
7897c478bd9Sstevel@tonic-gate 	ASSERT(sp->t == N_UPSET);
7907c478bd9Sstevel@tonic-gate 	ASSERT(ffep != NULL);
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	/*
7937c478bd9Sstevel@tonic-gate 	 * obtain instanced SERD engine from the upset sp.  from this
7947c478bd9Sstevel@tonic-gate 	 * derive serdname, the string used to identify the SERD engine.
7957c478bd9Sstevel@tonic-gate 	 */
7967c478bd9Sstevel@tonic-gate 	serdinst = eventprop_lookup(sp, L_engine);
7977c478bd9Sstevel@tonic-gate 
7987c478bd9Sstevel@tonic-gate 	if (serdinst == NULL)
7997c478bd9Sstevel@tonic-gate 		return (NULL);
8007c478bd9Sstevel@tonic-gate 
8017c478bd9Sstevel@tonic-gate 	serdname = ipath2str(serdinst->u.stmt.np->u.event.ename->u.name.s,
8027c478bd9Sstevel@tonic-gate 	    ipath(serdinst->u.stmt.np->u.event.epname));
8037c478bd9Sstevel@tonic-gate 
8047aec1d6eScindi 	/* handle serd engine "id" property, if there is one */
8057aec1d6eScindi 	if ((nid =
8067aec1d6eScindi 	    lut_lookup(serdinst->u.stmt.lutp, (void *)L_id, NULL)) != NULL) {
8077aec1d6eScindi 		struct evalue *gval;
8087aec1d6eScindi 		char suffixbuf[200];
8097aec1d6eScindi 		char *suffix;
8107aec1d6eScindi 		char *nserdname;
8117aec1d6eScindi 		size_t nname;
8127aec1d6eScindi 
8137aec1d6eScindi 		out(O_ALTFP|O_NONL, "serd \"%s\" id: ", serdname);
8147aec1d6eScindi 		ptree_name_iter(O_ALTFP|O_NONL, nid);
8157aec1d6eScindi 
8167aec1d6eScindi 		ASSERTinfo(nid->t == T_GLOBID, ptree_nodetype2str(nid->t));
8177aec1d6eScindi 
8187aec1d6eScindi 		if ((gval = lut_lookup(fmep->globals,
8197aec1d6eScindi 		    (void *)nid->u.globid.s, NULL)) == NULL) {
8207aec1d6eScindi 			out(O_ALTFP, " undefined");
8217aec1d6eScindi 		} else if (gval->t == UINT64) {
8227aec1d6eScindi 			out(O_ALTFP, " %llu", gval->v);
8237aec1d6eScindi 			(void) sprintf(suffixbuf, "%llu", gval->v);
8247aec1d6eScindi 			suffix = suffixbuf;
8257aec1d6eScindi 		} else {
8267aec1d6eScindi 			out(O_ALTFP, " \"%s\"", (char *)gval->v);
8277aec1d6eScindi 			suffix = (char *)gval->v;
8287aec1d6eScindi 		}
8297aec1d6eScindi 
8307aec1d6eScindi 		nname = strlen(serdname) + strlen(suffix) + 2;
8317aec1d6eScindi 		nserdname = MALLOC(nname);
8327aec1d6eScindi 		(void) snprintf(nserdname, nname, "%s:%s", serdname, suffix);
8337aec1d6eScindi 		FREE(serdname);
8347aec1d6eScindi 		serdname = nserdname;
8357aec1d6eScindi 	}
8367aec1d6eScindi 
8377c478bd9Sstevel@tonic-gate 	if (!fmd_serd_exists(hdl, serdname)) {
8387c478bd9Sstevel@tonic-gate 		struct node *nN, *nT;
8397c478bd9Sstevel@tonic-gate 
8407c478bd9Sstevel@tonic-gate 		/* no SERD engine yet, so create it */
8417c478bd9Sstevel@tonic-gate 		nN = lut_lookup(serdinst->u.stmt.lutp, (void *)L_N, NULL);
8427c478bd9Sstevel@tonic-gate 		nT = lut_lookup(serdinst->u.stmt.lutp, (void *)L_T, NULL);
8437c478bd9Sstevel@tonic-gate 
8447c478bd9Sstevel@tonic-gate 		ASSERT(nN->t == T_NUM);
8457c478bd9Sstevel@tonic-gate 		ASSERT(nT->t == T_TIMEVAL);
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 		fmd_serd_create(hdl, serdname, (uint_t)nN->u.ull,
8487c478bd9Sstevel@tonic-gate 		    (hrtime_t)nT->u.ull);
8497c478bd9Sstevel@tonic-gate 	}
8507c478bd9Sstevel@tonic-gate 
8517c478bd9Sstevel@tonic-gate 
8527c478bd9Sstevel@tonic-gate 	/*
8537c478bd9Sstevel@tonic-gate 	 * increment SERD engine.  if engine fires, reset serd
8547c478bd9Sstevel@tonic-gate 	 * engine and return trip_strcode
8557c478bd9Sstevel@tonic-gate 	 */
8567c478bd9Sstevel@tonic-gate 	if (fmd_serd_record(hdl, serdname, ffep)) {
8577c478bd9Sstevel@tonic-gate 		struct node *tripinst = lut_lookup(serdinst->u.stmt.lutp,
8587c478bd9Sstevel@tonic-gate 		    (void *)L_trip, NULL);
8597c478bd9Sstevel@tonic-gate 
8607c478bd9Sstevel@tonic-gate 		ASSERT(tripinst != NULL);
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 		*enamep = tripinst->u.event.ename->u.name.s;
8637c478bd9Sstevel@tonic-gate 		*ippp = ipath(tripinst->u.event.epname);
8647c478bd9Sstevel@tonic-gate 
8653e8d8e18Sdb 		fmd_case_add_serd(hdl, fmcase, serdname);
8667c478bd9Sstevel@tonic-gate 		fmd_serd_reset(hdl, serdname);
8677c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "[engine fired: %s, sending: ", serdname);
8687c478bd9Sstevel@tonic-gate 		ipath_print(O_ALTFP|O_NONL, *enamep, *ippp);
8697c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "]");
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 		FREE(serdname);
8727c478bd9Sstevel@tonic-gate 		return (1);
8737c478bd9Sstevel@tonic-gate 	}
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 	FREE(serdname);
8767c478bd9Sstevel@tonic-gate 	return (0);
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate /*
8807c478bd9Sstevel@tonic-gate  * search a suspect list for upsets.  feed each upset to serd_eval() and
8817c478bd9Sstevel@tonic-gate  * build up tripped[], an array of ereports produced by the firing of
8827c478bd9Sstevel@tonic-gate  * any SERD engines.  then feed each ereport back into
8837c478bd9Sstevel@tonic-gate  * fme_receive_report().
8847c478bd9Sstevel@tonic-gate  *
8857c478bd9Sstevel@tonic-gate  * returns ntrip, the number of these ereports produced.
8867c478bd9Sstevel@tonic-gate  */
8877c478bd9Sstevel@tonic-gate static int
8887c478bd9Sstevel@tonic-gate upsets_eval(struct fme *fmep, fmd_event_t *ffep)
8897c478bd9Sstevel@tonic-gate {
8907c478bd9Sstevel@tonic-gate 	/* we build an array of tripped ereports that we send ourselves */
8917c478bd9Sstevel@tonic-gate 	struct {
8927c478bd9Sstevel@tonic-gate 		const char *ename;
8937c478bd9Sstevel@tonic-gate 		const struct ipath *ipp;
8947c478bd9Sstevel@tonic-gate 	} *tripped;
8957c478bd9Sstevel@tonic-gate 	struct event *sp;
8967c478bd9Sstevel@tonic-gate 	int ntrip, nupset, i;
8977c478bd9Sstevel@tonic-gate 
8987c478bd9Sstevel@tonic-gate 	/*
8997c478bd9Sstevel@tonic-gate 	 * count the number of upsets to determine the upper limit on
9007c478bd9Sstevel@tonic-gate 	 * expected trip ereport strings.  remember that one upset can
9017c478bd9Sstevel@tonic-gate 	 * lead to at most one ereport.
9027c478bd9Sstevel@tonic-gate 	 */
9037c478bd9Sstevel@tonic-gate 	nupset = 0;
9047c478bd9Sstevel@tonic-gate 	for (sp = fmep->suspects; sp; sp = sp->suspects) {
9057c478bd9Sstevel@tonic-gate 		if (sp->t == N_UPSET)
9067c478bd9Sstevel@tonic-gate 			nupset++;
9077c478bd9Sstevel@tonic-gate 	}
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	if (nupset == 0)
9107c478bd9Sstevel@tonic-gate 		return (0);
9117c478bd9Sstevel@tonic-gate 
9127c478bd9Sstevel@tonic-gate 	/*
9137c478bd9Sstevel@tonic-gate 	 * get to this point if we have upsets and expect some trip
9147c478bd9Sstevel@tonic-gate 	 * ereports
9157c478bd9Sstevel@tonic-gate 	 */
9167c478bd9Sstevel@tonic-gate 	tripped = alloca(sizeof (*tripped) * nupset);
9177c478bd9Sstevel@tonic-gate 	bzero((void *)tripped, sizeof (*tripped) * nupset);
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	ntrip = 0;
9207c478bd9Sstevel@tonic-gate 	for (sp = fmep->suspects; sp; sp = sp->suspects)
9213e8d8e18Sdb 		if (sp->t == N_UPSET &&
9227aec1d6eScindi 		    serd_eval(fmep, fmep->hdl, ffep, fmep->fmcase, sp,
9233e8d8e18Sdb 			    &tripped[ntrip].ename, &tripped[ntrip].ipp))
9247c478bd9Sstevel@tonic-gate 			ntrip++;
9257c478bd9Sstevel@tonic-gate 
9267c478bd9Sstevel@tonic-gate 	for (i = 0; i < ntrip; i++)
9277aec1d6eScindi 		fme_receive_report(fmep->hdl, ffep,
9287c478bd9Sstevel@tonic-gate 		    tripped[i].ename, tripped[i].ipp, NULL);
9297c478bd9Sstevel@tonic-gate 
9307c478bd9Sstevel@tonic-gate 	return (ntrip);
9317c478bd9Sstevel@tonic-gate }
9327c478bd9Sstevel@tonic-gate 
9337c478bd9Sstevel@tonic-gate /*
9347c478bd9Sstevel@tonic-gate  * fme_receive_external_report -- call when an external ereport comes in
9357c478bd9Sstevel@tonic-gate  *
9367c478bd9Sstevel@tonic-gate  * this routine just converts the relevant information from the ereport
9377c478bd9Sstevel@tonic-gate  * into a format used internally and passes it on to fme_receive_report().
9387c478bd9Sstevel@tonic-gate  */
9397c478bd9Sstevel@tonic-gate void
9407c478bd9Sstevel@tonic-gate fme_receive_external_report(fmd_hdl_t *hdl, fmd_event_t *ffep, nvlist_t *nvl,
9417c478bd9Sstevel@tonic-gate     const char *eventstring)
9427c478bd9Sstevel@tonic-gate {
9437c478bd9Sstevel@tonic-gate 	struct node *epnamenp = platform_getpath(nvl);
9447c478bd9Sstevel@tonic-gate 	const struct ipath *ipp;
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 	/*
9477c478bd9Sstevel@tonic-gate 	 * XFILE: If we ended up without a path, it's an X-file.
9487c478bd9Sstevel@tonic-gate 	 * For now, use our undiagnosable interface.
9497c478bd9Sstevel@tonic-gate 	 */
9507c478bd9Sstevel@tonic-gate 	if (epnamenp == NULL) {
9517c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "XFILE: Unable to get path from ereport");
9527c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_NOPATH;
9537c478bd9Sstevel@tonic-gate 		publish_undiagnosable(hdl, ffep);
9547c478bd9Sstevel@tonic-gate 		return;
9557c478bd9Sstevel@tonic-gate 	}
9567c478bd9Sstevel@tonic-gate 
9577c478bd9Sstevel@tonic-gate 	ipp = ipath(epnamenp);
9587c478bd9Sstevel@tonic-gate 	tree_free(epnamenp);
9597c478bd9Sstevel@tonic-gate 	fme_receive_report(hdl, ffep, stable(eventstring), ipp, nvl);
9607c478bd9Sstevel@tonic-gate }
9617c478bd9Sstevel@tonic-gate 
9627aec1d6eScindi static int mark_arrows(struct fme *fmep, struct event *ep, int mark,
9637aec1d6eScindi     unsigned long long at_latest_by, unsigned long long *pdelay);
9647aec1d6eScindi 
9657aec1d6eScindi /* ARGSUSED */
9667aec1d6eScindi static void
9677aec1d6eScindi clear_arrows(struct event *ep, struct event *ep2, struct fme *fmep)
9687aec1d6eScindi {
9697aec1d6eScindi 	struct bubble *bp;
9707aec1d6eScindi 	struct arrowlist *ap;
9717aec1d6eScindi 
9727aec1d6eScindi 	ep->cached_state = 0;
9737aec1d6eScindi 	for (bp = itree_next_bubble(ep, NULL); bp;
9747aec1d6eScindi 	    bp = itree_next_bubble(ep, bp)) {
9757aec1d6eScindi 		if (bp->t != B_FROM)
9767aec1d6eScindi 			continue;
9777aec1d6eScindi 		bp->mark = 0;
9787aec1d6eScindi 		for (ap = itree_next_arrow(bp, NULL); ap;
9797aec1d6eScindi 		    ap = itree_next_arrow(bp, ap))
9807aec1d6eScindi 			ap->arrowp->mark = 0;
9817aec1d6eScindi 	}
9827aec1d6eScindi }
9837aec1d6eScindi 
9847c478bd9Sstevel@tonic-gate static void
9857c478bd9Sstevel@tonic-gate fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep,
9867c478bd9Sstevel@tonic-gate     const char *eventstring, const struct ipath *ipp, nvlist_t *nvl)
9877c478bd9Sstevel@tonic-gate {
9887c478bd9Sstevel@tonic-gate 	struct event *ep;
9897c478bd9Sstevel@tonic-gate 	struct fme *fmep = NULL;
9900cc1f05eSjrutt 	struct fme *ofmep = NULL;
9910cc1f05eSjrutt 	struct fme *cfmep, *svfmep;
9927c478bd9Sstevel@tonic-gate 	int matched = 0;
9930cc1f05eSjrutt 	nvlist_t *defect;
9947c478bd9Sstevel@tonic-gate 
9957c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_NONL, "fme_receive_report: ");
9967c478bd9Sstevel@tonic-gate 	ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
9977c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_STAMP, NULL);
9987c478bd9Sstevel@tonic-gate 
9997c478bd9Sstevel@tonic-gate 	/* decide which FME it goes to */
10007c478bd9Sstevel@tonic-gate 	for (fmep = FMElist; fmep; fmep = fmep->next) {
10017c478bd9Sstevel@tonic-gate 		int prev_verbose;
10027c478bd9Sstevel@tonic-gate 		unsigned long long my_delay = TIMEVAL_EVENTUALLY;
10037c478bd9Sstevel@tonic-gate 		enum fme_state state;
10047aec1d6eScindi 		nvlist_t *pre_peek_nvp = NULL;
10057c478bd9Sstevel@tonic-gate 
10060cc1f05eSjrutt 		if (fmep->overflow) {
10070cc1f05eSjrutt 			if (!(fmd_case_closed(fmep->hdl, fmep->fmcase)))
10080cc1f05eSjrutt 				ofmep = fmep;
10090cc1f05eSjrutt 
10100cc1f05eSjrutt 			continue;
10110cc1f05eSjrutt 		}
10120cc1f05eSjrutt 
10137c478bd9Sstevel@tonic-gate 		/* look up event in event tree for this FME */
10147c478bd9Sstevel@tonic-gate 		if ((ep = itree_lookup(fmep->eventtree,
10157c478bd9Sstevel@tonic-gate 		    eventstring, ipp)) == NULL)
10167c478bd9Sstevel@tonic-gate 			continue;
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 		/* note observation */
10197c478bd9Sstevel@tonic-gate 		fmep->ecurrent = ep;
10207c478bd9Sstevel@tonic-gate 		if (ep->count++ == 0) {
10217c478bd9Sstevel@tonic-gate 			/* link it into list of observations seen */
10227c478bd9Sstevel@tonic-gate 			ep->observations = fmep->observations;
10237c478bd9Sstevel@tonic-gate 			fmep->observations = ep;
10247c478bd9Sstevel@tonic-gate 			ep->nvp = evnv_dupnvl(nvl);
10257aec1d6eScindi 		} else {
10267aec1d6eScindi 			/* use new payload values for peek */
10277aec1d6eScindi 			pre_peek_nvp = ep->nvp;
10287aec1d6eScindi 			ep->nvp = evnv_dupnvl(nvl);
10297c478bd9Sstevel@tonic-gate 		}
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 		/* tell hypothesise() not to mess with suspect list */
10327c478bd9Sstevel@tonic-gate 		fmep->peek = 1;
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 		/* don't want this to be verbose (unless Debug is set) */
10357c478bd9Sstevel@tonic-gate 		prev_verbose = Verbose;
10367c478bd9Sstevel@tonic-gate 		if (Debug == 0)
10377c478bd9Sstevel@tonic-gate 			Verbose = 0;
10387c478bd9Sstevel@tonic-gate 
10397aec1d6eScindi 		lut_walk(fmep->eventtree, (lut_cb)clear_arrows, (void *)fmep);
10407aec1d6eScindi 		state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay);
10417c478bd9Sstevel@tonic-gate 
10427c478bd9Sstevel@tonic-gate 		fmep->peek = 0;
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 		/* put verbose flag back */
10457c478bd9Sstevel@tonic-gate 		Verbose = prev_verbose;
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 		if (state != FME_DISPROVED) {
10487c478bd9Sstevel@tonic-gate 			/* found an FME that explains the ereport */
10497c478bd9Sstevel@tonic-gate 			matched++;
10507c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_NONL, "[");
10517c478bd9Sstevel@tonic-gate 			ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
10527c478bd9Sstevel@tonic-gate 			out(O_ALTFP, " explained by FME%d]", fmep->id);
10537c478bd9Sstevel@tonic-gate 
10547aec1d6eScindi 			if (pre_peek_nvp)
10557aec1d6eScindi 				nvlist_free(pre_peek_nvp);
10567aec1d6eScindi 
10577c478bd9Sstevel@tonic-gate 			if (ep->count == 1)
10587c478bd9Sstevel@tonic-gate 				serialize_observation(fmep, eventstring, ipp);
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 			if (ffep)
10617c478bd9Sstevel@tonic-gate 				fmd_case_add_ereport(hdl, fmep->fmcase, ffep);
10627c478bd9Sstevel@tonic-gate 
10637c478bd9Sstevel@tonic-gate 			stats_counter_bump(fmep->Rcount);
10647c478bd9Sstevel@tonic-gate 
10657c478bd9Sstevel@tonic-gate 			/* re-eval FME */
10667c478bd9Sstevel@tonic-gate 			fme_eval(fmep, ffep);
10677c478bd9Sstevel@tonic-gate 		} else {
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 			/* not a match, undo noting of observation */
10707c478bd9Sstevel@tonic-gate 			fmep->ecurrent = NULL;
10717c478bd9Sstevel@tonic-gate 			if (--ep->count == 0) {
10727c478bd9Sstevel@tonic-gate 				/* unlink it from observations */
10737c478bd9Sstevel@tonic-gate 				fmep->observations = ep->observations;
10747c478bd9Sstevel@tonic-gate 				ep->observations = NULL;
10757c478bd9Sstevel@tonic-gate 				nvlist_free(ep->nvp);
10767c478bd9Sstevel@tonic-gate 				ep->nvp = NULL;
10777aec1d6eScindi 			} else {
10787aec1d6eScindi 				nvlist_free(ep->nvp);
10797aec1d6eScindi 				ep->nvp = pre_peek_nvp;
10807c478bd9Sstevel@tonic-gate 			}
10817c478bd9Sstevel@tonic-gate 		}
10827c478bd9Sstevel@tonic-gate 	}
10837c478bd9Sstevel@tonic-gate 
10847c478bd9Sstevel@tonic-gate 	if (matched)
10857c478bd9Sstevel@tonic-gate 		return;	/* explained by at least one existing FME */
10867c478bd9Sstevel@tonic-gate 
10877c478bd9Sstevel@tonic-gate 	/* clean up closed fmes */
10880cc1f05eSjrutt 	cfmep = ClosedFMEs;
10890cc1f05eSjrutt 	while (cfmep != NULL) {
10900cc1f05eSjrutt 		svfmep = cfmep->next;
10910cc1f05eSjrutt 		destroy_fme(cfmep);
10920cc1f05eSjrutt 		cfmep = svfmep;
10937c478bd9Sstevel@tonic-gate 	}
10947c478bd9Sstevel@tonic-gate 	ClosedFMEs = NULL;
10957c478bd9Sstevel@tonic-gate 
10960cc1f05eSjrutt 	if (ofmep) {
10970cc1f05eSjrutt 		out(O_ALTFP|O_NONL, "[");
10980cc1f05eSjrutt 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
10990cc1f05eSjrutt 		out(O_ALTFP, " ADDING TO OVERFLOW FME]");
11000cc1f05eSjrutt 		if (ffep)
11010cc1f05eSjrutt 			fmd_case_add_ereport(hdl, ofmep->fmcase, ffep);
11020cc1f05eSjrutt 
11030cc1f05eSjrutt 		return;
11040cc1f05eSjrutt 
11050cc1f05eSjrutt 	} else if (Max_fme && (Open_fme_count >= Max_fme)) {
11060cc1f05eSjrutt 		out(O_ALTFP|O_NONL, "[");
11070cc1f05eSjrutt 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
11080cc1f05eSjrutt 		out(O_ALTFP, " MAX OPEN FME REACHED]");
11090cc1f05eSjrutt 		/* Create overflow fme */
11100cc1f05eSjrutt 		if ((fmep = newfme(eventstring, ipp)) == NULL) {
11110cc1f05eSjrutt 			out(O_ALTFP|O_NONL, "[");
11120cc1f05eSjrutt 			ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
11130cc1f05eSjrutt 			out(O_ALTFP, " CANNOT OPEN OVERFLOW FME]");
11140cc1f05eSjrutt 			publish_undiagnosable(hdl, ffep);
11150cc1f05eSjrutt 			return;
11160cc1f05eSjrutt 		}
11170cc1f05eSjrutt 
11180cc1f05eSjrutt 		Open_fme_count++;
11190cc1f05eSjrutt 
11200cc1f05eSjrutt 		fmep->fmcase = fmd_case_open(hdl, NULL);
11210cc1f05eSjrutt 		fmep->hdl = hdl;
11220cc1f05eSjrutt 		init_fme_bufs(fmep);
11230cc1f05eSjrutt 		fmep->overflow = B_TRUE;
11240cc1f05eSjrutt 
11250cc1f05eSjrutt 		if (ffep)
11260cc1f05eSjrutt 			fmd_case_add_ereport(hdl, fmep->fmcase, ffep);
11270cc1f05eSjrutt 
11280cc1f05eSjrutt 		defect = fmd_nvl_create_fault(hdl, UNDIAGNOSABLE_DEFECT, 100,
11290cc1f05eSjrutt 		    NULL, NULL, NULL);
11300cc1f05eSjrutt 		(void) nvlist_add_string(defect, UNDIAG_REASON, UD_MAXFME);
11310cc1f05eSjrutt 		fmd_case_add_suspect(hdl, fmep->fmcase, defect);
11320cc1f05eSjrutt 		fmd_case_solve(hdl, fmep->fmcase);
11330cc1f05eSjrutt 		return;
11340cc1f05eSjrutt 	}
11350cc1f05eSjrutt 
11367c478bd9Sstevel@tonic-gate 	/* start a new FME */
11377c478bd9Sstevel@tonic-gate 	if ((fmep = newfme(eventstring, ipp)) == NULL) {
11387c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "[");
11397c478bd9Sstevel@tonic-gate 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
11407c478bd9Sstevel@tonic-gate 		out(O_ALTFP, " CANNOT DIAGNOSE]");
11417c478bd9Sstevel@tonic-gate 		publish_undiagnosable(hdl, ffep);
11427c478bd9Sstevel@tonic-gate 		return;
11437c478bd9Sstevel@tonic-gate 	}
11447c478bd9Sstevel@tonic-gate 
11450cc1f05eSjrutt 	Open_fme_count++;
11460cc1f05eSjrutt 
11477c478bd9Sstevel@tonic-gate 	/* open a case */
11487c478bd9Sstevel@tonic-gate 	fmep->fmcase = fmd_case_open(hdl, NULL);
11497c478bd9Sstevel@tonic-gate 	fmep->hdl = hdl;
11507c478bd9Sstevel@tonic-gate 	init_fme_bufs(fmep);
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_NONL, "[");
11537c478bd9Sstevel@tonic-gate 	ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
11547c478bd9Sstevel@tonic-gate 	out(O_ALTFP, " created FME%d, case %s]", fmep->id,
11557c478bd9Sstevel@tonic-gate 	    fmd_case_uuid(hdl, fmep->fmcase));
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	ep = fmep->e0;
11587c478bd9Sstevel@tonic-gate 	ASSERT(ep != NULL);
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate 	/* note observation */
11617c478bd9Sstevel@tonic-gate 	fmep->ecurrent = ep;
11627c478bd9Sstevel@tonic-gate 	if (ep->count++ == 0) {
11637c478bd9Sstevel@tonic-gate 		/* link it into list of observations seen */
11647c478bd9Sstevel@tonic-gate 		ep->observations = fmep->observations;
11657c478bd9Sstevel@tonic-gate 		fmep->observations = ep;
11667c478bd9Sstevel@tonic-gate 		ep->nvp = evnv_dupnvl(nvl);
11677c478bd9Sstevel@tonic-gate 		serialize_observation(fmep, eventstring, ipp);
11687aec1d6eScindi 	} else {
11697aec1d6eScindi 		/* new payload overrides any previous */
11707aec1d6eScindi 		nvlist_free(ep->nvp);
11717aec1d6eScindi 		ep->nvp = evnv_dupnvl(nvl);
11727c478bd9Sstevel@tonic-gate 	}
11737c478bd9Sstevel@tonic-gate 
11747c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Rcount);
11757c478bd9Sstevel@tonic-gate 
11767c478bd9Sstevel@tonic-gate 	if (ffep) {
11777c478bd9Sstevel@tonic-gate 		fmd_case_add_ereport(hdl, fmep->fmcase, ffep);
11787c478bd9Sstevel@tonic-gate 		fmd_case_setprincipal(hdl, fmep->fmcase, ffep);
11797c478bd9Sstevel@tonic-gate 		fmep->e0r = ffep;
11807c478bd9Sstevel@tonic-gate 	}
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	/* give the diagnosis algorithm a shot at the new FME state */
11837c478bd9Sstevel@tonic-gate 	fme_eval(fmep, ffep);
11847c478bd9Sstevel@tonic-gate }
11857c478bd9Sstevel@tonic-gate 
11867c478bd9Sstevel@tonic-gate void
11877c478bd9Sstevel@tonic-gate fme_status(int flags)
11887c478bd9Sstevel@tonic-gate {
11897c478bd9Sstevel@tonic-gate 	struct fme *fmep;
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	if (FMElist == NULL) {
11927c478bd9Sstevel@tonic-gate 		out(flags, "No fault management exercises underway.");
11937c478bd9Sstevel@tonic-gate 		return;
11947c478bd9Sstevel@tonic-gate 	}
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	for (fmep = FMElist; fmep; fmep = fmep->next)
11977c478bd9Sstevel@tonic-gate 		fme_print(flags, fmep);
11987c478bd9Sstevel@tonic-gate }
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate /*
12017c478bd9Sstevel@tonic-gate  * "indent" routines used mostly for nicely formatted debug output, but also
12027c478bd9Sstevel@tonic-gate  * for sanity checking for infinite recursion bugs.
12037c478bd9Sstevel@tonic-gate  */
12047c478bd9Sstevel@tonic-gate 
12057c478bd9Sstevel@tonic-gate #define	MAX_INDENT 1024
12067c478bd9Sstevel@tonic-gate static const char *indent_s[MAX_INDENT];
12077c478bd9Sstevel@tonic-gate static int current_indent;
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate static void
12107c478bd9Sstevel@tonic-gate indent_push(const char *s)
12117c478bd9Sstevel@tonic-gate {
12127c478bd9Sstevel@tonic-gate 	if (current_indent < MAX_INDENT)
12137c478bd9Sstevel@tonic-gate 		indent_s[current_indent++] = s;
12147c478bd9Sstevel@tonic-gate 	else
12157c478bd9Sstevel@tonic-gate 		out(O_DIE, "unexpected recursion depth (%d)", current_indent);
12167c478bd9Sstevel@tonic-gate }
12177c478bd9Sstevel@tonic-gate 
12187c478bd9Sstevel@tonic-gate static void
12197c478bd9Sstevel@tonic-gate indent_set(const char *s)
12207c478bd9Sstevel@tonic-gate {
12217c478bd9Sstevel@tonic-gate 	current_indent = 0;
12227c478bd9Sstevel@tonic-gate 	indent_push(s);
12237c478bd9Sstevel@tonic-gate }
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate static void
12267c478bd9Sstevel@tonic-gate indent_pop(void)
12277c478bd9Sstevel@tonic-gate {
12287c478bd9Sstevel@tonic-gate 	if (current_indent > 0)
12297c478bd9Sstevel@tonic-gate 		current_indent--;
12307c478bd9Sstevel@tonic-gate 	else
12317c478bd9Sstevel@tonic-gate 		out(O_DIE, "recursion underflow");
12327c478bd9Sstevel@tonic-gate }
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate static void
12357c478bd9Sstevel@tonic-gate indent(void)
12367c478bd9Sstevel@tonic-gate {
12377c478bd9Sstevel@tonic-gate 	int i;
12387c478bd9Sstevel@tonic-gate 	if (!Verbose)
12397c478bd9Sstevel@tonic-gate 		return;
12407c478bd9Sstevel@tonic-gate 	for (i = 0; i < current_indent; i++)
12417c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, indent_s[i]);
12427c478bd9Sstevel@tonic-gate }
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate static int
12457c478bd9Sstevel@tonic-gate suspects_changed(struct fme *fmep)
12467c478bd9Sstevel@tonic-gate {
12477c478bd9Sstevel@tonic-gate 	struct event *suspects = fmep->suspects;
12487c478bd9Sstevel@tonic-gate 	struct event *psuspects = fmep->psuspects;
12497c478bd9Sstevel@tonic-gate 
12507c478bd9Sstevel@tonic-gate 	while (suspects != NULL && psuspects != NULL) {
12517c478bd9Sstevel@tonic-gate 		if (suspects != psuspects)
12527c478bd9Sstevel@tonic-gate 			return (1);
12537c478bd9Sstevel@tonic-gate 		suspects = suspects->suspects;
12547c478bd9Sstevel@tonic-gate 		psuspects = psuspects->psuspects;
12557c478bd9Sstevel@tonic-gate 	}
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	return (suspects != psuspects);
12587c478bd9Sstevel@tonic-gate }
12597c478bd9Sstevel@tonic-gate 
12607c478bd9Sstevel@tonic-gate #define	SLNEW		1
12617c478bd9Sstevel@tonic-gate #define	SLCHANGED	2
12627c478bd9Sstevel@tonic-gate #define	SLWAIT		3
12637c478bd9Sstevel@tonic-gate #define	SLDISPROVED	4
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate static void
12667c478bd9Sstevel@tonic-gate print_suspects(int circumstance, struct fme *fmep)
12677c478bd9Sstevel@tonic-gate {
12687c478bd9Sstevel@tonic-gate 	struct event *ep;
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_NONL, "[");
12717c478bd9Sstevel@tonic-gate 	if (circumstance == SLCHANGED) {
12727c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "FME%d diagnosis changed. state: %s, "
12737c478bd9Sstevel@tonic-gate 		    "suspect list:", fmep->id, fme_state2str(fmep->state));
12747c478bd9Sstevel@tonic-gate 	} else if (circumstance == SLWAIT) {
12757c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "FME%d set wait timer ", fmep->id);
12767c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_NONL, &fmep->wull);
12777c478bd9Sstevel@tonic-gate 	} else if (circumstance == SLDISPROVED) {
12787c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "FME%d DIAGNOSIS UNKNOWN", fmep->id);
12797c478bd9Sstevel@tonic-gate 	} else {
12807c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "FME%d DIAGNOSIS PRODUCED:", fmep->id);
12817c478bd9Sstevel@tonic-gate 	}
12827c478bd9Sstevel@tonic-gate 
12837c478bd9Sstevel@tonic-gate 	if (circumstance == SLWAIT || circumstance == SLDISPROVED) {
12847c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "]");
12857c478bd9Sstevel@tonic-gate 		return;
12867c478bd9Sstevel@tonic-gate 	}
12877c478bd9Sstevel@tonic-gate 
12887c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = ep->suspects) {
12897c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, " ");
12907c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_NONL, ep);
12917c478bd9Sstevel@tonic-gate 	}
12927c478bd9Sstevel@tonic-gate 	out(O_ALTFP, "]");
12937c478bd9Sstevel@tonic-gate }
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate static struct node *
12967c478bd9Sstevel@tonic-gate eventprop_lookup(struct event *ep, const char *propname)
12977c478bd9Sstevel@tonic-gate {
12987c478bd9Sstevel@tonic-gate 	return (lut_lookup(ep->props, (void *)propname, NULL));
12997c478bd9Sstevel@tonic-gate }
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate #define	MAXDIGITIDX	23
13027c478bd9Sstevel@tonic-gate static char numbuf[MAXDIGITIDX + 1];
13037c478bd9Sstevel@tonic-gate 
13047c478bd9Sstevel@tonic-gate static int
13057c478bd9Sstevel@tonic-gate node2uint(struct node *n, uint_t *valp)
13067c478bd9Sstevel@tonic-gate {
13077c478bd9Sstevel@tonic-gate 	struct evalue value;
13087c478bd9Sstevel@tonic-gate 	struct lut *globals = NULL;
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 	if (n == NULL)
13117c478bd9Sstevel@tonic-gate 		return (1);
13127c478bd9Sstevel@tonic-gate 
13137c478bd9Sstevel@tonic-gate 	/*
13147c478bd9Sstevel@tonic-gate 	 * check value.v since we are being asked to convert an unsigned
13157c478bd9Sstevel@tonic-gate 	 * long long int to an unsigned int
13167c478bd9Sstevel@tonic-gate 	 */
13177c478bd9Sstevel@tonic-gate 	if (! eval_expr(n, NULL, NULL, &globals, NULL, NULL, 0, &value) ||
13187c478bd9Sstevel@tonic-gate 	    value.t != UINT64 || value.v > (1ULL << 32))
13197c478bd9Sstevel@tonic-gate 		return (1);
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate 	*valp = (uint_t)value.v;
13227c478bd9Sstevel@tonic-gate 
13237c478bd9Sstevel@tonic-gate 	return (0);
13247c478bd9Sstevel@tonic-gate }
13257c478bd9Sstevel@tonic-gate 
13267c478bd9Sstevel@tonic-gate static nvlist_t *
13277c478bd9Sstevel@tonic-gate node2fmri(struct node *n)
13287c478bd9Sstevel@tonic-gate {
13297c478bd9Sstevel@tonic-gate 	nvlist_t **pa, *f, *p;
13307c478bd9Sstevel@tonic-gate 	struct node *nc;
13317c478bd9Sstevel@tonic-gate 	uint_t depth = 0;
13327c478bd9Sstevel@tonic-gate 	char *numstr, *nullbyte;
13337c478bd9Sstevel@tonic-gate 	char *failure;
13347c478bd9Sstevel@tonic-gate 	int err, i;
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 	/* XXX do we need to be able to handle a non-T_NAME node? */
13377c478bd9Sstevel@tonic-gate 	if (n == NULL || n->t != T_NAME)
13387c478bd9Sstevel@tonic-gate 		return (NULL);
13397c478bd9Sstevel@tonic-gate 
13407c478bd9Sstevel@tonic-gate 	for (nc = n; nc != NULL; nc = nc->u.name.next) {
13417c478bd9Sstevel@tonic-gate 		if (nc->u.name.child == NULL || nc->u.name.child->t != T_NUM)
13427c478bd9Sstevel@tonic-gate 			break;
13437c478bd9Sstevel@tonic-gate 		depth++;
13447c478bd9Sstevel@tonic-gate 	}
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 	if (nc != NULL) {
13477c478bd9Sstevel@tonic-gate 		/* We bailed early, something went wrong */
13487c478bd9Sstevel@tonic-gate 		return (NULL);
13497c478bd9Sstevel@tonic-gate 	}
13507c478bd9Sstevel@tonic-gate 
13517c478bd9Sstevel@tonic-gate 	if ((err = nvlist_xalloc(&f, NV_UNIQUE_NAME, &Eft_nv_hdl)) != 0)
13527c478bd9Sstevel@tonic-gate 		out(O_DIE|O_SYS, "alloc of fmri nvl failed");
13537c478bd9Sstevel@tonic-gate 	pa = alloca(depth * sizeof (nvlist_t *));
13547c478bd9Sstevel@tonic-gate 	for (i = 0; i < depth; i++)
13557c478bd9Sstevel@tonic-gate 		pa[i] = NULL;
13567c478bd9Sstevel@tonic-gate 
13577c478bd9Sstevel@tonic-gate 	err = nvlist_add_string(f, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC);
13587c478bd9Sstevel@tonic-gate 	err |= nvlist_add_uint8(f, FM_VERSION, FM_HC_SCHEME_VERSION);
13597c478bd9Sstevel@tonic-gate 	err |= nvlist_add_string(f, FM_FMRI_HC_ROOT, "");
13607c478bd9Sstevel@tonic-gate 	err |= nvlist_add_uint32(f, FM_FMRI_HC_LIST_SZ, depth);
13617c478bd9Sstevel@tonic-gate 	if (err != 0) {
13627c478bd9Sstevel@tonic-gate 		failure = "basic construction of FMRI failed";
13637c478bd9Sstevel@tonic-gate 		goto boom;
13647c478bd9Sstevel@tonic-gate 	}
13657c478bd9Sstevel@tonic-gate 
13667c478bd9Sstevel@tonic-gate 	numbuf[MAXDIGITIDX] = '\0';
13677c478bd9Sstevel@tonic-gate 	nullbyte = &numbuf[MAXDIGITIDX];
13687c478bd9Sstevel@tonic-gate 	i = 0;
13697c478bd9Sstevel@tonic-gate 
13707c478bd9Sstevel@tonic-gate 	for (nc = n; nc != NULL; nc = nc->u.name.next) {
13717c478bd9Sstevel@tonic-gate 		err = nvlist_xalloc(&p, NV_UNIQUE_NAME, &Eft_nv_hdl);
13727c478bd9Sstevel@tonic-gate 		if (err != 0) {
13737c478bd9Sstevel@tonic-gate 			failure = "alloc of an hc-pair failed";
13747c478bd9Sstevel@tonic-gate 			goto boom;
13757c478bd9Sstevel@tonic-gate 		}
13767c478bd9Sstevel@tonic-gate 		err = nvlist_add_string(p, FM_FMRI_HC_NAME, nc->u.name.s);
13777c478bd9Sstevel@tonic-gate 		numstr = ulltostr(nc->u.name.child->u.ull, nullbyte);
13787c478bd9Sstevel@tonic-gate 		err |= nvlist_add_string(p, FM_FMRI_HC_ID, numstr);
13797c478bd9Sstevel@tonic-gate 		if (err != 0) {
13807c478bd9Sstevel@tonic-gate 			failure = "construction of an hc-pair failed";
13817c478bd9Sstevel@tonic-gate 			goto boom;
13827c478bd9Sstevel@tonic-gate 		}
13837c478bd9Sstevel@tonic-gate 		pa[i++] = p;
13847c478bd9Sstevel@tonic-gate 	}
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate 	err = nvlist_add_nvlist_array(f, FM_FMRI_HC_LIST, pa, depth);
13877c478bd9Sstevel@tonic-gate 	if (err == 0) {
13887c478bd9Sstevel@tonic-gate 		for (i = 0; i < depth; i++)
13897c478bd9Sstevel@tonic-gate 			if (pa[i] != NULL)
13907c478bd9Sstevel@tonic-gate 				nvlist_free(pa[i]);
13917c478bd9Sstevel@tonic-gate 		return (f);
13927c478bd9Sstevel@tonic-gate 	}
13937c478bd9Sstevel@tonic-gate 	failure = "addition of hc-pair array to FMRI failed";
13947c478bd9Sstevel@tonic-gate 
13957c478bd9Sstevel@tonic-gate boom:
13967c478bd9Sstevel@tonic-gate 	for (i = 0; i < depth; i++)
13977c478bd9Sstevel@tonic-gate 		if (pa[i] != NULL)
13987c478bd9Sstevel@tonic-gate 			nvlist_free(pa[i]);
13997c478bd9Sstevel@tonic-gate 	nvlist_free(f);
14007c478bd9Sstevel@tonic-gate 	out(O_DIE, "%s", failure);
14017c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
14027c478bd9Sstevel@tonic-gate }
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate static uint_t
14057c478bd9Sstevel@tonic-gate avg(uint_t sum, uint_t cnt)
14067c478bd9Sstevel@tonic-gate {
14077c478bd9Sstevel@tonic-gate 	unsigned long long s = sum * 10;
14087c478bd9Sstevel@tonic-gate 
14097c478bd9Sstevel@tonic-gate 	return ((s / cnt / 10) + (((s / cnt % 10) >= 5) ? 1 : 0));
14107c478bd9Sstevel@tonic-gate }
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate static uint8_t
14137c478bd9Sstevel@tonic-gate percentof(uint_t part, uint_t whole)
14147c478bd9Sstevel@tonic-gate {
14157c478bd9Sstevel@tonic-gate 	unsigned long long p = part * 1000;
14167c478bd9Sstevel@tonic-gate 
14177c478bd9Sstevel@tonic-gate 	return ((p / whole / 10) + (((p / whole % 10) >= 5) ? 1 : 0));
14187c478bd9Sstevel@tonic-gate }
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate static struct rsl {
14217c478bd9Sstevel@tonic-gate 	struct event *suspect;
14227c478bd9Sstevel@tonic-gate 	nvlist_t *asru;
14237c478bd9Sstevel@tonic-gate 	nvlist_t *fru;
14247c478bd9Sstevel@tonic-gate 	nvlist_t *rsrc;
14257c478bd9Sstevel@tonic-gate };
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate /*
14287c478bd9Sstevel@tonic-gate  *  rslfree -- free internal members of struct rsl not expected to be
14297c478bd9Sstevel@tonic-gate  *	freed elsewhere.
14307c478bd9Sstevel@tonic-gate  */
14317c478bd9Sstevel@tonic-gate static void
14327c478bd9Sstevel@tonic-gate rslfree(struct rsl *freeme)
14337c478bd9Sstevel@tonic-gate {
14347c478bd9Sstevel@tonic-gate 	if (freeme->asru != NULL)
14357c478bd9Sstevel@tonic-gate 		nvlist_free(freeme->asru);
14367c478bd9Sstevel@tonic-gate 	if (freeme->fru != NULL)
14377c478bd9Sstevel@tonic-gate 		nvlist_free(freeme->fru);
14387c478bd9Sstevel@tonic-gate 	if (freeme->rsrc != NULL && freeme->rsrc != freeme->asru)
14397c478bd9Sstevel@tonic-gate 		nvlist_free(freeme->rsrc);
14407c478bd9Sstevel@tonic-gate }
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate /*
14437c478bd9Sstevel@tonic-gate  *  rslcmp -- compare two rsl structures.  Use the following
14447c478bd9Sstevel@tonic-gate  *	comparisons to establish cardinality:
14457c478bd9Sstevel@tonic-gate  *
14467c478bd9Sstevel@tonic-gate  *	1. Name of the suspect's class. (simple strcmp)
14477c478bd9Sstevel@tonic-gate  *	2. Name of the suspect's ASRU. (trickier, since nvlist)
14487c478bd9Sstevel@tonic-gate  *
14497c478bd9Sstevel@tonic-gate  */
14507c478bd9Sstevel@tonic-gate static int
14517c478bd9Sstevel@tonic-gate rslcmp(const void *a, const void *b)
14527c478bd9Sstevel@tonic-gate {
14537c478bd9Sstevel@tonic-gate 	struct rsl *r1 = (struct rsl *)a;
14547c478bd9Sstevel@tonic-gate 	struct rsl *r2 = (struct rsl *)b;
14557c478bd9Sstevel@tonic-gate 	int rv;
14567c478bd9Sstevel@tonic-gate 
14577c478bd9Sstevel@tonic-gate 	rv = strcmp(r1->suspect->enode->u.event.ename->u.name.s,
14587c478bd9Sstevel@tonic-gate 	    r2->suspect->enode->u.event.ename->u.name.s);
14597c478bd9Sstevel@tonic-gate 	if (rv != 0)
14607c478bd9Sstevel@tonic-gate 		return (rv);
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate 	if (r1->asru == NULL && r2->asru == NULL)
14637c478bd9Sstevel@tonic-gate 		return (0);
14647c478bd9Sstevel@tonic-gate 	if (r1->asru == NULL)
14657c478bd9Sstevel@tonic-gate 		return (-1);
14667c478bd9Sstevel@tonic-gate 	if (r2->asru == NULL)
14677c478bd9Sstevel@tonic-gate 		return (1);
14687c478bd9Sstevel@tonic-gate 	return (evnv_cmpnvl(r1->asru, r2->asru, 0));
14697c478bd9Sstevel@tonic-gate }
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate /*
14727c478bd9Sstevel@tonic-gate  *  rsluniq -- given an array of rsl structures, seek out and "remove"
14737c478bd9Sstevel@tonic-gate  *	any duplicates.  Dups are "remove"d by NULLing the suspect pointer
14747c478bd9Sstevel@tonic-gate  *	of the array element.  Removal also means updating the number of
14757c478bd9Sstevel@tonic-gate  *	problems and the number of problems which are not faults.  User
14767c478bd9Sstevel@tonic-gate  *	provides the first and last element pointers.
14777c478bd9Sstevel@tonic-gate  */
14787c478bd9Sstevel@tonic-gate static void
14797c478bd9Sstevel@tonic-gate rsluniq(struct rsl *first, struct rsl *last, int *nprobs, int *nnonf)
14807c478bd9Sstevel@tonic-gate {
14817c478bd9Sstevel@tonic-gate 	struct rsl *cr;
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	if (*nprobs == 1)
14847c478bd9Sstevel@tonic-gate 		return;
14857c478bd9Sstevel@tonic-gate 
14867c478bd9Sstevel@tonic-gate 	/*
14877c478bd9Sstevel@tonic-gate 	 *  At this point, we only expect duplicate defects.
14887c478bd9Sstevel@tonic-gate 	 *  Eversholt's diagnosis algorithm prevents duplicate
14897c478bd9Sstevel@tonic-gate 	 *  suspects, but we rewrite defects in the platform code after
14907c478bd9Sstevel@tonic-gate 	 *  the diagnosis is made, and that can introduce new
14917c478bd9Sstevel@tonic-gate 	 *  duplicates.
14927c478bd9Sstevel@tonic-gate 	 */
14937c478bd9Sstevel@tonic-gate 	while (first <= last) {
14947c478bd9Sstevel@tonic-gate 		if (first->suspect == NULL || !is_defect(first->suspect->t)) {
14957c478bd9Sstevel@tonic-gate 			first++;
14967c478bd9Sstevel@tonic-gate 			continue;
14977c478bd9Sstevel@tonic-gate 		}
14987c478bd9Sstevel@tonic-gate 		cr = first + 1;
14997c478bd9Sstevel@tonic-gate 		while (cr <= last) {
15007c478bd9Sstevel@tonic-gate 			if (is_defect(first->suspect->t)) {
15017c478bd9Sstevel@tonic-gate 				if (rslcmp(first, cr) == 0) {
15027c478bd9Sstevel@tonic-gate 					cr->suspect = NULL;
15037c478bd9Sstevel@tonic-gate 					rslfree(cr);
15047c478bd9Sstevel@tonic-gate 					(*nprobs)--;
15057c478bd9Sstevel@tonic-gate 					(*nnonf)--;
15067c478bd9Sstevel@tonic-gate 				}
15077c478bd9Sstevel@tonic-gate 			}
15087c478bd9Sstevel@tonic-gate 			/*
15097c478bd9Sstevel@tonic-gate 			 * assume all defects are in order after our
15107c478bd9Sstevel@tonic-gate 			 * sort and short circuit here with "else break" ?
15117c478bd9Sstevel@tonic-gate 			 */
15127c478bd9Sstevel@tonic-gate 			cr++;
15137c478bd9Sstevel@tonic-gate 		}
15147c478bd9Sstevel@tonic-gate 		first++;
15157c478bd9Sstevel@tonic-gate 	}
15167c478bd9Sstevel@tonic-gate }
15177c478bd9Sstevel@tonic-gate 
15187c478bd9Sstevel@tonic-gate /*
15197c478bd9Sstevel@tonic-gate  * get_resources -- for a given suspect, determine what ASRU, FRU and
15207c478bd9Sstevel@tonic-gate  *     RSRC nvlists should be advertised in the final suspect list.
15217c478bd9Sstevel@tonic-gate  */
15227c478bd9Sstevel@tonic-gate void
15237c478bd9Sstevel@tonic-gate get_resources(struct event *sp, struct rsl *rsrcs, struct config *croot)
15247c478bd9Sstevel@tonic-gate {
15257c478bd9Sstevel@tonic-gate 	struct node *asrudef, *frudef;
15267c478bd9Sstevel@tonic-gate 	nvlist_t *asru, *fru;
15277c478bd9Sstevel@tonic-gate 	nvlist_t *rsrc = NULL;
15287c478bd9Sstevel@tonic-gate 	char *pathstr;
15297c478bd9Sstevel@tonic-gate 
15307c478bd9Sstevel@tonic-gate 	/*
15317c478bd9Sstevel@tonic-gate 	 * First find any ASRU and/or FRU defined in the
15327c478bd9Sstevel@tonic-gate 	 * initial fault tree.
15337c478bd9Sstevel@tonic-gate 	 */
15347c478bd9Sstevel@tonic-gate 	asrudef = eventprop_lookup(sp, L_ASRU);
15357c478bd9Sstevel@tonic-gate 	frudef = eventprop_lookup(sp, L_FRU);
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	/*
15387c478bd9Sstevel@tonic-gate 	 * Create FMRIs based on those definitions
15397c478bd9Sstevel@tonic-gate 	 */
15407c478bd9Sstevel@tonic-gate 	asru = node2fmri(asrudef);
15417c478bd9Sstevel@tonic-gate 	fru = node2fmri(frudef);
15427c478bd9Sstevel@tonic-gate 	pathstr = ipath2str(NULL, sp->ipp);
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 	/*
15457c478bd9Sstevel@tonic-gate 	 * Allow for platform translations of the FMRIs
15467c478bd9Sstevel@tonic-gate 	 */
15477c478bd9Sstevel@tonic-gate 	platform_units_translate(is_defect(sp->t), croot, &asru, &fru, &rsrc,
15487c478bd9Sstevel@tonic-gate 	    pathstr);
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	FREE(pathstr);
15517c478bd9Sstevel@tonic-gate 	rsrcs->suspect = sp;
15527c478bd9Sstevel@tonic-gate 	rsrcs->asru = asru;
15537c478bd9Sstevel@tonic-gate 	rsrcs->fru = fru;
15547c478bd9Sstevel@tonic-gate 	rsrcs->rsrc = rsrc;
15557c478bd9Sstevel@tonic-gate }
15567c478bd9Sstevel@tonic-gate 
15577c478bd9Sstevel@tonic-gate /*
15587c478bd9Sstevel@tonic-gate  * trim_suspects -- prior to publishing, we may need to remove some
15597c478bd9Sstevel@tonic-gate  *    suspects from the list.  If we're auto-closing upsets, we don't
15607c478bd9Sstevel@tonic-gate  *    want any of those in the published list.  If the ASRUs for multiple
15617c478bd9Sstevel@tonic-gate  *    defects resolve to the same ASRU (driver) we only want to publish
15627c478bd9Sstevel@tonic-gate  *    that as a single suspect.
15637c478bd9Sstevel@tonic-gate  */
15647c478bd9Sstevel@tonic-gate static void
15657c478bd9Sstevel@tonic-gate trim_suspects(struct fme *fmep, boolean_t no_upsets, struct rsl **begin,
15667c478bd9Sstevel@tonic-gate     struct rsl **end)
15677c478bd9Sstevel@tonic-gate {
15687c478bd9Sstevel@tonic-gate 	struct event *ep;
15697c478bd9Sstevel@tonic-gate 	struct rsl *rp;
15707c478bd9Sstevel@tonic-gate 	int rpcnt;
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 	/*
15737c478bd9Sstevel@tonic-gate 	 * First save the suspects in the psuspects, then copy back
15747c478bd9Sstevel@tonic-gate 	 * only the ones we wish to retain.  This resets nsuspects to
15757c478bd9Sstevel@tonic-gate 	 * zero.
15767c478bd9Sstevel@tonic-gate 	 */
15777c478bd9Sstevel@tonic-gate 	rpcnt = fmep->nsuspects;
15787c478bd9Sstevel@tonic-gate 	save_suspects(fmep);
15797c478bd9Sstevel@tonic-gate 
15807c478bd9Sstevel@tonic-gate 	/*
15817c478bd9Sstevel@tonic-gate 	 * allocate an array of resource pointers for the suspects.
15827c478bd9Sstevel@tonic-gate 	 * We may end up using less than the full allocation, but this
15837c478bd9Sstevel@tonic-gate 	 * is a very short-lived array.  publish_suspects() will free
15847c478bd9Sstevel@tonic-gate 	 * this array when it's done using it.
15857c478bd9Sstevel@tonic-gate 	 */
15867c478bd9Sstevel@tonic-gate 	rp = *begin = MALLOC(rpcnt * sizeof (struct rsl));
15877c478bd9Sstevel@tonic-gate 	bzero(rp, rpcnt * sizeof (struct rsl));
15887c478bd9Sstevel@tonic-gate 
15897c478bd9Sstevel@tonic-gate 	/* first pass, remove any unwanted upsets and populate our array */
15907c478bd9Sstevel@tonic-gate 	for (ep = fmep->psuspects; ep; ep = ep->psuspects) {
15917c478bd9Sstevel@tonic-gate 		if (no_upsets && is_upset(ep->t))
15927c478bd9Sstevel@tonic-gate 			continue;
15937c478bd9Sstevel@tonic-gate 		get_resources(ep, rp, fmep->cfgdata->cooked);
15947c478bd9Sstevel@tonic-gate 		rp++;
15957c478bd9Sstevel@tonic-gate 		fmep->nsuspects++;
15967c478bd9Sstevel@tonic-gate 		if (!is_fault(ep->t))
15977c478bd9Sstevel@tonic-gate 			fmep->nonfault++;
15987c478bd9Sstevel@tonic-gate 	}
15997c478bd9Sstevel@tonic-gate 
16007c478bd9Sstevel@tonic-gate 	/* if all we had was unwanted upsets, we're done */
16017c478bd9Sstevel@tonic-gate 	if (fmep->nsuspects == 0)
16027c478bd9Sstevel@tonic-gate 		return;
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 	*end = rp - 1;
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	/* sort the array */
16077c478bd9Sstevel@tonic-gate 	qsort(*begin, fmep->nsuspects, sizeof (struct rsl), rslcmp);
16087c478bd9Sstevel@tonic-gate 	rsluniq(*begin, *end, &fmep->nsuspects, &fmep->nonfault);
16097c478bd9Sstevel@tonic-gate }
16107c478bd9Sstevel@tonic-gate 
16117aec1d6eScindi /*
16127aec1d6eScindi  * addpayloadprop -- add a payload prop to a problem
16137aec1d6eScindi  */
16147aec1d6eScindi static void
16157aec1d6eScindi addpayloadprop(const char *lhs, struct evalue *rhs, nvlist_t *fault)
16167aec1d6eScindi {
16177aec1d6eScindi 	ASSERT(fault != NULL);
16187aec1d6eScindi 	ASSERT(lhs != NULL);
16197aec1d6eScindi 	ASSERT(rhs != NULL);
16207aec1d6eScindi 
16217aec1d6eScindi 	if (rhs->t == UINT64) {
16227aec1d6eScindi 		out(O_ALTFP|O_VERB2, "addpayloadprop: %s=%llu", lhs, rhs->v);
16237aec1d6eScindi 
16247aec1d6eScindi 		if (nvlist_add_uint64(fault, lhs, rhs->v) != 0)
16257aec1d6eScindi 			out(O_DIE,
16267aec1d6eScindi 			    "cannot add payloadprop \"%s\" to fault", lhs);
16277aec1d6eScindi 	} else {
16287aec1d6eScindi 		out(O_ALTFP|O_VERB2, "addpayloadprop: %s=\"%s\"",
16297aec1d6eScindi 		    lhs, (char *)rhs->v);
16307aec1d6eScindi 
16317aec1d6eScindi 		if (nvlist_add_string(fault, lhs, (char *)rhs->v) != 0)
16327aec1d6eScindi 			out(O_DIE,
16337aec1d6eScindi 			    "cannot add payloadprop \"%s\" to fault", lhs);
16347aec1d6eScindi 	}
16357aec1d6eScindi }
16367aec1d6eScindi 
16377aec1d6eScindi static char *Istatbuf;
16387aec1d6eScindi static char *Istatbufptr;
16397aec1d6eScindi static int Istatsz;
16407aec1d6eScindi 
16417aec1d6eScindi /*
16427aec1d6eScindi  * istataddsize -- calculate size of istat and add it to Istatsz
16437aec1d6eScindi  */
16447aec1d6eScindi /*ARGSUSED2*/
16457aec1d6eScindi static void
16467aec1d6eScindi istataddsize(const struct istat_entry *lhs, struct stats *rhs, void *arg)
16477aec1d6eScindi {
16487aec1d6eScindi 	int val;
16497aec1d6eScindi 
16507aec1d6eScindi 	ASSERT(lhs != NULL);
16517aec1d6eScindi 	ASSERT(rhs != NULL);
16527aec1d6eScindi 
16537aec1d6eScindi 	if ((val = stats_counter_value(rhs)) == 0)
16547aec1d6eScindi 		return;	/* skip zero-valued stats */
16557aec1d6eScindi 
16567aec1d6eScindi 	/* count up the size of the stat name */
16577aec1d6eScindi 	Istatsz += ipath2strlen(lhs->ename, lhs->ipath);
16587aec1d6eScindi 	Istatsz++;	/* for the trailing NULL byte */
16597aec1d6eScindi 
16607aec1d6eScindi 	/* count up the size of the stat value */
16617aec1d6eScindi 	Istatsz += snprintf(NULL, 0, "%d", val);
16627aec1d6eScindi 	Istatsz++;	/* for the trailing NULL byte */
16637aec1d6eScindi }
16647aec1d6eScindi 
16657aec1d6eScindi /*
16667aec1d6eScindi  * istat2str -- serialize an istat, writing result to *Istatbufptr
16677aec1d6eScindi  */
16687aec1d6eScindi /*ARGSUSED2*/
16697aec1d6eScindi static void
16707aec1d6eScindi istat2str(const struct istat_entry *lhs, struct stats *rhs, void *arg)
16717aec1d6eScindi {
16727aec1d6eScindi 	char *str;
16737aec1d6eScindi 	int len;
16747aec1d6eScindi 	int val;
16757aec1d6eScindi 
16767aec1d6eScindi 	ASSERT(lhs != NULL);
16777aec1d6eScindi 	ASSERT(rhs != NULL);
16787aec1d6eScindi 
16797aec1d6eScindi 	if ((val = stats_counter_value(rhs)) == 0)
16807aec1d6eScindi 		return;	/* skip zero-valued stats */
16817aec1d6eScindi 
16827aec1d6eScindi 	/* serialize the stat name */
16837aec1d6eScindi 	str = ipath2str(lhs->ename, lhs->ipath);
16847aec1d6eScindi 	len = strlen(str);
16857aec1d6eScindi 
16867aec1d6eScindi 	ASSERT(Istatbufptr + len + 1 < &Istatbuf[Istatsz]);
16877aec1d6eScindi 	(void) strlcpy(Istatbufptr, str, &Istatbuf[Istatsz] - Istatbufptr);
16887aec1d6eScindi 	Istatbufptr += len;
16897aec1d6eScindi 	FREE(str);
16907aec1d6eScindi 	*Istatbufptr++ = '\0';
16917aec1d6eScindi 
16927aec1d6eScindi 	/* serialize the stat value */
16937aec1d6eScindi 	Istatbufptr += snprintf(Istatbufptr, &Istatbuf[Istatsz] - Istatbufptr,
16947aec1d6eScindi 	    "%d", val);
16957aec1d6eScindi 	*Istatbufptr++ = '\0';
16967aec1d6eScindi 
16977aec1d6eScindi 	ASSERT(Istatbufptr <= &Istatbuf[Istatsz]);
16987aec1d6eScindi }
16997aec1d6eScindi 
17007aec1d6eScindi void
17017aec1d6eScindi istat_save()
17027aec1d6eScindi {
17037aec1d6eScindi 	if (Istat_need_save == 0)
17047aec1d6eScindi 		return;
17057aec1d6eScindi 
17067aec1d6eScindi 	/* figure out how big the serialzed info is */
17077aec1d6eScindi 	Istatsz = 0;
17087aec1d6eScindi 	lut_walk(Istats, (lut_cb)istataddsize, NULL);
17097aec1d6eScindi 
17107aec1d6eScindi 	if (Istatsz == 0) {
17117aec1d6eScindi 		/* no stats to save */
17127aec1d6eScindi 		fmd_buf_destroy(Hdl, NULL, WOBUF_ISTATS);
17137aec1d6eScindi 		return;
17147aec1d6eScindi 	}
17157aec1d6eScindi 
17167aec1d6eScindi 	/* create the serialized buffer */
17177aec1d6eScindi 	Istatbufptr = Istatbuf = MALLOC(Istatsz);
17187aec1d6eScindi 	lut_walk(Istats, (lut_cb)istat2str, NULL);
17197aec1d6eScindi 
17207aec1d6eScindi 	/* clear out current saved stats */
17217aec1d6eScindi 	fmd_buf_destroy(Hdl, NULL, WOBUF_ISTATS);
17227aec1d6eScindi 
17237aec1d6eScindi 	/* write out the new version */
17247aec1d6eScindi 	fmd_buf_write(Hdl, NULL, WOBUF_ISTATS, Istatbuf, Istatsz);
17257aec1d6eScindi 	FREE(Istatbuf);
17267aec1d6eScindi 
17277aec1d6eScindi 	Istat_need_save = 0;
17287aec1d6eScindi }
17297aec1d6eScindi 
17307aec1d6eScindi int
17317aec1d6eScindi istat_cmp(struct istat_entry *ent1, struct istat_entry *ent2)
17327aec1d6eScindi {
17337aec1d6eScindi 	if (ent1->ename != ent2->ename)
17347aec1d6eScindi 		return (ent2->ename - ent1->ename);
17357aec1d6eScindi 	if (ent1->ipath != ent2->ipath)
17367aec1d6eScindi 		return ((char *)ent2->ipath - (char *)ent1->ipath);
17377aec1d6eScindi 
17387aec1d6eScindi 	return (0);
17397aec1d6eScindi }
17407aec1d6eScindi 
17417aec1d6eScindi /*
17427aec1d6eScindi  * istat-verify -- verify the component associated with a stat still exists
17437aec1d6eScindi  *
17447aec1d6eScindi  * if the component no longer exists, this routine resets the stat and
17457aec1d6eScindi  * returns 0.  if the component still exists, it returns 1.
17467aec1d6eScindi  */
17477aec1d6eScindi static int
17487aec1d6eScindi istat_verify(struct node *snp, struct istat_entry *entp)
17497aec1d6eScindi {
17507aec1d6eScindi 	struct stats *statp;
17517aec1d6eScindi 	nvlist_t *fmri;
17527aec1d6eScindi 
17537aec1d6eScindi 	fmri = node2fmri(snp->u.event.epname);
17547aec1d6eScindi 	if (platform_path_exists(fmri)) {
17557aec1d6eScindi 		nvlist_free(fmri);
17567aec1d6eScindi 		return (1);
17577aec1d6eScindi 	}
17587aec1d6eScindi 	nvlist_free(fmri);
17597aec1d6eScindi 
17607aec1d6eScindi 	/* component no longer in system.  zero out the associated stats */
17617aec1d6eScindi 	if ((statp = (struct stats *)
17627aec1d6eScindi 	    lut_lookup(Istats, entp, (lut_cmp)istat_cmp)) == NULL ||
17637aec1d6eScindi 	    stats_counter_value(statp) == 0)
17647aec1d6eScindi 		return (0);	/* stat is already reset */
17657aec1d6eScindi 
17667aec1d6eScindi 	Istat_need_save = 1;
17677aec1d6eScindi 	stats_counter_reset(statp);
17687aec1d6eScindi 	return (0);
17697aec1d6eScindi }
17707aec1d6eScindi 
17717aec1d6eScindi static void
17727aec1d6eScindi istat_bump(struct node *snp, int n)
17737aec1d6eScindi {
17747aec1d6eScindi 	struct stats *statp;
17757aec1d6eScindi 	struct istat_entry ent;
17767aec1d6eScindi 
17777aec1d6eScindi 	ASSERT(snp != NULL);
17787aec1d6eScindi 	ASSERTinfo(snp->t == T_EVENT, ptree_nodetype2str(snp->t));
17797aec1d6eScindi 	ASSERT(snp->u.event.epname != NULL);
17807aec1d6eScindi 
17817aec1d6eScindi 	/* class name should be hoisted into a single stable entry */
17827aec1d6eScindi 	ASSERT(snp->u.event.ename->u.name.next == NULL);
17837aec1d6eScindi 	ent.ename = snp->u.event.ename->u.name.s;
17847aec1d6eScindi 	ent.ipath = ipath(snp->u.event.epname);
17857aec1d6eScindi 
17867aec1d6eScindi 	if (!istat_verify(snp, &ent)) {
17877aec1d6eScindi 		/* component no longer exists in system, nothing to do */
17887aec1d6eScindi 		return;
17897aec1d6eScindi 	}
17907aec1d6eScindi 
17917aec1d6eScindi 	if ((statp = (struct stats *)
17927aec1d6eScindi 	    lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL) {
17937aec1d6eScindi 		/* need to create the counter */
17947aec1d6eScindi 		int cnt = 0;
17957aec1d6eScindi 		struct node *np;
17967aec1d6eScindi 		char *sname;
17977aec1d6eScindi 		char *snamep;
17987aec1d6eScindi 		struct istat_entry *newentp;
17997aec1d6eScindi 
18007aec1d6eScindi 		/* count up the size of the stat name */
18017aec1d6eScindi 		np = snp->u.event.ename;
18027aec1d6eScindi 		while (np != NULL) {
18037aec1d6eScindi 			cnt += strlen(np->u.name.s);
18047aec1d6eScindi 			cnt++;	/* for the '.' or '@' */
18057aec1d6eScindi 			np = np->u.name.next;
18067aec1d6eScindi 		}
18077aec1d6eScindi 		np = snp->u.event.epname;
18087aec1d6eScindi 		while (np != NULL) {
18097aec1d6eScindi 			cnt += snprintf(NULL, 0, "%s%llu",
18107aec1d6eScindi 			    np->u.name.s, np->u.name.child->u.ull);
18117aec1d6eScindi 			cnt++;	/* for the '/' or trailing NULL byte */
18127aec1d6eScindi 			np = np->u.name.next;
18137aec1d6eScindi 		}
18147aec1d6eScindi 
18157aec1d6eScindi 		/* build the stat name */
18167aec1d6eScindi 		snamep = sname = alloca(cnt);
18177aec1d6eScindi 		np = snp->u.event.ename;
18187aec1d6eScindi 		while (np != NULL) {
18197aec1d6eScindi 			snamep += snprintf(snamep, &sname[cnt] - snamep,
18207aec1d6eScindi 			    "%s", np->u.name.s);
18217aec1d6eScindi 			np = np->u.name.next;
18227aec1d6eScindi 			if (np)
18237aec1d6eScindi 				*snamep++ = '.';
18247aec1d6eScindi 		}
18257aec1d6eScindi 		*snamep++ = '@';
18267aec1d6eScindi 		np = snp->u.event.epname;
18277aec1d6eScindi 		while (np != NULL) {
18287aec1d6eScindi 			snamep += snprintf(snamep, &sname[cnt] - snamep,
18297aec1d6eScindi 			    "%s%llu", np->u.name.s, np->u.name.child->u.ull);
18307aec1d6eScindi 			np = np->u.name.next;
18317aec1d6eScindi 			if (np)
18327aec1d6eScindi 				*snamep++ = '/';
18337aec1d6eScindi 		}
18347aec1d6eScindi 		*snamep++ = '\0';
18357aec1d6eScindi 
18367aec1d6eScindi 		/* create the new stat & add it to our list */
18377aec1d6eScindi 		newentp = MALLOC(sizeof (*newentp));
18387aec1d6eScindi 		*newentp = ent;
18397aec1d6eScindi 		statp = stats_new_counter(NULL, sname, 0);
18407aec1d6eScindi 		Istats = lut_add(Istats, (void *)newentp, (void *)statp,
18417aec1d6eScindi 		    (lut_cmp)istat_cmp);
18427aec1d6eScindi 	}
18437aec1d6eScindi 
18447aec1d6eScindi 	/* if n is non-zero, set that value instead of bumping */
18457aec1d6eScindi 	if (n) {
18467aec1d6eScindi 		stats_counter_reset(statp);
18477aec1d6eScindi 		stats_counter_add(statp, n);
18487aec1d6eScindi 	} else
18497aec1d6eScindi 		stats_counter_bump(statp);
18507aec1d6eScindi 	Istat_need_save = 1;
18517aec1d6eScindi }
18527aec1d6eScindi 
18537aec1d6eScindi /*ARGSUSED*/
18547aec1d6eScindi static void
18557aec1d6eScindi istat_destructor(void *left, void *right, void *arg)
18567aec1d6eScindi {
18577aec1d6eScindi 	struct istat_entry *entp = (struct istat_entry *)left;
18587aec1d6eScindi 	struct stats *statp = (struct stats *)right;
18597aec1d6eScindi 	FREE(entp);
18607aec1d6eScindi 	stats_delete(statp);
18617aec1d6eScindi }
18627aec1d6eScindi 
18637aec1d6eScindi void
18647aec1d6eScindi istat_fini(void)
18657aec1d6eScindi {
18667aec1d6eScindi 	lut_free(Istats, istat_destructor, NULL);
18677aec1d6eScindi }
18687aec1d6eScindi 
18697c478bd9Sstevel@tonic-gate static void
18707c478bd9Sstevel@tonic-gate publish_suspects(struct fme *fmep)
18717c478bd9Sstevel@tonic-gate {
18727c478bd9Sstevel@tonic-gate 	struct event *ep;
18737c478bd9Sstevel@tonic-gate 	struct rsl *srl = NULL;
18747c478bd9Sstevel@tonic-gate 	struct rsl *erl;
18757c478bd9Sstevel@tonic-gate 	struct rsl *rp;
18767c478bd9Sstevel@tonic-gate 	nvlist_t *fault;
18777c478bd9Sstevel@tonic-gate 	uint8_t cert;
18787c478bd9Sstevel@tonic-gate 	uint_t *frs;
18797c478bd9Sstevel@tonic-gate 	uint_t fravg, frsum, fr;
18807aec1d6eScindi 	uint_t messval;
18817aec1d6eScindi 	struct node *snp;
18827c478bd9Sstevel@tonic-gate 	int frcnt, fridx;
18837c478bd9Sstevel@tonic-gate 	boolean_t no_upsets = B_FALSE;
18847aec1d6eScindi 	boolean_t allfaulty = B_TRUE;
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->diags);
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 	/*
18897c478bd9Sstevel@tonic-gate 	 * The current fmd interfaces don't allow us to solve a case
18907c478bd9Sstevel@tonic-gate 	 * that's already solved.  If we make a new case, what of the
18917c478bd9Sstevel@tonic-gate 	 * ereports?  We don't appear to have an interface that allows
18927c478bd9Sstevel@tonic-gate 	 * us to access the ereports attached to a case (if we wanted
18937c478bd9Sstevel@tonic-gate 	 * to copy the original case's ereport attachments to the new
18947c478bd9Sstevel@tonic-gate 	 * case) and it's also a bit unclear if there would be any
18957c478bd9Sstevel@tonic-gate 	 * problems with having ereports attached to multiple cases
18967c478bd9Sstevel@tonic-gate 	 * and/or attaching DIAGNOSED ereports to a case.  For now,
18977c478bd9Sstevel@tonic-gate 	 * we'll just output a message.
18987c478bd9Sstevel@tonic-gate 	 */
18997c478bd9Sstevel@tonic-gate 	if (fmep->posted_suspects ||
19007c478bd9Sstevel@tonic-gate 	    fmd_case_solved(fmep->hdl, fmep->fmcase)) {
19017c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "Revised diagnosis for case %s: ",
19027c478bd9Sstevel@tonic-gate 		    fmd_case_uuid(fmep->hdl, fmep->fmcase));
19037c478bd9Sstevel@tonic-gate 		for (ep = fmep->suspects; ep; ep = ep->suspects) {
19047c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_NONL, " ");
19057c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_NONL, ep);
19067c478bd9Sstevel@tonic-gate 		}
19077c478bd9Sstevel@tonic-gate 		out(O_ALTFP, NULL);
19087c478bd9Sstevel@tonic-gate 		return;
19097c478bd9Sstevel@tonic-gate 	}
19107c478bd9Sstevel@tonic-gate 
19117c478bd9Sstevel@tonic-gate 	/*
19127c478bd9Sstevel@tonic-gate 	 * If we're auto-closing upsets, we don't want to include them
19137c478bd9Sstevel@tonic-gate 	 * in any produced suspect lists or certainty accounting.
19147c478bd9Sstevel@tonic-gate 	 */
19157c478bd9Sstevel@tonic-gate 	if (Autoclose != NULL)
19167c478bd9Sstevel@tonic-gate 		if (strcmp(Autoclose, "true") == 0 ||
19177c478bd9Sstevel@tonic-gate 		    strcmp(Autoclose, "all") == 0 ||
19187c478bd9Sstevel@tonic-gate 		    strcmp(Autoclose, "upsets") == 0)
19197c478bd9Sstevel@tonic-gate 			no_upsets = B_TRUE;
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate 	trim_suspects(fmep, no_upsets, &srl, &erl);
19227c478bd9Sstevel@tonic-gate 
19237c478bd9Sstevel@tonic-gate 	/*
19247c478bd9Sstevel@tonic-gate 	 * If the resulting suspect list has no members, we're
19257c478bd9Sstevel@tonic-gate 	 * done.  Returning here will simply close the case.
19267c478bd9Sstevel@tonic-gate 	 */
19277c478bd9Sstevel@tonic-gate 	if (fmep->nsuspects == 0) {
19287c478bd9Sstevel@tonic-gate 		out(O_ALTFP,
19297c478bd9Sstevel@tonic-gate 		    "[FME%d, case %s (all suspects are upsets)]",
19307c478bd9Sstevel@tonic-gate 		    fmep->id, fmd_case_uuid(fmep->hdl, fmep->fmcase));
19317c478bd9Sstevel@tonic-gate 		FREE(srl);
19327c478bd9Sstevel@tonic-gate 		restore_suspects(fmep);
19337c478bd9Sstevel@tonic-gate 		return;
19347c478bd9Sstevel@tonic-gate 	}
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 	/*
19377c478bd9Sstevel@tonic-gate 	 * If the suspect list is all faults, then for a given fault,
19387c478bd9Sstevel@tonic-gate 	 * say X of N, X's certainty is computed via:
19397c478bd9Sstevel@tonic-gate 	 *
19407c478bd9Sstevel@tonic-gate 	 * fitrate(X) / (fitrate(1) + ... + fitrate(N)) * 100
19417c478bd9Sstevel@tonic-gate 	 *
19427c478bd9Sstevel@tonic-gate 	 * If none of the suspects are faults, and there are N suspects,
19437c478bd9Sstevel@tonic-gate 	 * the certainty of a given suspect is 100/N.
19447c478bd9Sstevel@tonic-gate 	 *
19457c478bd9Sstevel@tonic-gate 	 * If there are are a mixture of faults and other problems in
19467c478bd9Sstevel@tonic-gate 	 * the suspect list, we take an average of the faults'
19477c478bd9Sstevel@tonic-gate 	 * FITrates and treat this average as the FITrate for any
19487c478bd9Sstevel@tonic-gate 	 * non-faults.  The fitrate of any given suspect is then
19497c478bd9Sstevel@tonic-gate 	 * computed per the first formula above.
19507c478bd9Sstevel@tonic-gate 	 */
19517c478bd9Sstevel@tonic-gate 	if (fmep->nonfault == fmep->nsuspects) {
19527c478bd9Sstevel@tonic-gate 		/* NO faults in the suspect list */
19537c478bd9Sstevel@tonic-gate 		cert = percentof(1, fmep->nsuspects);
19547c478bd9Sstevel@tonic-gate 	} else {
19557c478bd9Sstevel@tonic-gate 		/* sum the fitrates */
19567c478bd9Sstevel@tonic-gate 		frs = alloca(fmep->nsuspects * sizeof (uint_t));
19577c478bd9Sstevel@tonic-gate 		fridx = frcnt = frsum = 0;
19587c478bd9Sstevel@tonic-gate 
19597c478bd9Sstevel@tonic-gate 		for (rp = srl; rp <= erl; rp++) {
19607c478bd9Sstevel@tonic-gate 			struct node *n;
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate 			if (rp->suspect == NULL)
19637c478bd9Sstevel@tonic-gate 				continue;
19647c478bd9Sstevel@tonic-gate 			if (!is_fault(rp->suspect->t)) {
19657c478bd9Sstevel@tonic-gate 				frs[fridx++] = 0;
19667c478bd9Sstevel@tonic-gate 				continue;
19677c478bd9Sstevel@tonic-gate 			}
19687c478bd9Sstevel@tonic-gate 			n = eventprop_lookup(rp->suspect, L_FITrate);
19697c478bd9Sstevel@tonic-gate 			if (node2uint(n, &fr) != 0) {
19707c478bd9Sstevel@tonic-gate 				out(O_DEBUG|O_NONL, "event ");
19717c478bd9Sstevel@tonic-gate 				ipath_print(O_DEBUG|O_NONL,
19727c478bd9Sstevel@tonic-gate 				    ep->enode->u.event.ename->u.name.s,
19737c478bd9Sstevel@tonic-gate 				    ep->ipp);
19747c478bd9Sstevel@tonic-gate 				out(O_DEBUG, " has no FITrate (using 1)");
19757c478bd9Sstevel@tonic-gate 				fr = 1;
19767c478bd9Sstevel@tonic-gate 			} else if (fr == 0) {
19777c478bd9Sstevel@tonic-gate 				out(O_DEBUG|O_NONL, "event ");
19787c478bd9Sstevel@tonic-gate 				ipath_print(O_DEBUG|O_NONL,
19797c478bd9Sstevel@tonic-gate 				    ep->enode->u.event.ename->u.name.s,
19807c478bd9Sstevel@tonic-gate 				    ep->ipp);
19817c478bd9Sstevel@tonic-gate 				out(O_DEBUG, " has zero FITrate (using 1)");
19827c478bd9Sstevel@tonic-gate 				fr = 1;
19837c478bd9Sstevel@tonic-gate 			}
19847c478bd9Sstevel@tonic-gate 
19857c478bd9Sstevel@tonic-gate 			frs[fridx++] = fr;
19867c478bd9Sstevel@tonic-gate 			frsum += fr;
19877c478bd9Sstevel@tonic-gate 			frcnt++;
19887c478bd9Sstevel@tonic-gate 		}
19897c478bd9Sstevel@tonic-gate 		fravg = avg(frsum, frcnt);
19907c478bd9Sstevel@tonic-gate 		for (fridx = 0; fridx < fmep->nsuspects; fridx++)
19917c478bd9Sstevel@tonic-gate 			if (frs[fridx] == 0) {
19927c478bd9Sstevel@tonic-gate 				frs[fridx] = fravg;
19937c478bd9Sstevel@tonic-gate 				frsum += fravg;
19947c478bd9Sstevel@tonic-gate 			}
19957c478bd9Sstevel@tonic-gate 	}
19967c478bd9Sstevel@tonic-gate 
19977c478bd9Sstevel@tonic-gate 	/* Add them in reverse order of our sort, as fmd reverses order */
19987c478bd9Sstevel@tonic-gate 	for (rp = erl; rp >= srl; rp--) {
19997c478bd9Sstevel@tonic-gate 		if (rp->suspect == NULL)
20007c478bd9Sstevel@tonic-gate 			continue;
20017aec1d6eScindi 		if (!is_fault(rp->suspect->t))
20027aec1d6eScindi 			allfaulty = B_FALSE;
20037c478bd9Sstevel@tonic-gate 		if (fmep->nonfault != fmep->nsuspects)
20047c478bd9Sstevel@tonic-gate 			cert = percentof(frs[--fridx], frsum);
20057c478bd9Sstevel@tonic-gate 		fault = fmd_nvl_create_fault(fmep->hdl,
20067c478bd9Sstevel@tonic-gate 		    rp->suspect->enode->u.event.ename->u.name.s,
20077c478bd9Sstevel@tonic-gate 		    cert,
20087c478bd9Sstevel@tonic-gate 		    rp->asru,
20097c478bd9Sstevel@tonic-gate 		    rp->fru,
20107c478bd9Sstevel@tonic-gate 		    rp->rsrc);
20117c478bd9Sstevel@tonic-gate 		if (fault == NULL)
20127c478bd9Sstevel@tonic-gate 			out(O_DIE, "fault creation failed");
20137aec1d6eScindi 		/* if "message" property exists, add it to the fault */
20147aec1d6eScindi 		if (node2uint(eventprop_lookup(rp->suspect, L_message),
20157aec1d6eScindi 		    &messval) == 0) {
20167aec1d6eScindi 
20177aec1d6eScindi 			out(O_ALTFP,
20187aec1d6eScindi 			    "[FME%d, %s adds message=%d to suspect list]",
20197aec1d6eScindi 			    fmep->id,
20207aec1d6eScindi 			    rp->suspect->enode->u.event.ename->u.name.s,
20217aec1d6eScindi 			    messval);
20227aec1d6eScindi 			if (nvlist_add_boolean_value(fault,
20237aec1d6eScindi 			    FM_SUSPECT_MESSAGE,
20247aec1d6eScindi 			    (messval) ? B_TRUE : B_FALSE) != 0) {
20257aec1d6eScindi 				out(O_DIE, "cannot add no-message to fault");
20267aec1d6eScindi 			}
20277aec1d6eScindi 		}
20287aec1d6eScindi 		/* add any payload properties */
20297aec1d6eScindi 		lut_walk(rp->suspect->payloadprops,
20307aec1d6eScindi 		    (lut_cb)addpayloadprop, (void *)fault);
20317c478bd9Sstevel@tonic-gate 		fmd_case_add_suspect(fmep->hdl, fmep->fmcase, fault);
20327c478bd9Sstevel@tonic-gate 		rp->suspect->fault = fault;
20337c478bd9Sstevel@tonic-gate 		rslfree(rp);
2034*5f25dc2aSgavinm 
2035*5f25dc2aSgavinm 		/*
2036*5f25dc2aSgavinm 		 * If "action" property exists, evaluate it;  this must be done
2037*5f25dc2aSgavinm 		 * before the dupclose check below since some actions may
2038*5f25dc2aSgavinm 		 * modify the asru to be used in fmd_nvl_fmri_faulty.  This
2039*5f25dc2aSgavinm 		 * needs to be restructured if any new actions are introduced
2040*5f25dc2aSgavinm 		 * that have effects that we do not want to be visible if
2041*5f25dc2aSgavinm 		 * we decide not to publish in the dupclose check below.
2042*5f25dc2aSgavinm 		 */
20437aec1d6eScindi 		if ((snp = eventprop_lookup(rp->suspect, L_action)) != NULL) {
20447aec1d6eScindi 			struct evalue evalue;
20457aec1d6eScindi 
20467aec1d6eScindi 			out(O_ALTFP|O_NONL,
20477aec1d6eScindi 			    "[FME%d, %s action ", fmep->id,
20487aec1d6eScindi 			    rp->suspect->enode->u.event.ename->u.name.s);
20497aec1d6eScindi 			ptree_name_iter(O_ALTFP|O_NONL, snp);
20507aec1d6eScindi 			out(O_ALTFP, "]");
20517aec1d6eScindi 			Action_nvl = fault;
20527aec1d6eScindi 			(void) eval_expr(snp, NULL, NULL, NULL, NULL,
20537aec1d6eScindi 			    NULL, 0, &evalue);
20547aec1d6eScindi 		}
2055*5f25dc2aSgavinm 
20567aec1d6eScindi 		/*
20577aec1d6eScindi 		 * if "dupclose" tunable is set, check if the asru is
20587aec1d6eScindi 		 * already marked as "faulty".
20597aec1d6eScindi 		 */
20607aec1d6eScindi 		if (Dupclose && allfaulty) {
20617aec1d6eScindi 			nvlist_t *asru;
20627aec1d6eScindi 
20637aec1d6eScindi 			out(O_ALTFP|O_VERB, "FMD%d dupclose check ", fmep->id);
20647aec1d6eScindi 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, rp->suspect);
20657aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, " ");
20667aec1d6eScindi 			if (nvlist_lookup_nvlist(fault,
20677aec1d6eScindi 			    FM_FAULT_ASRU, &asru) != 0) {
20687aec1d6eScindi 				out(O_ALTFP|O_VERB, "NULL asru");
20697aec1d6eScindi 				allfaulty = B_FALSE;
20707aec1d6eScindi 			} else if (fmd_nvl_fmri_faulty(fmep->hdl, asru)) {
20717aec1d6eScindi 				out(O_ALTFP|O_VERB, "faulty");
20727aec1d6eScindi 			} else {
20737aec1d6eScindi 				out(O_ALTFP|O_VERB, "not faulty");
20747aec1d6eScindi 				allfaulty = B_FALSE;
20757aec1d6eScindi 			}
20767aec1d6eScindi 		}
20777aec1d6eScindi 
20787aec1d6eScindi 	}
2079*5f25dc2aSgavinm 
2080*5f25dc2aSgavinm 	/*
2081*5f25dc2aSgavinm 	 * Close the case if all asrus are already known to be faulty and if
2082*5f25dc2aSgavinm 	 * Dupclose is enabled.  Otherwise we are going to publish so take
2083*5f25dc2aSgavinm 	 * any pre-publication actions.
2084*5f25dc2aSgavinm 	 */
20857aec1d6eScindi 	if (Dupclose && allfaulty) {
20867aec1d6eScindi 		out(O_ALTFP, "[dupclose FME%d, case %s]", fmep->id,
20877aec1d6eScindi 		    fmd_case_uuid(fmep->hdl, fmep->fmcase));
20887aec1d6eScindi 		fmd_case_close(fmep->hdl, fmep->fmcase);
20897aec1d6eScindi 	} else {
2090*5f25dc2aSgavinm 		for (rp = erl; rp >= srl; rp--) {
2091*5f25dc2aSgavinm 			struct event *suspect = rp->suspect;
2092*5f25dc2aSgavinm 
2093*5f25dc2aSgavinm 			if (suspect == NULL)
2094*5f25dc2aSgavinm 				continue;
2095*5f25dc2aSgavinm 
2096*5f25dc2aSgavinm 			fault = suspect->fault;
2097*5f25dc2aSgavinm 
2098*5f25dc2aSgavinm 			/* if "count" exists, increment the appropriate stat */
2099*5f25dc2aSgavinm 			if ((snp = eventprop_lookup(suspect,
2100*5f25dc2aSgavinm 			    L_count)) != NULL) {
2101*5f25dc2aSgavinm 				out(O_ALTFP|O_NONL,
2102*5f25dc2aSgavinm 				    "[FME%d, %s count ", fmep->id,
2103*5f25dc2aSgavinm 				    suspect->enode->u.event.ename->u.name.s);
2104*5f25dc2aSgavinm 				ptree_name_iter(O_ALTFP|O_NONL, snp);
2105*5f25dc2aSgavinm 				out(O_ALTFP, "]");
2106*5f25dc2aSgavinm 				istat_bump(snp, 0);
2107*5f25dc2aSgavinm 
2108*5f25dc2aSgavinm 			}
2109*5f25dc2aSgavinm 		}
2110*5f25dc2aSgavinm 		istat_save();	/* write out any istat changes */
2111*5f25dc2aSgavinm 
21127aec1d6eScindi 		out(O_ALTFP, "[solving FME%d, case %s]", fmep->id,
21137aec1d6eScindi 		    fmd_case_uuid(fmep->hdl, fmep->fmcase));
21147aec1d6eScindi 		fmd_case_solve(fmep->hdl, fmep->fmcase);
21157c478bd9Sstevel@tonic-gate 	}
21167aec1d6eScindi 
21177c478bd9Sstevel@tonic-gate 	/*
21187c478bd9Sstevel@tonic-gate 	 * revert to the original suspect list
21197c478bd9Sstevel@tonic-gate 	 */
21207c478bd9Sstevel@tonic-gate 	FREE(srl);
21217c478bd9Sstevel@tonic-gate 	restore_suspects(fmep);
21227c478bd9Sstevel@tonic-gate }
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate static void
21257c478bd9Sstevel@tonic-gate publish_undiagnosable(fmd_hdl_t *hdl, fmd_event_t *ffep)
21267c478bd9Sstevel@tonic-gate {
21277c478bd9Sstevel@tonic-gate 	struct case_list *newcase;
21287c478bd9Sstevel@tonic-gate 	nvlist_t *defect;
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate 	out(O_ALTFP,
21317c478bd9Sstevel@tonic-gate 	    "[undiagnosable ereport received, "
21327c478bd9Sstevel@tonic-gate 	    "creating and closing a new case (%s)]",
21337c478bd9Sstevel@tonic-gate 	    Undiag_reason ? Undiag_reason : "reason not provided");
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate 	newcase = MALLOC(sizeof (struct case_list));
21367c478bd9Sstevel@tonic-gate 	newcase->next = NULL;
21377c478bd9Sstevel@tonic-gate 
21387c478bd9Sstevel@tonic-gate 	newcase->fmcase = fmd_case_open(hdl, NULL);
21397c478bd9Sstevel@tonic-gate 	if (Undiagablecaselist != NULL)
21407c478bd9Sstevel@tonic-gate 		newcase->next = Undiagablecaselist;
21417c478bd9Sstevel@tonic-gate 	Undiagablecaselist = newcase;
21427c478bd9Sstevel@tonic-gate 
21437c478bd9Sstevel@tonic-gate 	if (ffep != NULL)
21447c478bd9Sstevel@tonic-gate 		fmd_case_add_ereport(hdl, newcase->fmcase, ffep);
21457c478bd9Sstevel@tonic-gate 
21467c478bd9Sstevel@tonic-gate 	defect = fmd_nvl_create_fault(hdl, UNDIAGNOSABLE_DEFECT, 100,
21477c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL);
21487c478bd9Sstevel@tonic-gate 	if (Undiag_reason != NULL)
21497c478bd9Sstevel@tonic-gate 		(void) nvlist_add_string(defect, UNDIAG_REASON, Undiag_reason);
21507c478bd9Sstevel@tonic-gate 	fmd_case_add_suspect(hdl, newcase->fmcase, defect);
21517c478bd9Sstevel@tonic-gate 
21527c478bd9Sstevel@tonic-gate 	fmd_case_solve(hdl, newcase->fmcase);
21537c478bd9Sstevel@tonic-gate 	fmd_case_close(hdl, newcase->fmcase);
21547c478bd9Sstevel@tonic-gate }
21557c478bd9Sstevel@tonic-gate 
21567c478bd9Sstevel@tonic-gate static void
21577c478bd9Sstevel@tonic-gate fme_undiagnosable(struct fme *f)
21587c478bd9Sstevel@tonic-gate {
21597c478bd9Sstevel@tonic-gate 	nvlist_t *defect;
21607c478bd9Sstevel@tonic-gate 
21617c478bd9Sstevel@tonic-gate 	out(O_ALTFP, "[solving/closing FME%d, case %s (%s)]",
21627c478bd9Sstevel@tonic-gate 	    f->id, fmd_case_uuid(f->hdl, f->fmcase),
21637c478bd9Sstevel@tonic-gate 	    Undiag_reason ? Undiag_reason : "undiagnosable");
21647c478bd9Sstevel@tonic-gate 
21657c478bd9Sstevel@tonic-gate 	defect = fmd_nvl_create_fault(f->hdl, UNDIAGNOSABLE_DEFECT, 100,
21667c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL);
21677c478bd9Sstevel@tonic-gate 	if (Undiag_reason != NULL)
21687c478bd9Sstevel@tonic-gate 		(void) nvlist_add_string(defect, UNDIAG_REASON, Undiag_reason);
21697c478bd9Sstevel@tonic-gate 	fmd_case_add_suspect(f->hdl, f->fmcase, defect);
21707c478bd9Sstevel@tonic-gate 	fmd_case_solve(f->hdl, f->fmcase);
21717c478bd9Sstevel@tonic-gate 	destroy_fme_bufs(f);
21727c478bd9Sstevel@tonic-gate 	fmd_case_close(f->hdl, f->fmcase);
21737c478bd9Sstevel@tonic-gate }
21747c478bd9Sstevel@tonic-gate 
21757c478bd9Sstevel@tonic-gate /*
21767c478bd9Sstevel@tonic-gate  * fme_close_case
21777c478bd9Sstevel@tonic-gate  *
21787c478bd9Sstevel@tonic-gate  *	Find the requested case amongst our fmes and close it.  Free up
21797c478bd9Sstevel@tonic-gate  *	the related fme.
21807c478bd9Sstevel@tonic-gate  */
21817c478bd9Sstevel@tonic-gate void
21827c478bd9Sstevel@tonic-gate fme_close_case(fmd_hdl_t *hdl, fmd_case_t *fmcase)
21837c478bd9Sstevel@tonic-gate {
21847c478bd9Sstevel@tonic-gate 	struct case_list *ucasep, *prevcasep = NULL;
21857c478bd9Sstevel@tonic-gate 	struct fme *prev = NULL;
21867c478bd9Sstevel@tonic-gate 	struct fme *fmep;
21877c478bd9Sstevel@tonic-gate 
21887c478bd9Sstevel@tonic-gate 	for (ucasep = Undiagablecaselist; ucasep; ucasep = ucasep->next) {
21897c478bd9Sstevel@tonic-gate 		if (fmcase != ucasep->fmcase) {
21907c478bd9Sstevel@tonic-gate 			prevcasep = ucasep;
21917c478bd9Sstevel@tonic-gate 			continue;
21927c478bd9Sstevel@tonic-gate 		}
21937c478bd9Sstevel@tonic-gate 
21947c478bd9Sstevel@tonic-gate 		if (prevcasep == NULL)
21957c478bd9Sstevel@tonic-gate 			Undiagablecaselist = Undiagablecaselist->next;
21967c478bd9Sstevel@tonic-gate 		else
21977c478bd9Sstevel@tonic-gate 			prevcasep->next = ucasep->next;
21987c478bd9Sstevel@tonic-gate 
21997c478bd9Sstevel@tonic-gate 		FREE(ucasep);
22007c478bd9Sstevel@tonic-gate 		return;
22017c478bd9Sstevel@tonic-gate 	}
22027c478bd9Sstevel@tonic-gate 
22037c478bd9Sstevel@tonic-gate 	for (fmep = FMElist; fmep; fmep = fmep->next) {
22047c478bd9Sstevel@tonic-gate 		if (fmep->hdl == hdl && fmep->fmcase == fmcase)
22057c478bd9Sstevel@tonic-gate 			break;
22067c478bd9Sstevel@tonic-gate 		prev = fmep;
22077c478bd9Sstevel@tonic-gate 	}
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	if (fmep == NULL) {
22107c478bd9Sstevel@tonic-gate 		out(O_WARN, "Eft asked to close unrecognized case [%s].",
22117c478bd9Sstevel@tonic-gate 		    fmd_case_uuid(hdl, fmcase));
22127c478bd9Sstevel@tonic-gate 		return;
22137c478bd9Sstevel@tonic-gate 	}
22147c478bd9Sstevel@tonic-gate 
22157c478bd9Sstevel@tonic-gate 	if (EFMElist == fmep)
22167c478bd9Sstevel@tonic-gate 		EFMElist = prev;
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate 	if (prev == NULL)
22197c478bd9Sstevel@tonic-gate 		FMElist = FMElist->next;
22207c478bd9Sstevel@tonic-gate 	else
22217c478bd9Sstevel@tonic-gate 		prev->next = fmep->next;
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate 	fmep->next = NULL;
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate 	/* Get rid of any timer this fme has set */
22267c478bd9Sstevel@tonic-gate 	if (fmep->wull != 0)
22277c478bd9Sstevel@tonic-gate 		fmd_timer_remove(fmep->hdl, fmep->timer);
22287c478bd9Sstevel@tonic-gate 
22297c478bd9Sstevel@tonic-gate 	if (ClosedFMEs == NULL) {
22307c478bd9Sstevel@tonic-gate 		ClosedFMEs = fmep;
22317c478bd9Sstevel@tonic-gate 	} else {
22327c478bd9Sstevel@tonic-gate 		fmep->next = ClosedFMEs;
22337c478bd9Sstevel@tonic-gate 		ClosedFMEs = fmep;
22347c478bd9Sstevel@tonic-gate 	}
22350cc1f05eSjrutt 
22360cc1f05eSjrutt 	Open_fme_count--;
22370cc1f05eSjrutt 
22380cc1f05eSjrutt 	/* See if we can close the overflow FME */
22390cc1f05eSjrutt 	if (Open_fme_count <= Max_fme) {
22400cc1f05eSjrutt 		for (fmep = FMElist; fmep; fmep = fmep->next) {
22410cc1f05eSjrutt 			if (fmep->overflow && !(fmd_case_closed(fmep->hdl,
22420cc1f05eSjrutt 			    fmep->fmcase)))
22430cc1f05eSjrutt 				break;
22440cc1f05eSjrutt 		}
22450cc1f05eSjrutt 
22460cc1f05eSjrutt 		if (fmep != NULL)
22470cc1f05eSjrutt 			fmd_case_close(fmep->hdl, fmep->fmcase);
22480cc1f05eSjrutt 	}
22497c478bd9Sstevel@tonic-gate }
22507c478bd9Sstevel@tonic-gate 
22517c478bd9Sstevel@tonic-gate /*
22527c478bd9Sstevel@tonic-gate  * fme_set_timer()
22537c478bd9Sstevel@tonic-gate  *	If the time we need to wait for the given FME is less than the
22547c478bd9Sstevel@tonic-gate  *	current timer, kick that old timer out and establish a new one.
22557c478bd9Sstevel@tonic-gate  */
22567aec1d6eScindi static int
22577c478bd9Sstevel@tonic-gate fme_set_timer(struct fme *fmep, unsigned long long wull)
22587c478bd9Sstevel@tonic-gate {
22597c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, " fme_set_timer: request to wait ");
22607c478bd9Sstevel@tonic-gate 	ptree_timeval(O_ALTFP|O_VERB, &wull);
22617c478bd9Sstevel@tonic-gate 
22627c478bd9Sstevel@tonic-gate 	if (wull <= fmep->pull) {
22637c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "already have waited at least ");
22647c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB, &fmep->pull);
22657c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
22667c478bd9Sstevel@tonic-gate 		/* we've waited at least wull already, don't need timer */
22677aec1d6eScindi 		return (0);
22687c478bd9Sstevel@tonic-gate 	}
22697c478bd9Sstevel@tonic-gate 
22707c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, " currently ");
22717c478bd9Sstevel@tonic-gate 	if (fmep->wull != 0) {
22727c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "waiting ");
22737c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB, &fmep->wull);
22747c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
22757c478bd9Sstevel@tonic-gate 	} else {
22767c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "not waiting");
22777c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
22787c478bd9Sstevel@tonic-gate 	}
22797c478bd9Sstevel@tonic-gate 
22807c478bd9Sstevel@tonic-gate 	if (fmep->wull != 0)
22817c478bd9Sstevel@tonic-gate 		if (wull >= fmep->wull)
22827c478bd9Sstevel@tonic-gate 			/* New timer would fire later than established timer */
22837aec1d6eScindi 			return (0);
22847c478bd9Sstevel@tonic-gate 
22857aec1d6eScindi 	if (fmep->wull != 0) {
22867c478bd9Sstevel@tonic-gate 		fmd_timer_remove(fmep->hdl, fmep->timer);
22877aec1d6eScindi 		if (fmep->timer == fmep->htid) {
22887aec1d6eScindi 			out(O_ALTFP,
22897aec1d6eScindi 			    "[stopped hesitating FME%d, case %s]",
22907aec1d6eScindi 			    fmep->id,
22917aec1d6eScindi 			    fmd_case_uuid(fmep->hdl,
22927aec1d6eScindi 			    fmep->fmcase));
22937aec1d6eScindi 			fmep->htid = 0;
22947aec1d6eScindi 		}
22957aec1d6eScindi 	}
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 	fmep->timer = fmd_timer_install(fmep->hdl, (void *)fmep,
22987c478bd9Sstevel@tonic-gate 	    fmep->e0r, wull);
22997c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, "timer set, id is %ld", fmep->timer);
23007c478bd9Sstevel@tonic-gate 	fmep->wull = wull;
23017aec1d6eScindi 	return (1);
23027c478bd9Sstevel@tonic-gate }
23037c478bd9Sstevel@tonic-gate 
23047c478bd9Sstevel@tonic-gate void
23057c478bd9Sstevel@tonic-gate fme_timer_fired(struct fme *fmep, id_t tid)
23067c478bd9Sstevel@tonic-gate {
23077c478bd9Sstevel@tonic-gate 	struct fme *ffmep = NULL;
23087c478bd9Sstevel@tonic-gate 
23097c478bd9Sstevel@tonic-gate 	for (ffmep = FMElist; ffmep; ffmep = ffmep->next)
23107c478bd9Sstevel@tonic-gate 		if (ffmep == fmep)
23117c478bd9Sstevel@tonic-gate 			break;
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate 	if (ffmep == NULL) {
23147c478bd9Sstevel@tonic-gate 		out(O_WARN, "Timer fired for an FME (%p) not in FMEs list.",
23157c478bd9Sstevel@tonic-gate 		    (void *)fmep);
23167c478bd9Sstevel@tonic-gate 		return;
23177c478bd9Sstevel@tonic-gate 	}
23187c478bd9Sstevel@tonic-gate 
23197aec1d6eScindi 	out(O_ALTFP, "Timer fired %lx %lx", tid, fmep->htid);
23207c478bd9Sstevel@tonic-gate 	if (tid != fmep->htid) {
23217c478bd9Sstevel@tonic-gate 		/*
23227aec1d6eScindi 		 * normal timer (not the hesitation timer)
23237c478bd9Sstevel@tonic-gate 		 */
23247c478bd9Sstevel@tonic-gate 		fmep->pull = fmep->wull;
23257c478bd9Sstevel@tonic-gate 		fmep->wull = 0;
23267c478bd9Sstevel@tonic-gate 		fmd_buf_write(fmep->hdl, fmep->fmcase,
23277c478bd9Sstevel@tonic-gate 		    WOBUF_PULL, (void *)&fmep->pull, sizeof (fmep->pull));
23287aec1d6eScindi 		/*
23297aec1d6eScindi 		 * no point in heistating if we've already waited.
23307aec1d6eScindi 		 */
23317aec1d6eScindi 		fmep->hesitated = 1;
23327c478bd9Sstevel@tonic-gate 	} else {
23337c478bd9Sstevel@tonic-gate 		fmep->hesitated = 1;
23347c478bd9Sstevel@tonic-gate 	}
23357c478bd9Sstevel@tonic-gate 	fme_eval(fmep, NULL);
23367c478bd9Sstevel@tonic-gate }
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate /*
23397c478bd9Sstevel@tonic-gate  * Preserve the fme's suspect list in its psuspects list, NULLing the
23407c478bd9Sstevel@tonic-gate  * suspects list in the meantime.
23417c478bd9Sstevel@tonic-gate  */
23427c478bd9Sstevel@tonic-gate static void
23437c478bd9Sstevel@tonic-gate save_suspects(struct fme *fmep)
23447c478bd9Sstevel@tonic-gate {
23457c478bd9Sstevel@tonic-gate 	struct event *ep;
23467c478bd9Sstevel@tonic-gate 	struct event *nextep;
23477c478bd9Sstevel@tonic-gate 
23487c478bd9Sstevel@tonic-gate 	/* zero out the previous suspect list */
23497c478bd9Sstevel@tonic-gate 	for (ep = fmep->psuspects; ep; ep = nextep) {
23507c478bd9Sstevel@tonic-gate 		nextep = ep->psuspects;
23517c478bd9Sstevel@tonic-gate 		ep->psuspects = NULL;
23527c478bd9Sstevel@tonic-gate 	}
23537c478bd9Sstevel@tonic-gate 	fmep->psuspects = NULL;
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 	/* zero out the suspect list, copying it to previous suspect list */
23567c478bd9Sstevel@tonic-gate 	fmep->psuspects = fmep->suspects;
23577c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = nextep) {
23587c478bd9Sstevel@tonic-gate 		nextep = ep->suspects;
23597c478bd9Sstevel@tonic-gate 		ep->psuspects = ep->suspects;
23607c478bd9Sstevel@tonic-gate 		ep->suspects = NULL;
23617c478bd9Sstevel@tonic-gate 		ep->is_suspect = 0;
23627c478bd9Sstevel@tonic-gate 	}
23637c478bd9Sstevel@tonic-gate 	fmep->suspects = NULL;
23647c478bd9Sstevel@tonic-gate 	fmep->nsuspects = 0;
23657c478bd9Sstevel@tonic-gate 	fmep->nonfault = 0;
23667c478bd9Sstevel@tonic-gate }
23677c478bd9Sstevel@tonic-gate 
23687c478bd9Sstevel@tonic-gate /*
23697c478bd9Sstevel@tonic-gate  * Retrieve the fme's suspect list from its psuspects list.
23707c478bd9Sstevel@tonic-gate  */
23717c478bd9Sstevel@tonic-gate static void
23727c478bd9Sstevel@tonic-gate restore_suspects(struct fme *fmep)
23737c478bd9Sstevel@tonic-gate {
23747c478bd9Sstevel@tonic-gate 	struct event *ep;
23757c478bd9Sstevel@tonic-gate 	struct event *nextep;
23767c478bd9Sstevel@tonic-gate 
23777c478bd9Sstevel@tonic-gate 	fmep->nsuspects = fmep->nonfault = 0;
23787c478bd9Sstevel@tonic-gate 	fmep->suspects = fmep->psuspects;
23797c478bd9Sstevel@tonic-gate 	for (ep = fmep->psuspects; ep; ep = nextep) {
23807c478bd9Sstevel@tonic-gate 		fmep->nsuspects++;
23817c478bd9Sstevel@tonic-gate 		if (!is_fault(ep->t))
23827c478bd9Sstevel@tonic-gate 			fmep->nonfault++;
23837c478bd9Sstevel@tonic-gate 		nextep = ep->psuspects;
23847c478bd9Sstevel@tonic-gate 		ep->suspects = ep->psuspects;
23857c478bd9Sstevel@tonic-gate 	}
23867c478bd9Sstevel@tonic-gate }
23877c478bd9Sstevel@tonic-gate 
23887c478bd9Sstevel@tonic-gate /*
23897c478bd9Sstevel@tonic-gate  * this is what we use to call the Emrys prototype code instead of main()
23907c478bd9Sstevel@tonic-gate  */
23917c478bd9Sstevel@tonic-gate static void
23927c478bd9Sstevel@tonic-gate fme_eval(struct fme *fmep, fmd_event_t *ffep)
23937c478bd9Sstevel@tonic-gate {
23947c478bd9Sstevel@tonic-gate 	struct event *ep;
23957c478bd9Sstevel@tonic-gate 	unsigned long long my_delay = TIMEVAL_EVENTUALLY;
23967c478bd9Sstevel@tonic-gate 
23977c478bd9Sstevel@tonic-gate 	save_suspects(fmep);
23987c478bd9Sstevel@tonic-gate 
23997c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, "Evaluate FME %d", fmep->id);
24007c478bd9Sstevel@tonic-gate 	indent_set("  ");
24017c478bd9Sstevel@tonic-gate 
24027aec1d6eScindi 	lut_walk(fmep->eventtree, (lut_cb)clear_arrows, (void *)fmep);
24037aec1d6eScindi 	fmep->state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay);
24047c478bd9Sstevel@tonic-gate 
24057c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "FME%d state: %s, suspect list:", fmep->id,
24067c478bd9Sstevel@tonic-gate 	    fme_state2str(fmep->state));
24077c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = ep->suspects) {
24087c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " ");
24097c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
24107c478bd9Sstevel@tonic-gate 	}
24117c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
24127c478bd9Sstevel@tonic-gate 
24137c478bd9Sstevel@tonic-gate 	if (fmep->posted_suspects) {
24147c478bd9Sstevel@tonic-gate 		/*
24157c478bd9Sstevel@tonic-gate 		 * this FME has already posted a diagnosis, so see if
24167c478bd9Sstevel@tonic-gate 		 * the event changed the diagnosis and print a warning
24177c478bd9Sstevel@tonic-gate 		 * if it did.
24187c478bd9Sstevel@tonic-gate 		 *
24197c478bd9Sstevel@tonic-gate 		 */
24207c478bd9Sstevel@tonic-gate 		if (suspects_changed(fmep)) {
24217c478bd9Sstevel@tonic-gate 			print_suspects(SLCHANGED, fmep);
24227c478bd9Sstevel@tonic-gate 			publish_suspects(fmep);
24237c478bd9Sstevel@tonic-gate 		}
24247c478bd9Sstevel@tonic-gate 	} else {
24257c478bd9Sstevel@tonic-gate 		switch (fmep->state) {
24267c478bd9Sstevel@tonic-gate 		case FME_CREDIBLE:
24277c478bd9Sstevel@tonic-gate 			/*
24287c478bd9Sstevel@tonic-gate 			 * if the suspect list contains any upsets, we
24297c478bd9Sstevel@tonic-gate 			 * turn off the hesitation logic (by setting
24307c478bd9Sstevel@tonic-gate 			 * the hesitate flag which normally indicates
24317c478bd9Sstevel@tonic-gate 			 * we've already done the hesitate logic).
24327c478bd9Sstevel@tonic-gate 			 * this is done because hesitating with upsets
24337c478bd9Sstevel@tonic-gate 			 * causes us to explain away additional soft errors
24347c478bd9Sstevel@tonic-gate 			 * while the upset FME stays open.
24357c478bd9Sstevel@tonic-gate 			 */
24367c478bd9Sstevel@tonic-gate 			if (fmep->hesitated == 0) {
24377c478bd9Sstevel@tonic-gate 				struct event *s;
24387c478bd9Sstevel@tonic-gate 
24397c478bd9Sstevel@tonic-gate 				for (s = fmep->suspects; s; s = s->suspects) {
24407c478bd9Sstevel@tonic-gate 					if (s->t == N_UPSET) {
24417c478bd9Sstevel@tonic-gate 						fmep->hesitated = 1;
24427c478bd9Sstevel@tonic-gate 						break;
24437c478bd9Sstevel@tonic-gate 					}
24447c478bd9Sstevel@tonic-gate 				}
24457c478bd9Sstevel@tonic-gate 			}
24467c478bd9Sstevel@tonic-gate 
24477c478bd9Sstevel@tonic-gate 			if (Hesitate &&
24487c478bd9Sstevel@tonic-gate 			    fmep->suspects != NULL &&
24497c478bd9Sstevel@tonic-gate 			    fmep->suspects->suspects != NULL &&
24507c478bd9Sstevel@tonic-gate 			    fmep->hesitated == 0) {
24517c478bd9Sstevel@tonic-gate 				/*
24527c478bd9Sstevel@tonic-gate 				 * about to publish multi-entry suspect list,
24537c478bd9Sstevel@tonic-gate 				 * set the hesitation timer if not already set.
24547c478bd9Sstevel@tonic-gate 				 */
24557c478bd9Sstevel@tonic-gate 				if (fmep->htid == 0) {
24567c478bd9Sstevel@tonic-gate 					out(O_ALTFP|O_NONL,
24577c478bd9Sstevel@tonic-gate 					    "[hesitate FME%d, case %s ",
24587c478bd9Sstevel@tonic-gate 					    fmep->id,
24597c478bd9Sstevel@tonic-gate 					    fmd_case_uuid(fmep->hdl,
24607c478bd9Sstevel@tonic-gate 					    fmep->fmcase));
24617c478bd9Sstevel@tonic-gate 					ptree_timeval(O_ALTFP|O_NONL,
24627c478bd9Sstevel@tonic-gate 					    (unsigned long long *)&Hesitate);
24637c478bd9Sstevel@tonic-gate 					out(O_ALTFP, "]");
24647aec1d6eScindi 					if (fme_set_timer(fmep, Hesitate))
24657aec1d6eScindi 						fmep->htid = fmep->timer;
24667c478bd9Sstevel@tonic-gate 				} else {
24677c478bd9Sstevel@tonic-gate 					out(O_ALTFP,
24687c478bd9Sstevel@tonic-gate 					    "[still hesitating FME%d, case %s]",
24697c478bd9Sstevel@tonic-gate 					    fmep->id,
24707c478bd9Sstevel@tonic-gate 					    fmd_case_uuid(fmep->hdl,
24717c478bd9Sstevel@tonic-gate 					    fmep->fmcase));
24727c478bd9Sstevel@tonic-gate 				}
24737c478bd9Sstevel@tonic-gate 			} else {
24747c478bd9Sstevel@tonic-gate 				print_suspects(SLNEW, fmep);
24757c478bd9Sstevel@tonic-gate 				(void) upsets_eval(fmep, ffep);
24767c478bd9Sstevel@tonic-gate 				publish_suspects(fmep);
24777c478bd9Sstevel@tonic-gate 				fmep->posted_suspects = 1;
24787c478bd9Sstevel@tonic-gate 				fmd_buf_write(fmep->hdl, fmep->fmcase,
24797c478bd9Sstevel@tonic-gate 				    WOBUF_POSTD,
24807c478bd9Sstevel@tonic-gate 				    (void *)&fmep->posted_suspects,
24817c478bd9Sstevel@tonic-gate 				    sizeof (fmep->posted_suspects));
24827c478bd9Sstevel@tonic-gate 			}
24837c478bd9Sstevel@tonic-gate 			break;
24847c478bd9Sstevel@tonic-gate 
24857c478bd9Sstevel@tonic-gate 		case FME_WAIT:
24867c478bd9Sstevel@tonic-gate 			/*
24877c478bd9Sstevel@tonic-gate 			 * singleton suspect list implies
24887c478bd9Sstevel@tonic-gate 			 * no point in waiting
24897c478bd9Sstevel@tonic-gate 			 */
24907c478bd9Sstevel@tonic-gate 			if (fmep->suspects &&
24917c478bd9Sstevel@tonic-gate 			    fmep->suspects->suspects == NULL) {
24927c478bd9Sstevel@tonic-gate 				print_suspects(SLNEW, fmep);
24937c478bd9Sstevel@tonic-gate 				(void) upsets_eval(fmep, ffep);
24947c478bd9Sstevel@tonic-gate 				publish_suspects(fmep);
24957c478bd9Sstevel@tonic-gate 				fmep->posted_suspects = 1;
24967c478bd9Sstevel@tonic-gate 				fmd_buf_write(fmep->hdl, fmep->fmcase,
24977c478bd9Sstevel@tonic-gate 				    WOBUF_POSTD,
24987c478bd9Sstevel@tonic-gate 				    (void *)&fmep->posted_suspects,
24997c478bd9Sstevel@tonic-gate 				    sizeof (fmep->posted_suspects));
25007c478bd9Sstevel@tonic-gate 				fmep->state = FME_CREDIBLE;
25017c478bd9Sstevel@tonic-gate 			} else {
25027c478bd9Sstevel@tonic-gate 				ASSERT(my_delay > fmep->ull);
25037aec1d6eScindi 				(void) fme_set_timer(fmep, my_delay);
25047c478bd9Sstevel@tonic-gate 				print_suspects(SLWAIT, fmep);
25057c478bd9Sstevel@tonic-gate 			}
25067c478bd9Sstevel@tonic-gate 			break;
25077c478bd9Sstevel@tonic-gate 
25087c478bd9Sstevel@tonic-gate 		case FME_DISPROVED:
25097c478bd9Sstevel@tonic-gate 			print_suspects(SLDISPROVED, fmep);
25107c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_UNSOLVD;
25117c478bd9Sstevel@tonic-gate 			fme_undiagnosable(fmep);
25127c478bd9Sstevel@tonic-gate 			break;
25137c478bd9Sstevel@tonic-gate 		}
25147c478bd9Sstevel@tonic-gate 	}
25157c478bd9Sstevel@tonic-gate 
25167c478bd9Sstevel@tonic-gate 	if (fmep->posted_suspects == 1 && Autoclose != NULL) {
25177c478bd9Sstevel@tonic-gate 		int doclose = 0;
25187c478bd9Sstevel@tonic-gate 
25197c478bd9Sstevel@tonic-gate 		if (strcmp(Autoclose, "true") == 0 ||
25207c478bd9Sstevel@tonic-gate 		    strcmp(Autoclose, "all") == 0)
25217c478bd9Sstevel@tonic-gate 			doclose = 1;
25227c478bd9Sstevel@tonic-gate 
25237c478bd9Sstevel@tonic-gate 		if (strcmp(Autoclose, "upsets") == 0) {
25247c478bd9Sstevel@tonic-gate 			doclose = 1;
25257c478bd9Sstevel@tonic-gate 			for (ep = fmep->suspects; ep; ep = ep->suspects) {
25267c478bd9Sstevel@tonic-gate 				if (ep->t != N_UPSET) {
25277c478bd9Sstevel@tonic-gate 					doclose = 0;
25287c478bd9Sstevel@tonic-gate 					break;
25297c478bd9Sstevel@tonic-gate 				}
25307c478bd9Sstevel@tonic-gate 			}
25317c478bd9Sstevel@tonic-gate 		}
25327c478bd9Sstevel@tonic-gate 
25337c478bd9Sstevel@tonic-gate 		if (doclose) {
25347c478bd9Sstevel@tonic-gate 			out(O_ALTFP, "[closing FME%d, case %s (autoclose)]",
25357c478bd9Sstevel@tonic-gate 			    fmep->id, fmd_case_uuid(fmep->hdl, fmep->fmcase));
25367c478bd9Sstevel@tonic-gate 
25377c478bd9Sstevel@tonic-gate 			destroy_fme_bufs(fmep);
25387c478bd9Sstevel@tonic-gate 			fmd_case_close(fmep->hdl, fmep->fmcase);
25397c478bd9Sstevel@tonic-gate 		}
25407c478bd9Sstevel@tonic-gate 	}
25417c478bd9Sstevel@tonic-gate }
25427c478bd9Sstevel@tonic-gate 
25437c478bd9Sstevel@tonic-gate static void indent(void);
25447c478bd9Sstevel@tonic-gate static int triggered(struct fme *fmep, struct event *ep, int mark);
25457c478bd9Sstevel@tonic-gate static enum fme_state effects_test(struct fme *fmep,
25467aec1d6eScindi     struct event *fault_event, unsigned long long at_latest_by,
25477aec1d6eScindi     unsigned long long *pdelay);
25487c478bd9Sstevel@tonic-gate static enum fme_state requirements_test(struct fme *fmep, struct event *ep,
25497aec1d6eScindi     unsigned long long at_latest_by, unsigned long long *pdelay);
25507c478bd9Sstevel@tonic-gate static enum fme_state causes_test(struct fme *fmep, struct event *ep,
25517c478bd9Sstevel@tonic-gate     unsigned long long at_latest_by, unsigned long long *pdelay);
25527c478bd9Sstevel@tonic-gate 
25537aec1d6eScindi static int
25547aec1d6eScindi checkconstraints(struct fme *fmep, struct arrow *arrowp)
25557aec1d6eScindi {
25567aec1d6eScindi 	struct constraintlist *ctp;
25577aec1d6eScindi 	struct evalue value;
25587aec1d6eScindi 
25597aec1d6eScindi 	if (arrowp->forever_false) {
25607aec1d6eScindi 		char *sep = "";
25617aec1d6eScindi 		indent();
25627aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "  Forever false constraint: ");
25637aec1d6eScindi 		for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) {
25647aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, sep);
25657aec1d6eScindi 			ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0);
25667aec1d6eScindi 			sep = ", ";
25677aec1d6eScindi 		}
25687aec1d6eScindi 		out(O_ALTFP|O_VERB, NULL);
25697aec1d6eScindi 		return (0);
25707aec1d6eScindi 	}
25717aec1d6eScindi 
25727aec1d6eScindi 	for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) {
25737aec1d6eScindi 		if (eval_expr(ctp->cnode, NULL, NULL,
25747aec1d6eScindi 		    &fmep->globals, fmep->cfgdata->cooked,
25757aec1d6eScindi 		    arrowp, 0, &value)) {
25767aec1d6eScindi 			/* evaluation successful */
25777aec1d6eScindi 			if (value.t == UNDEFINED || value.v == 0) {
25787aec1d6eScindi 				/* known false */
25797aec1d6eScindi 				arrowp->forever_false = 1;
25807aec1d6eScindi 				indent();
25817aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
25827aec1d6eScindi 				    "  False constraint: ");
25837aec1d6eScindi 				ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0);
25847aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
25857aec1d6eScindi 				return (0);
25867aec1d6eScindi 			}
25877aec1d6eScindi 		} else {
25887aec1d6eScindi 			/* evaluation unsuccessful -- unknown value */
25897aec1d6eScindi 			indent();
25907aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL,
25917aec1d6eScindi 			    "  Deferred constraint: ");
25927aec1d6eScindi 			ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0);
25937aec1d6eScindi 			out(O_ALTFP|O_VERB, NULL);
25947aec1d6eScindi 			return (2);
25957aec1d6eScindi 		}
25967aec1d6eScindi 	}
25977aec1d6eScindi 	/* known true */
25987aec1d6eScindi 	return (1);
25997aec1d6eScindi }
26007aec1d6eScindi 
26017c478bd9Sstevel@tonic-gate static int
26027c478bd9Sstevel@tonic-gate triggered(struct fme *fmep, struct event *ep, int mark)
26037c478bd9Sstevel@tonic-gate {
26047c478bd9Sstevel@tonic-gate 	struct bubble *bp;
26057c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
26067c478bd9Sstevel@tonic-gate 	int count = 0;
26077c478bd9Sstevel@tonic-gate 
26087c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Tcallcount);
26097c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
26107c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
26117c478bd9Sstevel@tonic-gate 		if (bp->t != B_TO)
26127c478bd9Sstevel@tonic-gate 			continue;
26137c478bd9Sstevel@tonic-gate 		for (ap = itree_next_arrow(bp, NULL); ap;
26147c478bd9Sstevel@tonic-gate 		    ap = itree_next_arrow(bp, ap)) {
26157c478bd9Sstevel@tonic-gate 			/* check count of marks against K in the bubble */
26167aec1d6eScindi 			if ((ap->arrowp->mark & mark) &&
26177c478bd9Sstevel@tonic-gate 			    ++count >= bp->nork)
26187c478bd9Sstevel@tonic-gate 				return (1);
26197c478bd9Sstevel@tonic-gate 		}
26207c478bd9Sstevel@tonic-gate 	}
26217c478bd9Sstevel@tonic-gate 	return (0);
26227c478bd9Sstevel@tonic-gate }
26237c478bd9Sstevel@tonic-gate 
26247aec1d6eScindi static int
26257aec1d6eScindi mark_arrows(struct fme *fmep, struct event *ep, int mark,
26267aec1d6eScindi     unsigned long long at_latest_by, unsigned long long *pdelay)
26277c478bd9Sstevel@tonic-gate {
26287c478bd9Sstevel@tonic-gate 	struct bubble *bp;
26297c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
26307aec1d6eScindi 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
26317aec1d6eScindi 	unsigned long long my_delay;
26327aec1d6eScindi 	enum fme_state result;
26337aec1d6eScindi 	int retval = 0;
26347c478bd9Sstevel@tonic-gate 
26357c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
26367c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
26377c478bd9Sstevel@tonic-gate 		if (bp->t != B_FROM)
26387c478bd9Sstevel@tonic-gate 			continue;
26397aec1d6eScindi 		stats_counter_bump(fmep->Marrowcount);
26407aec1d6eScindi 		for (ap = itree_next_arrow(bp, NULL); ap;
26417aec1d6eScindi 		    ap = itree_next_arrow(bp, ap)) {
26427aec1d6eScindi 			struct event *ep2 = ap->arrowp->head->myevent;
26437aec1d6eScindi 			/*
26447aec1d6eScindi 			 * if we're clearing marks, we can avoid doing
26457aec1d6eScindi 			 * all that work evaluating constraints.
26467aec1d6eScindi 			 */
26477aec1d6eScindi 			if (mark == 0) {
26487aec1d6eScindi 				ap->arrowp->mark &= ~EFFECTS_COUNTER;
26497aec1d6eScindi 				ep2->cached_state &=
26507aec1d6eScindi 				    ~(WAIT_EFFECT|CREDIBLE_EFFECT|PARENT_WAIT);
26517aec1d6eScindi 				(void) mark_arrows(fmep, ep2, mark, 0, NULL);
26527aec1d6eScindi 				continue;
26537aec1d6eScindi 			}
26547aec1d6eScindi 			if (ep2->cached_state & REQMNTS_DISPROVED) {
26557aec1d6eScindi 				indent();
26567aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
26577aec1d6eScindi 				    "  ALREADY DISPROVED ");
26587aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
26597aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
26607aec1d6eScindi 				continue;
26617aec1d6eScindi 			}
26627aec1d6eScindi 			if (ep2->cached_state & WAIT_EFFECT) {
26637aec1d6eScindi 				indent();
26647aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
26657aec1d6eScindi 				    "  ALREADY EFFECTS WAIT ");
26667aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
26677aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
26687aec1d6eScindi 				continue;
26697aec1d6eScindi 			}
26707aec1d6eScindi 			if (ep2->cached_state & CREDIBLE_EFFECT) {
26717aec1d6eScindi 				indent();
26727aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
26737aec1d6eScindi 				    "  ALREADY EFFECTS CREDIBLE ");
26747aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
26757aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
26767aec1d6eScindi 				continue;
26777aec1d6eScindi 			}
26787aec1d6eScindi 			if ((ep2->cached_state & PARENT_WAIT) &&
26797aec1d6eScindi 			    (mark & PARENT_WAIT)) {
26807aec1d6eScindi 				indent();
26817aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
26827aec1d6eScindi 				    "  ALREADY PARENT EFFECTS WAIT ");
26837aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
26847aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
26857aec1d6eScindi 				continue;
26867aec1d6eScindi 			}
26877aec1d6eScindi 			platform_set_payloadnvp(ep2->nvp);
26887aec1d6eScindi 			if (checkconstraints(fmep, ap->arrowp) != 1) {
26897aec1d6eScindi 				platform_set_payloadnvp(NULL);
26907aec1d6eScindi 				indent();
26917aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
26927aec1d6eScindi 				    "  CONSTRAINTS FAIL ");
26937aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
26947aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
26957aec1d6eScindi 				continue;
26967aec1d6eScindi 			}
26977aec1d6eScindi 			platform_set_payloadnvp(NULL);
26987aec1d6eScindi 			ap->arrowp->mark |= EFFECTS_COUNTER;
26997aec1d6eScindi 			if (!triggered(fmep, ep2, EFFECTS_COUNTER)) {
27007aec1d6eScindi 				indent();
27017aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
27027aec1d6eScindi 				    "  K-COUNT NOT YET MET ");
27037aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
27047aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
27057aec1d6eScindi 				continue;
27067aec1d6eScindi 			}
27077aec1d6eScindi 			ep2->cached_state &= ~PARENT_WAIT;
27087aec1d6eScindi 			result = requirements_test(fmep, ep2, at_latest_by +
27097aec1d6eScindi 			    ap->arrowp->maxdelay,
27107aec1d6eScindi 			    &my_delay);
27117aec1d6eScindi 			if (result == FME_WAIT) {
27127aec1d6eScindi 				retval = WAIT_EFFECT;
27137aec1d6eScindi 				if (overall_delay > my_delay)
27147aec1d6eScindi 					overall_delay = my_delay;
27157aec1d6eScindi 				ep2->cached_state |= WAIT_EFFECT;
27167aec1d6eScindi 				indent();
27177aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL, "  EFFECTS WAIT ");
27187aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
27197aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
27207aec1d6eScindi 				indent_push("  E");
27217aec1d6eScindi 				if (mark_arrows(fmep, ep2, PARENT_WAIT,
27227aec1d6eScindi 				    at_latest_by, &my_delay) == WAIT_EFFECT) {
27237aec1d6eScindi 					retval = WAIT_EFFECT;
27247aec1d6eScindi 					if (overall_delay > my_delay)
27257aec1d6eScindi 						overall_delay = my_delay;
27267c478bd9Sstevel@tonic-gate 				}
27277aec1d6eScindi 				indent_pop();
27287aec1d6eScindi 			} else if (result == FME_DISPROVED) {
27297aec1d6eScindi 				indent();
27307aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
27317aec1d6eScindi 				    "  EFFECTS DISPROVED ");
27327aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
27337aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
27347aec1d6eScindi 			} else {
27357aec1d6eScindi 				ep2->cached_state |= mark;
27367aec1d6eScindi 				indent();
27377aec1d6eScindi 				if (mark == CREDIBLE_EFFECT)
27387c478bd9Sstevel@tonic-gate 					out(O_ALTFP|O_VERB|O_NONL,
27397aec1d6eScindi 					    "  EFFECTS CREDIBLE ");
27407aec1d6eScindi 				else
27417aec1d6eScindi 					out(O_ALTFP|O_VERB|O_NONL,
27427aec1d6eScindi 					    "  PARENT EFFECTS WAIT ");
27437aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
27447aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
27457aec1d6eScindi 				indent_push("  E");
27467aec1d6eScindi 				if (mark_arrows(fmep, ep2, mark, at_latest_by,
27477aec1d6eScindi 				    &my_delay) == WAIT_EFFECT) {
27487aec1d6eScindi 					retval = WAIT_EFFECT;
27497aec1d6eScindi 					if (overall_delay > my_delay)
27507aec1d6eScindi 						overall_delay = my_delay;
27517c478bd9Sstevel@tonic-gate 				}
27527aec1d6eScindi 				indent_pop();
27537c478bd9Sstevel@tonic-gate 			}
27547c478bd9Sstevel@tonic-gate 		}
27557c478bd9Sstevel@tonic-gate 	}
27567aec1d6eScindi 	if (retval == WAIT_EFFECT)
27577aec1d6eScindi 		*pdelay = overall_delay;
27587aec1d6eScindi 	return (retval);
27597c478bd9Sstevel@tonic-gate }
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate static enum fme_state
27627aec1d6eScindi effects_test(struct fme *fmep, struct event *fault_event,
27637aec1d6eScindi     unsigned long long at_latest_by, unsigned long long *pdelay)
27647c478bd9Sstevel@tonic-gate {
27657c478bd9Sstevel@tonic-gate 	struct event *error_event;
27667c478bd9Sstevel@tonic-gate 	enum fme_state return_value = FME_CREDIBLE;
27677aec1d6eScindi 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
27687aec1d6eScindi 	unsigned long long my_delay;
27697c478bd9Sstevel@tonic-gate 
27707c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Ecallcount);
27717c478bd9Sstevel@tonic-gate 	indent_push("  E");
27727c478bd9Sstevel@tonic-gate 	indent();
27737c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
27747c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, fault_event);
27757c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
27767c478bd9Sstevel@tonic-gate 
27777aec1d6eScindi 	(void) mark_arrows(fmep, fault_event, CREDIBLE_EFFECT, at_latest_by,
27787aec1d6eScindi 	    &my_delay);
27797c478bd9Sstevel@tonic-gate 	for (error_event = fmep->observations;
27807c478bd9Sstevel@tonic-gate 	    error_event; error_event = error_event->observations) {
27817c478bd9Sstevel@tonic-gate 		indent();
27827c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " ");
27837c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, error_event);
27847aec1d6eScindi 		if (!(error_event->cached_state & CREDIBLE_EFFECT)) {
27857aec1d6eScindi 			if (error_event->cached_state &
27867aec1d6eScindi 			    (PARENT_WAIT|WAIT_EFFECT)) {
27877aec1d6eScindi 				return_value = FME_WAIT;
27887aec1d6eScindi 				if (overall_delay > my_delay)
27897aec1d6eScindi 					overall_delay = my_delay;
27907aec1d6eScindi 				out(O_ALTFP|O_VERB, " NOT YET triggered");
27917aec1d6eScindi 				continue;
27927aec1d6eScindi 			}
27937c478bd9Sstevel@tonic-gate 			return_value = FME_DISPROVED;
27947c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, " NOT triggered");
27957c478bd9Sstevel@tonic-gate 			break;
27967c478bd9Sstevel@tonic-gate 		} else {
27977c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, " triggered");
27987c478bd9Sstevel@tonic-gate 		}
27997c478bd9Sstevel@tonic-gate 	}
28007aec1d6eScindi 	(void) mark_arrows(fmep, fault_event, 0, 0, NULL);
28017c478bd9Sstevel@tonic-gate 
28027c478bd9Sstevel@tonic-gate 	indent();
28037aec1d6eScindi 	out(O_ALTFP|O_VERB|O_NONL, "<-EFFECTS %s ",
28047aec1d6eScindi 	    fme_state2str(return_value));
28057c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, fault_event);
28067c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
28077c478bd9Sstevel@tonic-gate 	indent_pop();
28087aec1d6eScindi 	if (return_value == FME_WAIT)
28097aec1d6eScindi 		*pdelay = overall_delay;
28107c478bd9Sstevel@tonic-gate 	return (return_value);
28117c478bd9Sstevel@tonic-gate }
28127c478bd9Sstevel@tonic-gate 
28137c478bd9Sstevel@tonic-gate static enum fme_state
28147c478bd9Sstevel@tonic-gate requirements_test(struct fme *fmep, struct event *ep,
28157aec1d6eScindi     unsigned long long at_latest_by, unsigned long long *pdelay)
28167c478bd9Sstevel@tonic-gate {
28177c478bd9Sstevel@tonic-gate 	int waiting_events;
28187c478bd9Sstevel@tonic-gate 	int credible_events;
28197aec1d6eScindi 	int deferred_events;
28207c478bd9Sstevel@tonic-gate 	enum fme_state return_value = FME_CREDIBLE;
28217c478bd9Sstevel@tonic-gate 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
28227c478bd9Sstevel@tonic-gate 	unsigned long long arrow_delay;
28237c478bd9Sstevel@tonic-gate 	unsigned long long my_delay;
28247c478bd9Sstevel@tonic-gate 	struct event *ep2;
28257c478bd9Sstevel@tonic-gate 	struct bubble *bp;
28267c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
28277c478bd9Sstevel@tonic-gate 
28287aec1d6eScindi 	if (ep->cached_state & REQMNTS_CREDIBLE) {
28297aec1d6eScindi 		indent();
28307aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "  REQMNTS ALREADY CREDIBLE ");
28317aec1d6eScindi 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
28327aec1d6eScindi 		out(O_ALTFP|O_VERB, NULL);
28337aec1d6eScindi 		return (FME_CREDIBLE);
28347aec1d6eScindi 	}
28357aec1d6eScindi 	if (ep->cached_state & REQMNTS_DISPROVED) {
28367aec1d6eScindi 		indent();
28377aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "  REQMNTS ALREADY DISPROVED ");
28387aec1d6eScindi 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
28397aec1d6eScindi 		out(O_ALTFP|O_VERB, NULL);
28407aec1d6eScindi 		return (FME_DISPROVED);
28417aec1d6eScindi 	}
28427aec1d6eScindi 	if (ep->cached_state & REQMNTS_WAIT) {
28437aec1d6eScindi 		indent();
28447aec1d6eScindi 		*pdelay = ep->cached_delay;
28457aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "  REQMNTS ALREADY WAIT ");
28467aec1d6eScindi 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
28477aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, ", wait for: ");
28487aec1d6eScindi 		ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
28497aec1d6eScindi 		out(O_ALTFP|O_VERB, NULL);
28507aec1d6eScindi 		return (FME_WAIT);
28517aec1d6eScindi 	}
28527c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Rcallcount);
28537c478bd9Sstevel@tonic-gate 	indent_push("  R");
28547c478bd9Sstevel@tonic-gate 	indent();
28557c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
28567c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
28577c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, ", at latest by: ");
28587c478bd9Sstevel@tonic-gate 	ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
28597c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
28607c478bd9Sstevel@tonic-gate 
28617c478bd9Sstevel@tonic-gate 	if (ep->t == N_EREPORT) {
28627c478bd9Sstevel@tonic-gate 		if (ep->count == 0) {
28637c478bd9Sstevel@tonic-gate 			if (fmep->pull >= at_latest_by) {
28647c478bd9Sstevel@tonic-gate 				return_value = FME_DISPROVED;
28657c478bd9Sstevel@tonic-gate 			} else {
28667aec1d6eScindi 				ep->cached_delay = *pdelay = at_latest_by;
28677c478bd9Sstevel@tonic-gate 				return_value = FME_WAIT;
28687c478bd9Sstevel@tonic-gate 			}
28697c478bd9Sstevel@tonic-gate 		}
28707c478bd9Sstevel@tonic-gate 
28717c478bd9Sstevel@tonic-gate 		indent();
28727c478bd9Sstevel@tonic-gate 		switch (return_value) {
28737c478bd9Sstevel@tonic-gate 		case FME_CREDIBLE:
28747aec1d6eScindi 			ep->cached_state |= REQMNTS_CREDIBLE;
28757aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS CREDIBLE ");
28767c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
28777c478bd9Sstevel@tonic-gate 			break;
28787c478bd9Sstevel@tonic-gate 		case FME_DISPROVED:
28797aec1d6eScindi 			ep->cached_state |= REQMNTS_DISPROVED;
28807aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS DISPROVED ");
28817c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
28827c478bd9Sstevel@tonic-gate 			break;
28837c478bd9Sstevel@tonic-gate 		case FME_WAIT:
28847aec1d6eScindi 			ep->cached_state |= REQMNTS_WAIT;
28857aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS WAIT ");
28867c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
28877c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB|O_NONL, " to ");
28887c478bd9Sstevel@tonic-gate 			ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
28897c478bd9Sstevel@tonic-gate 			break;
28907c478bd9Sstevel@tonic-gate 		default:
28917c478bd9Sstevel@tonic-gate 			out(O_DIE, "requirements_test: unexpected fme_state");
28927c478bd9Sstevel@tonic-gate 			break;
28937c478bd9Sstevel@tonic-gate 		}
28947c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
28957c478bd9Sstevel@tonic-gate 		indent_pop();
28967c478bd9Sstevel@tonic-gate 
28977c478bd9Sstevel@tonic-gate 		return (return_value);
28987c478bd9Sstevel@tonic-gate 	}
28997c478bd9Sstevel@tonic-gate 
29007c478bd9Sstevel@tonic-gate 	/* this event is not a report, descend the tree */
29017c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
29027c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
29037aec1d6eScindi 		int n;
29047aec1d6eScindi 
29057c478bd9Sstevel@tonic-gate 		if (bp->t != B_FROM)
29067c478bd9Sstevel@tonic-gate 			continue;
29077c478bd9Sstevel@tonic-gate 
29087aec1d6eScindi 		n = bp->nork;
29097aec1d6eScindi 
29107aec1d6eScindi 		credible_events = 0;
29117aec1d6eScindi 		waiting_events = 0;
29127aec1d6eScindi 		deferred_events = 0;
29137aec1d6eScindi 		arrow_delay = TIMEVAL_EVENTUALLY;
29147aec1d6eScindi 		/*
29157aec1d6eScindi 		 * n is -1 for 'A' so adjust it.
29167aec1d6eScindi 		 * XXX just count up the arrows for now.
29177aec1d6eScindi 		 */
29187aec1d6eScindi 		if (n < 0) {
29197aec1d6eScindi 			n = 0;
29207aec1d6eScindi 			for (ap = itree_next_arrow(bp, NULL); ap;
29217aec1d6eScindi 			    ap = itree_next_arrow(bp, ap))
29227aec1d6eScindi 				n++;
29237aec1d6eScindi 			indent();
29247aec1d6eScindi 			out(O_ALTFP|O_VERB, " Bubble Counted N=%d", n);
29257aec1d6eScindi 		} else {
29267aec1d6eScindi 			indent();
29277aec1d6eScindi 			out(O_ALTFP|O_VERB, " Bubble N=%d", n);
29287aec1d6eScindi 		}
29297c478bd9Sstevel@tonic-gate 
29307aec1d6eScindi 		if (n == 0)
29317aec1d6eScindi 			continue;
29327aec1d6eScindi 		if (!(bp->mark & (BUBBLE_ELIDED|BUBBLE_OK))) {
29337c478bd9Sstevel@tonic-gate 			for (ap = itree_next_arrow(bp, NULL); ap;
29347c478bd9Sstevel@tonic-gate 			    ap = itree_next_arrow(bp, ap)) {
29357c478bd9Sstevel@tonic-gate 				ep2 = ap->arrowp->head->myevent;
29367aec1d6eScindi 				platform_set_payloadnvp(ep2->nvp);
29377aec1d6eScindi 				if (checkconstraints(fmep, ap->arrowp) == 0) {
29387aec1d6eScindi 					/*
29397aec1d6eScindi 					 * if any arrow is invalidated by the
29407aec1d6eScindi 					 * constraints, then we should elide the
29417aec1d6eScindi 					 * whole bubble to be consistant with
29427aec1d6eScindi 					 * the tree creation time behaviour
29437aec1d6eScindi 					 */
29447aec1d6eScindi 					bp->mark |= BUBBLE_ELIDED;
29457aec1d6eScindi 					platform_set_payloadnvp(NULL);
29467c478bd9Sstevel@tonic-gate 					break;
29477aec1d6eScindi 				}
29487aec1d6eScindi 				platform_set_payloadnvp(NULL);
29497aec1d6eScindi 			}
29507aec1d6eScindi 		}
29517aec1d6eScindi 		if (bp->mark & BUBBLE_ELIDED)
29527aec1d6eScindi 			continue;
29537aec1d6eScindi 		bp->mark |= BUBBLE_OK;
29547aec1d6eScindi 		for (ap = itree_next_arrow(bp, NULL); ap;
29557aec1d6eScindi 		    ap = itree_next_arrow(bp, ap)) {
29567aec1d6eScindi 			ep2 = ap->arrowp->head->myevent;
29577aec1d6eScindi 			if (n <= credible_events)
29587aec1d6eScindi 				break;
29597c478bd9Sstevel@tonic-gate 
29607aec1d6eScindi 			ap->arrowp->mark |= REQMNTS_COUNTER;
29617aec1d6eScindi 			if (triggered(fmep, ep2, REQMNTS_COUNTER))
29627aec1d6eScindi 				/* XXX adding max timevals! */
29637aec1d6eScindi 				switch (requirements_test(fmep, ep2,
29647aec1d6eScindi 				    at_latest_by + ap->arrowp->maxdelay,
29657aec1d6eScindi 				    &my_delay)) {
29667aec1d6eScindi 				case FME_DEFERRED:
29677aec1d6eScindi 					deferred_events++;
29687aec1d6eScindi 					break;
29697aec1d6eScindi 				case FME_CREDIBLE:
29707c478bd9Sstevel@tonic-gate 					credible_events++;
29717aec1d6eScindi 					break;
29727aec1d6eScindi 				case FME_DISPROVED:
29737aec1d6eScindi 					break;
29747aec1d6eScindi 				case FME_WAIT:
29757aec1d6eScindi 					if (my_delay < arrow_delay)
29767aec1d6eScindi 						arrow_delay = my_delay;
29777aec1d6eScindi 					waiting_events++;
29787aec1d6eScindi 					break;
29797aec1d6eScindi 				default:
29807aec1d6eScindi 					out(O_DIE,
29817aec1d6eScindi 					"Bug in requirements_test.");
29827aec1d6eScindi 				}
29837aec1d6eScindi 			else
29847aec1d6eScindi 				deferred_events++;
29857aec1d6eScindi 		}
29867aec1d6eScindi 		indent();
29877aec1d6eScindi 		out(O_ALTFP|O_VERB, " Credible: %d Waiting %d",
29887aec1d6eScindi 		    credible_events + deferred_events, waiting_events);
29897aec1d6eScindi 		if (credible_events + deferred_events + waiting_events < n) {
29907aec1d6eScindi 			/* Can never meet requirements */
29917aec1d6eScindi 			ep->cached_state |= REQMNTS_DISPROVED;
29927c478bd9Sstevel@tonic-gate 			indent();
29937aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS DISPROVED ");
29947c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
29957c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, NULL);
29967aec1d6eScindi 			indent_pop();
29977aec1d6eScindi 			return (FME_DISPROVED);
29987aec1d6eScindi 		}
29997aec1d6eScindi 		if (credible_events + deferred_events < n) {
30007aec1d6eScindi 			/* will have to wait */
30017aec1d6eScindi 			/* wait time is shortest known */
30027aec1d6eScindi 			if (arrow_delay < overall_delay)
30037aec1d6eScindi 				overall_delay = arrow_delay;
30047aec1d6eScindi 			return_value = FME_WAIT;
30057aec1d6eScindi 		} else if (credible_events < n) {
30067aec1d6eScindi 			if (return_value != FME_WAIT)
30077aec1d6eScindi 				return_value = FME_DEFERRED;
30087c478bd9Sstevel@tonic-gate 		}
30097c478bd9Sstevel@tonic-gate 	}
30107c478bd9Sstevel@tonic-gate 
30117c478bd9Sstevel@tonic-gate 	/*
30127aec1d6eScindi 	 * don't mark as FME_DEFERRED. If this event isn't reached by another
30137aec1d6eScindi 	 * path, then this will be considered FME_CREDIBLE. But if it is
30147aec1d6eScindi 	 * reached by a different path so the K-count is met, then might
30157aec1d6eScindi 	 * get overridden by FME_WAIT or FME_DISPROVED.
30167c478bd9Sstevel@tonic-gate 	 */
30177aec1d6eScindi 	if (return_value == FME_WAIT) {
30187aec1d6eScindi 		ep->cached_state |= REQMNTS_WAIT;
30197aec1d6eScindi 		ep->cached_delay = *pdelay = overall_delay;
30207aec1d6eScindi 	} else if (return_value == FME_CREDIBLE) {
30217aec1d6eScindi 		ep->cached_state |= REQMNTS_CREDIBLE;
30227c478bd9Sstevel@tonic-gate 	}
30237c478bd9Sstevel@tonic-gate 	indent();
30247aec1d6eScindi 	out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS %s ",
30257aec1d6eScindi 	    fme_state2str(return_value));
30267c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
30277c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
30287c478bd9Sstevel@tonic-gate 	indent_pop();
30297c478bd9Sstevel@tonic-gate 	return (return_value);
30307c478bd9Sstevel@tonic-gate }
30317c478bd9Sstevel@tonic-gate 
30327c478bd9Sstevel@tonic-gate static enum fme_state
30337c478bd9Sstevel@tonic-gate causes_test(struct fme *fmep, struct event *ep,
30347c478bd9Sstevel@tonic-gate     unsigned long long at_latest_by, unsigned long long *pdelay)
30357c478bd9Sstevel@tonic-gate {
30367c478bd9Sstevel@tonic-gate 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
30377c478bd9Sstevel@tonic-gate 	unsigned long long my_delay;
30387c478bd9Sstevel@tonic-gate 	int credible_results = 0;
30397c478bd9Sstevel@tonic-gate 	int waiting_results = 0;
30407c478bd9Sstevel@tonic-gate 	enum fme_state fstate;
30417c478bd9Sstevel@tonic-gate 	struct event *tail_event;
30427c478bd9Sstevel@tonic-gate 	struct bubble *bp;
30437c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
30447c478bd9Sstevel@tonic-gate 	int k = 1;
30457c478bd9Sstevel@tonic-gate 
30467c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Ccallcount);
30477c478bd9Sstevel@tonic-gate 	indent_push("  C");
30487c478bd9Sstevel@tonic-gate 	indent();
30497c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
30507c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
30517c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
30527c478bd9Sstevel@tonic-gate 
30537c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
30547c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
30557c478bd9Sstevel@tonic-gate 		if (bp->t != B_TO)
30567c478bd9Sstevel@tonic-gate 			continue;
30577c478bd9Sstevel@tonic-gate 		k = bp->nork;	/* remember the K value */
30587c478bd9Sstevel@tonic-gate 		for (ap = itree_next_arrow(bp, NULL); ap;
30597c478bd9Sstevel@tonic-gate 		    ap = itree_next_arrow(bp, ap)) {
30607c478bd9Sstevel@tonic-gate 			int do_not_follow = 0;
30617aec1d6eScindi 
30627aec1d6eScindi 			/*
30637aec1d6eScindi 			 * if we get to the same event multiple times
30647aec1d6eScindi 			 * only worry about the first one.
30657aec1d6eScindi 			 */
30667aec1d6eScindi 			if (ap->arrowp->tail->myevent->cached_state &
30677aec1d6eScindi 			    CAUSES_TESTED) {
30687aec1d6eScindi 				indent();
30697aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
30707aec1d6eScindi 				    "  causes test already run for ");
30717aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL,
30727aec1d6eScindi 				    ap->arrowp->tail->myevent);
30737aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
30747aec1d6eScindi 				continue;
30757aec1d6eScindi 			}
30767aec1d6eScindi 
30777c478bd9Sstevel@tonic-gate 			/*
30787c478bd9Sstevel@tonic-gate 			 * see if false constraint prevents us
30797c478bd9Sstevel@tonic-gate 			 * from traversing this arrow
30807c478bd9Sstevel@tonic-gate 			 */
30817c478bd9Sstevel@tonic-gate 			platform_set_payloadnvp(ep->nvp);
30827aec1d6eScindi 			if (checkconstraints(fmep, ap->arrowp) != 1)
30837aec1d6eScindi 				do_not_follow = 1;
30847c478bd9Sstevel@tonic-gate 			platform_set_payloadnvp(NULL);
30857c478bd9Sstevel@tonic-gate 			if (do_not_follow) {
30867c478bd9Sstevel@tonic-gate 				indent();
30877c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB|O_NONL,
30887c478bd9Sstevel@tonic-gate 				    "  False arrow from ");
30897c478bd9Sstevel@tonic-gate 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL,
30907c478bd9Sstevel@tonic-gate 				    ap->arrowp->tail->myevent);
30917c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB, NULL);
30927c478bd9Sstevel@tonic-gate 				continue;
30937c478bd9Sstevel@tonic-gate 			}
30947c478bd9Sstevel@tonic-gate 
30957aec1d6eScindi 			ap->arrowp->tail->myevent->cached_state |=
30967aec1d6eScindi 			    CAUSES_TESTED;
30977aec1d6eScindi 			tail_event = ap->arrowp->tail->myevent;
30987aec1d6eScindi 			fstate = hypothesise(fmep, tail_event, at_latest_by,
30997aec1d6eScindi 			    &my_delay);
31007c478bd9Sstevel@tonic-gate 
31017c478bd9Sstevel@tonic-gate 			switch (fstate) {
31027c478bd9Sstevel@tonic-gate 			case FME_WAIT:
31037c478bd9Sstevel@tonic-gate 				if (my_delay < overall_delay)
31047c478bd9Sstevel@tonic-gate 					overall_delay = my_delay;
31057c478bd9Sstevel@tonic-gate 				waiting_results++;
31067c478bd9Sstevel@tonic-gate 				break;
31077c478bd9Sstevel@tonic-gate 			case FME_CREDIBLE:
31087c478bd9Sstevel@tonic-gate 				credible_results++;
31097c478bd9Sstevel@tonic-gate 				break;
31107c478bd9Sstevel@tonic-gate 			case FME_DISPROVED:
31117c478bd9Sstevel@tonic-gate 				break;
31127c478bd9Sstevel@tonic-gate 			default:
31137c478bd9Sstevel@tonic-gate 				out(O_DIE, "Bug in causes_test");
31147c478bd9Sstevel@tonic-gate 			}
31157c478bd9Sstevel@tonic-gate 		}
31167c478bd9Sstevel@tonic-gate 	}
31177c478bd9Sstevel@tonic-gate 	/* compare against K */
31187c478bd9Sstevel@tonic-gate 	if (credible_results + waiting_results < k) {
31197c478bd9Sstevel@tonic-gate 		indent();
31207aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES DISPROVED ");
31217c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31227c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
31237c478bd9Sstevel@tonic-gate 		indent_pop();
31247c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
31257c478bd9Sstevel@tonic-gate 	}
31267c478bd9Sstevel@tonic-gate 	if (waiting_results != 0) {
31277c478bd9Sstevel@tonic-gate 		*pdelay = overall_delay;
31287c478bd9Sstevel@tonic-gate 		indent();
31297aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES WAIT ");
31307c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31317c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " to ");
31327c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
31337c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
31347c478bd9Sstevel@tonic-gate 		indent_pop();
31357c478bd9Sstevel@tonic-gate 		return (FME_WAIT);
31367c478bd9Sstevel@tonic-gate 	}
31377c478bd9Sstevel@tonic-gate 	indent();
31387aec1d6eScindi 	out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES CREDIBLE ");
31397c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31407c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
31417c478bd9Sstevel@tonic-gate 	indent_pop();
31427c478bd9Sstevel@tonic-gate 	return (FME_CREDIBLE);
31437c478bd9Sstevel@tonic-gate }
31447c478bd9Sstevel@tonic-gate 
31457c478bd9Sstevel@tonic-gate static enum fme_state
31467c478bd9Sstevel@tonic-gate hypothesise(struct fme *fmep, struct event *ep,
31477aec1d6eScindi 	unsigned long long at_latest_by, unsigned long long *pdelay)
31487c478bd9Sstevel@tonic-gate {
31497c478bd9Sstevel@tonic-gate 	enum fme_state rtr, otr;
31507c478bd9Sstevel@tonic-gate 	unsigned long long my_delay;
31517c478bd9Sstevel@tonic-gate 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
31527c478bd9Sstevel@tonic-gate 
31537c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Hcallcount);
31547c478bd9Sstevel@tonic-gate 	indent_push("  H");
31557c478bd9Sstevel@tonic-gate 	indent();
31567c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
31577c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31587c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, ", at latest by: ");
31597c478bd9Sstevel@tonic-gate 	ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
31607c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
31617c478bd9Sstevel@tonic-gate 
31627aec1d6eScindi 	rtr = requirements_test(fmep, ep, at_latest_by, &my_delay);
31637c478bd9Sstevel@tonic-gate 	if ((rtr == FME_WAIT) && (my_delay < overall_delay))
31647c478bd9Sstevel@tonic-gate 		overall_delay = my_delay;
31657c478bd9Sstevel@tonic-gate 	if (rtr != FME_DISPROVED) {
31667c478bd9Sstevel@tonic-gate 		if (is_problem(ep->t)) {
31677aec1d6eScindi 			otr = effects_test(fmep, ep, at_latest_by, &my_delay);
31687c478bd9Sstevel@tonic-gate 			if (otr != FME_DISPROVED) {
31697c478bd9Sstevel@tonic-gate 				if (fmep->peek == 0 && ep->is_suspect++ == 0) {
31707c478bd9Sstevel@tonic-gate 					ep->suspects = fmep->suspects;
31717c478bd9Sstevel@tonic-gate 					fmep->suspects = ep;
31727c478bd9Sstevel@tonic-gate 					fmep->nsuspects++;
31737c478bd9Sstevel@tonic-gate 					if (!is_fault(ep->t))
31747c478bd9Sstevel@tonic-gate 						fmep->nonfault++;
31757c478bd9Sstevel@tonic-gate 				}
31767c478bd9Sstevel@tonic-gate 			}
31777c478bd9Sstevel@tonic-gate 		} else
31787c478bd9Sstevel@tonic-gate 			otr = causes_test(fmep, ep, at_latest_by, &my_delay);
31797c478bd9Sstevel@tonic-gate 		if ((otr == FME_WAIT) && (my_delay < overall_delay))
31807c478bd9Sstevel@tonic-gate 			overall_delay = my_delay;
31817c478bd9Sstevel@tonic-gate 		if ((otr != FME_DISPROVED) &&
31827c478bd9Sstevel@tonic-gate 		    ((rtr == FME_WAIT) || (otr == FME_WAIT)))
31837c478bd9Sstevel@tonic-gate 			*pdelay = overall_delay;
31847c478bd9Sstevel@tonic-gate 	}
31857c478bd9Sstevel@tonic-gate 	if (rtr == FME_DISPROVED) {
31867c478bd9Sstevel@tonic-gate 		indent();
31877c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
31887c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31897c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, " (doesn't meet requirements)");
31907c478bd9Sstevel@tonic-gate 		indent_pop();
31917c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
31927c478bd9Sstevel@tonic-gate 	}
31937c478bd9Sstevel@tonic-gate 	if ((otr == FME_DISPROVED) && is_problem(ep->t)) {
31947c478bd9Sstevel@tonic-gate 		indent();
31957c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
31967c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31977c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, " (doesn't explain all reports)");
31987c478bd9Sstevel@tonic-gate 		indent_pop();
31997c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
32007c478bd9Sstevel@tonic-gate 	}
32017c478bd9Sstevel@tonic-gate 	if (otr == FME_DISPROVED) {
32027c478bd9Sstevel@tonic-gate 		indent();
32037c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
32047c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
32057c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, " (causes are not credible)");
32067c478bd9Sstevel@tonic-gate 		indent_pop();
32077c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
32087c478bd9Sstevel@tonic-gate 	}
32097c478bd9Sstevel@tonic-gate 	if ((rtr == FME_WAIT) || (otr == FME_WAIT)) {
32107c478bd9Sstevel@tonic-gate 		indent();
32117c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-WAIT ");
32127c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
32137c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " to ");
32147c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB|O_NONL, &overall_delay);
32157c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
32167c478bd9Sstevel@tonic-gate 		indent_pop();
32177c478bd9Sstevel@tonic-gate 		return (FME_WAIT);
32187c478bd9Sstevel@tonic-gate 	}
32197c478bd9Sstevel@tonic-gate 	indent();
32207c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "<-CREDIBLE ");
32217c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
32227c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
32237c478bd9Sstevel@tonic-gate 	indent_pop();
32247c478bd9Sstevel@tonic-gate 	return (FME_CREDIBLE);
32257c478bd9Sstevel@tonic-gate }
32267aec1d6eScindi 
32277aec1d6eScindi /*
32287aec1d6eScindi  * fme_istat_load -- reconstitute any persistent istats
32297aec1d6eScindi  */
32307aec1d6eScindi void
32317aec1d6eScindi fme_istat_load(fmd_hdl_t *hdl)
32327aec1d6eScindi {
32337aec1d6eScindi 	int sz;
32347aec1d6eScindi 	char *sbuf;
32357aec1d6eScindi 	char *ptr;
32367aec1d6eScindi 
32377aec1d6eScindi 	if ((sz = fmd_buf_size(hdl, NULL, WOBUF_ISTATS)) == 0) {
32387aec1d6eScindi 		out(O_ALTFP, "fme_istat_load: No stats");
32397aec1d6eScindi 		return;
32407aec1d6eScindi 	}
32417aec1d6eScindi 
32427aec1d6eScindi 	sbuf = alloca(sz);
32437aec1d6eScindi 
32447aec1d6eScindi 	fmd_buf_read(hdl, NULL, WOBUF_ISTATS, sbuf, sz);
32457aec1d6eScindi 
32467aec1d6eScindi 	/*
32477aec1d6eScindi 	 * pick apart the serialized stats
32487aec1d6eScindi 	 *
32497aec1d6eScindi 	 * format is:
32507aec1d6eScindi 	 *	<class-name>, '@', <path>, '\0', <value>, '\0'
32517aec1d6eScindi 	 * for example:
32527aec1d6eScindi 	 *	"stat.first@stat0/path0\02\0stat.second@stat0/path1\023\0"
32537aec1d6eScindi 	 *
32547aec1d6eScindi 	 * since this is parsing our own serialized data, any parsing issues
32557aec1d6eScindi 	 * are fatal, so we check for them all with ASSERT() below.
32567aec1d6eScindi 	 */
32577aec1d6eScindi 	ptr = sbuf;
32587aec1d6eScindi 	while (ptr < &sbuf[sz]) {
32597aec1d6eScindi 		char *sepptr;
32607aec1d6eScindi 		struct node *np;
32617aec1d6eScindi 		int val;
32627aec1d6eScindi 
32637aec1d6eScindi 		sepptr = strchr(ptr, '@');
32647aec1d6eScindi 		ASSERT(sepptr != NULL);
32657aec1d6eScindi 		*sepptr = '\0';
32667aec1d6eScindi 
32677aec1d6eScindi 		/* construct the event */
32687aec1d6eScindi 		np = newnode(T_EVENT, NULL, 0);
32697aec1d6eScindi 		np->u.event.ename = newnode(T_NAME, NULL, 0);
32707aec1d6eScindi 		np->u.event.ename->u.name.t = N_STAT;
32717aec1d6eScindi 		np->u.event.ename->u.name.s = stable(ptr);
32727aec1d6eScindi 		np->u.event.ename->u.name.it = IT_ENAME;
32737aec1d6eScindi 		np->u.event.ename->u.name.last = np->u.event.ename;
32747aec1d6eScindi 
32757aec1d6eScindi 		ptr = sepptr + 1;
32767aec1d6eScindi 		ASSERT(ptr < &sbuf[sz]);
32777aec1d6eScindi 		ptr += strlen(ptr);
32787aec1d6eScindi 		ptr++;	/* move past the '\0' separating path from value */
32797aec1d6eScindi 		ASSERT(ptr < &sbuf[sz]);
32807aec1d6eScindi 		ASSERT(isdigit(*ptr));
32817aec1d6eScindi 		val = atoi(ptr);
32827aec1d6eScindi 		ASSERT(val > 0);
32837aec1d6eScindi 		ptr += strlen(ptr);
32847aec1d6eScindi 		ptr++;	/* move past the final '\0' for this entry */
32857aec1d6eScindi 
32867aec1d6eScindi 		np->u.event.epname = pathstring2epnamenp(sepptr + 1);
32877aec1d6eScindi 		ASSERT(np->u.event.epname != NULL);
32887aec1d6eScindi 
32897aec1d6eScindi 		istat_bump(np, val);
32907aec1d6eScindi 		tree_free(np);
32917aec1d6eScindi 	}
32927aec1d6eScindi 
32937aec1d6eScindi 	istat_save();
32947aec1d6eScindi }
3295