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
55f25dc2aSgavinm  * Common Development and Distribution License (the "License").
65f25dc2aSgavinm  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
215f25dc2aSgavinm 
227c478bd9Sstevel@tonic-gate /*
23*b5016cbbSstephh  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  *
267c478bd9Sstevel@tonic-gate  * fme.c -- fault management exercise module
277c478bd9Sstevel@tonic-gate  *
287c478bd9Sstevel@tonic-gate  * this module provides the simulated fault management exercise.
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
327c478bd9Sstevel@tonic-gate 
337c478bd9Sstevel@tonic-gate #include <stdio.h>
347c478bd9Sstevel@tonic-gate #include <stdlib.h>
357c478bd9Sstevel@tonic-gate #include <string.h>
367c478bd9Sstevel@tonic-gate #include <strings.h>
377c478bd9Sstevel@tonic-gate #include <ctype.h>
387c478bd9Sstevel@tonic-gate #include <alloca.h>
397c478bd9Sstevel@tonic-gate #include <libnvpair.h>
407c478bd9Sstevel@tonic-gate #include <sys/fm/protocol.h>
417c478bd9Sstevel@tonic-gate #include <fm/fmd_api.h>
427c478bd9Sstevel@tonic-gate #include "alloc.h"
437c478bd9Sstevel@tonic-gate #include "out.h"
447c478bd9Sstevel@tonic-gate #include "stats.h"
457c478bd9Sstevel@tonic-gate #include "stable.h"
467c478bd9Sstevel@tonic-gate #include "literals.h"
477c478bd9Sstevel@tonic-gate #include "lut.h"
487c478bd9Sstevel@tonic-gate #include "tree.h"
497c478bd9Sstevel@tonic-gate #include "ptree.h"
507c478bd9Sstevel@tonic-gate #include "itree.h"
517c478bd9Sstevel@tonic-gate #include "ipath.h"
527c478bd9Sstevel@tonic-gate #include "fme.h"
537c478bd9Sstevel@tonic-gate #include "evnv.h"
547c478bd9Sstevel@tonic-gate #include "eval.h"
557c478bd9Sstevel@tonic-gate #include "config.h"
567c478bd9Sstevel@tonic-gate #include "platform.h"
577c478bd9Sstevel@tonic-gate 
587c478bd9Sstevel@tonic-gate /* imported from eft.c... */
597c478bd9Sstevel@tonic-gate extern char *Autoclose;
607aec1d6eScindi extern int Dupclose;
617c478bd9Sstevel@tonic-gate extern hrtime_t Hesitate;
627c478bd9Sstevel@tonic-gate extern nv_alloc_t Eft_nv_hdl;
630cc1f05eSjrutt extern int Max_fme;
647aec1d6eScindi extern fmd_hdl_t *Hdl;
657aec1d6eScindi 
667aec1d6eScindi static int Istat_need_save;
67*b5016cbbSstephh static int Serd_need_save;
6808f6c065Sgavinm void istat_save(void);
69*b5016cbbSstephh void serd_save(void);
707c478bd9Sstevel@tonic-gate 
717c478bd9Sstevel@tonic-gate /* fme under construction is global so we can free it on module abort */
727c478bd9Sstevel@tonic-gate static struct fme *Nfmep;
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate static const char *Undiag_reason;
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate static int Nextid = 0;
777c478bd9Sstevel@tonic-gate 
780cc1f05eSjrutt static int Open_fme_count = 0;	/* Count of open FMEs */
790cc1f05eSjrutt 
807c478bd9Sstevel@tonic-gate /* list of fault management exercises underway */
817c478bd9Sstevel@tonic-gate static struct fme {
827c478bd9Sstevel@tonic-gate 	struct fme *next;		/* next exercise */
837c478bd9Sstevel@tonic-gate 	unsigned long long ull;		/* time when fme was created */
847c478bd9Sstevel@tonic-gate 	int id;				/* FME id */
857c478bd9Sstevel@tonic-gate 	struct cfgdata *cfgdata;	/* full configuration data */
867c478bd9Sstevel@tonic-gate 	struct lut *eventtree;		/* propagation tree for this FME */
877c478bd9Sstevel@tonic-gate 	/*
887c478bd9Sstevel@tonic-gate 	 * The initial error report that created this FME is kept in
897c478bd9Sstevel@tonic-gate 	 * two forms.  e0 points to the instance tree node and is used
907c478bd9Sstevel@tonic-gate 	 * by fme_eval() as the starting point for the inference
917c478bd9Sstevel@tonic-gate 	 * algorithm.  e0r is the event handle FMD passed to us when
927c478bd9Sstevel@tonic-gate 	 * the ereport first arrived and is used when setting timers,
937c478bd9Sstevel@tonic-gate 	 * which are always relative to the time of this initial
947c478bd9Sstevel@tonic-gate 	 * report.
957c478bd9Sstevel@tonic-gate 	 */
967c478bd9Sstevel@tonic-gate 	struct event *e0;
977c478bd9Sstevel@tonic-gate 	fmd_event_t *e0r;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	id_t    timer;			/* for setting an fmd time-out */
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate 	struct event *ecurrent;		/* ereport under consideration */
1027c478bd9Sstevel@tonic-gate 	struct event *suspects;		/* current suspect list */
1037c478bd9Sstevel@tonic-gate 	struct event *psuspects;	/* previous suspect list */
1047c478bd9Sstevel@tonic-gate 	int nsuspects;			/* count of suspects */
1057c478bd9Sstevel@tonic-gate 	int nonfault;			/* zero if all suspects T_FAULT */
1067c478bd9Sstevel@tonic-gate 	int posted_suspects;		/* true if we've posted a diagnosis */
1077c478bd9Sstevel@tonic-gate 	int uniqobs;			/* number of unique events observed */
1087c478bd9Sstevel@tonic-gate 	int peek;			/* just peeking, don't track suspects */
1090cc1f05eSjrutt 	int overflow;			/* true if overflow FME */
1107c478bd9Sstevel@tonic-gate 	enum fme_state {
1117c478bd9Sstevel@tonic-gate 		FME_NOTHING = 5000,	/* not evaluated yet */
1127c478bd9Sstevel@tonic-gate 		FME_WAIT,		/* need to wait for more info */
1137c478bd9Sstevel@tonic-gate 		FME_CREDIBLE,		/* suspect list is credible */
1147aec1d6eScindi 		FME_DISPROVED,		/* no valid suspects found */
1157aec1d6eScindi 		FME_DEFERRED		/* don't know yet (k-count not met) */
1167c478bd9Sstevel@tonic-gate 	} state;
1177c478bd9Sstevel@tonic-gate 
1187c478bd9Sstevel@tonic-gate 	unsigned long long pull;	/* time passed since created */
1197c478bd9Sstevel@tonic-gate 	unsigned long long wull;	/* wait until this time for re-eval */
1207c478bd9Sstevel@tonic-gate 	struct event *observations;	/* observation list */
1217c478bd9Sstevel@tonic-gate 	struct lut *globals;		/* values of global variables */
1227c478bd9Sstevel@tonic-gate 	/* fmd interfacing */
1237c478bd9Sstevel@tonic-gate 	fmd_hdl_t *hdl;			/* handle for talking with fmd */
1247c478bd9Sstevel@tonic-gate 	fmd_case_t *fmcase;		/* what fmd 'case' we associate with */
1257c478bd9Sstevel@tonic-gate 	/* stats */
1267c478bd9Sstevel@tonic-gate 	struct stats *Rcount;
1277c478bd9Sstevel@tonic-gate 	struct stats *Hcallcount;
1287c478bd9Sstevel@tonic-gate 	struct stats *Rcallcount;
1297c478bd9Sstevel@tonic-gate 	struct stats *Ccallcount;
1307c478bd9Sstevel@tonic-gate 	struct stats *Ecallcount;
1317c478bd9Sstevel@tonic-gate 	struct stats *Tcallcount;
1327c478bd9Sstevel@tonic-gate 	struct stats *Marrowcount;
1337c478bd9Sstevel@tonic-gate 	struct stats *diags;
1347c478bd9Sstevel@tonic-gate } *FMElist, *EFMElist, *ClosedFMEs;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate static struct case_list {
1377c478bd9Sstevel@tonic-gate 	fmd_case_t *fmcase;
1387c478bd9Sstevel@tonic-gate 	struct case_list *next;
1397c478bd9Sstevel@tonic-gate } *Undiagablecaselist;
1407c478bd9Sstevel@tonic-gate 
1417c478bd9Sstevel@tonic-gate static void fme_eval(struct fme *fmep, fmd_event_t *ffep);
1427c478bd9Sstevel@tonic-gate static enum fme_state hypothesise(struct fme *fmep, struct event *ep,
1437aec1d6eScindi 	unsigned long long at_latest_by, unsigned long long *pdelay);
1447c478bd9Sstevel@tonic-gate static struct node *eventprop_lookup(struct event *ep, const char *propname);
1457c478bd9Sstevel@tonic-gate static struct node *pathstring2epnamenp(char *path);
146*b5016cbbSstephh static void publish_undiagnosable(fmd_hdl_t *hdl, fmd_event_t *ffep,
147*b5016cbbSstephh 	fmd_case_t *fmcase);
1487c478bd9Sstevel@tonic-gate static void restore_suspects(struct fme *fmep);
1497c478bd9Sstevel@tonic-gate static void save_suspects(struct fme *fmep);
1507c478bd9Sstevel@tonic-gate static void destroy_fme(struct fme *f);
1517c478bd9Sstevel@tonic-gate static void fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep,
1527c478bd9Sstevel@tonic-gate     const char *eventstring, const struct ipath *ipp, nvlist_t *nvl);
15308f6c065Sgavinm static void istat_counter_reset_cb(struct istat_entry *entp,
15408f6c065Sgavinm     struct stats *statp, const struct ipath *ipp);
155*b5016cbbSstephh static void serd_reset_cb(struct serd_entry *entp, void *unused,
156*b5016cbbSstephh     const struct ipath *ipp);
157*b5016cbbSstephh static void destroy_fme_bufs(struct fme *fp);
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate static struct fme *
1607c478bd9Sstevel@tonic-gate alloc_fme(void)
1617c478bd9Sstevel@tonic-gate {
1627c478bd9Sstevel@tonic-gate 	struct fme *fmep;
1637c478bd9Sstevel@tonic-gate 
1647c478bd9Sstevel@tonic-gate 	fmep = MALLOC(sizeof (*fmep));
1657c478bd9Sstevel@tonic-gate 	bzero(fmep, sizeof (*fmep));
1667c478bd9Sstevel@tonic-gate 	return (fmep);
1677c478bd9Sstevel@tonic-gate }
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate /*
1707c478bd9Sstevel@tonic-gate  * fme_ready -- called when all initialization of the FME (except for
1717c478bd9Sstevel@tonic-gate  *	stats) has completed successfully.  Adds the fme to global lists
1727c478bd9Sstevel@tonic-gate  *	and establishes its stats.
1737c478bd9Sstevel@tonic-gate  */
1747c478bd9Sstevel@tonic-gate static struct fme *
1757c478bd9Sstevel@tonic-gate fme_ready(struct fme *fmep)
1767c478bd9Sstevel@tonic-gate {
1777c478bd9Sstevel@tonic-gate 	char nbuf[100];
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate 	Nfmep = NULL;	/* don't need to free this on module abort now */
1807c478bd9Sstevel@tonic-gate 
1817c478bd9Sstevel@tonic-gate 	if (EFMElist) {
1827c478bd9Sstevel@tonic-gate 		EFMElist->next = fmep;
1837c478bd9Sstevel@tonic-gate 		EFMElist = fmep;
1847c478bd9Sstevel@tonic-gate 	} else
1857c478bd9Sstevel@tonic-gate 		FMElist = EFMElist = fmep;
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Rcount", fmep->id);
1887c478bd9Sstevel@tonic-gate 	fmep->Rcount = stats_new_counter(nbuf, "ereports received", 0);
1897c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Hcall", fmep->id);
1907c478bd9Sstevel@tonic-gate 	fmep->Hcallcount = stats_new_counter(nbuf, "calls to hypothesise()", 1);
1917c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Rcall", fmep->id);
1927c478bd9Sstevel@tonic-gate 	fmep->Rcallcount = stats_new_counter(nbuf,
1937c478bd9Sstevel@tonic-gate 	    "calls to requirements_test()", 1);
1947c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Ccall", fmep->id);
1957c478bd9Sstevel@tonic-gate 	fmep->Ccallcount = stats_new_counter(nbuf, "calls to causes_test()", 1);
1967c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Ecall", fmep->id);
1977c478bd9Sstevel@tonic-gate 	fmep->Ecallcount =
1987c478bd9Sstevel@tonic-gate 	    stats_new_counter(nbuf, "calls to effects_test()", 1);
1997c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Tcall", fmep->id);
2007c478bd9Sstevel@tonic-gate 	fmep->Tcallcount = stats_new_counter(nbuf, "calls to triggered()", 1);
2017c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Marrow", fmep->id);
2027c478bd9Sstevel@tonic-gate 	fmep->Marrowcount = stats_new_counter(nbuf,
2037c478bd9Sstevel@tonic-gate 	    "arrows marked by mark_arrows()", 1);
2047c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.diags", fmep->id);
2057c478bd9Sstevel@tonic-gate 	fmep->diags = stats_new_counter(nbuf, "suspect lists diagnosed", 0);
2067c478bd9Sstevel@tonic-gate 
2077c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB2, "newfme: config snapshot contains...");
2087c478bd9Sstevel@tonic-gate 	config_print(O_ALTFP|O_VERB2, fmep->cfgdata->cooked);
2097c478bd9Sstevel@tonic-gate 
2107c478bd9Sstevel@tonic-gate 	return (fmep);
2117c478bd9Sstevel@tonic-gate }
2127c478bd9Sstevel@tonic-gate 
213*b5016cbbSstephh extern void ipath_dummy_lut(struct arrow *);
214*b5016cbbSstephh extern struct lut *itree_create_dummy(const char *, const struct ipath *);
215*b5016cbbSstephh 
216*b5016cbbSstephh /* ARGSUSED */
217*b5016cbbSstephh static void
218*b5016cbbSstephh set_needed_arrows(struct event *ep, struct event *ep2, struct fme *fmep)
219*b5016cbbSstephh {
220*b5016cbbSstephh 	struct bubble *bp;
221*b5016cbbSstephh 	struct arrowlist *ap;
222*b5016cbbSstephh 
223*b5016cbbSstephh 	for (bp = itree_next_bubble(ep, NULL); bp;
224*b5016cbbSstephh 	    bp = itree_next_bubble(ep, bp)) {
225*b5016cbbSstephh 		if (bp->t != B_FROM)
226*b5016cbbSstephh 			continue;
227*b5016cbbSstephh 		for (ap = itree_next_arrow(bp, NULL); ap;
228*b5016cbbSstephh 		    ap = itree_next_arrow(bp, ap)) {
229*b5016cbbSstephh 			ap->arrowp->pnode->u.arrow.needed = 1;
230*b5016cbbSstephh 			ipath_dummy_lut(ap->arrowp);
231*b5016cbbSstephh 		}
232*b5016cbbSstephh 	}
233*b5016cbbSstephh }
234*b5016cbbSstephh 
235*b5016cbbSstephh /* ARGSUSED */
236*b5016cbbSstephh static void
237*b5016cbbSstephh unset_needed_arrows(struct event *ep, struct event *ep2, struct fme *fmep)
238*b5016cbbSstephh {
239*b5016cbbSstephh 	struct bubble *bp;
240*b5016cbbSstephh 	struct arrowlist *ap;
241*b5016cbbSstephh 
242*b5016cbbSstephh 	for (bp = itree_next_bubble(ep, NULL); bp;
243*b5016cbbSstephh 	    bp = itree_next_bubble(ep, bp)) {
244*b5016cbbSstephh 		if (bp->t != B_FROM)
245*b5016cbbSstephh 			continue;
246*b5016cbbSstephh 		for (ap = itree_next_arrow(bp, NULL); ap;
247*b5016cbbSstephh 		    ap = itree_next_arrow(bp, ap))
248*b5016cbbSstephh 			ap->arrowp->pnode->u.arrow.needed = 0;
249*b5016cbbSstephh 	}
250*b5016cbbSstephh }
251*b5016cbbSstephh 
252*b5016cbbSstephh static void globals_destructor(void *left, void *right, void *arg);
253*b5016cbbSstephh static void clear_arrows(struct event *ep, struct event *ep2, struct fme *fmep);
254*b5016cbbSstephh 
255*b5016cbbSstephh static void
256*b5016cbbSstephh prune_propagations(const char *e0class, const struct ipath *e0ipp)
257*b5016cbbSstephh {
258*b5016cbbSstephh 	char nbuf[100];
259*b5016cbbSstephh 	unsigned long long my_delay = TIMEVAL_EVENTUALLY;
260*b5016cbbSstephh 	extern struct lut *Usednames;
261*b5016cbbSstephh 
262*b5016cbbSstephh 	Nfmep = alloc_fme();
263*b5016cbbSstephh 	Nfmep->id = Nextid;
264*b5016cbbSstephh 	Nfmep->state = FME_NOTHING;
265*b5016cbbSstephh 	Nfmep->eventtree = itree_create_dummy(e0class, e0ipp);
266*b5016cbbSstephh 	if ((Nfmep->e0 =
267*b5016cbbSstephh 	    itree_lookup(Nfmep->eventtree, e0class, e0ipp)) == NULL) {
268*b5016cbbSstephh 		out(O_ALTFP, "prune_propagations: e0 not in instance tree");
269*b5016cbbSstephh 		itree_free(Nfmep->eventtree);
270*b5016cbbSstephh 		FREE(Nfmep);
271*b5016cbbSstephh 		Nfmep = NULL;
272*b5016cbbSstephh 		return;
273*b5016cbbSstephh 	}
274*b5016cbbSstephh 	Nfmep->ecurrent = Nfmep->observations = Nfmep->e0;
275*b5016cbbSstephh 	Nfmep->e0->count++;
276*b5016cbbSstephh 
277*b5016cbbSstephh 	(void) sprintf(nbuf, "fme%d.Rcount", Nfmep->id);
278*b5016cbbSstephh 	Nfmep->Rcount = stats_new_counter(nbuf, "ereports received", 0);
279*b5016cbbSstephh 	(void) sprintf(nbuf, "fme%d.Hcall", Nfmep->id);
280*b5016cbbSstephh 	Nfmep->Hcallcount =
281*b5016cbbSstephh 	    stats_new_counter(nbuf, "calls to hypothesise()", 1);
282*b5016cbbSstephh 	(void) sprintf(nbuf, "fme%d.Rcall", Nfmep->id);
283*b5016cbbSstephh 	Nfmep->Rcallcount = stats_new_counter(nbuf,
284*b5016cbbSstephh 	    "calls to requirements_test()", 1);
285*b5016cbbSstephh 	(void) sprintf(nbuf, "fme%d.Ccall", Nfmep->id);
286*b5016cbbSstephh 	Nfmep->Ccallcount =
287*b5016cbbSstephh 	    stats_new_counter(nbuf, "calls to causes_test()", 1);
288*b5016cbbSstephh 	(void) sprintf(nbuf, "fme%d.Ecall", Nfmep->id);
289*b5016cbbSstephh 	Nfmep->Ecallcount =
290*b5016cbbSstephh 	    stats_new_counter(nbuf, "calls to effects_test()", 1);
291*b5016cbbSstephh 	(void) sprintf(nbuf, "fme%d.Tcall", Nfmep->id);
292*b5016cbbSstephh 	Nfmep->Tcallcount = stats_new_counter(nbuf, "calls to triggered()", 1);
293*b5016cbbSstephh 	(void) sprintf(nbuf, "fme%d.Marrow", Nfmep->id);
294*b5016cbbSstephh 	Nfmep->Marrowcount = stats_new_counter(nbuf,
295*b5016cbbSstephh 	    "arrows marked by mark_arrows()", 1);
296*b5016cbbSstephh 	(void) sprintf(nbuf, "fme%d.diags", Nfmep->id);
297*b5016cbbSstephh 	Nfmep->diags = stats_new_counter(nbuf, "suspect lists diagnosed", 0);
298*b5016cbbSstephh 
299*b5016cbbSstephh 	Nfmep->peek = 1;
300*b5016cbbSstephh 	lut_walk(Nfmep->eventtree, (lut_cb)unset_needed_arrows, (void *)Nfmep);
301*b5016cbbSstephh 	lut_free(Usednames, NULL, NULL);
302*b5016cbbSstephh 	Usednames = NULL;
303*b5016cbbSstephh 	lut_walk(Nfmep->eventtree, (lut_cb)clear_arrows, (void *)Nfmep);
304*b5016cbbSstephh 	(void) hypothesise(Nfmep, Nfmep->e0, Nfmep->ull, &my_delay);
305*b5016cbbSstephh 	itree_prune(Nfmep->eventtree);
306*b5016cbbSstephh 	lut_walk(Nfmep->eventtree, (lut_cb)set_needed_arrows, (void *)Nfmep);
307*b5016cbbSstephh 
308*b5016cbbSstephh 	stats_delete(Nfmep->Rcount);
309*b5016cbbSstephh 	stats_delete(Nfmep->Hcallcount);
310*b5016cbbSstephh 	stats_delete(Nfmep->Rcallcount);
311*b5016cbbSstephh 	stats_delete(Nfmep->Ccallcount);
312*b5016cbbSstephh 	stats_delete(Nfmep->Ecallcount);
313*b5016cbbSstephh 	stats_delete(Nfmep->Tcallcount);
314*b5016cbbSstephh 	stats_delete(Nfmep->Marrowcount);
315*b5016cbbSstephh 	stats_delete(Nfmep->diags);
316*b5016cbbSstephh 	itree_free(Nfmep->eventtree);
317*b5016cbbSstephh 	lut_free(Nfmep->globals, globals_destructor, NULL);
318*b5016cbbSstephh 	FREE(Nfmep);
319*b5016cbbSstephh }
320*b5016cbbSstephh 
3217c478bd9Sstevel@tonic-gate static struct fme *
322*b5016cbbSstephh newfme(const char *e0class, const struct ipath *e0ipp, fmd_hdl_t *hdl,
323*b5016cbbSstephh 	fmd_case_t *fmcase)
3247c478bd9Sstevel@tonic-gate {
3257c478bd9Sstevel@tonic-gate 	struct cfgdata *cfgdata;
326*b5016cbbSstephh 	int init_size;
327*b5016cbbSstephh 	extern int alloc_total();
3287c478bd9Sstevel@tonic-gate 
329*b5016cbbSstephh 	init_size = alloc_total();
330*b5016cbbSstephh 	out(O_ALTFP|O_STAMP, "start config_snapshot using %d bytes", init_size);
3317c478bd9Sstevel@tonic-gate 	if ((cfgdata = config_snapshot()) == NULL) {
3327c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "newfme: NULL configuration");
3337c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_NOCONF;
3347c478bd9Sstevel@tonic-gate 		return (NULL);
3357c478bd9Sstevel@tonic-gate 	}
336*b5016cbbSstephh 	platform_save_config(hdl, fmcase);
337*b5016cbbSstephh 	out(O_ALTFP|O_STAMP, "config_snapshot added %d bytes",
338*b5016cbbSstephh 	    alloc_total() - init_size);
3397c478bd9Sstevel@tonic-gate 
3407c478bd9Sstevel@tonic-gate 	Nfmep = alloc_fme();
3417c478bd9Sstevel@tonic-gate 
3427c478bd9Sstevel@tonic-gate 	Nfmep->id = Nextid++;
3437c478bd9Sstevel@tonic-gate 	Nfmep->cfgdata = cfgdata;
3447c478bd9Sstevel@tonic-gate 	Nfmep->posted_suspects = 0;
3457c478bd9Sstevel@tonic-gate 	Nfmep->uniqobs = 0;
3467c478bd9Sstevel@tonic-gate 	Nfmep->state = FME_NOTHING;
3477c478bd9Sstevel@tonic-gate 	Nfmep->pull = 0ULL;
3480cc1f05eSjrutt 	Nfmep->overflow = 0;
3497c478bd9Sstevel@tonic-gate 
350*b5016cbbSstephh 	Nfmep->fmcase = fmcase;
351*b5016cbbSstephh 	Nfmep->hdl = hdl;
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	if ((Nfmep->eventtree = itree_create(cfgdata->cooked)) == NULL) {
3547c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "newfme: NULL instance tree");
3557c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_INSTFAIL;
3567c478bd9Sstevel@tonic-gate 		config_free(cfgdata);
357*b5016cbbSstephh 		destroy_fme_bufs(Nfmep);
3587c478bd9Sstevel@tonic-gate 		FREE(Nfmep);
3597c478bd9Sstevel@tonic-gate 		Nfmep = NULL;
3607c478bd9Sstevel@tonic-gate 		return (NULL);
3617c478bd9Sstevel@tonic-gate 	}
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate 	itree_ptree(O_ALTFP|O_VERB2, Nfmep->eventtree);
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	if ((Nfmep->e0 =
3667c478bd9Sstevel@tonic-gate 	    itree_lookup(Nfmep->eventtree, e0class, e0ipp)) == NULL) {
3677c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "newfme: e0 not in instance tree");
3687c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_BADEVENTI;
3697c478bd9Sstevel@tonic-gate 		itree_free(Nfmep->eventtree);
3707c478bd9Sstevel@tonic-gate 		config_free(cfgdata);
371*b5016cbbSstephh 		destroy_fme_bufs(Nfmep);
3727c478bd9Sstevel@tonic-gate 		FREE(Nfmep);
3737c478bd9Sstevel@tonic-gate 		Nfmep = NULL;
3747c478bd9Sstevel@tonic-gate 		return (NULL);
3757c478bd9Sstevel@tonic-gate 	}
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	return (fme_ready(Nfmep));
3787c478bd9Sstevel@tonic-gate }
3797c478bd9Sstevel@tonic-gate 
3807c478bd9Sstevel@tonic-gate void
3817c478bd9Sstevel@tonic-gate fme_fini(void)
3827c478bd9Sstevel@tonic-gate {
3837c478bd9Sstevel@tonic-gate 	struct fme *sfp, *fp;
3847c478bd9Sstevel@tonic-gate 	struct case_list *ucasep, *nextcasep;
3857c478bd9Sstevel@tonic-gate 
3867c478bd9Sstevel@tonic-gate 	ucasep = Undiagablecaselist;
3877c478bd9Sstevel@tonic-gate 	while (ucasep != NULL) {
3887c478bd9Sstevel@tonic-gate 		nextcasep = ucasep->next;
3897c478bd9Sstevel@tonic-gate 		FREE(ucasep);
3907c478bd9Sstevel@tonic-gate 		ucasep = nextcasep;
3917c478bd9Sstevel@tonic-gate 	}
3927c478bd9Sstevel@tonic-gate 	Undiagablecaselist = NULL;
3937c478bd9Sstevel@tonic-gate 
3947c478bd9Sstevel@tonic-gate 	/* clean up closed fmes */
3957c478bd9Sstevel@tonic-gate 	fp = ClosedFMEs;
3967c478bd9Sstevel@tonic-gate 	while (fp != NULL) {
3977c478bd9Sstevel@tonic-gate 		sfp = fp->next;
3987c478bd9Sstevel@tonic-gate 		destroy_fme(fp);
3997c478bd9Sstevel@tonic-gate 		fp = sfp;
4007c478bd9Sstevel@tonic-gate 	}
4017c478bd9Sstevel@tonic-gate 	ClosedFMEs = NULL;
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	fp = FMElist;
4047c478bd9Sstevel@tonic-gate 	while (fp != NULL) {
4057c478bd9Sstevel@tonic-gate 		sfp = fp->next;
4067c478bd9Sstevel@tonic-gate 		destroy_fme(fp);
4077c478bd9Sstevel@tonic-gate 		fp = sfp;
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 	FMElist = EFMElist = NULL;
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate 	/* if we were in the middle of creating an fme, free it now */
4127c478bd9Sstevel@tonic-gate 	if (Nfmep) {
4137c478bd9Sstevel@tonic-gate 		destroy_fme(Nfmep);
4147c478bd9Sstevel@tonic-gate 		Nfmep = NULL;
4157c478bd9Sstevel@tonic-gate 	}
4167c478bd9Sstevel@tonic-gate }
4177c478bd9Sstevel@tonic-gate 
4187c478bd9Sstevel@tonic-gate /*
4197c478bd9Sstevel@tonic-gate  * Allocated space for a buffer name.  20 bytes allows for
4207c478bd9Sstevel@tonic-gate  * a ridiculous 9,999,999 unique observations.
4217c478bd9Sstevel@tonic-gate  */
4227c478bd9Sstevel@tonic-gate #define	OBBUFNMSZ 20
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate /*
4257c478bd9Sstevel@tonic-gate  *  serialize_observation
4267c478bd9Sstevel@tonic-gate  *
4277c478bd9Sstevel@tonic-gate  *  Create a recoverable version of the current observation
4287c478bd9Sstevel@tonic-gate  *  (f->ecurrent).  We keep a serialized version of each unique
4297c478bd9Sstevel@tonic-gate  *  observation in order that we may resume correctly the fme in the
4307c478bd9Sstevel@tonic-gate  *  correct state if eft or fmd crashes and we're restarted.
4317c478bd9Sstevel@tonic-gate  */
4327c478bd9Sstevel@tonic-gate static void
4337c478bd9Sstevel@tonic-gate serialize_observation(struct fme *fp, const char *cls, const struct ipath *ipp)
4347c478bd9Sstevel@tonic-gate {
4357c478bd9Sstevel@tonic-gate 	size_t pkdlen;
4367c478bd9Sstevel@tonic-gate 	char tmpbuf[OBBUFNMSZ];
4377c478bd9Sstevel@tonic-gate 	char *pkd = NULL;
4387c478bd9Sstevel@tonic-gate 	char *estr;
4397c478bd9Sstevel@tonic-gate 
4407c478bd9Sstevel@tonic-gate 	(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", fp->uniqobs);
4417c478bd9Sstevel@tonic-gate 	estr = ipath2str(cls, ipp);
4427c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, tmpbuf, strlen(estr) + 1);
4437c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, tmpbuf, (void *)estr,
4447c478bd9Sstevel@tonic-gate 	    strlen(estr) + 1);
4457c478bd9Sstevel@tonic-gate 	FREE(estr);
4467c478bd9Sstevel@tonic-gate 
4477c478bd9Sstevel@tonic-gate 	if (fp->ecurrent != NULL && fp->ecurrent->nvp != NULL) {
4487c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf,
4497c478bd9Sstevel@tonic-gate 		    OBBUFNMSZ, "observed%d.nvp", fp->uniqobs);
4507c478bd9Sstevel@tonic-gate 		if (nvlist_xpack(fp->ecurrent->nvp,
4517c478bd9Sstevel@tonic-gate 		    &pkd, &pkdlen, NV_ENCODE_XDR, &Eft_nv_hdl) != 0)
4527c478bd9Sstevel@tonic-gate 			out(O_DIE|O_SYS, "pack of observed nvl failed");
4537c478bd9Sstevel@tonic-gate 		fmd_buf_create(fp->hdl, fp->fmcase, tmpbuf, pkdlen);
4547c478bd9Sstevel@tonic-gate 		fmd_buf_write(fp->hdl, fp->fmcase, tmpbuf, (void *)pkd, pkdlen);
4557c478bd9Sstevel@tonic-gate 		FREE(pkd);
4567c478bd9Sstevel@tonic-gate 	}
4577c478bd9Sstevel@tonic-gate 
4587c478bd9Sstevel@tonic-gate 	fp->uniqobs++;
4597c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_NOBS, (void *)&fp->uniqobs,
4607c478bd9Sstevel@tonic-gate 	    sizeof (fp->uniqobs));
4617c478bd9Sstevel@tonic-gate }
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate /*
4647c478bd9Sstevel@tonic-gate  *  init_fme_bufs -- We keep several bits of state about an fme for
4657c478bd9Sstevel@tonic-gate  *	use if eft or fmd crashes and we're restarted.
4667c478bd9Sstevel@tonic-gate  */
4677c478bd9Sstevel@tonic-gate static void
4687c478bd9Sstevel@tonic-gate init_fme_bufs(struct fme *fp)
4697c478bd9Sstevel@tonic-gate {
4707c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_PULL, sizeof (fp->pull));
4717c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_PULL, (void *)&fp->pull,
4727c478bd9Sstevel@tonic-gate 	    sizeof (fp->pull));
4737c478bd9Sstevel@tonic-gate 
4747c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_ID, sizeof (fp->id));
4757c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_ID, (void *)&fp->id,
4767c478bd9Sstevel@tonic-gate 	    sizeof (fp->id));
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_NOBS, sizeof (fp->uniqobs));
4797c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_NOBS, (void *)&fp->uniqobs,
4807c478bd9Sstevel@tonic-gate 	    sizeof (fp->uniqobs));
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_POSTD,
4837c478bd9Sstevel@tonic-gate 	    sizeof (fp->posted_suspects));
4847c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_POSTD,
4857c478bd9Sstevel@tonic-gate 	    (void *)&fp->posted_suspects, sizeof (fp->posted_suspects));
4867c478bd9Sstevel@tonic-gate }
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate static void
4897c478bd9Sstevel@tonic-gate destroy_fme_bufs(struct fme *fp)
4907c478bd9Sstevel@tonic-gate {
4917c478bd9Sstevel@tonic-gate 	char tmpbuf[OBBUFNMSZ];
4927c478bd9Sstevel@tonic-gate 	int o;
4937c478bd9Sstevel@tonic-gate 
494*b5016cbbSstephh 	platform_restore_config(fp->hdl, fp->fmcase);
4957c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_CFGLEN);
4967c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_CFG);
4977c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_PULL);
4987c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_ID);
4997c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_POSTD);
5007c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_NOBS);
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	for (o = 0; o < fp->uniqobs; o++) {
5037c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", o);
5047c478bd9Sstevel@tonic-gate 		fmd_buf_destroy(fp->hdl, fp->fmcase, tmpbuf);
5057c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d.nvp", o);
5067c478bd9Sstevel@tonic-gate 		fmd_buf_destroy(fp->hdl, fp->fmcase, tmpbuf);
5077c478bd9Sstevel@tonic-gate 	}
5087c478bd9Sstevel@tonic-gate }
5097c478bd9Sstevel@tonic-gate 
5107c478bd9Sstevel@tonic-gate /*
5117c478bd9Sstevel@tonic-gate  * reconstitute_observations -- convert a case's serialized observations
5127c478bd9Sstevel@tonic-gate  *	back into struct events.  Returns zero if all observations are
5137c478bd9Sstevel@tonic-gate  *	successfully reconstituted.
5147c478bd9Sstevel@tonic-gate  */
5157c478bd9Sstevel@tonic-gate static int
5167c478bd9Sstevel@tonic-gate reconstitute_observations(struct fme *fmep)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate 	struct event *ep;
5197c478bd9Sstevel@tonic-gate 	struct node *epnamenp = NULL;
5207c478bd9Sstevel@tonic-gate 	size_t pkdlen;
5217c478bd9Sstevel@tonic-gate 	char *pkd = NULL;
5227c478bd9Sstevel@tonic-gate 	char *tmpbuf = alloca(OBBUFNMSZ);
5237c478bd9Sstevel@tonic-gate 	char *sepptr;
5247c478bd9Sstevel@tonic-gate 	char *estr;
5257c478bd9Sstevel@tonic-gate 	int ocnt;
5267c478bd9Sstevel@tonic-gate 	int elen;
5277c478bd9Sstevel@tonic-gate 
5287c478bd9Sstevel@tonic-gate 	for (ocnt = 0; ocnt < fmep->uniqobs; ocnt++) {
5297c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", ocnt);
5307c478bd9Sstevel@tonic-gate 		elen = fmd_buf_size(fmep->hdl, fmep->fmcase, tmpbuf);
5317c478bd9Sstevel@tonic-gate 		if (elen == 0) {
5327c478bd9Sstevel@tonic-gate 			out(O_ALTFP,
5337c478bd9Sstevel@tonic-gate 			    "reconstitute_observation: no %s buffer found.",
5347c478bd9Sstevel@tonic-gate 			    tmpbuf);
5357c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_MISSINGOBS;
5367c478bd9Sstevel@tonic-gate 			break;
5377c478bd9Sstevel@tonic-gate 		}
5387c478bd9Sstevel@tonic-gate 
5397c478bd9Sstevel@tonic-gate 		estr = MALLOC(elen);
5407c478bd9Sstevel@tonic-gate 		fmd_buf_read(fmep->hdl, fmep->fmcase, tmpbuf, estr, elen);
5417c478bd9Sstevel@tonic-gate 		sepptr = strchr(estr, '@');
5427c478bd9Sstevel@tonic-gate 		if (sepptr == NULL) {
5437c478bd9Sstevel@tonic-gate 			out(O_ALTFP,
5447c478bd9Sstevel@tonic-gate 			    "reconstitute_observation: %s: "
5457c478bd9Sstevel@tonic-gate 			    "missing @ separator in %s.",
5467c478bd9Sstevel@tonic-gate 			    tmpbuf, estr);
5477c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_MISSINGPATH;
5487c478bd9Sstevel@tonic-gate 			FREE(estr);
5497c478bd9Sstevel@tonic-gate 			break;
5507c478bd9Sstevel@tonic-gate 		}
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 		*sepptr = '\0';
5537c478bd9Sstevel@tonic-gate 		if ((epnamenp = pathstring2epnamenp(sepptr + 1)) == NULL) {
5547c478bd9Sstevel@tonic-gate 			out(O_ALTFP,
5557c478bd9Sstevel@tonic-gate 			    "reconstitute_observation: %s: "
5567c478bd9Sstevel@tonic-gate 			    "trouble converting path string \"%s\" "
5577c478bd9Sstevel@tonic-gate 			    "to internal representation.",
5587c478bd9Sstevel@tonic-gate 			    tmpbuf, sepptr + 1);
5597c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_MISSINGPATH;
5607c478bd9Sstevel@tonic-gate 			FREE(estr);
5617c478bd9Sstevel@tonic-gate 			break;
5627c478bd9Sstevel@tonic-gate 		}
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 		/* construct the event */
5657c478bd9Sstevel@tonic-gate 		ep = itree_lookup(fmep->eventtree,
5667c478bd9Sstevel@tonic-gate 		    stable(estr), ipath(epnamenp));
5677c478bd9Sstevel@tonic-gate 		if (ep == NULL) {
5687c478bd9Sstevel@tonic-gate 			out(O_ALTFP,
5697c478bd9Sstevel@tonic-gate 			    "reconstitute_observation: %s: "
5707c478bd9Sstevel@tonic-gate 			    "lookup of  \"%s\" in itree failed.",
5717c478bd9Sstevel@tonic-gate 			    tmpbuf, ipath2str(estr, ipath(epnamenp)));
5727c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_BADOBS;
5737c478bd9Sstevel@tonic-gate 			tree_free(epnamenp);
5747c478bd9Sstevel@tonic-gate 			FREE(estr);
5757c478bd9Sstevel@tonic-gate 			break;
5767c478bd9Sstevel@tonic-gate 		}
5777c478bd9Sstevel@tonic-gate 		tree_free(epnamenp);
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 		/*
5807c478bd9Sstevel@tonic-gate 		 * We may or may not have a saved nvlist for the observation
5817c478bd9Sstevel@tonic-gate 		 */
5827c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d.nvp", ocnt);
5837c478bd9Sstevel@tonic-gate 		pkdlen = fmd_buf_size(fmep->hdl, fmep->fmcase, tmpbuf);
5847c478bd9Sstevel@tonic-gate 		if (pkdlen != 0) {
5857c478bd9Sstevel@tonic-gate 			pkd = MALLOC(pkdlen);
5867c478bd9Sstevel@tonic-gate 			fmd_buf_read(fmep->hdl,
5877c478bd9Sstevel@tonic-gate 			    fmep->fmcase, tmpbuf, pkd, pkdlen);
5887aec1d6eScindi 			ASSERT(ep->nvp == NULL);
5897c478bd9Sstevel@tonic-gate 			if (nvlist_xunpack(pkd,
5907c478bd9Sstevel@tonic-gate 			    pkdlen, &ep->nvp, &Eft_nv_hdl) != 0)
5917c478bd9Sstevel@tonic-gate 				out(O_DIE|O_SYS, "pack of observed nvl failed");
5927c478bd9Sstevel@tonic-gate 			FREE(pkd);
5937c478bd9Sstevel@tonic-gate 		}
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 		if (ocnt == 0)
5967c478bd9Sstevel@tonic-gate 			fmep->e0 = ep;
5977c478bd9Sstevel@tonic-gate 
5987c478bd9Sstevel@tonic-gate 		FREE(estr);
5997c478bd9Sstevel@tonic-gate 		fmep->ecurrent = ep;
6007c478bd9Sstevel@tonic-gate 		ep->count++;
6017c478bd9Sstevel@tonic-gate 
6027c478bd9Sstevel@tonic-gate 		/* link it into list of observations seen */
6037c478bd9Sstevel@tonic-gate 		ep->observations = fmep->observations;
6047c478bd9Sstevel@tonic-gate 		fmep->observations = ep;
6057c478bd9Sstevel@tonic-gate 	}
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	if (ocnt == fmep->uniqobs) {
6087c478bd9Sstevel@tonic-gate 		(void) fme_ready(fmep);
6097c478bd9Sstevel@tonic-gate 		return (0);
6107c478bd9Sstevel@tonic-gate 	}
6117c478bd9Sstevel@tonic-gate 
6127c478bd9Sstevel@tonic-gate 	return (1);
6137c478bd9Sstevel@tonic-gate }
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate /*
6167c478bd9Sstevel@tonic-gate  * restart_fme -- called during eft initialization.  Reconstitutes
6177c478bd9Sstevel@tonic-gate  *	an in-progress fme.
6187c478bd9Sstevel@tonic-gate  */
6197c478bd9Sstevel@tonic-gate void
6207c478bd9Sstevel@tonic-gate fme_restart(fmd_hdl_t *hdl, fmd_case_t *inprogress)
6217c478bd9Sstevel@tonic-gate {
6227c478bd9Sstevel@tonic-gate 	nvlist_t *defect;
6237c478bd9Sstevel@tonic-gate 	struct case_list *bad;
6247c478bd9Sstevel@tonic-gate 	struct fme *fmep;
6257c478bd9Sstevel@tonic-gate 	struct cfgdata *cfgdata = NULL;
6267c478bd9Sstevel@tonic-gate 	size_t rawsz;
627*b5016cbbSstephh 	struct event *ep;
628*b5016cbbSstephh 	char *tmpbuf = alloca(OBBUFNMSZ);
629*b5016cbbSstephh 	char *sepptr;
630*b5016cbbSstephh 	char *estr;
631*b5016cbbSstephh 	int elen;
632*b5016cbbSstephh 	struct node *epnamenp = NULL;
633*b5016cbbSstephh 	int init_size;
634*b5016cbbSstephh 	extern int alloc_total();
635*b5016cbbSstephh 
636*b5016cbbSstephh 	/*
637*b5016cbbSstephh 	 * ignore solved or closed cases
638*b5016cbbSstephh 	 */
639*b5016cbbSstephh 	if (fmd_case_solved(hdl, inprogress) ||
640*b5016cbbSstephh 	    fmd_case_closed(hdl, inprogress))
641*b5016cbbSstephh 		return;
6427c478bd9Sstevel@tonic-gate 
6437c478bd9Sstevel@tonic-gate 	fmep = alloc_fme();
6447c478bd9Sstevel@tonic-gate 	fmep->fmcase = inprogress;
6457c478bd9Sstevel@tonic-gate 	fmep->hdl = hdl;
6467c478bd9Sstevel@tonic-gate 
6479f8ca725Sstephh 	if (fmd_buf_size(hdl, inprogress, WOBUF_POSTD) == 0) {
6489f8ca725Sstephh 		out(O_ALTFP, "restart_fme: no saved posted status");
6499f8ca725Sstephh 		Undiag_reason = UD_MISSINGINFO;
6509f8ca725Sstephh 		goto badcase;
6519f8ca725Sstephh 	} else {
6529f8ca725Sstephh 		fmd_buf_read(hdl, inprogress, WOBUF_POSTD,
6539f8ca725Sstephh 		    (void *)&fmep->posted_suspects,
6549f8ca725Sstephh 		    sizeof (fmep->posted_suspects));
6559f8ca725Sstephh 	}
6569f8ca725Sstephh 
657*b5016cbbSstephh 	if (fmd_buf_size(hdl, inprogress, WOBUF_ID) == 0) {
658*b5016cbbSstephh 		out(O_ALTFP, "restart_fme: no saved id");
659*b5016cbbSstephh 		Undiag_reason = UD_MISSINGINFO;
6609f8ca725Sstephh 		goto badcase;
661*b5016cbbSstephh 	} else {
662*b5016cbbSstephh 		fmd_buf_read(hdl, inprogress, WOBUF_ID, (void *)&fmep->id,
663*b5016cbbSstephh 		    sizeof (fmep->id));
664*b5016cbbSstephh 	}
665*b5016cbbSstephh 	if (Nextid <= fmep->id)
666*b5016cbbSstephh 		Nextid = fmep->id + 1;
667*b5016cbbSstephh 
668*b5016cbbSstephh 	out(O_ALTFP, "Replay FME %d", fmep->id);
6699f8ca725Sstephh 
6707c478bd9Sstevel@tonic-gate 	if (fmd_buf_size(hdl, inprogress, WOBUF_CFGLEN) != sizeof (size_t)) {
6717c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: No config data");
6727c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGINFO;
6737c478bd9Sstevel@tonic-gate 		goto badcase;
6747c478bd9Sstevel@tonic-gate 	}
6757c478bd9Sstevel@tonic-gate 	fmd_buf_read(hdl, inprogress, WOBUF_CFGLEN, (void *)&rawsz,
6767c478bd9Sstevel@tonic-gate 	    sizeof (size_t));
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	if ((fmep->e0r = fmd_case_getprincipal(hdl, inprogress)) == NULL) {
6797c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: No event zero");
6807c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGZERO;
6817c478bd9Sstevel@tonic-gate 		goto badcase;
6827c478bd9Sstevel@tonic-gate 	}
6837c478bd9Sstevel@tonic-gate 
684*b5016cbbSstephh 	if (fmd_buf_size(hdl, inprogress, WOBUF_PULL) == 0) {
685*b5016cbbSstephh 		out(O_ALTFP, "restart_fme: no saved wait time");
686*b5016cbbSstephh 		Undiag_reason = UD_MISSINGINFO;
687*b5016cbbSstephh 		goto badcase;
688*b5016cbbSstephh 	} else {
689*b5016cbbSstephh 		fmd_buf_read(hdl, inprogress, WOBUF_PULL, (void *)&fmep->pull,
690*b5016cbbSstephh 		    sizeof (fmep->pull));
691*b5016cbbSstephh 	}
692*b5016cbbSstephh 
693*b5016cbbSstephh 	if (fmd_buf_size(hdl, inprogress, WOBUF_NOBS) == 0) {
694*b5016cbbSstephh 		out(O_ALTFP, "restart_fme: no count of observations");
695*b5016cbbSstephh 		Undiag_reason = UD_MISSINGINFO;
696*b5016cbbSstephh 		goto badcase;
697*b5016cbbSstephh 	} else {
698*b5016cbbSstephh 		fmd_buf_read(hdl, inprogress, WOBUF_NOBS,
699*b5016cbbSstephh 		    (void *)&fmep->uniqobs, sizeof (fmep->uniqobs));
700*b5016cbbSstephh 	}
701*b5016cbbSstephh 
702*b5016cbbSstephh 	(void) snprintf(tmpbuf, OBBUFNMSZ, "observed0");
703*b5016cbbSstephh 	elen = fmd_buf_size(fmep->hdl, fmep->fmcase, tmpbuf);
704*b5016cbbSstephh 	if (elen == 0) {
705*b5016cbbSstephh 		out(O_ALTFP, "reconstitute_observation: no %s buffer found.",
706*b5016cbbSstephh 		    tmpbuf);
707*b5016cbbSstephh 		Undiag_reason = UD_MISSINGOBS;
708*b5016cbbSstephh 		goto badcase;
709*b5016cbbSstephh 	}
710*b5016cbbSstephh 	estr = MALLOC(elen);
711*b5016cbbSstephh 	fmd_buf_read(fmep->hdl, fmep->fmcase, tmpbuf, estr, elen);
712*b5016cbbSstephh 	sepptr = strchr(estr, '@');
713*b5016cbbSstephh 	if (sepptr == NULL) {
714*b5016cbbSstephh 		out(O_ALTFP, "reconstitute_observation: %s: "
715*b5016cbbSstephh 		    "missing @ separator in %s.",
716*b5016cbbSstephh 		    tmpbuf, estr);
717*b5016cbbSstephh 		Undiag_reason = UD_MISSINGPATH;
718*b5016cbbSstephh 		FREE(estr);
719*b5016cbbSstephh 		goto badcase;
720*b5016cbbSstephh 	}
721*b5016cbbSstephh 	*sepptr = '\0';
722*b5016cbbSstephh 	if ((epnamenp = pathstring2epnamenp(sepptr + 1)) == NULL) {
723*b5016cbbSstephh 		out(O_ALTFP, "reconstitute_observation: %s: "
724*b5016cbbSstephh 		    "trouble converting path string \"%s\" "
725*b5016cbbSstephh 		    "to internal representation.", tmpbuf, sepptr + 1);
726*b5016cbbSstephh 		Undiag_reason = UD_MISSINGPATH;
727*b5016cbbSstephh 		FREE(estr);
728*b5016cbbSstephh 		goto badcase;
729*b5016cbbSstephh 	}
730*b5016cbbSstephh 	prune_propagations(stable(estr), ipath(epnamenp));
731*b5016cbbSstephh 	tree_free(epnamenp);
732*b5016cbbSstephh 	FREE(estr);
733*b5016cbbSstephh 
734*b5016cbbSstephh 	init_size = alloc_total();
735*b5016cbbSstephh 	out(O_ALTFP|O_STAMP, "start config_restore using %d bytes", init_size);
7367c478bd9Sstevel@tonic-gate 	cfgdata = MALLOC(sizeof (struct cfgdata));
7377c478bd9Sstevel@tonic-gate 	cfgdata->cooked = NULL;
7387c478bd9Sstevel@tonic-gate 	cfgdata->devcache = NULL;
7397c478bd9Sstevel@tonic-gate 	cfgdata->cpucache = NULL;
740*b5016cbbSstephh 	cfgdata->cooked_refcnt = 0;
741*b5016cbbSstephh 	cfgdata->raw_refcnt = 1;
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 	if (rawsz > 0) {
7447c478bd9Sstevel@tonic-gate 		if (fmd_buf_size(hdl, inprogress, WOBUF_CFG) != rawsz) {
7457c478bd9Sstevel@tonic-gate 			out(O_ALTFP, "restart_fme: Config data size mismatch");
7467c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_CFGMISMATCH;
7477c478bd9Sstevel@tonic-gate 			goto badcase;
7487c478bd9Sstevel@tonic-gate 		}
7497c478bd9Sstevel@tonic-gate 		cfgdata->begin = MALLOC(rawsz);
7507c478bd9Sstevel@tonic-gate 		cfgdata->end = cfgdata->nextfree = cfgdata->begin + rawsz;
7517c478bd9Sstevel@tonic-gate 		fmd_buf_read(hdl,
7527c478bd9Sstevel@tonic-gate 		    inprogress, WOBUF_CFG, cfgdata->begin, rawsz);
7537c478bd9Sstevel@tonic-gate 	} else {
7547c478bd9Sstevel@tonic-gate 		cfgdata->begin = cfgdata->end = cfgdata->nextfree = NULL;
7557c478bd9Sstevel@tonic-gate 	}
7567c478bd9Sstevel@tonic-gate 	fmep->cfgdata = cfgdata;
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	config_cook(cfgdata);
759*b5016cbbSstephh 	if (cfgdata->begin)
760*b5016cbbSstephh 		FREE(cfgdata->begin);
761*b5016cbbSstephh 	cfgdata->begin = NULL;
762*b5016cbbSstephh 	cfgdata->end = NULL;
763*b5016cbbSstephh 	cfgdata->nextfree = NULL;
764*b5016cbbSstephh 	out(O_ALTFP|O_STAMP, "config_restore added %d bytes",
765*b5016cbbSstephh 	    alloc_total() - init_size);
766*b5016cbbSstephh 
7677c478bd9Sstevel@tonic-gate 	if ((fmep->eventtree = itree_create(cfgdata->cooked)) == NULL) {
7687c478bd9Sstevel@tonic-gate 		/* case not properly saved or irretrievable */
7697c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: NULL instance tree");
7707c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_INSTFAIL;
7717c478bd9Sstevel@tonic-gate 		goto badcase;
7727c478bd9Sstevel@tonic-gate 	}
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate 	itree_ptree(O_ALTFP|O_VERB2, fmep->eventtree);
7757c478bd9Sstevel@tonic-gate 
776*b5016cbbSstephh 	if (reconstitute_observations(fmep) != 0)
7777c478bd9Sstevel@tonic-gate 		goto badcase;
7787c478bd9Sstevel@tonic-gate 
779*b5016cbbSstephh 	out(O_ALTFP|O_NONL, "FME %d replay observations: ", fmep->id);
780*b5016cbbSstephh 	for (ep = fmep->observations; ep; ep = ep->observations) {
781*b5016cbbSstephh 		out(O_ALTFP|O_NONL, " ");
782*b5016cbbSstephh 		itree_pevent_brief(O_ALTFP|O_NONL, ep);
7837c478bd9Sstevel@tonic-gate 	}
784*b5016cbbSstephh 	out(O_ALTFP, NULL);
7857c478bd9Sstevel@tonic-gate 
7860cc1f05eSjrutt 	Open_fme_count++;
7870cc1f05eSjrutt 
7887c478bd9Sstevel@tonic-gate 	/* give the diagnosis algorithm a shot at the new FME state */
7899f8ca725Sstephh 	fme_eval(fmep, fmep->e0r);
7907c478bd9Sstevel@tonic-gate 	return;
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate badcase:
7937c478bd9Sstevel@tonic-gate 	if (fmep->eventtree != NULL)
7947c478bd9Sstevel@tonic-gate 		itree_free(fmep->eventtree);
7957c478bd9Sstevel@tonic-gate 	config_free(cfgdata);
7967c478bd9Sstevel@tonic-gate 	destroy_fme_bufs(fmep);
7977c478bd9Sstevel@tonic-gate 	FREE(fmep);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	/*
8007c478bd9Sstevel@tonic-gate 	 * Since we're unable to restart the case, add it to the undiagable
8017c478bd9Sstevel@tonic-gate 	 * list and solve and close it as appropriate.
8027c478bd9Sstevel@tonic-gate 	 */
8037c478bd9Sstevel@tonic-gate 	bad = MALLOC(sizeof (struct case_list));
8047c478bd9Sstevel@tonic-gate 	bad->next = NULL;
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 	if (Undiagablecaselist != NULL)
8077c478bd9Sstevel@tonic-gate 		bad->next = Undiagablecaselist;
8087c478bd9Sstevel@tonic-gate 	Undiagablecaselist = bad;
8097c478bd9Sstevel@tonic-gate 	bad->fmcase = inprogress;
8107c478bd9Sstevel@tonic-gate 
8119f8ca725Sstephh 	out(O_ALTFP|O_NONL, "[case %s (unable to restart), ",
8127c478bd9Sstevel@tonic-gate 	    fmd_case_uuid(hdl, bad->fmcase));
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 	if (fmd_case_solved(hdl, bad->fmcase)) {
8159f8ca725Sstephh 		out(O_ALTFP|O_NONL, "already solved, ");
8167c478bd9Sstevel@tonic-gate 	} else {
8179f8ca725Sstephh 		out(O_ALTFP|O_NONL, "solving, ");
8187c478bd9Sstevel@tonic-gate 		defect = fmd_nvl_create_fault(hdl, UNDIAGNOSABLE_DEFECT, 100,
8197c478bd9Sstevel@tonic-gate 		    NULL, NULL, NULL);
8207c478bd9Sstevel@tonic-gate 		if (Undiag_reason != NULL)
8217c478bd9Sstevel@tonic-gate 			(void) nvlist_add_string(defect,
8227c478bd9Sstevel@tonic-gate 			    UNDIAG_REASON, Undiag_reason);
8237c478bd9Sstevel@tonic-gate 		fmd_case_add_suspect(hdl, bad->fmcase, defect);
8247c478bd9Sstevel@tonic-gate 		fmd_case_solve(hdl, bad->fmcase);
8257c478bd9Sstevel@tonic-gate 	}
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	if (fmd_case_closed(hdl, bad->fmcase)) {
8287c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "already closed ]");
8297c478bd9Sstevel@tonic-gate 	} else {
8307c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "closing ]");
8317c478bd9Sstevel@tonic-gate 		fmd_case_close(hdl, bad->fmcase);
8327c478bd9Sstevel@tonic-gate 	}
8337c478bd9Sstevel@tonic-gate }
8347c478bd9Sstevel@tonic-gate 
8357aec1d6eScindi /*ARGSUSED*/
8367aec1d6eScindi static void
8377aec1d6eScindi globals_destructor(void *left, void *right, void *arg)
8387aec1d6eScindi {
8397aec1d6eScindi 	struct evalue *evp = (struct evalue *)right;
8407aec1d6eScindi 	if (evp->t == NODEPTR)
84180ab886dSwesolows 		tree_free((struct node *)(uintptr_t)evp->v);
8427aec1d6eScindi 	evp->v = NULL;
8437aec1d6eScindi 	FREE(evp);
8447aec1d6eScindi }
8457aec1d6eScindi 
8467c478bd9Sstevel@tonic-gate void
8477c478bd9Sstevel@tonic-gate destroy_fme(struct fme *f)
8487c478bd9Sstevel@tonic-gate {
8497c478bd9Sstevel@tonic-gate 	stats_delete(f->Rcount);
8507c478bd9Sstevel@tonic-gate 	stats_delete(f->Hcallcount);
8517c478bd9Sstevel@tonic-gate 	stats_delete(f->Rcallcount);
8527c478bd9Sstevel@tonic-gate 	stats_delete(f->Ccallcount);
8537c478bd9Sstevel@tonic-gate 	stats_delete(f->Ecallcount);
8547c478bd9Sstevel@tonic-gate 	stats_delete(f->Tcallcount);
8557c478bd9Sstevel@tonic-gate 	stats_delete(f->Marrowcount);
8567c478bd9Sstevel@tonic-gate 	stats_delete(f->diags);
8577c478bd9Sstevel@tonic-gate 
8589f8ca725Sstephh 	if (f->eventtree != NULL)
8599f8ca725Sstephh 		itree_free(f->eventtree);
8609f8ca725Sstephh 	if (f->cfgdata != NULL)
8619f8ca725Sstephh 		config_free(f->cfgdata);
8627aec1d6eScindi 	lut_free(f->globals, globals_destructor, NULL);
8637c478bd9Sstevel@tonic-gate 	FREE(f);
8647c478bd9Sstevel@tonic-gate }
8657c478bd9Sstevel@tonic-gate 
8667c478bd9Sstevel@tonic-gate static const char *
8677c478bd9Sstevel@tonic-gate fme_state2str(enum fme_state s)
8687c478bd9Sstevel@tonic-gate {
8697c478bd9Sstevel@tonic-gate 	switch (s) {
8707c478bd9Sstevel@tonic-gate 	case FME_NOTHING:	return ("NOTHING");
8717c478bd9Sstevel@tonic-gate 	case FME_WAIT:		return ("WAIT");
8727c478bd9Sstevel@tonic-gate 	case FME_CREDIBLE:	return ("CREDIBLE");
8737c478bd9Sstevel@tonic-gate 	case FME_DISPROVED:	return ("DISPROVED");
8747aec1d6eScindi 	case FME_DEFERRED:	return ("DEFERRED");
8757c478bd9Sstevel@tonic-gate 	default:		return ("UNKNOWN");
8767c478bd9Sstevel@tonic-gate 	}
8777c478bd9Sstevel@tonic-gate }
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate static int
8807c478bd9Sstevel@tonic-gate is_problem(enum nametype t)
8817c478bd9Sstevel@tonic-gate {
8827c478bd9Sstevel@tonic-gate 	return (t == N_FAULT || t == N_DEFECT || t == N_UPSET);
8837c478bd9Sstevel@tonic-gate }
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate static int
8867c478bd9Sstevel@tonic-gate is_fault(enum nametype t)
8877c478bd9Sstevel@tonic-gate {
8887c478bd9Sstevel@tonic-gate 	return (t == N_FAULT);
8897c478bd9Sstevel@tonic-gate }
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate static int
8927c478bd9Sstevel@tonic-gate is_defect(enum nametype t)
8937c478bd9Sstevel@tonic-gate {
8947c478bd9Sstevel@tonic-gate 	return (t == N_DEFECT);
8957c478bd9Sstevel@tonic-gate }
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate static int
8987c478bd9Sstevel@tonic-gate is_upset(enum nametype t)
8997c478bd9Sstevel@tonic-gate {
9007c478bd9Sstevel@tonic-gate 	return (t == N_UPSET);
9017c478bd9Sstevel@tonic-gate }
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate static void
9047c478bd9Sstevel@tonic-gate fme_print(int flags, struct fme *fmep)
9057c478bd9Sstevel@tonic-gate {
9067c478bd9Sstevel@tonic-gate 	struct event *ep;
9077c478bd9Sstevel@tonic-gate 
9087c478bd9Sstevel@tonic-gate 	out(flags, "Fault Management Exercise %d", fmep->id);
9097c478bd9Sstevel@tonic-gate 	out(flags, "\t       State: %s", fme_state2str(fmep->state));
9107c478bd9Sstevel@tonic-gate 	out(flags|O_NONL, "\t  Start time: ");
9117c478bd9Sstevel@tonic-gate 	ptree_timeval(flags|O_NONL, &fmep->ull);
9127c478bd9Sstevel@tonic-gate 	out(flags, NULL);
9137c478bd9Sstevel@tonic-gate 	if (fmep->wull) {
9147c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, "\t   Wait time: ");
9157c478bd9Sstevel@tonic-gate 		ptree_timeval(flags|O_NONL, &fmep->wull);
9167c478bd9Sstevel@tonic-gate 		out(flags, NULL);
9177c478bd9Sstevel@tonic-gate 	}
9187c478bd9Sstevel@tonic-gate 	out(flags|O_NONL, "\t          E0: ");
9197c478bd9Sstevel@tonic-gate 	if (fmep->e0)
9207c478bd9Sstevel@tonic-gate 		itree_pevent_brief(flags|O_NONL, fmep->e0);
9217c478bd9Sstevel@tonic-gate 	else
9227c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, "NULL");
9237c478bd9Sstevel@tonic-gate 	out(flags, NULL);
9247c478bd9Sstevel@tonic-gate 	out(flags|O_NONL, "\tObservations:");
9257c478bd9Sstevel@tonic-gate 	for (ep = fmep->observations; ep; ep = ep->observations) {
9267c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, " ");
9277c478bd9Sstevel@tonic-gate 		itree_pevent_brief(flags|O_NONL, ep);
9287c478bd9Sstevel@tonic-gate 	}
9297c478bd9Sstevel@tonic-gate 	out(flags, NULL);
9307c478bd9Sstevel@tonic-gate 	out(flags|O_NONL, "\tSuspect list:");
9317c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = ep->suspects) {
9327c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, " ");
9337c478bd9Sstevel@tonic-gate 		itree_pevent_brief(flags|O_NONL, ep);
9347c478bd9Sstevel@tonic-gate 	}
9357c478bd9Sstevel@tonic-gate 	out(flags, NULL);
9369f8ca725Sstephh 	if (fmep->eventtree != NULL) {
9379f8ca725Sstephh 		out(flags|O_VERB2, "\t        Tree:");
9389f8ca725Sstephh 		itree_ptree(flags|O_VERB2, fmep->eventtree);
9399f8ca725Sstephh 	}
9407c478bd9Sstevel@tonic-gate }
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate static struct node *
9437c478bd9Sstevel@tonic-gate pathstring2epnamenp(char *path)
9447c478bd9Sstevel@tonic-gate {
9457c478bd9Sstevel@tonic-gate 	char *sep = "/";
9467c478bd9Sstevel@tonic-gate 	struct node *ret;
9477c478bd9Sstevel@tonic-gate 	char *ptr;
9487c478bd9Sstevel@tonic-gate 
9497c478bd9Sstevel@tonic-gate 	if ((ptr = strtok(path, sep)) == NULL)
9507c478bd9Sstevel@tonic-gate 		out(O_DIE, "pathstring2epnamenp: invalid empty class");
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	ret = tree_iname(stable(ptr), NULL, 0);
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 	while ((ptr = strtok(NULL, sep)) != NULL)
9557c478bd9Sstevel@tonic-gate 		ret = tree_name_append(ret,
9567c478bd9Sstevel@tonic-gate 		    tree_iname(stable(ptr), NULL, 0));
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	return (ret);
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate /*
9627c478bd9Sstevel@tonic-gate  * for a given upset sp, increment the corresponding SERD engine.  if the
9637c478bd9Sstevel@tonic-gate  * SERD engine trips, return the ename and ipp of the resulting ereport.
9647c478bd9Sstevel@tonic-gate  * returns true if engine tripped and *enamep and *ippp were filled in.
9657c478bd9Sstevel@tonic-gate  */
9667c478bd9Sstevel@tonic-gate static int
9677aec1d6eScindi serd_eval(struct fme *fmep, fmd_hdl_t *hdl, fmd_event_t *ffep,
9687aec1d6eScindi     fmd_case_t *fmcase, struct event *sp, const char **enamep,
9697aec1d6eScindi     const struct ipath **ippp)
9707c478bd9Sstevel@tonic-gate {
9717c478bd9Sstevel@tonic-gate 	struct node *serdinst;
9727c478bd9Sstevel@tonic-gate 	char *serdname;
9737aec1d6eScindi 	struct node *nid;
974*b5016cbbSstephh 	struct serd_entry *newentp;
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 	ASSERT(sp->t == N_UPSET);
9777c478bd9Sstevel@tonic-gate 	ASSERT(ffep != NULL);
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	/*
9807c478bd9Sstevel@tonic-gate 	 * obtain instanced SERD engine from the upset sp.  from this
9817c478bd9Sstevel@tonic-gate 	 * derive serdname, the string used to identify the SERD engine.
9827c478bd9Sstevel@tonic-gate 	 */
9837c478bd9Sstevel@tonic-gate 	serdinst = eventprop_lookup(sp, L_engine);
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	if (serdinst == NULL)
9867c478bd9Sstevel@tonic-gate 		return (NULL);
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 	serdname = ipath2str(serdinst->u.stmt.np->u.event.ename->u.name.s,
9897c478bd9Sstevel@tonic-gate 	    ipath(serdinst->u.stmt.np->u.event.epname));
9907c478bd9Sstevel@tonic-gate 
9917aec1d6eScindi 	/* handle serd engine "id" property, if there is one */
9927aec1d6eScindi 	if ((nid =
9937aec1d6eScindi 	    lut_lookup(serdinst->u.stmt.lutp, (void *)L_id, NULL)) != NULL) {
9947aec1d6eScindi 		struct evalue *gval;
9957aec1d6eScindi 		char suffixbuf[200];
9967aec1d6eScindi 		char *suffix;
9977aec1d6eScindi 		char *nserdname;
9987aec1d6eScindi 		size_t nname;
9997aec1d6eScindi 
10007aec1d6eScindi 		out(O_ALTFP|O_NONL, "serd \"%s\" id: ", serdname);
10017aec1d6eScindi 		ptree_name_iter(O_ALTFP|O_NONL, nid);
10027aec1d6eScindi 
10037aec1d6eScindi 		ASSERTinfo(nid->t == T_GLOBID, ptree_nodetype2str(nid->t));
10047aec1d6eScindi 
10057aec1d6eScindi 		if ((gval = lut_lookup(fmep->globals,
10067aec1d6eScindi 		    (void *)nid->u.globid.s, NULL)) == NULL) {
10077aec1d6eScindi 			out(O_ALTFP, " undefined");
10087aec1d6eScindi 		} else if (gval->t == UINT64) {
10097aec1d6eScindi 			out(O_ALTFP, " %llu", gval->v);
10107aec1d6eScindi 			(void) sprintf(suffixbuf, "%llu", gval->v);
10117aec1d6eScindi 			suffix = suffixbuf;
10127aec1d6eScindi 		} else {
101380ab886dSwesolows 			out(O_ALTFP, " \"%s\"", (char *)(uintptr_t)gval->v);
101480ab886dSwesolows 			suffix = (char *)(uintptr_t)gval->v;
10157aec1d6eScindi 		}
10167aec1d6eScindi 
10177aec1d6eScindi 		nname = strlen(serdname) + strlen(suffix) + 2;
10187aec1d6eScindi 		nserdname = MALLOC(nname);
10197aec1d6eScindi 		(void) snprintf(nserdname, nname, "%s:%s", serdname, suffix);
10207aec1d6eScindi 		FREE(serdname);
10217aec1d6eScindi 		serdname = nserdname;
10227aec1d6eScindi 	}
10237aec1d6eScindi 
10247c478bd9Sstevel@tonic-gate 	if (!fmd_serd_exists(hdl, serdname)) {
10257c478bd9Sstevel@tonic-gate 		struct node *nN, *nT;
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 		/* no SERD engine yet, so create it */
10287c478bd9Sstevel@tonic-gate 		nN = lut_lookup(serdinst->u.stmt.lutp, (void *)L_N, NULL);
10297c478bd9Sstevel@tonic-gate 		nT = lut_lookup(serdinst->u.stmt.lutp, (void *)L_T, NULL);
10307c478bd9Sstevel@tonic-gate 
10317c478bd9Sstevel@tonic-gate 		ASSERT(nN->t == T_NUM);
10327c478bd9Sstevel@tonic-gate 		ASSERT(nT->t == T_TIMEVAL);
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 		fmd_serd_create(hdl, serdname, (uint_t)nN->u.ull,
10357c478bd9Sstevel@tonic-gate 		    (hrtime_t)nT->u.ull);
10367c478bd9Sstevel@tonic-gate 	}
10377c478bd9Sstevel@tonic-gate 
1038*b5016cbbSstephh 	newentp = MALLOC(sizeof (*newentp));
1039*b5016cbbSstephh 	newentp->ename = serdinst->u.stmt.np->u.event.ename->u.name.s;
1040*b5016cbbSstephh 	newentp->ipath = ipath(serdinst->u.stmt.np->u.event.epname);
1041*b5016cbbSstephh 	newentp->hdl = hdl;
1042*b5016cbbSstephh 	if (lut_lookup(SerdEngines, newentp, (lut_cmp)serd_cmp) == NULL) {
1043*b5016cbbSstephh 		SerdEngines = lut_add(SerdEngines, (void *)newentp,
1044*b5016cbbSstephh 		    (void *)NULL, (lut_cmp)serd_cmp);
1045*b5016cbbSstephh 		Serd_need_save = 1;
1046*b5016cbbSstephh 		serd_save();
1047*b5016cbbSstephh 	} else {
1048*b5016cbbSstephh 		FREE(newentp);
1049*b5016cbbSstephh 	}
1050*b5016cbbSstephh 
10517c478bd9Sstevel@tonic-gate 
10527c478bd9Sstevel@tonic-gate 	/*
10537c478bd9Sstevel@tonic-gate 	 * increment SERD engine.  if engine fires, reset serd
10547c478bd9Sstevel@tonic-gate 	 * engine and return trip_strcode
10557c478bd9Sstevel@tonic-gate 	 */
10567c478bd9Sstevel@tonic-gate 	if (fmd_serd_record(hdl, serdname, ffep)) {
10577c478bd9Sstevel@tonic-gate 		struct node *tripinst = lut_lookup(serdinst->u.stmt.lutp,
10587c478bd9Sstevel@tonic-gate 		    (void *)L_trip, NULL);
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate 		ASSERT(tripinst != NULL);
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 		*enamep = tripinst->u.event.ename->u.name.s;
10637c478bd9Sstevel@tonic-gate 		*ippp = ipath(tripinst->u.event.epname);
10647c478bd9Sstevel@tonic-gate 
10653e8d8e18Sdb 		fmd_case_add_serd(hdl, fmcase, serdname);
10667c478bd9Sstevel@tonic-gate 		fmd_serd_reset(hdl, serdname);
10677c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "[engine fired: %s, sending: ", serdname);
10687c478bd9Sstevel@tonic-gate 		ipath_print(O_ALTFP|O_NONL, *enamep, *ippp);
10697c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "]");
10707c478bd9Sstevel@tonic-gate 
10717c478bd9Sstevel@tonic-gate 		FREE(serdname);
10727c478bd9Sstevel@tonic-gate 		return (1);
10737c478bd9Sstevel@tonic-gate 	}
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 	FREE(serdname);
10767c478bd9Sstevel@tonic-gate 	return (0);
10777c478bd9Sstevel@tonic-gate }
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate /*
10807c478bd9Sstevel@tonic-gate  * search a suspect list for upsets.  feed each upset to serd_eval() and
10817c478bd9Sstevel@tonic-gate  * build up tripped[], an array of ereports produced by the firing of
10827c478bd9Sstevel@tonic-gate  * any SERD engines.  then feed each ereport back into
10837c478bd9Sstevel@tonic-gate  * fme_receive_report().
10847c478bd9Sstevel@tonic-gate  *
10857c478bd9Sstevel@tonic-gate  * returns ntrip, the number of these ereports produced.
10867c478bd9Sstevel@tonic-gate  */
10877c478bd9Sstevel@tonic-gate static int
10887c478bd9Sstevel@tonic-gate upsets_eval(struct fme *fmep, fmd_event_t *ffep)
10897c478bd9Sstevel@tonic-gate {
10907c478bd9Sstevel@tonic-gate 	/* we build an array of tripped ereports that we send ourselves */
10917c478bd9Sstevel@tonic-gate 	struct {
10927c478bd9Sstevel@tonic-gate 		const char *ename;
10937c478bd9Sstevel@tonic-gate 		const struct ipath *ipp;
10947c478bd9Sstevel@tonic-gate 	} *tripped;
10957c478bd9Sstevel@tonic-gate 	struct event *sp;
10967c478bd9Sstevel@tonic-gate 	int ntrip, nupset, i;
10977c478bd9Sstevel@tonic-gate 
10987c478bd9Sstevel@tonic-gate 	/*
10997c478bd9Sstevel@tonic-gate 	 * count the number of upsets to determine the upper limit on
11007c478bd9Sstevel@tonic-gate 	 * expected trip ereport strings.  remember that one upset can
11017c478bd9Sstevel@tonic-gate 	 * lead to at most one ereport.
11027c478bd9Sstevel@tonic-gate 	 */
11037c478bd9Sstevel@tonic-gate 	nupset = 0;
11047c478bd9Sstevel@tonic-gate 	for (sp = fmep->suspects; sp; sp = sp->suspects) {
11057c478bd9Sstevel@tonic-gate 		if (sp->t == N_UPSET)
11067c478bd9Sstevel@tonic-gate 			nupset++;
11077c478bd9Sstevel@tonic-gate 	}
11087c478bd9Sstevel@tonic-gate 
11097c478bd9Sstevel@tonic-gate 	if (nupset == 0)
11107c478bd9Sstevel@tonic-gate 		return (0);
11117c478bd9Sstevel@tonic-gate 
11127c478bd9Sstevel@tonic-gate 	/*
11137c478bd9Sstevel@tonic-gate 	 * get to this point if we have upsets and expect some trip
11147c478bd9Sstevel@tonic-gate 	 * ereports
11157c478bd9Sstevel@tonic-gate 	 */
11167c478bd9Sstevel@tonic-gate 	tripped = alloca(sizeof (*tripped) * nupset);
11177c478bd9Sstevel@tonic-gate 	bzero((void *)tripped, sizeof (*tripped) * nupset);
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	ntrip = 0;
11207c478bd9Sstevel@tonic-gate 	for (sp = fmep->suspects; sp; sp = sp->suspects)
11213e8d8e18Sdb 		if (sp->t == N_UPSET &&
11227aec1d6eScindi 		    serd_eval(fmep, fmep->hdl, ffep, fmep->fmcase, sp,
1123*b5016cbbSstephh 		    &tripped[ntrip].ename, &tripped[ntrip].ipp))
11247c478bd9Sstevel@tonic-gate 			ntrip++;
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	for (i = 0; i < ntrip; i++)
11277aec1d6eScindi 		fme_receive_report(fmep->hdl, ffep,
11287c478bd9Sstevel@tonic-gate 		    tripped[i].ename, tripped[i].ipp, NULL);
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate 	return (ntrip);
11317c478bd9Sstevel@tonic-gate }
11327c478bd9Sstevel@tonic-gate 
11337c478bd9Sstevel@tonic-gate /*
11347c478bd9Sstevel@tonic-gate  * fme_receive_external_report -- call when an external ereport comes in
11357c478bd9Sstevel@tonic-gate  *
11367c478bd9Sstevel@tonic-gate  * this routine just converts the relevant information from the ereport
11377c478bd9Sstevel@tonic-gate  * into a format used internally and passes it on to fme_receive_report().
11387c478bd9Sstevel@tonic-gate  */
11397c478bd9Sstevel@tonic-gate void
11407c478bd9Sstevel@tonic-gate fme_receive_external_report(fmd_hdl_t *hdl, fmd_event_t *ffep, nvlist_t *nvl,
11417c478bd9Sstevel@tonic-gate     const char *eventstring)
11427c478bd9Sstevel@tonic-gate {
11437c478bd9Sstevel@tonic-gate 	struct node *epnamenp = platform_getpath(nvl);
11447c478bd9Sstevel@tonic-gate 	const struct ipath *ipp;
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	/*
11477c478bd9Sstevel@tonic-gate 	 * XFILE: If we ended up without a path, it's an X-file.
11487c478bd9Sstevel@tonic-gate 	 * For now, use our undiagnosable interface.
11497c478bd9Sstevel@tonic-gate 	 */
11507c478bd9Sstevel@tonic-gate 	if (epnamenp == NULL) {
1151*b5016cbbSstephh 		fmd_case_t *fmcase;
1152*b5016cbbSstephh 
11537c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "XFILE: Unable to get path from ereport");
11547c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_NOPATH;
1155*b5016cbbSstephh 		fmcase = fmd_case_open(hdl, NULL);
1156*b5016cbbSstephh 		publish_undiagnosable(hdl, ffep, fmcase);
11577c478bd9Sstevel@tonic-gate 		return;
11587c478bd9Sstevel@tonic-gate 	}
11597c478bd9Sstevel@tonic-gate 
11607c478bd9Sstevel@tonic-gate 	ipp = ipath(epnamenp);
11617c478bd9Sstevel@tonic-gate 	tree_free(epnamenp);
11627c478bd9Sstevel@tonic-gate 	fme_receive_report(hdl, ffep, stable(eventstring), ipp, nvl);
11637c478bd9Sstevel@tonic-gate }
11647c478bd9Sstevel@tonic-gate 
116508f6c065Sgavinm /*ARGSUSED*/
116608f6c065Sgavinm void
116708f6c065Sgavinm fme_receive_repair_list(fmd_hdl_t *hdl, fmd_event_t *ffep, nvlist_t *nvl,
116808f6c065Sgavinm     const char *eventstring)
116908f6c065Sgavinm {
117008f6c065Sgavinm 	char *uuid;
117108f6c065Sgavinm 	nvlist_t **nva;
117208f6c065Sgavinm 	uint_t nvc;
117308f6c065Sgavinm 	const struct ipath *ipp;
117408f6c065Sgavinm 
117508f6c065Sgavinm 	if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) != 0 ||
117608f6c065Sgavinm 	    nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST,
117708f6c065Sgavinm 	    &nva, &nvc) != 0) {
117808f6c065Sgavinm 		out(O_ALTFP, "No uuid or fault list for list.repaired event");
117908f6c065Sgavinm 		return;
118008f6c065Sgavinm 	}
118108f6c065Sgavinm 
118208f6c065Sgavinm 	out(O_ALTFP, "Processing list.repaired from case %s", uuid);
118308f6c065Sgavinm 
118408f6c065Sgavinm 	while (nvc-- != 0) {
118508f6c065Sgavinm 		/*
1186*b5016cbbSstephh 		 * Reset any istat or serd engine associated with this path.
118708f6c065Sgavinm 		 */
118808f6c065Sgavinm 		char *path;
118908f6c065Sgavinm 
119008f6c065Sgavinm 		if ((ipp = platform_fault2ipath(*nva++)) == NULL)
119108f6c065Sgavinm 			continue;
119208f6c065Sgavinm 
119308f6c065Sgavinm 		path = ipath2str(NULL, ipp);
119408f6c065Sgavinm 		out(O_ALTFP, "fme_receive_repair_list: resetting state for %s",
119508f6c065Sgavinm 		    path);
119608f6c065Sgavinm 		FREE(path);
119708f6c065Sgavinm 
119808f6c065Sgavinm 		lut_walk(Istats, (lut_cb)istat_counter_reset_cb, (void *)ipp);
119908f6c065Sgavinm 		istat_save();
120008f6c065Sgavinm 
1201*b5016cbbSstephh 		lut_walk(SerdEngines, (lut_cb)serd_reset_cb, (void *)ipp);
1202*b5016cbbSstephh 		serd_save();
120308f6c065Sgavinm 	}
120408f6c065Sgavinm }
120508f6c065Sgavinm 
12067aec1d6eScindi static int mark_arrows(struct fme *fmep, struct event *ep, int mark,
120700d0963fSdilpreet     unsigned long long at_latest_by, unsigned long long *pdelay, int keep);
12087aec1d6eScindi 
12097aec1d6eScindi /* ARGSUSED */
12107aec1d6eScindi static void
12117aec1d6eScindi clear_arrows(struct event *ep, struct event *ep2, struct fme *fmep)
12127aec1d6eScindi {
12137aec1d6eScindi 	struct bubble *bp;
12147aec1d6eScindi 	struct arrowlist *ap;
12157aec1d6eScindi 
12167aec1d6eScindi 	ep->cached_state = 0;
121700d0963fSdilpreet 	ep->keep_in_tree = 0;
12187aec1d6eScindi 	for (bp = itree_next_bubble(ep, NULL); bp;
12197aec1d6eScindi 	    bp = itree_next_bubble(ep, bp)) {
12207aec1d6eScindi 		if (bp->t != B_FROM)
12217aec1d6eScindi 			continue;
12227aec1d6eScindi 		bp->mark = 0;
12237aec1d6eScindi 		for (ap = itree_next_arrow(bp, NULL); ap;
12247aec1d6eScindi 		    ap = itree_next_arrow(bp, ap))
12257aec1d6eScindi 			ap->arrowp->mark = 0;
12267aec1d6eScindi 	}
12277aec1d6eScindi }
12287aec1d6eScindi 
1229*b5016cbbSstephh static void
1230*b5016cbbSstephh fme_reload_cfgdata(struct fme *fmep)
1231*b5016cbbSstephh {
1232*b5016cbbSstephh 	size_t rawsz;
1233*b5016cbbSstephh 
1234*b5016cbbSstephh 	fmep->cfgdata = MALLOC(sizeof (struct cfgdata));
1235*b5016cbbSstephh 	fmep->cfgdata->cooked = NULL;
1236*b5016cbbSstephh 	fmep->cfgdata->devcache = NULL;
1237*b5016cbbSstephh 	fmep->cfgdata->cpucache = NULL;
1238*b5016cbbSstephh 	fmep->cfgdata->cooked_refcnt = 0;
1239*b5016cbbSstephh 	fmep->cfgdata->raw_refcnt = 1;
1240*b5016cbbSstephh 	fmd_buf_read(fmep->hdl, fmep->fmcase, WOBUF_CFGLEN,
1241*b5016cbbSstephh 	    (void *)&rawsz, sizeof (size_t));
1242*b5016cbbSstephh 	if (rawsz > 0) {
1243*b5016cbbSstephh 		fmep->cfgdata->begin = MALLOC(rawsz);
1244*b5016cbbSstephh 		fmep->cfgdata->end = fmep->cfgdata->nextfree =
1245*b5016cbbSstephh 		    fmep->cfgdata->begin + rawsz;
1246*b5016cbbSstephh 		fmd_buf_read(fmep->hdl, fmep->fmcase, WOBUF_CFG,
1247*b5016cbbSstephh 		    fmep->cfgdata->begin, rawsz);
1248*b5016cbbSstephh 		config_cook(fmep->cfgdata);
1249*b5016cbbSstephh 		FREE(fmep->cfgdata->begin);
1250*b5016cbbSstephh 	}
1251*b5016cbbSstephh 	fmep->cfgdata->begin = NULL;
1252*b5016cbbSstephh 	fmep->cfgdata->end = NULL;
1253*b5016cbbSstephh 	fmep->cfgdata->nextfree = NULL;
1254*b5016cbbSstephh }
1255*b5016cbbSstephh 
12567c478bd9Sstevel@tonic-gate static void
12577c478bd9Sstevel@tonic-gate fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep,
12587c478bd9Sstevel@tonic-gate     const char *eventstring, const struct ipath *ipp, nvlist_t *nvl)
12597c478bd9Sstevel@tonic-gate {
12607c478bd9Sstevel@tonic-gate 	struct event *ep;
12617c478bd9Sstevel@tonic-gate 	struct fme *fmep = NULL;
12620cc1f05eSjrutt 	struct fme *ofmep = NULL;
12630cc1f05eSjrutt 	struct fme *cfmep, *svfmep;
12647c478bd9Sstevel@tonic-gate 	int matched = 0;
12650cc1f05eSjrutt 	nvlist_t *defect;
1266*b5016cbbSstephh 	fmd_case_t *fmcase;
12677c478bd9Sstevel@tonic-gate 
12687c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_NONL, "fme_receive_report: ");
12697c478bd9Sstevel@tonic-gate 	ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
12707c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_STAMP, NULL);
12717c478bd9Sstevel@tonic-gate 
12727c478bd9Sstevel@tonic-gate 	/* decide which FME it goes to */
12737c478bd9Sstevel@tonic-gate 	for (fmep = FMElist; fmep; fmep = fmep->next) {
12747c478bd9Sstevel@tonic-gate 		int prev_verbose;
12757c478bd9Sstevel@tonic-gate 		unsigned long long my_delay = TIMEVAL_EVENTUALLY;
12767c478bd9Sstevel@tonic-gate 		enum fme_state state;
12777aec1d6eScindi 		nvlist_t *pre_peek_nvp = NULL;
12787c478bd9Sstevel@tonic-gate 
12790cc1f05eSjrutt 		if (fmep->overflow) {
12800cc1f05eSjrutt 			if (!(fmd_case_closed(fmep->hdl, fmep->fmcase)))
12810cc1f05eSjrutt 				ofmep = fmep;
12820cc1f05eSjrutt 
12830cc1f05eSjrutt 			continue;
12840cc1f05eSjrutt 		}
12850cc1f05eSjrutt 
1286d96ce684Sstephh 		/*
1287d96ce684Sstephh 		 * ignore solved or closed cases
1288d96ce684Sstephh 		 */
1289d96ce684Sstephh 		if (fmep->posted_suspects ||
1290d96ce684Sstephh 		    fmd_case_solved(fmep->hdl, fmep->fmcase) ||
1291d96ce684Sstephh 		    fmd_case_closed(fmep->hdl, fmep->fmcase))
1292d96ce684Sstephh 			continue;
1293d96ce684Sstephh 
12947c478bd9Sstevel@tonic-gate 		/* look up event in event tree for this FME */
12957c478bd9Sstevel@tonic-gate 		if ((ep = itree_lookup(fmep->eventtree,
12967c478bd9Sstevel@tonic-gate 		    eventstring, ipp)) == NULL)
12977c478bd9Sstevel@tonic-gate 			continue;
12987c478bd9Sstevel@tonic-gate 
12997c478bd9Sstevel@tonic-gate 		/* note observation */
13007c478bd9Sstevel@tonic-gate 		fmep->ecurrent = ep;
13017c478bd9Sstevel@tonic-gate 		if (ep->count++ == 0) {
13027c478bd9Sstevel@tonic-gate 			/* link it into list of observations seen */
13037c478bd9Sstevel@tonic-gate 			ep->observations = fmep->observations;
13047c478bd9Sstevel@tonic-gate 			fmep->observations = ep;
13057c478bd9Sstevel@tonic-gate 			ep->nvp = evnv_dupnvl(nvl);
13067aec1d6eScindi 		} else {
13077aec1d6eScindi 			/* use new payload values for peek */
13087aec1d6eScindi 			pre_peek_nvp = ep->nvp;
13097aec1d6eScindi 			ep->nvp = evnv_dupnvl(nvl);
13107c478bd9Sstevel@tonic-gate 		}
13117c478bd9Sstevel@tonic-gate 
13127c478bd9Sstevel@tonic-gate 		/* tell hypothesise() not to mess with suspect list */
13137c478bd9Sstevel@tonic-gate 		fmep->peek = 1;
13147c478bd9Sstevel@tonic-gate 
13157c478bd9Sstevel@tonic-gate 		/* don't want this to be verbose (unless Debug is set) */
13167c478bd9Sstevel@tonic-gate 		prev_verbose = Verbose;
13177c478bd9Sstevel@tonic-gate 		if (Debug == 0)
13187c478bd9Sstevel@tonic-gate 			Verbose = 0;
13197c478bd9Sstevel@tonic-gate 
1320*b5016cbbSstephh 		fme_reload_cfgdata(fmep);
1321*b5016cbbSstephh 
13227aec1d6eScindi 		lut_walk(fmep->eventtree, (lut_cb)clear_arrows, (void *)fmep);
13237aec1d6eScindi 		state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay);
13247c478bd9Sstevel@tonic-gate 
13257c478bd9Sstevel@tonic-gate 		fmep->peek = 0;
13267c478bd9Sstevel@tonic-gate 
13277c478bd9Sstevel@tonic-gate 		/* put verbose flag back */
13287c478bd9Sstevel@tonic-gate 		Verbose = prev_verbose;
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 		if (state != FME_DISPROVED) {
13317c478bd9Sstevel@tonic-gate 			/* found an FME that explains the ereport */
13327c478bd9Sstevel@tonic-gate 			matched++;
13337c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_NONL, "[");
13347c478bd9Sstevel@tonic-gate 			ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
13357c478bd9Sstevel@tonic-gate 			out(O_ALTFP, " explained by FME%d]", fmep->id);
13367c478bd9Sstevel@tonic-gate 
13377aec1d6eScindi 			if (pre_peek_nvp)
13387aec1d6eScindi 				nvlist_free(pre_peek_nvp);
13397aec1d6eScindi 
13407c478bd9Sstevel@tonic-gate 			if (ep->count == 1)
13417c478bd9Sstevel@tonic-gate 				serialize_observation(fmep, eventstring, ipp);
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 			if (ffep)
13447c478bd9Sstevel@tonic-gate 				fmd_case_add_ereport(hdl, fmep->fmcase, ffep);
13457c478bd9Sstevel@tonic-gate 
13467c478bd9Sstevel@tonic-gate 			stats_counter_bump(fmep->Rcount);
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate 			/* re-eval FME */
13497c478bd9Sstevel@tonic-gate 			fme_eval(fmep, ffep);
13507c478bd9Sstevel@tonic-gate 		} else {
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 			/* not a match, undo noting of observation */
1353*b5016cbbSstephh 			config_free(fmep->cfgdata);
1354*b5016cbbSstephh 			fmep->cfgdata = NULL;
13557c478bd9Sstevel@tonic-gate 			fmep->ecurrent = NULL;
13567c478bd9Sstevel@tonic-gate 			if (--ep->count == 0) {
13577c478bd9Sstevel@tonic-gate 				/* unlink it from observations */
13587c478bd9Sstevel@tonic-gate 				fmep->observations = ep->observations;
13597c478bd9Sstevel@tonic-gate 				ep->observations = NULL;
13607c478bd9Sstevel@tonic-gate 				nvlist_free(ep->nvp);
13617c478bd9Sstevel@tonic-gate 				ep->nvp = NULL;
13627aec1d6eScindi 			} else {
13637aec1d6eScindi 				nvlist_free(ep->nvp);
13647aec1d6eScindi 				ep->nvp = pre_peek_nvp;
13657c478bd9Sstevel@tonic-gate 			}
13667c478bd9Sstevel@tonic-gate 		}
13677c478bd9Sstevel@tonic-gate 	}
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 	if (matched)
13707c478bd9Sstevel@tonic-gate 		return;	/* explained by at least one existing FME */
13717c478bd9Sstevel@tonic-gate 
13727c478bd9Sstevel@tonic-gate 	/* clean up closed fmes */
13730cc1f05eSjrutt 	cfmep = ClosedFMEs;
13740cc1f05eSjrutt 	while (cfmep != NULL) {
13750cc1f05eSjrutt 		svfmep = cfmep->next;
13760cc1f05eSjrutt 		destroy_fme(cfmep);
13770cc1f05eSjrutt 		cfmep = svfmep;
13787c478bd9Sstevel@tonic-gate 	}
13797c478bd9Sstevel@tonic-gate 	ClosedFMEs = NULL;
1380*b5016cbbSstephh 	prune_propagations(eventstring, ipp);
13817c478bd9Sstevel@tonic-gate 
13820cc1f05eSjrutt 	if (ofmep) {
13830cc1f05eSjrutt 		out(O_ALTFP|O_NONL, "[");
13840cc1f05eSjrutt 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
13850cc1f05eSjrutt 		out(O_ALTFP, " ADDING TO OVERFLOW FME]");
13860cc1f05eSjrutt 		if (ffep)
13870cc1f05eSjrutt 			fmd_case_add_ereport(hdl, ofmep->fmcase, ffep);
13880cc1f05eSjrutt 
13890cc1f05eSjrutt 		return;
13900cc1f05eSjrutt 
13910cc1f05eSjrutt 	} else if (Max_fme && (Open_fme_count >= Max_fme)) {
13920cc1f05eSjrutt 		out(O_ALTFP|O_NONL, "[");
13930cc1f05eSjrutt 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
13940cc1f05eSjrutt 		out(O_ALTFP, " MAX OPEN FME REACHED]");
1395*b5016cbbSstephh 
1396*b5016cbbSstephh 		fmcase = fmd_case_open(hdl, NULL);
1397*b5016cbbSstephh 
13980cc1f05eSjrutt 		/* Create overflow fme */
1399*b5016cbbSstephh 		if ((fmep = newfme(eventstring, ipp, hdl, fmcase)) == NULL) {
14000cc1f05eSjrutt 			out(O_ALTFP|O_NONL, "[");
14010cc1f05eSjrutt 			ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
14020cc1f05eSjrutt 			out(O_ALTFP, " CANNOT OPEN OVERFLOW FME]");
1403*b5016cbbSstephh 			publish_undiagnosable(hdl, ffep, fmcase);
14040cc1f05eSjrutt 			return;
14050cc1f05eSjrutt 		}
14060cc1f05eSjrutt 
14070cc1f05eSjrutt 		Open_fme_count++;
14080cc1f05eSjrutt 
14090cc1f05eSjrutt 		init_fme_bufs(fmep);
14100cc1f05eSjrutt 		fmep->overflow = B_TRUE;
14110cc1f05eSjrutt 
14120cc1f05eSjrutt 		if (ffep)
14130cc1f05eSjrutt 			fmd_case_add_ereport(hdl, fmep->fmcase, ffep);
14140cc1f05eSjrutt 
14150cc1f05eSjrutt 		defect = fmd_nvl_create_fault(hdl, UNDIAGNOSABLE_DEFECT, 100,
14160cc1f05eSjrutt 		    NULL, NULL, NULL);
14170cc1f05eSjrutt 		(void) nvlist_add_string(defect, UNDIAG_REASON, UD_MAXFME);
14180cc1f05eSjrutt 		fmd_case_add_suspect(hdl, fmep->fmcase, defect);
14190cc1f05eSjrutt 		fmd_case_solve(hdl, fmep->fmcase);
14200cc1f05eSjrutt 		return;
14210cc1f05eSjrutt 	}
14220cc1f05eSjrutt 
1423*b5016cbbSstephh 	/* open a case */
1424*b5016cbbSstephh 	fmcase = fmd_case_open(hdl, NULL);
1425*b5016cbbSstephh 
14267c478bd9Sstevel@tonic-gate 	/* start a new FME */
1427*b5016cbbSstephh 	if ((fmep = newfme(eventstring, ipp, hdl, fmcase)) == NULL) {
14287c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "[");
14297c478bd9Sstevel@tonic-gate 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
14307c478bd9Sstevel@tonic-gate 		out(O_ALTFP, " CANNOT DIAGNOSE]");
1431*b5016cbbSstephh 		publish_undiagnosable(hdl, ffep, fmcase);
14327c478bd9Sstevel@tonic-gate 		return;
14337c478bd9Sstevel@tonic-gate 	}
14347c478bd9Sstevel@tonic-gate 
14350cc1f05eSjrutt 	Open_fme_count++;
14360cc1f05eSjrutt 
14377c478bd9Sstevel@tonic-gate 	init_fme_bufs(fmep);
14387c478bd9Sstevel@tonic-gate 
14397c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_NONL, "[");
14407c478bd9Sstevel@tonic-gate 	ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
14417c478bd9Sstevel@tonic-gate 	out(O_ALTFP, " created FME%d, case %s]", fmep->id,
14427c478bd9Sstevel@tonic-gate 	    fmd_case_uuid(hdl, fmep->fmcase));
14437c478bd9Sstevel@tonic-gate 
14447c478bd9Sstevel@tonic-gate 	ep = fmep->e0;
14457c478bd9Sstevel@tonic-gate 	ASSERT(ep != NULL);
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate 	/* note observation */
14487c478bd9Sstevel@tonic-gate 	fmep->ecurrent = ep;
14497c478bd9Sstevel@tonic-gate 	if (ep->count++ == 0) {
14507c478bd9Sstevel@tonic-gate 		/* link it into list of observations seen */
14517c478bd9Sstevel@tonic-gate 		ep->observations = fmep->observations;
14527c478bd9Sstevel@tonic-gate 		fmep->observations = ep;
14537c478bd9Sstevel@tonic-gate 		ep->nvp = evnv_dupnvl(nvl);
14547c478bd9Sstevel@tonic-gate 		serialize_observation(fmep, eventstring, ipp);
14557aec1d6eScindi 	} else {
14567aec1d6eScindi 		/* new payload overrides any previous */
14577aec1d6eScindi 		nvlist_free(ep->nvp);
14587aec1d6eScindi 		ep->nvp = evnv_dupnvl(nvl);
14597c478bd9Sstevel@tonic-gate 	}
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Rcount);
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	if (ffep) {
14647c478bd9Sstevel@tonic-gate 		fmd_case_add_ereport(hdl, fmep->fmcase, ffep);
14657c478bd9Sstevel@tonic-gate 		fmd_case_setprincipal(hdl, fmep->fmcase, ffep);
14667c478bd9Sstevel@tonic-gate 		fmep->e0r = ffep;
14677c478bd9Sstevel@tonic-gate 	}
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 	/* give the diagnosis algorithm a shot at the new FME state */
14707c478bd9Sstevel@tonic-gate 	fme_eval(fmep, ffep);
14717c478bd9Sstevel@tonic-gate }
14727c478bd9Sstevel@tonic-gate 
14737c478bd9Sstevel@tonic-gate void
14747c478bd9Sstevel@tonic-gate fme_status(int flags)
14757c478bd9Sstevel@tonic-gate {
14767c478bd9Sstevel@tonic-gate 	struct fme *fmep;
14777c478bd9Sstevel@tonic-gate 
14787c478bd9Sstevel@tonic-gate 	if (FMElist == NULL) {
14797c478bd9Sstevel@tonic-gate 		out(flags, "No fault management exercises underway.");
14807c478bd9Sstevel@tonic-gate 		return;
14817c478bd9Sstevel@tonic-gate 	}
14827c478bd9Sstevel@tonic-gate 
14837c478bd9Sstevel@tonic-gate 	for (fmep = FMElist; fmep; fmep = fmep->next)
14847c478bd9Sstevel@tonic-gate 		fme_print(flags, fmep);
14857c478bd9Sstevel@tonic-gate }
14867c478bd9Sstevel@tonic-gate 
14877c478bd9Sstevel@tonic-gate /*
14887c478bd9Sstevel@tonic-gate  * "indent" routines used mostly for nicely formatted debug output, but also
14897c478bd9Sstevel@tonic-gate  * for sanity checking for infinite recursion bugs.
14907c478bd9Sstevel@tonic-gate  */
14917c478bd9Sstevel@tonic-gate 
14927c478bd9Sstevel@tonic-gate #define	MAX_INDENT 1024
14937c478bd9Sstevel@tonic-gate static const char *indent_s[MAX_INDENT];
14947c478bd9Sstevel@tonic-gate static int current_indent;
14957c478bd9Sstevel@tonic-gate 
14967c478bd9Sstevel@tonic-gate static void
14977c478bd9Sstevel@tonic-gate indent_push(const char *s)
14987c478bd9Sstevel@tonic-gate {
14997c478bd9Sstevel@tonic-gate 	if (current_indent < MAX_INDENT)
15007c478bd9Sstevel@tonic-gate 		indent_s[current_indent++] = s;
15017c478bd9Sstevel@tonic-gate 	else
15027c478bd9Sstevel@tonic-gate 		out(O_DIE, "unexpected recursion depth (%d)", current_indent);
15037c478bd9Sstevel@tonic-gate }
15047c478bd9Sstevel@tonic-gate 
15057c478bd9Sstevel@tonic-gate static void
15067c478bd9Sstevel@tonic-gate indent_set(const char *s)
15077c478bd9Sstevel@tonic-gate {
15087c478bd9Sstevel@tonic-gate 	current_indent = 0;
15097c478bd9Sstevel@tonic-gate 	indent_push(s);
15107c478bd9Sstevel@tonic-gate }
15117c478bd9Sstevel@tonic-gate 
15127c478bd9Sstevel@tonic-gate static void
15137c478bd9Sstevel@tonic-gate indent_pop(void)
15147c478bd9Sstevel@tonic-gate {
15157c478bd9Sstevel@tonic-gate 	if (current_indent > 0)
15167c478bd9Sstevel@tonic-gate 		current_indent--;
15177c478bd9Sstevel@tonic-gate 	else
15187c478bd9Sstevel@tonic-gate 		out(O_DIE, "recursion underflow");
15197c478bd9Sstevel@tonic-gate }
15207c478bd9Sstevel@tonic-gate 
15217c478bd9Sstevel@tonic-gate static void
15227c478bd9Sstevel@tonic-gate indent(void)
15237c478bd9Sstevel@tonic-gate {
15247c478bd9Sstevel@tonic-gate 	int i;
15257c478bd9Sstevel@tonic-gate 	if (!Verbose)
15267c478bd9Sstevel@tonic-gate 		return;
15277c478bd9Sstevel@tonic-gate 	for (i = 0; i < current_indent; i++)
15287c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, indent_s[i]);
15297c478bd9Sstevel@tonic-gate }
15307c478bd9Sstevel@tonic-gate 
15317c478bd9Sstevel@tonic-gate #define	SLNEW		1
15327c478bd9Sstevel@tonic-gate #define	SLCHANGED	2
15337c478bd9Sstevel@tonic-gate #define	SLWAIT		3
15347c478bd9Sstevel@tonic-gate #define	SLDISPROVED	4
15357c478bd9Sstevel@tonic-gate 
15367c478bd9Sstevel@tonic-gate static void
15377c478bd9Sstevel@tonic-gate print_suspects(int circumstance, struct fme *fmep)
15387c478bd9Sstevel@tonic-gate {
15397c478bd9Sstevel@tonic-gate 	struct event *ep;
15407c478bd9Sstevel@tonic-gate 
15417c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_NONL, "[");
15427c478bd9Sstevel@tonic-gate 	if (circumstance == SLCHANGED) {
15437c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "FME%d diagnosis changed. state: %s, "
15447c478bd9Sstevel@tonic-gate 		    "suspect list:", fmep->id, fme_state2str(fmep->state));
15457c478bd9Sstevel@tonic-gate 	} else if (circumstance == SLWAIT) {
1546*b5016cbbSstephh 		out(O_ALTFP|O_NONL, "FME%d set wait timer %ld ", fmep->id,
1547*b5016cbbSstephh 		    fmep->timer);
15487c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_NONL, &fmep->wull);
15497c478bd9Sstevel@tonic-gate 	} else if (circumstance == SLDISPROVED) {
15507c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "FME%d DIAGNOSIS UNKNOWN", fmep->id);
15517c478bd9Sstevel@tonic-gate 	} else {
15527c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "FME%d DIAGNOSIS PRODUCED:", fmep->id);
15537c478bd9Sstevel@tonic-gate 	}
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate 	if (circumstance == SLWAIT || circumstance == SLDISPROVED) {
15567c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "]");
15577c478bd9Sstevel@tonic-gate 		return;
15587c478bd9Sstevel@tonic-gate 	}
15597c478bd9Sstevel@tonic-gate 
15607c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = ep->suspects) {
15617c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, " ");
15627c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_NONL, ep);
15637c478bd9Sstevel@tonic-gate 	}
15647c478bd9Sstevel@tonic-gate 	out(O_ALTFP, "]");
15657c478bd9Sstevel@tonic-gate }
15667c478bd9Sstevel@tonic-gate 
15677c478bd9Sstevel@tonic-gate static struct node *
15687c478bd9Sstevel@tonic-gate eventprop_lookup(struct event *ep, const char *propname)
15697c478bd9Sstevel@tonic-gate {
15707c478bd9Sstevel@tonic-gate 	return (lut_lookup(ep->props, (void *)propname, NULL));
15717c478bd9Sstevel@tonic-gate }
15727c478bd9Sstevel@tonic-gate 
15737c478bd9Sstevel@tonic-gate #define	MAXDIGITIDX	23
15747c478bd9Sstevel@tonic-gate static char numbuf[MAXDIGITIDX + 1];
15757c478bd9Sstevel@tonic-gate 
15767c478bd9Sstevel@tonic-gate static int
15777c478bd9Sstevel@tonic-gate node2uint(struct node *n, uint_t *valp)
15787c478bd9Sstevel@tonic-gate {
15797c478bd9Sstevel@tonic-gate 	struct evalue value;
15807c478bd9Sstevel@tonic-gate 	struct lut *globals = NULL;
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate 	if (n == NULL)
15837c478bd9Sstevel@tonic-gate 		return (1);
15847c478bd9Sstevel@tonic-gate 
15857c478bd9Sstevel@tonic-gate 	/*
15867c478bd9Sstevel@tonic-gate 	 * check value.v since we are being asked to convert an unsigned
15877c478bd9Sstevel@tonic-gate 	 * long long int to an unsigned int
15887c478bd9Sstevel@tonic-gate 	 */
15897c478bd9Sstevel@tonic-gate 	if (! eval_expr(n, NULL, NULL, &globals, NULL, NULL, 0, &value) ||
15907c478bd9Sstevel@tonic-gate 	    value.t != UINT64 || value.v > (1ULL << 32))
15917c478bd9Sstevel@tonic-gate 		return (1);
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 	*valp = (uint_t)value.v;
15947c478bd9Sstevel@tonic-gate 
15957c478bd9Sstevel@tonic-gate 	return (0);
15967c478bd9Sstevel@tonic-gate }
15977c478bd9Sstevel@tonic-gate 
15987c478bd9Sstevel@tonic-gate static nvlist_t *
15997c478bd9Sstevel@tonic-gate node2fmri(struct node *n)
16007c478bd9Sstevel@tonic-gate {
16017c478bd9Sstevel@tonic-gate 	nvlist_t **pa, *f, *p;
16027c478bd9Sstevel@tonic-gate 	struct node *nc;
16037c478bd9Sstevel@tonic-gate 	uint_t depth = 0;
16047c478bd9Sstevel@tonic-gate 	char *numstr, *nullbyte;
16057c478bd9Sstevel@tonic-gate 	char *failure;
16067c478bd9Sstevel@tonic-gate 	int err, i;
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	/* XXX do we need to be able to handle a non-T_NAME node? */
16097c478bd9Sstevel@tonic-gate 	if (n == NULL || n->t != T_NAME)
16107c478bd9Sstevel@tonic-gate 		return (NULL);
16117c478bd9Sstevel@tonic-gate 
16127c478bd9Sstevel@tonic-gate 	for (nc = n; nc != NULL; nc = nc->u.name.next) {
16137c478bd9Sstevel@tonic-gate 		if (nc->u.name.child == NULL || nc->u.name.child->t != T_NUM)
16147c478bd9Sstevel@tonic-gate 			break;
16157c478bd9Sstevel@tonic-gate 		depth++;
16167c478bd9Sstevel@tonic-gate 	}
16177c478bd9Sstevel@tonic-gate 
16187c478bd9Sstevel@tonic-gate 	if (nc != NULL) {
16197c478bd9Sstevel@tonic-gate 		/* We bailed early, something went wrong */
16207c478bd9Sstevel@tonic-gate 		return (NULL);
16217c478bd9Sstevel@tonic-gate 	}
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 	if ((err = nvlist_xalloc(&f, NV_UNIQUE_NAME, &Eft_nv_hdl)) != 0)
16247c478bd9Sstevel@tonic-gate 		out(O_DIE|O_SYS, "alloc of fmri nvl failed");
16257c478bd9Sstevel@tonic-gate 	pa = alloca(depth * sizeof (nvlist_t *));
16267c478bd9Sstevel@tonic-gate 	for (i = 0; i < depth; i++)
16277c478bd9Sstevel@tonic-gate 		pa[i] = NULL;
16287c478bd9Sstevel@tonic-gate 
16297c478bd9Sstevel@tonic-gate 	err = nvlist_add_string(f, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC);
16307c478bd9Sstevel@tonic-gate 	err |= nvlist_add_uint8(f, FM_VERSION, FM_HC_SCHEME_VERSION);
16317c478bd9Sstevel@tonic-gate 	err |= nvlist_add_string(f, FM_FMRI_HC_ROOT, "");
16327c478bd9Sstevel@tonic-gate 	err |= nvlist_add_uint32(f, FM_FMRI_HC_LIST_SZ, depth);
16337c478bd9Sstevel@tonic-gate 	if (err != 0) {
16347c478bd9Sstevel@tonic-gate 		failure = "basic construction of FMRI failed";
16357c478bd9Sstevel@tonic-gate 		goto boom;
16367c478bd9Sstevel@tonic-gate 	}
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 	numbuf[MAXDIGITIDX] = '\0';
16397c478bd9Sstevel@tonic-gate 	nullbyte = &numbuf[MAXDIGITIDX];
16407c478bd9Sstevel@tonic-gate 	i = 0;
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 	for (nc = n; nc != NULL; nc = nc->u.name.next) {
16437c478bd9Sstevel@tonic-gate 		err = nvlist_xalloc(&p, NV_UNIQUE_NAME, &Eft_nv_hdl);
16447c478bd9Sstevel@tonic-gate 		if (err != 0) {
16457c478bd9Sstevel@tonic-gate 			failure = "alloc of an hc-pair failed";
16467c478bd9Sstevel@tonic-gate 			goto boom;
16477c478bd9Sstevel@tonic-gate 		}
16487c478bd9Sstevel@tonic-gate 		err = nvlist_add_string(p, FM_FMRI_HC_NAME, nc->u.name.s);
16497c478bd9Sstevel@tonic-gate 		numstr = ulltostr(nc->u.name.child->u.ull, nullbyte);
16507c478bd9Sstevel@tonic-gate 		err |= nvlist_add_string(p, FM_FMRI_HC_ID, numstr);
16517c478bd9Sstevel@tonic-gate 		if (err != 0) {
16527c478bd9Sstevel@tonic-gate 			failure = "construction of an hc-pair failed";
16537c478bd9Sstevel@tonic-gate 			goto boom;
16547c478bd9Sstevel@tonic-gate 		}
16557c478bd9Sstevel@tonic-gate 		pa[i++] = p;
16567c478bd9Sstevel@tonic-gate 	}
16577c478bd9Sstevel@tonic-gate 
16587c478bd9Sstevel@tonic-gate 	err = nvlist_add_nvlist_array(f, FM_FMRI_HC_LIST, pa, depth);
16597c478bd9Sstevel@tonic-gate 	if (err == 0) {
16607c478bd9Sstevel@tonic-gate 		for (i = 0; i < depth; i++)
16617c478bd9Sstevel@tonic-gate 			if (pa[i] != NULL)
16627c478bd9Sstevel@tonic-gate 				nvlist_free(pa[i]);
16637c478bd9Sstevel@tonic-gate 		return (f);
16647c478bd9Sstevel@tonic-gate 	}
16657c478bd9Sstevel@tonic-gate 	failure = "addition of hc-pair array to FMRI failed";
16667c478bd9Sstevel@tonic-gate 
16677c478bd9Sstevel@tonic-gate boom:
16687c478bd9Sstevel@tonic-gate 	for (i = 0; i < depth; i++)
16697c478bd9Sstevel@tonic-gate 		if (pa[i] != NULL)
16707c478bd9Sstevel@tonic-gate 			nvlist_free(pa[i]);
16717c478bd9Sstevel@tonic-gate 	nvlist_free(f);
16727c478bd9Sstevel@tonic-gate 	out(O_DIE, "%s", failure);
16737c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
167480ab886dSwesolows 	return (NULL);
16757c478bd9Sstevel@tonic-gate }
16767c478bd9Sstevel@tonic-gate 
16777c478bd9Sstevel@tonic-gate static uint_t
16787c478bd9Sstevel@tonic-gate avg(uint_t sum, uint_t cnt)
16797c478bd9Sstevel@tonic-gate {
16807c478bd9Sstevel@tonic-gate 	unsigned long long s = sum * 10;
16817c478bd9Sstevel@tonic-gate 
16827c478bd9Sstevel@tonic-gate 	return ((s / cnt / 10) + (((s / cnt % 10) >= 5) ? 1 : 0));
16837c478bd9Sstevel@tonic-gate }
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate static uint8_t
16867c478bd9Sstevel@tonic-gate percentof(uint_t part, uint_t whole)
16877c478bd9Sstevel@tonic-gate {
16887c478bd9Sstevel@tonic-gate 	unsigned long long p = part * 1000;
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate 	return ((p / whole / 10) + (((p / whole % 10) >= 5) ? 1 : 0));
16917c478bd9Sstevel@tonic-gate }
16927c478bd9Sstevel@tonic-gate 
169380ab886dSwesolows struct rsl {
16947c478bd9Sstevel@tonic-gate 	struct event *suspect;
16957c478bd9Sstevel@tonic-gate 	nvlist_t *asru;
16967c478bd9Sstevel@tonic-gate 	nvlist_t *fru;
16977c478bd9Sstevel@tonic-gate 	nvlist_t *rsrc;
16987c478bd9Sstevel@tonic-gate };
16997c478bd9Sstevel@tonic-gate 
17007c478bd9Sstevel@tonic-gate /*
17017c478bd9Sstevel@tonic-gate  *  rslfree -- free internal members of struct rsl not expected to be
17027c478bd9Sstevel@tonic-gate  *	freed elsewhere.
17037c478bd9Sstevel@tonic-gate  */
17047c478bd9Sstevel@tonic-gate static void
17057c478bd9Sstevel@tonic-gate rslfree(struct rsl *freeme)
17067c478bd9Sstevel@tonic-gate {
17077c478bd9Sstevel@tonic-gate 	if (freeme->asru != NULL)
17087c478bd9Sstevel@tonic-gate 		nvlist_free(freeme->asru);
17097c478bd9Sstevel@tonic-gate 	if (freeme->fru != NULL)
17107c478bd9Sstevel@tonic-gate 		nvlist_free(freeme->fru);
17117c478bd9Sstevel@tonic-gate 	if (freeme->rsrc != NULL && freeme->rsrc != freeme->asru)
17127c478bd9Sstevel@tonic-gate 		nvlist_free(freeme->rsrc);
17137c478bd9Sstevel@tonic-gate }
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate /*
17167c478bd9Sstevel@tonic-gate  *  rslcmp -- compare two rsl structures.  Use the following
17177c478bd9Sstevel@tonic-gate  *	comparisons to establish cardinality:
17187c478bd9Sstevel@tonic-gate  *
17197c478bd9Sstevel@tonic-gate  *	1. Name of the suspect's class. (simple strcmp)
17207c478bd9Sstevel@tonic-gate  *	2. Name of the suspect's ASRU. (trickier, since nvlist)
17217c478bd9Sstevel@tonic-gate  *
17227c478bd9Sstevel@tonic-gate  */
17237c478bd9Sstevel@tonic-gate static int
17247c478bd9Sstevel@tonic-gate rslcmp(const void *a, const void *b)
17257c478bd9Sstevel@tonic-gate {
17267c478bd9Sstevel@tonic-gate 	struct rsl *r1 = (struct rsl *)a;
17277c478bd9Sstevel@tonic-gate 	struct rsl *r2 = (struct rsl *)b;
17287c478bd9Sstevel@tonic-gate 	int rv;
17297c478bd9Sstevel@tonic-gate 
17307c478bd9Sstevel@tonic-gate 	rv = strcmp(r1->suspect->enode->u.event.ename->u.name.s,
17317c478bd9Sstevel@tonic-gate 	    r2->suspect->enode->u.event.ename->u.name.s);
17327c478bd9Sstevel@tonic-gate 	if (rv != 0)
17337c478bd9Sstevel@tonic-gate 		return (rv);
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 	if (r1->asru == NULL && r2->asru == NULL)
17367c478bd9Sstevel@tonic-gate 		return (0);
17377c478bd9Sstevel@tonic-gate 	if (r1->asru == NULL)
17387c478bd9Sstevel@tonic-gate 		return (-1);
17397c478bd9Sstevel@tonic-gate 	if (r2->asru == NULL)
17407c478bd9Sstevel@tonic-gate 		return (1);
17417c478bd9Sstevel@tonic-gate 	return (evnv_cmpnvl(r1->asru, r2->asru, 0));
17427c478bd9Sstevel@tonic-gate }
17437c478bd9Sstevel@tonic-gate 
17447c478bd9Sstevel@tonic-gate /*
17457c478bd9Sstevel@tonic-gate  *  rsluniq -- given an array of rsl structures, seek out and "remove"
17467c478bd9Sstevel@tonic-gate  *	any duplicates.  Dups are "remove"d by NULLing the suspect pointer
17477c478bd9Sstevel@tonic-gate  *	of the array element.  Removal also means updating the number of
17487c478bd9Sstevel@tonic-gate  *	problems and the number of problems which are not faults.  User
17497c478bd9Sstevel@tonic-gate  *	provides the first and last element pointers.
17507c478bd9Sstevel@tonic-gate  */
17517c478bd9Sstevel@tonic-gate static void
17527c478bd9Sstevel@tonic-gate rsluniq(struct rsl *first, struct rsl *last, int *nprobs, int *nnonf)
17537c478bd9Sstevel@tonic-gate {
17547c478bd9Sstevel@tonic-gate 	struct rsl *cr;
17557c478bd9Sstevel@tonic-gate 
17567c478bd9Sstevel@tonic-gate 	if (*nprobs == 1)
17577c478bd9Sstevel@tonic-gate 		return;
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate 	/*
17607c478bd9Sstevel@tonic-gate 	 *  At this point, we only expect duplicate defects.
17617c478bd9Sstevel@tonic-gate 	 *  Eversholt's diagnosis algorithm prevents duplicate
17627c478bd9Sstevel@tonic-gate 	 *  suspects, but we rewrite defects in the platform code after
17637c478bd9Sstevel@tonic-gate 	 *  the diagnosis is made, and that can introduce new
17647c478bd9Sstevel@tonic-gate 	 *  duplicates.
17657c478bd9Sstevel@tonic-gate 	 */
17667c478bd9Sstevel@tonic-gate 	while (first <= last) {
17677c478bd9Sstevel@tonic-gate 		if (first->suspect == NULL || !is_defect(first->suspect->t)) {
17687c478bd9Sstevel@tonic-gate 			first++;
17697c478bd9Sstevel@tonic-gate 			continue;
17707c478bd9Sstevel@tonic-gate 		}
17717c478bd9Sstevel@tonic-gate 		cr = first + 1;
17727c478bd9Sstevel@tonic-gate 		while (cr <= last) {
17737c478bd9Sstevel@tonic-gate 			if (is_defect(first->suspect->t)) {
17747c478bd9Sstevel@tonic-gate 				if (rslcmp(first, cr) == 0) {
17757c478bd9Sstevel@tonic-gate 					cr->suspect = NULL;
17767c478bd9Sstevel@tonic-gate 					rslfree(cr);
17777c478bd9Sstevel@tonic-gate 					(*nprobs)--;
17787c478bd9Sstevel@tonic-gate 					(*nnonf)--;
17797c478bd9Sstevel@tonic-gate 				}
17807c478bd9Sstevel@tonic-gate 			}
17817c478bd9Sstevel@tonic-gate 			/*
17827c478bd9Sstevel@tonic-gate 			 * assume all defects are in order after our
17837c478bd9Sstevel@tonic-gate 			 * sort and short circuit here with "else break" ?
17847c478bd9Sstevel@tonic-gate 			 */
17857c478bd9Sstevel@tonic-gate 			cr++;
17867c478bd9Sstevel@tonic-gate 		}
17877c478bd9Sstevel@tonic-gate 		first++;
17887c478bd9Sstevel@tonic-gate 	}
17897c478bd9Sstevel@tonic-gate }
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate /*
17927c478bd9Sstevel@tonic-gate  * get_resources -- for a given suspect, determine what ASRU, FRU and
17937c478bd9Sstevel@tonic-gate  *     RSRC nvlists should be advertised in the final suspect list.
17947c478bd9Sstevel@tonic-gate  */
17957c478bd9Sstevel@tonic-gate void
17967c478bd9Sstevel@tonic-gate get_resources(struct event *sp, struct rsl *rsrcs, struct config *croot)
17977c478bd9Sstevel@tonic-gate {
17987c478bd9Sstevel@tonic-gate 	struct node *asrudef, *frudef;
17997c478bd9Sstevel@tonic-gate 	nvlist_t *asru, *fru;
18007c478bd9Sstevel@tonic-gate 	nvlist_t *rsrc = NULL;
18017c478bd9Sstevel@tonic-gate 	char *pathstr;
18027c478bd9Sstevel@tonic-gate 
18037c478bd9Sstevel@tonic-gate 	/*
18047c478bd9Sstevel@tonic-gate 	 * First find any ASRU and/or FRU defined in the
18057c478bd9Sstevel@tonic-gate 	 * initial fault tree.
18067c478bd9Sstevel@tonic-gate 	 */
18077c478bd9Sstevel@tonic-gate 	asrudef = eventprop_lookup(sp, L_ASRU);
18087c478bd9Sstevel@tonic-gate 	frudef = eventprop_lookup(sp, L_FRU);
18097c478bd9Sstevel@tonic-gate 
18107c478bd9Sstevel@tonic-gate 	/*
18117c478bd9Sstevel@tonic-gate 	 * Create FMRIs based on those definitions
18127c478bd9Sstevel@tonic-gate 	 */
18137c478bd9Sstevel@tonic-gate 	asru = node2fmri(asrudef);
18147c478bd9Sstevel@tonic-gate 	fru = node2fmri(frudef);
18157c478bd9Sstevel@tonic-gate 	pathstr = ipath2str(NULL, sp->ipp);
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 	/*
18187c478bd9Sstevel@tonic-gate 	 * Allow for platform translations of the FMRIs
18197c478bd9Sstevel@tonic-gate 	 */
18207c478bd9Sstevel@tonic-gate 	platform_units_translate(is_defect(sp->t), croot, &asru, &fru, &rsrc,
18217c478bd9Sstevel@tonic-gate 	    pathstr);
18227c478bd9Sstevel@tonic-gate 
18237c478bd9Sstevel@tonic-gate 	FREE(pathstr);
18247c478bd9Sstevel@tonic-gate 	rsrcs->suspect = sp;
18257c478bd9Sstevel@tonic-gate 	rsrcs->asru = asru;
18267c478bd9Sstevel@tonic-gate 	rsrcs->fru = fru;
18277c478bd9Sstevel@tonic-gate 	rsrcs->rsrc = rsrc;
18287c478bd9Sstevel@tonic-gate }
18297c478bd9Sstevel@tonic-gate 
18307c478bd9Sstevel@tonic-gate /*
18317c478bd9Sstevel@tonic-gate  * trim_suspects -- prior to publishing, we may need to remove some
18327c478bd9Sstevel@tonic-gate  *    suspects from the list.  If we're auto-closing upsets, we don't
18337c478bd9Sstevel@tonic-gate  *    want any of those in the published list.  If the ASRUs for multiple
18347c478bd9Sstevel@tonic-gate  *    defects resolve to the same ASRU (driver) we only want to publish
18357c478bd9Sstevel@tonic-gate  *    that as a single suspect.
18367c478bd9Sstevel@tonic-gate  */
18377c478bd9Sstevel@tonic-gate static void
18387c478bd9Sstevel@tonic-gate trim_suspects(struct fme *fmep, boolean_t no_upsets, struct rsl **begin,
18397c478bd9Sstevel@tonic-gate     struct rsl **end)
18407c478bd9Sstevel@tonic-gate {
18417c478bd9Sstevel@tonic-gate 	struct event *ep;
18427c478bd9Sstevel@tonic-gate 	struct rsl *rp;
18437c478bd9Sstevel@tonic-gate 	int rpcnt;
18447c478bd9Sstevel@tonic-gate 
18457c478bd9Sstevel@tonic-gate 	/*
18467c478bd9Sstevel@tonic-gate 	 * First save the suspects in the psuspects, then copy back
18477c478bd9Sstevel@tonic-gate 	 * only the ones we wish to retain.  This resets nsuspects to
18487c478bd9Sstevel@tonic-gate 	 * zero.
18497c478bd9Sstevel@tonic-gate 	 */
18507c478bd9Sstevel@tonic-gate 	rpcnt = fmep->nsuspects;
18517c478bd9Sstevel@tonic-gate 	save_suspects(fmep);
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 	/*
18547c478bd9Sstevel@tonic-gate 	 * allocate an array of resource pointers for the suspects.
18557c478bd9Sstevel@tonic-gate 	 * We may end up using less than the full allocation, but this
18567c478bd9Sstevel@tonic-gate 	 * is a very short-lived array.  publish_suspects() will free
18577c478bd9Sstevel@tonic-gate 	 * this array when it's done using it.
18587c478bd9Sstevel@tonic-gate 	 */
18597c478bd9Sstevel@tonic-gate 	rp = *begin = MALLOC(rpcnt * sizeof (struct rsl));
18607c478bd9Sstevel@tonic-gate 	bzero(rp, rpcnt * sizeof (struct rsl));
18617c478bd9Sstevel@tonic-gate 
18627c478bd9Sstevel@tonic-gate 	/* first pass, remove any unwanted upsets and populate our array */
18637c478bd9Sstevel@tonic-gate 	for (ep = fmep->psuspects; ep; ep = ep->psuspects) {
18647c478bd9Sstevel@tonic-gate 		if (no_upsets && is_upset(ep->t))
18657c478bd9Sstevel@tonic-gate 			continue;
18667c478bd9Sstevel@tonic-gate 		get_resources(ep, rp, fmep->cfgdata->cooked);
18677c478bd9Sstevel@tonic-gate 		rp++;
18687c478bd9Sstevel@tonic-gate 		fmep->nsuspects++;
18697c478bd9Sstevel@tonic-gate 		if (!is_fault(ep->t))
18707c478bd9Sstevel@tonic-gate 			fmep->nonfault++;
18717c478bd9Sstevel@tonic-gate 	}
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate 	/* if all we had was unwanted upsets, we're done */
18747c478bd9Sstevel@tonic-gate 	if (fmep->nsuspects == 0)
18757c478bd9Sstevel@tonic-gate 		return;
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 	*end = rp - 1;
18787c478bd9Sstevel@tonic-gate 
18797c478bd9Sstevel@tonic-gate 	/* sort the array */
18807c478bd9Sstevel@tonic-gate 	qsort(*begin, fmep->nsuspects, sizeof (struct rsl), rslcmp);
18817c478bd9Sstevel@tonic-gate 	rsluniq(*begin, *end, &fmep->nsuspects, &fmep->nonfault);
18827c478bd9Sstevel@tonic-gate }
18837c478bd9Sstevel@tonic-gate 
18847aec1d6eScindi /*
18857aec1d6eScindi  * addpayloadprop -- add a payload prop to a problem
18867aec1d6eScindi  */
18877aec1d6eScindi static void
18887aec1d6eScindi addpayloadprop(const char *lhs, struct evalue *rhs, nvlist_t *fault)
18897aec1d6eScindi {
18907aec1d6eScindi 	ASSERT(fault != NULL);
18917aec1d6eScindi 	ASSERT(lhs != NULL);
18927aec1d6eScindi 	ASSERT(rhs != NULL);
18937aec1d6eScindi 
18947aec1d6eScindi 	if (rhs->t == UINT64) {
18957aec1d6eScindi 		out(O_ALTFP|O_VERB2, "addpayloadprop: %s=%llu", lhs, rhs->v);
18967aec1d6eScindi 
18977aec1d6eScindi 		if (nvlist_add_uint64(fault, lhs, rhs->v) != 0)
18987aec1d6eScindi 			out(O_DIE,
18997aec1d6eScindi 			    "cannot add payloadprop \"%s\" to fault", lhs);
19007aec1d6eScindi 	} else {
19017aec1d6eScindi 		out(O_ALTFP|O_VERB2, "addpayloadprop: %s=\"%s\"",
190280ab886dSwesolows 		    lhs, (char *)(uintptr_t)rhs->v);
19037aec1d6eScindi 
190480ab886dSwesolows 		if (nvlist_add_string(fault, lhs, (char *)(uintptr_t)rhs->v) !=
190580ab886dSwesolows 		    0)
19067aec1d6eScindi 			out(O_DIE,
19077aec1d6eScindi 			    "cannot add payloadprop \"%s\" to fault", lhs);
19087aec1d6eScindi 	}
19097aec1d6eScindi }
19107aec1d6eScindi 
19117aec1d6eScindi static char *Istatbuf;
19127aec1d6eScindi static char *Istatbufptr;
19137aec1d6eScindi static int Istatsz;
19147aec1d6eScindi 
19157aec1d6eScindi /*
19167aec1d6eScindi  * istataddsize -- calculate size of istat and add it to Istatsz
19177aec1d6eScindi  */
19187aec1d6eScindi /*ARGSUSED2*/
19197aec1d6eScindi static void
19207aec1d6eScindi istataddsize(const struct istat_entry *lhs, struct stats *rhs, void *arg)
19217aec1d6eScindi {
19227aec1d6eScindi 	int val;
19237aec1d6eScindi 
19247aec1d6eScindi 	ASSERT(lhs != NULL);
19257aec1d6eScindi 	ASSERT(rhs != NULL);
19267aec1d6eScindi 
19277aec1d6eScindi 	if ((val = stats_counter_value(rhs)) == 0)
19287aec1d6eScindi 		return;	/* skip zero-valued stats */
19297aec1d6eScindi 
19307aec1d6eScindi 	/* count up the size of the stat name */
19317aec1d6eScindi 	Istatsz += ipath2strlen(lhs->ename, lhs->ipath);
19327aec1d6eScindi 	Istatsz++;	/* for the trailing NULL byte */
19337aec1d6eScindi 
19347aec1d6eScindi 	/* count up the size of the stat value */
19357aec1d6eScindi 	Istatsz += snprintf(NULL, 0, "%d", val);
19367aec1d6eScindi 	Istatsz++;	/* for the trailing NULL byte */
19377aec1d6eScindi }
19387aec1d6eScindi 
19397aec1d6eScindi /*
19407aec1d6eScindi  * istat2str -- serialize an istat, writing result to *Istatbufptr
19417aec1d6eScindi  */
19427aec1d6eScindi /*ARGSUSED2*/
19437aec1d6eScindi static void
19447aec1d6eScindi istat2str(const struct istat_entry *lhs, struct stats *rhs, void *arg)
19457aec1d6eScindi {
19467aec1d6eScindi 	char *str;
19477aec1d6eScindi 	int len;
19487aec1d6eScindi 	int val;
19497aec1d6eScindi 
19507aec1d6eScindi 	ASSERT(lhs != NULL);
19517aec1d6eScindi 	ASSERT(rhs != NULL);
19527aec1d6eScindi 
19537aec1d6eScindi 	if ((val = stats_counter_value(rhs)) == 0)
19547aec1d6eScindi 		return;	/* skip zero-valued stats */
19557aec1d6eScindi 
19567aec1d6eScindi 	/* serialize the stat name */
19577aec1d6eScindi 	str = ipath2str(lhs->ename, lhs->ipath);
19587aec1d6eScindi 	len = strlen(str);
19597aec1d6eScindi 
19607aec1d6eScindi 	ASSERT(Istatbufptr + len + 1 < &Istatbuf[Istatsz]);
19617aec1d6eScindi 	(void) strlcpy(Istatbufptr, str, &Istatbuf[Istatsz] - Istatbufptr);
19627aec1d6eScindi 	Istatbufptr += len;
19637aec1d6eScindi 	FREE(str);
19647aec1d6eScindi 	*Istatbufptr++ = '\0';
19657aec1d6eScindi 
19667aec1d6eScindi 	/* serialize the stat value */
19677aec1d6eScindi 	Istatbufptr += snprintf(Istatbufptr, &Istatbuf[Istatsz] - Istatbufptr,
19687aec1d6eScindi 	    "%d", val);
19697aec1d6eScindi 	*Istatbufptr++ = '\0';
19707aec1d6eScindi 
19717aec1d6eScindi 	ASSERT(Istatbufptr <= &Istatbuf[Istatsz]);
19727aec1d6eScindi }
19737aec1d6eScindi 
19747aec1d6eScindi void
19757aec1d6eScindi istat_save()
19767aec1d6eScindi {
19777aec1d6eScindi 	if (Istat_need_save == 0)
19787aec1d6eScindi 		return;
19797aec1d6eScindi 
19807aec1d6eScindi 	/* figure out how big the serialzed info is */
19817aec1d6eScindi 	Istatsz = 0;
19827aec1d6eScindi 	lut_walk(Istats, (lut_cb)istataddsize, NULL);
19837aec1d6eScindi 
19847aec1d6eScindi 	if (Istatsz == 0) {
19857aec1d6eScindi 		/* no stats to save */
19867aec1d6eScindi 		fmd_buf_destroy(Hdl, NULL, WOBUF_ISTATS);
19877aec1d6eScindi 		return;
19887aec1d6eScindi 	}
19897aec1d6eScindi 
19907aec1d6eScindi 	/* create the serialized buffer */
19917aec1d6eScindi 	Istatbufptr = Istatbuf = MALLOC(Istatsz);
19927aec1d6eScindi 	lut_walk(Istats, (lut_cb)istat2str, NULL);
19937aec1d6eScindi 
19947aec1d6eScindi 	/* clear out current saved stats */
19957aec1d6eScindi 	fmd_buf_destroy(Hdl, NULL, WOBUF_ISTATS);
19967aec1d6eScindi 
19977aec1d6eScindi 	/* write out the new version */
19987aec1d6eScindi 	fmd_buf_write(Hdl, NULL, WOBUF_ISTATS, Istatbuf, Istatsz);
19997aec1d6eScindi 	FREE(Istatbuf);
20007aec1d6eScindi 
20017aec1d6eScindi 	Istat_need_save = 0;
20027aec1d6eScindi }
20037aec1d6eScindi 
20047aec1d6eScindi int
20057aec1d6eScindi istat_cmp(struct istat_entry *ent1, struct istat_entry *ent2)
20067aec1d6eScindi {
20077aec1d6eScindi 	if (ent1->ename != ent2->ename)
20087aec1d6eScindi 		return (ent2->ename - ent1->ename);
20097aec1d6eScindi 	if (ent1->ipath != ent2->ipath)
20107aec1d6eScindi 		return ((char *)ent2->ipath - (char *)ent1->ipath);
20117aec1d6eScindi 
20127aec1d6eScindi 	return (0);
20137aec1d6eScindi }
20147aec1d6eScindi 
20157aec1d6eScindi /*
20167aec1d6eScindi  * istat-verify -- verify the component associated with a stat still exists
20177aec1d6eScindi  *
20187aec1d6eScindi  * if the component no longer exists, this routine resets the stat and
20197aec1d6eScindi  * returns 0.  if the component still exists, it returns 1.
20207aec1d6eScindi  */
20217aec1d6eScindi static int
20227aec1d6eScindi istat_verify(struct node *snp, struct istat_entry *entp)
20237aec1d6eScindi {
20247aec1d6eScindi 	struct stats *statp;
20257aec1d6eScindi 	nvlist_t *fmri;
20267aec1d6eScindi 
20277aec1d6eScindi 	fmri = node2fmri(snp->u.event.epname);
20287aec1d6eScindi 	if (platform_path_exists(fmri)) {
20297aec1d6eScindi 		nvlist_free(fmri);
20307aec1d6eScindi 		return (1);
20317aec1d6eScindi 	}
20327aec1d6eScindi 	nvlist_free(fmri);
20337aec1d6eScindi 
20347aec1d6eScindi 	/* component no longer in system.  zero out the associated stats */
20357aec1d6eScindi 	if ((statp = (struct stats *)
20367aec1d6eScindi 	    lut_lookup(Istats, entp, (lut_cmp)istat_cmp)) == NULL ||
20377aec1d6eScindi 	    stats_counter_value(statp) == 0)
20387aec1d6eScindi 		return (0);	/* stat is already reset */
20397aec1d6eScindi 
20407aec1d6eScindi 	Istat_need_save = 1;
20417aec1d6eScindi 	stats_counter_reset(statp);
20427aec1d6eScindi 	return (0);
20437aec1d6eScindi }
20447aec1d6eScindi 
20457aec1d6eScindi static void
20467aec1d6eScindi istat_bump(struct node *snp, int n)
20477aec1d6eScindi {
20487aec1d6eScindi 	struct stats *statp;
20497aec1d6eScindi 	struct istat_entry ent;
20507aec1d6eScindi 
20517aec1d6eScindi 	ASSERT(snp != NULL);
20527aec1d6eScindi 	ASSERTinfo(snp->t == T_EVENT, ptree_nodetype2str(snp->t));
20537aec1d6eScindi 	ASSERT(snp->u.event.epname != NULL);
20547aec1d6eScindi 
20557aec1d6eScindi 	/* class name should be hoisted into a single stable entry */
20567aec1d6eScindi 	ASSERT(snp->u.event.ename->u.name.next == NULL);
20577aec1d6eScindi 	ent.ename = snp->u.event.ename->u.name.s;
20587aec1d6eScindi 	ent.ipath = ipath(snp->u.event.epname);
20597aec1d6eScindi 
20607aec1d6eScindi 	if (!istat_verify(snp, &ent)) {
20617aec1d6eScindi 		/* component no longer exists in system, nothing to do */
20627aec1d6eScindi 		return;
20637aec1d6eScindi 	}
20647aec1d6eScindi 
20657aec1d6eScindi 	if ((statp = (struct stats *)
20667aec1d6eScindi 	    lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL) {
20677aec1d6eScindi 		/* need to create the counter */
20687aec1d6eScindi 		int cnt = 0;
20697aec1d6eScindi 		struct node *np;
20707aec1d6eScindi 		char *sname;
20717aec1d6eScindi 		char *snamep;
20727aec1d6eScindi 		struct istat_entry *newentp;
20737aec1d6eScindi 
20747aec1d6eScindi 		/* count up the size of the stat name */
20757aec1d6eScindi 		np = snp->u.event.ename;
20767aec1d6eScindi 		while (np != NULL) {
20777aec1d6eScindi 			cnt += strlen(np->u.name.s);
20787aec1d6eScindi 			cnt++;	/* for the '.' or '@' */
20797aec1d6eScindi 			np = np->u.name.next;
20807aec1d6eScindi 		}
20817aec1d6eScindi 		np = snp->u.event.epname;
20827aec1d6eScindi 		while (np != NULL) {
20837aec1d6eScindi 			cnt += snprintf(NULL, 0, "%s%llu",
20847aec1d6eScindi 			    np->u.name.s, np->u.name.child->u.ull);
20857aec1d6eScindi 			cnt++;	/* for the '/' or trailing NULL byte */
20867aec1d6eScindi 			np = np->u.name.next;
20877aec1d6eScindi 		}
20887aec1d6eScindi 
20897aec1d6eScindi 		/* build the stat name */
20907aec1d6eScindi 		snamep = sname = alloca(cnt);
20917aec1d6eScindi 		np = snp->u.event.ename;
20927aec1d6eScindi 		while (np != NULL) {
20937aec1d6eScindi 			snamep += snprintf(snamep, &sname[cnt] - snamep,
20947aec1d6eScindi 			    "%s", np->u.name.s);
20957aec1d6eScindi 			np = np->u.name.next;
20967aec1d6eScindi 			if (np)
20977aec1d6eScindi 				*snamep++ = '.';
20987aec1d6eScindi 		}
20997aec1d6eScindi 		*snamep++ = '@';
21007aec1d6eScindi 		np = snp->u.event.epname;
21017aec1d6eScindi 		while (np != NULL) {
21027aec1d6eScindi 			snamep += snprintf(snamep, &sname[cnt] - snamep,
21037aec1d6eScindi 			    "%s%llu", np->u.name.s, np->u.name.child->u.ull);
21047aec1d6eScindi 			np = np->u.name.next;
21057aec1d6eScindi 			if (np)
21067aec1d6eScindi 				*snamep++ = '/';
21077aec1d6eScindi 		}
21087aec1d6eScindi 		*snamep++ = '\0';
21097aec1d6eScindi 
21107aec1d6eScindi 		/* create the new stat & add it to our list */
21117aec1d6eScindi 		newentp = MALLOC(sizeof (*newentp));
21127aec1d6eScindi 		*newentp = ent;
21137aec1d6eScindi 		statp = stats_new_counter(NULL, sname, 0);
21147aec1d6eScindi 		Istats = lut_add(Istats, (void *)newentp, (void *)statp,
21157aec1d6eScindi 		    (lut_cmp)istat_cmp);
21167aec1d6eScindi 	}
21177aec1d6eScindi 
21187aec1d6eScindi 	/* if n is non-zero, set that value instead of bumping */
21197aec1d6eScindi 	if (n) {
21207aec1d6eScindi 		stats_counter_reset(statp);
21217aec1d6eScindi 		stats_counter_add(statp, n);
21227aec1d6eScindi 	} else
21237aec1d6eScindi 		stats_counter_bump(statp);
21247aec1d6eScindi 	Istat_need_save = 1;
21258a40a695Sgavinm 
21268a40a695Sgavinm 	ipath_print(O_ALTFP|O_VERB2, ent.ename, ent.ipath);
21278a40a695Sgavinm 	out(O_ALTFP|O_VERB2, " %s to value %d", n ? "set" : "incremented",
21288a40a695Sgavinm 	    stats_counter_value(statp));
21297aec1d6eScindi }
21307aec1d6eScindi 
21317aec1d6eScindi /*ARGSUSED*/
21327aec1d6eScindi static void
21337aec1d6eScindi istat_destructor(void *left, void *right, void *arg)
21347aec1d6eScindi {
21357aec1d6eScindi 	struct istat_entry *entp = (struct istat_entry *)left;
21367aec1d6eScindi 	struct stats *statp = (struct stats *)right;
21377aec1d6eScindi 	FREE(entp);
21387aec1d6eScindi 	stats_delete(statp);
21397aec1d6eScindi }
21407aec1d6eScindi 
214108f6c065Sgavinm /*
214208f6c065Sgavinm  * Callback used in a walk of the Istats to reset matching stat counters.
214308f6c065Sgavinm  */
214408f6c065Sgavinm static void
214508f6c065Sgavinm istat_counter_reset_cb(struct istat_entry *entp, struct stats *statp,
214608f6c065Sgavinm     const struct ipath *ipp)
214708f6c065Sgavinm {
214808f6c065Sgavinm 	char *path;
214908f6c065Sgavinm 
215008f6c065Sgavinm 	if (entp->ipath == ipp) {
215108f6c065Sgavinm 		path = ipath2str(entp->ename, ipp);
215208f6c065Sgavinm 		out(O_ALTFP, "istat_counter_reset_cb: resetting %s", path);
215308f6c065Sgavinm 		FREE(path);
215408f6c065Sgavinm 		stats_counter_reset(statp);
215508f6c065Sgavinm 		Istat_need_save = 1;
215608f6c065Sgavinm 	}
215708f6c065Sgavinm }
215808f6c065Sgavinm 
21597aec1d6eScindi void
21607aec1d6eScindi istat_fini(void)
21617aec1d6eScindi {
21627aec1d6eScindi 	lut_free(Istats, istat_destructor, NULL);
21637aec1d6eScindi }
21647aec1d6eScindi 
2165*b5016cbbSstephh static char *Serdbuf;
2166*b5016cbbSstephh static char *Serdbufptr;
2167*b5016cbbSstephh static int Serdsz;
2168*b5016cbbSstephh 
2169*b5016cbbSstephh /*
2170*b5016cbbSstephh  * serdaddsize -- calculate size of serd and add it to Serdsz
2171*b5016cbbSstephh  */
2172*b5016cbbSstephh /*ARGSUSED*/
2173*b5016cbbSstephh static void
2174*b5016cbbSstephh serdaddsize(const struct serd_entry *lhs, struct stats *rhs, void *arg)
2175*b5016cbbSstephh {
2176*b5016cbbSstephh 	ASSERT(lhs != NULL);
2177*b5016cbbSstephh 
2178*b5016cbbSstephh 	/* count up the size of the stat name */
2179*b5016cbbSstephh 	Serdsz += ipath2strlen(lhs->ename, lhs->ipath);
2180*b5016cbbSstephh 	Serdsz++;	/* for the trailing NULL byte */
2181*b5016cbbSstephh }
2182*b5016cbbSstephh 
2183*b5016cbbSstephh /*
2184*b5016cbbSstephh  * serd2str -- serialize a serd engine, writing result to *Serdbufptr
2185*b5016cbbSstephh  */
2186*b5016cbbSstephh /*ARGSUSED*/
2187*b5016cbbSstephh static void
2188*b5016cbbSstephh serd2str(const struct serd_entry *lhs, struct stats *rhs, void *arg)
2189*b5016cbbSstephh {
2190*b5016cbbSstephh 	char *str;
2191*b5016cbbSstephh 	int len;
2192*b5016cbbSstephh 
2193*b5016cbbSstephh 	ASSERT(lhs != NULL);
2194*b5016cbbSstephh 
2195*b5016cbbSstephh 	/* serialize the serd engine name */
2196*b5016cbbSstephh 	str = ipath2str(lhs->ename, lhs->ipath);
2197*b5016cbbSstephh 	len = strlen(str);
2198*b5016cbbSstephh 
2199*b5016cbbSstephh 	ASSERT(Serdbufptr + len + 1 <= &Serdbuf[Serdsz]);
2200*b5016cbbSstephh 	(void) strlcpy(Serdbufptr, str, &Serdbuf[Serdsz] - Serdbufptr);
2201*b5016cbbSstephh 	Serdbufptr += len;
2202*b5016cbbSstephh 	FREE(str);
2203*b5016cbbSstephh 	*Serdbufptr++ = '\0';
2204*b5016cbbSstephh 	ASSERT(Serdbufptr <= &Serdbuf[Serdsz]);
2205*b5016cbbSstephh }
2206*b5016cbbSstephh 
2207*b5016cbbSstephh void
2208*b5016cbbSstephh serd_save()
2209*b5016cbbSstephh {
2210*b5016cbbSstephh 	if (Serd_need_save == 0)
2211*b5016cbbSstephh 		return;
2212*b5016cbbSstephh 
2213*b5016cbbSstephh 	/* figure out how big the serialzed info is */
2214*b5016cbbSstephh 	Serdsz = 0;
2215*b5016cbbSstephh 	lut_walk(SerdEngines, (lut_cb)serdaddsize, NULL);
2216*b5016cbbSstephh 
2217*b5016cbbSstephh 	if (Serdsz == 0) {
2218*b5016cbbSstephh 		/* no serd engines to save */
2219*b5016cbbSstephh 		fmd_buf_destroy(Hdl, NULL, WOBUF_SERDS);
2220*b5016cbbSstephh 		return;
2221*b5016cbbSstephh 	}
2222*b5016cbbSstephh 
2223*b5016cbbSstephh 	/* create the serialized buffer */
2224*b5016cbbSstephh 	Serdbufptr = Serdbuf = MALLOC(Serdsz);
2225*b5016cbbSstephh 	lut_walk(SerdEngines, (lut_cb)serd2str, NULL);
2226*b5016cbbSstephh 
2227*b5016cbbSstephh 	/* clear out current saved stats */
2228*b5016cbbSstephh 	fmd_buf_destroy(Hdl, NULL, WOBUF_SERDS);
2229*b5016cbbSstephh 
2230*b5016cbbSstephh 	/* write out the new version */
2231*b5016cbbSstephh 	fmd_buf_write(Hdl, NULL, WOBUF_SERDS, Serdbuf, Serdsz);
2232*b5016cbbSstephh 	FREE(Serdbuf);
2233*b5016cbbSstephh 	Serd_need_save = 0;
2234*b5016cbbSstephh }
2235*b5016cbbSstephh 
2236*b5016cbbSstephh int
2237*b5016cbbSstephh serd_cmp(struct serd_entry *ent1, struct serd_entry *ent2)
2238*b5016cbbSstephh {
2239*b5016cbbSstephh 	if (ent1->ename != ent2->ename)
2240*b5016cbbSstephh 		return (ent2->ename - ent1->ename);
2241*b5016cbbSstephh 	if (ent1->ipath != ent2->ipath)
2242*b5016cbbSstephh 		return ((char *)ent2->ipath - (char *)ent1->ipath);
2243*b5016cbbSstephh 
2244*b5016cbbSstephh 	return (0);
2245*b5016cbbSstephh }
2246*b5016cbbSstephh 
2247*b5016cbbSstephh void
2248*b5016cbbSstephh fme_serd_load(fmd_hdl_t *hdl)
2249*b5016cbbSstephh {
2250*b5016cbbSstephh 	int sz;
2251*b5016cbbSstephh 	char *sbuf;
2252*b5016cbbSstephh 	char *sepptr;
2253*b5016cbbSstephh 	char *ptr;
2254*b5016cbbSstephh 	struct serd_entry *newentp;
2255*b5016cbbSstephh 	struct node *epname;
2256*b5016cbbSstephh 	nvlist_t *fmri;
2257*b5016cbbSstephh 	char *namestring;
2258*b5016cbbSstephh 
2259*b5016cbbSstephh 	if ((sz = fmd_buf_size(hdl, NULL, WOBUF_SERDS)) == 0)
2260*b5016cbbSstephh 		return;
2261*b5016cbbSstephh 	sbuf = alloca(sz);
2262*b5016cbbSstephh 	fmd_buf_read(hdl, NULL, WOBUF_SERDS, sbuf, sz);
2263*b5016cbbSstephh 	ptr = sbuf;
2264*b5016cbbSstephh 	while (ptr < &sbuf[sz]) {
2265*b5016cbbSstephh 		sepptr = strchr(ptr, '@');
2266*b5016cbbSstephh 		*sepptr = '\0';
2267*b5016cbbSstephh 		namestring = ptr;
2268*b5016cbbSstephh 		sepptr++;
2269*b5016cbbSstephh 		ptr = sepptr;
2270*b5016cbbSstephh 		ptr += strlen(ptr);
2271*b5016cbbSstephh 		ptr++;	/* move past the '\0' separating paths */
2272*b5016cbbSstephh 		epname = pathstring2epnamenp(sepptr);
2273*b5016cbbSstephh 		fmri = node2fmri(epname);
2274*b5016cbbSstephh 		if (platform_path_exists(fmri)) {
2275*b5016cbbSstephh 			newentp = MALLOC(sizeof (*newentp));
2276*b5016cbbSstephh 			newentp->hdl = hdl;
2277*b5016cbbSstephh 			newentp->ipath = ipath(epname);
2278*b5016cbbSstephh 			newentp->ename = stable(namestring);
2279*b5016cbbSstephh 			SerdEngines = lut_add(SerdEngines, (void *)newentp,
2280*b5016cbbSstephh 			    (void *)NULL, (lut_cmp)serd_cmp);
2281*b5016cbbSstephh 		} else
2282*b5016cbbSstephh 			Serd_need_save = 1;
2283*b5016cbbSstephh 		nvlist_free(fmri);
2284*b5016cbbSstephh 	}
2285*b5016cbbSstephh 	/* save it back again in case some of the paths no longer exist */
2286*b5016cbbSstephh 	serd_save();
2287*b5016cbbSstephh }
2288*b5016cbbSstephh 
2289*b5016cbbSstephh /*ARGSUSED*/
2290*b5016cbbSstephh static void
2291*b5016cbbSstephh serd_destructor(void *left, void *right, void *arg)
2292*b5016cbbSstephh {
2293*b5016cbbSstephh 	struct serd_entry *entp = (struct serd_entry *)left;
2294*b5016cbbSstephh 	FREE(entp);
2295*b5016cbbSstephh }
2296*b5016cbbSstephh 
2297*b5016cbbSstephh /*
2298*b5016cbbSstephh  * Callback used in a walk of the SerdEngines to reset matching serd engines.
2299*b5016cbbSstephh  */
2300*b5016cbbSstephh /*ARGSUSED*/
2301*b5016cbbSstephh static void
2302*b5016cbbSstephh serd_reset_cb(struct serd_entry *entp, void *unused, const struct ipath *ipp)
2303*b5016cbbSstephh {
2304*b5016cbbSstephh 	char *path;
2305*b5016cbbSstephh 
2306*b5016cbbSstephh 	if (entp->ipath == ipp) {
2307*b5016cbbSstephh 		path = ipath2str(entp->ename, ipp);
2308*b5016cbbSstephh 		out(O_ALTFP, "serd_reset_cb: resetting %s", path);
2309*b5016cbbSstephh 		fmd_serd_reset(entp->hdl, path);
2310*b5016cbbSstephh 		FREE(path);
2311*b5016cbbSstephh 		Serd_need_save = 1;
2312*b5016cbbSstephh 	}
2313*b5016cbbSstephh }
2314*b5016cbbSstephh 
2315*b5016cbbSstephh void
2316*b5016cbbSstephh serd_fini(void)
2317*b5016cbbSstephh {
2318*b5016cbbSstephh 	lut_free(SerdEngines, serd_destructor, NULL);
2319*b5016cbbSstephh }
2320*b5016cbbSstephh 
23217c478bd9Sstevel@tonic-gate static void
23227c478bd9Sstevel@tonic-gate publish_suspects(struct fme *fmep)
23237c478bd9Sstevel@tonic-gate {
23247c478bd9Sstevel@tonic-gate 	struct rsl *srl = NULL;
23257c478bd9Sstevel@tonic-gate 	struct rsl *erl;
23267c478bd9Sstevel@tonic-gate 	struct rsl *rp;
23277c478bd9Sstevel@tonic-gate 	nvlist_t *fault;
23287c478bd9Sstevel@tonic-gate 	uint8_t cert;
23297c478bd9Sstevel@tonic-gate 	uint_t *frs;
23307c478bd9Sstevel@tonic-gate 	uint_t fravg, frsum, fr;
23317aec1d6eScindi 	uint_t messval;
23327aec1d6eScindi 	struct node *snp;
23337c478bd9Sstevel@tonic-gate 	int frcnt, fridx;
23347c478bd9Sstevel@tonic-gate 	boolean_t no_upsets = B_FALSE;
23357aec1d6eScindi 	boolean_t allfaulty = B_TRUE;
23367c478bd9Sstevel@tonic-gate 
23377c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->diags);
23387c478bd9Sstevel@tonic-gate 
23397c478bd9Sstevel@tonic-gate 	/*
23407c478bd9Sstevel@tonic-gate 	 * If we're auto-closing upsets, we don't want to include them
23417c478bd9Sstevel@tonic-gate 	 * in any produced suspect lists or certainty accounting.
23427c478bd9Sstevel@tonic-gate 	 */
23437c478bd9Sstevel@tonic-gate 	if (Autoclose != NULL)
23447c478bd9Sstevel@tonic-gate 		if (strcmp(Autoclose, "true") == 0 ||
23457c478bd9Sstevel@tonic-gate 		    strcmp(Autoclose, "all") == 0 ||
23467c478bd9Sstevel@tonic-gate 		    strcmp(Autoclose, "upsets") == 0)
23477c478bd9Sstevel@tonic-gate 			no_upsets = B_TRUE;
23487c478bd9Sstevel@tonic-gate 
23497c478bd9Sstevel@tonic-gate 	trim_suspects(fmep, no_upsets, &srl, &erl);
23507c478bd9Sstevel@tonic-gate 
23517c478bd9Sstevel@tonic-gate 	/*
23527c478bd9Sstevel@tonic-gate 	 * If the resulting suspect list has no members, we're
23537c478bd9Sstevel@tonic-gate 	 * done.  Returning here will simply close the case.
23547c478bd9Sstevel@tonic-gate 	 */
23557c478bd9Sstevel@tonic-gate 	if (fmep->nsuspects == 0) {
23567c478bd9Sstevel@tonic-gate 		out(O_ALTFP,
23577c478bd9Sstevel@tonic-gate 		    "[FME%d, case %s (all suspects are upsets)]",
23587c478bd9Sstevel@tonic-gate 		    fmep->id, fmd_case_uuid(fmep->hdl, fmep->fmcase));
23597c478bd9Sstevel@tonic-gate 		FREE(srl);
23607c478bd9Sstevel@tonic-gate 		restore_suspects(fmep);
23617c478bd9Sstevel@tonic-gate 		return;
23627c478bd9Sstevel@tonic-gate 	}
23637c478bd9Sstevel@tonic-gate 
23647c478bd9Sstevel@tonic-gate 	/*
23657c478bd9Sstevel@tonic-gate 	 * If the suspect list is all faults, then for a given fault,
23667c478bd9Sstevel@tonic-gate 	 * say X of N, X's certainty is computed via:
23677c478bd9Sstevel@tonic-gate 	 *
23687c478bd9Sstevel@tonic-gate 	 * fitrate(X) / (fitrate(1) + ... + fitrate(N)) * 100
23697c478bd9Sstevel@tonic-gate 	 *
23707c478bd9Sstevel@tonic-gate 	 * If none of the suspects are faults, and there are N suspects,
23717c478bd9Sstevel@tonic-gate 	 * the certainty of a given suspect is 100/N.
23727c478bd9Sstevel@tonic-gate 	 *
23737c478bd9Sstevel@tonic-gate 	 * If there are are a mixture of faults and other problems in
23747c478bd9Sstevel@tonic-gate 	 * the suspect list, we take an average of the faults'
23757c478bd9Sstevel@tonic-gate 	 * FITrates and treat this average as the FITrate for any
23767c478bd9Sstevel@tonic-gate 	 * non-faults.  The fitrate of any given suspect is then
23777c478bd9Sstevel@tonic-gate 	 * computed per the first formula above.
23787c478bd9Sstevel@tonic-gate 	 */
23797c478bd9Sstevel@tonic-gate 	if (fmep->nonfault == fmep->nsuspects) {
23807c478bd9Sstevel@tonic-gate 		/* NO faults in the suspect list */
23817c478bd9Sstevel@tonic-gate 		cert = percentof(1, fmep->nsuspects);
23827c478bd9Sstevel@tonic-gate 	} else {
23837c478bd9Sstevel@tonic-gate 		/* sum the fitrates */
23847c478bd9Sstevel@tonic-gate 		frs = alloca(fmep->nsuspects * sizeof (uint_t));
23857c478bd9Sstevel@tonic-gate 		fridx = frcnt = frsum = 0;
23867c478bd9Sstevel@tonic-gate 
23877c478bd9Sstevel@tonic-gate 		for (rp = srl; rp <= erl; rp++) {
23887c478bd9Sstevel@tonic-gate 			struct node *n;
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate 			if (rp->suspect == NULL)
23917c478bd9Sstevel@tonic-gate 				continue;
23927c478bd9Sstevel@tonic-gate 			if (!is_fault(rp->suspect->t)) {
23937c478bd9Sstevel@tonic-gate 				frs[fridx++] = 0;
23947c478bd9Sstevel@tonic-gate 				continue;
23957c478bd9Sstevel@tonic-gate 			}
23967c478bd9Sstevel@tonic-gate 			n = eventprop_lookup(rp->suspect, L_FITrate);
23977c478bd9Sstevel@tonic-gate 			if (node2uint(n, &fr) != 0) {
23987c478bd9Sstevel@tonic-gate 				out(O_DEBUG|O_NONL, "event ");
23997c478bd9Sstevel@tonic-gate 				ipath_print(O_DEBUG|O_NONL,
2400d96ce684Sstephh 				    rp->suspect->enode->u.event.ename->u.name.s,
2401d96ce684Sstephh 				    rp->suspect->ipp);
24027c478bd9Sstevel@tonic-gate 				out(O_DEBUG, " has no FITrate (using 1)");
24037c478bd9Sstevel@tonic-gate 				fr = 1;
24047c478bd9Sstevel@tonic-gate 			} else if (fr == 0) {
24057c478bd9Sstevel@tonic-gate 				out(O_DEBUG|O_NONL, "event ");
24067c478bd9Sstevel@tonic-gate 				ipath_print(O_DEBUG|O_NONL,
2407d96ce684Sstephh 				    rp->suspect->enode->u.event.ename->u.name.s,
2408d96ce684Sstephh 				    rp->suspect->ipp);
24097c478bd9Sstevel@tonic-gate 				out(O_DEBUG, " has zero FITrate (using 1)");
24107c478bd9Sstevel@tonic-gate 				fr = 1;
24117c478bd9Sstevel@tonic-gate 			}
24127c478bd9Sstevel@tonic-gate 
24137c478bd9Sstevel@tonic-gate 			frs[fridx++] = fr;
24147c478bd9Sstevel@tonic-gate 			frsum += fr;
24157c478bd9Sstevel@tonic-gate 			frcnt++;
24167c478bd9Sstevel@tonic-gate 		}
24177c478bd9Sstevel@tonic-gate 		fravg = avg(frsum, frcnt);
24187c478bd9Sstevel@tonic-gate 		for (fridx = 0; fridx < fmep->nsuspects; fridx++)
24197c478bd9Sstevel@tonic-gate 			if (frs[fridx] == 0) {
24207c478bd9Sstevel@tonic-gate 				frs[fridx] = fravg;
24217c478bd9Sstevel@tonic-gate 				frsum += fravg;
24227c478bd9Sstevel@tonic-gate 			}
24237c478bd9Sstevel@tonic-gate 	}
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate 	/* Add them in reverse order of our sort, as fmd reverses order */
24267c478bd9Sstevel@tonic-gate 	for (rp = erl; rp >= srl; rp--) {
24277c478bd9Sstevel@tonic-gate 		if (rp->suspect == NULL)
24287c478bd9Sstevel@tonic-gate 			continue;
24297aec1d6eScindi 		if (!is_fault(rp->suspect->t))
24307aec1d6eScindi 			allfaulty = B_FALSE;
24317c478bd9Sstevel@tonic-gate 		if (fmep->nonfault != fmep->nsuspects)
24327c478bd9Sstevel@tonic-gate 			cert = percentof(frs[--fridx], frsum);
24337c478bd9Sstevel@tonic-gate 		fault = fmd_nvl_create_fault(fmep->hdl,
24347c478bd9Sstevel@tonic-gate 		    rp->suspect->enode->u.event.ename->u.name.s,
24357c478bd9Sstevel@tonic-gate 		    cert,
24367c478bd9Sstevel@tonic-gate 		    rp->asru,
24377c478bd9Sstevel@tonic-gate 		    rp->fru,
24387c478bd9Sstevel@tonic-gate 		    rp->rsrc);
24397c478bd9Sstevel@tonic-gate 		if (fault == NULL)
24407c478bd9Sstevel@tonic-gate 			out(O_DIE, "fault creation failed");
24417aec1d6eScindi 		/* if "message" property exists, add it to the fault */
24427aec1d6eScindi 		if (node2uint(eventprop_lookup(rp->suspect, L_message),
24437aec1d6eScindi 		    &messval) == 0) {
24447aec1d6eScindi 
24457aec1d6eScindi 			out(O_ALTFP,
24467aec1d6eScindi 			    "[FME%d, %s adds message=%d to suspect list]",
24477aec1d6eScindi 			    fmep->id,
24487aec1d6eScindi 			    rp->suspect->enode->u.event.ename->u.name.s,
24497aec1d6eScindi 			    messval);
24507aec1d6eScindi 			if (nvlist_add_boolean_value(fault,
24517aec1d6eScindi 			    FM_SUSPECT_MESSAGE,
24527aec1d6eScindi 			    (messval) ? B_TRUE : B_FALSE) != 0) {
24537aec1d6eScindi 				out(O_DIE, "cannot add no-message to fault");
24547aec1d6eScindi 			}
24557aec1d6eScindi 		}
24567aec1d6eScindi 		/* add any payload properties */
24577aec1d6eScindi 		lut_walk(rp->suspect->payloadprops,
24587aec1d6eScindi 		    (lut_cb)addpayloadprop, (void *)fault);
24597c478bd9Sstevel@tonic-gate 		fmd_case_add_suspect(fmep->hdl, fmep->fmcase, fault);
24607c478bd9Sstevel@tonic-gate 		rslfree(rp);
24615f25dc2aSgavinm 
24625f25dc2aSgavinm 		/*
24635f25dc2aSgavinm 		 * If "action" property exists, evaluate it;  this must be done
24645f25dc2aSgavinm 		 * before the dupclose check below since some actions may
24655f25dc2aSgavinm 		 * modify the asru to be used in fmd_nvl_fmri_faulty.  This
24665f25dc2aSgavinm 		 * needs to be restructured if any new actions are introduced
24675f25dc2aSgavinm 		 * that have effects that we do not want to be visible if
24685f25dc2aSgavinm 		 * we decide not to publish in the dupclose check below.
24695f25dc2aSgavinm 		 */
24707aec1d6eScindi 		if ((snp = eventprop_lookup(rp->suspect, L_action)) != NULL) {
24717aec1d6eScindi 			struct evalue evalue;
24727aec1d6eScindi 
24737aec1d6eScindi 			out(O_ALTFP|O_NONL,
24747aec1d6eScindi 			    "[FME%d, %s action ", fmep->id,
24757aec1d6eScindi 			    rp->suspect->enode->u.event.ename->u.name.s);
24767aec1d6eScindi 			ptree_name_iter(O_ALTFP|O_NONL, snp);
24777aec1d6eScindi 			out(O_ALTFP, "]");
24787aec1d6eScindi 			Action_nvl = fault;
24797aec1d6eScindi 			(void) eval_expr(snp, NULL, NULL, NULL, NULL,
24807aec1d6eScindi 			    NULL, 0, &evalue);
24817aec1d6eScindi 		}
24825f25dc2aSgavinm 
24837aec1d6eScindi 		/*
24847aec1d6eScindi 		 * if "dupclose" tunable is set, check if the asru is
24857aec1d6eScindi 		 * already marked as "faulty".
24867aec1d6eScindi 		 */
24877aec1d6eScindi 		if (Dupclose && allfaulty) {
24887aec1d6eScindi 			nvlist_t *asru;
24897aec1d6eScindi 
24907aec1d6eScindi 			out(O_ALTFP|O_VERB, "FMD%d dupclose check ", fmep->id);
24917aec1d6eScindi 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, rp->suspect);
24927aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, " ");
24937aec1d6eScindi 			if (nvlist_lookup_nvlist(fault,
24947aec1d6eScindi 			    FM_FAULT_ASRU, &asru) != 0) {
24957aec1d6eScindi 				out(O_ALTFP|O_VERB, "NULL asru");
24967aec1d6eScindi 				allfaulty = B_FALSE;
24977aec1d6eScindi 			} else if (fmd_nvl_fmri_faulty(fmep->hdl, asru)) {
24987aec1d6eScindi 				out(O_ALTFP|O_VERB, "faulty");
24997aec1d6eScindi 			} else {
25007aec1d6eScindi 				out(O_ALTFP|O_VERB, "not faulty");
25017aec1d6eScindi 				allfaulty = B_FALSE;
25027aec1d6eScindi 			}
25037aec1d6eScindi 		}
25047aec1d6eScindi 
25057aec1d6eScindi 	}
25065f25dc2aSgavinm 
25075f25dc2aSgavinm 	/*
25085f25dc2aSgavinm 	 * Close the case if all asrus are already known to be faulty and if
25095f25dc2aSgavinm 	 * Dupclose is enabled.  Otherwise we are going to publish so take
25105f25dc2aSgavinm 	 * any pre-publication actions.
25115f25dc2aSgavinm 	 */
25127aec1d6eScindi 	if (Dupclose && allfaulty) {
25137aec1d6eScindi 		out(O_ALTFP, "[dupclose FME%d, case %s]", fmep->id,
25147aec1d6eScindi 		    fmd_case_uuid(fmep->hdl, fmep->fmcase));
25157aec1d6eScindi 		fmd_case_close(fmep->hdl, fmep->fmcase);
25167aec1d6eScindi 	} else {
25175f25dc2aSgavinm 		for (rp = erl; rp >= srl; rp--) {
25185f25dc2aSgavinm 			struct event *suspect = rp->suspect;
25195f25dc2aSgavinm 
25205f25dc2aSgavinm 			if (suspect == NULL)
25215f25dc2aSgavinm 				continue;
25225f25dc2aSgavinm 
25235f25dc2aSgavinm 			/* if "count" exists, increment the appropriate stat */
25245f25dc2aSgavinm 			if ((snp = eventprop_lookup(suspect,
25255f25dc2aSgavinm 			    L_count)) != NULL) {
25265f25dc2aSgavinm 				out(O_ALTFP|O_NONL,
25275f25dc2aSgavinm 				    "[FME%d, %s count ", fmep->id,
25285f25dc2aSgavinm 				    suspect->enode->u.event.ename->u.name.s);
25295f25dc2aSgavinm 				ptree_name_iter(O_ALTFP|O_NONL, snp);
25305f25dc2aSgavinm 				out(O_ALTFP, "]");
25315f25dc2aSgavinm 				istat_bump(snp, 0);
25325f25dc2aSgavinm 
25335f25dc2aSgavinm 			}
25345f25dc2aSgavinm 		}
25355f25dc2aSgavinm 		istat_save();	/* write out any istat changes */
25365f25dc2aSgavinm 
25377aec1d6eScindi 		out(O_ALTFP, "[solving FME%d, case %s]", fmep->id,
25387aec1d6eScindi 		    fmd_case_uuid(fmep->hdl, fmep->fmcase));
25397aec1d6eScindi 		fmd_case_solve(fmep->hdl, fmep->fmcase);
25407c478bd9Sstevel@tonic-gate 	}
25417aec1d6eScindi 
25427c478bd9Sstevel@tonic-gate 	/*
25437c478bd9Sstevel@tonic-gate 	 * revert to the original suspect list
25447c478bd9Sstevel@tonic-gate 	 */
25457c478bd9Sstevel@tonic-gate 	FREE(srl);
25467c478bd9Sstevel@tonic-gate 	restore_suspects(fmep);
25477c478bd9Sstevel@tonic-gate }
25487c478bd9Sstevel@tonic-gate 
25497c478bd9Sstevel@tonic-gate static void
2550*b5016cbbSstephh publish_undiagnosable(fmd_hdl_t *hdl, fmd_event_t *ffep, fmd_case_t *fmcase)
25517c478bd9Sstevel@tonic-gate {
25527c478bd9Sstevel@tonic-gate 	struct case_list *newcase;
25537c478bd9Sstevel@tonic-gate 	nvlist_t *defect;
25547c478bd9Sstevel@tonic-gate 
25557c478bd9Sstevel@tonic-gate 	out(O_ALTFP,
25567c478bd9Sstevel@tonic-gate 	    "[undiagnosable ereport received, "
25577c478bd9Sstevel@tonic-gate 	    "creating and closing a new case (%s)]",
25587c478bd9Sstevel@tonic-gate 	    Undiag_reason ? Undiag_reason : "reason not provided");
25597c478bd9Sstevel@tonic-gate 
25607c478bd9Sstevel@tonic-gate 	newcase = MALLOC(sizeof (struct case_list));
25617c478bd9Sstevel@tonic-gate 	newcase->next = NULL;
2562*b5016cbbSstephh 	newcase->fmcase = fmcase;
25637c478bd9Sstevel@tonic-gate 	if (Undiagablecaselist != NULL)
25647c478bd9Sstevel@tonic-gate 		newcase->next = Undiagablecaselist;
25657c478bd9Sstevel@tonic-gate 	Undiagablecaselist = newcase;
25667c478bd9Sstevel@tonic-gate 
25677c478bd9Sstevel@tonic-gate 	if (ffep != NULL)
25687c478bd9Sstevel@tonic-gate 		fmd_case_add_ereport(hdl, newcase->fmcase, ffep);
25697c478bd9Sstevel@tonic-gate 
25707c478bd9Sstevel@tonic-gate 	defect = fmd_nvl_create_fault(hdl, UNDIAGNOSABLE_DEFECT, 100,
25717c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL);
25727c478bd9Sstevel@tonic-gate 	if (Undiag_reason != NULL)
25737c478bd9Sstevel@tonic-gate 		(void) nvlist_add_string(defect, UNDIAG_REASON, Undiag_reason);
25747c478bd9Sstevel@tonic-gate 	fmd_case_add_suspect(hdl, newcase->fmcase, defect);
25757c478bd9Sstevel@tonic-gate 
25767c478bd9Sstevel@tonic-gate 	fmd_case_solve(hdl, newcase->fmcase);
25777c478bd9Sstevel@tonic-gate 	fmd_case_close(hdl, newcase->fmcase);
25787c478bd9Sstevel@tonic-gate }
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate static void
25817c478bd9Sstevel@tonic-gate fme_undiagnosable(struct fme *f)
25827c478bd9Sstevel@tonic-gate {
25837c478bd9Sstevel@tonic-gate 	nvlist_t *defect;
25847c478bd9Sstevel@tonic-gate 
25857c478bd9Sstevel@tonic-gate 	out(O_ALTFP, "[solving/closing FME%d, case %s (%s)]",
25867c478bd9Sstevel@tonic-gate 	    f->id, fmd_case_uuid(f->hdl, f->fmcase),
25877c478bd9Sstevel@tonic-gate 	    Undiag_reason ? Undiag_reason : "undiagnosable");
25887c478bd9Sstevel@tonic-gate 
25897c478bd9Sstevel@tonic-gate 	defect = fmd_nvl_create_fault(f->hdl, UNDIAGNOSABLE_DEFECT, 100,
25907c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL);
25917c478bd9Sstevel@tonic-gate 	if (Undiag_reason != NULL)
25927c478bd9Sstevel@tonic-gate 		(void) nvlist_add_string(defect, UNDIAG_REASON, Undiag_reason);
25937c478bd9Sstevel@tonic-gate 	fmd_case_add_suspect(f->hdl, f->fmcase, defect);
25947c478bd9Sstevel@tonic-gate 	fmd_case_solve(f->hdl, f->fmcase);
25957c478bd9Sstevel@tonic-gate 	fmd_case_close(f->hdl, f->fmcase);
25967c478bd9Sstevel@tonic-gate }
25977c478bd9Sstevel@tonic-gate 
25987c478bd9Sstevel@tonic-gate /*
25997c478bd9Sstevel@tonic-gate  * fme_close_case
26007c478bd9Sstevel@tonic-gate  *
26017c478bd9Sstevel@tonic-gate  *	Find the requested case amongst our fmes and close it.  Free up
26027c478bd9Sstevel@tonic-gate  *	the related fme.
26037c478bd9Sstevel@tonic-gate  */
26047c478bd9Sstevel@tonic-gate void
26057c478bd9Sstevel@tonic-gate fme_close_case(fmd_hdl_t *hdl, fmd_case_t *fmcase)
26067c478bd9Sstevel@tonic-gate {
26077c478bd9Sstevel@tonic-gate 	struct case_list *ucasep, *prevcasep = NULL;
26087c478bd9Sstevel@tonic-gate 	struct fme *prev = NULL;
26097c478bd9Sstevel@tonic-gate 	struct fme *fmep;
26107c478bd9Sstevel@tonic-gate 
26117c478bd9Sstevel@tonic-gate 	for (ucasep = Undiagablecaselist; ucasep; ucasep = ucasep->next) {
26127c478bd9Sstevel@tonic-gate 		if (fmcase != ucasep->fmcase) {
26137c478bd9Sstevel@tonic-gate 			prevcasep = ucasep;
26147c478bd9Sstevel@tonic-gate 			continue;
26157c478bd9Sstevel@tonic-gate 		}
26167c478bd9Sstevel@tonic-gate 
26177c478bd9Sstevel@tonic-gate 		if (prevcasep == NULL)
26187c478bd9Sstevel@tonic-gate 			Undiagablecaselist = Undiagablecaselist->next;
26197c478bd9Sstevel@tonic-gate 		else
26207c478bd9Sstevel@tonic-gate 			prevcasep->next = ucasep->next;
26217c478bd9Sstevel@tonic-gate 
26227c478bd9Sstevel@tonic-gate 		FREE(ucasep);
26237c478bd9Sstevel@tonic-gate 		return;
26247c478bd9Sstevel@tonic-gate 	}
26257c478bd9Sstevel@tonic-gate 
26267c478bd9Sstevel@tonic-gate 	for (fmep = FMElist; fmep; fmep = fmep->next) {
26277c478bd9Sstevel@tonic-gate 		if (fmep->hdl == hdl && fmep->fmcase == fmcase)
26287c478bd9Sstevel@tonic-gate 			break;
26297c478bd9Sstevel@tonic-gate 		prev = fmep;
26307c478bd9Sstevel@tonic-gate 	}
26317c478bd9Sstevel@tonic-gate 
26327c478bd9Sstevel@tonic-gate 	if (fmep == NULL) {
26337c478bd9Sstevel@tonic-gate 		out(O_WARN, "Eft asked to close unrecognized case [%s].",
26347c478bd9Sstevel@tonic-gate 		    fmd_case_uuid(hdl, fmcase));
26357c478bd9Sstevel@tonic-gate 		return;
26367c478bd9Sstevel@tonic-gate 	}
26377c478bd9Sstevel@tonic-gate 
26387c478bd9Sstevel@tonic-gate 	if (EFMElist == fmep)
26397c478bd9Sstevel@tonic-gate 		EFMElist = prev;
26407c478bd9Sstevel@tonic-gate 
26417c478bd9Sstevel@tonic-gate 	if (prev == NULL)
26427c478bd9Sstevel@tonic-gate 		FMElist = FMElist->next;
26437c478bd9Sstevel@tonic-gate 	else
26447c478bd9Sstevel@tonic-gate 		prev->next = fmep->next;
26457c478bd9Sstevel@tonic-gate 
26467c478bd9Sstevel@tonic-gate 	fmep->next = NULL;
26477c478bd9Sstevel@tonic-gate 
26487c478bd9Sstevel@tonic-gate 	/* Get rid of any timer this fme has set */
26497c478bd9Sstevel@tonic-gate 	if (fmep->wull != 0)
26507c478bd9Sstevel@tonic-gate 		fmd_timer_remove(fmep->hdl, fmep->timer);
26517c478bd9Sstevel@tonic-gate 
26527c478bd9Sstevel@tonic-gate 	if (ClosedFMEs == NULL) {
26537c478bd9Sstevel@tonic-gate 		ClosedFMEs = fmep;
26547c478bd9Sstevel@tonic-gate 	} else {
26557c478bd9Sstevel@tonic-gate 		fmep->next = ClosedFMEs;
26567c478bd9Sstevel@tonic-gate 		ClosedFMEs = fmep;
26577c478bd9Sstevel@tonic-gate 	}
26580cc1f05eSjrutt 
26590cc1f05eSjrutt 	Open_fme_count--;
26600cc1f05eSjrutt 
26610cc1f05eSjrutt 	/* See if we can close the overflow FME */
26620cc1f05eSjrutt 	if (Open_fme_count <= Max_fme) {
26630cc1f05eSjrutt 		for (fmep = FMElist; fmep; fmep = fmep->next) {
26640cc1f05eSjrutt 			if (fmep->overflow && !(fmd_case_closed(fmep->hdl,
26650cc1f05eSjrutt 			    fmep->fmcase)))
26660cc1f05eSjrutt 				break;
26670cc1f05eSjrutt 		}
26680cc1f05eSjrutt 
26690cc1f05eSjrutt 		if (fmep != NULL)
26700cc1f05eSjrutt 			fmd_case_close(fmep->hdl, fmep->fmcase);
26710cc1f05eSjrutt 	}
26727c478bd9Sstevel@tonic-gate }
26737c478bd9Sstevel@tonic-gate 
26747c478bd9Sstevel@tonic-gate /*
26757c478bd9Sstevel@tonic-gate  * fme_set_timer()
26767c478bd9Sstevel@tonic-gate  *	If the time we need to wait for the given FME is less than the
26777c478bd9Sstevel@tonic-gate  *	current timer, kick that old timer out and establish a new one.
26787c478bd9Sstevel@tonic-gate  */
26797aec1d6eScindi static int
26807c478bd9Sstevel@tonic-gate fme_set_timer(struct fme *fmep, unsigned long long wull)
26817c478bd9Sstevel@tonic-gate {
26827c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, " fme_set_timer: request to wait ");
26837c478bd9Sstevel@tonic-gate 	ptree_timeval(O_ALTFP|O_VERB, &wull);
26847c478bd9Sstevel@tonic-gate 
26857c478bd9Sstevel@tonic-gate 	if (wull <= fmep->pull) {
26867c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "already have waited at least ");
26877c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB, &fmep->pull);
26887c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
26897c478bd9Sstevel@tonic-gate 		/* we've waited at least wull already, don't need timer */
26907aec1d6eScindi 		return (0);
26917c478bd9Sstevel@tonic-gate 	}
26927c478bd9Sstevel@tonic-gate 
26937c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, " currently ");
26947c478bd9Sstevel@tonic-gate 	if (fmep->wull != 0) {
26957c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "waiting ");
26967c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB, &fmep->wull);
26977c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
26987c478bd9Sstevel@tonic-gate 	} else {
26997c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "not waiting");
27007c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
27017c478bd9Sstevel@tonic-gate 	}
27027c478bd9Sstevel@tonic-gate 
27037c478bd9Sstevel@tonic-gate 	if (fmep->wull != 0)
27047c478bd9Sstevel@tonic-gate 		if (wull >= fmep->wull)
27057c478bd9Sstevel@tonic-gate 			/* New timer would fire later than established timer */
27067aec1d6eScindi 			return (0);
27077c478bd9Sstevel@tonic-gate 
27087aec1d6eScindi 	if (fmep->wull != 0) {
27097c478bd9Sstevel@tonic-gate 		fmd_timer_remove(fmep->hdl, fmep->timer);
27107aec1d6eScindi 	}
27117c478bd9Sstevel@tonic-gate 
27127c478bd9Sstevel@tonic-gate 	fmep->timer = fmd_timer_install(fmep->hdl, (void *)fmep,
27137c478bd9Sstevel@tonic-gate 	    fmep->e0r, wull);
27147c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, "timer set, id is %ld", fmep->timer);
27157c478bd9Sstevel@tonic-gate 	fmep->wull = wull;
27167aec1d6eScindi 	return (1);
27177c478bd9Sstevel@tonic-gate }
27187c478bd9Sstevel@tonic-gate 
27197c478bd9Sstevel@tonic-gate void
27207c478bd9Sstevel@tonic-gate fme_timer_fired(struct fme *fmep, id_t tid)
27217c478bd9Sstevel@tonic-gate {
27227c478bd9Sstevel@tonic-gate 	struct fme *ffmep = NULL;
27237c478bd9Sstevel@tonic-gate 
27247c478bd9Sstevel@tonic-gate 	for (ffmep = FMElist; ffmep; ffmep = ffmep->next)
27257c478bd9Sstevel@tonic-gate 		if (ffmep == fmep)
27267c478bd9Sstevel@tonic-gate 			break;
27277c478bd9Sstevel@tonic-gate 
27287c478bd9Sstevel@tonic-gate 	if (ffmep == NULL) {
27297c478bd9Sstevel@tonic-gate 		out(O_WARN, "Timer fired for an FME (%p) not in FMEs list.",
27307c478bd9Sstevel@tonic-gate 		    (void *)fmep);
27317c478bd9Sstevel@tonic-gate 		return;
27327c478bd9Sstevel@tonic-gate 	}
27337c478bd9Sstevel@tonic-gate 
2734*b5016cbbSstephh 	out(O_ALTFP|O_VERB, "Timer fired %lx", tid);
2735d96ce684Sstephh 	fmep->pull = fmep->wull;
2736d96ce684Sstephh 	fmep->wull = 0;
2737d96ce684Sstephh 	fmd_buf_write(fmep->hdl, fmep->fmcase,
2738d96ce684Sstephh 	    WOBUF_PULL, (void *)&fmep->pull, sizeof (fmep->pull));
2739*b5016cbbSstephh 
2740*b5016cbbSstephh 	fme_reload_cfgdata(fmep);
2741*b5016cbbSstephh 
274200d0963fSdilpreet 	fme_eval(fmep, fmep->e0r);
27437c478bd9Sstevel@tonic-gate }
27447c478bd9Sstevel@tonic-gate 
27457c478bd9Sstevel@tonic-gate /*
27467c478bd9Sstevel@tonic-gate  * Preserve the fme's suspect list in its psuspects list, NULLing the
27477c478bd9Sstevel@tonic-gate  * suspects list in the meantime.
27487c478bd9Sstevel@tonic-gate  */
27497c478bd9Sstevel@tonic-gate static void
27507c478bd9Sstevel@tonic-gate save_suspects(struct fme *fmep)
27517c478bd9Sstevel@tonic-gate {
27527c478bd9Sstevel@tonic-gate 	struct event *ep;
27537c478bd9Sstevel@tonic-gate 	struct event *nextep;
27547c478bd9Sstevel@tonic-gate 
27557c478bd9Sstevel@tonic-gate 	/* zero out the previous suspect list */
27567c478bd9Sstevel@tonic-gate 	for (ep = fmep->psuspects; ep; ep = nextep) {
27577c478bd9Sstevel@tonic-gate 		nextep = ep->psuspects;
27587c478bd9Sstevel@tonic-gate 		ep->psuspects = NULL;
27597c478bd9Sstevel@tonic-gate 	}
27607c478bd9Sstevel@tonic-gate 	fmep->psuspects = NULL;
27617c478bd9Sstevel@tonic-gate 
27627c478bd9Sstevel@tonic-gate 	/* zero out the suspect list, copying it to previous suspect list */
27637c478bd9Sstevel@tonic-gate 	fmep->psuspects = fmep->suspects;
27647c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = nextep) {
27657c478bd9Sstevel@tonic-gate 		nextep = ep->suspects;
27667c478bd9Sstevel@tonic-gate 		ep->psuspects = ep->suspects;
27677c478bd9Sstevel@tonic-gate 		ep->suspects = NULL;
27687c478bd9Sstevel@tonic-gate 		ep->is_suspect = 0;
27697c478bd9Sstevel@tonic-gate 	}
27707c478bd9Sstevel@tonic-gate 	fmep->suspects = NULL;
27717c478bd9Sstevel@tonic-gate 	fmep->nsuspects = 0;
27727c478bd9Sstevel@tonic-gate 	fmep->nonfault = 0;
27737c478bd9Sstevel@tonic-gate }
27747c478bd9Sstevel@tonic-gate 
27757c478bd9Sstevel@tonic-gate /*
27767c478bd9Sstevel@tonic-gate  * Retrieve the fme's suspect list from its psuspects list.
27777c478bd9Sstevel@tonic-gate  */
27787c478bd9Sstevel@tonic-gate static void
27797c478bd9Sstevel@tonic-gate restore_suspects(struct fme *fmep)
27807c478bd9Sstevel@tonic-gate {
27817c478bd9Sstevel@tonic-gate 	struct event *ep;
27827c478bd9Sstevel@tonic-gate 	struct event *nextep;
27837c478bd9Sstevel@tonic-gate 
27847c478bd9Sstevel@tonic-gate 	fmep->nsuspects = fmep->nonfault = 0;
27857c478bd9Sstevel@tonic-gate 	fmep->suspects = fmep->psuspects;
27867c478bd9Sstevel@tonic-gate 	for (ep = fmep->psuspects; ep; ep = nextep) {
27877c478bd9Sstevel@tonic-gate 		fmep->nsuspects++;
27887c478bd9Sstevel@tonic-gate 		if (!is_fault(ep->t))
27897c478bd9Sstevel@tonic-gate 			fmep->nonfault++;
27907c478bd9Sstevel@tonic-gate 		nextep = ep->psuspects;
27917c478bd9Sstevel@tonic-gate 		ep->suspects = ep->psuspects;
27927c478bd9Sstevel@tonic-gate 	}
27937c478bd9Sstevel@tonic-gate }
27947c478bd9Sstevel@tonic-gate 
27957c478bd9Sstevel@tonic-gate /*
27967c478bd9Sstevel@tonic-gate  * this is what we use to call the Emrys prototype code instead of main()
27977c478bd9Sstevel@tonic-gate  */
27987c478bd9Sstevel@tonic-gate static void
27997c478bd9Sstevel@tonic-gate fme_eval(struct fme *fmep, fmd_event_t *ffep)
28007c478bd9Sstevel@tonic-gate {
28017c478bd9Sstevel@tonic-gate 	struct event *ep;
28027c478bd9Sstevel@tonic-gate 	unsigned long long my_delay = TIMEVAL_EVENTUALLY;
28037c478bd9Sstevel@tonic-gate 
28047c478bd9Sstevel@tonic-gate 	save_suspects(fmep);
28057c478bd9Sstevel@tonic-gate 
2806*b5016cbbSstephh 	out(O_ALTFP, "Evaluate FME %d", fmep->id);
28077c478bd9Sstevel@tonic-gate 	indent_set("  ");
28087c478bd9Sstevel@tonic-gate 
28097aec1d6eScindi 	lut_walk(fmep->eventtree, (lut_cb)clear_arrows, (void *)fmep);
28107aec1d6eScindi 	fmep->state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay);
28117c478bd9Sstevel@tonic-gate 
2812*b5016cbbSstephh 	out(O_ALTFP|O_NONL, "FME%d state: %s, suspect list:", fmep->id,
28137c478bd9Sstevel@tonic-gate 	    fme_state2str(fmep->state));
28147c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = ep->suspects) {
2815*b5016cbbSstephh 		out(O_ALTFP|O_NONL, " ");
2816*b5016cbbSstephh 		itree_pevent_brief(O_ALTFP|O_NONL, ep);
28177c478bd9Sstevel@tonic-gate 	}
2818*b5016cbbSstephh 	out(O_ALTFP, NULL);
28197c478bd9Sstevel@tonic-gate 
2820d96ce684Sstephh 	switch (fmep->state) {
2821d96ce684Sstephh 	case FME_CREDIBLE:
2822d96ce684Sstephh 		print_suspects(SLNEW, fmep);
2823d96ce684Sstephh 		(void) upsets_eval(fmep, ffep);
2824d96ce684Sstephh 
28257c478bd9Sstevel@tonic-gate 		/*
2826d96ce684Sstephh 		 * we may have already posted suspects in upsets_eval() which
2827d96ce684Sstephh 		 * can recurse into fme_eval() again. If so then just return.
28287c478bd9Sstevel@tonic-gate 		 */
2829d96ce684Sstephh 		if (fmep->posted_suspects)
2830d96ce684Sstephh 			return;
28317c478bd9Sstevel@tonic-gate 
2832d96ce684Sstephh 		publish_suspects(fmep);
2833d96ce684Sstephh 		fmep->posted_suspects = 1;
2834d96ce684Sstephh 		fmd_buf_write(fmep->hdl, fmep->fmcase,
2835d96ce684Sstephh 		    WOBUF_POSTD,
2836d96ce684Sstephh 		    (void *)&fmep->posted_suspects,
2837d96ce684Sstephh 		    sizeof (fmep->posted_suspects));
28387c478bd9Sstevel@tonic-gate 
2839d96ce684Sstephh 		/*
2840d96ce684Sstephh 		 * Now the suspects have been posted, we can clear up
2841d96ce684Sstephh 		 * the instance tree as we won't be looking at it again.
2842d96ce684Sstephh 		 * Also cancel the timer as the case is now solved.
2843d96ce684Sstephh 		 */
2844d96ce684Sstephh 		if (fmep->wull != 0) {
2845d96ce684Sstephh 			fmd_timer_remove(fmep->hdl, fmep->timer);
2846d96ce684Sstephh 			fmep->wull = 0;
28477c478bd9Sstevel@tonic-gate 		}
2848d96ce684Sstephh 		break;
2849d96ce684Sstephh 
2850d96ce684Sstephh 	case FME_WAIT:
2851d96ce684Sstephh 		ASSERT(my_delay > fmep->ull);
2852d96ce684Sstephh 		(void) fme_set_timer(fmep, my_delay);
2853d96ce684Sstephh 		print_suspects(SLWAIT, fmep);
2854*b5016cbbSstephh 		itree_prune(fmep->eventtree);
2855*b5016cbbSstephh 		config_free(fmep->cfgdata);
2856*b5016cbbSstephh 		fmep->cfgdata = NULL;
2857*b5016cbbSstephh 		return;
2858d96ce684Sstephh 
2859d96ce684Sstephh 	case FME_DISPROVED:
2860d96ce684Sstephh 		print_suspects(SLDISPROVED, fmep);
2861d96ce684Sstephh 		Undiag_reason = UD_UNSOLVD;
2862d96ce684Sstephh 		fme_undiagnosable(fmep);
2863d96ce684Sstephh 		break;
28647c478bd9Sstevel@tonic-gate 	}
28657c478bd9Sstevel@tonic-gate 
28667c478bd9Sstevel@tonic-gate 	if (fmep->posted_suspects == 1 && Autoclose != NULL) {
28677c478bd9Sstevel@tonic-gate 		int doclose = 0;
28687c478bd9Sstevel@tonic-gate 
28697c478bd9Sstevel@tonic-gate 		if (strcmp(Autoclose, "true") == 0 ||
28707c478bd9Sstevel@tonic-gate 		    strcmp(Autoclose, "all") == 0)
28717c478bd9Sstevel@tonic-gate 			doclose = 1;
28727c478bd9Sstevel@tonic-gate 
28737c478bd9Sstevel@tonic-gate 		if (strcmp(Autoclose, "upsets") == 0) {
28747c478bd9Sstevel@tonic-gate 			doclose = 1;
28757c478bd9Sstevel@tonic-gate 			for (ep = fmep->suspects; ep; ep = ep->suspects) {
28767c478bd9Sstevel@tonic-gate 				if (ep->t != N_UPSET) {
28777c478bd9Sstevel@tonic-gate 					doclose = 0;
28787c478bd9Sstevel@tonic-gate 					break;
28797c478bd9Sstevel@tonic-gate 				}
28807c478bd9Sstevel@tonic-gate 			}
28817c478bd9Sstevel@tonic-gate 		}
28827c478bd9Sstevel@tonic-gate 
28837c478bd9Sstevel@tonic-gate 		if (doclose) {
28847c478bd9Sstevel@tonic-gate 			out(O_ALTFP, "[closing FME%d, case %s (autoclose)]",
28857c478bd9Sstevel@tonic-gate 			    fmep->id, fmd_case_uuid(fmep->hdl, fmep->fmcase));
28867c478bd9Sstevel@tonic-gate 			fmd_case_close(fmep->hdl, fmep->fmcase);
28877c478bd9Sstevel@tonic-gate 		}
28887c478bd9Sstevel@tonic-gate 	}
2889*b5016cbbSstephh 	itree_free(fmep->eventtree);
2890*b5016cbbSstephh 	fmep->eventtree = NULL;
2891*b5016cbbSstephh 	config_free(fmep->cfgdata);
2892*b5016cbbSstephh 	fmep->cfgdata = NULL;
2893*b5016cbbSstephh 	destroy_fme_bufs(fmep);
28947c478bd9Sstevel@tonic-gate }
28957c478bd9Sstevel@tonic-gate 
28967c478bd9Sstevel@tonic-gate static void indent(void);
28977c478bd9Sstevel@tonic-gate static int triggered(struct fme *fmep, struct event *ep, int mark);
28987c478bd9Sstevel@tonic-gate static enum fme_state effects_test(struct fme *fmep,
28997aec1d6eScindi     struct event *fault_event, unsigned long long at_latest_by,
29007aec1d6eScindi     unsigned long long *pdelay);
29017c478bd9Sstevel@tonic-gate static enum fme_state requirements_test(struct fme *fmep, struct event *ep,
29027aec1d6eScindi     unsigned long long at_latest_by, unsigned long long *pdelay);
29037c478bd9Sstevel@tonic-gate static enum fme_state causes_test(struct fme *fmep, struct event *ep,
29047c478bd9Sstevel@tonic-gate     unsigned long long at_latest_by, unsigned long long *pdelay);
29057c478bd9Sstevel@tonic-gate 
29067aec1d6eScindi static int
29077aec1d6eScindi checkconstraints(struct fme *fmep, struct arrow *arrowp)
29087aec1d6eScindi {
29097aec1d6eScindi 	struct constraintlist *ctp;
29107aec1d6eScindi 	struct evalue value;
2911*b5016cbbSstephh 	char *sep = "";
29127aec1d6eScindi 
29137aec1d6eScindi 	if (arrowp->forever_false) {
29147aec1d6eScindi 		indent();
29157aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "  Forever false constraint: ");
29167aec1d6eScindi 		for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) {
29177aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, sep);
29187aec1d6eScindi 			ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0);
29197aec1d6eScindi 			sep = ", ";
29207aec1d6eScindi 		}
29217aec1d6eScindi 		out(O_ALTFP|O_VERB, NULL);
29227aec1d6eScindi 		return (0);
29237aec1d6eScindi 	}
2924*b5016cbbSstephh 	if (arrowp->forever_true) {
2925*b5016cbbSstephh 		indent();
2926*b5016cbbSstephh 		out(O_ALTFP|O_VERB|O_NONL, "  Forever true constraint: ");
2927*b5016cbbSstephh 		for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) {
2928*b5016cbbSstephh 			out(O_ALTFP|O_VERB|O_NONL, sep);
2929*b5016cbbSstephh 			ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0);
2930*b5016cbbSstephh 			sep = ", ";
2931*b5016cbbSstephh 		}
2932*b5016cbbSstephh 		out(O_ALTFP|O_VERB, NULL);
2933*b5016cbbSstephh 		return (1);
2934*b5016cbbSstephh 	}
29357aec1d6eScindi 
29367aec1d6eScindi 	for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) {
29377aec1d6eScindi 		if (eval_expr(ctp->cnode, NULL, NULL,
29387aec1d6eScindi 		    &fmep->globals, fmep->cfgdata->cooked,
29397aec1d6eScindi 		    arrowp, 0, &value)) {
29407aec1d6eScindi 			/* evaluation successful */
29417aec1d6eScindi 			if (value.t == UNDEFINED || value.v == 0) {
29427aec1d6eScindi 				/* known false */
29437aec1d6eScindi 				arrowp->forever_false = 1;
29447aec1d6eScindi 				indent();
29457aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
29467aec1d6eScindi 				    "  False constraint: ");
29477aec1d6eScindi 				ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0);
29487aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
29497aec1d6eScindi 				return (0);
29507aec1d6eScindi 			}
29517aec1d6eScindi 		} else {
29527aec1d6eScindi 			/* evaluation unsuccessful -- unknown value */
29537aec1d6eScindi 			indent();
29547aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL,
29557aec1d6eScindi 			    "  Deferred constraint: ");
29567aec1d6eScindi 			ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0);
29577aec1d6eScindi 			out(O_ALTFP|O_VERB, NULL);
2958*b5016cbbSstephh 			return (1);
29597aec1d6eScindi 		}
29607aec1d6eScindi 	}
29617aec1d6eScindi 	/* known true */
2962*b5016cbbSstephh 	arrowp->forever_true = 1;
2963*b5016cbbSstephh 	indent();
2964*b5016cbbSstephh 	out(O_ALTFP|O_VERB|O_NONL, "  True constraint: ");
2965*b5016cbbSstephh 	for (ctp = arrowp->constraints; ctp != NULL; ctp = ctp->next) {
2966*b5016cbbSstephh 		out(O_ALTFP|O_VERB|O_NONL, sep);
2967*b5016cbbSstephh 		ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0);
2968*b5016cbbSstephh 		sep = ", ";
2969*b5016cbbSstephh 	}
2970*b5016cbbSstephh 	out(O_ALTFP|O_VERB, NULL);
29717aec1d6eScindi 	return (1);
29727aec1d6eScindi }
29737aec1d6eScindi 
29747c478bd9Sstevel@tonic-gate static int
29757c478bd9Sstevel@tonic-gate triggered(struct fme *fmep, struct event *ep, int mark)
29767c478bd9Sstevel@tonic-gate {
29777c478bd9Sstevel@tonic-gate 	struct bubble *bp;
29787c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
29797c478bd9Sstevel@tonic-gate 	int count = 0;
29807c478bd9Sstevel@tonic-gate 
29817c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Tcallcount);
29827c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
29837c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
29847c478bd9Sstevel@tonic-gate 		if (bp->t != B_TO)
29857c478bd9Sstevel@tonic-gate 			continue;
29867c478bd9Sstevel@tonic-gate 		for (ap = itree_next_arrow(bp, NULL); ap;
29877c478bd9Sstevel@tonic-gate 		    ap = itree_next_arrow(bp, ap)) {
29887c478bd9Sstevel@tonic-gate 			/* check count of marks against K in the bubble */
29897aec1d6eScindi 			if ((ap->arrowp->mark & mark) &&
29907c478bd9Sstevel@tonic-gate 			    ++count >= bp->nork)
29917c478bd9Sstevel@tonic-gate 				return (1);
29927c478bd9Sstevel@tonic-gate 		}
29937c478bd9Sstevel@tonic-gate 	}
29947c478bd9Sstevel@tonic-gate 	return (0);
29957c478bd9Sstevel@tonic-gate }
29967c478bd9Sstevel@tonic-gate 
29977aec1d6eScindi static int
29987aec1d6eScindi mark_arrows(struct fme *fmep, struct event *ep, int mark,
299900d0963fSdilpreet     unsigned long long at_latest_by, unsigned long long *pdelay, int keep)
30007c478bd9Sstevel@tonic-gate {
30017c478bd9Sstevel@tonic-gate 	struct bubble *bp;
30027c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
30037aec1d6eScindi 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
30047aec1d6eScindi 	unsigned long long my_delay;
30057aec1d6eScindi 	enum fme_state result;
30067aec1d6eScindi 	int retval = 0;
30077c478bd9Sstevel@tonic-gate 
30087c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
30097c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
30107c478bd9Sstevel@tonic-gate 		if (bp->t != B_FROM)
30117c478bd9Sstevel@tonic-gate 			continue;
30127aec1d6eScindi 		stats_counter_bump(fmep->Marrowcount);
30137aec1d6eScindi 		for (ap = itree_next_arrow(bp, NULL); ap;
30147aec1d6eScindi 		    ap = itree_next_arrow(bp, ap)) {
30157aec1d6eScindi 			struct event *ep2 = ap->arrowp->head->myevent;
30167aec1d6eScindi 			/*
30177aec1d6eScindi 			 * if we're clearing marks, we can avoid doing
30187aec1d6eScindi 			 * all that work evaluating constraints.
30197aec1d6eScindi 			 */
30207aec1d6eScindi 			if (mark == 0) {
3021*b5016cbbSstephh 				if (ap->arrowp->arrow_marked == 0)
3022*b5016cbbSstephh 					continue;
3023*b5016cbbSstephh 				ap->arrowp->arrow_marked = 0;
30247aec1d6eScindi 				ap->arrowp->mark &= ~EFFECTS_COUNTER;
302500d0963fSdilpreet 				if (keep && (ep2->cached_state &
302600d0963fSdilpreet 				    (WAIT_EFFECT|CREDIBLE_EFFECT|PARENT_WAIT)))
302700d0963fSdilpreet 					ep2->keep_in_tree = 1;
30287aec1d6eScindi 				ep2->cached_state &=
30297aec1d6eScindi 				    ~(WAIT_EFFECT|CREDIBLE_EFFECT|PARENT_WAIT);
303000d0963fSdilpreet 				(void) mark_arrows(fmep, ep2, mark, 0, NULL,
303100d0963fSdilpreet 				    keep);
30327aec1d6eScindi 				continue;
30337aec1d6eScindi 			}
3034*b5016cbbSstephh 			ap->arrowp->arrow_marked = 1;
30357aec1d6eScindi 			if (ep2->cached_state & REQMNTS_DISPROVED) {
30367aec1d6eScindi 				indent();
30377aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
30387aec1d6eScindi 				    "  ALREADY DISPROVED ");
30397aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
30407aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
30417aec1d6eScindi 				continue;
30427aec1d6eScindi 			}
30437aec1d6eScindi 			if (ep2->cached_state & WAIT_EFFECT) {
30447aec1d6eScindi 				indent();
30457aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
30467aec1d6eScindi 				    "  ALREADY EFFECTS WAIT ");
30477aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
30487aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
30497aec1d6eScindi 				continue;
30507aec1d6eScindi 			}
30517aec1d6eScindi 			if (ep2->cached_state & CREDIBLE_EFFECT) {
30527aec1d6eScindi 				indent();
30537aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
30547aec1d6eScindi 				    "  ALREADY EFFECTS CREDIBLE ");
30557aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
30567aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
30577aec1d6eScindi 				continue;
30587aec1d6eScindi 			}
30597aec1d6eScindi 			if ((ep2->cached_state & PARENT_WAIT) &&
30607aec1d6eScindi 			    (mark & PARENT_WAIT)) {
30617aec1d6eScindi 				indent();
30627aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
30637aec1d6eScindi 				    "  ALREADY PARENT EFFECTS WAIT ");
30647aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
30657aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
30667aec1d6eScindi 				continue;
30677aec1d6eScindi 			}
30687aec1d6eScindi 			platform_set_payloadnvp(ep2->nvp);
306900d0963fSdilpreet 			if (checkconstraints(fmep, ap->arrowp) == 0) {
30707aec1d6eScindi 				platform_set_payloadnvp(NULL);
30717aec1d6eScindi 				indent();
30727aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
30737aec1d6eScindi 				    "  CONSTRAINTS FAIL ");
30747aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
30757aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
30767aec1d6eScindi 				continue;
30777aec1d6eScindi 			}
30787aec1d6eScindi 			platform_set_payloadnvp(NULL);
30797aec1d6eScindi 			ap->arrowp->mark |= EFFECTS_COUNTER;
30807aec1d6eScindi 			if (!triggered(fmep, ep2, EFFECTS_COUNTER)) {
30817aec1d6eScindi 				indent();
30827aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
30837aec1d6eScindi 				    "  K-COUNT NOT YET MET ");
30847aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
30857aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
30867aec1d6eScindi 				continue;
30877aec1d6eScindi 			}
30887aec1d6eScindi 			ep2->cached_state &= ~PARENT_WAIT;
3089d96ce684Sstephh 			/*
3090d96ce684Sstephh 			 * if we've reached an ereport and no propagation time
3091d96ce684Sstephh 			 * is specified, use the Hesitate value
3092d96ce684Sstephh 			 */
3093d96ce684Sstephh 			if (ep2->t == N_EREPORT && at_latest_by == 0ULL &&
3094d96ce684Sstephh 			    ap->arrowp->maxdelay == 0ULL) {
3095d96ce684Sstephh 				out(O_ALTFP|O_VERB|O_NONL, "  default wait ");
3096d96ce684Sstephh 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
3097d96ce684Sstephh 				out(O_ALTFP|O_VERB, NULL);
3098*b5016cbbSstephh 				result = requirements_test(fmep, ep2, Hesitate,
3099*b5016cbbSstephh 				    &my_delay);
3100d96ce684Sstephh 			} else {
3101d96ce684Sstephh 				result = requirements_test(fmep, ep2,
3102d96ce684Sstephh 				    at_latest_by + ap->arrowp->maxdelay,
3103d96ce684Sstephh 				    &my_delay);
3104d96ce684Sstephh 			}
31057aec1d6eScindi 			if (result == FME_WAIT) {
31067aec1d6eScindi 				retval = WAIT_EFFECT;
31077aec1d6eScindi 				if (overall_delay > my_delay)
31087aec1d6eScindi 					overall_delay = my_delay;
31097aec1d6eScindi 				ep2->cached_state |= WAIT_EFFECT;
31107aec1d6eScindi 				indent();
31117aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL, "  EFFECTS WAIT ");
31127aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
31137aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
31147aec1d6eScindi 				indent_push("  E");
31157aec1d6eScindi 				if (mark_arrows(fmep, ep2, PARENT_WAIT,
311600d0963fSdilpreet 				    at_latest_by, &my_delay, 0) ==
311700d0963fSdilpreet 				    WAIT_EFFECT) {
31187aec1d6eScindi 					retval = WAIT_EFFECT;
31197aec1d6eScindi 					if (overall_delay > my_delay)
31207aec1d6eScindi 						overall_delay = my_delay;
31217c478bd9Sstevel@tonic-gate 				}
31227aec1d6eScindi 				indent_pop();
31237aec1d6eScindi 			} else if (result == FME_DISPROVED) {
31247aec1d6eScindi 				indent();
31257aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
31267aec1d6eScindi 				    "  EFFECTS DISPROVED ");
31277aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
31287aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
31297aec1d6eScindi 			} else {
31307aec1d6eScindi 				ep2->cached_state |= mark;
31317aec1d6eScindi 				indent();
31327aec1d6eScindi 				if (mark == CREDIBLE_EFFECT)
31337c478bd9Sstevel@tonic-gate 					out(O_ALTFP|O_VERB|O_NONL,
31347aec1d6eScindi 					    "  EFFECTS CREDIBLE ");
31357aec1d6eScindi 				else
31367aec1d6eScindi 					out(O_ALTFP|O_VERB|O_NONL,
31377aec1d6eScindi 					    "  PARENT EFFECTS WAIT ");
31387aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep2);
31397aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
31407aec1d6eScindi 				indent_push("  E");
31417aec1d6eScindi 				if (mark_arrows(fmep, ep2, mark, at_latest_by,
314200d0963fSdilpreet 				    &my_delay, 0) == WAIT_EFFECT) {
31437aec1d6eScindi 					retval = WAIT_EFFECT;
31447aec1d6eScindi 					if (overall_delay > my_delay)
31457aec1d6eScindi 						overall_delay = my_delay;
31467c478bd9Sstevel@tonic-gate 				}
31477aec1d6eScindi 				indent_pop();
31487c478bd9Sstevel@tonic-gate 			}
31497c478bd9Sstevel@tonic-gate 		}
31507c478bd9Sstevel@tonic-gate 	}
31517aec1d6eScindi 	if (retval == WAIT_EFFECT)
31527aec1d6eScindi 		*pdelay = overall_delay;
31537aec1d6eScindi 	return (retval);
31547c478bd9Sstevel@tonic-gate }
31557c478bd9Sstevel@tonic-gate 
31567c478bd9Sstevel@tonic-gate static enum fme_state
31577aec1d6eScindi effects_test(struct fme *fmep, struct event *fault_event,
31587aec1d6eScindi     unsigned long long at_latest_by, unsigned long long *pdelay)
31597c478bd9Sstevel@tonic-gate {
31607c478bd9Sstevel@tonic-gate 	struct event *error_event;
31617c478bd9Sstevel@tonic-gate 	enum fme_state return_value = FME_CREDIBLE;
31627aec1d6eScindi 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
31637aec1d6eScindi 	unsigned long long my_delay;
31647c478bd9Sstevel@tonic-gate 
31657c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Ecallcount);
31667c478bd9Sstevel@tonic-gate 	indent_push("  E");
31677c478bd9Sstevel@tonic-gate 	indent();
31687c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
31697c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, fault_event);
31707c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
31717c478bd9Sstevel@tonic-gate 
3172d96ce684Sstephh 	if (mark_arrows(fmep, fault_event, CREDIBLE_EFFECT, at_latest_by,
3173d96ce684Sstephh 	    &my_delay, 0) == WAIT_EFFECT) {
3174d96ce684Sstephh 		return_value = FME_WAIT;
3175d96ce684Sstephh 		if (overall_delay > my_delay)
3176d96ce684Sstephh 			overall_delay = my_delay;
3177d96ce684Sstephh 	}
31787c478bd9Sstevel@tonic-gate 	for (error_event = fmep->observations;
31797c478bd9Sstevel@tonic-gate 	    error_event; error_event = error_event->observations) {
31807c478bd9Sstevel@tonic-gate 		indent();
31817c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " ");
31827c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, error_event);
31837aec1d6eScindi 		if (!(error_event->cached_state & CREDIBLE_EFFECT)) {
31847aec1d6eScindi 			if (error_event->cached_state &
31857aec1d6eScindi 			    (PARENT_WAIT|WAIT_EFFECT)) {
31867aec1d6eScindi 				out(O_ALTFP|O_VERB, " NOT YET triggered");
31877aec1d6eScindi 				continue;
31887aec1d6eScindi 			}
31897c478bd9Sstevel@tonic-gate 			return_value = FME_DISPROVED;
31907c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, " NOT triggered");
31917c478bd9Sstevel@tonic-gate 			break;
31927c478bd9Sstevel@tonic-gate 		} else {
31937c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, " triggered");
31947c478bd9Sstevel@tonic-gate 		}
31957c478bd9Sstevel@tonic-gate 	}
319600d0963fSdilpreet 	if (return_value == FME_DISPROVED) {
319700d0963fSdilpreet 		(void) mark_arrows(fmep, fault_event, 0, 0, NULL, 0);
319800d0963fSdilpreet 	} else {
319900d0963fSdilpreet 		fault_event->keep_in_tree = 1;
320000d0963fSdilpreet 		(void) mark_arrows(fmep, fault_event, 0, 0, NULL, 1);
320100d0963fSdilpreet 	}
32027c478bd9Sstevel@tonic-gate 
32037c478bd9Sstevel@tonic-gate 	indent();
32047aec1d6eScindi 	out(O_ALTFP|O_VERB|O_NONL, "<-EFFECTS %s ",
32057aec1d6eScindi 	    fme_state2str(return_value));
32067c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, fault_event);
32077c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
32087c478bd9Sstevel@tonic-gate 	indent_pop();
32097aec1d6eScindi 	if (return_value == FME_WAIT)
32107aec1d6eScindi 		*pdelay = overall_delay;
32117c478bd9Sstevel@tonic-gate 	return (return_value);
32127c478bd9Sstevel@tonic-gate }
32137c478bd9Sstevel@tonic-gate 
32147c478bd9Sstevel@tonic-gate static enum fme_state
32157c478bd9Sstevel@tonic-gate requirements_test(struct fme *fmep, struct event *ep,
32167aec1d6eScindi     unsigned long long at_latest_by, unsigned long long *pdelay)
32177c478bd9Sstevel@tonic-gate {
32187c478bd9Sstevel@tonic-gate 	int waiting_events;
32197c478bd9Sstevel@tonic-gate 	int credible_events;
32207aec1d6eScindi 	int deferred_events;
32217c478bd9Sstevel@tonic-gate 	enum fme_state return_value = FME_CREDIBLE;
32227c478bd9Sstevel@tonic-gate 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
32237c478bd9Sstevel@tonic-gate 	unsigned long long arrow_delay;
32247c478bd9Sstevel@tonic-gate 	unsigned long long my_delay;
32257c478bd9Sstevel@tonic-gate 	struct event *ep2;
32267c478bd9Sstevel@tonic-gate 	struct bubble *bp;
32277c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
32287c478bd9Sstevel@tonic-gate 
32297aec1d6eScindi 	if (ep->cached_state & REQMNTS_CREDIBLE) {
32307aec1d6eScindi 		indent();
32317aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "  REQMNTS ALREADY CREDIBLE ");
32327aec1d6eScindi 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
32337aec1d6eScindi 		out(O_ALTFP|O_VERB, NULL);
32347aec1d6eScindi 		return (FME_CREDIBLE);
32357aec1d6eScindi 	}
32367aec1d6eScindi 	if (ep->cached_state & REQMNTS_DISPROVED) {
32377aec1d6eScindi 		indent();
32387aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "  REQMNTS ALREADY DISPROVED ");
32397aec1d6eScindi 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
32407aec1d6eScindi 		out(O_ALTFP|O_VERB, NULL);
32417aec1d6eScindi 		return (FME_DISPROVED);
32427aec1d6eScindi 	}
32437aec1d6eScindi 	if (ep->cached_state & REQMNTS_WAIT) {
32447aec1d6eScindi 		indent();
32457aec1d6eScindi 		*pdelay = ep->cached_delay;
32467aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "  REQMNTS ALREADY WAIT ");
32477aec1d6eScindi 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
32487aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, ", wait for: ");
32497aec1d6eScindi 		ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
32507aec1d6eScindi 		out(O_ALTFP|O_VERB, NULL);
32517aec1d6eScindi 		return (FME_WAIT);
32527aec1d6eScindi 	}
32537c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Rcallcount);
32547c478bd9Sstevel@tonic-gate 	indent_push("  R");
32557c478bd9Sstevel@tonic-gate 	indent();
32567c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
32577c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
32587c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, ", at latest by: ");
32597c478bd9Sstevel@tonic-gate 	ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
32607c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
32617c478bd9Sstevel@tonic-gate 
32627c478bd9Sstevel@tonic-gate 	if (ep->t == N_EREPORT) {
32637c478bd9Sstevel@tonic-gate 		if (ep->count == 0) {
32647c478bd9Sstevel@tonic-gate 			if (fmep->pull >= at_latest_by) {
32657c478bd9Sstevel@tonic-gate 				return_value = FME_DISPROVED;
32667c478bd9Sstevel@tonic-gate 			} else {
32677aec1d6eScindi 				ep->cached_delay = *pdelay = at_latest_by;
32687c478bd9Sstevel@tonic-gate 				return_value = FME_WAIT;
32697c478bd9Sstevel@tonic-gate 			}
32707c478bd9Sstevel@tonic-gate 		}
32717c478bd9Sstevel@tonic-gate 
32727c478bd9Sstevel@tonic-gate 		indent();
32737c478bd9Sstevel@tonic-gate 		switch (return_value) {
32747c478bd9Sstevel@tonic-gate 		case FME_CREDIBLE:
32757aec1d6eScindi 			ep->cached_state |= REQMNTS_CREDIBLE;
32767aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS CREDIBLE ");
32777c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
32787c478bd9Sstevel@tonic-gate 			break;
32797c478bd9Sstevel@tonic-gate 		case FME_DISPROVED:
32807aec1d6eScindi 			ep->cached_state |= REQMNTS_DISPROVED;
32817aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS DISPROVED ");
32827c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
32837c478bd9Sstevel@tonic-gate 			break;
32847c478bd9Sstevel@tonic-gate 		case FME_WAIT:
32857aec1d6eScindi 			ep->cached_state |= REQMNTS_WAIT;
32867aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS WAIT ");
32877c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
32887c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB|O_NONL, " to ");
32897c478bd9Sstevel@tonic-gate 			ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
32907c478bd9Sstevel@tonic-gate 			break;
32917c478bd9Sstevel@tonic-gate 		default:
32927c478bd9Sstevel@tonic-gate 			out(O_DIE, "requirements_test: unexpected fme_state");
32937c478bd9Sstevel@tonic-gate 			break;
32947c478bd9Sstevel@tonic-gate 		}
32957c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
32967c478bd9Sstevel@tonic-gate 		indent_pop();
32977c478bd9Sstevel@tonic-gate 
32987c478bd9Sstevel@tonic-gate 		return (return_value);
32997c478bd9Sstevel@tonic-gate 	}
33007c478bd9Sstevel@tonic-gate 
33017c478bd9Sstevel@tonic-gate 	/* this event is not a report, descend the tree */
33027c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
33037c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
33047aec1d6eScindi 		int n;
33057aec1d6eScindi 
33067c478bd9Sstevel@tonic-gate 		if (bp->t != B_FROM)
33077c478bd9Sstevel@tonic-gate 			continue;
33087c478bd9Sstevel@tonic-gate 
33097aec1d6eScindi 		n = bp->nork;
33107aec1d6eScindi 
33117aec1d6eScindi 		credible_events = 0;
33127aec1d6eScindi 		waiting_events = 0;
33137aec1d6eScindi 		deferred_events = 0;
33147aec1d6eScindi 		arrow_delay = TIMEVAL_EVENTUALLY;
33157aec1d6eScindi 		/*
33167aec1d6eScindi 		 * n is -1 for 'A' so adjust it.
33177aec1d6eScindi 		 * XXX just count up the arrows for now.
33187aec1d6eScindi 		 */
33197aec1d6eScindi 		if (n < 0) {
33207aec1d6eScindi 			n = 0;
33217aec1d6eScindi 			for (ap = itree_next_arrow(bp, NULL); ap;
33227aec1d6eScindi 			    ap = itree_next_arrow(bp, ap))
33237aec1d6eScindi 				n++;
33247aec1d6eScindi 			indent();
33257aec1d6eScindi 			out(O_ALTFP|O_VERB, " Bubble Counted N=%d", n);
33267aec1d6eScindi 		} else {
33277aec1d6eScindi 			indent();
33287aec1d6eScindi 			out(O_ALTFP|O_VERB, " Bubble N=%d", n);
33297aec1d6eScindi 		}
33307c478bd9Sstevel@tonic-gate 
33317aec1d6eScindi 		if (n == 0)
33327aec1d6eScindi 			continue;
33337aec1d6eScindi 		if (!(bp->mark & (BUBBLE_ELIDED|BUBBLE_OK))) {
33347c478bd9Sstevel@tonic-gate 			for (ap = itree_next_arrow(bp, NULL); ap;
33357c478bd9Sstevel@tonic-gate 			    ap = itree_next_arrow(bp, ap)) {
33367c478bd9Sstevel@tonic-gate 				ep2 = ap->arrowp->head->myevent;
33377aec1d6eScindi 				platform_set_payloadnvp(ep2->nvp);
33387aec1d6eScindi 				if (checkconstraints(fmep, ap->arrowp) == 0) {
33397aec1d6eScindi 					/*
33407aec1d6eScindi 					 * if any arrow is invalidated by the
33417aec1d6eScindi 					 * constraints, then we should elide the
33427aec1d6eScindi 					 * whole bubble to be consistant with
33437aec1d6eScindi 					 * the tree creation time behaviour
33447aec1d6eScindi 					 */
33457aec1d6eScindi 					bp->mark |= BUBBLE_ELIDED;
33467aec1d6eScindi 					platform_set_payloadnvp(NULL);
33477c478bd9Sstevel@tonic-gate 					break;
33487aec1d6eScindi 				}
33497aec1d6eScindi 				platform_set_payloadnvp(NULL);
33507aec1d6eScindi 			}
33517aec1d6eScindi 		}
33527aec1d6eScindi 		if (bp->mark & BUBBLE_ELIDED)
33537aec1d6eScindi 			continue;
33547aec1d6eScindi 		bp->mark |= BUBBLE_OK;
33557aec1d6eScindi 		for (ap = itree_next_arrow(bp, NULL); ap;
33567aec1d6eScindi 		    ap = itree_next_arrow(bp, ap)) {
33577aec1d6eScindi 			ep2 = ap->arrowp->head->myevent;
33587aec1d6eScindi 			if (n <= credible_events)
33597aec1d6eScindi 				break;
33607c478bd9Sstevel@tonic-gate 
33617aec1d6eScindi 			ap->arrowp->mark |= REQMNTS_COUNTER;
33627aec1d6eScindi 			if (triggered(fmep, ep2, REQMNTS_COUNTER))
33637aec1d6eScindi 				/* XXX adding max timevals! */
33647aec1d6eScindi 				switch (requirements_test(fmep, ep2,
33657aec1d6eScindi 				    at_latest_by + ap->arrowp->maxdelay,
33667aec1d6eScindi 				    &my_delay)) {
33677aec1d6eScindi 				case FME_DEFERRED:
33687aec1d6eScindi 					deferred_events++;
33697aec1d6eScindi 					break;
33707aec1d6eScindi 				case FME_CREDIBLE:
33717c478bd9Sstevel@tonic-gate 					credible_events++;
33727aec1d6eScindi 					break;
33737aec1d6eScindi 				case FME_DISPROVED:
33747aec1d6eScindi 					break;
33757aec1d6eScindi 				case FME_WAIT:
33767aec1d6eScindi 					if (my_delay < arrow_delay)
33777aec1d6eScindi 						arrow_delay = my_delay;
33787aec1d6eScindi 					waiting_events++;
33797aec1d6eScindi 					break;
33807aec1d6eScindi 				default:
33817aec1d6eScindi 					out(O_DIE,
33827aec1d6eScindi 					"Bug in requirements_test.");
33837aec1d6eScindi 				}
33847aec1d6eScindi 			else
33857aec1d6eScindi 				deferred_events++;
33867aec1d6eScindi 		}
33877aec1d6eScindi 		indent();
33887aec1d6eScindi 		out(O_ALTFP|O_VERB, " Credible: %d Waiting %d",
33897aec1d6eScindi 		    credible_events + deferred_events, waiting_events);
33907aec1d6eScindi 		if (credible_events + deferred_events + waiting_events < n) {
33917aec1d6eScindi 			/* Can never meet requirements */
33927aec1d6eScindi 			ep->cached_state |= REQMNTS_DISPROVED;
33937c478bd9Sstevel@tonic-gate 			indent();
33947aec1d6eScindi 			out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS DISPROVED ");
33957c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
33967c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, NULL);
33977aec1d6eScindi 			indent_pop();
33987aec1d6eScindi 			return (FME_DISPROVED);
33997aec1d6eScindi 		}
34007aec1d6eScindi 		if (credible_events + deferred_events < n) {
34017aec1d6eScindi 			/* will have to wait */
34027aec1d6eScindi 			/* wait time is shortest known */
34037aec1d6eScindi 			if (arrow_delay < overall_delay)
34047aec1d6eScindi 				overall_delay = arrow_delay;
34057aec1d6eScindi 			return_value = FME_WAIT;
34067aec1d6eScindi 		} else if (credible_events < n) {
34077aec1d6eScindi 			if (return_value != FME_WAIT)
34087aec1d6eScindi 				return_value = FME_DEFERRED;
34097c478bd9Sstevel@tonic-gate 		}
34107c478bd9Sstevel@tonic-gate 	}
34117c478bd9Sstevel@tonic-gate 
34127c478bd9Sstevel@tonic-gate 	/*
34137aec1d6eScindi 	 * don't mark as FME_DEFERRED. If this event isn't reached by another
34147aec1d6eScindi 	 * path, then this will be considered FME_CREDIBLE. But if it is
34157aec1d6eScindi 	 * reached by a different path so the K-count is met, then might
34167aec1d6eScindi 	 * get overridden by FME_WAIT or FME_DISPROVED.
34177c478bd9Sstevel@tonic-gate 	 */
34187aec1d6eScindi 	if (return_value == FME_WAIT) {
34197aec1d6eScindi 		ep->cached_state |= REQMNTS_WAIT;
34207aec1d6eScindi 		ep->cached_delay = *pdelay = overall_delay;
34217aec1d6eScindi 	} else if (return_value == FME_CREDIBLE) {
34227aec1d6eScindi 		ep->cached_state |= REQMNTS_CREDIBLE;
34237c478bd9Sstevel@tonic-gate 	}
34247c478bd9Sstevel@tonic-gate 	indent();
34257aec1d6eScindi 	out(O_ALTFP|O_VERB|O_NONL, "<-REQMNTS %s ",
34267aec1d6eScindi 	    fme_state2str(return_value));
34277c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
34287c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
34297c478bd9Sstevel@tonic-gate 	indent_pop();
34307c478bd9Sstevel@tonic-gate 	return (return_value);
34317c478bd9Sstevel@tonic-gate }
34327c478bd9Sstevel@tonic-gate 
34337c478bd9Sstevel@tonic-gate static enum fme_state
34347c478bd9Sstevel@tonic-gate causes_test(struct fme *fmep, struct event *ep,
34357c478bd9Sstevel@tonic-gate     unsigned long long at_latest_by, unsigned long long *pdelay)
34367c478bd9Sstevel@tonic-gate {
34377c478bd9Sstevel@tonic-gate 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
34387c478bd9Sstevel@tonic-gate 	unsigned long long my_delay;
34397c478bd9Sstevel@tonic-gate 	int credible_results = 0;
34407c478bd9Sstevel@tonic-gate 	int waiting_results = 0;
34417c478bd9Sstevel@tonic-gate 	enum fme_state fstate;
34427c478bd9Sstevel@tonic-gate 	struct event *tail_event;
34437c478bd9Sstevel@tonic-gate 	struct bubble *bp;
34447c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
34457c478bd9Sstevel@tonic-gate 	int k = 1;
34467c478bd9Sstevel@tonic-gate 
34477c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Ccallcount);
34487c478bd9Sstevel@tonic-gate 	indent_push("  C");
34497c478bd9Sstevel@tonic-gate 	indent();
34507c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
34517c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
34527c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
34537c478bd9Sstevel@tonic-gate 
34547c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
34557c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
34567c478bd9Sstevel@tonic-gate 		if (bp->t != B_TO)
34577c478bd9Sstevel@tonic-gate 			continue;
34587c478bd9Sstevel@tonic-gate 		k = bp->nork;	/* remember the K value */
34597c478bd9Sstevel@tonic-gate 		for (ap = itree_next_arrow(bp, NULL); ap;
34607c478bd9Sstevel@tonic-gate 		    ap = itree_next_arrow(bp, ap)) {
34617c478bd9Sstevel@tonic-gate 			int do_not_follow = 0;
34627aec1d6eScindi 
34637aec1d6eScindi 			/*
34647aec1d6eScindi 			 * if we get to the same event multiple times
34657aec1d6eScindi 			 * only worry about the first one.
34667aec1d6eScindi 			 */
34677aec1d6eScindi 			if (ap->arrowp->tail->myevent->cached_state &
34687aec1d6eScindi 			    CAUSES_TESTED) {
34697aec1d6eScindi 				indent();
34707aec1d6eScindi 				out(O_ALTFP|O_VERB|O_NONL,
34717aec1d6eScindi 				    "  causes test already run for ");
34727aec1d6eScindi 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL,
34737aec1d6eScindi 				    ap->arrowp->tail->myevent);
34747aec1d6eScindi 				out(O_ALTFP|O_VERB, NULL);
34757aec1d6eScindi 				continue;
34767aec1d6eScindi 			}
34777aec1d6eScindi 
34787c478bd9Sstevel@tonic-gate 			/*
34797c478bd9Sstevel@tonic-gate 			 * see if false constraint prevents us
34807c478bd9Sstevel@tonic-gate 			 * from traversing this arrow
34817c478bd9Sstevel@tonic-gate 			 */
34827c478bd9Sstevel@tonic-gate 			platform_set_payloadnvp(ep->nvp);
348300d0963fSdilpreet 			if (checkconstraints(fmep, ap->arrowp) == 0)
34847aec1d6eScindi 				do_not_follow = 1;
34857c478bd9Sstevel@tonic-gate 			platform_set_payloadnvp(NULL);
34867c478bd9Sstevel@tonic-gate 			if (do_not_follow) {
34877c478bd9Sstevel@tonic-gate 				indent();
34887c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB|O_NONL,
34897c478bd9Sstevel@tonic-gate 				    "  False arrow from ");
34907c478bd9Sstevel@tonic-gate 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL,
34917c478bd9Sstevel@tonic-gate 				    ap->arrowp->tail->myevent);
34927c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB, NULL);
34937c478bd9Sstevel@tonic-gate 				continue;
34947c478bd9Sstevel@tonic-gate 			}
34957c478bd9Sstevel@tonic-gate 
34967aec1d6eScindi 			ap->arrowp->tail->myevent->cached_state |=
34977aec1d6eScindi 			    CAUSES_TESTED;
34987aec1d6eScindi 			tail_event = ap->arrowp->tail->myevent;
34997aec1d6eScindi 			fstate = hypothesise(fmep, tail_event, at_latest_by,
35007aec1d6eScindi 			    &my_delay);
35017c478bd9Sstevel@tonic-gate 
35027c478bd9Sstevel@tonic-gate 			switch (fstate) {
35037c478bd9Sstevel@tonic-gate 			case FME_WAIT:
35047c478bd9Sstevel@tonic-gate 				if (my_delay < overall_delay)
35057c478bd9Sstevel@tonic-gate 					overall_delay = my_delay;
35067c478bd9Sstevel@tonic-gate 				waiting_results++;
35077c478bd9Sstevel@tonic-gate 				break;
35087c478bd9Sstevel@tonic-gate 			case FME_CREDIBLE:
35097c478bd9Sstevel@tonic-gate 				credible_results++;
35107c478bd9Sstevel@tonic-gate 				break;
35117c478bd9Sstevel@tonic-gate 			case FME_DISPROVED:
35127c478bd9Sstevel@tonic-gate 				break;
35137c478bd9Sstevel@tonic-gate 			default:
35147c478bd9Sstevel@tonic-gate 				out(O_DIE, "Bug in causes_test");
35157c478bd9Sstevel@tonic-gate 			}
35167c478bd9Sstevel@tonic-gate 		}
35177c478bd9Sstevel@tonic-gate 	}
35187c478bd9Sstevel@tonic-gate 	/* compare against K */
35197c478bd9Sstevel@tonic-gate 	if (credible_results + waiting_results < k) {
35207c478bd9Sstevel@tonic-gate 		indent();
35217aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES DISPROVED ");
35227c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
35237c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
35247c478bd9Sstevel@tonic-gate 		indent_pop();
35257c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
35267c478bd9Sstevel@tonic-gate 	}
35277c478bd9Sstevel@tonic-gate 	if (waiting_results != 0) {
35287c478bd9Sstevel@tonic-gate 		*pdelay = overall_delay;
35297c478bd9Sstevel@tonic-gate 		indent();
35307aec1d6eScindi 		out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES WAIT ");
35317c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
35327c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " to ");
35337c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
35347c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
35357c478bd9Sstevel@tonic-gate 		indent_pop();
35367c478bd9Sstevel@tonic-gate 		return (FME_WAIT);
35377c478bd9Sstevel@tonic-gate 	}
35387c478bd9Sstevel@tonic-gate 	indent();
35397aec1d6eScindi 	out(O_ALTFP|O_VERB|O_NONL, "<-CAUSES CREDIBLE ");
35407c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
35417c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
35427c478bd9Sstevel@tonic-gate 	indent_pop();
35437c478bd9Sstevel@tonic-gate 	return (FME_CREDIBLE);
35447c478bd9Sstevel@tonic-gate }
35457c478bd9Sstevel@tonic-gate 
35467c478bd9Sstevel@tonic-gate static enum fme_state
35477c478bd9Sstevel@tonic-gate hypothesise(struct fme *fmep, struct event *ep,
35487aec1d6eScindi 	unsigned long long at_latest_by, unsigned long long *pdelay)
35497c478bd9Sstevel@tonic-gate {
35507c478bd9Sstevel@tonic-gate 	enum fme_state rtr, otr;
35517c478bd9Sstevel@tonic-gate 	unsigned long long my_delay;
35527c478bd9Sstevel@tonic-gate 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
35537c478bd9Sstevel@tonic-gate 
35547c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Hcallcount);
35557c478bd9Sstevel@tonic-gate 	indent_push("  H");
35567c478bd9Sstevel@tonic-gate 	indent();
35577c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
35587c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
35597c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, ", at latest by: ");
35607c478bd9Sstevel@tonic-gate 	ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
35617c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
35627c478bd9Sstevel@tonic-gate 
35637aec1d6eScindi 	rtr = requirements_test(fmep, ep, at_latest_by, &my_delay);
35647c478bd9Sstevel@tonic-gate 	if ((rtr == FME_WAIT) && (my_delay < overall_delay))
35657c478bd9Sstevel@tonic-gate 		overall_delay = my_delay;
35667c478bd9Sstevel@tonic-gate 	if (rtr != FME_DISPROVED) {
35677c478bd9Sstevel@tonic-gate 		if (is_problem(ep->t)) {
35687aec1d6eScindi 			otr = effects_test(fmep, ep, at_latest_by, &my_delay);
35697c478bd9Sstevel@tonic-gate 			if (otr != FME_DISPROVED) {
3570*b5016cbbSstephh 				if (fmep->peek == 0 && ep->is_suspect == 0) {
35717c478bd9Sstevel@tonic-gate 					ep->suspects = fmep->suspects;
3572*b5016cbbSstephh 					ep->is_suspect = 1;
35737c478bd9Sstevel@tonic-gate 					fmep->suspects = ep;
35747c478bd9Sstevel@tonic-gate 					fmep->nsuspects++;
35757c478bd9Sstevel@tonic-gate 					if (!is_fault(ep->t))
35767c478bd9Sstevel@tonic-gate 						fmep->nonfault++;
35777c478bd9Sstevel@tonic-gate 				}
35787c478bd9Sstevel@tonic-gate 			}
35797c478bd9Sstevel@tonic-gate 		} else
35807c478bd9Sstevel@tonic-gate 			otr = causes_test(fmep, ep, at_latest_by, &my_delay);
35817c478bd9Sstevel@tonic-gate 		if ((otr == FME_WAIT) && (my_delay < overall_delay))
35827c478bd9Sstevel@tonic-gate 			overall_delay = my_delay;
35837c478bd9Sstevel@tonic-gate 		if ((otr != FME_DISPROVED) &&
35847c478bd9Sstevel@tonic-gate 		    ((rtr == FME_WAIT) || (otr == FME_WAIT)))
35857c478bd9Sstevel@tonic-gate 			*pdelay = overall_delay;
35867c478bd9Sstevel@tonic-gate 	}
35877c478bd9Sstevel@tonic-gate 	if (rtr == FME_DISPROVED) {
35887c478bd9Sstevel@tonic-gate 		indent();
35897c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
35907c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
35917c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, " (doesn't meet requirements)");
35927c478bd9Sstevel@tonic-gate 		indent_pop();
35937c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
35947c478bd9Sstevel@tonic-gate 	}
35957c478bd9Sstevel@tonic-gate 	if ((otr == FME_DISPROVED) && is_problem(ep->t)) {
35967c478bd9Sstevel@tonic-gate 		indent();
35977c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
35987c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
35997c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, " (doesn't explain all reports)");
36007c478bd9Sstevel@tonic-gate 		indent_pop();
36017c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
36027c478bd9Sstevel@tonic-gate 	}
36037c478bd9Sstevel@tonic-gate 	if (otr == FME_DISPROVED) {
36047c478bd9Sstevel@tonic-gate 		indent();
36057c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
36067c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
36077c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, " (causes are not credible)");
36087c478bd9Sstevel@tonic-gate 		indent_pop();
36097c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
36107c478bd9Sstevel@tonic-gate 	}
36117c478bd9Sstevel@tonic-gate 	if ((rtr == FME_WAIT) || (otr == FME_WAIT)) {
36127c478bd9Sstevel@tonic-gate 		indent();
36137c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-WAIT ");
36147c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
36157c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " to ");
36167c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB|O_NONL, &overall_delay);
36177c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
36187c478bd9Sstevel@tonic-gate 		indent_pop();
36197c478bd9Sstevel@tonic-gate 		return (FME_WAIT);
36207c478bd9Sstevel@tonic-gate 	}
36217c478bd9Sstevel@tonic-gate 	indent();
36227c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "<-CREDIBLE ");
36237c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
36247c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
36257c478bd9Sstevel@tonic-gate 	indent_pop();
36267c478bd9Sstevel@tonic-gate 	return (FME_CREDIBLE);
36277c478bd9Sstevel@tonic-gate }
36287aec1d6eScindi 
36297aec1d6eScindi /*
36307aec1d6eScindi  * fme_istat_load -- reconstitute any persistent istats
36317aec1d6eScindi  */
36327aec1d6eScindi void
36337aec1d6eScindi fme_istat_load(fmd_hdl_t *hdl)
36347aec1d6eScindi {
36357aec1d6eScindi 	int sz;
36367aec1d6eScindi 	char *sbuf;
36377aec1d6eScindi 	char *ptr;
36387aec1d6eScindi 
36397aec1d6eScindi 	if ((sz = fmd_buf_size(hdl, NULL, WOBUF_ISTATS)) == 0) {
36407aec1d6eScindi 		out(O_ALTFP, "fme_istat_load: No stats");
36417aec1d6eScindi 		return;
36427aec1d6eScindi 	}
36437aec1d6eScindi 
36447aec1d6eScindi 	sbuf = alloca(sz);
36457aec1d6eScindi 
36467aec1d6eScindi 	fmd_buf_read(hdl, NULL, WOBUF_ISTATS, sbuf, sz);
36477aec1d6eScindi 
36487aec1d6eScindi 	/*
36497aec1d6eScindi 	 * pick apart the serialized stats
36507aec1d6eScindi 	 *
36517aec1d6eScindi 	 * format is:
36527aec1d6eScindi 	 *	<class-name>, '@', <path>, '\0', <value>, '\0'
36537aec1d6eScindi 	 * for example:
36547aec1d6eScindi 	 *	"stat.first@stat0/path0\02\0stat.second@stat0/path1\023\0"
36557aec1d6eScindi 	 *
36567aec1d6eScindi 	 * since this is parsing our own serialized data, any parsing issues
36577aec1d6eScindi 	 * are fatal, so we check for them all with ASSERT() below.
36587aec1d6eScindi 	 */
36597aec1d6eScindi 	ptr = sbuf;
36607aec1d6eScindi 	while (ptr < &sbuf[sz]) {
36617aec1d6eScindi 		char *sepptr;
36627aec1d6eScindi 		struct node *np;
36637aec1d6eScindi 		int val;
36647aec1d6eScindi 
36657aec1d6eScindi 		sepptr = strchr(ptr, '@');
36667aec1d6eScindi 		ASSERT(sepptr != NULL);
36677aec1d6eScindi 		*sepptr = '\0';
36687aec1d6eScindi 
36697aec1d6eScindi 		/* construct the event */
36707aec1d6eScindi 		np = newnode(T_EVENT, NULL, 0);
36717aec1d6eScindi 		np->u.event.ename = newnode(T_NAME, NULL, 0);
36727aec1d6eScindi 		np->u.event.ename->u.name.t = N_STAT;
36737aec1d6eScindi 		np->u.event.ename->u.name.s = stable(ptr);
36747aec1d6eScindi 		np->u.event.ename->u.name.it = IT_ENAME;
36757aec1d6eScindi 		np->u.event.ename->u.name.last = np->u.event.ename;
36767aec1d6eScindi 
36777aec1d6eScindi 		ptr = sepptr + 1;
36787aec1d6eScindi 		ASSERT(ptr < &sbuf[sz]);
36797aec1d6eScindi 		ptr += strlen(ptr);
36807aec1d6eScindi 		ptr++;	/* move past the '\0' separating path from value */
36817aec1d6eScindi 		ASSERT(ptr < &sbuf[sz]);
36827aec1d6eScindi 		ASSERT(isdigit(*ptr));
36837aec1d6eScindi 		val = atoi(ptr);
36847aec1d6eScindi 		ASSERT(val > 0);
36857aec1d6eScindi 		ptr += strlen(ptr);
36867aec1d6eScindi 		ptr++;	/* move past the final '\0' for this entry */
36877aec1d6eScindi 
36887aec1d6eScindi 		np->u.event.epname = pathstring2epnamenp(sepptr + 1);
36897aec1d6eScindi 		ASSERT(np->u.event.epname != NULL);
36907aec1d6eScindi 
36917aec1d6eScindi 		istat_bump(np, val);
36927aec1d6eScindi 		tree_free(np);
36937aec1d6eScindi 	}
36947aec1d6eScindi 
36957aec1d6eScindi 	istat_save();
36967aec1d6eScindi }
3697