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
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
23*7aec1d6eScindi  * 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;
60*7aec1d6eScindi 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;
64*7aec1d6eScindi extern fmd_hdl_t *Hdl;
65*7aec1d6eScindi 
66*7aec1d6eScindi 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 */
113*7aec1d6eScindi 		FME_DISPROVED,		/* no valid suspects found */
114*7aec1d6eScindi 		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,
142*7aec1d6eScindi 	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);
473*7aec1d6eScindi 			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 
653*7aec1d6eScindi /*ARGSUSED*/
654*7aec1d6eScindi static void
655*7aec1d6eScindi globals_destructor(void *left, void *right, void *arg)
656*7aec1d6eScindi {
657*7aec1d6eScindi 	struct evalue *evp = (struct evalue *)right;
658*7aec1d6eScindi 	if (evp->t == NODEPTR)
659*7aec1d6eScindi 		tree_free((struct node *)evp->v);
660*7aec1d6eScindi 	evp->v = NULL;
661*7aec1d6eScindi 	FREE(evp);
662*7aec1d6eScindi }
663*7aec1d6eScindi 
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);
678*7aec1d6eScindi 	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");
690*7aec1d6eScindi 	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
781*7aec1d6eScindi serd_eval(struct fme *fmep, fmd_hdl_t *hdl, fmd_event_t *ffep,
782*7aec1d6eScindi     fmd_case_t *fmcase, struct event *sp, const char **enamep,
783*7aec1d6eScindi     const struct ipath **ippp)
7847c478bd9Sstevel@tonic-gate {
7857c478bd9Sstevel@tonic-gate 	struct node *serdinst;
7867c478bd9Sstevel@tonic-gate 	char *serdname;
787*7aec1d6eScindi 	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 
804*7aec1d6eScindi 	/* handle serd engine "id" property, if there is one */
805*7aec1d6eScindi 	if ((nid =
806*7aec1d6eScindi 	    lut_lookup(serdinst->u.stmt.lutp, (void *)L_id, NULL)) != NULL) {
807*7aec1d6eScindi 		struct evalue *gval;
808*7aec1d6eScindi 		char suffixbuf[200];
809*7aec1d6eScindi 		char *suffix;
810*7aec1d6eScindi 		char *nserdname;
811*7aec1d6eScindi 		size_t nname;
812*7aec1d6eScindi 
813*7aec1d6eScindi 		out(O_ALTFP|O_NONL, "serd \"%s\" id: ", serdname);
814*7aec1d6eScindi 		ptree_name_iter(O_ALTFP|O_NONL, nid);
815*7aec1d6eScindi 
816*7aec1d6eScindi 		ASSERTinfo(nid->t == T_GLOBID, ptree_nodetype2str(nid->t));
817*7aec1d6eScindi 
818*7aec1d6eScindi 		if ((gval = lut_lookup(fmep->globals,
819*7aec1d6eScindi 		    (void *)nid->u.globid.s, NULL)) == NULL) {
820*7aec1d6eScindi 			out(O_ALTFP, " undefined");
821*7aec1d6eScindi 		} else if (gval->t == UINT64) {
822*7aec1d6eScindi 			out(O_ALTFP, " %llu", gval->v);
823*7aec1d6eScindi 			(void) sprintf(suffixbuf, "%llu", gval->v);
824*7aec1d6eScindi 			suffix = suffixbuf;
825*7aec1d6eScindi 		} else {
826*7aec1d6eScindi 			out(O_ALTFP, " \"%s\"", (char *)gval->v);
827*7aec1d6eScindi 			suffix = (char *)gval->v;
828*7aec1d6eScindi 		}
829*7aec1d6eScindi 
830*7aec1d6eScindi 		nname = strlen(serdname) + strlen(suffix) + 2;
831*7aec1d6eScindi 		nserdname = MALLOC(nname);
832*7aec1d6eScindi 		(void) snprintf(nserdname, nname, "%s:%s", serdname, suffix);
833*7aec1d6eScindi 		FREE(serdname);
834*7aec1d6eScindi 		serdname = nserdname;
835*7aec1d6eScindi 	}
836*7aec1d6eScindi 
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 &&
922*7aec1d6eScindi 		    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++)
927*7aec1d6eScindi 		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 
962*7aec1d6eScindi static int mark_arrows(struct fme *fmep, struct event *ep, int mark,
963*7aec1d6eScindi     unsigned long long at_latest_by, unsigned long long *pdelay);
964*7aec1d6eScindi 
965*7aec1d6eScindi /* ARGSUSED */
966*7aec1d6eScindi static void
967*7aec1d6eScindi clear_arrows(struct event *ep, struct event *ep2, struct fme *fmep)
968*7aec1d6eScindi {
969*7aec1d6eScindi 	struct bubble *bp;
970*7aec1d6eScindi 	struct arrowlist *ap;
971*7aec1d6eScindi 
972*7aec1d6eScindi 	ep->cached_state = 0;
973*7aec1d6eScindi 	for (bp = itree_next_bubble(ep, NULL); bp;
974*7aec1d6eScindi 	    bp = itree_next_bubble(ep, bp)) {
975*7aec1d6eScindi 		if (bp->t != B_FROM)
976*7aec1d6eScindi 			continue;
977*7aec1d6eScindi 		bp->mark = 0;
978*7aec1d6eScindi 		for (ap = itree_next_arrow(bp, NULL); ap;
979*7aec1d6eScindi 		    ap = itree_next_arrow(bp, ap))
980*7aec1d6eScindi 			ap->arrowp->mark = 0;
981*7aec1d6eScindi 	}
982*7aec1d6eScindi }
983*7aec1d6eScindi 
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;
1004*7aec1d6eScindi 		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);
1025*7aec1d6eScindi 		} else {
1026*7aec1d6eScindi 			/* use new payload values for peek */
1027*7aec1d6eScindi 			pre_peek_nvp = ep->nvp;
1028*7aec1d6eScindi 			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 
1039*7aec1d6eScindi 		lut_walk(fmep->eventtree, (lut_cb)clear_arrows, (void *)fmep);
1040*7aec1d6eScindi 		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 
1054*7aec1d6eScindi 			if (pre_peek_nvp)
1055*7aec1d6eScindi 				nvlist_free(pre_peek_nvp);
1056*7aec1d6eScindi 
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;
1077*7aec1d6eScindi 			} else {
1078*7aec1d6eScindi 				nvlist_free(ep->nvp);
1079*7aec1d6eScindi 				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);
1168*7aec1d6eScindi 	} else {
1169*7aec1d6eScindi 		/* new payload overrides any previous */
1170*7aec1d6eScindi 		nvlist_free(ep->nvp);
1171*7aec1d6eScindi 		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 
1611*7aec1d6eScindi /*
1612*7aec1d6eScindi  * addpayloadprop -- add a payload prop to a problem
1613*7aec1d6eScindi  */
1614*7aec1d6eScindi static void
1615*7aec1d6eScindi addpayloadprop(const char *lhs, struct evalue *rhs, nvlist_t *fault)
1616*7aec1d6eScindi {
1617*7aec1d6eScindi 	ASSERT(fault != NULL);
1618*7aec1d6eScindi 	ASSERT(lhs != NULL);
1619*7aec1d6eScindi 	ASSERT(rhs != NULL);
1620*7aec1d6eScindi 
1621*7aec1d6eScindi 	if (rhs->t == UINT64) {
1622*7aec1d6eScindi 		out(O_ALTFP|O_VERB2, "addpayloadprop: %s=%llu", lhs, rhs->v);
1623*7aec1d6eScindi 
1624*7aec1d6eScindi 		if (nvlist_add_uint64(fault, lhs, rhs->v) != 0)
1625*7aec1d6eScindi 			out(O_DIE,
1626*7aec1d6eScindi 			    "cannot add payloadprop \"%s\" to fault", lhs);
1627*7aec1d6eScindi 	} else {
1628*7aec1d6eScindi 		out(O_ALTFP|O_VERB2, "addpayloadprop: %s=\"%s\"",
1629*7aec1d6eScindi 		    lhs, (char *)rhs->v);
1630*7aec1d6eScindi 
1631*7aec1d6eScindi 		if (nvlist_add_string(fault, lhs, (char *)rhs->v) != 0)
1632*7aec1d6eScindi 			out(O_DIE,
1633*7aec1d6eScindi 			    "cannot add payloadprop \"%s\" to fault", lhs);
1634*7aec1d6eScindi 	}
1635*7aec1d6eScindi }
1636*7aec1d6eScindi 
1637*7aec1d6eScindi static char *Istatbuf;
1638*7aec1d6eScindi static char *Istatbufptr;
1639*7aec1d6eScindi static int Istatsz;
1640*7aec1d6eScindi 
1641*7aec1d6eScindi /*
1642*7aec1d6eScindi  * istataddsize -- calculate size of istat and add it to Istatsz
1643*7aec1d6eScindi  */
1644*7aec1d6eScindi /*ARGSUSED2*/
1645*7aec1d6eScindi static void
1646*7aec1d6eScindi istataddsize(const struct istat_entry *lhs, struct stats *rhs, void *arg)
1647*7aec1d6eScindi {
1648*7aec1d6eScindi 	int val;
1649*7aec1d6eScindi 
1650*7aec1d6eScindi 	ASSERT(lhs != NULL);
1651*7aec1d6eScindi 	ASSERT(rhs != NULL);
1652*7aec1d6eScindi 
1653*7aec1d6eScindi 	if ((val = stats_counter_value(rhs)) == 0)
1654*7aec1d6eScindi 		return;	/* skip zero-valued stats */
1655*7aec1d6eScindi 
1656*7aec1d6eScindi 	/* count up the size of the stat name */
1657*7aec1d6eScindi 	Istatsz += ipath2strlen(lhs->ename, lhs->ipath);
1658*7aec1d6eScindi 	Istatsz++;	/* for the trailing NULL byte */
1659*7aec1d6eScindi 
1660*7aec1d6eScindi 	/* count up the size of the stat value */
1661*7aec1d6eScindi 	Istatsz += snprintf(NULL, 0, "%d", val);
1662*7aec1d6eScindi 	Istatsz++;	/* for the trailing NULL byte */
1663*7aec1d6eScindi }
1664*7aec1d6eScindi 
1665*7aec1d6eScindi /*
1666*7aec1d6eScindi  * istat2str -- serialize an istat, writing result to *Istatbufptr
1667*7aec1d6eScindi  */
1668*7aec1d6eScindi /*ARGSUSED2*/
1669*7aec1d6eScindi static void
1670*7aec1d6eScindi istat2str(const struct istat_entry *lhs, struct stats *rhs, void *arg)
1671*7aec1d6eScindi {
1672*7aec1d6eScindi 	char *str;
1673*7aec1d6eScindi 	int len;
1674*7aec1d6eScindi 	int val;
1675*7aec1d6eScindi 
1676*7aec1d6eScindi 	ASSERT(lhs != NULL);
1677*7aec1d6eScindi 	ASSERT(rhs != NULL);
1678*7aec1d6eScindi 
1679*7aec1d6eScindi 	if ((val = stats_counter_value(rhs)) == 0)
1680*7aec1d6eScindi 		return;	/* skip zero-valued stats */
1681*7aec1d6eScindi 
1682*7aec1d6eScindi 	/* serialize the stat name */
1683*7aec1d6eScindi 	str = ipath2str(lhs->ename, lhs->ipath);
1684*7aec1d6eScindi 	len = strlen(str);
1685*7aec1d6eScindi 
1686*7aec1d6eScindi 	ASSERT(Istatbufptr + len + 1 < &Istatbuf[Istatsz]);
1687*7aec1d6eScindi 	(void) strlcpy(Istatbufptr, str, &Istatbuf[Istatsz] - Istatbufptr);
1688*7aec1d6eScindi 	Istatbufptr += len;
1689*7aec1d6eScindi 	FREE(str);
1690*7aec1d6eScindi 	*Istatbufptr++ = '\0';
1691*7aec1d6eScindi 
1692*7aec1d6eScindi 	/* serialize the stat value */
1693*7aec1d6eScindi 	Istatbufptr += snprintf(Istatbufptr, &Istatbuf[Istatsz] - Istatbufptr,
1694*7aec1d6eScindi 	    "%d", val);
1695*7aec1d6eScindi 	*Istatbufptr++ = '\0';
1696*7aec1d6eScindi 
1697*7aec1d6eScindi 	ASSERT(Istatbufptr <= &Istatbuf[Istatsz]);
1698*7aec1d6eScindi }
1699*7aec1d6eScindi 
1700*7aec1d6eScindi void
1701*7aec1d6eScindi istat_save()
1702*7aec1d6eScindi {
1703*7aec1d6eScindi 	if (Istat_need_save == 0)
1704*7aec1d6eScindi 		return;
1705*7aec1d6eScindi 
1706*7aec1d6eScindi 	/* figure out how big the serialzed info is */
1707*7aec1d6eScindi 	Istatsz = 0;
1708*7aec1d6eScindi 	lut_walk(Istats, (lut_cb)istataddsize, NULL);
1709*7aec1d6eScindi 
1710*7aec1d6eScindi 	if (Istatsz == 0) {
1711*7aec1d6eScindi 		/* no stats to save */
1712*7aec1d6eScindi 		fmd_buf_destroy(Hdl, NULL, WOBUF_ISTATS);
1713*7aec1d6eScindi 		return;
1714*7aec1d6eScindi 	}
1715*7aec1d6eScindi 
1716*7aec1d6eScindi 	/* create the serialized buffer */
1717*7aec1d6eScindi 	Istatbufptr = Istatbuf = MALLOC(Istatsz);
1718*7aec1d6eScindi 	lut_walk(Istats, (lut_cb)istat2str, NULL);
1719*7aec1d6eScindi 
1720*7aec1d6eScindi 	/* clear out current saved stats */
1721*7aec1d6eScindi 	fmd_buf_destroy(Hdl, NULL, WOBUF_ISTATS);
1722*7aec1d6eScindi 
1723*7aec1d6eScindi 	/* write out the new version */
1724*7aec1d6eScindi 	fmd_buf_write(Hdl, NULL, WOBUF_ISTATS, Istatbuf, Istatsz);
1725*7aec1d6eScindi 	FREE(Istatbuf);
1726*7aec1d6eScindi 
1727*7aec1d6eScindi 	Istat_need_save = 0;
1728*7aec1d6eScindi }
1729*7aec1d6eScindi 
1730*7aec1d6eScindi int
1731*7aec1d6eScindi istat_cmp(struct istat_entry *ent1, struct istat_entry *ent2)
1732*7aec1d6eScindi {
1733*7aec1d6eScindi 	if (ent1->ename != ent2->ename)
1734*7aec1d6eScindi 		return (ent2->ename - ent1->ename);
1735*7aec1d6eScindi 	if (ent1->ipath != ent2->ipath)
1736*7aec1d6eScindi 		return ((char *)ent2->ipath - (char *)ent1->ipath);
1737*7aec1d6eScindi 
1738*7aec1d6eScindi 	return (0);
1739*7aec1d6eScindi }
1740*7aec1d6eScindi 
1741*7aec1d6eScindi /*
1742*7aec1d6eScindi  * istat-verify -- verify the component associated with a stat still exists
1743*7aec1d6eScindi  *
1744*7aec1d6eScindi  * if the component no longer exists, this routine resets the stat and
1745*7aec1d6eScindi  * returns 0.  if the component still exists, it returns 1.
1746*7aec1d6eScindi  */
1747*7aec1d6eScindi static int
1748*7aec1d6eScindi istat_verify(struct node *snp, struct istat_entry *entp)
1749*7aec1d6eScindi {
1750*7aec1d6eScindi 	struct stats *statp;
1751*7aec1d6eScindi 	nvlist_t *fmri;
1752*7aec1d6eScindi 
1753*7aec1d6eScindi 	fmri = node2fmri(snp->u.event.epname);
1754*7aec1d6eScindi 	if (platform_path_exists(fmri)) {
1755*7aec1d6eScindi 		nvlist_free(fmri);
1756*7aec1d6eScindi 		return (1);
1757*7aec1d6eScindi 	}
1758*7aec1d6eScindi 	nvlist_free(fmri);
1759*7aec1d6eScindi 
1760*7aec1d6eScindi 	/* component no longer in system.  zero out the associated stats */
1761*7aec1d6eScindi 	if ((statp = (struct stats *)
1762*7aec1d6eScindi 	    lut_lookup(Istats, entp, (lut_cmp)istat_cmp)) == NULL ||
1763*7aec1d6eScindi 	    stats_counter_value(statp) == 0)
1764*7aec1d6eScindi 		return (0);	/* stat is already reset */
1765*7aec1d6eScindi 
1766*7aec1d6eScindi 	Istat_need_save = 1;
1767*7aec1d6eScindi 	stats_counter_reset(statp);
1768*7aec1d6eScindi 	return (0);
1769*7aec1d6eScindi }
1770*7aec1d6eScindi 
1771*7aec1d6eScindi static void
1772*7aec1d6eScindi istat_bump(struct node *snp, int n)
1773*7aec1d6eScindi {
1774*7aec1d6eScindi 	struct stats *statp;
1775*7aec1d6eScindi 	struct istat_entry ent;
1776*7aec1d6eScindi 
1777*7aec1d6eScindi 	ASSERT(snp != NULL);
1778*7aec1d6eScindi 	ASSERTinfo(snp->t == T_EVENT, ptree_nodetype2str(snp->t));
1779*7aec1d6eScindi 	ASSERT(snp->u.event.epname != NULL);
1780*7aec1d6eScindi 
1781*7aec1d6eScindi 	/* class name should be hoisted into a single stable entry */
1782*7aec1d6eScindi 	ASSERT(snp->u.event.ename->u.name.next == NULL);
1783*7aec1d6eScindi 	ent.ename = snp->u.event.ename->u.name.s;
1784*7aec1d6eScindi 	ent.ipath = ipath(snp->u.event.epname);
1785*7aec1d6eScindi 
1786*7aec1d6eScindi 	if (!istat_verify(snp, &ent)) {
1787*7aec1d6eScindi 		/* component no longer exists in system, nothing to do */
1788*7aec1d6eScindi 		return;
1789*7aec1d6eScindi 	}
1790*7aec1d6eScindi 
1791*7aec1d6eScindi 	if ((statp = (struct stats *)
1792*7aec1d6eScindi 	    lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL) {
1793*7aec1d6eScindi 		/* need to create the counter */
1794*7aec1d6eScindi 		int cnt = 0;
1795*7aec1d6eScindi 		struct node *np;
1796*7aec1d6eScindi 		char *sname;
1797*7aec1d6eScindi 		char *snamep;
1798*7aec1d6eScindi 		struct istat_entry *newentp;
1799*7aec1d6eScindi 
1800*7aec1d6eScindi 		/* count up the size of the stat name */
1801*7aec1d6eScindi 		np = snp->u.event.ename;
1802*7aec1d6eScindi 		while (np != NULL) {
1803*7aec1d6eScindi 			cnt += strlen(np->u.name.s);
1804*7aec1d6eScindi 			cnt++;	/* for the '.' or '@' */
1805*7aec1d6eScindi 			np = np->u.name.next;
1806*7aec1d6eScindi 		}
1807*7aec1d6eScindi 		np = snp->u.event.epname;
1808*7aec1d6eScindi 		while (np != NULL) {
1809*7aec1d6eScindi 			cnt += snprintf(NULL, 0, "%s%llu",
1810*7aec1d6eScindi 			    np->u.name.s, np->u.name.child->u.ull);
1811*7aec1d6eScindi 			cnt++;	/* for the '/' or trailing NULL byte */
1812*7aec1d6eScindi 			np = np->u.name.next;
1813*7aec1d6eScindi 		}
1814*7aec1d6eScindi 
1815*7aec1d6eScindi 		/* build the stat name */
1816*7aec1d6eScindi 		snamep = sname = alloca(cnt);
1817*7aec1d6eScindi 		np = snp->u.event.ename;
1818*7aec1d6eScindi 		while (np != NULL) {
1819*7aec1d6eScindi 			snamep += snprintf(snamep, &sname[cnt] - snamep,
1820*7aec1d6eScindi 			    "%s", np->u.name.s);
1821*7aec1d6eScindi 			np = np->u.name.next;
1822*7aec1d6eScindi 			if (np)
1823*7aec1d6eScindi 				*snamep++ = '.';
1824*7aec1d6eScindi 		}
1825*7aec1d6eScindi 		*snamep++ = '@';
1826*7aec1d6eScindi 		np = snp->u.event.epname;
1827*7aec1d6eScindi 		while (np != NULL) {
1828*7aec1d6eScindi 			snamep += snprintf(snamep, &sname[cnt] - snamep,
1829*7aec1d6eScindi 			    "%s%llu", np->u.name.s, np->u.name.child->u.ull);
1830*7aec1d6eScindi 			np = np->u.name.next;
1831*7aec1d6eScindi 			if (np)
1832*7aec1d6eScindi 				*snamep++ = '/';
1833*7aec1d6eScindi 		}
1834*7aec1d6eScindi 		*snamep++ = '\0';
1835*7aec1d6eScindi 
1836*7aec1d6eScindi 		/* create the new stat & add it to our list */
1837*7aec1d6eScindi 		newentp = MALLOC(sizeof (*newentp));
1838*7aec1d6eScindi 		*newentp = ent;
1839*7aec1d6eScindi 		statp = stats_new_counter(NULL, sname, 0);
1840*7aec1d6eScindi 		Istats = lut_add(Istats, (void *)newentp, (void *)statp,
1841*7aec1d6eScindi 		    (lut_cmp)istat_cmp);
1842*7aec1d6eScindi 	}
1843*7aec1d6eScindi 
1844*7aec1d6eScindi 	/* if n is non-zero, set that value instead of bumping */
1845*7aec1d6eScindi 	if (n) {
1846*7aec1d6eScindi 		stats_counter_reset(statp);
1847*7aec1d6eScindi 		stats_counter_add(statp, n);
1848*7aec1d6eScindi 	} else
1849*7aec1d6eScindi 		stats_counter_bump(statp);
1850*7aec1d6eScindi 	Istat_need_save = 1;
1851*7aec1d6eScindi }
1852*7aec1d6eScindi 
1853*7aec1d6eScindi /*ARGSUSED*/
1854*7aec1d6eScindi static void
1855*7aec1d6eScindi istat_destructor(void *left, void *right, void *arg)
1856*7aec1d6eScindi {
1857*7aec1d6eScindi 	struct istat_entry *entp = (struct istat_entry *)left;
1858*7aec1d6eScindi 	struct stats *statp = (struct stats *)right;
1859*7aec1d6eScindi 	FREE(entp);
1860*7aec1d6eScindi 	stats_delete(statp);
1861*7aec1d6eScindi }
1862*7aec1d6eScindi 
1863*7aec1d6eScindi void
1864*7aec1d6eScindi istat_fini(void)
1865*7aec1d6eScindi {
1866*7aec1d6eScindi 	lut_free(Istats, istat_destructor, NULL);
1867*7aec1d6eScindi }
1868*7aec1d6eScindi 
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;
1880*7aec1d6eScindi 	uint_t messval;
1881*7aec1d6eScindi 	struct node *snp;
18827c478bd9Sstevel@tonic-gate 	int frcnt, fridx;
18837c478bd9Sstevel@tonic-gate 	boolean_t no_upsets = B_FALSE;
1884*7aec1d6eScindi 	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;
2001*7aec1d6eScindi 		if (!is_fault(rp->suspect->t))
2002*7aec1d6eScindi 			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");
2013*7aec1d6eScindi 		/* if "message" property exists, add it to the fault */
2014*7aec1d6eScindi 		if (node2uint(eventprop_lookup(rp->suspect, L_message),
2015*7aec1d6eScindi 		    &messval) == 0) {
2016*7aec1d6eScindi 
2017*7aec1d6eScindi 			out(O_ALTFP,
2018*7aec1d6eScindi 			    "[FME%d, %s adds message=%d to suspect list]",
2019*7aec1d6eScindi 			    fmep->id,
2020*7aec1d6eScindi 			    rp->suspect->enode->u.event.ename->u.name.s,
2021*7aec1d6eScindi 			    messval);
2022*7aec1d6eScindi 			if (nvlist_add_boolean_value(fault,
2023*7aec1d6eScindi 			    FM_SUSPECT_MESSAGE,
2024*7aec1d6eScindi 			    (messval) ? B_TRUE : B_FALSE) != 0) {
2025*7aec1d6eScindi 				out(O_DIE, "cannot add no-message to fault");
2026*7aec1d6eScindi 			}
2027*7aec1d6eScindi 		}
2028*7aec1d6eScindi 		/* add any payload properties */
2029*7aec1d6eScindi 		lut_walk(rp->suspect->payloadprops,
2030*7aec1d6eScindi 		    (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*7aec1d6eScindi 		/* if "count" property exists, increment the appropriate stat */
2035*7aec1d6eScindi 		if ((snp = eventprop_lookup(rp->suspect, L_count)) != NULL) {
2036*7aec1d6eScindi 			out(O_ALTFP|O_NONL,
2037*7aec1d6eScindi 			    "[FME%d, %s count ", fmep->id,
2038*7aec1d6eScindi 			    rp->suspect->enode->u.event.ename->u.name.s);
2039*7aec1d6eScindi 			ptree_name_iter(O_ALTFP|O_NONL, snp);
2040*7aec1d6eScindi 			out(O_ALTFP, "]");
2041*7aec1d6eScindi 			istat_bump(snp, 0);
2042*7aec1d6eScindi 		}
2043*7aec1d6eScindi 		/* if "action" property exists, evaluate it */
2044*7aec1d6eScindi 		if ((snp = eventprop_lookup(rp->suspect, L_action)) != NULL) {
2045*7aec1d6eScindi 			struct evalue evalue;
2046*7aec1d6eScindi 
2047*7aec1d6eScindi 			out(O_ALTFP|O_NONL,
2048*7aec1d6eScindi 			    "[FME%d, %s action ", fmep->id,
2049*7aec1d6eScindi 			    rp->suspect->enode->u.event.ename->u.name.s);
2050*7aec1d6eScindi 			ptree_name_iter(O_ALTFP|O_NONL, snp);
2051*7aec1d6eScindi 			out(O_ALTFP, "]");
2052*7aec1d6eScindi 			Action_nvl = fault;
2053*7aec1d6eScindi 			(void) eval_expr(snp, NULL, NULL, NULL, NULL,
2054*7aec1d6eScindi 			    NULL, 0, &evalue);
2055*7aec1d6eScindi 		}
2056*7aec1d6eScindi 		/*
2057*7aec1d6eScindi 		 * if "dupclose" tunable is set, check if the asru is
2058*7aec1d6eScindi 		 * already marked as "faulty".
2059*7aec1d6eScindi 		 */
2060*7aec1d6eScindi 		if (Dupclose && allfaulty) {
2061*7aec1d6eScindi 			nvlist_t *asru;
2062*7aec1d6eScindi 
2063*7aec1d6eScindi 			out(O_ALTFP|O_VERB, "FMD%d dupclose check ", fmep->id);
2064*7aec1d6eScindi 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, rp->suspect);
2065*7aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, " ");
2066*7aec1d6eScindi 			if (nvlist_lookup_nvlist(fault,
2067*7aec1d6eScindi 			    FM_FAULT_ASRU, &asru) != 0) {
2068*7aec1d6eScindi 				out(O_ALTFP|O_VERB, "NULL asru");
2069*7aec1d6eScindi 				allfaulty = B_FALSE;
2070*7aec1d6eScindi 			} else if (fmd_nvl_fmri_faulty(fmep->hdl, asru)) {
2071*7aec1d6eScindi 				out(O_ALTFP|O_VERB, "faulty");
2072*7aec1d6eScindi 			} else {
2073*7aec1d6eScindi 				out(O_ALTFP|O_VERB, "not faulty");
2074*7aec1d6eScindi 				allfaulty = B_FALSE;
2075*7aec1d6eScindi 			}
2076*7aec1d6eScindi 		}
2077*7aec1d6eScindi 
2078*7aec1d6eScindi 	}
2079*7aec1d6eScindi 	if (Dupclose && allfaulty) {
2080*7aec1d6eScindi 		out(O_ALTFP, "[dupclose FME%d, case %s]", fmep->id,
2081*7aec1d6eScindi 		    fmd_case_uuid(fmep->hdl, fmep->fmcase));
2082*7aec1d6eScindi 		fmd_case_close(fmep->hdl, fmep->fmcase);
2083*7aec1d6eScindi 	} else {
2084*7aec1d6eScindi 		out(O_ALTFP, "[solving FME%d, case %s]", fmep->id,
2085*7aec1d6eScindi 		    fmd_case_uuid(fmep->hdl, fmep->fmcase));
2086*7aec1d6eScindi 		fmd_case_solve(fmep->hdl, fmep->fmcase);
20877c478bd9Sstevel@tonic-gate 	}
2088*7aec1d6eScindi 
2089*7aec1d6eScindi 	istat_save();	/* write out any istat changes */
20907c478bd9Sstevel@tonic-gate 
20917c478bd9Sstevel@tonic-gate 	/*
20927c478bd9Sstevel@tonic-gate 	 * revert to the original suspect list
20937c478bd9Sstevel@tonic-gate 	 */
20947c478bd9Sstevel@tonic-gate 	FREE(srl);
20957c478bd9Sstevel@tonic-gate 	restore_suspects(fmep);
20967c478bd9Sstevel@tonic-gate }
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate static void
20997c478bd9Sstevel@tonic-gate publish_undiagnosable(fmd_hdl_t *hdl, fmd_event_t *ffep)
21007c478bd9Sstevel@tonic-gate {
21017c478bd9Sstevel@tonic-gate 	struct case_list *newcase;
21027c478bd9Sstevel@tonic-gate 	nvlist_t *defect;
21037c478bd9Sstevel@tonic-gate 
21047c478bd9Sstevel@tonic-gate 	out(O_ALTFP,
21057c478bd9Sstevel@tonic-gate 	    "[undiagnosable ereport received, "
21067c478bd9Sstevel@tonic-gate 	    "creating and closing a new case (%s)]",
21077c478bd9Sstevel@tonic-gate 	    Undiag_reason ? Undiag_reason : "reason not provided");
21087c478bd9Sstevel@tonic-gate 
21097c478bd9Sstevel@tonic-gate 	newcase = MALLOC(sizeof (struct case_list));
21107c478bd9Sstevel@tonic-gate 	newcase->next = NULL;
21117c478bd9Sstevel@tonic-gate 
21127c478bd9Sstevel@tonic-gate 	newcase->fmcase = fmd_case_open(hdl, NULL);
21137c478bd9Sstevel@tonic-gate 	if (Undiagablecaselist != NULL)
21147c478bd9Sstevel@tonic-gate 		newcase->next = Undiagablecaselist;
21157c478bd9Sstevel@tonic-gate 	Undiagablecaselist = newcase;
21167c478bd9Sstevel@tonic-gate 
21177c478bd9Sstevel@tonic-gate 	if (ffep != NULL)
21187c478bd9Sstevel@tonic-gate 		fmd_case_add_ereport(hdl, newcase->fmcase, ffep);
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 	defect = fmd_nvl_create_fault(hdl, UNDIAGNOSABLE_DEFECT, 100,
21217c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL);
21227c478bd9Sstevel@tonic-gate 	if (Undiag_reason != NULL)
21237c478bd9Sstevel@tonic-gate 		(void) nvlist_add_string(defect, UNDIAG_REASON, Undiag_reason);
21247c478bd9Sstevel@tonic-gate 	fmd_case_add_suspect(hdl, newcase->fmcase, defect);
21257c478bd9Sstevel@tonic-gate 
21267c478bd9Sstevel@tonic-gate 	fmd_case_solve(hdl, newcase->fmcase);
21277c478bd9Sstevel@tonic-gate 	fmd_case_close(hdl, newcase->fmcase);
21287c478bd9Sstevel@tonic-gate }
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate static void
21317c478bd9Sstevel@tonic-gate fme_undiagnosable(struct fme *f)
21327c478bd9Sstevel@tonic-gate {
21337c478bd9Sstevel@tonic-gate 	nvlist_t *defect;
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate 	out(O_ALTFP, "[solving/closing FME%d, case %s (%s)]",
21367c478bd9Sstevel@tonic-gate 	    f->id, fmd_case_uuid(f->hdl, f->fmcase),
21377c478bd9Sstevel@tonic-gate 	    Undiag_reason ? Undiag_reason : "undiagnosable");
21387c478bd9Sstevel@tonic-gate 
21397c478bd9Sstevel@tonic-gate 	defect = fmd_nvl_create_fault(f->hdl, UNDIAGNOSABLE_DEFECT, 100,
21407c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL);
21417c478bd9Sstevel@tonic-gate 	if (Undiag_reason != NULL)
21427c478bd9Sstevel@tonic-gate 		(void) nvlist_add_string(defect, UNDIAG_REASON, Undiag_reason);
21437c478bd9Sstevel@tonic-gate 	fmd_case_add_suspect(f->hdl, f->fmcase, defect);
21447c478bd9Sstevel@tonic-gate 	fmd_case_solve(f->hdl, f->fmcase);
21457c478bd9Sstevel@tonic-gate 	destroy_fme_bufs(f);
21467c478bd9Sstevel@tonic-gate 	fmd_case_close(f->hdl, f->fmcase);
21477c478bd9Sstevel@tonic-gate }
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate /*
21507c478bd9Sstevel@tonic-gate  * fme_close_case
21517c478bd9Sstevel@tonic-gate  *
21527c478bd9Sstevel@tonic-gate  *	Find the requested case amongst our fmes and close it.  Free up
21537c478bd9Sstevel@tonic-gate  *	the related fme.
21547c478bd9Sstevel@tonic-gate  */
21557c478bd9Sstevel@tonic-gate void
21567c478bd9Sstevel@tonic-gate fme_close_case(fmd_hdl_t *hdl, fmd_case_t *fmcase)
21577c478bd9Sstevel@tonic-gate {
21587c478bd9Sstevel@tonic-gate 	struct case_list *ucasep, *prevcasep = NULL;
21597c478bd9Sstevel@tonic-gate 	struct fme *prev = NULL;
21607c478bd9Sstevel@tonic-gate 	struct fme *fmep;
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate 	for (ucasep = Undiagablecaselist; ucasep; ucasep = ucasep->next) {
21637c478bd9Sstevel@tonic-gate 		if (fmcase != ucasep->fmcase) {
21647c478bd9Sstevel@tonic-gate 			prevcasep = ucasep;
21657c478bd9Sstevel@tonic-gate 			continue;
21667c478bd9Sstevel@tonic-gate 		}
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 		if (prevcasep == NULL)
21697c478bd9Sstevel@tonic-gate 			Undiagablecaselist = Undiagablecaselist->next;
21707c478bd9Sstevel@tonic-gate 		else
21717c478bd9Sstevel@tonic-gate 			prevcasep->next = ucasep->next;
21727c478bd9Sstevel@tonic-gate 
21737c478bd9Sstevel@tonic-gate 		FREE(ucasep);
21747c478bd9Sstevel@tonic-gate 		return;
21757c478bd9Sstevel@tonic-gate 	}
21767c478bd9Sstevel@tonic-gate 
21777c478bd9Sstevel@tonic-gate 	for (fmep = FMElist; fmep; fmep = fmep->next) {
21787c478bd9Sstevel@tonic-gate 		if (fmep->hdl == hdl && fmep->fmcase == fmcase)
21797c478bd9Sstevel@tonic-gate 			break;
21807c478bd9Sstevel@tonic-gate 		prev = fmep;
21817c478bd9Sstevel@tonic-gate 	}
21827c478bd9Sstevel@tonic-gate 
21837c478bd9Sstevel@tonic-gate 	if (fmep == NULL) {
21847c478bd9Sstevel@tonic-gate 		out(O_WARN, "Eft asked to close unrecognized case [%s].",
21857c478bd9Sstevel@tonic-gate 		    fmd_case_uuid(hdl, fmcase));
21867c478bd9Sstevel@tonic-gate 		return;
21877c478bd9Sstevel@tonic-gate 	}
21887c478bd9Sstevel@tonic-gate 
21897c478bd9Sstevel@tonic-gate 	if (EFMElist == fmep)
21907c478bd9Sstevel@tonic-gate 		EFMElist = prev;
21917c478bd9Sstevel@tonic-gate 
21927c478bd9Sstevel@tonic-gate 	if (prev == NULL)
21937c478bd9Sstevel@tonic-gate 		FMElist = FMElist->next;
21947c478bd9Sstevel@tonic-gate 	else
21957c478bd9Sstevel@tonic-gate 		prev->next = fmep->next;
21967c478bd9Sstevel@tonic-gate 
21977c478bd9Sstevel@tonic-gate 	fmep->next = NULL;
21987c478bd9Sstevel@tonic-gate 
21997c478bd9Sstevel@tonic-gate 	/* Get rid of any timer this fme has set */
22007c478bd9Sstevel@tonic-gate 	if (fmep->wull != 0)
22017c478bd9Sstevel@tonic-gate 		fmd_timer_remove(fmep->hdl, fmep->timer);
22027c478bd9Sstevel@tonic-gate 
22037c478bd9Sstevel@tonic-gate 	if (ClosedFMEs == NULL) {
22047c478bd9Sstevel@tonic-gate 		ClosedFMEs = fmep;
22057c478bd9Sstevel@tonic-gate 	} else {
22067c478bd9Sstevel@tonic-gate 		fmep->next = ClosedFMEs;
22077c478bd9Sstevel@tonic-gate 		ClosedFMEs = fmep;
22087c478bd9Sstevel@tonic-gate 	}
22090cc1f05eSjrutt 
22100cc1f05eSjrutt 	Open_fme_count--;
22110cc1f05eSjrutt 
22120cc1f05eSjrutt 	/* See if we can close the overflow FME */
22130cc1f05eSjrutt 	if (Open_fme_count <= Max_fme) {
22140cc1f05eSjrutt 		for (fmep = FMElist; fmep; fmep = fmep->next) {
22150cc1f05eSjrutt 			if (fmep->overflow && !(fmd_case_closed(fmep->hdl,
22160cc1f05eSjrutt 			    fmep->fmcase)))
22170cc1f05eSjrutt 				break;
22180cc1f05eSjrutt 		}
22190cc1f05eSjrutt 
22200cc1f05eSjrutt 		if (fmep != NULL)
22210cc1f05eSjrutt 			fmd_case_close(fmep->hdl, fmep->fmcase);
22220cc1f05eSjrutt 	}
22237c478bd9Sstevel@tonic-gate }
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate /*
22267c478bd9Sstevel@tonic-gate  * fme_set_timer()
22277c478bd9Sstevel@tonic-gate  *	If the time we need to wait for the given FME is less than the
22287c478bd9Sstevel@tonic-gate  *	current timer, kick that old timer out and establish a new one.
22297c478bd9Sstevel@tonic-gate  */
2230*7aec1d6eScindi static int
22317c478bd9Sstevel@tonic-gate fme_set_timer(struct fme *fmep, unsigned long long wull)
22327c478bd9Sstevel@tonic-gate {
22337c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, " fme_set_timer: request to wait ");
22347c478bd9Sstevel@tonic-gate 	ptree_timeval(O_ALTFP|O_VERB, &wull);
22357c478bd9Sstevel@tonic-gate 
22367c478bd9Sstevel@tonic-gate 	if (wull <= fmep->pull) {
22377c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "already have waited at least ");
22387c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB, &fmep->pull);
22397c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
22407c478bd9Sstevel@tonic-gate 		/* we've waited at least wull already, don't need timer */
2241*7aec1d6eScindi 		return (0);
22427c478bd9Sstevel@tonic-gate 	}
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, " currently ");
22457c478bd9Sstevel@tonic-gate 	if (fmep->wull != 0) {
22467c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "waiting ");
22477c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB, &fmep->wull);
22487c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
22497c478bd9Sstevel@tonic-gate 	} else {
22507c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "not waiting");
22517c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
22527c478bd9Sstevel@tonic-gate 	}
22537c478bd9Sstevel@tonic-gate 
22547c478bd9Sstevel@tonic-gate 	if (fmep->wull != 0)
22557c478bd9Sstevel@tonic-gate 		if (wull >= fmep->wull)
22567c478bd9Sstevel@tonic-gate 			/* New timer would fire later than established timer */
2257*7aec1d6eScindi 			return (0);
22587c478bd9Sstevel@tonic-gate 
2259*7aec1d6eScindi 	if (fmep->wull != 0) {
22607c478bd9Sstevel@tonic-gate 		fmd_timer_remove(fmep->hdl, fmep->timer);
2261*7aec1d6eScindi 		if (fmep->timer == fmep->htid) {
2262*7aec1d6eScindi 			out(O_ALTFP,
2263*7aec1d6eScindi 			    "[stopped hesitating FME%d, case %s]",
2264*7aec1d6eScindi 			    fmep->id,
2265*7aec1d6eScindi 			    fmd_case_uuid(fmep->hdl,
2266*7aec1d6eScindi 			    fmep->fmcase));
2267*7aec1d6eScindi 			fmep->htid = 0;
2268*7aec1d6eScindi 		}
2269*7aec1d6eScindi 	}
22707c478bd9Sstevel@tonic-gate 
22717c478bd9Sstevel@tonic-gate 	fmep->timer = fmd_timer_install(fmep->hdl, (void *)fmep,
22727c478bd9Sstevel@tonic-gate 	    fmep->e0r, wull);
22737c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, "timer set, id is %ld", fmep->timer);
22747c478bd9Sstevel@tonic-gate 	fmep->wull = wull;
2275*7aec1d6eScindi 	return (1);
22767c478bd9Sstevel@tonic-gate }
22777c478bd9Sstevel@tonic-gate 
22787c478bd9Sstevel@tonic-gate void
22797c478bd9Sstevel@tonic-gate fme_timer_fired(struct fme *fmep, id_t tid)
22807c478bd9Sstevel@tonic-gate {
22817c478bd9Sstevel@tonic-gate 	struct fme *ffmep = NULL;
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate 	for (ffmep = FMElist; ffmep; ffmep = ffmep->next)
22847c478bd9Sstevel@tonic-gate 		if (ffmep == fmep)
22857c478bd9Sstevel@tonic-gate 			break;
22867c478bd9Sstevel@tonic-gate 
22877c478bd9Sstevel@tonic-gate 	if (ffmep == NULL) {
22887c478bd9Sstevel@tonic-gate 		out(O_WARN, "Timer fired for an FME (%p) not in FMEs list.",
22897c478bd9Sstevel@tonic-gate 		    (void *)fmep);
22907c478bd9Sstevel@tonic-gate 		return;
22917c478bd9Sstevel@tonic-gate 	}
22927c478bd9Sstevel@tonic-gate 
2293*7aec1d6eScindi 	out(O_ALTFP, "Timer fired %lx %lx", tid, fmep->htid);
22947c478bd9Sstevel@tonic-gate 	if (tid != fmep->htid) {
22957c478bd9Sstevel@tonic-gate 		/*
2296*7aec1d6eScindi 		 * normal timer (not the hesitation timer)
22977c478bd9Sstevel@tonic-gate 		 */
22987c478bd9Sstevel@tonic-gate 		fmep->pull = fmep->wull;
22997c478bd9Sstevel@tonic-gate 		fmep->wull = 0;
23007c478bd9Sstevel@tonic-gate 		fmd_buf_write(fmep->hdl, fmep->fmcase,
23017c478bd9Sstevel@tonic-gate 		    WOBUF_PULL, (void *)&fmep->pull, sizeof (fmep->pull));
2302*7aec1d6eScindi 		/*
2303*7aec1d6eScindi 		 * no point in heistating if we've already waited.
2304*7aec1d6eScindi 		 */
2305*7aec1d6eScindi 		fmep->hesitated = 1;
23067c478bd9Sstevel@tonic-gate 	} else {
23077c478bd9Sstevel@tonic-gate 		fmep->hesitated = 1;
23087c478bd9Sstevel@tonic-gate 	}
23097c478bd9Sstevel@tonic-gate 	fme_eval(fmep, NULL);
23107c478bd9Sstevel@tonic-gate }
23117c478bd9Sstevel@tonic-gate 
23127c478bd9Sstevel@tonic-gate /*
23137c478bd9Sstevel@tonic-gate  * Preserve the fme's suspect list in its psuspects list, NULLing the
23147c478bd9Sstevel@tonic-gate  * suspects list in the meantime.
23157c478bd9Sstevel@tonic-gate  */
23167c478bd9Sstevel@tonic-gate static void
23177c478bd9Sstevel@tonic-gate save_suspects(struct fme *fmep)
23187c478bd9Sstevel@tonic-gate {
23197c478bd9Sstevel@tonic-gate 	struct event *ep;
23207c478bd9Sstevel@tonic-gate 	struct event *nextep;
23217c478bd9Sstevel@tonic-gate 
23227c478bd9Sstevel@tonic-gate 	/* zero out the previous suspect list */
23237c478bd9Sstevel@tonic-gate 	for (ep = fmep->psuspects; ep; ep = nextep) {
23247c478bd9Sstevel@tonic-gate 		nextep = ep->psuspects;
23257c478bd9Sstevel@tonic-gate 		ep->psuspects = NULL;
23267c478bd9Sstevel@tonic-gate 	}
23277c478bd9Sstevel@tonic-gate 	fmep->psuspects = NULL;
23287c478bd9Sstevel@tonic-gate 
23297c478bd9Sstevel@tonic-gate 	/* zero out the suspect list, copying it to previous suspect list */
23307c478bd9Sstevel@tonic-gate 	fmep->psuspects = fmep->suspects;
23317c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = nextep) {
23327c478bd9Sstevel@tonic-gate 		nextep = ep->suspects;
23337c478bd9Sstevel@tonic-gate 		ep->psuspects = ep->suspects;
23347c478bd9Sstevel@tonic-gate 		ep->suspects = NULL;
23357c478bd9Sstevel@tonic-gate 		ep->is_suspect = 0;
23367c478bd9Sstevel@tonic-gate 	}
23377c478bd9Sstevel@tonic-gate 	fmep->suspects = NULL;
23387c478bd9Sstevel@tonic-gate 	fmep->nsuspects = 0;
23397c478bd9Sstevel@tonic-gate 	fmep->nonfault = 0;
23407c478bd9Sstevel@tonic-gate }
23417c478bd9Sstevel@tonic-gate 
23427c478bd9Sstevel@tonic-gate /*
23437c478bd9Sstevel@tonic-gate  * Retrieve the fme's suspect list from its psuspects list.
23447c478bd9Sstevel@tonic-gate  */
23457c478bd9Sstevel@tonic-gate static void
23467c478bd9Sstevel@tonic-gate restore_suspects(struct fme *fmep)
23477c478bd9Sstevel@tonic-gate {
23487c478bd9Sstevel@tonic-gate 	struct event *ep;
23497c478bd9Sstevel@tonic-gate 	struct event *nextep;
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate 	fmep->nsuspects = fmep->nonfault = 0;
23527c478bd9Sstevel@tonic-gate 	fmep->suspects = fmep->psuspects;
23537c478bd9Sstevel@tonic-gate 	for (ep = fmep->psuspects; ep; ep = nextep) {
23547c478bd9Sstevel@tonic-gate 		fmep->nsuspects++;
23557c478bd9Sstevel@tonic-gate 		if (!is_fault(ep->t))
23567c478bd9Sstevel@tonic-gate 			fmep->nonfault++;
23577c478bd9Sstevel@tonic-gate 		nextep = ep->psuspects;
23587c478bd9Sstevel@tonic-gate 		ep->suspects = ep->psuspects;
23597c478bd9Sstevel@tonic-gate 	}
23607c478bd9Sstevel@tonic-gate }
23617c478bd9Sstevel@tonic-gate 
23627c478bd9Sstevel@tonic-gate /*
23637c478bd9Sstevel@tonic-gate  * this is what we use to call the Emrys prototype code instead of main()
23647c478bd9Sstevel@tonic-gate  */
23657c478bd9Sstevel@tonic-gate static void
23667c478bd9Sstevel@tonic-gate fme_eval(struct fme *fmep, fmd_event_t *ffep)
23677c478bd9Sstevel@tonic-gate {
23687c478bd9Sstevel@tonic-gate 	struct event *ep;
23697c478bd9Sstevel@tonic-gate 	unsigned long long my_delay = TIMEVAL_EVENTUALLY;
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate 	save_suspects(fmep);
23727c478bd9Sstevel@tonic-gate 
23737c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, "Evaluate FME %d", fmep->id);
23747c478bd9Sstevel@tonic-gate 	indent_set("  ");
23757c478bd9Sstevel@tonic-gate 
2376*7aec1d6eScindi 	lut_walk(fmep->eventtree, (lut_cb)clear_arrows, (void *)fmep);
2377*7aec1d6eScindi 	fmep->state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay);
23787c478bd9Sstevel@tonic-gate 
23797c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "FME%d state: %s, suspect list:", fmep->id,
23807c478bd9Sstevel@tonic-gate 	    fme_state2str(fmep->state));
23817c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = ep->suspects) {
23827c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " ");
23837c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
23847c478bd9Sstevel@tonic-gate 	}
23857c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
23867c478bd9Sstevel@tonic-gate 
23877c478bd9Sstevel@tonic-gate 	if (fmep->posted_suspects) {
23887c478bd9Sstevel@tonic-gate 		/*
23897c478bd9Sstevel@tonic-gate 		 * this FME has already posted a diagnosis, so see if
23907c478bd9Sstevel@tonic-gate 		 * the event changed the diagnosis and print a warning
23917c478bd9Sstevel@tonic-gate 		 * if it did.
23927c478bd9Sstevel@tonic-gate 		 *
23937c478bd9Sstevel@tonic-gate 		 */
23947c478bd9Sstevel@tonic-gate 		if (suspects_changed(fmep)) {
23957c478bd9Sstevel@tonic-gate 			print_suspects(SLCHANGED, fmep);
23967c478bd9Sstevel@tonic-gate 			publish_suspects(fmep);
23977c478bd9Sstevel@tonic-gate 		}
23987c478bd9Sstevel@tonic-gate 	} else {
23997c478bd9Sstevel@tonic-gate 		switch (fmep->state) {
24007c478bd9Sstevel@tonic-gate 		case FME_CREDIBLE:
24017c478bd9Sstevel@tonic-gate 			/*
24027c478bd9Sstevel@tonic-gate 			 * if the suspect list contains any upsets, we
24037c478bd9Sstevel@tonic-gate 			 * turn off the hesitation logic (by setting
24047c478bd9Sstevel@tonic-gate 			 * the hesitate flag which normally indicates
24057c478bd9Sstevel@tonic-gate 			 * we've already done the hesitate logic).
24067c478bd9Sstevel@tonic-gate 			 * this is done because hesitating with upsets
24077c478bd9Sstevel@tonic-gate 			 * causes us to explain away additional soft errors
24087c478bd9Sstevel@tonic-gate 			 * while the upset FME stays open.
24097c478bd9Sstevel@tonic-gate 			 */
24107c478bd9Sstevel@tonic-gate 			if (fmep->hesitated == 0) {
24117c478bd9Sstevel@tonic-gate 				struct event *s;
24127c478bd9Sstevel@tonic-gate 
24137c478bd9Sstevel@tonic-gate 				for (s = fmep->suspects; s; s = s->suspects) {
24147c478bd9Sstevel@tonic-gate 					if (s->t == N_UPSET) {
24157c478bd9Sstevel@tonic-gate 						fmep->hesitated = 1;
24167c478bd9Sstevel@tonic-gate 						break;
24177c478bd9Sstevel@tonic-gate 					}
24187c478bd9Sstevel@tonic-gate 				}
24197c478bd9Sstevel@tonic-gate 			}
24207c478bd9Sstevel@tonic-gate 
24217c478bd9Sstevel@tonic-gate 			if (Hesitate &&
24227c478bd9Sstevel@tonic-gate 			    fmep->suspects != NULL &&
24237c478bd9Sstevel@tonic-gate 			    fmep->suspects->suspects != NULL &&
24247c478bd9Sstevel@tonic-gate 			    fmep->hesitated == 0) {
24257c478bd9Sstevel@tonic-gate 				/*
24267c478bd9Sstevel@tonic-gate 				 * about to publish multi-entry suspect list,
24277c478bd9Sstevel@tonic-gate 				 * set the hesitation timer if not already set.
24287c478bd9Sstevel@tonic-gate 				 */
24297c478bd9Sstevel@tonic-gate 				if (fmep->htid == 0) {
24307c478bd9Sstevel@tonic-gate 					out(O_ALTFP|O_NONL,
24317c478bd9Sstevel@tonic-gate 					    "[hesitate FME%d, case %s ",
24327c478bd9Sstevel@tonic-gate 					    fmep->id,
24337c478bd9Sstevel@tonic-gate 					    fmd_case_uuid(fmep->hdl,
24347c478bd9Sstevel@tonic-gate 					    fmep->fmcase));
24357c478bd9Sstevel@tonic-gate 					ptree_timeval(O_ALTFP|O_NONL,
24367c478bd9Sstevel@tonic-gate 					    (unsigned long long *)&Hesitate);
24377c478bd9Sstevel@tonic-gate 					out(O_ALTFP, "]");
2438*7aec1d6eScindi 					if (fme_set_timer(fmep, Hesitate))
2439*7aec1d6eScindi 						fmep->htid = fmep->timer;
24407c478bd9Sstevel@tonic-gate 				} else {
24417c478bd9Sstevel@tonic-gate 					out(O_ALTFP,
24427c478bd9Sstevel@tonic-gate 					    "[still hesitating FME%d, case %s]",
24437c478bd9Sstevel@tonic-gate 					    fmep->id,
24447c478bd9Sstevel@tonic-gate 					    fmd_case_uuid(fmep->hdl,
24457c478bd9Sstevel@tonic-gate 					    fmep->fmcase));
24467c478bd9Sstevel@tonic-gate 				}
24477c478bd9Sstevel@tonic-gate 			} else {
24487c478bd9Sstevel@tonic-gate 				print_suspects(SLNEW, fmep);
24497c478bd9Sstevel@tonic-gate 				(void) upsets_eval(fmep, ffep);
24507c478bd9Sstevel@tonic-gate 				publish_suspects(fmep);
24517c478bd9Sstevel@tonic-gate 				fmep->posted_suspects = 1;
24527c478bd9Sstevel@tonic-gate 				fmd_buf_write(fmep->hdl, fmep->fmcase,
24537c478bd9Sstevel@tonic-gate 				    WOBUF_POSTD,
24547c478bd9Sstevel@tonic-gate 				    (void *)&fmep->posted_suspects,
24557c478bd9Sstevel@tonic-gate 				    sizeof (fmep->posted_suspects));
24567c478bd9Sstevel@tonic-gate 			}
24577c478bd9Sstevel@tonic-gate 			break;
24587c478bd9Sstevel@tonic-gate 
24597c478bd9Sstevel@tonic-gate 		case FME_WAIT:
24607c478bd9Sstevel@tonic-gate 			/*
24617c478bd9Sstevel@tonic-gate 			 * singleton suspect list implies
24627c478bd9Sstevel@tonic-gate 			 * no point in waiting
24637c478bd9Sstevel@tonic-gate 			 */
24647c478bd9Sstevel@tonic-gate 			if (fmep->suspects &&
24657c478bd9Sstevel@tonic-gate 			    fmep->suspects->suspects == NULL) {
24667c478bd9Sstevel@tonic-gate 				print_suspects(SLNEW, fmep);
24677c478bd9Sstevel@tonic-gate 				(void) upsets_eval(fmep, ffep);
24687c478bd9Sstevel@tonic-gate 				publish_suspects(fmep);
24697c478bd9Sstevel@tonic-gate 				fmep->posted_suspects = 1;
24707c478bd9Sstevel@tonic-gate 				fmd_buf_write(fmep->hdl, fmep->fmcase,
24717c478bd9Sstevel@tonic-gate 				    WOBUF_POSTD,
24727c478bd9Sstevel@tonic-gate 				    (void *)&fmep->posted_suspects,
24737c478bd9Sstevel@tonic-gate 				    sizeof (fmep->posted_suspects));
24747c478bd9Sstevel@tonic-gate 				fmep->state = FME_CREDIBLE;
24757c478bd9Sstevel@tonic-gate 			} else {
24767c478bd9Sstevel@tonic-gate 				ASSERT(my_delay > fmep->ull);
2477*7aec1d6eScindi 				(void) fme_set_timer(fmep, my_delay);
24787c478bd9Sstevel@tonic-gate 				print_suspects(SLWAIT, fmep);
24797c478bd9Sstevel@tonic-gate 			}
24807c478bd9Sstevel@tonic-gate 			break;
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate 		case FME_DISPROVED:
24837c478bd9Sstevel@tonic-gate 			print_suspects(SLDISPROVED, fmep);
24847c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_UNSOLVD;
24857c478bd9Sstevel@tonic-gate 			fme_undiagnosable(fmep);
24867c478bd9Sstevel@tonic-gate 			break;
24877c478bd9Sstevel@tonic-gate 		}
24887c478bd9Sstevel@tonic-gate 	}
24897c478bd9Sstevel@tonic-gate 
24907c478bd9Sstevel@tonic-gate 	if (fmep->posted_suspects == 1 && Autoclose != NULL) {
24917c478bd9Sstevel@tonic-gate 		int doclose = 0;
24927c478bd9Sstevel@tonic-gate 
24937c478bd9Sstevel@tonic-gate 		if (strcmp(Autoclose, "true") == 0 ||
24947c478bd9Sstevel@tonic-gate 		    strcmp(Autoclose, "all") == 0)
24957c478bd9Sstevel@tonic-gate 			doclose = 1;
24967c478bd9Sstevel@tonic-gate 
24977c478bd9Sstevel@tonic-gate 		if (strcmp(Autoclose, "upsets") == 0) {
24987c478bd9Sstevel@tonic-gate 			doclose = 1;
24997c478bd9Sstevel@tonic-gate 			for (ep = fmep->suspects; ep; ep = ep->suspects) {
25007c478bd9Sstevel@tonic-gate 				if (ep->t != N_UPSET) {
25017c478bd9Sstevel@tonic-gate 					doclose = 0;
25027c478bd9Sstevel@tonic-gate 					break;
25037c478bd9Sstevel@tonic-gate 				}
25047c478bd9Sstevel@tonic-gate 			}
25057c478bd9Sstevel@tonic-gate 		}
25067c478bd9Sstevel@tonic-gate 
25077c478bd9Sstevel@tonic-gate 		if (doclose) {
25087c478bd9Sstevel@tonic-gate 			out(O_ALTFP, "[closing FME%d, case %s (autoclose)]",
25097c478bd9Sstevel@tonic-gate 			    fmep->id, fmd_case_uuid(fmep->hdl, fmep->fmcase));
25107c478bd9Sstevel@tonic-gate 
25117c478bd9Sstevel@tonic-gate 			destroy_fme_bufs(fmep);
25127c478bd9Sstevel@tonic-gate 			fmd_case_close(fmep->hdl, fmep->fmcase);
25137c478bd9Sstevel@tonic-gate 		}
25147c478bd9Sstevel@tonic-gate 	}
25157c478bd9Sstevel@tonic-gate }
25167c478bd9Sstevel@tonic-gate 
25177c478bd9Sstevel@tonic-gate static void indent(void);
25187c478bd9Sstevel@tonic-gate static int triggered(struct fme *fmep, struct event *ep, int mark);
25197c478bd9Sstevel@tonic-gate static enum fme_state effects_test(struct fme *fmep,
2520*7aec1d6eScindi     struct event *fault_event, unsigned long long at_latest_by,
2521*7aec1d6eScindi     unsigned long long *pdelay);
25227c478bd9Sstevel@tonic-gate static enum fme_state requirements_test(struct fme *fmep, struct event *ep,
2523*7aec1d6eScindi     unsigned long long at_latest_by, unsigned long long *pdelay);
25247c478bd9Sstevel@tonic-gate static enum fme_state causes_test(struct fme *fmep, struct event *ep,
25257c478bd9Sstevel@tonic-gate     unsigned long long at_latest_by, unsigned long long *pdelay);
25267c478bd9Sstevel@tonic-gate 
2527*7aec1d6eScindi static int
2528*7aec1d6eScindi checkconstraints(struct fme *fmep, struct arrow *arrowp)
2529*7aec1d6eScindi {
2530*7aec1d6eScindi 	struct constraintlist *ctp;
2531*7aec1d6eScindi 	struct evalue value;
2532*7aec1d6eScindi 
2533*7aec1d6eScindi 	if (arrowp->forever_false) {
2534*7aec1d6eScindi 		char *sep = "";
2535*7aec1d6eScindi 		indent();
2536*7aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "  Forever false constraint: ");
2537*7aec1d6eScindi 		for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) {
2538*7aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, sep);
2539*7aec1d6eScindi 			ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0);
2540*7aec1d6eScindi 			sep = ", ";
2541*7aec1d6eScindi 		}
2542*7aec1d6eScindi 		out(O_ALTFP|O_VERB, NULL);
2543*7aec1d6eScindi 		return (0);
2544*7aec1d6eScindi 	}
2545*7aec1d6eScindi 
2546*7aec1d6eScindi 	for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) {
2547*7aec1d6eScindi 		if (eval_expr(ctp->cnode, NULL, NULL,
2548*7aec1d6eScindi 		    &fmep->globals, fmep->cfgdata->cooked,
2549*7aec1d6eScindi 		    arrowp, 0, &value)) {
2550*7aec1d6eScindi 			/* evaluation successful */
2551*7aec1d6eScindi 			if (value.t == UNDEFINED || value.v == 0) {
2552*7aec1d6eScindi 				/* known false */
2553*7aec1d6eScindi 				arrowp->forever_false = 1;
2554*7aec1d6eScindi 				indent();
2555*7aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
2556*7aec1d6eScindi 				    "  False constraint: ");
2557*7aec1d6eScindi 				ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0);
2558*7aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
2559*7aec1d6eScindi 				return (0);
2560*7aec1d6eScindi 			}
2561*7aec1d6eScindi 		} else {
2562*7aec1d6eScindi 			/* evaluation unsuccessful -- unknown value */
2563*7aec1d6eScindi 			indent();
2564*7aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL,
2565*7aec1d6eScindi 			    "  Deferred constraint: ");
2566*7aec1d6eScindi 			ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0);
2567*7aec1d6eScindi 			out(O_ALTFP|O_VERB, NULL);
2568*7aec1d6eScindi 			return (2);
2569*7aec1d6eScindi 		}
2570*7aec1d6eScindi 	}
2571*7aec1d6eScindi 	/* known true */
2572*7aec1d6eScindi 	return (1);
2573*7aec1d6eScindi }
2574*7aec1d6eScindi 
25757c478bd9Sstevel@tonic-gate static int
25767c478bd9Sstevel@tonic-gate triggered(struct fme *fmep, struct event *ep, int mark)
25777c478bd9Sstevel@tonic-gate {
25787c478bd9Sstevel@tonic-gate 	struct bubble *bp;
25797c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
25807c478bd9Sstevel@tonic-gate 	int count = 0;
25817c478bd9Sstevel@tonic-gate 
25827c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Tcallcount);
25837c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
25847c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
25857c478bd9Sstevel@tonic-gate 		if (bp->t != B_TO)
25867c478bd9Sstevel@tonic-gate 			continue;
25877c478bd9Sstevel@tonic-gate 		for (ap = itree_next_arrow(bp, NULL); ap;
25887c478bd9Sstevel@tonic-gate 		    ap = itree_next_arrow(bp, ap)) {
25897c478bd9Sstevel@tonic-gate 			/* check count of marks against K in the bubble */
2590*7aec1d6eScindi 			if ((ap->arrowp->mark & mark) &&
25917c478bd9Sstevel@tonic-gate 			    ++count >= bp->nork)
25927c478bd9Sstevel@tonic-gate 				return (1);
25937c478bd9Sstevel@tonic-gate 		}
25947c478bd9Sstevel@tonic-gate 	}
25957c478bd9Sstevel@tonic-gate 	return (0);
25967c478bd9Sstevel@tonic-gate }
25977c478bd9Sstevel@tonic-gate 
2598*7aec1d6eScindi static int
2599*7aec1d6eScindi mark_arrows(struct fme *fmep, struct event *ep, int mark,
2600*7aec1d6eScindi     unsigned long long at_latest_by, unsigned long long *pdelay)
26017c478bd9Sstevel@tonic-gate {
26027c478bd9Sstevel@tonic-gate 	struct bubble *bp;
26037c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
2604*7aec1d6eScindi 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
2605*7aec1d6eScindi 	unsigned long long my_delay;
2606*7aec1d6eScindi 	enum fme_state result;
2607*7aec1d6eScindi 	int retval = 0;
26087c478bd9Sstevel@tonic-gate 
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_FROM)
26127c478bd9Sstevel@tonic-gate 			continue;
2613*7aec1d6eScindi 		stats_counter_bump(fmep->Marrowcount);
2614*7aec1d6eScindi 		for (ap = itree_next_arrow(bp, NULL); ap;
2615*7aec1d6eScindi 		    ap = itree_next_arrow(bp, ap)) {
2616*7aec1d6eScindi 			struct event *ep2 = ap->arrowp->head->myevent;
2617*7aec1d6eScindi 			/*
2618*7aec1d6eScindi 			 * if we're clearing marks, we can avoid doing
2619*7aec1d6eScindi 			 * all that work evaluating constraints.
2620*7aec1d6eScindi 			 */
2621*7aec1d6eScindi 			if (mark == 0) {
2622*7aec1d6eScindi 				ap->arrowp->mark &= ~EFFECTS_COUNTER;
2623*7aec1d6eScindi 				ep2->cached_state &=
2624*7aec1d6eScindi 				    ~(WAIT_EFFECT|CREDIBLE_EFFECT|PARENT_WAIT);
2625*7aec1d6eScindi 				(void) mark_arrows(fmep, ep2, mark, 0, NULL);
2626*7aec1d6eScindi 				continue;
2627*7aec1d6eScindi 			}
2628*7aec1d6eScindi 			if (ep2->cached_state & REQMNTS_DISPROVED) {
2629*7aec1d6eScindi 				indent();
2630*7aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
2631*7aec1d6eScindi 				    "  ALREADY DISPROVED ");
2632*7aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
2633*7aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
2634*7aec1d6eScindi 				continue;
2635*7aec1d6eScindi 			}
2636*7aec1d6eScindi 			if (ep2->cached_state & WAIT_EFFECT) {
2637*7aec1d6eScindi 				indent();
2638*7aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
2639*7aec1d6eScindi 				    "  ALREADY EFFECTS WAIT ");
2640*7aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
2641*7aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
2642*7aec1d6eScindi 				continue;
2643*7aec1d6eScindi 			}
2644*7aec1d6eScindi 			if (ep2->cached_state & CREDIBLE_EFFECT) {
2645*7aec1d6eScindi 				indent();
2646*7aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
2647*7aec1d6eScindi 				    "  ALREADY EFFECTS CREDIBLE ");
2648*7aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
2649*7aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
2650*7aec1d6eScindi 				continue;
2651*7aec1d6eScindi 			}
2652*7aec1d6eScindi 			if ((ep2->cached_state & PARENT_WAIT) &&
2653*7aec1d6eScindi 			    (mark & PARENT_WAIT)) {
2654*7aec1d6eScindi 				indent();
2655*7aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
2656*7aec1d6eScindi 				    "  ALREADY PARENT EFFECTS WAIT ");
2657*7aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
2658*7aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
2659*7aec1d6eScindi 				continue;
2660*7aec1d6eScindi 			}
2661*7aec1d6eScindi 			platform_set_payloadnvp(ep2->nvp);
2662*7aec1d6eScindi 			if (checkconstraints(fmep, ap->arrowp) != 1) {
2663*7aec1d6eScindi 				platform_set_payloadnvp(NULL);
2664*7aec1d6eScindi 				indent();
2665*7aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
2666*7aec1d6eScindi 				    "  CONSTRAINTS FAIL ");
2667*7aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
2668*7aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
2669*7aec1d6eScindi 				continue;
2670*7aec1d6eScindi 			}
2671*7aec1d6eScindi 			platform_set_payloadnvp(NULL);
2672*7aec1d6eScindi 			ap->arrowp->mark |= EFFECTS_COUNTER;
2673*7aec1d6eScindi 			if (!triggered(fmep, ep2, EFFECTS_COUNTER)) {
2674*7aec1d6eScindi 				indent();
2675*7aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
2676*7aec1d6eScindi 				    "  K-COUNT NOT YET MET ");
2677*7aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
2678*7aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
2679*7aec1d6eScindi 				continue;
2680*7aec1d6eScindi 			}
2681*7aec1d6eScindi 			ep2->cached_state &= ~PARENT_WAIT;
2682*7aec1d6eScindi 			result = requirements_test(fmep, ep2, at_latest_by +
2683*7aec1d6eScindi 			    ap->arrowp->maxdelay,
2684*7aec1d6eScindi 			    &my_delay);
2685*7aec1d6eScindi 			if (result == FME_WAIT) {
2686*7aec1d6eScindi 				retval = WAIT_EFFECT;
2687*7aec1d6eScindi 				if (overall_delay > my_delay)
2688*7aec1d6eScindi 					overall_delay = my_delay;
2689*7aec1d6eScindi 				ep2->cached_state |= WAIT_EFFECT;
2690*7aec1d6eScindi 				indent();
2691*7aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL, "  EFFECTS WAIT ");
2692*7aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
2693*7aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
2694*7aec1d6eScindi 				indent_push("  E");
2695*7aec1d6eScindi 				if (mark_arrows(fmep, ep2, PARENT_WAIT,
2696*7aec1d6eScindi 				    at_latest_by, &my_delay) == WAIT_EFFECT) {
2697*7aec1d6eScindi 					retval = WAIT_EFFECT;
2698*7aec1d6eScindi 					if (overall_delay > my_delay)
2699*7aec1d6eScindi 						overall_delay = my_delay;
27007c478bd9Sstevel@tonic-gate 				}
2701*7aec1d6eScindi 				indent_pop();
2702*7aec1d6eScindi 			} else if (result == FME_DISPROVED) {
2703*7aec1d6eScindi 				indent();
2704*7aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
2705*7aec1d6eScindi 				    "  EFFECTS DISPROVED ");
2706*7aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
2707*7aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
2708*7aec1d6eScindi 			} else {
2709*7aec1d6eScindi 				ep2->cached_state |= mark;
2710*7aec1d6eScindi 				indent();
2711*7aec1d6eScindi 				if (mark == CREDIBLE_EFFECT)
27127c478bd9Sstevel@tonic-gate 					out(O_ALTFP|O_VERB|O_NONL,
2713*7aec1d6eScindi 					    "  EFFECTS CREDIBLE ");
2714*7aec1d6eScindi 				else
2715*7aec1d6eScindi 					out(O_ALTFP|O_VERB|O_NONL,
2716*7aec1d6eScindi 					    "  PARENT EFFECTS WAIT ");
2717*7aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
2718*7aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
2719*7aec1d6eScindi 				indent_push("  E");
2720*7aec1d6eScindi 				if (mark_arrows(fmep, ep2, mark, at_latest_by,
2721*7aec1d6eScindi 				    &my_delay) == WAIT_EFFECT) {
2722*7aec1d6eScindi 					retval = WAIT_EFFECT;
2723*7aec1d6eScindi 					if (overall_delay > my_delay)
2724*7aec1d6eScindi 						overall_delay = my_delay;
27257c478bd9Sstevel@tonic-gate 				}
2726*7aec1d6eScindi 				indent_pop();
27277c478bd9Sstevel@tonic-gate 			}
27287c478bd9Sstevel@tonic-gate 		}
27297c478bd9Sstevel@tonic-gate 	}
2730*7aec1d6eScindi 	if (retval == WAIT_EFFECT)
2731*7aec1d6eScindi 		*pdelay = overall_delay;
2732*7aec1d6eScindi 	return (retval);
27337c478bd9Sstevel@tonic-gate }
27347c478bd9Sstevel@tonic-gate 
27357c478bd9Sstevel@tonic-gate static enum fme_state
2736*7aec1d6eScindi effects_test(struct fme *fmep, struct event *fault_event,
2737*7aec1d6eScindi     unsigned long long at_latest_by, unsigned long long *pdelay)
27387c478bd9Sstevel@tonic-gate {
27397c478bd9Sstevel@tonic-gate 	struct event *error_event;
27407c478bd9Sstevel@tonic-gate 	enum fme_state return_value = FME_CREDIBLE;
2741*7aec1d6eScindi 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
2742*7aec1d6eScindi 	unsigned long long my_delay;
27437c478bd9Sstevel@tonic-gate 
27447c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Ecallcount);
27457c478bd9Sstevel@tonic-gate 	indent_push("  E");
27467c478bd9Sstevel@tonic-gate 	indent();
27477c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
27487c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, fault_event);
27497c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
27507c478bd9Sstevel@tonic-gate 
2751*7aec1d6eScindi 	(void) mark_arrows(fmep, fault_event, CREDIBLE_EFFECT, at_latest_by,
2752*7aec1d6eScindi 	    &my_delay);
27537c478bd9Sstevel@tonic-gate 	for (error_event = fmep->observations;
27547c478bd9Sstevel@tonic-gate 	    error_event; error_event = error_event->observations) {
27557c478bd9Sstevel@tonic-gate 		indent();
27567c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " ");
27577c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, error_event);
2758*7aec1d6eScindi 		if (!(error_event->cached_state & CREDIBLE_EFFECT)) {
2759*7aec1d6eScindi 			if (error_event->cached_state &
2760*7aec1d6eScindi 			    (PARENT_WAIT|WAIT_EFFECT)) {
2761*7aec1d6eScindi 				return_value = FME_WAIT;
2762*7aec1d6eScindi 				if (overall_delay > my_delay)
2763*7aec1d6eScindi 					overall_delay = my_delay;
2764*7aec1d6eScindi 				out(O_ALTFP|O_VERB, " NOT YET triggered");
2765*7aec1d6eScindi 				continue;
2766*7aec1d6eScindi 			}
27677c478bd9Sstevel@tonic-gate 			return_value = FME_DISPROVED;
27687c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, " NOT triggered");
27697c478bd9Sstevel@tonic-gate 			break;
27707c478bd9Sstevel@tonic-gate 		} else {
27717c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, " triggered");
27727c478bd9Sstevel@tonic-gate 		}
27737c478bd9Sstevel@tonic-gate 	}
2774*7aec1d6eScindi 	(void) mark_arrows(fmep, fault_event, 0, 0, NULL);
27757c478bd9Sstevel@tonic-gate 
27767c478bd9Sstevel@tonic-gate 	indent();
2777*7aec1d6eScindi 	out(O_ALTFP|O_VERB|O_NONL, "<-EFFECTS %s ",
2778*7aec1d6eScindi 	    fme_state2str(return_value));
27797c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, fault_event);
27807c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
27817c478bd9Sstevel@tonic-gate 	indent_pop();
2782*7aec1d6eScindi 	if (return_value == FME_WAIT)
2783*7aec1d6eScindi 		*pdelay = overall_delay;
27847c478bd9Sstevel@tonic-gate 	return (return_value);
27857c478bd9Sstevel@tonic-gate }
27867c478bd9Sstevel@tonic-gate 
27877c478bd9Sstevel@tonic-gate static enum fme_state
27887c478bd9Sstevel@tonic-gate requirements_test(struct fme *fmep, struct event *ep,
2789*7aec1d6eScindi     unsigned long long at_latest_by, unsigned long long *pdelay)
27907c478bd9Sstevel@tonic-gate {
27917c478bd9Sstevel@tonic-gate 	int waiting_events;
27927c478bd9Sstevel@tonic-gate 	int credible_events;
2793*7aec1d6eScindi 	int deferred_events;
27947c478bd9Sstevel@tonic-gate 	enum fme_state return_value = FME_CREDIBLE;
27957c478bd9Sstevel@tonic-gate 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
27967c478bd9Sstevel@tonic-gate 	unsigned long long arrow_delay;
27977c478bd9Sstevel@tonic-gate 	unsigned long long my_delay;
27987c478bd9Sstevel@tonic-gate 	struct event *ep2;
27997c478bd9Sstevel@tonic-gate 	struct bubble *bp;
28007c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
28017c478bd9Sstevel@tonic-gate 
2802*7aec1d6eScindi 	if (ep->cached_state & REQMNTS_CREDIBLE) {
2803*7aec1d6eScindi 		indent();
2804*7aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "  REQMNTS ALREADY CREDIBLE ");
2805*7aec1d6eScindi 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
2806*7aec1d6eScindi 		out(O_ALTFP|O_VERB, NULL);
2807*7aec1d6eScindi 		return (FME_CREDIBLE);
2808*7aec1d6eScindi 	}
2809*7aec1d6eScindi 	if (ep->cached_state & REQMNTS_DISPROVED) {
2810*7aec1d6eScindi 		indent();
2811*7aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "  REQMNTS ALREADY DISPROVED ");
2812*7aec1d6eScindi 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
2813*7aec1d6eScindi 		out(O_ALTFP|O_VERB, NULL);
2814*7aec1d6eScindi 		return (FME_DISPROVED);
2815*7aec1d6eScindi 	}
2816*7aec1d6eScindi 	if (ep->cached_state & REQMNTS_WAIT) {
2817*7aec1d6eScindi 		indent();
2818*7aec1d6eScindi 		*pdelay = ep->cached_delay;
2819*7aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "  REQMNTS ALREADY WAIT ");
2820*7aec1d6eScindi 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
2821*7aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, ", wait for: ");
2822*7aec1d6eScindi 		ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
2823*7aec1d6eScindi 		out(O_ALTFP|O_VERB, NULL);
2824*7aec1d6eScindi 		return (FME_WAIT);
2825*7aec1d6eScindi 	}
28267c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Rcallcount);
28277c478bd9Sstevel@tonic-gate 	indent_push("  R");
28287c478bd9Sstevel@tonic-gate 	indent();
28297c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
28307c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
28317c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, ", at latest by: ");
28327c478bd9Sstevel@tonic-gate 	ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
28337c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
28347c478bd9Sstevel@tonic-gate 
28357c478bd9Sstevel@tonic-gate 	if (ep->t == N_EREPORT) {
28367c478bd9Sstevel@tonic-gate 		if (ep->count == 0) {
28377c478bd9Sstevel@tonic-gate 			if (fmep->pull >= at_latest_by) {
28387c478bd9Sstevel@tonic-gate 				return_value = FME_DISPROVED;
28397c478bd9Sstevel@tonic-gate 			} else {
2840*7aec1d6eScindi 				ep->cached_delay = *pdelay = at_latest_by;
28417c478bd9Sstevel@tonic-gate 				return_value = FME_WAIT;
28427c478bd9Sstevel@tonic-gate 			}
28437c478bd9Sstevel@tonic-gate 		}
28447c478bd9Sstevel@tonic-gate 
28457c478bd9Sstevel@tonic-gate 		indent();
28467c478bd9Sstevel@tonic-gate 		switch (return_value) {
28477c478bd9Sstevel@tonic-gate 		case FME_CREDIBLE:
2848*7aec1d6eScindi 			ep->cached_state |= REQMNTS_CREDIBLE;
2849*7aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS CREDIBLE ");
28507c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
28517c478bd9Sstevel@tonic-gate 			break;
28527c478bd9Sstevel@tonic-gate 		case FME_DISPROVED:
2853*7aec1d6eScindi 			ep->cached_state |= REQMNTS_DISPROVED;
2854*7aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS DISPROVED ");
28557c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
28567c478bd9Sstevel@tonic-gate 			break;
28577c478bd9Sstevel@tonic-gate 		case FME_WAIT:
2858*7aec1d6eScindi 			ep->cached_state |= REQMNTS_WAIT;
2859*7aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS WAIT ");
28607c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
28617c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB|O_NONL, " to ");
28627c478bd9Sstevel@tonic-gate 			ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
28637c478bd9Sstevel@tonic-gate 			break;
28647c478bd9Sstevel@tonic-gate 		default:
28657c478bd9Sstevel@tonic-gate 			out(O_DIE, "requirements_test: unexpected fme_state");
28667c478bd9Sstevel@tonic-gate 			break;
28677c478bd9Sstevel@tonic-gate 		}
28687c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
28697c478bd9Sstevel@tonic-gate 		indent_pop();
28707c478bd9Sstevel@tonic-gate 
28717c478bd9Sstevel@tonic-gate 		return (return_value);
28727c478bd9Sstevel@tonic-gate 	}
28737c478bd9Sstevel@tonic-gate 
28747c478bd9Sstevel@tonic-gate 	/* this event is not a report, descend the tree */
28757c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
28767c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
2877*7aec1d6eScindi 		int n;
2878*7aec1d6eScindi 
28797c478bd9Sstevel@tonic-gate 		if (bp->t != B_FROM)
28807c478bd9Sstevel@tonic-gate 			continue;
28817c478bd9Sstevel@tonic-gate 
2882*7aec1d6eScindi 		n = bp->nork;
2883*7aec1d6eScindi 
2884*7aec1d6eScindi 		credible_events = 0;
2885*7aec1d6eScindi 		waiting_events = 0;
2886*7aec1d6eScindi 		deferred_events = 0;
2887*7aec1d6eScindi 		arrow_delay = TIMEVAL_EVENTUALLY;
2888*7aec1d6eScindi 		/*
2889*7aec1d6eScindi 		 * n is -1 for 'A' so adjust it.
2890*7aec1d6eScindi 		 * XXX just count up the arrows for now.
2891*7aec1d6eScindi 		 */
2892*7aec1d6eScindi 		if (n < 0) {
2893*7aec1d6eScindi 			n = 0;
2894*7aec1d6eScindi 			for (ap = itree_next_arrow(bp, NULL); ap;
2895*7aec1d6eScindi 			    ap = itree_next_arrow(bp, ap))
2896*7aec1d6eScindi 				n++;
2897*7aec1d6eScindi 			indent();
2898*7aec1d6eScindi 			out(O_ALTFP|O_VERB, " Bubble Counted N=%d", n);
2899*7aec1d6eScindi 		} else {
2900*7aec1d6eScindi 			indent();
2901*7aec1d6eScindi 			out(O_ALTFP|O_VERB, " Bubble N=%d", n);
2902*7aec1d6eScindi 		}
29037c478bd9Sstevel@tonic-gate 
2904*7aec1d6eScindi 		if (n == 0)
2905*7aec1d6eScindi 			continue;
2906*7aec1d6eScindi 		if (!(bp->mark & (BUBBLE_ELIDED|BUBBLE_OK))) {
29077c478bd9Sstevel@tonic-gate 			for (ap = itree_next_arrow(bp, NULL); ap;
29087c478bd9Sstevel@tonic-gate 			    ap = itree_next_arrow(bp, ap)) {
29097c478bd9Sstevel@tonic-gate 				ep2 = ap->arrowp->head->myevent;
2910*7aec1d6eScindi 				platform_set_payloadnvp(ep2->nvp);
2911*7aec1d6eScindi 				if (checkconstraints(fmep, ap->arrowp) == 0) {
2912*7aec1d6eScindi 					/*
2913*7aec1d6eScindi 					 * if any arrow is invalidated by the
2914*7aec1d6eScindi 					 * constraints, then we should elide the
2915*7aec1d6eScindi 					 * whole bubble to be consistant with
2916*7aec1d6eScindi 					 * the tree creation time behaviour
2917*7aec1d6eScindi 					 */
2918*7aec1d6eScindi 					bp->mark |= BUBBLE_ELIDED;
2919*7aec1d6eScindi 					platform_set_payloadnvp(NULL);
29207c478bd9Sstevel@tonic-gate 					break;
2921*7aec1d6eScindi 				}
2922*7aec1d6eScindi 				platform_set_payloadnvp(NULL);
2923*7aec1d6eScindi 			}
2924*7aec1d6eScindi 		}
2925*7aec1d6eScindi 		if (bp->mark & BUBBLE_ELIDED)
2926*7aec1d6eScindi 			continue;
2927*7aec1d6eScindi 		bp->mark |= BUBBLE_OK;
2928*7aec1d6eScindi 		for (ap = itree_next_arrow(bp, NULL); ap;
2929*7aec1d6eScindi 		    ap = itree_next_arrow(bp, ap)) {
2930*7aec1d6eScindi 			ep2 = ap->arrowp->head->myevent;
2931*7aec1d6eScindi 			if (n <= credible_events)
2932*7aec1d6eScindi 				break;
29337c478bd9Sstevel@tonic-gate 
2934*7aec1d6eScindi 			ap->arrowp->mark |= REQMNTS_COUNTER;
2935*7aec1d6eScindi 			if (triggered(fmep, ep2, REQMNTS_COUNTER))
2936*7aec1d6eScindi 				/* XXX adding max timevals! */
2937*7aec1d6eScindi 				switch (requirements_test(fmep, ep2,
2938*7aec1d6eScindi 				    at_latest_by + ap->arrowp->maxdelay,
2939*7aec1d6eScindi 				    &my_delay)) {
2940*7aec1d6eScindi 				case FME_DEFERRED:
2941*7aec1d6eScindi 					deferred_events++;
2942*7aec1d6eScindi 					break;
2943*7aec1d6eScindi 				case FME_CREDIBLE:
29447c478bd9Sstevel@tonic-gate 					credible_events++;
2945*7aec1d6eScindi 					break;
2946*7aec1d6eScindi 				case FME_DISPROVED:
2947*7aec1d6eScindi 					break;
2948*7aec1d6eScindi 				case FME_WAIT:
2949*7aec1d6eScindi 					if (my_delay < arrow_delay)
2950*7aec1d6eScindi 						arrow_delay = my_delay;
2951*7aec1d6eScindi 					waiting_events++;
2952*7aec1d6eScindi 					break;
2953*7aec1d6eScindi 				default:
2954*7aec1d6eScindi 					out(O_DIE,
2955*7aec1d6eScindi 					"Bug in requirements_test.");
2956*7aec1d6eScindi 				}
2957*7aec1d6eScindi 			else
2958*7aec1d6eScindi 				deferred_events++;
2959*7aec1d6eScindi 		}
2960*7aec1d6eScindi 		indent();
2961*7aec1d6eScindi 		out(O_ALTFP|O_VERB, " Credible: %d Waiting %d",
2962*7aec1d6eScindi 		    credible_events + deferred_events, waiting_events);
2963*7aec1d6eScindi 		if (credible_events + deferred_events + waiting_events < n) {
2964*7aec1d6eScindi 			/* Can never meet requirements */
2965*7aec1d6eScindi 			ep->cached_state |= REQMNTS_DISPROVED;
29667c478bd9Sstevel@tonic-gate 			indent();
2967*7aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS DISPROVED ");
29687c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
29697c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, NULL);
2970*7aec1d6eScindi 			indent_pop();
2971*7aec1d6eScindi 			return (FME_DISPROVED);
2972*7aec1d6eScindi 		}
2973*7aec1d6eScindi 		if (credible_events + deferred_events < n) {
2974*7aec1d6eScindi 			/* will have to wait */
2975*7aec1d6eScindi 			/* wait time is shortest known */
2976*7aec1d6eScindi 			if (arrow_delay < overall_delay)
2977*7aec1d6eScindi 				overall_delay = arrow_delay;
2978*7aec1d6eScindi 			return_value = FME_WAIT;
2979*7aec1d6eScindi 		} else if (credible_events < n) {
2980*7aec1d6eScindi 			if (return_value != FME_WAIT)
2981*7aec1d6eScindi 				return_value = FME_DEFERRED;
29827c478bd9Sstevel@tonic-gate 		}
29837c478bd9Sstevel@tonic-gate 	}
29847c478bd9Sstevel@tonic-gate 
29857c478bd9Sstevel@tonic-gate 	/*
2986*7aec1d6eScindi 	 * don't mark as FME_DEFERRED. If this event isn't reached by another
2987*7aec1d6eScindi 	 * path, then this will be considered FME_CREDIBLE. But if it is
2988*7aec1d6eScindi 	 * reached by a different path so the K-count is met, then might
2989*7aec1d6eScindi 	 * get overridden by FME_WAIT or FME_DISPROVED.
29907c478bd9Sstevel@tonic-gate 	 */
2991*7aec1d6eScindi 	if (return_value == FME_WAIT) {
2992*7aec1d6eScindi 		ep->cached_state |= REQMNTS_WAIT;
2993*7aec1d6eScindi 		ep->cached_delay = *pdelay = overall_delay;
2994*7aec1d6eScindi 	} else if (return_value == FME_CREDIBLE) {
2995*7aec1d6eScindi 		ep->cached_state |= REQMNTS_CREDIBLE;
29967c478bd9Sstevel@tonic-gate 	}
29977c478bd9Sstevel@tonic-gate 	indent();
2998*7aec1d6eScindi 	out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS %s ",
2999*7aec1d6eScindi 	    fme_state2str(return_value));
30007c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
30017c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
30027c478bd9Sstevel@tonic-gate 	indent_pop();
30037c478bd9Sstevel@tonic-gate 	return (return_value);
30047c478bd9Sstevel@tonic-gate }
30057c478bd9Sstevel@tonic-gate 
30067c478bd9Sstevel@tonic-gate static enum fme_state
30077c478bd9Sstevel@tonic-gate causes_test(struct fme *fmep, struct event *ep,
30087c478bd9Sstevel@tonic-gate     unsigned long long at_latest_by, unsigned long long *pdelay)
30097c478bd9Sstevel@tonic-gate {
30107c478bd9Sstevel@tonic-gate 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
30117c478bd9Sstevel@tonic-gate 	unsigned long long my_delay;
30127c478bd9Sstevel@tonic-gate 	int credible_results = 0;
30137c478bd9Sstevel@tonic-gate 	int waiting_results = 0;
30147c478bd9Sstevel@tonic-gate 	enum fme_state fstate;
30157c478bd9Sstevel@tonic-gate 	struct event *tail_event;
30167c478bd9Sstevel@tonic-gate 	struct bubble *bp;
30177c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
30187c478bd9Sstevel@tonic-gate 	int k = 1;
30197c478bd9Sstevel@tonic-gate 
30207c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Ccallcount);
30217c478bd9Sstevel@tonic-gate 	indent_push("  C");
30227c478bd9Sstevel@tonic-gate 	indent();
30237c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
30247c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
30257c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
30267c478bd9Sstevel@tonic-gate 
30277c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
30287c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
30297c478bd9Sstevel@tonic-gate 		if (bp->t != B_TO)
30307c478bd9Sstevel@tonic-gate 			continue;
30317c478bd9Sstevel@tonic-gate 		k = bp->nork;	/* remember the K value */
30327c478bd9Sstevel@tonic-gate 		for (ap = itree_next_arrow(bp, NULL); ap;
30337c478bd9Sstevel@tonic-gate 		    ap = itree_next_arrow(bp, ap)) {
30347c478bd9Sstevel@tonic-gate 			int do_not_follow = 0;
3035*7aec1d6eScindi 
3036*7aec1d6eScindi 			/*
3037*7aec1d6eScindi 			 * if we get to the same event multiple times
3038*7aec1d6eScindi 			 * only worry about the first one.
3039*7aec1d6eScindi 			 */
3040*7aec1d6eScindi 			if (ap->arrowp->tail->myevent->cached_state &
3041*7aec1d6eScindi 			    CAUSES_TESTED) {
3042*7aec1d6eScindi 				indent();
3043*7aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
3044*7aec1d6eScindi 				    "  causes test already run for ");
3045*7aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL,
3046*7aec1d6eScindi 				    ap->arrowp->tail->myevent);
3047*7aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
3048*7aec1d6eScindi 				continue;
3049*7aec1d6eScindi 			}
3050*7aec1d6eScindi 
30517c478bd9Sstevel@tonic-gate 			/*
30527c478bd9Sstevel@tonic-gate 			 * see if false constraint prevents us
30537c478bd9Sstevel@tonic-gate 			 * from traversing this arrow
30547c478bd9Sstevel@tonic-gate 			 */
30557c478bd9Sstevel@tonic-gate 			platform_set_payloadnvp(ep->nvp);
3056*7aec1d6eScindi 			if (checkconstraints(fmep, ap->arrowp) != 1)
3057*7aec1d6eScindi 				do_not_follow = 1;
30587c478bd9Sstevel@tonic-gate 			platform_set_payloadnvp(NULL);
30597c478bd9Sstevel@tonic-gate 			if (do_not_follow) {
30607c478bd9Sstevel@tonic-gate 				indent();
30617c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB|O_NONL,
30627c478bd9Sstevel@tonic-gate 				    "  False arrow from ");
30637c478bd9Sstevel@tonic-gate 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL,
30647c478bd9Sstevel@tonic-gate 				    ap->arrowp->tail->myevent);
30657c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB, NULL);
30667c478bd9Sstevel@tonic-gate 				continue;
30677c478bd9Sstevel@tonic-gate 			}
30687c478bd9Sstevel@tonic-gate 
3069*7aec1d6eScindi 			ap->arrowp->tail->myevent->cached_state |=
3070*7aec1d6eScindi 			    CAUSES_TESTED;
3071*7aec1d6eScindi 			tail_event = ap->arrowp->tail->myevent;
3072*7aec1d6eScindi 			fstate = hypothesise(fmep, tail_event, at_latest_by,
3073*7aec1d6eScindi 			    &my_delay);
30747c478bd9Sstevel@tonic-gate 
30757c478bd9Sstevel@tonic-gate 			switch (fstate) {
30767c478bd9Sstevel@tonic-gate 			case FME_WAIT:
30777c478bd9Sstevel@tonic-gate 				if (my_delay < overall_delay)
30787c478bd9Sstevel@tonic-gate 					overall_delay = my_delay;
30797c478bd9Sstevel@tonic-gate 				waiting_results++;
30807c478bd9Sstevel@tonic-gate 				break;
30817c478bd9Sstevel@tonic-gate 			case FME_CREDIBLE:
30827c478bd9Sstevel@tonic-gate 				credible_results++;
30837c478bd9Sstevel@tonic-gate 				break;
30847c478bd9Sstevel@tonic-gate 			case FME_DISPROVED:
30857c478bd9Sstevel@tonic-gate 				break;
30867c478bd9Sstevel@tonic-gate 			default:
30877c478bd9Sstevel@tonic-gate 				out(O_DIE, "Bug in causes_test");
30887c478bd9Sstevel@tonic-gate 			}
30897c478bd9Sstevel@tonic-gate 		}
30907c478bd9Sstevel@tonic-gate 	}
30917c478bd9Sstevel@tonic-gate 	/* compare against K */
30927c478bd9Sstevel@tonic-gate 	if (credible_results + waiting_results < k) {
30937c478bd9Sstevel@tonic-gate 		indent();
3094*7aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES DISPROVED ");
30957c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
30967c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
30977c478bd9Sstevel@tonic-gate 		indent_pop();
30987c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
30997c478bd9Sstevel@tonic-gate 	}
31007c478bd9Sstevel@tonic-gate 	if (waiting_results != 0) {
31017c478bd9Sstevel@tonic-gate 		*pdelay = overall_delay;
31027c478bd9Sstevel@tonic-gate 		indent();
3103*7aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES WAIT ");
31047c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31057c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " to ");
31067c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
31077c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
31087c478bd9Sstevel@tonic-gate 		indent_pop();
31097c478bd9Sstevel@tonic-gate 		return (FME_WAIT);
31107c478bd9Sstevel@tonic-gate 	}
31117c478bd9Sstevel@tonic-gate 	indent();
3112*7aec1d6eScindi 	out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES CREDIBLE ");
31137c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31147c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
31157c478bd9Sstevel@tonic-gate 	indent_pop();
31167c478bd9Sstevel@tonic-gate 	return (FME_CREDIBLE);
31177c478bd9Sstevel@tonic-gate }
31187c478bd9Sstevel@tonic-gate 
31197c478bd9Sstevel@tonic-gate static enum fme_state
31207c478bd9Sstevel@tonic-gate hypothesise(struct fme *fmep, struct event *ep,
3121*7aec1d6eScindi 	unsigned long long at_latest_by, unsigned long long *pdelay)
31227c478bd9Sstevel@tonic-gate {
31237c478bd9Sstevel@tonic-gate 	enum fme_state rtr, otr;
31247c478bd9Sstevel@tonic-gate 	unsigned long long my_delay;
31257c478bd9Sstevel@tonic-gate 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
31267c478bd9Sstevel@tonic-gate 
31277c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Hcallcount);
31287c478bd9Sstevel@tonic-gate 	indent_push("  H");
31297c478bd9Sstevel@tonic-gate 	indent();
31307c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
31317c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31327c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, ", at latest by: ");
31337c478bd9Sstevel@tonic-gate 	ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
31347c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
31357c478bd9Sstevel@tonic-gate 
3136*7aec1d6eScindi 	rtr = requirements_test(fmep, ep, at_latest_by, &my_delay);
31377c478bd9Sstevel@tonic-gate 	if ((rtr == FME_WAIT) && (my_delay < overall_delay))
31387c478bd9Sstevel@tonic-gate 		overall_delay = my_delay;
31397c478bd9Sstevel@tonic-gate 	if (rtr != FME_DISPROVED) {
31407c478bd9Sstevel@tonic-gate 		if (is_problem(ep->t)) {
3141*7aec1d6eScindi 			otr = effects_test(fmep, ep, at_latest_by, &my_delay);
31427c478bd9Sstevel@tonic-gate 			if (otr != FME_DISPROVED) {
31437c478bd9Sstevel@tonic-gate 				if (fmep->peek == 0 && ep->is_suspect++ == 0) {
31447c478bd9Sstevel@tonic-gate 					ep->suspects = fmep->suspects;
31457c478bd9Sstevel@tonic-gate 					fmep->suspects = ep;
31467c478bd9Sstevel@tonic-gate 					fmep->nsuspects++;
31477c478bd9Sstevel@tonic-gate 					if (!is_fault(ep->t))
31487c478bd9Sstevel@tonic-gate 						fmep->nonfault++;
31497c478bd9Sstevel@tonic-gate 				}
31507c478bd9Sstevel@tonic-gate 			}
31517c478bd9Sstevel@tonic-gate 		} else
31527c478bd9Sstevel@tonic-gate 			otr = causes_test(fmep, ep, at_latest_by, &my_delay);
31537c478bd9Sstevel@tonic-gate 		if ((otr == FME_WAIT) && (my_delay < overall_delay))
31547c478bd9Sstevel@tonic-gate 			overall_delay = my_delay;
31557c478bd9Sstevel@tonic-gate 		if ((otr != FME_DISPROVED) &&
31567c478bd9Sstevel@tonic-gate 		    ((rtr == FME_WAIT) || (otr == FME_WAIT)))
31577c478bd9Sstevel@tonic-gate 			*pdelay = overall_delay;
31587c478bd9Sstevel@tonic-gate 	}
31597c478bd9Sstevel@tonic-gate 	if (rtr == FME_DISPROVED) {
31607c478bd9Sstevel@tonic-gate 		indent();
31617c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
31627c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31637c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, " (doesn't meet requirements)");
31647c478bd9Sstevel@tonic-gate 		indent_pop();
31657c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
31667c478bd9Sstevel@tonic-gate 	}
31677c478bd9Sstevel@tonic-gate 	if ((otr == FME_DISPROVED) && is_problem(ep->t)) {
31687c478bd9Sstevel@tonic-gate 		indent();
31697c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
31707c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31717c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, " (doesn't explain all reports)");
31727c478bd9Sstevel@tonic-gate 		indent_pop();
31737c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
31747c478bd9Sstevel@tonic-gate 	}
31757c478bd9Sstevel@tonic-gate 	if (otr == FME_DISPROVED) {
31767c478bd9Sstevel@tonic-gate 		indent();
31777c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
31787c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31797c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, " (causes are not credible)");
31807c478bd9Sstevel@tonic-gate 		indent_pop();
31817c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
31827c478bd9Sstevel@tonic-gate 	}
31837c478bd9Sstevel@tonic-gate 	if ((rtr == FME_WAIT) || (otr == FME_WAIT)) {
31847c478bd9Sstevel@tonic-gate 		indent();
31857c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-WAIT ");
31867c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31877c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " to ");
31887c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB|O_NONL, &overall_delay);
31897c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
31907c478bd9Sstevel@tonic-gate 		indent_pop();
31917c478bd9Sstevel@tonic-gate 		return (FME_WAIT);
31927c478bd9Sstevel@tonic-gate 	}
31937c478bd9Sstevel@tonic-gate 	indent();
31947c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "<-CREDIBLE ");
31957c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
31967c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
31977c478bd9Sstevel@tonic-gate 	indent_pop();
31987c478bd9Sstevel@tonic-gate 	return (FME_CREDIBLE);
31997c478bd9Sstevel@tonic-gate }
3200*7aec1d6eScindi 
3201*7aec1d6eScindi /*
3202*7aec1d6eScindi  * fme_istat_load -- reconstitute any persistent istats
3203*7aec1d6eScindi  */
3204*7aec1d6eScindi void
3205*7aec1d6eScindi fme_istat_load(fmd_hdl_t *hdl)
3206*7aec1d6eScindi {
3207*7aec1d6eScindi 	int sz;
3208*7aec1d6eScindi 	char *sbuf;
3209*7aec1d6eScindi 	char *ptr;
3210*7aec1d6eScindi 
3211*7aec1d6eScindi 	if ((sz = fmd_buf_size(hdl, NULL, WOBUF_ISTATS)) == 0) {
3212*7aec1d6eScindi 		out(O_ALTFP, "fme_istat_load: No stats");
3213*7aec1d6eScindi 		return;
3214*7aec1d6eScindi 	}
3215*7aec1d6eScindi 
3216*7aec1d6eScindi 	sbuf = alloca(sz);
3217*7aec1d6eScindi 
3218*7aec1d6eScindi 	fmd_buf_read(hdl, NULL, WOBUF_ISTATS, sbuf, sz);
3219*7aec1d6eScindi 
3220*7aec1d6eScindi 	/*
3221*7aec1d6eScindi 	 * pick apart the serialized stats
3222*7aec1d6eScindi 	 *
3223*7aec1d6eScindi 	 * format is:
3224*7aec1d6eScindi 	 *	<class-name>, '@', <path>, '\0', <value>, '\0'
3225*7aec1d6eScindi 	 * for example:
3226*7aec1d6eScindi 	 *	"stat.first@stat0/path0\02\0stat.second@stat0/path1\023\0"
3227*7aec1d6eScindi 	 *
3228*7aec1d6eScindi 	 * since this is parsing our own serialized data, any parsing issues
3229*7aec1d6eScindi 	 * are fatal, so we check for them all with ASSERT() below.
3230*7aec1d6eScindi 	 */
3231*7aec1d6eScindi 	ptr = sbuf;
3232*7aec1d6eScindi 	while (ptr < &sbuf[sz]) {
3233*7aec1d6eScindi 		char *sepptr;
3234*7aec1d6eScindi 		struct node *np;
3235*7aec1d6eScindi 		int val;
3236*7aec1d6eScindi 
3237*7aec1d6eScindi 		sepptr = strchr(ptr, '@');
3238*7aec1d6eScindi 		ASSERT(sepptr != NULL);
3239*7aec1d6eScindi 		*sepptr = '\0';
3240*7aec1d6eScindi 
3241*7aec1d6eScindi 		/* construct the event */
3242*7aec1d6eScindi 		np = newnode(T_EVENT, NULL, 0);
3243*7aec1d6eScindi 		np->u.event.ename = newnode(T_NAME, NULL, 0);
3244*7aec1d6eScindi 		np->u.event.ename->u.name.t = N_STAT;
3245*7aec1d6eScindi 		np->u.event.ename->u.name.s = stable(ptr);
3246*7aec1d6eScindi 		np->u.event.ename->u.name.it = IT_ENAME;
3247*7aec1d6eScindi 		np->u.event.ename->u.name.last = np->u.event.ename;
3248*7aec1d6eScindi 
3249*7aec1d6eScindi 		ptr = sepptr + 1;
3250*7aec1d6eScindi 		ASSERT(ptr < &sbuf[sz]);
3251*7aec1d6eScindi 		ptr += strlen(ptr);
3252*7aec1d6eScindi 		ptr++;	/* move past the '\0' separating path from value */
3253*7aec1d6eScindi 		ASSERT(ptr < &sbuf[sz]);
3254*7aec1d6eScindi 		ASSERT(isdigit(*ptr));
3255*7aec1d6eScindi 		val = atoi(ptr);
3256*7aec1d6eScindi 		ASSERT(val > 0);
3257*7aec1d6eScindi 		ptr += strlen(ptr);
3258*7aec1d6eScindi 		ptr++;	/* move past the final '\0' for this entry */
3259*7aec1d6eScindi 
3260*7aec1d6eScindi 		np->u.event.epname = pathstring2epnamenp(sepptr + 1);
3261*7aec1d6eScindi 		ASSERT(np->u.event.epname != NULL);
3262*7aec1d6eScindi 
3263*7aec1d6eScindi 		istat_bump(np, val);
3264*7aec1d6eScindi 		tree_free(np);
3265*7aec1d6eScindi 	}
3266*7aec1d6eScindi 
3267*7aec1d6eScindi 	istat_save();
3268*7aec1d6eScindi }
3269