17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
57c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
67c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
77c478bd9Sstevel@tonic-gate  * with the License.
87c478bd9Sstevel@tonic-gate  *
97c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
107c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
117c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
127c478bd9Sstevel@tonic-gate  * and limitations under the License.
137c478bd9Sstevel@tonic-gate  *
147c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
157c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
167c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
177c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
187c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
197c478bd9Sstevel@tonic-gate  *
207c478bd9Sstevel@tonic-gate  * CDDL HEADER END
217c478bd9Sstevel@tonic-gate  */
227c478bd9Sstevel@tonic-gate /*
237c478bd9Sstevel@tonic-gate  * Copyright 2005 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 int Autoconvict;
607c478bd9Sstevel@tonic-gate extern char *Autoclose;
617c478bd9Sstevel@tonic-gate extern hrtime_t Hesitate;
627c478bd9Sstevel@tonic-gate extern nv_alloc_t Eft_nv_hdl;
63*0cc1f05eSjrutt extern int Max_fme;
647c478bd9Sstevel@tonic-gate 
657c478bd9Sstevel@tonic-gate /* fme under construction is global so we can free it on module abort */
667c478bd9Sstevel@tonic-gate static struct fme *Nfmep;
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate static const char *Undiag_reason;
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate static int Nextid = 0;
717c478bd9Sstevel@tonic-gate 
72*0cc1f05eSjrutt static int Open_fme_count = 0;	/* Count of open FMEs */
73*0cc1f05eSjrutt 
747c478bd9Sstevel@tonic-gate /* list of fault management exercises underway */
757c478bd9Sstevel@tonic-gate static struct fme {
767c478bd9Sstevel@tonic-gate 	struct fme *next;		/* next exercise */
777c478bd9Sstevel@tonic-gate 	unsigned long long ull;		/* time when fme was created */
787c478bd9Sstevel@tonic-gate 	int id;				/* FME id */
797c478bd9Sstevel@tonic-gate 	struct cfgdata *cfgdata;	/* full configuration data */
807c478bd9Sstevel@tonic-gate 	struct lut *eventtree;		/* propagation tree for this FME */
817c478bd9Sstevel@tonic-gate 	/*
827c478bd9Sstevel@tonic-gate 	 * The initial error report that created this FME is kept in
837c478bd9Sstevel@tonic-gate 	 * two forms.  e0 points to the instance tree node and is used
847c478bd9Sstevel@tonic-gate 	 * by fme_eval() as the starting point for the inference
857c478bd9Sstevel@tonic-gate 	 * algorithm.  e0r is the event handle FMD passed to us when
867c478bd9Sstevel@tonic-gate 	 * the ereport first arrived and is used when setting timers,
877c478bd9Sstevel@tonic-gate 	 * which are always relative to the time of this initial
887c478bd9Sstevel@tonic-gate 	 * report.
897c478bd9Sstevel@tonic-gate 	 */
907c478bd9Sstevel@tonic-gate 	struct event *e0;
917c478bd9Sstevel@tonic-gate 	fmd_event_t *e0r;
927c478bd9Sstevel@tonic-gate 
937c478bd9Sstevel@tonic-gate 	id_t    timer;			/* for setting an fmd time-out */
947c478bd9Sstevel@tonic-gate 	id_t	htid;			/* for setting hesitation timer */
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate 	struct event *ecurrent;		/* ereport under consideration */
977c478bd9Sstevel@tonic-gate 	struct event *suspects;		/* current suspect list */
987c478bd9Sstevel@tonic-gate 	struct event *psuspects;	/* previous suspect list */
997c478bd9Sstevel@tonic-gate 	int nsuspects;			/* count of suspects */
1007c478bd9Sstevel@tonic-gate 	int nonfault;			/* zero if all suspects T_FAULT */
1017c478bd9Sstevel@tonic-gate 	int posted_suspects;		/* true if we've posted a diagnosis */
1027c478bd9Sstevel@tonic-gate 	int hesitated;			/* true if we hesitated */
1037c478bd9Sstevel@tonic-gate 	int uniqobs;			/* number of unique events observed */
1047c478bd9Sstevel@tonic-gate 	int peek;			/* just peeking, don't track suspects */
105*0cc1f05eSjrutt 	int overflow;			/* true if overflow FME */
1067c478bd9Sstevel@tonic-gate 	enum fme_state {
1077c478bd9Sstevel@tonic-gate 		FME_NOTHING = 5000,	/* not evaluated yet */
1087c478bd9Sstevel@tonic-gate 		FME_WAIT,		/* need to wait for more info */
1097c478bd9Sstevel@tonic-gate 		FME_CREDIBLE,		/* suspect list is credible */
1107c478bd9Sstevel@tonic-gate 		FME_DISPROVED		/* no valid suspects found */
1117c478bd9Sstevel@tonic-gate 	} state;
1127c478bd9Sstevel@tonic-gate 
1137c478bd9Sstevel@tonic-gate 	unsigned long long pull;	/* time passed since created */
1147c478bd9Sstevel@tonic-gate 	unsigned long long wull;	/* wait until this time for re-eval */
1157c478bd9Sstevel@tonic-gate 	struct event *observations;	/* observation list */
1167c478bd9Sstevel@tonic-gate 	struct lut *globals;		/* values of global variables */
1177c478bd9Sstevel@tonic-gate 	/* fmd interfacing */
1187c478bd9Sstevel@tonic-gate 	fmd_hdl_t *hdl;			/* handle for talking with fmd */
1197c478bd9Sstevel@tonic-gate 	fmd_case_t *fmcase;		/* what fmd 'case' we associate with */
1207c478bd9Sstevel@tonic-gate 	/* stats */
1217c478bd9Sstevel@tonic-gate 	struct stats *Rcount;
1227c478bd9Sstevel@tonic-gate 	struct stats *Hcallcount;
1237c478bd9Sstevel@tonic-gate 	struct stats *Rcallcount;
1247c478bd9Sstevel@tonic-gate 	struct stats *Ccallcount;
1257c478bd9Sstevel@tonic-gate 	struct stats *Ecallcount;
1267c478bd9Sstevel@tonic-gate 	struct stats *Tcallcount;
1277c478bd9Sstevel@tonic-gate 	struct stats *Marrowcount;
1287c478bd9Sstevel@tonic-gate 	struct stats *diags;
1297c478bd9Sstevel@tonic-gate } *FMElist, *EFMElist, *ClosedFMEs;
1307c478bd9Sstevel@tonic-gate 
1317c478bd9Sstevel@tonic-gate static struct case_list {
1327c478bd9Sstevel@tonic-gate 	fmd_case_t *fmcase;
1337c478bd9Sstevel@tonic-gate 	struct case_list *next;
1347c478bd9Sstevel@tonic-gate } *Undiagablecaselist;
1357c478bd9Sstevel@tonic-gate 
1367c478bd9Sstevel@tonic-gate static void fme_eval(struct fme *fmep, fmd_event_t *ffep);
1377c478bd9Sstevel@tonic-gate static enum fme_state hypothesise(struct fme *fmep, struct event *ep,
1387c478bd9Sstevel@tonic-gate 	unsigned long long at_latest_by, unsigned long long *pdelay,
1397c478bd9Sstevel@tonic-gate 	struct arrow *arrowp);
1407c478bd9Sstevel@tonic-gate static struct node *eventprop_lookup(struct event *ep, const char *propname);
1417c478bd9Sstevel@tonic-gate static struct node *pathstring2epnamenp(char *path);
1427c478bd9Sstevel@tonic-gate static void publish_undiagnosable(fmd_hdl_t *hdl, fmd_event_t *ffep);
1437c478bd9Sstevel@tonic-gate static void restore_suspects(struct fme *fmep);
1447c478bd9Sstevel@tonic-gate static void save_suspects(struct fme *fmep);
1457c478bd9Sstevel@tonic-gate static void destroy_fme(struct fme *f);
1467c478bd9Sstevel@tonic-gate static void fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep,
1477c478bd9Sstevel@tonic-gate     const char *eventstring, const struct ipath *ipp, nvlist_t *nvl);
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate static struct fme *
1507c478bd9Sstevel@tonic-gate alloc_fme(void)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	struct fme *fmep;
1537c478bd9Sstevel@tonic-gate 
1547c478bd9Sstevel@tonic-gate 	fmep = MALLOC(sizeof (*fmep));
1557c478bd9Sstevel@tonic-gate 	bzero(fmep, sizeof (*fmep));
1567c478bd9Sstevel@tonic-gate 	return (fmep);
1577c478bd9Sstevel@tonic-gate }
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate  * fme_ready -- called when all initialization of the FME (except for
1617c478bd9Sstevel@tonic-gate  *	stats) has completed successfully.  Adds the fme to global lists
1627c478bd9Sstevel@tonic-gate  *	and establishes its stats.
1637c478bd9Sstevel@tonic-gate  */
1647c478bd9Sstevel@tonic-gate static struct fme *
1657c478bd9Sstevel@tonic-gate fme_ready(struct fme *fmep)
1667c478bd9Sstevel@tonic-gate {
1677c478bd9Sstevel@tonic-gate 	char nbuf[100];
1687c478bd9Sstevel@tonic-gate 
1697c478bd9Sstevel@tonic-gate 	Nfmep = NULL;	/* don't need to free this on module abort now */
1707c478bd9Sstevel@tonic-gate 
1717c478bd9Sstevel@tonic-gate 	if (EFMElist) {
1727c478bd9Sstevel@tonic-gate 		EFMElist->next = fmep;
1737c478bd9Sstevel@tonic-gate 		EFMElist = fmep;
1747c478bd9Sstevel@tonic-gate 	} else
1757c478bd9Sstevel@tonic-gate 		FMElist = EFMElist = fmep;
1767c478bd9Sstevel@tonic-gate 
1777c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Rcount", fmep->id);
1787c478bd9Sstevel@tonic-gate 	fmep->Rcount = stats_new_counter(nbuf, "ereports received", 0);
1797c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Hcall", fmep->id);
1807c478bd9Sstevel@tonic-gate 	fmep->Hcallcount = stats_new_counter(nbuf, "calls to hypothesise()", 1);
1817c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Rcall", fmep->id);
1827c478bd9Sstevel@tonic-gate 	fmep->Rcallcount = stats_new_counter(nbuf,
1837c478bd9Sstevel@tonic-gate 	    "calls to requirements_test()", 1);
1847c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Ccall", fmep->id);
1857c478bd9Sstevel@tonic-gate 	fmep->Ccallcount = stats_new_counter(nbuf, "calls to causes_test()", 1);
1867c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Ecall", fmep->id);
1877c478bd9Sstevel@tonic-gate 	fmep->Ecallcount =
1887c478bd9Sstevel@tonic-gate 	    stats_new_counter(nbuf, "calls to effects_test()", 1);
1897c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Tcall", fmep->id);
1907c478bd9Sstevel@tonic-gate 	fmep->Tcallcount = stats_new_counter(nbuf, "calls to triggered()", 1);
1917c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.Marrow", fmep->id);
1927c478bd9Sstevel@tonic-gate 	fmep->Marrowcount = stats_new_counter(nbuf,
1937c478bd9Sstevel@tonic-gate 	    "arrows marked by mark_arrows()", 1);
1947c478bd9Sstevel@tonic-gate 	(void) sprintf(nbuf, "fme%d.diags", fmep->id);
1957c478bd9Sstevel@tonic-gate 	fmep->diags = stats_new_counter(nbuf, "suspect lists diagnosed", 0);
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB2, "newfme: config snapshot contains...");
1987c478bd9Sstevel@tonic-gate 	config_print(O_ALTFP|O_VERB2, fmep->cfgdata->cooked);
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate 	return (fmep);
2017c478bd9Sstevel@tonic-gate }
2027c478bd9Sstevel@tonic-gate 
2037c478bd9Sstevel@tonic-gate static struct fme *
2047c478bd9Sstevel@tonic-gate newfme(const char *e0class, const struct ipath *e0ipp)
2057c478bd9Sstevel@tonic-gate {
2067c478bd9Sstevel@tonic-gate 	struct cfgdata *cfgdata;
2077c478bd9Sstevel@tonic-gate 
2087c478bd9Sstevel@tonic-gate 	if ((cfgdata = config_snapshot()) == NULL) {
2097c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "newfme: NULL configuration");
2107c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_NOCONF;
2117c478bd9Sstevel@tonic-gate 		return (NULL);
2127c478bd9Sstevel@tonic-gate 	}
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 	Nfmep = alloc_fme();
2157c478bd9Sstevel@tonic-gate 
2167c478bd9Sstevel@tonic-gate 	Nfmep->id = Nextid++;
2177c478bd9Sstevel@tonic-gate 	Nfmep->cfgdata = cfgdata;
2187c478bd9Sstevel@tonic-gate 	Nfmep->posted_suspects = 0;
2197c478bd9Sstevel@tonic-gate 	Nfmep->uniqobs = 0;
2207c478bd9Sstevel@tonic-gate 	Nfmep->state = FME_NOTHING;
2217c478bd9Sstevel@tonic-gate 	Nfmep->pull = 0ULL;
222*0cc1f05eSjrutt 	Nfmep->overflow = 0;
2237c478bd9Sstevel@tonic-gate 
2247c478bd9Sstevel@tonic-gate 	Nfmep->fmcase = NULL;
2257c478bd9Sstevel@tonic-gate 	Nfmep->hdl = NULL;
2267c478bd9Sstevel@tonic-gate 
2277c478bd9Sstevel@tonic-gate 	if ((Nfmep->eventtree = itree_create(cfgdata->cooked)) == NULL) {
2287c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "newfme: NULL instance tree");
2297c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_INSTFAIL;
2307c478bd9Sstevel@tonic-gate 		config_free(cfgdata);
2317c478bd9Sstevel@tonic-gate 		FREE(Nfmep);
2327c478bd9Sstevel@tonic-gate 		Nfmep = NULL;
2337c478bd9Sstevel@tonic-gate 		return (NULL);
2347c478bd9Sstevel@tonic-gate 	}
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate 	itree_ptree(O_ALTFP|O_VERB2, Nfmep->eventtree);
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	if ((Nfmep->e0 =
2397c478bd9Sstevel@tonic-gate 	    itree_lookup(Nfmep->eventtree, e0class, e0ipp)) == NULL) {
2407c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "newfme: e0 not in instance tree");
2417c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_BADEVENTI;
2427c478bd9Sstevel@tonic-gate 		itree_free(Nfmep->eventtree);
2437c478bd9Sstevel@tonic-gate 		config_free(cfgdata);
2447c478bd9Sstevel@tonic-gate 		FREE(Nfmep);
2457c478bd9Sstevel@tonic-gate 		Nfmep = NULL;
2467c478bd9Sstevel@tonic-gate 		return (NULL);
2477c478bd9Sstevel@tonic-gate 	}
2487c478bd9Sstevel@tonic-gate 
2497c478bd9Sstevel@tonic-gate 	return (fme_ready(Nfmep));
2507c478bd9Sstevel@tonic-gate }
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate void
2537c478bd9Sstevel@tonic-gate fme_fini(void)
2547c478bd9Sstevel@tonic-gate {
2557c478bd9Sstevel@tonic-gate 	struct fme *sfp, *fp;
2567c478bd9Sstevel@tonic-gate 	struct case_list *ucasep, *nextcasep;
2577c478bd9Sstevel@tonic-gate 
2587c478bd9Sstevel@tonic-gate 	ucasep = Undiagablecaselist;
2597c478bd9Sstevel@tonic-gate 	while (ucasep != NULL) {
2607c478bd9Sstevel@tonic-gate 		nextcasep = ucasep->next;
2617c478bd9Sstevel@tonic-gate 		FREE(ucasep);
2627c478bd9Sstevel@tonic-gate 		ucasep = nextcasep;
2637c478bd9Sstevel@tonic-gate 	}
2647c478bd9Sstevel@tonic-gate 	Undiagablecaselist = NULL;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	/* clean up closed fmes */
2677c478bd9Sstevel@tonic-gate 	fp = ClosedFMEs;
2687c478bd9Sstevel@tonic-gate 	while (fp != NULL) {
2697c478bd9Sstevel@tonic-gate 		sfp = fp->next;
2707c478bd9Sstevel@tonic-gate 		destroy_fme(fp);
2717c478bd9Sstevel@tonic-gate 		fp = sfp;
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate 	ClosedFMEs = NULL;
2747c478bd9Sstevel@tonic-gate 
2757c478bd9Sstevel@tonic-gate 	fp = FMElist;
2767c478bd9Sstevel@tonic-gate 	while (fp != NULL) {
2777c478bd9Sstevel@tonic-gate 		sfp = fp->next;
2787c478bd9Sstevel@tonic-gate 		destroy_fme(fp);
2797c478bd9Sstevel@tonic-gate 		fp = sfp;
2807c478bd9Sstevel@tonic-gate 	}
2817c478bd9Sstevel@tonic-gate 	FMElist = EFMElist = NULL;
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate 	/* if we were in the middle of creating an fme, free it now */
2847c478bd9Sstevel@tonic-gate 	if (Nfmep) {
2857c478bd9Sstevel@tonic-gate 		destroy_fme(Nfmep);
2867c478bd9Sstevel@tonic-gate 		Nfmep = NULL;
2877c478bd9Sstevel@tonic-gate 	}
2887c478bd9Sstevel@tonic-gate }
2897c478bd9Sstevel@tonic-gate 
2907c478bd9Sstevel@tonic-gate /*
2917c478bd9Sstevel@tonic-gate  * Allocated space for a buffer name.  20 bytes allows for
2927c478bd9Sstevel@tonic-gate  * a ridiculous 9,999,999 unique observations.
2937c478bd9Sstevel@tonic-gate  */
2947c478bd9Sstevel@tonic-gate #define	OBBUFNMSZ 20
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate /*
2977c478bd9Sstevel@tonic-gate  *  serialize_observation
2987c478bd9Sstevel@tonic-gate  *
2997c478bd9Sstevel@tonic-gate  *  Create a recoverable version of the current observation
3007c478bd9Sstevel@tonic-gate  *  (f->ecurrent).  We keep a serialized version of each unique
3017c478bd9Sstevel@tonic-gate  *  observation in order that we may resume correctly the fme in the
3027c478bd9Sstevel@tonic-gate  *  correct state if eft or fmd crashes and we're restarted.
3037c478bd9Sstevel@tonic-gate  */
3047c478bd9Sstevel@tonic-gate static void
3057c478bd9Sstevel@tonic-gate serialize_observation(struct fme *fp, const char *cls, const struct ipath *ipp)
3067c478bd9Sstevel@tonic-gate {
3077c478bd9Sstevel@tonic-gate 	size_t pkdlen;
3087c478bd9Sstevel@tonic-gate 	char tmpbuf[OBBUFNMSZ];
3097c478bd9Sstevel@tonic-gate 	char *pkd = NULL;
3107c478bd9Sstevel@tonic-gate 	char *estr;
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", fp->uniqobs);
3137c478bd9Sstevel@tonic-gate 	estr = ipath2str(cls, ipp);
3147c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, tmpbuf, strlen(estr) + 1);
3157c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, tmpbuf, (void *)estr,
3167c478bd9Sstevel@tonic-gate 	    strlen(estr) + 1);
3177c478bd9Sstevel@tonic-gate 	FREE(estr);
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate 	if (fp->ecurrent != NULL && fp->ecurrent->nvp != NULL) {
3207c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf,
3217c478bd9Sstevel@tonic-gate 		    OBBUFNMSZ, "observed%d.nvp", fp->uniqobs);
3227c478bd9Sstevel@tonic-gate 		if (nvlist_xpack(fp->ecurrent->nvp,
3237c478bd9Sstevel@tonic-gate 		    &pkd, &pkdlen, NV_ENCODE_XDR, &Eft_nv_hdl) != 0)
3247c478bd9Sstevel@tonic-gate 			out(O_DIE|O_SYS, "pack of observed nvl failed");
3257c478bd9Sstevel@tonic-gate 		fmd_buf_create(fp->hdl, fp->fmcase, tmpbuf, pkdlen);
3267c478bd9Sstevel@tonic-gate 		fmd_buf_write(fp->hdl, fp->fmcase, tmpbuf, (void *)pkd, pkdlen);
3277c478bd9Sstevel@tonic-gate 		FREE(pkd);
3287c478bd9Sstevel@tonic-gate 	}
3297c478bd9Sstevel@tonic-gate 
3307c478bd9Sstevel@tonic-gate 	fp->uniqobs++;
3317c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_NOBS, (void *)&fp->uniqobs,
3327c478bd9Sstevel@tonic-gate 	    sizeof (fp->uniqobs));
3337c478bd9Sstevel@tonic-gate }
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate /*
3367c478bd9Sstevel@tonic-gate  *  init_fme_bufs -- We keep several bits of state about an fme for
3377c478bd9Sstevel@tonic-gate  *	use if eft or fmd crashes and we're restarted.
3387c478bd9Sstevel@tonic-gate  */
3397c478bd9Sstevel@tonic-gate static void
3407c478bd9Sstevel@tonic-gate init_fme_bufs(struct fme *fp)
3417c478bd9Sstevel@tonic-gate {
3427c478bd9Sstevel@tonic-gate 	size_t cfglen = fp->cfgdata->nextfree - fp->cfgdata->begin;
3437c478bd9Sstevel@tonic-gate 
3447c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_CFGLEN, sizeof (cfglen));
3457c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_CFGLEN, (void *)&cfglen,
3467c478bd9Sstevel@tonic-gate 	    sizeof (cfglen));
3477c478bd9Sstevel@tonic-gate 	if (cfglen != 0) {
3487c478bd9Sstevel@tonic-gate 		fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_CFG, cfglen);
3497c478bd9Sstevel@tonic-gate 		fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_CFG,
3507c478bd9Sstevel@tonic-gate 		    fp->cfgdata->begin, cfglen);
3517c478bd9Sstevel@tonic-gate 	}
3527c478bd9Sstevel@tonic-gate 
3537c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_PULL, sizeof (fp->pull));
3547c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_PULL, (void *)&fp->pull,
3557c478bd9Sstevel@tonic-gate 	    sizeof (fp->pull));
3567c478bd9Sstevel@tonic-gate 
3577c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_ID, sizeof (fp->id));
3587c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_ID, (void *)&fp->id,
3597c478bd9Sstevel@tonic-gate 	    sizeof (fp->id));
3607c478bd9Sstevel@tonic-gate 
3617c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_NOBS, sizeof (fp->uniqobs));
3627c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_NOBS, (void *)&fp->uniqobs,
3637c478bd9Sstevel@tonic-gate 	    sizeof (fp->uniqobs));
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_POSTD,
3667c478bd9Sstevel@tonic-gate 	    sizeof (fp->posted_suspects));
3677c478bd9Sstevel@tonic-gate 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_POSTD,
3687c478bd9Sstevel@tonic-gate 	    (void *)&fp->posted_suspects, sizeof (fp->posted_suspects));
3697c478bd9Sstevel@tonic-gate }
3707c478bd9Sstevel@tonic-gate 
3717c478bd9Sstevel@tonic-gate static void
3727c478bd9Sstevel@tonic-gate destroy_fme_bufs(struct fme *fp)
3737c478bd9Sstevel@tonic-gate {
3747c478bd9Sstevel@tonic-gate 	char tmpbuf[OBBUFNMSZ];
3757c478bd9Sstevel@tonic-gate 	int o;
3767c478bd9Sstevel@tonic-gate 
3777c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_CFGLEN);
3787c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_CFG);
3797c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_PULL);
3807c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_ID);
3817c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_POSTD);
3827c478bd9Sstevel@tonic-gate 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_NOBS);
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate 	for (o = 0; o < fp->uniqobs; o++) {
3857c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", o);
3867c478bd9Sstevel@tonic-gate 		fmd_buf_destroy(fp->hdl, fp->fmcase, tmpbuf);
3877c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d.nvp", o);
3887c478bd9Sstevel@tonic-gate 		fmd_buf_destroy(fp->hdl, fp->fmcase, tmpbuf);
3897c478bd9Sstevel@tonic-gate 	}
3907c478bd9Sstevel@tonic-gate }
3917c478bd9Sstevel@tonic-gate 
3927c478bd9Sstevel@tonic-gate /*
3937c478bd9Sstevel@tonic-gate  * reconstitute_observations -- convert a case's serialized observations
3947c478bd9Sstevel@tonic-gate  *	back into struct events.  Returns zero if all observations are
3957c478bd9Sstevel@tonic-gate  *	successfully reconstituted.
3967c478bd9Sstevel@tonic-gate  */
3977c478bd9Sstevel@tonic-gate static int
3987c478bd9Sstevel@tonic-gate reconstitute_observations(struct fme *fmep)
3997c478bd9Sstevel@tonic-gate {
4007c478bd9Sstevel@tonic-gate 	struct event *ep;
4017c478bd9Sstevel@tonic-gate 	struct node *epnamenp = NULL;
4027c478bd9Sstevel@tonic-gate 	size_t pkdlen;
4037c478bd9Sstevel@tonic-gate 	char *pkd = NULL;
4047c478bd9Sstevel@tonic-gate 	char *tmpbuf = alloca(OBBUFNMSZ);
4057c478bd9Sstevel@tonic-gate 	char *sepptr;
4067c478bd9Sstevel@tonic-gate 	char *estr;
4077c478bd9Sstevel@tonic-gate 	int ocnt;
4087c478bd9Sstevel@tonic-gate 	int elen;
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	for (ocnt = 0; ocnt < fmep->uniqobs; ocnt++) {
4117c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", ocnt);
4127c478bd9Sstevel@tonic-gate 		elen = fmd_buf_size(fmep->hdl, fmep->fmcase, tmpbuf);
4137c478bd9Sstevel@tonic-gate 		if (elen == 0) {
4147c478bd9Sstevel@tonic-gate 			out(O_ALTFP,
4157c478bd9Sstevel@tonic-gate 			    "reconstitute_observation: no %s buffer found.",
4167c478bd9Sstevel@tonic-gate 			    tmpbuf);
4177c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_MISSINGOBS;
4187c478bd9Sstevel@tonic-gate 			break;
4197c478bd9Sstevel@tonic-gate 		}
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 		estr = MALLOC(elen);
4227c478bd9Sstevel@tonic-gate 		fmd_buf_read(fmep->hdl, fmep->fmcase, tmpbuf, estr, elen);
4237c478bd9Sstevel@tonic-gate 		sepptr = strchr(estr, '@');
4247c478bd9Sstevel@tonic-gate 		if (sepptr == NULL) {
4257c478bd9Sstevel@tonic-gate 			out(O_ALTFP,
4267c478bd9Sstevel@tonic-gate 			    "reconstitute_observation: %s: "
4277c478bd9Sstevel@tonic-gate 			    "missing @ separator in %s.",
4287c478bd9Sstevel@tonic-gate 			    tmpbuf, estr);
4297c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_MISSINGPATH;
4307c478bd9Sstevel@tonic-gate 			FREE(estr);
4317c478bd9Sstevel@tonic-gate 			break;
4327c478bd9Sstevel@tonic-gate 		}
4337c478bd9Sstevel@tonic-gate 
4347c478bd9Sstevel@tonic-gate 		*sepptr = '\0';
4357c478bd9Sstevel@tonic-gate 		if ((epnamenp = pathstring2epnamenp(sepptr + 1)) == NULL) {
4367c478bd9Sstevel@tonic-gate 			out(O_ALTFP,
4377c478bd9Sstevel@tonic-gate 			    "reconstitute_observation: %s: "
4387c478bd9Sstevel@tonic-gate 			    "trouble converting path string \"%s\" "
4397c478bd9Sstevel@tonic-gate 			    "to internal representation.",
4407c478bd9Sstevel@tonic-gate 			    tmpbuf, sepptr + 1);
4417c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_MISSINGPATH;
4427c478bd9Sstevel@tonic-gate 			FREE(estr);
4437c478bd9Sstevel@tonic-gate 			break;
4447c478bd9Sstevel@tonic-gate 		}
4457c478bd9Sstevel@tonic-gate 
4467c478bd9Sstevel@tonic-gate 		/* construct the event */
4477c478bd9Sstevel@tonic-gate 		ep = itree_lookup(fmep->eventtree,
4487c478bd9Sstevel@tonic-gate 		    stable(estr), ipath(epnamenp));
4497c478bd9Sstevel@tonic-gate 		if (ep == NULL) {
4507c478bd9Sstevel@tonic-gate 			out(O_ALTFP,
4517c478bd9Sstevel@tonic-gate 			    "reconstitute_observation: %s: "
4527c478bd9Sstevel@tonic-gate 			    "lookup of  \"%s\" in itree failed.",
4537c478bd9Sstevel@tonic-gate 			    tmpbuf, ipath2str(estr, ipath(epnamenp)));
4547c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_BADOBS;
4557c478bd9Sstevel@tonic-gate 			tree_free(epnamenp);
4567c478bd9Sstevel@tonic-gate 			FREE(estr);
4577c478bd9Sstevel@tonic-gate 			break;
4587c478bd9Sstevel@tonic-gate 		}
4597c478bd9Sstevel@tonic-gate 		tree_free(epnamenp);
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate 		/*
4627c478bd9Sstevel@tonic-gate 		 * We may or may not have a saved nvlist for the observation
4637c478bd9Sstevel@tonic-gate 		 */
4647c478bd9Sstevel@tonic-gate 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d.nvp", ocnt);
4657c478bd9Sstevel@tonic-gate 		pkdlen = fmd_buf_size(fmep->hdl, fmep->fmcase, tmpbuf);
4667c478bd9Sstevel@tonic-gate 		if (pkdlen != 0) {
4677c478bd9Sstevel@tonic-gate 			pkd = MALLOC(pkdlen);
4687c478bd9Sstevel@tonic-gate 			fmd_buf_read(fmep->hdl,
4697c478bd9Sstevel@tonic-gate 			    fmep->fmcase, tmpbuf, pkd, pkdlen);
4707c478bd9Sstevel@tonic-gate 			if (nvlist_xunpack(pkd,
4717c478bd9Sstevel@tonic-gate 			    pkdlen, &ep->nvp, &Eft_nv_hdl) != 0)
4727c478bd9Sstevel@tonic-gate 				out(O_DIE|O_SYS, "pack of observed nvl failed");
4737c478bd9Sstevel@tonic-gate 			FREE(pkd);
4747c478bd9Sstevel@tonic-gate 		}
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate 		if (ocnt == 0)
4777c478bd9Sstevel@tonic-gate 			fmep->e0 = ep;
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 		FREE(estr);
4807c478bd9Sstevel@tonic-gate 		fmep->ecurrent = ep;
4817c478bd9Sstevel@tonic-gate 		ep->count++;
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate 		/* link it into list of observations seen */
4847c478bd9Sstevel@tonic-gate 		ep->observations = fmep->observations;
4857c478bd9Sstevel@tonic-gate 		fmep->observations = ep;
4867c478bd9Sstevel@tonic-gate 	}
4877c478bd9Sstevel@tonic-gate 
4887c478bd9Sstevel@tonic-gate 	if (ocnt == fmep->uniqobs) {
4897c478bd9Sstevel@tonic-gate 		(void) fme_ready(fmep);
4907c478bd9Sstevel@tonic-gate 		return (0);
4917c478bd9Sstevel@tonic-gate 	}
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate 	return (1);
4947c478bd9Sstevel@tonic-gate }
4957c478bd9Sstevel@tonic-gate 
4967c478bd9Sstevel@tonic-gate /*
4977c478bd9Sstevel@tonic-gate  * restart_fme -- called during eft initialization.  Reconstitutes
4987c478bd9Sstevel@tonic-gate  *	an in-progress fme.
4997c478bd9Sstevel@tonic-gate  */
5007c478bd9Sstevel@tonic-gate void
5017c478bd9Sstevel@tonic-gate fme_restart(fmd_hdl_t *hdl, fmd_case_t *inprogress)
5027c478bd9Sstevel@tonic-gate {
5037c478bd9Sstevel@tonic-gate 	nvlist_t *defect;
5047c478bd9Sstevel@tonic-gate 	struct case_list *bad;
5057c478bd9Sstevel@tonic-gate 	struct fme *fmep;
5067c478bd9Sstevel@tonic-gate 	struct cfgdata *cfgdata = NULL;
5077c478bd9Sstevel@tonic-gate 	size_t rawsz;
5087c478bd9Sstevel@tonic-gate 
5097c478bd9Sstevel@tonic-gate 	fmep = alloc_fme();
5107c478bd9Sstevel@tonic-gate 	fmep->fmcase = inprogress;
5117c478bd9Sstevel@tonic-gate 	fmep->hdl = hdl;
5127c478bd9Sstevel@tonic-gate 
5137c478bd9Sstevel@tonic-gate 	if (fmd_buf_size(hdl, inprogress, WOBUF_CFGLEN) != sizeof (size_t)) {
5147c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: No config data");
5157c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGINFO;
5167c478bd9Sstevel@tonic-gate 		goto badcase;
5177c478bd9Sstevel@tonic-gate 	}
5187c478bd9Sstevel@tonic-gate 	fmd_buf_read(hdl, inprogress, WOBUF_CFGLEN, (void *)&rawsz,
5197c478bd9Sstevel@tonic-gate 	    sizeof (size_t));
5207c478bd9Sstevel@tonic-gate 
5217c478bd9Sstevel@tonic-gate 	if ((fmep->e0r = fmd_case_getprincipal(hdl, inprogress)) == NULL) {
5227c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: No event zero");
5237c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGZERO;
5247c478bd9Sstevel@tonic-gate 		goto badcase;
5257c478bd9Sstevel@tonic-gate 	}
5267c478bd9Sstevel@tonic-gate 
5277c478bd9Sstevel@tonic-gate 	cfgdata = MALLOC(sizeof (struct cfgdata));
5287c478bd9Sstevel@tonic-gate 	cfgdata->cooked = NULL;
5297c478bd9Sstevel@tonic-gate 	cfgdata->devcache = NULL;
5307c478bd9Sstevel@tonic-gate 	cfgdata->cpucache = NULL;
5317c478bd9Sstevel@tonic-gate 	cfgdata->refcnt = 1;
5327c478bd9Sstevel@tonic-gate 
5337c478bd9Sstevel@tonic-gate 	if (rawsz > 0) {
5347c478bd9Sstevel@tonic-gate 		if (fmd_buf_size(hdl, inprogress, WOBUF_CFG) != rawsz) {
5357c478bd9Sstevel@tonic-gate 			out(O_ALTFP, "restart_fme: Config data size mismatch");
5367c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_CFGMISMATCH;
5377c478bd9Sstevel@tonic-gate 			goto badcase;
5387c478bd9Sstevel@tonic-gate 		}
5397c478bd9Sstevel@tonic-gate 		cfgdata->begin = MALLOC(rawsz);
5407c478bd9Sstevel@tonic-gate 		cfgdata->end = cfgdata->nextfree = cfgdata->begin + rawsz;
5417c478bd9Sstevel@tonic-gate 		fmd_buf_read(hdl,
5427c478bd9Sstevel@tonic-gate 		    inprogress, WOBUF_CFG, cfgdata->begin, rawsz);
5437c478bd9Sstevel@tonic-gate 	} else {
5447c478bd9Sstevel@tonic-gate 		cfgdata->begin = cfgdata->end = cfgdata->nextfree = NULL;
5457c478bd9Sstevel@tonic-gate 	}
5467c478bd9Sstevel@tonic-gate 	fmep->cfgdata = cfgdata;
5477c478bd9Sstevel@tonic-gate 
5487c478bd9Sstevel@tonic-gate 	config_cook(cfgdata);
5497c478bd9Sstevel@tonic-gate 	if ((fmep->eventtree = itree_create(cfgdata->cooked)) == NULL) {
5507c478bd9Sstevel@tonic-gate 		/* case not properly saved or irretrievable */
5517c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: NULL instance tree");
5527c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_INSTFAIL;
5537c478bd9Sstevel@tonic-gate 		goto badcase;
5547c478bd9Sstevel@tonic-gate 	}
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 	itree_ptree(O_ALTFP|O_VERB2, fmep->eventtree);
5577c478bd9Sstevel@tonic-gate 
5587c478bd9Sstevel@tonic-gate 	if (fmd_buf_size(hdl, inprogress, WOBUF_PULL) == 0) {
5597c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: no saved wait time");
5607c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGINFO;
5617c478bd9Sstevel@tonic-gate 		goto badcase;
5627c478bd9Sstevel@tonic-gate 	} else {
5637c478bd9Sstevel@tonic-gate 		fmd_buf_read(hdl, inprogress, WOBUF_PULL, (void *)&fmep->pull,
5647c478bd9Sstevel@tonic-gate 		    sizeof (fmep->pull));
5657c478bd9Sstevel@tonic-gate 	}
5667c478bd9Sstevel@tonic-gate 
5677c478bd9Sstevel@tonic-gate 	if (fmd_buf_size(hdl, inprogress, WOBUF_POSTD) == 0) {
5687c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: no saved posted status");
5697c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGINFO;
5707c478bd9Sstevel@tonic-gate 		goto badcase;
5717c478bd9Sstevel@tonic-gate 	} else {
5727c478bd9Sstevel@tonic-gate 		fmd_buf_read(hdl, inprogress, WOBUF_POSTD,
5737c478bd9Sstevel@tonic-gate 		    (void *)&fmep->posted_suspects,
5747c478bd9Sstevel@tonic-gate 		    sizeof (fmep->posted_suspects));
5757c478bd9Sstevel@tonic-gate 	}
5767c478bd9Sstevel@tonic-gate 
5777c478bd9Sstevel@tonic-gate 	if (fmd_buf_size(hdl, inprogress, WOBUF_ID) == 0) {
5787c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: no saved id");
5797c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGINFO;
5807c478bd9Sstevel@tonic-gate 		goto badcase;
5817c478bd9Sstevel@tonic-gate 	} else {
5827c478bd9Sstevel@tonic-gate 		fmd_buf_read(hdl, inprogress, WOBUF_ID, (void *)&fmep->id,
5837c478bd9Sstevel@tonic-gate 		    sizeof (fmep->id));
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 	if (Nextid <= fmep->id)
5867c478bd9Sstevel@tonic-gate 		Nextid = fmep->id + 1;
5877c478bd9Sstevel@tonic-gate 
5887c478bd9Sstevel@tonic-gate 	if (fmd_buf_size(hdl, inprogress, WOBUF_NOBS) == 0) {
5897c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "restart_fme: no count of observations");
5907c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_MISSINGINFO;
5917c478bd9Sstevel@tonic-gate 		goto badcase;
5927c478bd9Sstevel@tonic-gate 	} else {
5937c478bd9Sstevel@tonic-gate 		fmd_buf_read(hdl, inprogress, WOBUF_NOBS,
5947c478bd9Sstevel@tonic-gate 		    (void *)&fmep->uniqobs, sizeof (fmep->uniqobs));
5957c478bd9Sstevel@tonic-gate 	}
5967c478bd9Sstevel@tonic-gate 
5977c478bd9Sstevel@tonic-gate 	if (reconstitute_observations(fmep) != 0)
5987c478bd9Sstevel@tonic-gate 		goto badcase;
5997c478bd9Sstevel@tonic-gate 
600*0cc1f05eSjrutt 	Open_fme_count++;
601*0cc1f05eSjrutt 
6027c478bd9Sstevel@tonic-gate 	/* give the diagnosis algorithm a shot at the new FME state */
6037c478bd9Sstevel@tonic-gate 	fme_eval(fmep, NULL);
6047c478bd9Sstevel@tonic-gate 	return;
6057c478bd9Sstevel@tonic-gate 
6067c478bd9Sstevel@tonic-gate badcase:
6077c478bd9Sstevel@tonic-gate 	if (fmep->eventtree != NULL)
6087c478bd9Sstevel@tonic-gate 		itree_free(fmep->eventtree);
6097c478bd9Sstevel@tonic-gate 	config_free(cfgdata);
6107c478bd9Sstevel@tonic-gate 	destroy_fme_bufs(fmep);
6117c478bd9Sstevel@tonic-gate 	FREE(fmep);
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 	/*
6147c478bd9Sstevel@tonic-gate 	 * Since we're unable to restart the case, add it to the undiagable
6157c478bd9Sstevel@tonic-gate 	 * list and solve and close it as appropriate.
6167c478bd9Sstevel@tonic-gate 	 */
6177c478bd9Sstevel@tonic-gate 	bad = MALLOC(sizeof (struct case_list));
6187c478bd9Sstevel@tonic-gate 	bad->next = NULL;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	if (Undiagablecaselist != NULL)
6217c478bd9Sstevel@tonic-gate 		bad->next = Undiagablecaselist;
6227c478bd9Sstevel@tonic-gate 	Undiagablecaselist = bad;
6237c478bd9Sstevel@tonic-gate 	bad->fmcase = inprogress;
6247c478bd9Sstevel@tonic-gate 
6257c478bd9Sstevel@tonic-gate 	out(O_ALTFP, "[case %s (unable to restart), ",
6267c478bd9Sstevel@tonic-gate 	    fmd_case_uuid(hdl, bad->fmcase));
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	if (fmd_case_solved(hdl, bad->fmcase)) {
6297c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "already solved, ");
6307c478bd9Sstevel@tonic-gate 	} else {
6317c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "solving, ");
6327c478bd9Sstevel@tonic-gate 		defect = fmd_nvl_create_fault(hdl, UNDIAGNOSABLE_DEFECT, 100,
6337c478bd9Sstevel@tonic-gate 		    NULL, NULL, NULL);
6347c478bd9Sstevel@tonic-gate 		if (Undiag_reason != NULL)
6357c478bd9Sstevel@tonic-gate 			(void) nvlist_add_string(defect,
6367c478bd9Sstevel@tonic-gate 			    UNDIAG_REASON, Undiag_reason);
6377c478bd9Sstevel@tonic-gate 		fmd_case_add_suspect(hdl, bad->fmcase, defect);
6387c478bd9Sstevel@tonic-gate 		fmd_case_solve(hdl, bad->fmcase);
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	if (fmd_case_closed(hdl, bad->fmcase)) {
6427c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "already closed ]");
6437c478bd9Sstevel@tonic-gate 	} else {
6447c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "closing ]");
6457c478bd9Sstevel@tonic-gate 		fmd_case_close(hdl, bad->fmcase);
6467c478bd9Sstevel@tonic-gate 	}
6477c478bd9Sstevel@tonic-gate }
6487c478bd9Sstevel@tonic-gate 
6497c478bd9Sstevel@tonic-gate void
6507c478bd9Sstevel@tonic-gate destroy_fme(struct fme *f)
6517c478bd9Sstevel@tonic-gate {
6527c478bd9Sstevel@tonic-gate 	stats_delete(f->Rcount);
6537c478bd9Sstevel@tonic-gate 	stats_delete(f->Hcallcount);
6547c478bd9Sstevel@tonic-gate 	stats_delete(f->Rcallcount);
6557c478bd9Sstevel@tonic-gate 	stats_delete(f->Ccallcount);
6567c478bd9Sstevel@tonic-gate 	stats_delete(f->Ecallcount);
6577c478bd9Sstevel@tonic-gate 	stats_delete(f->Tcallcount);
6587c478bd9Sstevel@tonic-gate 	stats_delete(f->Marrowcount);
6597c478bd9Sstevel@tonic-gate 	stats_delete(f->diags);
6607c478bd9Sstevel@tonic-gate 
6617c478bd9Sstevel@tonic-gate 	itree_free(f->eventtree);
6627c478bd9Sstevel@tonic-gate 	config_free(f->cfgdata);
6637c478bd9Sstevel@tonic-gate 	FREE(f);
6647c478bd9Sstevel@tonic-gate }
6657c478bd9Sstevel@tonic-gate 
6667c478bd9Sstevel@tonic-gate static const char *
6677c478bd9Sstevel@tonic-gate fme_state2str(enum fme_state s)
6687c478bd9Sstevel@tonic-gate {
6697c478bd9Sstevel@tonic-gate 	switch (s) {
6707c478bd9Sstevel@tonic-gate 	case FME_NOTHING:	return ("NOTHING");
6717c478bd9Sstevel@tonic-gate 	case FME_WAIT:		return ("WAIT");
6727c478bd9Sstevel@tonic-gate 	case FME_CREDIBLE:	return ("CREDIBLE");
6737c478bd9Sstevel@tonic-gate 	case FME_DISPROVED:	return ("DISPROVED");
6747c478bd9Sstevel@tonic-gate 	default:		return ("UNKNOWN");
6757c478bd9Sstevel@tonic-gate 	}
6767c478bd9Sstevel@tonic-gate }
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate static int
6797c478bd9Sstevel@tonic-gate is_problem(enum nametype t)
6807c478bd9Sstevel@tonic-gate {
6817c478bd9Sstevel@tonic-gate 	return (t == N_FAULT || t == N_DEFECT || t == N_UPSET);
6827c478bd9Sstevel@tonic-gate }
6837c478bd9Sstevel@tonic-gate 
6847c478bd9Sstevel@tonic-gate static int
6857c478bd9Sstevel@tonic-gate is_fault(enum nametype t)
6867c478bd9Sstevel@tonic-gate {
6877c478bd9Sstevel@tonic-gate 	return (t == N_FAULT);
6887c478bd9Sstevel@tonic-gate }
6897c478bd9Sstevel@tonic-gate 
6907c478bd9Sstevel@tonic-gate static int
6917c478bd9Sstevel@tonic-gate is_defect(enum nametype t)
6927c478bd9Sstevel@tonic-gate {
6937c478bd9Sstevel@tonic-gate 	return (t == N_DEFECT);
6947c478bd9Sstevel@tonic-gate }
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate static int
6977c478bd9Sstevel@tonic-gate is_upset(enum nametype t)
6987c478bd9Sstevel@tonic-gate {
6997c478bd9Sstevel@tonic-gate 	return (t == N_UPSET);
7007c478bd9Sstevel@tonic-gate }
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate /*ARGSUSED*/
7037c478bd9Sstevel@tonic-gate static void
7047c478bd9Sstevel@tonic-gate clear_causes_tested(struct event *lhs, struct event *ep, void *arg)
7057c478bd9Sstevel@tonic-gate {
7067c478bd9Sstevel@tonic-gate 	struct bubble *bp;
7077c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
7087c478bd9Sstevel@tonic-gate 
7097c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
7107c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
7117c478bd9Sstevel@tonic-gate 		if (bp->t != B_FROM)
7127c478bd9Sstevel@tonic-gate 			continue;
7137c478bd9Sstevel@tonic-gate 		for (ap = itree_next_arrow(bp, NULL); ap;
7147c478bd9Sstevel@tonic-gate 		    ap = itree_next_arrow(bp, ap))
7157c478bd9Sstevel@tonic-gate 			ap->arrowp->causes_tested = 0;
7167c478bd9Sstevel@tonic-gate 	}
7177c478bd9Sstevel@tonic-gate }
7187c478bd9Sstevel@tonic-gate 
7197c478bd9Sstevel@tonic-gate /*
7207c478bd9Sstevel@tonic-gate  * call this function with initcode set to 0 to initialize cycle tracking
7217c478bd9Sstevel@tonic-gate  */
7227c478bd9Sstevel@tonic-gate static void
7237c478bd9Sstevel@tonic-gate initialize_cycles(struct fme *fmep)
7247c478bd9Sstevel@tonic-gate {
7257c478bd9Sstevel@tonic-gate 	lut_walk(fmep->eventtree, (lut_cb)clear_causes_tested, NULL);
7267c478bd9Sstevel@tonic-gate }
7277c478bd9Sstevel@tonic-gate 
7287c478bd9Sstevel@tonic-gate static void
7297c478bd9Sstevel@tonic-gate fme_print(int flags, struct fme *fmep)
7307c478bd9Sstevel@tonic-gate {
7317c478bd9Sstevel@tonic-gate 	struct event *ep;
7327c478bd9Sstevel@tonic-gate 
7337c478bd9Sstevel@tonic-gate 	out(flags, "Fault Management Exercise %d", fmep->id);
7347c478bd9Sstevel@tonic-gate 	out(flags, "\t       State: %s", fme_state2str(fmep->state));
7357c478bd9Sstevel@tonic-gate 	out(flags|O_NONL, "\t  Start time: ");
7367c478bd9Sstevel@tonic-gate 	ptree_timeval(flags|O_NONL, &fmep->ull);
7377c478bd9Sstevel@tonic-gate 	out(flags, NULL);
7387c478bd9Sstevel@tonic-gate 	if (fmep->wull) {
7397c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, "\t   Wait time: ");
7407c478bd9Sstevel@tonic-gate 		ptree_timeval(flags|O_NONL, &fmep->wull);
7417c478bd9Sstevel@tonic-gate 		out(flags, NULL);
7427c478bd9Sstevel@tonic-gate 	}
7437c478bd9Sstevel@tonic-gate 	out(flags|O_NONL, "\t          E0: ");
7447c478bd9Sstevel@tonic-gate 	if (fmep->e0)
7457c478bd9Sstevel@tonic-gate 		itree_pevent_brief(flags|O_NONL, fmep->e0);
7467c478bd9Sstevel@tonic-gate 	else
7477c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, "NULL");
7487c478bd9Sstevel@tonic-gate 	out(flags, NULL);
7497c478bd9Sstevel@tonic-gate 	out(flags|O_NONL, "\tObservations:");
7507c478bd9Sstevel@tonic-gate 	for (ep = fmep->observations; ep; ep = ep->observations) {
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_NONL, "\tSuspect list:");
7567c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = ep->suspects) {
7577c478bd9Sstevel@tonic-gate 		out(flags|O_NONL, " ");
7587c478bd9Sstevel@tonic-gate 		itree_pevent_brief(flags|O_NONL, ep);
7597c478bd9Sstevel@tonic-gate 	}
7607c478bd9Sstevel@tonic-gate 	out(flags, NULL);
7617c478bd9Sstevel@tonic-gate 	out(flags|O_VERB2, "\t        Tree:");
7627c478bd9Sstevel@tonic-gate 	itree_ptree(flags|O_VERB2, fmep->eventtree);
7637c478bd9Sstevel@tonic-gate }
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate static struct node *
7667c478bd9Sstevel@tonic-gate pathstring2epnamenp(char *path)
7677c478bd9Sstevel@tonic-gate {
7687c478bd9Sstevel@tonic-gate 	char *sep = "/";
7697c478bd9Sstevel@tonic-gate 	struct node *ret;
7707c478bd9Sstevel@tonic-gate 	char *ptr;
7717c478bd9Sstevel@tonic-gate 
7727c478bd9Sstevel@tonic-gate 	if ((ptr = strtok(path, sep)) == NULL)
7737c478bd9Sstevel@tonic-gate 		out(O_DIE, "pathstring2epnamenp: invalid empty class");
7747c478bd9Sstevel@tonic-gate 
7757c478bd9Sstevel@tonic-gate 	ret = tree_iname(stable(ptr), NULL, 0);
7767c478bd9Sstevel@tonic-gate 
7777c478bd9Sstevel@tonic-gate 	while ((ptr = strtok(NULL, sep)) != NULL)
7787c478bd9Sstevel@tonic-gate 		ret = tree_name_append(ret,
7797c478bd9Sstevel@tonic-gate 		    tree_iname(stable(ptr), NULL, 0));
7807c478bd9Sstevel@tonic-gate 
7817c478bd9Sstevel@tonic-gate 	return (ret);
7827c478bd9Sstevel@tonic-gate }
7837c478bd9Sstevel@tonic-gate 
7847c478bd9Sstevel@tonic-gate /*
7857c478bd9Sstevel@tonic-gate  * for a given upset sp, increment the corresponding SERD engine.  if the
7867c478bd9Sstevel@tonic-gate  * SERD engine trips, return the ename and ipp of the resulting ereport.
7877c478bd9Sstevel@tonic-gate  * returns true if engine tripped and *enamep and *ippp were filled in.
7887c478bd9Sstevel@tonic-gate  */
7897c478bd9Sstevel@tonic-gate static int
7903e8d8e18Sdb serd_eval(fmd_hdl_t *hdl, fmd_event_t *ffep, fmd_case_t *fmcase,
7913e8d8e18Sdb 	struct event *sp, const char **enamep, const struct ipath **ippp)
7927c478bd9Sstevel@tonic-gate {
7937c478bd9Sstevel@tonic-gate 	struct node *serdinst;
7947c478bd9Sstevel@tonic-gate 	char *serdname;
7957c478bd9Sstevel@tonic-gate 
7967c478bd9Sstevel@tonic-gate 	ASSERT(sp->t == N_UPSET);
7977c478bd9Sstevel@tonic-gate 	ASSERT(ffep != NULL);
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	/*
8007c478bd9Sstevel@tonic-gate 	 * obtain instanced SERD engine from the upset sp.  from this
8017c478bd9Sstevel@tonic-gate 	 * derive serdname, the string used to identify the SERD engine.
8027c478bd9Sstevel@tonic-gate 	 */
8037c478bd9Sstevel@tonic-gate 	serdinst = eventprop_lookup(sp, L_engine);
8047c478bd9Sstevel@tonic-gate 
8057c478bd9Sstevel@tonic-gate 	if (serdinst == NULL)
8067c478bd9Sstevel@tonic-gate 		return (NULL);
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	serdname = ipath2str(serdinst->u.stmt.np->u.event.ename->u.name.s,
8097c478bd9Sstevel@tonic-gate 	    ipath(serdinst->u.stmt.np->u.event.epname));
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate 	if (!fmd_serd_exists(hdl, serdname)) {
8127c478bd9Sstevel@tonic-gate 		struct node *nN, *nT;
8137c478bd9Sstevel@tonic-gate 
8147c478bd9Sstevel@tonic-gate 		/* no SERD engine yet, so create it */
8157c478bd9Sstevel@tonic-gate 		nN = lut_lookup(serdinst->u.stmt.lutp, (void *)L_N, NULL);
8167c478bd9Sstevel@tonic-gate 		nT = lut_lookup(serdinst->u.stmt.lutp, (void *)L_T, NULL);
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 		ASSERT(nN->t == T_NUM);
8197c478bd9Sstevel@tonic-gate 		ASSERT(nT->t == T_TIMEVAL);
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 		fmd_serd_create(hdl, serdname, (uint_t)nN->u.ull,
8227c478bd9Sstevel@tonic-gate 		    (hrtime_t)nT->u.ull);
8237c478bd9Sstevel@tonic-gate 	}
8247c478bd9Sstevel@tonic-gate 
8257c478bd9Sstevel@tonic-gate 
8267c478bd9Sstevel@tonic-gate 	/*
8277c478bd9Sstevel@tonic-gate 	 * increment SERD engine.  if engine fires, reset serd
8287c478bd9Sstevel@tonic-gate 	 * engine and return trip_strcode
8297c478bd9Sstevel@tonic-gate 	 */
8307c478bd9Sstevel@tonic-gate 	if (fmd_serd_record(hdl, serdname, ffep)) {
8317c478bd9Sstevel@tonic-gate 		struct node *tripinst = lut_lookup(serdinst->u.stmt.lutp,
8327c478bd9Sstevel@tonic-gate 		    (void *)L_trip, NULL);
8337c478bd9Sstevel@tonic-gate 
8347c478bd9Sstevel@tonic-gate 		ASSERT(tripinst != NULL);
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 		*enamep = tripinst->u.event.ename->u.name.s;
8377c478bd9Sstevel@tonic-gate 		*ippp = ipath(tripinst->u.event.epname);
8387c478bd9Sstevel@tonic-gate 
8393e8d8e18Sdb 		fmd_case_add_serd(hdl, fmcase, serdname);
8407c478bd9Sstevel@tonic-gate 		fmd_serd_reset(hdl, serdname);
8417c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "[engine fired: %s, sending: ", serdname);
8427c478bd9Sstevel@tonic-gate 		ipath_print(O_ALTFP|O_NONL, *enamep, *ippp);
8437c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "]");
8447c478bd9Sstevel@tonic-gate 
8457c478bd9Sstevel@tonic-gate 		FREE(serdname);
8467c478bd9Sstevel@tonic-gate 		return (1);
8477c478bd9Sstevel@tonic-gate 	}
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate 	FREE(serdname);
8507c478bd9Sstevel@tonic-gate 	return (0);
8517c478bd9Sstevel@tonic-gate }
8527c478bd9Sstevel@tonic-gate 
8537c478bd9Sstevel@tonic-gate /*
8547c478bd9Sstevel@tonic-gate  * search a suspect list for upsets.  feed each upset to serd_eval() and
8557c478bd9Sstevel@tonic-gate  * build up tripped[], an array of ereports produced by the firing of
8567c478bd9Sstevel@tonic-gate  * any SERD engines.  then feed each ereport back into
8577c478bd9Sstevel@tonic-gate  * fme_receive_report().
8587c478bd9Sstevel@tonic-gate  *
8597c478bd9Sstevel@tonic-gate  * returns ntrip, the number of these ereports produced.
8607c478bd9Sstevel@tonic-gate  */
8617c478bd9Sstevel@tonic-gate static int
8627c478bd9Sstevel@tonic-gate upsets_eval(struct fme *fmep, fmd_event_t *ffep)
8637c478bd9Sstevel@tonic-gate {
8647c478bd9Sstevel@tonic-gate 	/* we build an array of tripped ereports that we send ourselves */
8657c478bd9Sstevel@tonic-gate 	struct {
8667c478bd9Sstevel@tonic-gate 		const char *ename;
8677c478bd9Sstevel@tonic-gate 		const struct ipath *ipp;
8687c478bd9Sstevel@tonic-gate 	} *tripped;
8697c478bd9Sstevel@tonic-gate 	struct event *sp;
8707c478bd9Sstevel@tonic-gate 	int ntrip, nupset, i;
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate 	/*
8737c478bd9Sstevel@tonic-gate 	 * we avoid recursion by calling fme_receive_report() at the end of
8747c478bd9Sstevel@tonic-gate 	 * this function with a NULL ffep
8757c478bd9Sstevel@tonic-gate 	 */
8767c478bd9Sstevel@tonic-gate 	if (ffep == NULL)
8777c478bd9Sstevel@tonic-gate 		return (0);
8787c478bd9Sstevel@tonic-gate 
8797c478bd9Sstevel@tonic-gate 	/*
8807c478bd9Sstevel@tonic-gate 	 * count the number of upsets to determine the upper limit on
8817c478bd9Sstevel@tonic-gate 	 * expected trip ereport strings.  remember that one upset can
8827c478bd9Sstevel@tonic-gate 	 * lead to at most one ereport.
8837c478bd9Sstevel@tonic-gate 	 */
8847c478bd9Sstevel@tonic-gate 	nupset = 0;
8857c478bd9Sstevel@tonic-gate 	for (sp = fmep->suspects; sp; sp = sp->suspects) {
8867c478bd9Sstevel@tonic-gate 		if (sp->t == N_UPSET)
8877c478bd9Sstevel@tonic-gate 			nupset++;
8887c478bd9Sstevel@tonic-gate 	}
8897c478bd9Sstevel@tonic-gate 
8907c478bd9Sstevel@tonic-gate 	if (nupset == 0)
8917c478bd9Sstevel@tonic-gate 		return (0);
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate 	/*
8947c478bd9Sstevel@tonic-gate 	 * get to this point if we have upsets and expect some trip
8957c478bd9Sstevel@tonic-gate 	 * ereports
8967c478bd9Sstevel@tonic-gate 	 */
8977c478bd9Sstevel@tonic-gate 	tripped = alloca(sizeof (*tripped) * nupset);
8987c478bd9Sstevel@tonic-gate 	bzero((void *)tripped, sizeof (*tripped) * nupset);
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	ntrip = 0;
9017c478bd9Sstevel@tonic-gate 	for (sp = fmep->suspects; sp; sp = sp->suspects)
9023e8d8e18Sdb 		if (sp->t == N_UPSET &&
9033e8d8e18Sdb 		    serd_eval(fmep->hdl, ffep, fmep->fmcase, sp,
9043e8d8e18Sdb 			    &tripped[ntrip].ename, &tripped[ntrip].ipp))
9057c478bd9Sstevel@tonic-gate 			ntrip++;
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate 	for (i = 0; i < ntrip; i++)
9087c478bd9Sstevel@tonic-gate 		fme_receive_report(fmep->hdl, NULL,
9097c478bd9Sstevel@tonic-gate 		    tripped[i].ename, tripped[i].ipp, NULL);
9107c478bd9Sstevel@tonic-gate 
9117c478bd9Sstevel@tonic-gate 	return (ntrip);
9127c478bd9Sstevel@tonic-gate }
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate /*
9157c478bd9Sstevel@tonic-gate  * fme_receive_external_report -- call when an external ereport comes in
9167c478bd9Sstevel@tonic-gate  *
9177c478bd9Sstevel@tonic-gate  * this routine just converts the relevant information from the ereport
9187c478bd9Sstevel@tonic-gate  * into a format used internally and passes it on to fme_receive_report().
9197c478bd9Sstevel@tonic-gate  */
9207c478bd9Sstevel@tonic-gate void
9217c478bd9Sstevel@tonic-gate fme_receive_external_report(fmd_hdl_t *hdl, fmd_event_t *ffep, nvlist_t *nvl,
9227c478bd9Sstevel@tonic-gate     const char *eventstring)
9237c478bd9Sstevel@tonic-gate {
9247c478bd9Sstevel@tonic-gate 	struct node *epnamenp = platform_getpath(nvl);
9257c478bd9Sstevel@tonic-gate 	const struct ipath *ipp;
9267c478bd9Sstevel@tonic-gate 
9277c478bd9Sstevel@tonic-gate 	/*
9287c478bd9Sstevel@tonic-gate 	 * XFILE: If we ended up without a path, it's an X-file.
9297c478bd9Sstevel@tonic-gate 	 * For now, use our undiagnosable interface.
9307c478bd9Sstevel@tonic-gate 	 */
9317c478bd9Sstevel@tonic-gate 	if (epnamenp == NULL) {
9327c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "XFILE: Unable to get path from ereport");
9337c478bd9Sstevel@tonic-gate 		Undiag_reason = UD_NOPATH;
9347c478bd9Sstevel@tonic-gate 		publish_undiagnosable(hdl, ffep);
9357c478bd9Sstevel@tonic-gate 		return;
9367c478bd9Sstevel@tonic-gate 	}
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	ipp = ipath(epnamenp);
9397c478bd9Sstevel@tonic-gate 	tree_free(epnamenp);
9407c478bd9Sstevel@tonic-gate 	fme_receive_report(hdl, ffep, stable(eventstring), ipp, nvl);
9417c478bd9Sstevel@tonic-gate }
9427c478bd9Sstevel@tonic-gate 
9437c478bd9Sstevel@tonic-gate static void
9447c478bd9Sstevel@tonic-gate fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep,
9457c478bd9Sstevel@tonic-gate     const char *eventstring, const struct ipath *ipp, nvlist_t *nvl)
9467c478bd9Sstevel@tonic-gate {
9477c478bd9Sstevel@tonic-gate 	struct event *ep;
9487c478bd9Sstevel@tonic-gate 	struct fme *fmep = NULL;
949*0cc1f05eSjrutt 	struct fme *ofmep = NULL;
950*0cc1f05eSjrutt 	struct fme *cfmep, *svfmep;
9517c478bd9Sstevel@tonic-gate 	int matched = 0;
952*0cc1f05eSjrutt 	nvlist_t *defect;
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_NONL, "fme_receive_report: ");
9557c478bd9Sstevel@tonic-gate 	ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
9567c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_STAMP, NULL);
9577c478bd9Sstevel@tonic-gate 
9587c478bd9Sstevel@tonic-gate 	/* decide which FME it goes to */
9597c478bd9Sstevel@tonic-gate 	for (fmep = FMElist; fmep; fmep = fmep->next) {
9607c478bd9Sstevel@tonic-gate 		int prev_verbose;
9617c478bd9Sstevel@tonic-gate 		unsigned long long my_delay = TIMEVAL_EVENTUALLY;
9627c478bd9Sstevel@tonic-gate 		enum fme_state state;
9637c478bd9Sstevel@tonic-gate 
964*0cc1f05eSjrutt 		if (fmep->overflow) {
965*0cc1f05eSjrutt 			if (!(fmd_case_closed(fmep->hdl, fmep->fmcase)))
966*0cc1f05eSjrutt 				ofmep = fmep;
967*0cc1f05eSjrutt 
968*0cc1f05eSjrutt 			continue;
969*0cc1f05eSjrutt 		}
970*0cc1f05eSjrutt 
9717c478bd9Sstevel@tonic-gate 		/* look up event in event tree for this FME */
9727c478bd9Sstevel@tonic-gate 		if ((ep = itree_lookup(fmep->eventtree,
9737c478bd9Sstevel@tonic-gate 		    eventstring, ipp)) == NULL)
9747c478bd9Sstevel@tonic-gate 			continue;
9757c478bd9Sstevel@tonic-gate 
9767c478bd9Sstevel@tonic-gate 		/* note observation */
9777c478bd9Sstevel@tonic-gate 		fmep->ecurrent = ep;
9787c478bd9Sstevel@tonic-gate 		if (ep->count++ == 0) {
9797c478bd9Sstevel@tonic-gate 			/* link it into list of observations seen */
9807c478bd9Sstevel@tonic-gate 			ep->observations = fmep->observations;
9817c478bd9Sstevel@tonic-gate 			fmep->observations = ep;
9827c478bd9Sstevel@tonic-gate 			ep->nvp = evnv_dupnvl(nvl);
9837c478bd9Sstevel@tonic-gate 		}
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 		/* tell hypothesise() not to mess with suspect list */
9867c478bd9Sstevel@tonic-gate 		fmep->peek = 1;
9877c478bd9Sstevel@tonic-gate 
9887c478bd9Sstevel@tonic-gate 		/* don't want this to be verbose (unless Debug is set) */
9897c478bd9Sstevel@tonic-gate 		prev_verbose = Verbose;
9907c478bd9Sstevel@tonic-gate 		if (Debug == 0)
9917c478bd9Sstevel@tonic-gate 			Verbose = 0;
9927c478bd9Sstevel@tonic-gate 
9937c478bd9Sstevel@tonic-gate 		initialize_cycles(fmep);
9947c478bd9Sstevel@tonic-gate 		state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay, NULL);
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 		fmep->peek = 0;
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 		/* put verbose flag back */
9997c478bd9Sstevel@tonic-gate 		Verbose = prev_verbose;
10007c478bd9Sstevel@tonic-gate 
10017c478bd9Sstevel@tonic-gate 		if (state != FME_DISPROVED) {
10027c478bd9Sstevel@tonic-gate 			/* found an FME that explains the ereport */
10037c478bd9Sstevel@tonic-gate 			matched++;
10047c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_NONL, "[");
10057c478bd9Sstevel@tonic-gate 			ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
10067c478bd9Sstevel@tonic-gate 			out(O_ALTFP, " explained by FME%d]", fmep->id);
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 			if (ep->count == 1)
10097c478bd9Sstevel@tonic-gate 				serialize_observation(fmep, eventstring, ipp);
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 			if (ffep)
10127c478bd9Sstevel@tonic-gate 				fmd_case_add_ereport(hdl, fmep->fmcase, ffep);
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 			stats_counter_bump(fmep->Rcount);
10157c478bd9Sstevel@tonic-gate 
10167c478bd9Sstevel@tonic-gate 			/* re-eval FME */
10177c478bd9Sstevel@tonic-gate 			fme_eval(fmep, ffep);
10187c478bd9Sstevel@tonic-gate 		} else {
10197c478bd9Sstevel@tonic-gate 
10207c478bd9Sstevel@tonic-gate 			/* not a match, undo noting of observation */
10217c478bd9Sstevel@tonic-gate 			fmep->ecurrent = NULL;
10227c478bd9Sstevel@tonic-gate 			if (--ep->count == 0) {
10237c478bd9Sstevel@tonic-gate 				/* unlink it from observations */
10247c478bd9Sstevel@tonic-gate 				fmep->observations = ep->observations;
10257c478bd9Sstevel@tonic-gate 				ep->observations = NULL;
10267c478bd9Sstevel@tonic-gate 				nvlist_free(ep->nvp);
10277c478bd9Sstevel@tonic-gate 				ep->nvp = NULL;
10287c478bd9Sstevel@tonic-gate 			}
10297c478bd9Sstevel@tonic-gate 		}
10307c478bd9Sstevel@tonic-gate 	}
10317c478bd9Sstevel@tonic-gate 
10327c478bd9Sstevel@tonic-gate 	if (matched)
10337c478bd9Sstevel@tonic-gate 		return;	/* explained by at least one existing FME */
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 	/* clean up closed fmes */
1036*0cc1f05eSjrutt 	cfmep = ClosedFMEs;
1037*0cc1f05eSjrutt 	while (cfmep != NULL) {
1038*0cc1f05eSjrutt 		svfmep = cfmep->next;
1039*0cc1f05eSjrutt 		destroy_fme(cfmep);
1040*0cc1f05eSjrutt 		cfmep = svfmep;
10417c478bd9Sstevel@tonic-gate 	}
10427c478bd9Sstevel@tonic-gate 	ClosedFMEs = NULL;
10437c478bd9Sstevel@tonic-gate 
1044*0cc1f05eSjrutt 	if (ofmep) {
1045*0cc1f05eSjrutt 		out(O_ALTFP|O_NONL, "[");
1046*0cc1f05eSjrutt 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
1047*0cc1f05eSjrutt 		out(O_ALTFP, " ADDING TO OVERFLOW FME]");
1048*0cc1f05eSjrutt 		if (ffep)
1049*0cc1f05eSjrutt 			fmd_case_add_ereport(hdl, ofmep->fmcase, ffep);
1050*0cc1f05eSjrutt 
1051*0cc1f05eSjrutt 		return;
1052*0cc1f05eSjrutt 
1053*0cc1f05eSjrutt 	} else if (Max_fme && (Open_fme_count >= Max_fme)) {
1054*0cc1f05eSjrutt 		out(O_ALTFP|O_NONL, "[");
1055*0cc1f05eSjrutt 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
1056*0cc1f05eSjrutt 		out(O_ALTFP, " MAX OPEN FME REACHED]");
1057*0cc1f05eSjrutt 		/* Create overflow fme */
1058*0cc1f05eSjrutt 		if ((fmep = newfme(eventstring, ipp)) == NULL) {
1059*0cc1f05eSjrutt 			out(O_ALTFP|O_NONL, "[");
1060*0cc1f05eSjrutt 			ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
1061*0cc1f05eSjrutt 			out(O_ALTFP, " CANNOT OPEN OVERFLOW FME]");
1062*0cc1f05eSjrutt 			publish_undiagnosable(hdl, ffep);
1063*0cc1f05eSjrutt 			return;
1064*0cc1f05eSjrutt 		}
1065*0cc1f05eSjrutt 
1066*0cc1f05eSjrutt 		Open_fme_count++;
1067*0cc1f05eSjrutt 
1068*0cc1f05eSjrutt 		fmep->fmcase = fmd_case_open(hdl, NULL);
1069*0cc1f05eSjrutt 		fmep->hdl = hdl;
1070*0cc1f05eSjrutt 		init_fme_bufs(fmep);
1071*0cc1f05eSjrutt 		fmep->overflow = B_TRUE;
1072*0cc1f05eSjrutt 
1073*0cc1f05eSjrutt 		if (ffep)
1074*0cc1f05eSjrutt 			fmd_case_add_ereport(hdl, fmep->fmcase, ffep);
1075*0cc1f05eSjrutt 
1076*0cc1f05eSjrutt 		defect = fmd_nvl_create_fault(hdl, UNDIAGNOSABLE_DEFECT, 100,
1077*0cc1f05eSjrutt 		    NULL, NULL, NULL);
1078*0cc1f05eSjrutt 		(void) nvlist_add_string(defect, UNDIAG_REASON, UD_MAXFME);
1079*0cc1f05eSjrutt 		fmd_case_add_suspect(hdl, fmep->fmcase, defect);
1080*0cc1f05eSjrutt 		fmd_case_solve(hdl, fmep->fmcase);
1081*0cc1f05eSjrutt 		return;
1082*0cc1f05eSjrutt 	}
1083*0cc1f05eSjrutt 
10847c478bd9Sstevel@tonic-gate 	/* start a new FME */
10857c478bd9Sstevel@tonic-gate 	if ((fmep = newfme(eventstring, ipp)) == NULL) {
10867c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "[");
10877c478bd9Sstevel@tonic-gate 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
10887c478bd9Sstevel@tonic-gate 		out(O_ALTFP, " CANNOT DIAGNOSE]");
10897c478bd9Sstevel@tonic-gate 		publish_undiagnosable(hdl, ffep);
10907c478bd9Sstevel@tonic-gate 		return;
10917c478bd9Sstevel@tonic-gate 	}
10927c478bd9Sstevel@tonic-gate 
1093*0cc1f05eSjrutt 	Open_fme_count++;
1094*0cc1f05eSjrutt 
10957c478bd9Sstevel@tonic-gate 	/* open a case */
10967c478bd9Sstevel@tonic-gate 	fmep->fmcase = fmd_case_open(hdl, NULL);
10977c478bd9Sstevel@tonic-gate 	fmep->hdl = hdl;
10987c478bd9Sstevel@tonic-gate 	init_fme_bufs(fmep);
10997c478bd9Sstevel@tonic-gate 
11007c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_NONL, "[");
11017c478bd9Sstevel@tonic-gate 	ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
11027c478bd9Sstevel@tonic-gate 	out(O_ALTFP, " created FME%d, case %s]", fmep->id,
11037c478bd9Sstevel@tonic-gate 	    fmd_case_uuid(hdl, fmep->fmcase));
11047c478bd9Sstevel@tonic-gate 
11057c478bd9Sstevel@tonic-gate 	ep = fmep->e0;
11067c478bd9Sstevel@tonic-gate 	ASSERT(ep != NULL);
11077c478bd9Sstevel@tonic-gate 
11087c478bd9Sstevel@tonic-gate 	/* note observation */
11097c478bd9Sstevel@tonic-gate 	fmep->ecurrent = ep;
11107c478bd9Sstevel@tonic-gate 	if (ep->count++ == 0) {
11117c478bd9Sstevel@tonic-gate 		/* link it into list of observations seen */
11127c478bd9Sstevel@tonic-gate 		ep->observations = fmep->observations;
11137c478bd9Sstevel@tonic-gate 		fmep->observations = ep;
11147c478bd9Sstevel@tonic-gate 		ep->nvp = evnv_dupnvl(nvl);
11157c478bd9Sstevel@tonic-gate 		serialize_observation(fmep, eventstring, ipp);
11167c478bd9Sstevel@tonic-gate 	}
11177c478bd9Sstevel@tonic-gate 
11187c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Rcount);
11197c478bd9Sstevel@tonic-gate 
11207c478bd9Sstevel@tonic-gate 	if (ffep) {
11217c478bd9Sstevel@tonic-gate 		fmd_case_add_ereport(hdl, fmep->fmcase, ffep);
11227c478bd9Sstevel@tonic-gate 		fmd_case_setprincipal(hdl, fmep->fmcase, ffep);
11237c478bd9Sstevel@tonic-gate 		fmep->e0r = ffep;
11247c478bd9Sstevel@tonic-gate 	}
11257c478bd9Sstevel@tonic-gate 
11267c478bd9Sstevel@tonic-gate 	/* give the diagnosis algorithm a shot at the new FME state */
11277c478bd9Sstevel@tonic-gate 	fme_eval(fmep, ffep);
11287c478bd9Sstevel@tonic-gate }
11297c478bd9Sstevel@tonic-gate 
11307c478bd9Sstevel@tonic-gate void
11317c478bd9Sstevel@tonic-gate fme_status(int flags)
11327c478bd9Sstevel@tonic-gate {
11337c478bd9Sstevel@tonic-gate 	struct fme *fmep;
11347c478bd9Sstevel@tonic-gate 
11357c478bd9Sstevel@tonic-gate 	if (FMElist == NULL) {
11367c478bd9Sstevel@tonic-gate 		out(flags, "No fault management exercises underway.");
11377c478bd9Sstevel@tonic-gate 		return;
11387c478bd9Sstevel@tonic-gate 	}
11397c478bd9Sstevel@tonic-gate 
11407c478bd9Sstevel@tonic-gate 	for (fmep = FMElist; fmep; fmep = fmep->next)
11417c478bd9Sstevel@tonic-gate 		fme_print(flags, fmep);
11427c478bd9Sstevel@tonic-gate }
11437c478bd9Sstevel@tonic-gate 
11447c478bd9Sstevel@tonic-gate /*
11457c478bd9Sstevel@tonic-gate  * "indent" routines used mostly for nicely formatted debug output, but also
11467c478bd9Sstevel@tonic-gate  * for sanity checking for infinite recursion bugs.
11477c478bd9Sstevel@tonic-gate  */
11487c478bd9Sstevel@tonic-gate 
11497c478bd9Sstevel@tonic-gate #define	MAX_INDENT 1024
11507c478bd9Sstevel@tonic-gate static const char *indent_s[MAX_INDENT];
11517c478bd9Sstevel@tonic-gate static int current_indent;
11527c478bd9Sstevel@tonic-gate 
11537c478bd9Sstevel@tonic-gate static void
11547c478bd9Sstevel@tonic-gate indent_push(const char *s)
11557c478bd9Sstevel@tonic-gate {
11567c478bd9Sstevel@tonic-gate 	if (current_indent < MAX_INDENT)
11577c478bd9Sstevel@tonic-gate 		indent_s[current_indent++] = s;
11587c478bd9Sstevel@tonic-gate 	else
11597c478bd9Sstevel@tonic-gate 		out(O_DIE, "unexpected recursion depth (%d)", current_indent);
11607c478bd9Sstevel@tonic-gate }
11617c478bd9Sstevel@tonic-gate 
11627c478bd9Sstevel@tonic-gate static void
11637c478bd9Sstevel@tonic-gate indent_set(const char *s)
11647c478bd9Sstevel@tonic-gate {
11657c478bd9Sstevel@tonic-gate 	current_indent = 0;
11667c478bd9Sstevel@tonic-gate 	indent_push(s);
11677c478bd9Sstevel@tonic-gate }
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate static void
11707c478bd9Sstevel@tonic-gate indent_pop(void)
11717c478bd9Sstevel@tonic-gate {
11727c478bd9Sstevel@tonic-gate 	if (current_indent > 0)
11737c478bd9Sstevel@tonic-gate 		current_indent--;
11747c478bd9Sstevel@tonic-gate 	else
11757c478bd9Sstevel@tonic-gate 		out(O_DIE, "recursion underflow");
11767c478bd9Sstevel@tonic-gate }
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate static void
11797c478bd9Sstevel@tonic-gate indent(void)
11807c478bd9Sstevel@tonic-gate {
11817c478bd9Sstevel@tonic-gate 	int i;
11827c478bd9Sstevel@tonic-gate 	if (!Verbose)
11837c478bd9Sstevel@tonic-gate 		return;
11847c478bd9Sstevel@tonic-gate 	for (i = 0; i < current_indent; i++)
11857c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, indent_s[i]);
11867c478bd9Sstevel@tonic-gate }
11877c478bd9Sstevel@tonic-gate 
11887c478bd9Sstevel@tonic-gate static int
11897c478bd9Sstevel@tonic-gate suspects_changed(struct fme *fmep)
11907c478bd9Sstevel@tonic-gate {
11917c478bd9Sstevel@tonic-gate 	struct event *suspects = fmep->suspects;
11927c478bd9Sstevel@tonic-gate 	struct event *psuspects = fmep->psuspects;
11937c478bd9Sstevel@tonic-gate 
11947c478bd9Sstevel@tonic-gate 	while (suspects != NULL && psuspects != NULL) {
11957c478bd9Sstevel@tonic-gate 		if (suspects != psuspects)
11967c478bd9Sstevel@tonic-gate 			return (1);
11977c478bd9Sstevel@tonic-gate 		suspects = suspects->suspects;
11987c478bd9Sstevel@tonic-gate 		psuspects = psuspects->psuspects;
11997c478bd9Sstevel@tonic-gate 	}
12007c478bd9Sstevel@tonic-gate 
12017c478bd9Sstevel@tonic-gate 	return (suspects != psuspects);
12027c478bd9Sstevel@tonic-gate }
12037c478bd9Sstevel@tonic-gate 
12047c478bd9Sstevel@tonic-gate #define	SLNEW		1
12057c478bd9Sstevel@tonic-gate #define	SLCHANGED	2
12067c478bd9Sstevel@tonic-gate #define	SLWAIT		3
12077c478bd9Sstevel@tonic-gate #define	SLDISPROVED	4
12087c478bd9Sstevel@tonic-gate 
12097c478bd9Sstevel@tonic-gate static void
12107c478bd9Sstevel@tonic-gate print_suspects(int circumstance, struct fme *fmep)
12117c478bd9Sstevel@tonic-gate {
12127c478bd9Sstevel@tonic-gate 	struct event *ep;
12137c478bd9Sstevel@tonic-gate 
12147c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_NONL, "[");
12157c478bd9Sstevel@tonic-gate 	if (circumstance == SLCHANGED) {
12167c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "FME%d diagnosis changed. state: %s, "
12177c478bd9Sstevel@tonic-gate 		    "suspect list:", fmep->id, fme_state2str(fmep->state));
12187c478bd9Sstevel@tonic-gate 	} else if (circumstance == SLWAIT) {
12197c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "FME%d set wait timer ", fmep->id);
12207c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_NONL, &fmep->wull);
12217c478bd9Sstevel@tonic-gate 	} else if (circumstance == SLDISPROVED) {
12227c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "FME%d DIAGNOSIS UNKNOWN", fmep->id);
12237c478bd9Sstevel@tonic-gate 	} else {
12247c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "FME%d DIAGNOSIS PRODUCED:", fmep->id);
12257c478bd9Sstevel@tonic-gate 	}
12267c478bd9Sstevel@tonic-gate 
12277c478bd9Sstevel@tonic-gate 	if (circumstance == SLWAIT || circumstance == SLDISPROVED) {
12287c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "]");
12297c478bd9Sstevel@tonic-gate 		return;
12307c478bd9Sstevel@tonic-gate 	}
12317c478bd9Sstevel@tonic-gate 
12327c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = ep->suspects) {
12337c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, " ");
12347c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_NONL, ep);
12357c478bd9Sstevel@tonic-gate 	}
12367c478bd9Sstevel@tonic-gate 	out(O_ALTFP, "]");
12377c478bd9Sstevel@tonic-gate }
12387c478bd9Sstevel@tonic-gate 
12397c478bd9Sstevel@tonic-gate static struct node *
12407c478bd9Sstevel@tonic-gate eventprop_lookup(struct event *ep, const char *propname)
12417c478bd9Sstevel@tonic-gate {
12427c478bd9Sstevel@tonic-gate 	return (lut_lookup(ep->props, (void *)propname, NULL));
12437c478bd9Sstevel@tonic-gate }
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate #define	MAXDIGITIDX	23
12467c478bd9Sstevel@tonic-gate static char numbuf[MAXDIGITIDX + 1];
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate static int
12497c478bd9Sstevel@tonic-gate node2uint(struct node *n, uint_t *valp)
12507c478bd9Sstevel@tonic-gate {
12517c478bd9Sstevel@tonic-gate 	struct evalue value;
12527c478bd9Sstevel@tonic-gate 	struct lut *globals = NULL;
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate 	if (n == NULL)
12557c478bd9Sstevel@tonic-gate 		return (1);
12567c478bd9Sstevel@tonic-gate 
12577c478bd9Sstevel@tonic-gate 	/*
12587c478bd9Sstevel@tonic-gate 	 * check value.v since we are being asked to convert an unsigned
12597c478bd9Sstevel@tonic-gate 	 * long long int to an unsigned int
12607c478bd9Sstevel@tonic-gate 	 */
12617c478bd9Sstevel@tonic-gate 	if (! eval_expr(n, NULL, NULL, &globals, NULL, NULL, 0, &value) ||
12627c478bd9Sstevel@tonic-gate 	    value.t != UINT64 || value.v > (1ULL << 32))
12637c478bd9Sstevel@tonic-gate 		return (1);
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 	*valp = (uint_t)value.v;
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	return (0);
12687c478bd9Sstevel@tonic-gate }
12697c478bd9Sstevel@tonic-gate 
12707c478bd9Sstevel@tonic-gate static nvlist_t *
12717c478bd9Sstevel@tonic-gate node2fmri(struct node *n)
12727c478bd9Sstevel@tonic-gate {
12737c478bd9Sstevel@tonic-gate 	nvlist_t **pa, *f, *p;
12747c478bd9Sstevel@tonic-gate 	struct node *nc;
12757c478bd9Sstevel@tonic-gate 	uint_t depth = 0;
12767c478bd9Sstevel@tonic-gate 	char *numstr, *nullbyte;
12777c478bd9Sstevel@tonic-gate 	char *failure;
12787c478bd9Sstevel@tonic-gate 	int err, i;
12797c478bd9Sstevel@tonic-gate 
12807c478bd9Sstevel@tonic-gate 	/* XXX do we need to be able to handle a non-T_NAME node? */
12817c478bd9Sstevel@tonic-gate 	if (n == NULL || n->t != T_NAME)
12827c478bd9Sstevel@tonic-gate 		return (NULL);
12837c478bd9Sstevel@tonic-gate 
12847c478bd9Sstevel@tonic-gate 	for (nc = n; nc != NULL; nc = nc->u.name.next) {
12857c478bd9Sstevel@tonic-gate 		if (nc->u.name.child == NULL || nc->u.name.child->t != T_NUM)
12867c478bd9Sstevel@tonic-gate 			break;
12877c478bd9Sstevel@tonic-gate 		depth++;
12887c478bd9Sstevel@tonic-gate 	}
12897c478bd9Sstevel@tonic-gate 
12907c478bd9Sstevel@tonic-gate 	if (nc != NULL) {
12917c478bd9Sstevel@tonic-gate 		/* We bailed early, something went wrong */
12927c478bd9Sstevel@tonic-gate 		return (NULL);
12937c478bd9Sstevel@tonic-gate 	}
12947c478bd9Sstevel@tonic-gate 
12957c478bd9Sstevel@tonic-gate 	if ((err = nvlist_xalloc(&f, NV_UNIQUE_NAME, &Eft_nv_hdl)) != 0)
12967c478bd9Sstevel@tonic-gate 		out(O_DIE|O_SYS, "alloc of fmri nvl failed");
12977c478bd9Sstevel@tonic-gate 	pa = alloca(depth * sizeof (nvlist_t *));
12987c478bd9Sstevel@tonic-gate 	for (i = 0; i < depth; i++)
12997c478bd9Sstevel@tonic-gate 		pa[i] = NULL;
13007c478bd9Sstevel@tonic-gate 
13017c478bd9Sstevel@tonic-gate 	err = nvlist_add_string(f, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC);
13027c478bd9Sstevel@tonic-gate 	err |= nvlist_add_uint8(f, FM_VERSION, FM_HC_SCHEME_VERSION);
13037c478bd9Sstevel@tonic-gate 	err |= nvlist_add_string(f, FM_FMRI_HC_ROOT, "");
13047c478bd9Sstevel@tonic-gate 	err |= nvlist_add_uint32(f, FM_FMRI_HC_LIST_SZ, depth);
13057c478bd9Sstevel@tonic-gate 	if (err != 0) {
13067c478bd9Sstevel@tonic-gate 		failure = "basic construction of FMRI failed";
13077c478bd9Sstevel@tonic-gate 		goto boom;
13087c478bd9Sstevel@tonic-gate 	}
13097c478bd9Sstevel@tonic-gate 
13107c478bd9Sstevel@tonic-gate 	numbuf[MAXDIGITIDX] = '\0';
13117c478bd9Sstevel@tonic-gate 	nullbyte = &numbuf[MAXDIGITIDX];
13127c478bd9Sstevel@tonic-gate 	i = 0;
13137c478bd9Sstevel@tonic-gate 
13147c478bd9Sstevel@tonic-gate 	for (nc = n; nc != NULL; nc = nc->u.name.next) {
13157c478bd9Sstevel@tonic-gate 		err = nvlist_xalloc(&p, NV_UNIQUE_NAME, &Eft_nv_hdl);
13167c478bd9Sstevel@tonic-gate 		if (err != 0) {
13177c478bd9Sstevel@tonic-gate 			failure = "alloc of an hc-pair failed";
13187c478bd9Sstevel@tonic-gate 			goto boom;
13197c478bd9Sstevel@tonic-gate 		}
13207c478bd9Sstevel@tonic-gate 		err = nvlist_add_string(p, FM_FMRI_HC_NAME, nc->u.name.s);
13217c478bd9Sstevel@tonic-gate 		numstr = ulltostr(nc->u.name.child->u.ull, nullbyte);
13227c478bd9Sstevel@tonic-gate 		err |= nvlist_add_string(p, FM_FMRI_HC_ID, numstr);
13237c478bd9Sstevel@tonic-gate 		if (err != 0) {
13247c478bd9Sstevel@tonic-gate 			failure = "construction of an hc-pair failed";
13257c478bd9Sstevel@tonic-gate 			goto boom;
13267c478bd9Sstevel@tonic-gate 		}
13277c478bd9Sstevel@tonic-gate 		pa[i++] = p;
13287c478bd9Sstevel@tonic-gate 	}
13297c478bd9Sstevel@tonic-gate 
13307c478bd9Sstevel@tonic-gate 	err = nvlist_add_nvlist_array(f, FM_FMRI_HC_LIST, pa, depth);
13317c478bd9Sstevel@tonic-gate 	if (err == 0) {
13327c478bd9Sstevel@tonic-gate 		for (i = 0; i < depth; i++)
13337c478bd9Sstevel@tonic-gate 			if (pa[i] != NULL)
13347c478bd9Sstevel@tonic-gate 				nvlist_free(pa[i]);
13357c478bd9Sstevel@tonic-gate 		return (f);
13367c478bd9Sstevel@tonic-gate 	}
13377c478bd9Sstevel@tonic-gate 	failure = "addition of hc-pair array to FMRI failed";
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate boom:
13407c478bd9Sstevel@tonic-gate 	for (i = 0; i < depth; i++)
13417c478bd9Sstevel@tonic-gate 		if (pa[i] != NULL)
13427c478bd9Sstevel@tonic-gate 			nvlist_free(pa[i]);
13437c478bd9Sstevel@tonic-gate 	nvlist_free(f);
13447c478bd9Sstevel@tonic-gate 	out(O_DIE, "%s", failure);
13457c478bd9Sstevel@tonic-gate 	/*NOTREACHED*/
13467c478bd9Sstevel@tonic-gate }
13477c478bd9Sstevel@tonic-gate 
13487c478bd9Sstevel@tonic-gate static uint_t
13497c478bd9Sstevel@tonic-gate avg(uint_t sum, uint_t cnt)
13507c478bd9Sstevel@tonic-gate {
13517c478bd9Sstevel@tonic-gate 	unsigned long long s = sum * 10;
13527c478bd9Sstevel@tonic-gate 
13537c478bd9Sstevel@tonic-gate 	return ((s / cnt / 10) + (((s / cnt % 10) >= 5) ? 1 : 0));
13547c478bd9Sstevel@tonic-gate }
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate static uint8_t
13577c478bd9Sstevel@tonic-gate percentof(uint_t part, uint_t whole)
13587c478bd9Sstevel@tonic-gate {
13597c478bd9Sstevel@tonic-gate 	unsigned long long p = part * 1000;
13607c478bd9Sstevel@tonic-gate 
13617c478bd9Sstevel@tonic-gate 	return ((p / whole / 10) + (((p / whole % 10) >= 5) ? 1 : 0));
13627c478bd9Sstevel@tonic-gate }
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate static struct rsl {
13657c478bd9Sstevel@tonic-gate 	struct event *suspect;
13667c478bd9Sstevel@tonic-gate 	nvlist_t *asru;
13677c478bd9Sstevel@tonic-gate 	nvlist_t *fru;
13687c478bd9Sstevel@tonic-gate 	nvlist_t *rsrc;
13697c478bd9Sstevel@tonic-gate };
13707c478bd9Sstevel@tonic-gate 
13717c478bd9Sstevel@tonic-gate /*
13727c478bd9Sstevel@tonic-gate  *  rslfree -- free internal members of struct rsl not expected to be
13737c478bd9Sstevel@tonic-gate  *	freed elsewhere.
13747c478bd9Sstevel@tonic-gate  */
13757c478bd9Sstevel@tonic-gate static void
13767c478bd9Sstevel@tonic-gate rslfree(struct rsl *freeme)
13777c478bd9Sstevel@tonic-gate {
13787c478bd9Sstevel@tonic-gate 	if (freeme->asru != NULL)
13797c478bd9Sstevel@tonic-gate 		nvlist_free(freeme->asru);
13807c478bd9Sstevel@tonic-gate 	if (freeme->fru != NULL)
13817c478bd9Sstevel@tonic-gate 		nvlist_free(freeme->fru);
13827c478bd9Sstevel@tonic-gate 	if (freeme->rsrc != NULL && freeme->rsrc != freeme->asru)
13837c478bd9Sstevel@tonic-gate 		nvlist_free(freeme->rsrc);
13847c478bd9Sstevel@tonic-gate }
13857c478bd9Sstevel@tonic-gate 
13867c478bd9Sstevel@tonic-gate /*
13877c478bd9Sstevel@tonic-gate  *  rslcmp -- compare two rsl structures.  Use the following
13887c478bd9Sstevel@tonic-gate  *	comparisons to establish cardinality:
13897c478bd9Sstevel@tonic-gate  *
13907c478bd9Sstevel@tonic-gate  *	1. Name of the suspect's class. (simple strcmp)
13917c478bd9Sstevel@tonic-gate  *	2. Name of the suspect's ASRU. (trickier, since nvlist)
13927c478bd9Sstevel@tonic-gate  *
13937c478bd9Sstevel@tonic-gate  */
13947c478bd9Sstevel@tonic-gate static int
13957c478bd9Sstevel@tonic-gate rslcmp(const void *a, const void *b)
13967c478bd9Sstevel@tonic-gate {
13977c478bd9Sstevel@tonic-gate 	struct rsl *r1 = (struct rsl *)a;
13987c478bd9Sstevel@tonic-gate 	struct rsl *r2 = (struct rsl *)b;
13997c478bd9Sstevel@tonic-gate 	int rv;
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	rv = strcmp(r1->suspect->enode->u.event.ename->u.name.s,
14027c478bd9Sstevel@tonic-gate 	    r2->suspect->enode->u.event.ename->u.name.s);
14037c478bd9Sstevel@tonic-gate 	if (rv != 0)
14047c478bd9Sstevel@tonic-gate 		return (rv);
14057c478bd9Sstevel@tonic-gate 
14067c478bd9Sstevel@tonic-gate 	if (r1->asru == NULL && r2->asru == NULL)
14077c478bd9Sstevel@tonic-gate 		return (0);
14087c478bd9Sstevel@tonic-gate 	if (r1->asru == NULL)
14097c478bd9Sstevel@tonic-gate 		return (-1);
14107c478bd9Sstevel@tonic-gate 	if (r2->asru == NULL)
14117c478bd9Sstevel@tonic-gate 		return (1);
14127c478bd9Sstevel@tonic-gate 	return (evnv_cmpnvl(r1->asru, r2->asru, 0));
14137c478bd9Sstevel@tonic-gate }
14147c478bd9Sstevel@tonic-gate 
14157c478bd9Sstevel@tonic-gate /*
14167c478bd9Sstevel@tonic-gate  *  rsluniq -- given an array of rsl structures, seek out and "remove"
14177c478bd9Sstevel@tonic-gate  *	any duplicates.  Dups are "remove"d by NULLing the suspect pointer
14187c478bd9Sstevel@tonic-gate  *	of the array element.  Removal also means updating the number of
14197c478bd9Sstevel@tonic-gate  *	problems and the number of problems which are not faults.  User
14207c478bd9Sstevel@tonic-gate  *	provides the first and last element pointers.
14217c478bd9Sstevel@tonic-gate  */
14227c478bd9Sstevel@tonic-gate static void
14237c478bd9Sstevel@tonic-gate rsluniq(struct rsl *first, struct rsl *last, int *nprobs, int *nnonf)
14247c478bd9Sstevel@tonic-gate {
14257c478bd9Sstevel@tonic-gate 	struct rsl *cr;
14267c478bd9Sstevel@tonic-gate 
14277c478bd9Sstevel@tonic-gate 	if (*nprobs == 1)
14287c478bd9Sstevel@tonic-gate 		return;
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 	/*
14317c478bd9Sstevel@tonic-gate 	 *  At this point, we only expect duplicate defects.
14327c478bd9Sstevel@tonic-gate 	 *  Eversholt's diagnosis algorithm prevents duplicate
14337c478bd9Sstevel@tonic-gate 	 *  suspects, but we rewrite defects in the platform code after
14347c478bd9Sstevel@tonic-gate 	 *  the diagnosis is made, and that can introduce new
14357c478bd9Sstevel@tonic-gate 	 *  duplicates.
14367c478bd9Sstevel@tonic-gate 	 */
14377c478bd9Sstevel@tonic-gate 	while (first <= last) {
14387c478bd9Sstevel@tonic-gate 		if (first->suspect == NULL || !is_defect(first->suspect->t)) {
14397c478bd9Sstevel@tonic-gate 			first++;
14407c478bd9Sstevel@tonic-gate 			continue;
14417c478bd9Sstevel@tonic-gate 		}
14427c478bd9Sstevel@tonic-gate 		cr = first + 1;
14437c478bd9Sstevel@tonic-gate 		while (cr <= last) {
14447c478bd9Sstevel@tonic-gate 			if (is_defect(first->suspect->t)) {
14457c478bd9Sstevel@tonic-gate 				if (rslcmp(first, cr) == 0) {
14467c478bd9Sstevel@tonic-gate 					cr->suspect = NULL;
14477c478bd9Sstevel@tonic-gate 					rslfree(cr);
14487c478bd9Sstevel@tonic-gate 					(*nprobs)--;
14497c478bd9Sstevel@tonic-gate 					(*nnonf)--;
14507c478bd9Sstevel@tonic-gate 				}
14517c478bd9Sstevel@tonic-gate 			}
14527c478bd9Sstevel@tonic-gate 			/*
14537c478bd9Sstevel@tonic-gate 			 * assume all defects are in order after our
14547c478bd9Sstevel@tonic-gate 			 * sort and short circuit here with "else break" ?
14557c478bd9Sstevel@tonic-gate 			 */
14567c478bd9Sstevel@tonic-gate 			cr++;
14577c478bd9Sstevel@tonic-gate 		}
14587c478bd9Sstevel@tonic-gate 		first++;
14597c478bd9Sstevel@tonic-gate 	}
14607c478bd9Sstevel@tonic-gate }
14617c478bd9Sstevel@tonic-gate 
14627c478bd9Sstevel@tonic-gate /*
14637c478bd9Sstevel@tonic-gate  * get_resources -- for a given suspect, determine what ASRU, FRU and
14647c478bd9Sstevel@tonic-gate  *     RSRC nvlists should be advertised in the final suspect list.
14657c478bd9Sstevel@tonic-gate  */
14667c478bd9Sstevel@tonic-gate void
14677c478bd9Sstevel@tonic-gate get_resources(struct event *sp, struct rsl *rsrcs, struct config *croot)
14687c478bd9Sstevel@tonic-gate {
14697c478bd9Sstevel@tonic-gate 	struct node *asrudef, *frudef;
14707c478bd9Sstevel@tonic-gate 	nvlist_t *asru, *fru;
14717c478bd9Sstevel@tonic-gate 	nvlist_t *rsrc = NULL;
14727c478bd9Sstevel@tonic-gate 	char *pathstr;
14737c478bd9Sstevel@tonic-gate 
14747c478bd9Sstevel@tonic-gate 	/*
14757c478bd9Sstevel@tonic-gate 	 * First find any ASRU and/or FRU defined in the
14767c478bd9Sstevel@tonic-gate 	 * initial fault tree.
14777c478bd9Sstevel@tonic-gate 	 */
14787c478bd9Sstevel@tonic-gate 	asrudef = eventprop_lookup(sp, L_ASRU);
14797c478bd9Sstevel@tonic-gate 	frudef = eventprop_lookup(sp, L_FRU);
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	/*
14827c478bd9Sstevel@tonic-gate 	 * Create FMRIs based on those definitions
14837c478bd9Sstevel@tonic-gate 	 */
14847c478bd9Sstevel@tonic-gate 	asru = node2fmri(asrudef);
14857c478bd9Sstevel@tonic-gate 	fru = node2fmri(frudef);
14867c478bd9Sstevel@tonic-gate 	pathstr = ipath2str(NULL, sp->ipp);
14877c478bd9Sstevel@tonic-gate 
14887c478bd9Sstevel@tonic-gate 	/*
14897c478bd9Sstevel@tonic-gate 	 * Allow for platform translations of the FMRIs
14907c478bd9Sstevel@tonic-gate 	 */
14917c478bd9Sstevel@tonic-gate 	platform_units_translate(is_defect(sp->t), croot, &asru, &fru, &rsrc,
14927c478bd9Sstevel@tonic-gate 	    pathstr);
14937c478bd9Sstevel@tonic-gate 
14947c478bd9Sstevel@tonic-gate 	FREE(pathstr);
14957c478bd9Sstevel@tonic-gate 	rsrcs->suspect = sp;
14967c478bd9Sstevel@tonic-gate 	rsrcs->asru = asru;
14977c478bd9Sstevel@tonic-gate 	rsrcs->fru = fru;
14987c478bd9Sstevel@tonic-gate 	rsrcs->rsrc = rsrc;
14997c478bd9Sstevel@tonic-gate }
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate /*
15027c478bd9Sstevel@tonic-gate  * trim_suspects -- prior to publishing, we may need to remove some
15037c478bd9Sstevel@tonic-gate  *    suspects from the list.  If we're auto-closing upsets, we don't
15047c478bd9Sstevel@tonic-gate  *    want any of those in the published list.  If the ASRUs for multiple
15057c478bd9Sstevel@tonic-gate  *    defects resolve to the same ASRU (driver) we only want to publish
15067c478bd9Sstevel@tonic-gate  *    that as a single suspect.
15077c478bd9Sstevel@tonic-gate  */
15087c478bd9Sstevel@tonic-gate static void
15097c478bd9Sstevel@tonic-gate trim_suspects(struct fme *fmep, boolean_t no_upsets, struct rsl **begin,
15107c478bd9Sstevel@tonic-gate     struct rsl **end)
15117c478bd9Sstevel@tonic-gate {
15127c478bd9Sstevel@tonic-gate 	struct event *ep;
15137c478bd9Sstevel@tonic-gate 	struct rsl *rp;
15147c478bd9Sstevel@tonic-gate 	int rpcnt;
15157c478bd9Sstevel@tonic-gate 
15167c478bd9Sstevel@tonic-gate 	/*
15177c478bd9Sstevel@tonic-gate 	 * First save the suspects in the psuspects, then copy back
15187c478bd9Sstevel@tonic-gate 	 * only the ones we wish to retain.  This resets nsuspects to
15197c478bd9Sstevel@tonic-gate 	 * zero.
15207c478bd9Sstevel@tonic-gate 	 */
15217c478bd9Sstevel@tonic-gate 	rpcnt = fmep->nsuspects;
15227c478bd9Sstevel@tonic-gate 	save_suspects(fmep);
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate 	/*
15257c478bd9Sstevel@tonic-gate 	 * allocate an array of resource pointers for the suspects.
15267c478bd9Sstevel@tonic-gate 	 * We may end up using less than the full allocation, but this
15277c478bd9Sstevel@tonic-gate 	 * is a very short-lived array.  publish_suspects() will free
15287c478bd9Sstevel@tonic-gate 	 * this array when it's done using it.
15297c478bd9Sstevel@tonic-gate 	 */
15307c478bd9Sstevel@tonic-gate 	rp = *begin = MALLOC(rpcnt * sizeof (struct rsl));
15317c478bd9Sstevel@tonic-gate 	bzero(rp, rpcnt * sizeof (struct rsl));
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate 	/* first pass, remove any unwanted upsets and populate our array */
15347c478bd9Sstevel@tonic-gate 	for (ep = fmep->psuspects; ep; ep = ep->psuspects) {
15357c478bd9Sstevel@tonic-gate 		if (no_upsets && is_upset(ep->t))
15367c478bd9Sstevel@tonic-gate 			continue;
15377c478bd9Sstevel@tonic-gate 		get_resources(ep, rp, fmep->cfgdata->cooked);
15387c478bd9Sstevel@tonic-gate 		rp++;
15397c478bd9Sstevel@tonic-gate 		fmep->nsuspects++;
15407c478bd9Sstevel@tonic-gate 		if (!is_fault(ep->t))
15417c478bd9Sstevel@tonic-gate 			fmep->nonfault++;
15427c478bd9Sstevel@tonic-gate 	}
15437c478bd9Sstevel@tonic-gate 
15447c478bd9Sstevel@tonic-gate 	/* if all we had was unwanted upsets, we're done */
15457c478bd9Sstevel@tonic-gate 	if (fmep->nsuspects == 0)
15467c478bd9Sstevel@tonic-gate 		return;
15477c478bd9Sstevel@tonic-gate 
15487c478bd9Sstevel@tonic-gate 	*end = rp - 1;
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 	/* sort the array */
15517c478bd9Sstevel@tonic-gate 	qsort(*begin, fmep->nsuspects, sizeof (struct rsl), rslcmp);
15527c478bd9Sstevel@tonic-gate 	rsluniq(*begin, *end, &fmep->nsuspects, &fmep->nonfault);
15537c478bd9Sstevel@tonic-gate }
15547c478bd9Sstevel@tonic-gate 
15557c478bd9Sstevel@tonic-gate static void
15567c478bd9Sstevel@tonic-gate publish_suspects(struct fme *fmep)
15577c478bd9Sstevel@tonic-gate {
15587c478bd9Sstevel@tonic-gate 	struct event *ep;
15597c478bd9Sstevel@tonic-gate 	struct rsl *srl = NULL;
15607c478bd9Sstevel@tonic-gate 	struct rsl *erl;
15617c478bd9Sstevel@tonic-gate 	struct rsl *rp;
15627c478bd9Sstevel@tonic-gate 	nvlist_t *fault;
15637c478bd9Sstevel@tonic-gate 	uint8_t cert;
15647c478bd9Sstevel@tonic-gate 	uint_t *frs;
15657c478bd9Sstevel@tonic-gate 	uint_t fravg, frsum, fr;
15667c478bd9Sstevel@tonic-gate 	int frcnt, fridx;
15677c478bd9Sstevel@tonic-gate 	boolean_t no_upsets = B_FALSE;
15687c478bd9Sstevel@tonic-gate 
15697c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->diags);
15707c478bd9Sstevel@tonic-gate 
15717c478bd9Sstevel@tonic-gate 	/*
15727c478bd9Sstevel@tonic-gate 	 * The current fmd interfaces don't allow us to solve a case
15737c478bd9Sstevel@tonic-gate 	 * that's already solved.  If we make a new case, what of the
15747c478bd9Sstevel@tonic-gate 	 * ereports?  We don't appear to have an interface that allows
15757c478bd9Sstevel@tonic-gate 	 * us to access the ereports attached to a case (if we wanted
15767c478bd9Sstevel@tonic-gate 	 * to copy the original case's ereport attachments to the new
15777c478bd9Sstevel@tonic-gate 	 * case) and it's also a bit unclear if there would be any
15787c478bd9Sstevel@tonic-gate 	 * problems with having ereports attached to multiple cases
15797c478bd9Sstevel@tonic-gate 	 * and/or attaching DIAGNOSED ereports to a case.  For now,
15807c478bd9Sstevel@tonic-gate 	 * we'll just output a message.
15817c478bd9Sstevel@tonic-gate 	 */
15827c478bd9Sstevel@tonic-gate 	if (fmep->posted_suspects ||
15837c478bd9Sstevel@tonic-gate 	    fmd_case_solved(fmep->hdl, fmep->fmcase)) {
15847c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_NONL, "Revised diagnosis for case %s: ",
15857c478bd9Sstevel@tonic-gate 		    fmd_case_uuid(fmep->hdl, fmep->fmcase));
15867c478bd9Sstevel@tonic-gate 		for (ep = fmep->suspects; ep; ep = ep->suspects) {
15877c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_NONL, " ");
15887c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_NONL, ep);
15897c478bd9Sstevel@tonic-gate 		}
15907c478bd9Sstevel@tonic-gate 		out(O_ALTFP, NULL);
15917c478bd9Sstevel@tonic-gate 		return;
15927c478bd9Sstevel@tonic-gate 	}
15937c478bd9Sstevel@tonic-gate 
15947c478bd9Sstevel@tonic-gate 	/*
15957c478bd9Sstevel@tonic-gate 	 * If we're auto-closing upsets, we don't want to include them
15967c478bd9Sstevel@tonic-gate 	 * in any produced suspect lists or certainty accounting.
15977c478bd9Sstevel@tonic-gate 	 */
15987c478bd9Sstevel@tonic-gate 	if (Autoclose != NULL)
15997c478bd9Sstevel@tonic-gate 		if (strcmp(Autoclose, "true") == 0 ||
16007c478bd9Sstevel@tonic-gate 		    strcmp(Autoclose, "all") == 0 ||
16017c478bd9Sstevel@tonic-gate 		    strcmp(Autoclose, "upsets") == 0)
16027c478bd9Sstevel@tonic-gate 			no_upsets = B_TRUE;
16037c478bd9Sstevel@tonic-gate 
16047c478bd9Sstevel@tonic-gate 	trim_suspects(fmep, no_upsets, &srl, &erl);
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	/*
16077c478bd9Sstevel@tonic-gate 	 * If the resulting suspect list has no members, we're
16087c478bd9Sstevel@tonic-gate 	 * done.  Returning here will simply close the case.
16097c478bd9Sstevel@tonic-gate 	 */
16107c478bd9Sstevel@tonic-gate 	if (fmep->nsuspects == 0) {
16117c478bd9Sstevel@tonic-gate 		out(O_ALTFP,
16127c478bd9Sstevel@tonic-gate 		    "[FME%d, case %s (all suspects are upsets)]",
16137c478bd9Sstevel@tonic-gate 		    fmep->id, fmd_case_uuid(fmep->hdl, fmep->fmcase));
16147c478bd9Sstevel@tonic-gate 		FREE(srl);
16157c478bd9Sstevel@tonic-gate 		restore_suspects(fmep);
16167c478bd9Sstevel@tonic-gate 		return;
16177c478bd9Sstevel@tonic-gate 	}
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 	/*
16207c478bd9Sstevel@tonic-gate 	 * If the suspect list is all faults, then for a given fault,
16217c478bd9Sstevel@tonic-gate 	 * say X of N, X's certainty is computed via:
16227c478bd9Sstevel@tonic-gate 	 *
16237c478bd9Sstevel@tonic-gate 	 * fitrate(X) / (fitrate(1) + ... + fitrate(N)) * 100
16247c478bd9Sstevel@tonic-gate 	 *
16257c478bd9Sstevel@tonic-gate 	 * If none of the suspects are faults, and there are N suspects,
16267c478bd9Sstevel@tonic-gate 	 * the certainty of a given suspect is 100/N.
16277c478bd9Sstevel@tonic-gate 	 *
16287c478bd9Sstevel@tonic-gate 	 * If there are are a mixture of faults and other problems in
16297c478bd9Sstevel@tonic-gate 	 * the suspect list, we take an average of the faults'
16307c478bd9Sstevel@tonic-gate 	 * FITrates and treat this average as the FITrate for any
16317c478bd9Sstevel@tonic-gate 	 * non-faults.  The fitrate of any given suspect is then
16327c478bd9Sstevel@tonic-gate 	 * computed per the first formula above.
16337c478bd9Sstevel@tonic-gate 	 */
16347c478bd9Sstevel@tonic-gate 	if (fmep->nonfault == fmep->nsuspects) {
16357c478bd9Sstevel@tonic-gate 		/* NO faults in the suspect list */
16367c478bd9Sstevel@tonic-gate 		cert = percentof(1, fmep->nsuspects);
16377c478bd9Sstevel@tonic-gate 	} else {
16387c478bd9Sstevel@tonic-gate 		/* sum the fitrates */
16397c478bd9Sstevel@tonic-gate 		frs = alloca(fmep->nsuspects * sizeof (uint_t));
16407c478bd9Sstevel@tonic-gate 		fridx = frcnt = frsum = 0;
16417c478bd9Sstevel@tonic-gate 
16427c478bd9Sstevel@tonic-gate 		for (rp = srl; rp <= erl; rp++) {
16437c478bd9Sstevel@tonic-gate 			struct node *n;
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 			if (rp->suspect == NULL)
16467c478bd9Sstevel@tonic-gate 				continue;
16477c478bd9Sstevel@tonic-gate 			if (!is_fault(rp->suspect->t)) {
16487c478bd9Sstevel@tonic-gate 				frs[fridx++] = 0;
16497c478bd9Sstevel@tonic-gate 				continue;
16507c478bd9Sstevel@tonic-gate 			}
16517c478bd9Sstevel@tonic-gate 			n = eventprop_lookup(rp->suspect, L_FITrate);
16527c478bd9Sstevel@tonic-gate 			if (node2uint(n, &fr) != 0) {
16537c478bd9Sstevel@tonic-gate 				out(O_DEBUG|O_NONL, "event ");
16547c478bd9Sstevel@tonic-gate 				ipath_print(O_DEBUG|O_NONL,
16557c478bd9Sstevel@tonic-gate 				    ep->enode->u.event.ename->u.name.s,
16567c478bd9Sstevel@tonic-gate 				    ep->ipp);
16577c478bd9Sstevel@tonic-gate 				out(O_DEBUG, " has no FITrate (using 1)");
16587c478bd9Sstevel@tonic-gate 				fr = 1;
16597c478bd9Sstevel@tonic-gate 			} else if (fr == 0) {
16607c478bd9Sstevel@tonic-gate 				out(O_DEBUG|O_NONL, "event ");
16617c478bd9Sstevel@tonic-gate 				ipath_print(O_DEBUG|O_NONL,
16627c478bd9Sstevel@tonic-gate 				    ep->enode->u.event.ename->u.name.s,
16637c478bd9Sstevel@tonic-gate 				    ep->ipp);
16647c478bd9Sstevel@tonic-gate 				out(O_DEBUG, " has zero FITrate (using 1)");
16657c478bd9Sstevel@tonic-gate 				fr = 1;
16667c478bd9Sstevel@tonic-gate 			}
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 			frs[fridx++] = fr;
16697c478bd9Sstevel@tonic-gate 			frsum += fr;
16707c478bd9Sstevel@tonic-gate 			frcnt++;
16717c478bd9Sstevel@tonic-gate 		}
16727c478bd9Sstevel@tonic-gate 		fravg = avg(frsum, frcnt);
16737c478bd9Sstevel@tonic-gate 		for (fridx = 0; fridx < fmep->nsuspects; fridx++)
16747c478bd9Sstevel@tonic-gate 			if (frs[fridx] == 0) {
16757c478bd9Sstevel@tonic-gate 				frs[fridx] = fravg;
16767c478bd9Sstevel@tonic-gate 				frsum += fravg;
16777c478bd9Sstevel@tonic-gate 			}
16787c478bd9Sstevel@tonic-gate 	}
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 	/* Add them in reverse order of our sort, as fmd reverses order */
16817c478bd9Sstevel@tonic-gate 	for (rp = erl; rp >= srl; rp--) {
16827c478bd9Sstevel@tonic-gate 		if (rp->suspect == NULL)
16837c478bd9Sstevel@tonic-gate 			continue;
16847c478bd9Sstevel@tonic-gate 		if (fmep->nonfault != fmep->nsuspects)
16857c478bd9Sstevel@tonic-gate 			cert = percentof(frs[--fridx], frsum);
16867c478bd9Sstevel@tonic-gate 		fault = fmd_nvl_create_fault(fmep->hdl,
16877c478bd9Sstevel@tonic-gate 		    rp->suspect->enode->u.event.ename->u.name.s,
16887c478bd9Sstevel@tonic-gate 		    cert,
16897c478bd9Sstevel@tonic-gate 		    rp->asru,
16907c478bd9Sstevel@tonic-gate 		    rp->fru,
16917c478bd9Sstevel@tonic-gate 		    rp->rsrc);
16927c478bd9Sstevel@tonic-gate 		if (fault == NULL)
16937c478bd9Sstevel@tonic-gate 			out(O_DIE, "fault creation failed");
16947c478bd9Sstevel@tonic-gate 		fmd_case_add_suspect(fmep->hdl, fmep->fmcase, fault);
16957c478bd9Sstevel@tonic-gate 		rp->suspect->fault = fault;
16967c478bd9Sstevel@tonic-gate 		rslfree(rp);
16977c478bd9Sstevel@tonic-gate 	}
16987c478bd9Sstevel@tonic-gate 	fmd_case_solve(fmep->hdl, fmep->fmcase);
16997c478bd9Sstevel@tonic-gate 	out(O_ALTFP, "[solving FME%d, case %s]", fmep->id,
17007c478bd9Sstevel@tonic-gate 	    fmd_case_uuid(fmep->hdl, fmep->fmcase));
17017c478bd9Sstevel@tonic-gate 
17027c478bd9Sstevel@tonic-gate 	if (Autoconvict) {
17037c478bd9Sstevel@tonic-gate 		for (rp = srl; rp <= erl; rp++) {
17047c478bd9Sstevel@tonic-gate 			if (rp->suspect == NULL)
17057c478bd9Sstevel@tonic-gate 				continue;
17067c478bd9Sstevel@tonic-gate 			fmd_case_convict(fmep->hdl,
17077c478bd9Sstevel@tonic-gate 			    fmep->fmcase, rp->suspect->fault);
17087c478bd9Sstevel@tonic-gate 		}
17097c478bd9Sstevel@tonic-gate 		out(O_ALTFP, "[convicting FME%d, case %s]", fmep->id,
17107c478bd9Sstevel@tonic-gate 		    fmd_case_uuid(fmep->hdl, fmep->fmcase));
17117c478bd9Sstevel@tonic-gate 	}
17127c478bd9Sstevel@tonic-gate 
17137c478bd9Sstevel@tonic-gate 	/*
17147c478bd9Sstevel@tonic-gate 	 * revert to the original suspect list
17157c478bd9Sstevel@tonic-gate 	 */
17167c478bd9Sstevel@tonic-gate 	FREE(srl);
17177c478bd9Sstevel@tonic-gate 	restore_suspects(fmep);
17187c478bd9Sstevel@tonic-gate }
17197c478bd9Sstevel@tonic-gate 
17207c478bd9Sstevel@tonic-gate static void
17217c478bd9Sstevel@tonic-gate publish_undiagnosable(fmd_hdl_t *hdl, fmd_event_t *ffep)
17227c478bd9Sstevel@tonic-gate {
17237c478bd9Sstevel@tonic-gate 	struct case_list *newcase;
17247c478bd9Sstevel@tonic-gate 	nvlist_t *defect;
17257c478bd9Sstevel@tonic-gate 
17267c478bd9Sstevel@tonic-gate 	out(O_ALTFP,
17277c478bd9Sstevel@tonic-gate 	    "[undiagnosable ereport received, "
17287c478bd9Sstevel@tonic-gate 	    "creating and closing a new case (%s)]",
17297c478bd9Sstevel@tonic-gate 	    Undiag_reason ? Undiag_reason : "reason not provided");
17307c478bd9Sstevel@tonic-gate 
17317c478bd9Sstevel@tonic-gate 	newcase = MALLOC(sizeof (struct case_list));
17327c478bd9Sstevel@tonic-gate 	newcase->next = NULL;
17337c478bd9Sstevel@tonic-gate 
17347c478bd9Sstevel@tonic-gate 	newcase->fmcase = fmd_case_open(hdl, NULL);
17357c478bd9Sstevel@tonic-gate 	if (Undiagablecaselist != NULL)
17367c478bd9Sstevel@tonic-gate 		newcase->next = Undiagablecaselist;
17377c478bd9Sstevel@tonic-gate 	Undiagablecaselist = newcase;
17387c478bd9Sstevel@tonic-gate 
17397c478bd9Sstevel@tonic-gate 	if (ffep != NULL)
17407c478bd9Sstevel@tonic-gate 		fmd_case_add_ereport(hdl, newcase->fmcase, ffep);
17417c478bd9Sstevel@tonic-gate 
17427c478bd9Sstevel@tonic-gate 	defect = fmd_nvl_create_fault(hdl, UNDIAGNOSABLE_DEFECT, 100,
17437c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL);
17447c478bd9Sstevel@tonic-gate 	if (Undiag_reason != NULL)
17457c478bd9Sstevel@tonic-gate 		(void) nvlist_add_string(defect, UNDIAG_REASON, Undiag_reason);
17467c478bd9Sstevel@tonic-gate 	fmd_case_add_suspect(hdl, newcase->fmcase, defect);
17477c478bd9Sstevel@tonic-gate 
17487c478bd9Sstevel@tonic-gate 	fmd_case_solve(hdl, newcase->fmcase);
17497c478bd9Sstevel@tonic-gate 	fmd_case_close(hdl, newcase->fmcase);
17507c478bd9Sstevel@tonic-gate }
17517c478bd9Sstevel@tonic-gate 
17527c478bd9Sstevel@tonic-gate static void
17537c478bd9Sstevel@tonic-gate fme_undiagnosable(struct fme *f)
17547c478bd9Sstevel@tonic-gate {
17557c478bd9Sstevel@tonic-gate 	nvlist_t *defect;
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 	out(O_ALTFP, "[solving/closing FME%d, case %s (%s)]",
17587c478bd9Sstevel@tonic-gate 	    f->id, fmd_case_uuid(f->hdl, f->fmcase),
17597c478bd9Sstevel@tonic-gate 	    Undiag_reason ? Undiag_reason : "undiagnosable");
17607c478bd9Sstevel@tonic-gate 
17617c478bd9Sstevel@tonic-gate 	defect = fmd_nvl_create_fault(f->hdl, UNDIAGNOSABLE_DEFECT, 100,
17627c478bd9Sstevel@tonic-gate 	    NULL, NULL, NULL);
17637c478bd9Sstevel@tonic-gate 	if (Undiag_reason != NULL)
17647c478bd9Sstevel@tonic-gate 		(void) nvlist_add_string(defect, UNDIAG_REASON, Undiag_reason);
17657c478bd9Sstevel@tonic-gate 	fmd_case_add_suspect(f->hdl, f->fmcase, defect);
17667c478bd9Sstevel@tonic-gate 	fmd_case_solve(f->hdl, f->fmcase);
17677c478bd9Sstevel@tonic-gate 	destroy_fme_bufs(f);
17687c478bd9Sstevel@tonic-gate 	fmd_case_close(f->hdl, f->fmcase);
17697c478bd9Sstevel@tonic-gate }
17707c478bd9Sstevel@tonic-gate 
17717c478bd9Sstevel@tonic-gate /*
17727c478bd9Sstevel@tonic-gate  * fme_close_case
17737c478bd9Sstevel@tonic-gate  *
17747c478bd9Sstevel@tonic-gate  *	Find the requested case amongst our fmes and close it.  Free up
17757c478bd9Sstevel@tonic-gate  *	the related fme.
17767c478bd9Sstevel@tonic-gate  */
17777c478bd9Sstevel@tonic-gate void
17787c478bd9Sstevel@tonic-gate fme_close_case(fmd_hdl_t *hdl, fmd_case_t *fmcase)
17797c478bd9Sstevel@tonic-gate {
17807c478bd9Sstevel@tonic-gate 	struct case_list *ucasep, *prevcasep = NULL;
17817c478bd9Sstevel@tonic-gate 	struct fme *prev = NULL;
17827c478bd9Sstevel@tonic-gate 	struct fme *fmep;
17837c478bd9Sstevel@tonic-gate 
17847c478bd9Sstevel@tonic-gate 	for (ucasep = Undiagablecaselist; ucasep; ucasep = ucasep->next) {
17857c478bd9Sstevel@tonic-gate 		if (fmcase != ucasep->fmcase) {
17867c478bd9Sstevel@tonic-gate 			prevcasep = ucasep;
17877c478bd9Sstevel@tonic-gate 			continue;
17887c478bd9Sstevel@tonic-gate 		}
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 		if (prevcasep == NULL)
17917c478bd9Sstevel@tonic-gate 			Undiagablecaselist = Undiagablecaselist->next;
17927c478bd9Sstevel@tonic-gate 		else
17937c478bd9Sstevel@tonic-gate 			prevcasep->next = ucasep->next;
17947c478bd9Sstevel@tonic-gate 
17957c478bd9Sstevel@tonic-gate 		FREE(ucasep);
17967c478bd9Sstevel@tonic-gate 		return;
17977c478bd9Sstevel@tonic-gate 	}
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate 	for (fmep = FMElist; fmep; fmep = fmep->next) {
18007c478bd9Sstevel@tonic-gate 		if (fmep->hdl == hdl && fmep->fmcase == fmcase)
18017c478bd9Sstevel@tonic-gate 			break;
18027c478bd9Sstevel@tonic-gate 		prev = fmep;
18037c478bd9Sstevel@tonic-gate 	}
18047c478bd9Sstevel@tonic-gate 
18057c478bd9Sstevel@tonic-gate 	if (fmep == NULL) {
18067c478bd9Sstevel@tonic-gate 		out(O_WARN, "Eft asked to close unrecognized case [%s].",
18077c478bd9Sstevel@tonic-gate 		    fmd_case_uuid(hdl, fmcase));
18087c478bd9Sstevel@tonic-gate 		return;
18097c478bd9Sstevel@tonic-gate 	}
18107c478bd9Sstevel@tonic-gate 
18117c478bd9Sstevel@tonic-gate 	if (EFMElist == fmep)
18127c478bd9Sstevel@tonic-gate 		EFMElist = prev;
18137c478bd9Sstevel@tonic-gate 
18147c478bd9Sstevel@tonic-gate 	if (prev == NULL)
18157c478bd9Sstevel@tonic-gate 		FMElist = FMElist->next;
18167c478bd9Sstevel@tonic-gate 	else
18177c478bd9Sstevel@tonic-gate 		prev->next = fmep->next;
18187c478bd9Sstevel@tonic-gate 
18197c478bd9Sstevel@tonic-gate 	fmep->next = NULL;
18207c478bd9Sstevel@tonic-gate 
18217c478bd9Sstevel@tonic-gate 	/* Get rid of any timer this fme has set */
18227c478bd9Sstevel@tonic-gate 	if (fmep->wull != 0)
18237c478bd9Sstevel@tonic-gate 		fmd_timer_remove(fmep->hdl, fmep->timer);
18247c478bd9Sstevel@tonic-gate 
18257c478bd9Sstevel@tonic-gate 	if (ClosedFMEs == NULL) {
18267c478bd9Sstevel@tonic-gate 		ClosedFMEs = fmep;
18277c478bd9Sstevel@tonic-gate 	} else {
18287c478bd9Sstevel@tonic-gate 		fmep->next = ClosedFMEs;
18297c478bd9Sstevel@tonic-gate 		ClosedFMEs = fmep;
18307c478bd9Sstevel@tonic-gate 	}
1831*0cc1f05eSjrutt 
1832*0cc1f05eSjrutt 	Open_fme_count--;
1833*0cc1f05eSjrutt 
1834*0cc1f05eSjrutt 	/* See if we can close the overflow FME */
1835*0cc1f05eSjrutt 	if (Open_fme_count <= Max_fme) {
1836*0cc1f05eSjrutt 		for (fmep = FMElist; fmep; fmep = fmep->next) {
1837*0cc1f05eSjrutt 			if (fmep->overflow && !(fmd_case_closed(fmep->hdl,
1838*0cc1f05eSjrutt 			    fmep->fmcase)))
1839*0cc1f05eSjrutt 				break;
1840*0cc1f05eSjrutt 		}
1841*0cc1f05eSjrutt 
1842*0cc1f05eSjrutt 		if (fmep != NULL)
1843*0cc1f05eSjrutt 			fmd_case_close(fmep->hdl, fmep->fmcase);
1844*0cc1f05eSjrutt 	}
18457c478bd9Sstevel@tonic-gate }
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate /*
18487c478bd9Sstevel@tonic-gate  * fme_set_timer()
18497c478bd9Sstevel@tonic-gate  *	If the time we need to wait for the given FME is less than the
18507c478bd9Sstevel@tonic-gate  *	current timer, kick that old timer out and establish a new one.
18517c478bd9Sstevel@tonic-gate  */
18527c478bd9Sstevel@tonic-gate static void
18537c478bd9Sstevel@tonic-gate fme_set_timer(struct fme *fmep, unsigned long long wull)
18547c478bd9Sstevel@tonic-gate {
18557c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, " fme_set_timer: request to wait ");
18567c478bd9Sstevel@tonic-gate 	ptree_timeval(O_ALTFP|O_VERB, &wull);
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 	if (wull <= fmep->pull) {
18597c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "already have waited at least ");
18607c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB, &fmep->pull);
18617c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
18627c478bd9Sstevel@tonic-gate 		/* we've waited at least wull already, don't need timer */
18637c478bd9Sstevel@tonic-gate 		return;
18647c478bd9Sstevel@tonic-gate 	}
18657c478bd9Sstevel@tonic-gate 
18667c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, " currently ");
18677c478bd9Sstevel@tonic-gate 	if (fmep->wull != 0) {
18687c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "waiting ");
18697c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB, &fmep->wull);
18707c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
18717c478bd9Sstevel@tonic-gate 	} else {
18727c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "not waiting");
18737c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
18747c478bd9Sstevel@tonic-gate 	}
18757c478bd9Sstevel@tonic-gate 
18767c478bd9Sstevel@tonic-gate 	if (fmep->wull != 0)
18777c478bd9Sstevel@tonic-gate 		if (wull >= fmep->wull)
18787c478bd9Sstevel@tonic-gate 			/* New timer would fire later than established timer */
18797c478bd9Sstevel@tonic-gate 			return;
18807c478bd9Sstevel@tonic-gate 
18817c478bd9Sstevel@tonic-gate 	if (fmep->wull != 0)
18827c478bd9Sstevel@tonic-gate 		fmd_timer_remove(fmep->hdl, fmep->timer);
18837c478bd9Sstevel@tonic-gate 
18847c478bd9Sstevel@tonic-gate 	fmep->timer = fmd_timer_install(fmep->hdl, (void *)fmep,
18857c478bd9Sstevel@tonic-gate 	    fmep->e0r, wull);
18867c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, "timer set, id is %ld", fmep->timer);
18877c478bd9Sstevel@tonic-gate 	fmep->wull = wull;
18887c478bd9Sstevel@tonic-gate }
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate void
18917c478bd9Sstevel@tonic-gate fme_timer_fired(struct fme *fmep, id_t tid)
18927c478bd9Sstevel@tonic-gate {
18937c478bd9Sstevel@tonic-gate 	struct fme *ffmep = NULL;
18947c478bd9Sstevel@tonic-gate 
18957c478bd9Sstevel@tonic-gate 	for (ffmep = FMElist; ffmep; ffmep = ffmep->next)
18967c478bd9Sstevel@tonic-gate 		if (ffmep == fmep)
18977c478bd9Sstevel@tonic-gate 			break;
18987c478bd9Sstevel@tonic-gate 
18997c478bd9Sstevel@tonic-gate 	if (ffmep == NULL) {
19007c478bd9Sstevel@tonic-gate 		out(O_WARN, "Timer fired for an FME (%p) not in FMEs list.",
19017c478bd9Sstevel@tonic-gate 		    (void *)fmep);
19027c478bd9Sstevel@tonic-gate 		return;
19037c478bd9Sstevel@tonic-gate 	}
19047c478bd9Sstevel@tonic-gate 
19057c478bd9Sstevel@tonic-gate 	if (tid != fmep->htid) {
19067c478bd9Sstevel@tonic-gate 		/*
19077c478bd9Sstevel@tonic-gate 		 * normal timer (not the hesitation timer
19087c478bd9Sstevel@tonic-gate 		 */
19097c478bd9Sstevel@tonic-gate 		fmep->pull = fmep->wull;
19107c478bd9Sstevel@tonic-gate 		fmep->wull = 0;
19117c478bd9Sstevel@tonic-gate 		fmd_buf_write(fmep->hdl, fmep->fmcase,
19127c478bd9Sstevel@tonic-gate 		    WOBUF_PULL, (void *)&fmep->pull, sizeof (fmep->pull));
19137c478bd9Sstevel@tonic-gate 	} else {
19147c478bd9Sstevel@tonic-gate 		fmep->hesitated = 1;
19157c478bd9Sstevel@tonic-gate 	}
19167c478bd9Sstevel@tonic-gate 	fme_eval(fmep, NULL);
19177c478bd9Sstevel@tonic-gate }
19187c478bd9Sstevel@tonic-gate 
19197c478bd9Sstevel@tonic-gate /*
19207c478bd9Sstevel@tonic-gate  * Preserve the fme's suspect list in its psuspects list, NULLing the
19217c478bd9Sstevel@tonic-gate  * suspects list in the meantime.
19227c478bd9Sstevel@tonic-gate  */
19237c478bd9Sstevel@tonic-gate static void
19247c478bd9Sstevel@tonic-gate save_suspects(struct fme *fmep)
19257c478bd9Sstevel@tonic-gate {
19267c478bd9Sstevel@tonic-gate 	struct event *ep;
19277c478bd9Sstevel@tonic-gate 	struct event *nextep;
19287c478bd9Sstevel@tonic-gate 
19297c478bd9Sstevel@tonic-gate 	/* zero out the previous suspect list */
19307c478bd9Sstevel@tonic-gate 	for (ep = fmep->psuspects; ep; ep = nextep) {
19317c478bd9Sstevel@tonic-gate 		nextep = ep->psuspects;
19327c478bd9Sstevel@tonic-gate 		ep->psuspects = NULL;
19337c478bd9Sstevel@tonic-gate 	}
19347c478bd9Sstevel@tonic-gate 	fmep->psuspects = NULL;
19357c478bd9Sstevel@tonic-gate 
19367c478bd9Sstevel@tonic-gate 	/* zero out the suspect list, copying it to previous suspect list */
19377c478bd9Sstevel@tonic-gate 	fmep->psuspects = fmep->suspects;
19387c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = nextep) {
19397c478bd9Sstevel@tonic-gate 		nextep = ep->suspects;
19407c478bd9Sstevel@tonic-gate 		ep->psuspects = ep->suspects;
19417c478bd9Sstevel@tonic-gate 		ep->suspects = NULL;
19427c478bd9Sstevel@tonic-gate 		ep->is_suspect = 0;
19437c478bd9Sstevel@tonic-gate 	}
19447c478bd9Sstevel@tonic-gate 	fmep->suspects = NULL;
19457c478bd9Sstevel@tonic-gate 	fmep->nsuspects = 0;
19467c478bd9Sstevel@tonic-gate 	fmep->nonfault = 0;
19477c478bd9Sstevel@tonic-gate }
19487c478bd9Sstevel@tonic-gate 
19497c478bd9Sstevel@tonic-gate /*
19507c478bd9Sstevel@tonic-gate  * Retrieve the fme's suspect list from its psuspects list.
19517c478bd9Sstevel@tonic-gate  */
19527c478bd9Sstevel@tonic-gate static void
19537c478bd9Sstevel@tonic-gate restore_suspects(struct fme *fmep)
19547c478bd9Sstevel@tonic-gate {
19557c478bd9Sstevel@tonic-gate 	struct event *ep;
19567c478bd9Sstevel@tonic-gate 	struct event *nextep;
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate 	fmep->nsuspects = fmep->nonfault = 0;
19597c478bd9Sstevel@tonic-gate 	fmep->suspects = fmep->psuspects;
19607c478bd9Sstevel@tonic-gate 	for (ep = fmep->psuspects; ep; ep = nextep) {
19617c478bd9Sstevel@tonic-gate 		fmep->nsuspects++;
19627c478bd9Sstevel@tonic-gate 		if (!is_fault(ep->t))
19637c478bd9Sstevel@tonic-gate 			fmep->nonfault++;
19647c478bd9Sstevel@tonic-gate 		nextep = ep->psuspects;
19657c478bd9Sstevel@tonic-gate 		ep->suspects = ep->psuspects;
19667c478bd9Sstevel@tonic-gate 	}
19677c478bd9Sstevel@tonic-gate }
19687c478bd9Sstevel@tonic-gate 
19697c478bd9Sstevel@tonic-gate /*
19707c478bd9Sstevel@tonic-gate  * this is what we use to call the Emrys prototype code instead of main()
19717c478bd9Sstevel@tonic-gate  */
19727c478bd9Sstevel@tonic-gate static void
19737c478bd9Sstevel@tonic-gate fme_eval(struct fme *fmep, fmd_event_t *ffep)
19747c478bd9Sstevel@tonic-gate {
19757c478bd9Sstevel@tonic-gate 	struct event *ep;
19767c478bd9Sstevel@tonic-gate 	unsigned long long my_delay = TIMEVAL_EVENTUALLY;
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate 	save_suspects(fmep);
19797c478bd9Sstevel@tonic-gate 
19807c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, "Evaluate FME %d", fmep->id);
19817c478bd9Sstevel@tonic-gate 	indent_set("  ");
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate 	initialize_cycles(fmep);
19847c478bd9Sstevel@tonic-gate 	fmep->state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay, NULL);
19857c478bd9Sstevel@tonic-gate 
19867c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "FME%d state: %s, suspect list:", fmep->id,
19877c478bd9Sstevel@tonic-gate 	    fme_state2str(fmep->state));
19887c478bd9Sstevel@tonic-gate 	for (ep = fmep->suspects; ep; ep = ep->suspects) {
19897c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " ");
19907c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
19917c478bd9Sstevel@tonic-gate 	}
19927c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate 	if (fmep->posted_suspects) {
19957c478bd9Sstevel@tonic-gate 		/*
19967c478bd9Sstevel@tonic-gate 		 * this FME has already posted a diagnosis, so see if
19977c478bd9Sstevel@tonic-gate 		 * the event changed the diagnosis and print a warning
19987c478bd9Sstevel@tonic-gate 		 * if it did.
19997c478bd9Sstevel@tonic-gate 		 *
20007c478bd9Sstevel@tonic-gate 		 */
20017c478bd9Sstevel@tonic-gate 		if (suspects_changed(fmep)) {
20027c478bd9Sstevel@tonic-gate 			print_suspects(SLCHANGED, fmep);
20037c478bd9Sstevel@tonic-gate 			publish_suspects(fmep);
20047c478bd9Sstevel@tonic-gate 		}
20057c478bd9Sstevel@tonic-gate 	} else {
20067c478bd9Sstevel@tonic-gate 		switch (fmep->state) {
20077c478bd9Sstevel@tonic-gate 		case FME_CREDIBLE:
20087c478bd9Sstevel@tonic-gate 			/*
20097c478bd9Sstevel@tonic-gate 			 * if the suspect list contains any upsets, we
20107c478bd9Sstevel@tonic-gate 			 * turn off the hesitation logic (by setting
20117c478bd9Sstevel@tonic-gate 			 * the hesitate flag which normally indicates
20127c478bd9Sstevel@tonic-gate 			 * we've already done the hesitate logic).
20137c478bd9Sstevel@tonic-gate 			 * this is done because hesitating with upsets
20147c478bd9Sstevel@tonic-gate 			 * causes us to explain away additional soft errors
20157c478bd9Sstevel@tonic-gate 			 * while the upset FME stays open.
20167c478bd9Sstevel@tonic-gate 			 */
20177c478bd9Sstevel@tonic-gate 			if (fmep->hesitated == 0) {
20187c478bd9Sstevel@tonic-gate 				struct event *s;
20197c478bd9Sstevel@tonic-gate 
20207c478bd9Sstevel@tonic-gate 				for (s = fmep->suspects; s; s = s->suspects) {
20217c478bd9Sstevel@tonic-gate 					if (s->t == N_UPSET) {
20227c478bd9Sstevel@tonic-gate 						fmep->hesitated = 1;
20237c478bd9Sstevel@tonic-gate 						break;
20247c478bd9Sstevel@tonic-gate 					}
20257c478bd9Sstevel@tonic-gate 				}
20267c478bd9Sstevel@tonic-gate 			}
20277c478bd9Sstevel@tonic-gate 
20287c478bd9Sstevel@tonic-gate 			if (Hesitate &&
20297c478bd9Sstevel@tonic-gate 			    fmep->suspects != NULL &&
20307c478bd9Sstevel@tonic-gate 			    fmep->suspects->suspects != NULL &&
20317c478bd9Sstevel@tonic-gate 			    fmep->hesitated == 0) {
20327c478bd9Sstevel@tonic-gate 				/*
20337c478bd9Sstevel@tonic-gate 				 * about to publish multi-entry suspect list,
20347c478bd9Sstevel@tonic-gate 				 * set the hesitation timer if not already set.
20357c478bd9Sstevel@tonic-gate 				 */
20367c478bd9Sstevel@tonic-gate 				if (fmep->htid == 0) {
20377c478bd9Sstevel@tonic-gate 					out(O_ALTFP|O_NONL,
20387c478bd9Sstevel@tonic-gate 					    "[hesitate FME%d, case %s ",
20397c478bd9Sstevel@tonic-gate 					    fmep->id,
20407c478bd9Sstevel@tonic-gate 					    fmd_case_uuid(fmep->hdl,
20417c478bd9Sstevel@tonic-gate 					    fmep->fmcase));
20427c478bd9Sstevel@tonic-gate 					ptree_timeval(O_ALTFP|O_NONL,
20437c478bd9Sstevel@tonic-gate 					    (unsigned long long *)&Hesitate);
20447c478bd9Sstevel@tonic-gate 					out(O_ALTFP, "]");
20457c478bd9Sstevel@tonic-gate 					fme_set_timer(fmep, my_delay);
20467c478bd9Sstevel@tonic-gate 					fmep->htid =
20477c478bd9Sstevel@tonic-gate 					    fmd_timer_install(fmep->hdl,
20487c478bd9Sstevel@tonic-gate 					    (void *)fmep, NULL, Hesitate);
20497c478bd9Sstevel@tonic-gate 				} else {
20507c478bd9Sstevel@tonic-gate 					out(O_ALTFP,
20517c478bd9Sstevel@tonic-gate 					    "[still hesitating FME%d, case %s]",
20527c478bd9Sstevel@tonic-gate 					    fmep->id,
20537c478bd9Sstevel@tonic-gate 					    fmd_case_uuid(fmep->hdl,
20547c478bd9Sstevel@tonic-gate 					    fmep->fmcase));
20557c478bd9Sstevel@tonic-gate 				}
20567c478bd9Sstevel@tonic-gate 			} else {
20577c478bd9Sstevel@tonic-gate 				print_suspects(SLNEW, fmep);
20587c478bd9Sstevel@tonic-gate 				(void) upsets_eval(fmep, ffep);
20597c478bd9Sstevel@tonic-gate 				publish_suspects(fmep);
20607c478bd9Sstevel@tonic-gate 				fmep->posted_suspects = 1;
20617c478bd9Sstevel@tonic-gate 				fmd_buf_write(fmep->hdl, fmep->fmcase,
20627c478bd9Sstevel@tonic-gate 				    WOBUF_POSTD,
20637c478bd9Sstevel@tonic-gate 				    (void *)&fmep->posted_suspects,
20647c478bd9Sstevel@tonic-gate 				    sizeof (fmep->posted_suspects));
20657c478bd9Sstevel@tonic-gate 			}
20667c478bd9Sstevel@tonic-gate 			break;
20677c478bd9Sstevel@tonic-gate 
20687c478bd9Sstevel@tonic-gate 		case FME_WAIT:
20697c478bd9Sstevel@tonic-gate 			/*
20707c478bd9Sstevel@tonic-gate 			 * singleton suspect list implies
20717c478bd9Sstevel@tonic-gate 			 * no point in waiting
20727c478bd9Sstevel@tonic-gate 			 */
20737c478bd9Sstevel@tonic-gate 			if (fmep->suspects &&
20747c478bd9Sstevel@tonic-gate 			    fmep->suspects->suspects == NULL) {
20757c478bd9Sstevel@tonic-gate 				print_suspects(SLNEW, fmep);
20767c478bd9Sstevel@tonic-gate 				(void) upsets_eval(fmep, ffep);
20777c478bd9Sstevel@tonic-gate 				publish_suspects(fmep);
20787c478bd9Sstevel@tonic-gate 				fmep->posted_suspects = 1;
20797c478bd9Sstevel@tonic-gate 				fmd_buf_write(fmep->hdl, fmep->fmcase,
20807c478bd9Sstevel@tonic-gate 				    WOBUF_POSTD,
20817c478bd9Sstevel@tonic-gate 				    (void *)&fmep->posted_suspects,
20827c478bd9Sstevel@tonic-gate 				    sizeof (fmep->posted_suspects));
20837c478bd9Sstevel@tonic-gate 				fmep->state = FME_CREDIBLE;
20847c478bd9Sstevel@tonic-gate 			} else {
20857c478bd9Sstevel@tonic-gate 				ASSERT(my_delay > fmep->ull);
20867c478bd9Sstevel@tonic-gate 				fme_set_timer(fmep, my_delay);
20877c478bd9Sstevel@tonic-gate 				print_suspects(SLWAIT, fmep);
20887c478bd9Sstevel@tonic-gate 			}
20897c478bd9Sstevel@tonic-gate 			break;
20907c478bd9Sstevel@tonic-gate 
20917c478bd9Sstevel@tonic-gate 		case FME_DISPROVED:
20927c478bd9Sstevel@tonic-gate 			print_suspects(SLDISPROVED, fmep);
20937c478bd9Sstevel@tonic-gate 			Undiag_reason = UD_UNSOLVD;
20947c478bd9Sstevel@tonic-gate 			fme_undiagnosable(fmep);
20957c478bd9Sstevel@tonic-gate 			break;
20967c478bd9Sstevel@tonic-gate 		}
20977c478bd9Sstevel@tonic-gate 	}
20987c478bd9Sstevel@tonic-gate 
20997c478bd9Sstevel@tonic-gate 	if (fmep->posted_suspects == 1 && Autoclose != NULL) {
21007c478bd9Sstevel@tonic-gate 		int doclose = 0;
21017c478bd9Sstevel@tonic-gate 
21027c478bd9Sstevel@tonic-gate 		if (strcmp(Autoclose, "true") == 0 ||
21037c478bd9Sstevel@tonic-gate 		    strcmp(Autoclose, "all") == 0)
21047c478bd9Sstevel@tonic-gate 			doclose = 1;
21057c478bd9Sstevel@tonic-gate 
21067c478bd9Sstevel@tonic-gate 		if (strcmp(Autoclose, "upsets") == 0) {
21077c478bd9Sstevel@tonic-gate 			doclose = 1;
21087c478bd9Sstevel@tonic-gate 			for (ep = fmep->suspects; ep; ep = ep->suspects) {
21097c478bd9Sstevel@tonic-gate 				if (ep->t != N_UPSET) {
21107c478bd9Sstevel@tonic-gate 					doclose = 0;
21117c478bd9Sstevel@tonic-gate 					break;
21127c478bd9Sstevel@tonic-gate 				}
21137c478bd9Sstevel@tonic-gate 			}
21147c478bd9Sstevel@tonic-gate 		}
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate 		if (doclose) {
21177c478bd9Sstevel@tonic-gate 			out(O_ALTFP, "[closing FME%d, case %s (autoclose)]",
21187c478bd9Sstevel@tonic-gate 			    fmep->id, fmd_case_uuid(fmep->hdl, fmep->fmcase));
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 			destroy_fme_bufs(fmep);
21217c478bd9Sstevel@tonic-gate 			fmd_case_close(fmep->hdl, fmep->fmcase);
21227c478bd9Sstevel@tonic-gate 		}
21237c478bd9Sstevel@tonic-gate 	}
21247c478bd9Sstevel@tonic-gate }
21257c478bd9Sstevel@tonic-gate 
21267c478bd9Sstevel@tonic-gate /*
21277c478bd9Sstevel@tonic-gate  * below here is the code derived from the Emrys prototype
21287c478bd9Sstevel@tonic-gate  */
21297c478bd9Sstevel@tonic-gate 
21307c478bd9Sstevel@tonic-gate static void indent(void);
21317c478bd9Sstevel@tonic-gate static int triggered(struct fme *fmep, struct event *ep, int mark);
21327c478bd9Sstevel@tonic-gate static void mark_arrows(struct fme *fmep, struct event *ep, int mark);
21337c478bd9Sstevel@tonic-gate static enum fme_state effects_test(struct fme *fmep,
21347c478bd9Sstevel@tonic-gate     struct event *fault_event);
21357c478bd9Sstevel@tonic-gate static enum fme_state requirements_test(struct fme *fmep, struct event *ep,
21367c478bd9Sstevel@tonic-gate     unsigned long long at_latest_by, unsigned long long *pdelay,
21377c478bd9Sstevel@tonic-gate     struct arrow *arrowp);
21387c478bd9Sstevel@tonic-gate static enum fme_state causes_test(struct fme *fmep, struct event *ep,
21397c478bd9Sstevel@tonic-gate     unsigned long long at_latest_by, unsigned long long *pdelay);
21407c478bd9Sstevel@tonic-gate 
21417c478bd9Sstevel@tonic-gate static int
21427c478bd9Sstevel@tonic-gate triggered(struct fme *fmep, struct event *ep, int mark)
21437c478bd9Sstevel@tonic-gate {
21447c478bd9Sstevel@tonic-gate 	struct bubble *bp;
21457c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
21467c478bd9Sstevel@tonic-gate 	int count = 0;
21477c478bd9Sstevel@tonic-gate 
21487c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Tcallcount);
21497c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
21507c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
21517c478bd9Sstevel@tonic-gate 		if (bp->t != B_TO)
21527c478bd9Sstevel@tonic-gate 			continue;
21537c478bd9Sstevel@tonic-gate 		for (ap = itree_next_arrow(bp, NULL); ap;
21547c478bd9Sstevel@tonic-gate 		    ap = itree_next_arrow(bp, ap)) {
21557c478bd9Sstevel@tonic-gate 			/* check count of marks against K in the bubble */
21567c478bd9Sstevel@tonic-gate 			if (ap->arrowp->tail->mark == mark &&
21577c478bd9Sstevel@tonic-gate 			    ++count >= bp->nork)
21587c478bd9Sstevel@tonic-gate 				return (1);
21597c478bd9Sstevel@tonic-gate 		}
21607c478bd9Sstevel@tonic-gate 	}
21617c478bd9Sstevel@tonic-gate 	return (0);
21627c478bd9Sstevel@tonic-gate }
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate static void
21657c478bd9Sstevel@tonic-gate mark_arrows(struct fme *fmep, struct event *ep, int mark)
21667c478bd9Sstevel@tonic-gate {
21677c478bd9Sstevel@tonic-gate 	struct bubble *bp;
21687c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
21697c478bd9Sstevel@tonic-gate 
21707c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
21717c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
21727c478bd9Sstevel@tonic-gate 		if (bp->t != B_FROM)
21737c478bd9Sstevel@tonic-gate 			continue;
21747c478bd9Sstevel@tonic-gate 		if (bp->mark != mark) {
21757c478bd9Sstevel@tonic-gate 			stats_counter_bump(fmep->Marrowcount);
21767c478bd9Sstevel@tonic-gate 			bp->mark = mark;
21777c478bd9Sstevel@tonic-gate 			for (ap = itree_next_arrow(bp, NULL); ap;
21787c478bd9Sstevel@tonic-gate 			    ap = itree_next_arrow(bp, ap)) {
21797c478bd9Sstevel@tonic-gate 				struct constraintlist *ctp;
21807c478bd9Sstevel@tonic-gate 				struct evalue value;
21817c478bd9Sstevel@tonic-gate 				int do_not_follow = 0;
21827c478bd9Sstevel@tonic-gate 				/*
21837c478bd9Sstevel@tonic-gate 				 * see if false constraint prevents us
21847c478bd9Sstevel@tonic-gate 				 * from traversing this arrow, but don't
21857c478bd9Sstevel@tonic-gate 				 * bother if the event is an ereport we
21867c478bd9Sstevel@tonic-gate 				 * haven't seen
21877c478bd9Sstevel@tonic-gate 				 */
21887c478bd9Sstevel@tonic-gate 				if (ap->arrowp->head->myevent->t != N_EREPORT ||
21897c478bd9Sstevel@tonic-gate 				    ap->arrowp->head->myevent->count != 0) {
21907c478bd9Sstevel@tonic-gate 					platform_set_payloadnvp(
21917c478bd9Sstevel@tonic-gate 					    ap->arrowp->head->myevent->nvp);
21927c478bd9Sstevel@tonic-gate 					for (ctp = ap->arrowp->constraints;
21937c478bd9Sstevel@tonic-gate 					    ctp != NULL; ctp = ctp->next) {
21947c478bd9Sstevel@tonic-gate 						if (eval_expr(ctp->cnode,
21957c478bd9Sstevel@tonic-gate 						    NULL, NULL,
21967c478bd9Sstevel@tonic-gate 						    &fmep->globals,
21977c478bd9Sstevel@tonic-gate 						    fmep->cfgdata->cooked,
21987c478bd9Sstevel@tonic-gate 						    ap->arrowp, 0,
21997c478bd9Sstevel@tonic-gate 						    &value) == 0 ||
22007c478bd9Sstevel@tonic-gate 						    value.t == UNDEFINED ||
22017c478bd9Sstevel@tonic-gate 						    value.v == 0) {
22027c478bd9Sstevel@tonic-gate 							do_not_follow = 1;
22037c478bd9Sstevel@tonic-gate 							break;
22047c478bd9Sstevel@tonic-gate 						}
22057c478bd9Sstevel@tonic-gate 					}
22067c478bd9Sstevel@tonic-gate 					platform_set_payloadnvp(NULL);
22077c478bd9Sstevel@tonic-gate 				}
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 				if (do_not_follow) {
22107c478bd9Sstevel@tonic-gate 					indent();
22117c478bd9Sstevel@tonic-gate 					out(O_ALTFP|O_VERB|O_NONL,
22127c478bd9Sstevel@tonic-gate 					    "  False arrow to ");
22137c478bd9Sstevel@tonic-gate 					itree_pevent_brief(
22147c478bd9Sstevel@tonic-gate 					    O_ALTFP|O_VERB|O_NONL,
22157c478bd9Sstevel@tonic-gate 					    ap->arrowp->head->myevent);
22167c478bd9Sstevel@tonic-gate 					out(O_ALTFP|O_VERB|O_NONL, " ");
22177c478bd9Sstevel@tonic-gate 					ptree(O_ALTFP|O_VERB|O_NONL,
22187c478bd9Sstevel@tonic-gate 					    ctp->cnode, 1, 0);
22197c478bd9Sstevel@tonic-gate 					out(O_ALTFP|O_VERB, NULL);
22207c478bd9Sstevel@tonic-gate 					continue;
22217c478bd9Sstevel@tonic-gate 				}
22227c478bd9Sstevel@tonic-gate 
22237c478bd9Sstevel@tonic-gate 				if (triggered(fmep, ap->arrowp->head->myevent,
22247c478bd9Sstevel@tonic-gate 				    mark))
22257c478bd9Sstevel@tonic-gate 					mark_arrows(fmep,
22267c478bd9Sstevel@tonic-gate 					    ap->arrowp->head->myevent, mark);
22277c478bd9Sstevel@tonic-gate 			}
22287c478bd9Sstevel@tonic-gate 		}
22297c478bd9Sstevel@tonic-gate 	}
22307c478bd9Sstevel@tonic-gate }
22317c478bd9Sstevel@tonic-gate 
22327c478bd9Sstevel@tonic-gate static enum fme_state
22337c478bd9Sstevel@tonic-gate effects_test(struct fme *fmep, struct event *fault_event)
22347c478bd9Sstevel@tonic-gate {
22357c478bd9Sstevel@tonic-gate 	struct event *error_event;
22367c478bd9Sstevel@tonic-gate 	enum fme_state return_value = FME_CREDIBLE;
22377c478bd9Sstevel@tonic-gate 
22387c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Ecallcount);
22397c478bd9Sstevel@tonic-gate 	indent_push("  E");
22407c478bd9Sstevel@tonic-gate 	indent();
22417c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
22427c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, fault_event);
22437c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
22447c478bd9Sstevel@tonic-gate 
22457c478bd9Sstevel@tonic-gate 	mark_arrows(fmep, fault_event, 1);
22467c478bd9Sstevel@tonic-gate 	for (error_event = fmep->observations;
22477c478bd9Sstevel@tonic-gate 	    error_event; error_event = error_event->observations) {
22487c478bd9Sstevel@tonic-gate 		indent();
22497c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " ");
22507c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, error_event);
22517c478bd9Sstevel@tonic-gate 		if (!triggered(fmep, error_event, 1)) {
22527c478bd9Sstevel@tonic-gate 			return_value = FME_DISPROVED;
22537c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, " NOT triggered");
22547c478bd9Sstevel@tonic-gate 			break;
22557c478bd9Sstevel@tonic-gate 		} else {
22567c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, " triggered");
22577c478bd9Sstevel@tonic-gate 		}
22587c478bd9Sstevel@tonic-gate 	}
22597c478bd9Sstevel@tonic-gate 	mark_arrows(fmep, fault_event, 0);
22607c478bd9Sstevel@tonic-gate 
22617c478bd9Sstevel@tonic-gate 	indent();
22627c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "<-%s ", fme_state2str(return_value));
22637c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, fault_event);
22647c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
22657c478bd9Sstevel@tonic-gate 	indent_pop();
22667c478bd9Sstevel@tonic-gate 	return (return_value);
22677c478bd9Sstevel@tonic-gate }
22687c478bd9Sstevel@tonic-gate 
22697c478bd9Sstevel@tonic-gate static enum fme_state
22707c478bd9Sstevel@tonic-gate requirements_test(struct fme *fmep, struct event *ep,
22717c478bd9Sstevel@tonic-gate     unsigned long long at_latest_by, unsigned long long *pdelay,
22727c478bd9Sstevel@tonic-gate     struct arrow *arrowp)
22737c478bd9Sstevel@tonic-gate {
22747c478bd9Sstevel@tonic-gate 	int waiting_events;
22757c478bd9Sstevel@tonic-gate 	int credible_events;
22767c478bd9Sstevel@tonic-gate 	enum fme_state return_value = FME_CREDIBLE;
22777c478bd9Sstevel@tonic-gate 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
22787c478bd9Sstevel@tonic-gate 	unsigned long long arrow_delay;
22797c478bd9Sstevel@tonic-gate 	unsigned long long my_delay;
22807c478bd9Sstevel@tonic-gate 	struct event *ep2;
22817c478bd9Sstevel@tonic-gate 	struct bubble *bp;
22827c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
22837c478bd9Sstevel@tonic-gate 
22847c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Rcallcount);
22857c478bd9Sstevel@tonic-gate 	indent_push("  R");
22867c478bd9Sstevel@tonic-gate 	indent();
22877c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
22887c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
22897c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, ", at latest by: ");
22907c478bd9Sstevel@tonic-gate 	ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
22917c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
22927c478bd9Sstevel@tonic-gate 
22937c478bd9Sstevel@tonic-gate 	if (ep->t == N_EREPORT) {
22947c478bd9Sstevel@tonic-gate 		if (ep->count == 0) {
22957c478bd9Sstevel@tonic-gate 			if (fmep->pull >= at_latest_by) {
22967c478bd9Sstevel@tonic-gate 				return_value = FME_DISPROVED;
22977c478bd9Sstevel@tonic-gate 			} else {
22987c478bd9Sstevel@tonic-gate 				*pdelay = at_latest_by;
22997c478bd9Sstevel@tonic-gate 				return_value = FME_WAIT;
23007c478bd9Sstevel@tonic-gate 			}
23017c478bd9Sstevel@tonic-gate 		} else if (arrowp != NULL) {
23027c478bd9Sstevel@tonic-gate 			/*
23037c478bd9Sstevel@tonic-gate 			 * evaluate constraints only for current observation
23047c478bd9Sstevel@tonic-gate 			 */
23057c478bd9Sstevel@tonic-gate 			struct constraintlist *ctp;
23067c478bd9Sstevel@tonic-gate 			struct evalue value;
23077c478bd9Sstevel@tonic-gate 
23087c478bd9Sstevel@tonic-gate 			platform_set_payloadnvp(ep->nvp);
23097c478bd9Sstevel@tonic-gate 			for (ctp = arrowp->constraints; ctp != NULL;
23107c478bd9Sstevel@tonic-gate 				ctp = ctp->next) {
23117c478bd9Sstevel@tonic-gate 				if (eval_expr(ctp->cnode, NULL, NULL,
23127c478bd9Sstevel@tonic-gate 				    &fmep->globals, fmep->cfgdata->cooked,
23137c478bd9Sstevel@tonic-gate 				    arrowp, 0, &value) == 0 ||
23147c478bd9Sstevel@tonic-gate 				    value.t == UNDEFINED || value.v == 0) {
23157c478bd9Sstevel@tonic-gate 					indent();
23167c478bd9Sstevel@tonic-gate 					out(O_ALTFP|O_VERB|O_NONL,
23177c478bd9Sstevel@tonic-gate 					    "  False constraint ");
23187c478bd9Sstevel@tonic-gate 					out(O_ALTFP|O_VERB|O_NONL, " ");
23197c478bd9Sstevel@tonic-gate 					ptree(O_ALTFP|O_VERB|O_NONL,
23207c478bd9Sstevel@tonic-gate 					    ctp->cnode, 1, 0);
23217c478bd9Sstevel@tonic-gate 					out(O_ALTFP|O_VERB, NULL);
23227c478bd9Sstevel@tonic-gate 					return_value = FME_DISPROVED;
23237c478bd9Sstevel@tonic-gate 					break;
23247c478bd9Sstevel@tonic-gate 				}
23257c478bd9Sstevel@tonic-gate 			}
23267c478bd9Sstevel@tonic-gate 			platform_set_payloadnvp(NULL);
23277c478bd9Sstevel@tonic-gate 		}
23287c478bd9Sstevel@tonic-gate 
23297c478bd9Sstevel@tonic-gate 		indent();
23307c478bd9Sstevel@tonic-gate 		switch (return_value) {
23317c478bd9Sstevel@tonic-gate 		case FME_CREDIBLE:
23327c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB|O_NONL, "<-CREDIBLE ");
23337c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
23347c478bd9Sstevel@tonic-gate 			break;
23357c478bd9Sstevel@tonic-gate 		case FME_DISPROVED:
23367c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
23377c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
23387c478bd9Sstevel@tonic-gate 			break;
23397c478bd9Sstevel@tonic-gate 		case FME_WAIT:
23407c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB|O_NONL, "<-WAIT ");
23417c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
23427c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB|O_NONL, " to ");
23437c478bd9Sstevel@tonic-gate 			ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
23447c478bd9Sstevel@tonic-gate 			break;
23457c478bd9Sstevel@tonic-gate 		default:
23467c478bd9Sstevel@tonic-gate 			out(O_DIE, "requirements_test: unexpected fme_state");
23477c478bd9Sstevel@tonic-gate 			break;
23487c478bd9Sstevel@tonic-gate 		}
23497c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
23507c478bd9Sstevel@tonic-gate 		indent_pop();
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 		return (return_value);
23537c478bd9Sstevel@tonic-gate 	}
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate 	/* this event is not a report, descend the tree */
23567c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
23577c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
23587c478bd9Sstevel@tonic-gate 		if (bp->t != B_FROM)
23597c478bd9Sstevel@tonic-gate 			continue;
23607c478bd9Sstevel@tonic-gate 		if (bp->mark == 0) {
23617c478bd9Sstevel@tonic-gate 			int n = bp->nork;
23627c478bd9Sstevel@tonic-gate 
23637c478bd9Sstevel@tonic-gate 			bp->mark = 1;
23647c478bd9Sstevel@tonic-gate 			credible_events = 0;
23657c478bd9Sstevel@tonic-gate 			waiting_events = 0;
23667c478bd9Sstevel@tonic-gate 			arrow_delay = TIMEVAL_EVENTUALLY;
23677c478bd9Sstevel@tonic-gate 			/*
23687c478bd9Sstevel@tonic-gate 			 * n is -1 for 'A' so adjust it.
23697c478bd9Sstevel@tonic-gate 			 * XXX just count up the arrows for now.
23707c478bd9Sstevel@tonic-gate 			 */
23717c478bd9Sstevel@tonic-gate 			if (n < 0) {
23727c478bd9Sstevel@tonic-gate 				n = 0;
23737c478bd9Sstevel@tonic-gate 				for (ap = itree_next_arrow(bp, NULL); ap;
23747c478bd9Sstevel@tonic-gate 				    ap = itree_next_arrow(bp, ap))
23757c478bd9Sstevel@tonic-gate 					n++;
23767c478bd9Sstevel@tonic-gate 				indent();
23777c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB, " Bubble Counted N=%d", n);
23787c478bd9Sstevel@tonic-gate 			} else {
23797c478bd9Sstevel@tonic-gate 				indent();
23807c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB, " Bubble N=%d", n);
23817c478bd9Sstevel@tonic-gate 			}
23827c478bd9Sstevel@tonic-gate 
23837c478bd9Sstevel@tonic-gate 			for (ap = itree_next_arrow(bp, NULL); ap;
23847c478bd9Sstevel@tonic-gate 			    ap = itree_next_arrow(bp, ap)) {
23857c478bd9Sstevel@tonic-gate 				ep2 = ap->arrowp->head->myevent;
23867c478bd9Sstevel@tonic-gate 				if (n <= credible_events)
23877c478bd9Sstevel@tonic-gate 					break;
23887c478bd9Sstevel@tonic-gate 
23897c478bd9Sstevel@tonic-gate 				if (triggered(fmep, ep2, 1))
23907c478bd9Sstevel@tonic-gate 					/* XXX adding max timevals! */
23917c478bd9Sstevel@tonic-gate 					switch (requirements_test(fmep, ep2,
23927c478bd9Sstevel@tonic-gate 					    at_latest_by + ap->arrowp->maxdelay,
23937c478bd9Sstevel@tonic-gate 					    &my_delay, ap->arrowp)) {
23947c478bd9Sstevel@tonic-gate 					case FME_CREDIBLE:
23957c478bd9Sstevel@tonic-gate 						credible_events++;
23967c478bd9Sstevel@tonic-gate 						break;
23977c478bd9Sstevel@tonic-gate 					case FME_DISPROVED:
23987c478bd9Sstevel@tonic-gate 						break;
23997c478bd9Sstevel@tonic-gate 					case FME_WAIT:
24007c478bd9Sstevel@tonic-gate 						if (my_delay < arrow_delay)
24017c478bd9Sstevel@tonic-gate 							arrow_delay = my_delay;
24027c478bd9Sstevel@tonic-gate 						waiting_events++;
24037c478bd9Sstevel@tonic-gate 						break;
24047c478bd9Sstevel@tonic-gate 					default:
24057c478bd9Sstevel@tonic-gate 						out(O_DIE,
24067c478bd9Sstevel@tonic-gate 						"Bug in requirements_test.");
24077c478bd9Sstevel@tonic-gate 					}
24087c478bd9Sstevel@tonic-gate 				else
24097c478bd9Sstevel@tonic-gate 					credible_events++;
24107c478bd9Sstevel@tonic-gate 			}
24117c478bd9Sstevel@tonic-gate 			indent();
24127c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, " Credible: %d Waiting %d",
24137c478bd9Sstevel@tonic-gate 			    credible_events, waiting_events);
24147c478bd9Sstevel@tonic-gate 			if (credible_events + waiting_events < n) {
24157c478bd9Sstevel@tonic-gate 				/* Can never meet requirements */
24167c478bd9Sstevel@tonic-gate 				indent();
24177c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
24187c478bd9Sstevel@tonic-gate 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
24197c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB, NULL);
24207c478bd9Sstevel@tonic-gate 				indent_pop();
24217c478bd9Sstevel@tonic-gate 				return (FME_DISPROVED);
24227c478bd9Sstevel@tonic-gate 			}
24237c478bd9Sstevel@tonic-gate 			if (credible_events < n) { /* will have to wait */
24247c478bd9Sstevel@tonic-gate 				/* wait time is shortest known */
24257c478bd9Sstevel@tonic-gate 				if (arrow_delay < overall_delay)
24267c478bd9Sstevel@tonic-gate 					overall_delay = arrow_delay;
24277c478bd9Sstevel@tonic-gate 				return_value = FME_WAIT;
24287c478bd9Sstevel@tonic-gate 			}
24297c478bd9Sstevel@tonic-gate 		} else {
24307c478bd9Sstevel@tonic-gate 			indent();
24317c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB|O_NONL, " Mark was set: ");
24327c478bd9Sstevel@tonic-gate 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
24337c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB|O_NONL, " to");
24347c478bd9Sstevel@tonic-gate 			for (ap = itree_next_arrow(bp, NULL); ap;
24357c478bd9Sstevel@tonic-gate 			    ap = itree_next_arrow(bp, ap)) {
24367c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB|O_NONL, " ");
24377c478bd9Sstevel@tonic-gate 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL,
24387c478bd9Sstevel@tonic-gate 				    ap->arrowp->head->myevent);
24397c478bd9Sstevel@tonic-gate 			}
24407c478bd9Sstevel@tonic-gate 			out(O_ALTFP|O_VERB, NULL);
24417c478bd9Sstevel@tonic-gate 		}
24427c478bd9Sstevel@tonic-gate 	}
24437c478bd9Sstevel@tonic-gate 
24447c478bd9Sstevel@tonic-gate 	/*
24457c478bd9Sstevel@tonic-gate 	 * evaluate constraints for ctlist, which is the list of
24467c478bd9Sstevel@tonic-gate 	 * constraints for the arrow pointing into this node of the tree
24477c478bd9Sstevel@tonic-gate 	 */
24487c478bd9Sstevel@tonic-gate 	if (return_value == FME_CREDIBLE && arrowp != NULL) {
24497c478bd9Sstevel@tonic-gate 		struct constraintlist *ctp;
24507c478bd9Sstevel@tonic-gate 		struct evalue value;
24517c478bd9Sstevel@tonic-gate 
24527c478bd9Sstevel@tonic-gate 		platform_set_payloadnvp(ep->nvp);
24537c478bd9Sstevel@tonic-gate 		for (ctp = arrowp->constraints; ctp != NULL;
24547c478bd9Sstevel@tonic-gate 			ctp = ctp->next) {
24557c478bd9Sstevel@tonic-gate 			if (eval_expr(ctp->cnode, NULL,	NULL, &fmep->globals,
24567c478bd9Sstevel@tonic-gate 			    fmep->cfgdata->cooked, arrowp, 0, &value) == 0 ||
24577c478bd9Sstevel@tonic-gate 			    value.t == UNDEFINED || value.v == 0) {
24587c478bd9Sstevel@tonic-gate 				indent();
24597c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB|O_NONL,
24607c478bd9Sstevel@tonic-gate 				    "  False constraint ");
24617c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB|O_NONL, " ");
24627c478bd9Sstevel@tonic-gate 				ptree(O_ALTFP|O_VERB|O_NONL,
24637c478bd9Sstevel@tonic-gate 				    ctp->cnode, 1, 0);
24647c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB, NULL);
24657c478bd9Sstevel@tonic-gate 				return_value = FME_DISPROVED;
24667c478bd9Sstevel@tonic-gate 				break;
24677c478bd9Sstevel@tonic-gate 			}
24687c478bd9Sstevel@tonic-gate 		}
24697c478bd9Sstevel@tonic-gate 		platform_set_payloadnvp(NULL);
24707c478bd9Sstevel@tonic-gate 	}
24717c478bd9Sstevel@tonic-gate 
24727c478bd9Sstevel@tonic-gate 	if (return_value == FME_WAIT)
24737c478bd9Sstevel@tonic-gate 		*pdelay = overall_delay;
24747c478bd9Sstevel@tonic-gate 	indent();
24757c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "<-%s ", fme_state2str(return_value));
24767c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
24777c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
24787c478bd9Sstevel@tonic-gate 	indent_pop();
24797c478bd9Sstevel@tonic-gate 	return (return_value);
24807c478bd9Sstevel@tonic-gate }
24817c478bd9Sstevel@tonic-gate 
24827c478bd9Sstevel@tonic-gate static enum fme_state
24837c478bd9Sstevel@tonic-gate causes_test(struct fme *fmep, struct event *ep,
24847c478bd9Sstevel@tonic-gate     unsigned long long at_latest_by, unsigned long long *pdelay)
24857c478bd9Sstevel@tonic-gate {
24867c478bd9Sstevel@tonic-gate 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
24877c478bd9Sstevel@tonic-gate 	unsigned long long my_delay;
24887c478bd9Sstevel@tonic-gate 	int credible_results = 0;
24897c478bd9Sstevel@tonic-gate 	int waiting_results = 0;
24907c478bd9Sstevel@tonic-gate 	enum fme_state fstate;
24917c478bd9Sstevel@tonic-gate 	struct event *tail_event;
24927c478bd9Sstevel@tonic-gate 	struct bubble *bp;
24937c478bd9Sstevel@tonic-gate 	struct arrowlist *ap;
24947c478bd9Sstevel@tonic-gate 	int k = 1;
24957c478bd9Sstevel@tonic-gate 
24967c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Ccallcount);
24977c478bd9Sstevel@tonic-gate 	indent_push("  C");
24987c478bd9Sstevel@tonic-gate 	indent();
24997c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
25007c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
25017c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
25027c478bd9Sstevel@tonic-gate 
25037c478bd9Sstevel@tonic-gate 	for (bp = itree_next_bubble(ep, NULL); bp;
25047c478bd9Sstevel@tonic-gate 	    bp = itree_next_bubble(ep, bp)) {
25057c478bd9Sstevel@tonic-gate 		if (bp->t != B_TO)
25067c478bd9Sstevel@tonic-gate 			continue;
25077c478bd9Sstevel@tonic-gate 		k = bp->nork;	/* remember the K value */
25087c478bd9Sstevel@tonic-gate 		for (ap = itree_next_arrow(bp, NULL); ap;
25097c478bd9Sstevel@tonic-gate 		    ap = itree_next_arrow(bp, ap)) {
25107c478bd9Sstevel@tonic-gate 			struct constraintlist *ctp;
25117c478bd9Sstevel@tonic-gate 			struct evalue value;
25127c478bd9Sstevel@tonic-gate 			int do_not_follow = 0;
25137c478bd9Sstevel@tonic-gate 			/*
25147c478bd9Sstevel@tonic-gate 			 * see if false constraint prevents us
25157c478bd9Sstevel@tonic-gate 			 * from traversing this arrow
25167c478bd9Sstevel@tonic-gate 			 */
25177c478bd9Sstevel@tonic-gate 			platform_set_payloadnvp(ep->nvp);
25187c478bd9Sstevel@tonic-gate 			for (ctp = ap->arrowp->constraints;
25197c478bd9Sstevel@tonic-gate 			    ctp != NULL; ctp = ctp->next) {
25207c478bd9Sstevel@tonic-gate 				if (eval_expr(ctp->cnode, NULL, NULL,
25217c478bd9Sstevel@tonic-gate 				    &fmep->globals,
25227c478bd9Sstevel@tonic-gate 				    fmep->cfgdata->cooked,
25237c478bd9Sstevel@tonic-gate 				    ap->arrowp, 0,
25247c478bd9Sstevel@tonic-gate 				    &value) == 0 ||
25257c478bd9Sstevel@tonic-gate 				    value.t == UNDEFINED ||
25267c478bd9Sstevel@tonic-gate 				    value.v == 0) {
25277c478bd9Sstevel@tonic-gate 					do_not_follow = 1;
25287c478bd9Sstevel@tonic-gate 					break;
25297c478bd9Sstevel@tonic-gate 				}
25307c478bd9Sstevel@tonic-gate 			}
25317c478bd9Sstevel@tonic-gate 			platform_set_payloadnvp(NULL);
25327c478bd9Sstevel@tonic-gate 			if (do_not_follow) {
25337c478bd9Sstevel@tonic-gate 				indent();
25347c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB|O_NONL,
25357c478bd9Sstevel@tonic-gate 				    "  False arrow from ");
25367c478bd9Sstevel@tonic-gate 				itree_pevent_brief(O_ALTFP|O_VERB|O_NONL,
25377c478bd9Sstevel@tonic-gate 				    ap->arrowp->tail->myevent);
25387c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB|O_NONL, " ");
25397c478bd9Sstevel@tonic-gate 				ptree(O_ALTFP|O_VERB|O_NONL, ctp->cnode, 1, 0);
25407c478bd9Sstevel@tonic-gate 				out(O_ALTFP|O_VERB, NULL);
25417c478bd9Sstevel@tonic-gate 				continue;
25427c478bd9Sstevel@tonic-gate 			}
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 			if (ap->arrowp->causes_tested++ > 0) {
25457c478bd9Sstevel@tonic-gate 				/*
25467c478bd9Sstevel@tonic-gate 				 * get to this point if this is not the
25477c478bd9Sstevel@tonic-gate 				 * first time we're going through this
25487c478bd9Sstevel@tonic-gate 				 * arrow in the causes test.  consider this
25497c478bd9Sstevel@tonic-gate 				 * branch to be credible and let the
25507c478bd9Sstevel@tonic-gate 				 * credible/noncredible outcome depend on
25517c478bd9Sstevel@tonic-gate 				 * the other branches in this cycle.
25527c478bd9Sstevel@tonic-gate 				 */
25537c478bd9Sstevel@tonic-gate 				fstate = FME_CREDIBLE;
25547c478bd9Sstevel@tonic-gate 			} else {
25557c478bd9Sstevel@tonic-gate 				/*
25567c478bd9Sstevel@tonic-gate 				 * get to this point if this is the first
25577c478bd9Sstevel@tonic-gate 				 * time we're going through this arrow.
25587c478bd9Sstevel@tonic-gate 				 */
25597c478bd9Sstevel@tonic-gate 				tail_event = ap->arrowp->tail->myevent;
25607c478bd9Sstevel@tonic-gate 				fstate = hypothesise(fmep, tail_event,
25617c478bd9Sstevel@tonic-gate 						    at_latest_by,
25627c478bd9Sstevel@tonic-gate 						    &my_delay, ap->arrowp);
25637c478bd9Sstevel@tonic-gate 			}
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate 			switch (fstate) {
25667c478bd9Sstevel@tonic-gate 			case FME_WAIT:
25677c478bd9Sstevel@tonic-gate 				if (my_delay < overall_delay)
25687c478bd9Sstevel@tonic-gate 					overall_delay = my_delay;
25697c478bd9Sstevel@tonic-gate 				waiting_results++;
25707c478bd9Sstevel@tonic-gate 				break;
25717c478bd9Sstevel@tonic-gate 			case FME_CREDIBLE:
25727c478bd9Sstevel@tonic-gate 				credible_results++;
25737c478bd9Sstevel@tonic-gate 				break;
25747c478bd9Sstevel@tonic-gate 			case FME_DISPROVED:
25757c478bd9Sstevel@tonic-gate 				break;
25767c478bd9Sstevel@tonic-gate 			default:
25777c478bd9Sstevel@tonic-gate 				out(O_DIE, "Bug in causes_test");
25787c478bd9Sstevel@tonic-gate 			}
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate 			ap->arrowp->causes_tested--;
25817c478bd9Sstevel@tonic-gate 			ASSERT(ap->arrowp->causes_tested >= 0);
25827c478bd9Sstevel@tonic-gate 		}
25837c478bd9Sstevel@tonic-gate 	}
25847c478bd9Sstevel@tonic-gate 	/* compare against K */
25857c478bd9Sstevel@tonic-gate 	if (credible_results + waiting_results < k) {
25867c478bd9Sstevel@tonic-gate 		indent();
25877c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
25887c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
25897c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
25907c478bd9Sstevel@tonic-gate 		indent_pop();
25917c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
25927c478bd9Sstevel@tonic-gate 	}
25937c478bd9Sstevel@tonic-gate 	if (waiting_results != 0) {
25947c478bd9Sstevel@tonic-gate 		*pdelay = overall_delay;
25957c478bd9Sstevel@tonic-gate 		indent();
25967c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-WAIT ");
25977c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
25987c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " to ");
25997c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
26007c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
26017c478bd9Sstevel@tonic-gate 		indent_pop();
26027c478bd9Sstevel@tonic-gate 		return (FME_WAIT);
26037c478bd9Sstevel@tonic-gate 	}
26047c478bd9Sstevel@tonic-gate 	indent();
26057c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "<-CREDIBLE ");
26067c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
26077c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
26087c478bd9Sstevel@tonic-gate 	indent_pop();
26097c478bd9Sstevel@tonic-gate 	return (FME_CREDIBLE);
26107c478bd9Sstevel@tonic-gate }
26117c478bd9Sstevel@tonic-gate 
26127c478bd9Sstevel@tonic-gate static enum fme_state
26137c478bd9Sstevel@tonic-gate hypothesise(struct fme *fmep, struct event *ep,
26147c478bd9Sstevel@tonic-gate 	unsigned long long at_latest_by, unsigned long long *pdelay,
26157c478bd9Sstevel@tonic-gate 	struct arrow *arrowp)
26167c478bd9Sstevel@tonic-gate {
26177c478bd9Sstevel@tonic-gate 	enum fme_state rtr, otr;
26187c478bd9Sstevel@tonic-gate 	unsigned long long my_delay;
26197c478bd9Sstevel@tonic-gate 	unsigned long long overall_delay = TIMEVAL_EVENTUALLY;
26207c478bd9Sstevel@tonic-gate 
26217c478bd9Sstevel@tonic-gate 	stats_counter_bump(fmep->Hcallcount);
26227c478bd9Sstevel@tonic-gate 	indent_push("  H");
26237c478bd9Sstevel@tonic-gate 	indent();
26247c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "->");
26257c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
26267c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, ", at latest by: ");
26277c478bd9Sstevel@tonic-gate 	ptree_timeval(O_ALTFP|O_VERB|O_NONL, &at_latest_by);
26287c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
26297c478bd9Sstevel@tonic-gate 
26307c478bd9Sstevel@tonic-gate 	rtr = requirements_test(fmep, ep, at_latest_by, &my_delay, arrowp);
26317c478bd9Sstevel@tonic-gate 	mark_arrows(fmep, ep, 0); /* clean up after requirements test */
26327c478bd9Sstevel@tonic-gate 	if ((rtr == FME_WAIT) && (my_delay < overall_delay))
26337c478bd9Sstevel@tonic-gate 		overall_delay = my_delay;
26347c478bd9Sstevel@tonic-gate 	if (rtr != FME_DISPROVED) {
26357c478bd9Sstevel@tonic-gate 		if (is_problem(ep->t)) {
26367c478bd9Sstevel@tonic-gate 			otr = effects_test(fmep, ep);
26377c478bd9Sstevel@tonic-gate 			if (otr != FME_DISPROVED) {
26387c478bd9Sstevel@tonic-gate 				if (fmep->peek == 0 && ep->is_suspect++ == 0) {
26397c478bd9Sstevel@tonic-gate 					ep->suspects = fmep->suspects;
26407c478bd9Sstevel@tonic-gate 					fmep->suspects = ep;
26417c478bd9Sstevel@tonic-gate 					fmep->nsuspects++;
26427c478bd9Sstevel@tonic-gate 					if (!is_fault(ep->t))
26437c478bd9Sstevel@tonic-gate 						fmep->nonfault++;
26447c478bd9Sstevel@tonic-gate 				}
26457c478bd9Sstevel@tonic-gate 			}
26467c478bd9Sstevel@tonic-gate 		} else
26477c478bd9Sstevel@tonic-gate 			otr = causes_test(fmep, ep, at_latest_by, &my_delay);
26487c478bd9Sstevel@tonic-gate 		if ((otr == FME_WAIT) && (my_delay < overall_delay))
26497c478bd9Sstevel@tonic-gate 			overall_delay = my_delay;
26507c478bd9Sstevel@tonic-gate 		if ((otr != FME_DISPROVED) &&
26517c478bd9Sstevel@tonic-gate 		    ((rtr == FME_WAIT) || (otr == FME_WAIT)))
26527c478bd9Sstevel@tonic-gate 			*pdelay = overall_delay;
26537c478bd9Sstevel@tonic-gate 	}
26547c478bd9Sstevel@tonic-gate 	if (rtr == FME_DISPROVED) {
26557c478bd9Sstevel@tonic-gate 		indent();
26567c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
26577c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
26587c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, " (doesn't meet requirements)");
26597c478bd9Sstevel@tonic-gate 		indent_pop();
26607c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
26617c478bd9Sstevel@tonic-gate 	}
26627c478bd9Sstevel@tonic-gate 	if ((otr == FME_DISPROVED) && is_problem(ep->t)) {
26637c478bd9Sstevel@tonic-gate 		indent();
26647c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
26657c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
26667c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, " (doesn't explain all reports)");
26677c478bd9Sstevel@tonic-gate 		indent_pop();
26687c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
26697c478bd9Sstevel@tonic-gate 	}
26707c478bd9Sstevel@tonic-gate 	if (otr == FME_DISPROVED) {
26717c478bd9Sstevel@tonic-gate 		indent();
26727c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-DISPROVED ");
26737c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
26747c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, " (causes are not credible)");
26757c478bd9Sstevel@tonic-gate 		indent_pop();
26767c478bd9Sstevel@tonic-gate 		return (FME_DISPROVED);
26777c478bd9Sstevel@tonic-gate 	}
26787c478bd9Sstevel@tonic-gate 	if ((rtr == FME_WAIT) || (otr == FME_WAIT)) {
26797c478bd9Sstevel@tonic-gate 		indent();
26807c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, "<-WAIT ");
26817c478bd9Sstevel@tonic-gate 		itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
26827c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB|O_NONL, " to ");
26837c478bd9Sstevel@tonic-gate 		ptree_timeval(O_ALTFP|O_VERB|O_NONL, &overall_delay);
26847c478bd9Sstevel@tonic-gate 		out(O_ALTFP|O_VERB, NULL);
26857c478bd9Sstevel@tonic-gate 		indent_pop();
26867c478bd9Sstevel@tonic-gate 		return (FME_WAIT);
26877c478bd9Sstevel@tonic-gate 	}
26887c478bd9Sstevel@tonic-gate 	indent();
26897c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB|O_NONL, "<-CREDIBLE ");
26907c478bd9Sstevel@tonic-gate 	itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, ep);
26917c478bd9Sstevel@tonic-gate 	out(O_ALTFP|O_VERB, NULL);
26927c478bd9Sstevel@tonic-gate 	indent_pop();
26937c478bd9Sstevel@tonic-gate 	return (FME_CREDIBLE);
26947c478bd9Sstevel@tonic-gate }
2695