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