Home | History | Annotate | Download | only in eversholt
      1     0    stevel /*
      2     0    stevel  * CDDL HEADER START
      3     0    stevel  *
      4     0    stevel  * The contents of this file are subject to the terms of the
      5  1493    gavinm  * Common Development and Distribution License (the "License").
      6  1493    gavinm  * You may not use this file except in compliance with the License.
      7     0    stevel  *
      8     0    stevel  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
      9     0    stevel  * or http://www.opensolaris.org/os/licensing.
     10     0    stevel  * See the License for the specific language governing permissions
     11     0    stevel  * and limitations under the License.
     12     0    stevel  *
     13     0    stevel  * When distributing Covered Code, include this CDDL HEADER in each
     14     0    stevel  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
     15     0    stevel  * If applicable, add the following below this CDDL HEADER, with the
     16     0    stevel  * fields enclosed by brackets "[]" replaced with your own identifying
     17     0    stevel  * information: Portions Copyright [yyyy] [name of copyright owner]
     18     0    stevel  *
     19     0    stevel  * CDDL HEADER END
     20     0    stevel  */
     21  1493    gavinm 
     22     0    stevel /*
     23  9078   Stephen  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
     24     0    stevel  * Use is subject to license terms.
     25     0    stevel  *
     26     0    stevel  * fme.c -- fault management exercise module
     27     0    stevel  *
     28     0    stevel  * this module provides the simulated fault management exercise.
     29     0    stevel  */
     30     0    stevel 
     31     0    stevel #include <stdio.h>
     32     0    stevel #include <stdlib.h>
     33     0    stevel #include <string.h>
     34     0    stevel #include <strings.h>
     35     0    stevel #include <ctype.h>
     36     0    stevel #include <alloca.h>
     37     0    stevel #include <libnvpair.h>
     38     0    stevel #include <sys/fm/protocol.h>
     39     0    stevel #include <fm/fmd_api.h>
     40     0    stevel #include "alloc.h"
     41     0    stevel #include "out.h"
     42     0    stevel #include "stats.h"
     43     0    stevel #include "stable.h"
     44     0    stevel #include "literals.h"
     45     0    stevel #include "lut.h"
     46     0    stevel #include "tree.h"
     47     0    stevel #include "ptree.h"
     48     0    stevel #include "itree.h"
     49     0    stevel #include "ipath.h"
     50     0    stevel #include "fme.h"
     51     0    stevel #include "evnv.h"
     52     0    stevel #include "eval.h"
     53     0    stevel #include "config.h"
     54     0    stevel #include "platform.h"
     55  5204    stephh #include "esclex.h"
     56     0    stevel 
     57     0    stevel /* imported from eft.c... */
     58     0    stevel extern hrtime_t Hesitate;
     59  5204    stephh extern char *Serd_Override;
     60     0    stevel extern nv_alloc_t Eft_nv_hdl;
     61   814     jrutt extern int Max_fme;
     62  1414     cindi extern fmd_hdl_t *Hdl;
     63  1414     cindi 
     64  1414     cindi static int Istat_need_save;
     65  4436    stephh static int Serd_need_save;
     66  2120    gavinm void istat_save(void);
     67  4436    stephh void serd_save(void);
     68     0    stevel 
     69     0    stevel /* fme under construction is global so we can free it on module abort */
     70     0    stevel static struct fme *Nfmep;
     71     0    stevel 
     72  7748     Tarik static int Undiag_reason = UD_VAL_UNKNOWN;
     73     0    stevel 
     74     0    stevel static int Nextid = 0;
     75   814     jrutt 
     76   814     jrutt static int Open_fme_count = 0;	/* Count of open FMEs */
     77     0    stevel 
     78     0    stevel /* list of fault management exercises underway */
     79     0    stevel static struct fme {
     80     0    stevel 	struct fme *next;		/* next exercise */
     81     0    stevel 	unsigned long long ull;		/* time when fme was created */
     82     0    stevel 	int id;				/* FME id */
     83  5204    stephh 	struct config *config;		/* cooked configuration data */
     84     0    stevel 	struct lut *eventtree;		/* propagation tree for this FME */
     85     0    stevel 	/*
     86     0    stevel 	 * The initial error report that created this FME is kept in
     87     0    stevel 	 * two forms.  e0 points to the instance tree node and is used
     88     0    stevel 	 * by fme_eval() as the starting point for the inference
     89     0    stevel 	 * algorithm.  e0r is the event handle FMD passed to us when
     90     0    stevel 	 * the ereport first arrived and is used when setting timers,
     91     0    stevel 	 * which are always relative to the time of this initial
     92     0    stevel 	 * report.
     93     0    stevel 	 */
     94     0    stevel 	struct event *e0;
     95     0    stevel 	fmd_event_t *e0r;
     96     0    stevel 
     97     0    stevel 	id_t    timer;			/* for setting an fmd time-out */
     98     0    stevel 
     99     0    stevel 	struct event *ecurrent;		/* ereport under consideration */
    100     0    stevel 	struct event *suspects;		/* current suspect list */
    101     0    stevel 	struct event *psuspects;	/* previous suspect list */
    102     0    stevel 	int nsuspects;			/* count of suspects */
    103     0    stevel 	int posted_suspects;		/* true if we've posted a diagnosis */
    104     0    stevel 	int uniqobs;			/* number of unique events observed */
    105     0    stevel 	int peek;			/* just peeking, don't track suspects */
    106   814     jrutt 	int overflow;			/* true if overflow FME */
    107     0    stevel 	enum fme_state {
    108     0    stevel 		FME_NOTHING = 5000,	/* not evaluated yet */
    109     0    stevel 		FME_WAIT,		/* need to wait for more info */
    110     0    stevel 		FME_CREDIBLE,		/* suspect list is credible */
    111  1414     cindi 		FME_DISPROVED,		/* no valid suspects found */
    112  1414     cindi 		FME_DEFERRED		/* don't know yet (k-count not met) */
    113     0    stevel 	} state;
    114     0    stevel 
    115     0    stevel 	unsigned long long pull;	/* time passed since created */
    116     0    stevel 	unsigned long long wull;	/* wait until this time for re-eval */
    117     0    stevel 	struct event *observations;	/* observation list */
    118     0    stevel 	struct lut *globals;		/* values of global variables */
    119     0    stevel 	/* fmd interfacing */
    120     0    stevel 	fmd_hdl_t *hdl;			/* handle for talking with fmd */
    121     0    stevel 	fmd_case_t *fmcase;		/* what fmd 'case' we associate with */
    122     0    stevel 	/* stats */
    123     0    stevel 	struct stats *Rcount;
    124     0    stevel 	struct stats *Hcallcount;
    125     0    stevel 	struct stats *Rcallcount;
    126     0    stevel 	struct stats *Ccallcount;
    127     0    stevel 	struct stats *Ecallcount;
    128     0    stevel 	struct stats *Tcallcount;
    129     0    stevel 	struct stats *Marrowcount;
    130     0    stevel 	struct stats *diags;
    131     0    stevel } *FMElist, *EFMElist, *ClosedFMEs;
    132     0    stevel 
    133     0    stevel static struct case_list {
    134     0    stevel 	fmd_case_t *fmcase;
    135     0    stevel 	struct case_list *next;
    136     0    stevel } *Undiagablecaselist;
    137     0    stevel 
    138     0    stevel static void fme_eval(struct fme *fmep, fmd_event_t *ffep);
    139     0    stevel static enum fme_state hypothesise(struct fme *fmep, struct event *ep,
    140  1414     cindi 	unsigned long long at_latest_by, unsigned long long *pdelay);
    141     0    stevel static struct node *eventprop_lookup(struct event *ep, const char *propname);
    142     0    stevel static struct node *pathstring2epnamenp(char *path);
    143  4436    stephh static void publish_undiagnosable(fmd_hdl_t *hdl, fmd_event_t *ffep,
    144  4436    stephh 	fmd_case_t *fmcase);
    145  7748     Tarik static const char *undiag_2reason_str(int ud);
    146  7748     Tarik static const char *undiag_2defect_str(int ud);
    147     0    stevel static void restore_suspects(struct fme *fmep);
    148     0    stevel static void save_suspects(struct fme *fmep);
    149     0    stevel static void destroy_fme(struct fme *f);
    150     0    stevel static void fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep,
    151     0    stevel     const char *eventstring, const struct ipath *ipp, nvlist_t *nvl);
    152  2120    gavinm static void istat_counter_reset_cb(struct istat_entry *entp,
    153  2120    gavinm     struct stats *statp, const struct ipath *ipp);
    154  5204    stephh static void istat_counter_topo_chg_cb(struct istat_entry *entp,
    155  5204    stephh     struct stats *statp, void *unused);
    156  4436    stephh static void serd_reset_cb(struct serd_entry *entp, void *unused,
    157  4436    stephh     const struct ipath *ipp);
    158  5204    stephh static void serd_topo_chg_cb(struct serd_entry *entp, void *unused,
    159  5204    stephh     void *unused2);
    160  4436    stephh static void destroy_fme_bufs(struct fme *fp);
    161     0    stevel 
    162     0    stevel static struct fme *
    163     0    stevel alloc_fme(void)
    164     0    stevel {
    165     0    stevel 	struct fme *fmep;
    166     0    stevel 
    167     0    stevel 	fmep = MALLOC(sizeof (*fmep));
    168     0    stevel 	bzero(fmep, sizeof (*fmep));
    169     0    stevel 	return (fmep);
    170     0    stevel }
    171     0    stevel 
    172     0    stevel /*
    173     0    stevel  * fme_ready -- called when all initialization of the FME (except for
    174     0    stevel  *	stats) has completed successfully.  Adds the fme to global lists
    175     0    stevel  *	and establishes its stats.
    176     0    stevel  */
    177     0    stevel static struct fme *
    178     0    stevel fme_ready(struct fme *fmep)
    179     0    stevel {
    180     0    stevel 	char nbuf[100];
    181     0    stevel 
    182     0    stevel 	Nfmep = NULL;	/* don't need to free this on module abort now */
    183     0    stevel 
    184     0    stevel 	if (EFMElist) {
    185     0    stevel 		EFMElist->next = fmep;
    186     0    stevel 		EFMElist = fmep;
    187     0    stevel 	} else
    188     0    stevel 		FMElist = EFMElist = fmep;
    189     0    stevel 
    190     0    stevel 	(void) sprintf(nbuf, "fme%d.Rcount", fmep->id);
    191     0    stevel 	fmep->Rcount = stats_new_counter(nbuf, "ereports received", 0);
    192     0    stevel 	(void) sprintf(nbuf, "fme%d.Hcall", fmep->id);
    193     0    stevel 	fmep->Hcallcount = stats_new_counter(nbuf, "calls to hypothesise()", 1);
    194     0    stevel 	(void) sprintf(nbuf, "fme%d.Rcall", fmep->id);
    195     0    stevel 	fmep->Rcallcount = stats_new_counter(nbuf,
    196     0    stevel 	    "calls to requirements_test()", 1);
    197     0    stevel 	(void) sprintf(nbuf, "fme%d.Ccall", fmep->id);
    198     0    stevel 	fmep->Ccallcount = stats_new_counter(nbuf, "calls to causes_test()", 1);
    199     0    stevel 	(void) sprintf(nbuf, "fme%d.Ecall", fmep->id);
    200     0    stevel 	fmep->Ecallcount =
    201     0    stevel 	    stats_new_counter(nbuf, "calls to effects_test()", 1);
    202     0    stevel 	(void) sprintf(nbuf, "fme%d.Tcall", fmep->id);
    203     0    stevel 	fmep->Tcallcount = stats_new_counter(nbuf, "calls to triggered()", 1);
    204     0    stevel 	(void) sprintf(nbuf, "fme%d.Marrow", fmep->id);
    205     0    stevel 	fmep->Marrowcount = stats_new_counter(nbuf,
    206     0    stevel 	    "arrows marked by mark_arrows()", 1);
    207     0    stevel 	(void) sprintf(nbuf, "fme%d.diags", fmep->id);
    208     0    stevel 	fmep->diags = stats_new_counter(nbuf, "suspect lists diagnosed", 0);
    209     0    stevel 
    210     0    stevel 	out(O_ALTFP|O_VERB2, "newfme: config snapshot contains...");
    211  5204    stephh 	config_print(O_ALTFP|O_VERB2, fmep->config);
    212     0    stevel 
    213     0    stevel 	return (fmep);
    214     0    stevel }
    215     0    stevel 
    216  4436    stephh extern void ipath_dummy_lut(struct arrow *);
    217  4436    stephh extern struct lut *itree_create_dummy(const char *, const struct ipath *);
    218  4436    stephh 
    219  4436    stephh /* ARGSUSED */
    220  4436    stephh static void
    221  4436    stephh set_needed_arrows(struct event *ep, struct event *ep2, struct fme *fmep)
    222  4436    stephh {
    223  4436    stephh 	struct bubble *bp;
    224  4436    stephh 	struct arrowlist *ap;
    225  4436    stephh 
    226  4436    stephh 	for (bp = itree_next_bubble(ep, NULL); bp;
    227  4436    stephh 	    bp = itree_next_bubble(ep, bp)) {
    228  4436    stephh 		if (bp->t != B_FROM)
    229  4436    stephh 			continue;
    230  4436    stephh 		for (ap = itree_next_arrow(bp, NULL); ap;
    231  4436    stephh 		    ap = itree_next_arrow(bp, ap)) {
    232  4436    stephh 			ap->arrowp->pnode->u.arrow.needed = 1;
    233  4436    stephh 			ipath_dummy_lut(ap->arrowp);
    234  4436    stephh 		}
    235  4436    stephh 	}
    236  4436    stephh }
    237  4436    stephh 
    238  4436    stephh /* ARGSUSED */
    239  4436    stephh static void
    240  4436    stephh unset_needed_arrows(struct event *ep, struct event *ep2, struct fme *fmep)
    241  4436    stephh {
    242  4436    stephh 	struct bubble *bp;
    243  4436    stephh 	struct arrowlist *ap;
    244  4436    stephh 
    245  4436    stephh 	for (bp = itree_next_bubble(ep, NULL); bp;
    246  4436    stephh 	    bp = itree_next_bubble(ep, bp)) {
    247  4436    stephh 		if (bp->t != B_FROM)
    248  4436    stephh 			continue;
    249  4436    stephh 		for (ap = itree_next_arrow(bp, NULL); ap;
    250  4436    stephh 		    ap = itree_next_arrow(bp, ap))
    251  4436    stephh 			ap->arrowp->pnode->u.arrow.needed = 0;
    252  4436    stephh 	}
    253  4436    stephh }
    254  4436    stephh 
    255  4436    stephh static void globals_destructor(void *left, void *right, void *arg);
    256  4436    stephh static void clear_arrows(struct event *ep, struct event *ep2, struct fme *fmep);
    257  4436    stephh 
    258  4436    stephh static void
    259  4436    stephh prune_propagations(const char *e0class, const struct ipath *e0ipp)
    260  4436    stephh {
    261  4436    stephh 	char nbuf[100];
    262  4436    stephh 	unsigned long long my_delay = TIMEVAL_EVENTUALLY;
    263  4436    stephh 	extern struct lut *Usednames;
    264  4436    stephh 
    265  4436    stephh 	Nfmep = alloc_fme();
    266  4436    stephh 	Nfmep->id = Nextid;
    267  4436    stephh 	Nfmep->state = FME_NOTHING;
    268  4436    stephh 	Nfmep->eventtree = itree_create_dummy(e0class, e0ipp);
    269  4436    stephh 	if ((Nfmep->e0 =
    270  4436    stephh 	    itree_lookup(Nfmep->eventtree, e0class, e0ipp)) == NULL) {
    271  4436    stephh 		out(O_ALTFP, "prune_propagations: e0 not in instance tree");
    272  4436    stephh 		itree_free(Nfmep->eventtree);
    273  4436    stephh 		FREE(Nfmep);
    274  4436    stephh 		Nfmep = NULL;
    275  4436    stephh 		return;
    276  4436    stephh 	}
    277  4436    stephh 	Nfmep->ecurrent = Nfmep->observations = Nfmep->e0;
    278  4436    stephh 	Nfmep->e0->count++;
    279  4436    stephh 
    280  4436    stephh 	(void) sprintf(nbuf, "fme%d.Rcount", Nfmep->id);
    281  4436    stephh 	Nfmep->Rcount = stats_new_counter(nbuf, "ereports received", 0);
    282  4436    stephh 	(void) sprintf(nbuf, "fme%d.Hcall", Nfmep->id);
    283  4436    stephh 	Nfmep->Hcallcount =
    284  4436    stephh 	    stats_new_counter(nbuf, "calls to hypothesise()", 1);
    285  4436    stephh 	(void) sprintf(nbuf, "fme%d.Rcall", Nfmep->id);
    286  4436    stephh 	Nfmep->Rcallcount = stats_new_counter(nbuf,
    287  4436    stephh 	    "calls to requirements_test()", 1);
    288  4436    stephh 	(void) sprintf(nbuf, "fme%d.Ccall", Nfmep->id);
    289  4436    stephh 	Nfmep->Ccallcount =
    290  4436    stephh 	    stats_new_counter(nbuf, "calls to causes_test()", 1);
    291  4436    stephh 	(void) sprintf(nbuf, "fme%d.Ecall", Nfmep->id);
    292  4436    stephh 	Nfmep->Ecallcount =
    293  4436    stephh 	    stats_new_counter(nbuf, "calls to effects_test()", 1);
    294  4436    stephh 	(void) sprintf(nbuf, "fme%d.Tcall", Nfmep->id);
    295  4436    stephh 	Nfmep->Tcallcount = stats_new_counter(nbuf, "calls to triggered()", 1);
    296  4436    stephh 	(void) sprintf(nbuf, "fme%d.Marrow", Nfmep->id);
    297  4436    stephh 	Nfmep->Marrowcount = stats_new_counter(nbuf,
    298  4436    stephh 	    "arrows marked by mark_arrows()", 1);
    299  4436    stephh 	(void) sprintf(nbuf, "fme%d.diags", Nfmep->id);
    300  4436    stephh 	Nfmep->diags = stats_new_counter(nbuf, "suspect lists diagnosed", 0);
    301  4436    stephh 
    302  4436    stephh 	Nfmep->peek = 1;
    303  4436    stephh 	lut_walk(Nfmep->eventtree, (lut_cb)unset_needed_arrows, (void *)Nfmep);
    304  4436    stephh 	lut_free(Usednames, NULL, NULL);
    305  4436    stephh 	Usednames = NULL;
    306  4436    stephh 	lut_walk(Nfmep->eventtree, (lut_cb)clear_arrows, (void *)Nfmep);
    307  4436    stephh 	(void) hypothesise(Nfmep, Nfmep->e0, Nfmep->ull, &my_delay);
    308  4436    stephh 	itree_prune(Nfmep->eventtree);
    309  4436    stephh 	lut_walk(Nfmep->eventtree, (lut_cb)set_needed_arrows, (void *)Nfmep);
    310  4436    stephh 
    311  4436    stephh 	stats_delete(Nfmep->Rcount);
    312  4436    stephh 	stats_delete(Nfmep->Hcallcount);
    313  4436    stephh 	stats_delete(Nfmep->Rcallcount);
    314  4436    stephh 	stats_delete(Nfmep->Ccallcount);
    315  4436    stephh 	stats_delete(Nfmep->Ecallcount);
    316  4436    stephh 	stats_delete(Nfmep->Tcallcount);
    317  4436    stephh 	stats_delete(Nfmep->Marrowcount);
    318  4436    stephh 	stats_delete(Nfmep->diags);
    319  4436    stephh 	itree_free(Nfmep->eventtree);
    320  4436    stephh 	lut_free(Nfmep->globals, globals_destructor, NULL);
    321  4436    stephh 	FREE(Nfmep);
    322  4436    stephh }
    323  4436    stephh 
    324     0    stevel static struct fme *
    325  4436    stephh newfme(const char *e0class, const struct ipath *e0ipp, fmd_hdl_t *hdl,
    326  4436    stephh 	fmd_case_t *fmcase)
    327     0    stevel {
    328     0    stevel 	struct cfgdata *cfgdata;
    329  4436    stephh 	int init_size;
    330  4436    stephh 	extern int alloc_total();
    331     0    stevel 
    332  4436    stephh 	init_size = alloc_total();
    333  4436    stephh 	out(O_ALTFP|O_STAMP, "start config_snapshot using %d bytes", init_size);
    334  7748     Tarik 	cfgdata = config_snapshot();
    335  4436    stephh 	platform_save_config(hdl, fmcase);
    336  4436    stephh 	out(O_ALTFP|O_STAMP, "config_snapshot added %d bytes",
    337  4436    stephh 	    alloc_total() - init_size);
    338     0    stevel 
    339     0    stevel 	Nfmep = alloc_fme();
    340     0    stevel 
    341     0    stevel 	Nfmep->id = Nextid++;
    342  5204    stephh 	Nfmep->config = cfgdata->cooked;
    343  5204    stephh 	config_free(cfgdata);
    344     0    stevel 	Nfmep->posted_suspects = 0;
    345     0    stevel 	Nfmep->uniqobs = 0;
    346     0    stevel 	Nfmep->state = FME_NOTHING;
    347     0    stevel 	Nfmep->pull = 0ULL;
    348   814     jrutt 	Nfmep->overflow = 0;
    349     0    stevel 
    350  4436    stephh 	Nfmep->fmcase = fmcase;
    351  4436    stephh 	Nfmep->hdl = hdl;
    352     0    stevel 
    353  5204    stephh 	if ((Nfmep->eventtree = itree_create(Nfmep->config)) == NULL) {
    354     0    stevel 		out(O_ALTFP, "newfme: NULL instance tree");
    355  7748     Tarik 		Undiag_reason = UD_VAL_INSTFAIL;
    356  5204    stephh 		structconfig_free(Nfmep->config);
    357  4436    stephh 		destroy_fme_bufs(Nfmep);
    358     0    stevel 		FREE(Nfmep);
    359     0    stevel 		Nfmep = NULL;
    360     0    stevel 		return (NULL);
    361     0    stevel 	}
    362     0    stevel 
    363     0    stevel 	itree_ptree(O_ALTFP|O_VERB2, Nfmep->eventtree);
    364     0    stevel 
    365     0    stevel 	if ((Nfmep->e0 =
    366     0    stevel 	    itree_lookup(Nfmep->eventtree, e0class, e0ipp)) == NULL) {
    367     0    stevel 		out(O_ALTFP, "newfme: e0 not in instance tree");
    368  7748     Tarik 		Undiag_reason = UD_VAL_BADEVENTI;
    369     0    stevel 		itree_free(Nfmep->eventtree);
    370  5204    stephh 		structconfig_free(Nfmep->config);
    371  4436    stephh 		destroy_fme_bufs(Nfmep);
    372     0    stevel 		FREE(Nfmep);
    373     0    stevel 		Nfmep = NULL;
    374     0    stevel 		return (NULL);
    375     0    stevel 	}
    376     0    stevel 
    377     0    stevel 	return (fme_ready(Nfmep));
    378     0    stevel }
    379     0    stevel 
    380     0    stevel void
    381     0    stevel fme_fini(void)
    382     0    stevel {
    383     0    stevel 	struct fme *sfp, *fp;
    384     0    stevel 	struct case_list *ucasep, *nextcasep;
    385     0    stevel 
    386     0    stevel 	ucasep = Undiagablecaselist;
    387     0    stevel 	while (ucasep != NULL) {
    388     0    stevel 		nextcasep = ucasep->next;
    389     0    stevel 		FREE(ucasep);
    390     0    stevel 		ucasep = nextcasep;
    391     0    stevel 	}
    392     0    stevel 	Undiagablecaselist = NULL;
    393     0    stevel 
    394     0    stevel 	/* clean up closed fmes */
    395     0    stevel 	fp = ClosedFMEs;
    396     0    stevel 	while (fp != NULL) {
    397     0    stevel 		sfp = fp->next;
    398     0    stevel 		destroy_fme(fp);
    399     0    stevel 		fp = sfp;
    400     0    stevel 	}
    401     0    stevel 	ClosedFMEs = NULL;
    402     0    stevel 
    403     0    stevel 	fp = FMElist;
    404     0    stevel 	while (fp != NULL) {
    405     0    stevel 		sfp = fp->next;
    406     0    stevel 		destroy_fme(fp);
    407     0    stevel 		fp = sfp;
    408     0    stevel 	}
    409     0    stevel 	FMElist = EFMElist = NULL;
    410     0    stevel 
    411     0    stevel 	/* if we were in the middle of creating an fme, free it now */
    412     0    stevel 	if (Nfmep) {
    413     0    stevel 		destroy_fme(Nfmep);
    414     0    stevel 		Nfmep = NULL;
    415     0    stevel 	}
    416     0    stevel }
    417     0    stevel 
    418     0    stevel /*
    419     0    stevel  * Allocated space for a buffer name.  20 bytes allows for
    420     0    stevel  * a ridiculous 9,999,999 unique observations.
    421     0    stevel  */
    422     0    stevel #define	OBBUFNMSZ 20
    423     0    stevel 
    424     0    stevel /*
    425     0    stevel  *  serialize_observation
    426     0    stevel  *
    427     0    stevel  *  Create a recoverable version of the current observation
    428     0    stevel  *  (f->ecurrent).  We keep a serialized version of each unique
    429     0    stevel  *  observation in order that we may resume correctly the fme in the
    430     0    stevel  *  correct state if eft or fmd crashes and we're restarted.
    431     0    stevel  */
    432     0    stevel static void
    433     0    stevel serialize_observation(struct fme *fp, const char *cls, const struct ipath *ipp)
    434     0    stevel {
    435     0    stevel 	size_t pkdlen;
    436     0    stevel 	char tmpbuf[OBBUFNMSZ];
    437     0    stevel 	char *pkd = NULL;
    438     0    stevel 	char *estr;
    439     0    stevel 
    440     0    stevel 	(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", fp->uniqobs);
    441     0    stevel 	estr = ipath2str(cls, ipp);
    442     0    stevel 	fmd_buf_create(fp->hdl, fp->fmcase, tmpbuf, strlen(estr) + 1);
    443     0    stevel 	fmd_buf_write(fp->hdl, fp->fmcase, tmpbuf, (void *)estr,
    444     0    stevel 	    strlen(estr) + 1);
    445     0    stevel 	FREE(estr);
    446     0    stevel 
    447     0    stevel 	if (fp->ecurrent != NULL && fp->ecurrent->nvp != NULL) {
    448     0    stevel 		(void) snprintf(tmpbuf,
    449     0    stevel 		    OBBUFNMSZ, "observed%d.nvp", fp->uniqobs);
    450     0    stevel 		if (nvlist_xpack(fp->ecurrent->nvp,
    451     0    stevel 		    &pkd, &pkdlen, NV_ENCODE_XDR, &Eft_nv_hdl) != 0)
    452     0    stevel 			out(O_DIE|O_SYS, "pack of observed nvl failed");
    453     0    stevel 		fmd_buf_create(fp->hdl, fp->fmcase, tmpbuf, pkdlen);
    454     0    stevel 		fmd_buf_write(fp->hdl, fp->fmcase, tmpbuf, (void *)pkd, pkdlen);
    455     0    stevel 		FREE(pkd);
    456     0    stevel 	}
    457     0    stevel 
    458     0    stevel 	fp->uniqobs++;
    459     0    stevel 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_NOBS, (void *)&fp->uniqobs,
    460     0    stevel 	    sizeof (fp->uniqobs));
    461     0    stevel }
    462     0    stevel 
    463     0    stevel /*
    464     0    stevel  *  init_fme_bufs -- We keep several bits of state about an fme for
    465     0    stevel  *	use if eft or fmd crashes and we're restarted.
    466     0    stevel  */
    467     0    stevel static void
    468     0    stevel init_fme_bufs(struct fme *fp)
    469     0    stevel {
    470     0    stevel 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_PULL, sizeof (fp->pull));
    471     0    stevel 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_PULL, (void *)&fp->pull,
    472     0    stevel 	    sizeof (fp->pull));
    473     0    stevel 
    474     0    stevel 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_ID, sizeof (fp->id));
    475     0    stevel 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_ID, (void *)&fp->id,
    476     0    stevel 	    sizeof (fp->id));
    477     0    stevel 
    478     0    stevel 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_NOBS, sizeof (fp->uniqobs));
    479     0    stevel 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_NOBS, (void *)&fp->uniqobs,
    480     0    stevel 	    sizeof (fp->uniqobs));
    481     0    stevel 
    482     0    stevel 	fmd_buf_create(fp->hdl, fp->fmcase, WOBUF_POSTD,
    483     0    stevel 	    sizeof (fp->posted_suspects));
    484     0    stevel 	fmd_buf_write(fp->hdl, fp->fmcase, WOBUF_POSTD,
    485     0    stevel 	    (void *)&fp->posted_suspects, sizeof (fp->posted_suspects));
    486     0    stevel }
    487     0    stevel 
    488     0    stevel static void
    489     0    stevel destroy_fme_bufs(struct fme *fp)
    490     0    stevel {
    491     0    stevel 	char tmpbuf[OBBUFNMSZ];
    492     0    stevel 	int o;
    493     0    stevel 
    494  4436    stephh 	platform_restore_config(fp->hdl, fp->fmcase);
    495     0    stevel 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_CFGLEN);
    496     0    stevel 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_CFG);
    497     0    stevel 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_PULL);
    498     0    stevel 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_ID);
    499     0    stevel 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_POSTD);
    500     0    stevel 	fmd_buf_destroy(fp->hdl, fp->fmcase, WOBUF_NOBS);
    501     0    stevel 
    502     0    stevel 	for (o = 0; o < fp->uniqobs; o++) {
    503     0    stevel 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", o);
    504     0    stevel 		fmd_buf_destroy(fp->hdl, fp->fmcase, tmpbuf);
    505     0    stevel 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d.nvp", o);
    506     0    stevel 		fmd_buf_destroy(fp->hdl, fp->fmcase, tmpbuf);
    507     0    stevel 	}
    508     0    stevel }
    509     0    stevel 
    510     0    stevel /*
    511     0    stevel  * reconstitute_observations -- convert a case's serialized observations
    512     0    stevel  *	back into struct events.  Returns zero if all observations are
    513     0    stevel  *	successfully reconstituted.
    514     0    stevel  */
    515     0    stevel static int
    516     0    stevel reconstitute_observations(struct fme *fmep)
    517     0    stevel {
    518     0    stevel 	struct event *ep;
    519     0    stevel 	struct node *epnamenp = NULL;
    520     0    stevel 	size_t pkdlen;
    521     0    stevel 	char *pkd = NULL;
    522     0    stevel 	char *tmpbuf = alloca(OBBUFNMSZ);
    523     0    stevel 	char *sepptr;
    524     0    stevel 	char *estr;
    525     0    stevel 	int ocnt;
    526     0    stevel 	int elen;
    527     0    stevel 
    528     0    stevel 	for (ocnt = 0; ocnt < fmep->uniqobs; ocnt++) {
    529     0    stevel 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d", ocnt);
    530     0    stevel 		elen = fmd_buf_size(fmep->hdl, fmep->fmcase, tmpbuf);
    531     0    stevel 		if (elen == 0) {
    532     0    stevel 			out(O_ALTFP,
    533     0    stevel 			    "reconstitute_observation: no %s buffer found.",
    534     0    stevel 			    tmpbuf);
    535  7748     Tarik 			Undiag_reason = UD_VAL_MISSINGOBS;
    536     0    stevel 			break;
    537     0    stevel 		}
    538     0    stevel 
    539     0    stevel 		estr = MALLOC(elen);
    540     0    stevel 		fmd_buf_read(fmep->hdl, fmep->fmcase, tmpbuf, estr, elen);
    541     0    stevel 		sepptr = strchr(estr, '@');
    542     0    stevel 		if (sepptr == NULL) {
    543     0    stevel 			out(O_ALTFP,
    544     0    stevel 			    "reconstitute_observation: %s: "
    545     0    stevel 			    "missing @ separator in %s.",
    546     0    stevel 			    tmpbuf, estr);
    547  7748     Tarik 			Undiag_reason = UD_VAL_MISSINGPATH;
    548     0    stevel 			FREE(estr);
    549     0    stevel 			break;
    550     0    stevel 		}
    551     0    stevel 
    552     0    stevel 		*sepptr = '\0';
    553     0    stevel 		if ((epnamenp = pathstring2epnamenp(sepptr + 1)) == NULL) {
    554     0    stevel 			out(O_ALTFP,
    555     0    stevel 			    "reconstitute_observation: %s: "
    556     0    stevel 			    "trouble converting path string \"%s\" "
    557     0    stevel 			    "to internal representation.",
    558     0    stevel 			    tmpbuf, sepptr + 1);
    559  7748     Tarik 			Undiag_reason = UD_VAL_MISSINGPATH;
    560     0    stevel 			FREE(estr);
    561     0    stevel 			break;
    562     0    stevel 		}
    563     0    stevel 
    564     0    stevel 		/* construct the event */
    565     0    stevel 		ep = itree_lookup(fmep->eventtree,
    566     0    stevel 		    stable(estr), ipath(epnamenp));
    567     0    stevel 		if (ep == NULL) {
    568     0    stevel 			out(O_ALTFP,
    569     0    stevel 			    "reconstitute_observation: %s: "
    570     0    stevel 			    "lookup of  \"%s\" in itree failed.",
    571     0    stevel 			    tmpbuf, ipath2str(estr, ipath(epnamenp)));
    572  7748     Tarik 			Undiag_reason = UD_VAL_BADOBS;
    573     0    stevel 			tree_free(epnamenp);
    574     0    stevel 			FREE(estr);
    575     0    stevel 			break;
    576     0    stevel 		}
    577     0    stevel 		tree_free(epnamenp);
    578     0    stevel 
    579     0    stevel 		/*
    580     0    stevel 		 * We may or may not have a saved nvlist for the observation
    581     0    stevel 		 */
    582     0    stevel 		(void) snprintf(tmpbuf, OBBUFNMSZ, "observed%d.nvp", ocnt);
    583     0    stevel 		pkdlen = fmd_buf_size(fmep->hdl, fmep->fmcase, tmpbuf);
    584     0    stevel 		if (pkdlen != 0) {
    585     0    stevel 			pkd = MALLOC(pkdlen);
    586     0    stevel 			fmd_buf_read(fmep->hdl,
    587     0    stevel 			    fmep->fmcase, tmpbuf, pkd, pkdlen);
    588  1414     cindi 			ASSERT(ep->nvp == NULL);
    589     0    stevel 			if (nvlist_xunpack(pkd,
    590     0    stevel 			    pkdlen, &ep->nvp, &Eft_nv_hdl) != 0)
    591     0    stevel 				out(O_DIE|O_SYS, "pack of observed nvl failed");
    592     0    stevel 			FREE(pkd);
    593     0    stevel 		}
    594     0    stevel 
    595     0    stevel 		if (ocnt == 0)
    596     0    stevel 			fmep->e0 = ep;
    597     0    stevel 
    598     0    stevel 		FREE(estr);
    599     0    stevel 		fmep->ecurrent = ep;
    600     0    stevel 		ep->count++;
    601     0    stevel 
    602     0    stevel 		/* link it into list of observations seen */
    603     0    stevel 		ep->observations = fmep->observations;
    604     0    stevel 		fmep->observations = ep;
    605     0    stevel 	}
    606     0    stevel 
    607     0    stevel 	if (ocnt == fmep->uniqobs) {
    608     0    stevel 		(void) fme_ready(fmep);
    609     0    stevel 		return (0);
    610     0    stevel 	}
    611     0    stevel 
    612     0    stevel 	return (1);
    613     0    stevel }
    614     0    stevel 
    615     0    stevel /*
    616     0    stevel  * restart_fme -- called during eft initialization.  Reconstitutes
    617     0    stevel  *	an in-progress fme.
    618     0    stevel  */
    619     0    stevel void
    620     0    stevel fme_restart(fmd_hdl_t *hdl, fmd_case_t *inprogress)
    621     0    stevel {
    622     0    stevel 	nvlist_t *defect;
    623     0    stevel 	struct case_list *bad;
    624     0    stevel 	struct fme *fmep;
    625  5204    stephh 	struct cfgdata *cfgdata;
    626     0    stevel 	size_t rawsz;
    627  4436    stephh 	struct event *ep;
    628  4436    stephh 	char *tmpbuf = alloca(OBBUFNMSZ);
    629  4436    stephh 	char *sepptr;
    630  4436    stephh 	char *estr;
    631  4436    stephh 	int elen;
    632  4436    stephh 	struct node *epnamenp = NULL;
    633  4436    stephh 	int init_size;
    634  4436    stephh 	extern int alloc_total();
    635  4436    stephh 
    636  4436    stephh 	/*
    637  4436    stephh 	 * ignore solved or closed cases
    638  4436    stephh 	 */
    639  4436    stephh 	if (fmd_case_solved(hdl, inprogress) ||
    640  4436    stephh 	    fmd_case_closed(hdl, inprogress))
    641  4436    stephh 		return;
    642     0    stevel 
    643     0    stevel 	fmep = alloc_fme();
    644     0    stevel 	fmep->fmcase = inprogress;
    645     0    stevel 	fmep->hdl = hdl;
    646     0    stevel 
    647  2914    stephh 	if (fmd_buf_size(hdl, inprogress, WOBUF_POSTD) == 0) {
    648  2914    stephh 		out(O_ALTFP, "restart_fme: no saved posted status");
    649  7748     Tarik 		Undiag_reason = UD_VAL_MISSINGINFO;
    650  2914    stephh 		goto badcase;
    651  2914    stephh 	} else {
    652  2914    stephh 		fmd_buf_read(hdl, inprogress, WOBUF_POSTD,
    653  2914    stephh 		    (void *)&fmep->posted_suspects,
    654  2914    stephh 		    sizeof (fmep->posted_suspects));
    655  2914    stephh 	}
    656  2914    stephh 
    657  4436    stephh 	if (fmd_buf_size(hdl, inprogress, WOBUF_ID) == 0) {
    658  4436    stephh 		out(O_ALTFP, "restart_fme: no saved id");
    659  7748     Tarik 		Undiag_reason = UD_VAL_MISSINGINFO;
    660  2914    stephh 		goto badcase;
    661  4436    stephh 	} else {
    662  4436    stephh 		fmd_buf_read(hdl, inprogress, WOBUF_ID, (void *)&fmep->id,
    663  4436    stephh 		    sizeof (fmep->id));
    664  4436    stephh 	}
    665  4436    stephh 	if (Nextid <= fmep->id)
    666  4436    stephh 		Nextid = fmep->id + 1;
    667  4436    stephh 
    668  4436    stephh 	out(O_ALTFP, "Replay FME %d", fmep->id);
    669  2914    stephh 
    670     0    stevel 	if (fmd_buf_size(hdl, inprogress, WOBUF_CFGLEN) != sizeof (size_t)) {
    671     0    stevel 		out(O_ALTFP, "restart_fme: No config data");
    672  7748     Tarik 		Undiag_reason = UD_VAL_MISSINGINFO;
    673     0    stevel 		goto badcase;
    674     0    stevel 	}
    675     0    stevel 	fmd_buf_read(hdl, inprogress, WOBUF_CFGLEN, (void *)&rawsz,
    676     0    stevel 	    sizeof (size_t));
    677     0    stevel 
    678     0    stevel 	if ((fmep->e0r = fmd_case_getprincipal(hdl, inprogress)) == NULL) {
    679     0    stevel 		out(O_ALTFP, "restart_fme: No event zero");
    680  7748     Tarik 		Undiag_reason = UD_VAL_MISSINGZERO;
    681     0    stevel 		goto badcase;
    682     0    stevel 	}
    683     0    stevel 
    684  4436    stephh 	if (fmd_buf_size(hdl, inprogress, WOBUF_PULL) == 0) {
    685  4436    stephh 		out(O_ALTFP, "restart_fme: no saved wait time");
    686  7748     Tarik 		Undiag_reason = UD_VAL_MISSINGINFO;
    687  4436    stephh 		goto badcase;
    688  4436    stephh 	} else {
    689  4436    stephh 		fmd_buf_read(hdl, inprogress, WOBUF_PULL, (void *)&fmep->pull,
    690  4436    stephh 		    sizeof (fmep->pull));
    691  4436    stephh 	}
    692  4436    stephh 
    693  4436    stephh 	if (fmd_buf_size(hdl, inprogress, WOBUF_NOBS) == 0) {
    694  4436    stephh 		out(O_ALTFP, "restart_fme: no count of observations");
    695  7748     Tarik 		Undiag_reason = UD_VAL_MISSINGINFO;
    696  4436    stephh 		goto badcase;
    697  4436    stephh 	} else {
    698  4436    stephh 		fmd_buf_read(hdl, inprogress, WOBUF_NOBS,
    699  4436    stephh 		    (void *)&fmep->uniqobs, sizeof (fmep->uniqobs));
    700  4436    stephh 	}
    701  4436    stephh 
    702  4436    stephh 	(void) snprintf(tmpbuf, OBBUFNMSZ, "observed0");
    703  4436    stephh 	elen = fmd_buf_size(fmep->hdl, fmep->fmcase, tmpbuf);
    704  4436    stephh 	if (elen == 0) {
    705  4436    stephh 		out(O_ALTFP, "reconstitute_observation: no %s buffer found.",
    706  4436    stephh 		    tmpbuf);
    707  7748     Tarik 		Undiag_reason = UD_VAL_MISSINGOBS;
    708  4436    stephh 		goto badcase;
    709  4436    stephh 	}
    710  4436    stephh 	estr = MALLOC(elen);
    711  4436    stephh 	fmd_buf_read(fmep->hdl, fmep->fmcase, tmpbuf, estr, elen);
    712  4436    stephh 	sepptr = strchr(estr, '@');
    713  4436    stephh 	if (sepptr == NULL) {
    714  4436    stephh 		out(O_ALTFP, "reconstitute_observation: %s: "
    715  4436    stephh 		    "missing @ separator in %s.",
    716  4436    stephh 		    tmpbuf, estr);
    717  7748     Tarik 		Undiag_reason = UD_VAL_MISSINGPATH;
    718  4436    stephh 		FREE(estr);
    719  4436    stephh 		goto badcase;
    720  4436    stephh 	}
    721  4436    stephh 	*sepptr = '\0';
    722  4436    stephh 	if ((epnamenp = pathstring2epnamenp(sepptr + 1)) == NULL) {
    723  4436    stephh 		out(O_ALTFP, "reconstitute_observation: %s: "
    724  4436    stephh 		    "trouble converting path string \"%s\" "
    725  4436    stephh 		    "to internal representation.", tmpbuf, sepptr + 1);
    726  7748     Tarik 		Undiag_reason = UD_VAL_MISSINGPATH;
    727  4436    stephh 		FREE(estr);
    728  4436    stephh 		goto badcase;
    729  4436    stephh 	}
    730  4436    stephh 	prune_propagations(stable(estr), ipath(epnamenp));
    731  4436    stephh 	tree_free(epnamenp);
    732  4436    stephh 	FREE(estr);
    733  4436    stephh 
    734  4436    stephh 	init_size = alloc_total();
    735  4436    stephh 	out(O_ALTFP|O_STAMP, "start config_restore using %d bytes", init_size);
    736     0    stevel 	cfgdata = MALLOC(sizeof (struct cfgdata));
    737     0    stevel 	cfgdata->cooked = NULL;
    738     0    stevel 	cfgdata->devcache = NULL;
    739  6640       cth 	cfgdata->devidcache = NULL;
    740     0    stevel 	cfgdata->cpucache = NULL;
    741  4436    stephh 	cfgdata->raw_refcnt = 1;
    742     0    stevel 
    743     0    stevel 	if (rawsz > 0) {
    744     0    stevel 		if (fmd_buf_size(hdl, inprogress, WOBUF_CFG) != rawsz) {
    745     0    stevel 			out(O_ALTFP, "restart_fme: Config data size mismatch");
    746  7748     Tarik 			Undiag_reason = UD_VAL_CFGMISMATCH;
    747     0    stevel 			goto badcase;
    748     0    stevel 		}
    749     0    stevel 		cfgdata->begin = MALLOC(rawsz);
    750     0    stevel 		cfgdata->end = cfgdata->nextfree = cfgdata->begin + rawsz;
    751     0    stevel 		fmd_buf_read(hdl,
    752     0    stevel 		    inprogress, WOBUF_CFG, cfgdata->begin, rawsz);
    753     0    stevel 	} else {
    754     0    stevel 		cfgdata->begin = cfgdata->end = cfgdata->nextfree = NULL;
    755     0    stevel 	}
    756     0    stevel 
    757     0    stevel 	config_cook(cfgdata);
    758  5204    stephh 	fmep->config = cfgdata->cooked;
    759  5204    stephh 	config_free(cfgdata);
    760  4436    stephh 	out(O_ALTFP|O_STAMP, "config_restore added %d bytes",
    761  4436    stephh 	    alloc_total() - init_size);
    762  4436    stephh 
    763  5204    stephh 	if ((fmep->eventtree = itree_create(fmep->config)) == NULL) {
    764     0    stevel 		/* case not properly saved or irretrievable */
    765     0    stevel 		out(O_ALTFP, "restart_fme: NULL instance tree");
    766  7748     Tarik 		Undiag_reason = UD_VAL_INSTFAIL;
    767     0    stevel 		goto badcase;
    768     0    stevel 	}
    769     0    stevel 
    770     0    stevel 	itree_ptree(O_ALTFP|O_VERB2, fmep->eventtree);
    771     0    stevel 
    772     0    stevel 	if (reconstitute_observations(fmep) != 0)
    773     0    stevel 		goto badcase;
    774  4436    stephh 
    775  4436    stephh 	out(O_ALTFP|O_NONL, "FME %d replay observations: ", fmep->id);
    776  4436    stephh 	for (ep = fmep->observations; ep; ep = ep->observations) {
    777  4436    stephh 		out(O_ALTFP|O_NONL, " ");
    778  4436    stephh 		itree_pevent_brief(O_ALTFP|O_NONL, ep);
    779  4436    stephh 	}
    780  4436    stephh 	out(O_ALTFP, NULL);
    781     0    stevel 
    782   814     jrutt 	Open_fme_count++;
    783   814     jrutt 
    784     0    stevel 	/* give the diagnosis algorithm a shot at the new FME state */
    785  2914    stephh 	fme_eval(fmep, fmep->e0r);
    786     0    stevel 	return;
    787     0    stevel 
    788     0    stevel badcase:
    789     0    stevel 	if (fmep->eventtree != NULL)
    790     0    stevel 		itree_free(fmep->eventtree);
    791  5204    stephh 	if (fmep->config)
    792  5204    stephh 		structconfig_free(fmep->config);
    793     0    stevel 	destroy_fme_bufs(fmep);
    794     0    stevel 	FREE(fmep);
    795     0    stevel 
    796     0    stevel 	/*
    797     0    stevel 	 * Since we're unable to restart the case, add it to the undiagable
    798     0    stevel 	 * list and solve and close it as appropriate.
    799     0    stevel 	 */
    800     0    stevel 	bad = MALLOC(sizeof (struct case_list));
    801     0    stevel 	bad->next = NULL;
    802     0    stevel 
    803     0    stevel 	if (Undiagablecaselist != NULL)
    804     0    stevel 		bad->next = Undiagablecaselist;
    805     0    stevel 	Undiagablecaselist = bad;
    806     0    stevel 	bad->fmcase = inprogress;
    807     0    stevel 
    808  2914    stephh 	out(O_ALTFP|O_NONL, "[case %s (unable to restart), ",
    809     0    stevel 	    fmd_case_uuid(hdl, bad->fmcase));
    810     0    stevel 
    811     0    stevel 	if (fmd_case_solved(hdl, bad->fmcase)) {
    812  2914    stephh 		out(O_ALTFP|O_NONL, "already solved, ");
    813     0    stevel 	} else {
    814  2914    stephh 		out(O_ALTFP|O_NONL, "solving, ");
    815  7748     Tarik 		defect = fmd_nvl_create_fault(hdl,
    816  7748     Tarik 		    undiag_2defect_str(Undiag_reason), 100, NULL, NULL, NULL);
    817  7748     Tarik 		(void) nvlist_add_string(defect, UNDIAG_REASON,
    818  7748     Tarik 		    undiag_2reason_str(Undiag_reason));
    819     0    stevel 		fmd_case_add_suspect(hdl, bad->fmcase, defect);
    820     0    stevel 		fmd_case_solve(hdl, bad->fmcase);
    821  7748     Tarik 		Undiag_reason = UD_VAL_UNKNOWN;
    822     0    stevel 	}
    823     0    stevel 
    824     0    stevel 	if (fmd_case_closed(hdl, bad->fmcase)) {
    825     0    stevel 		out(O_ALTFP, "already closed ]");
    826     0    stevel 	} else {
    827     0    stevel 		out(O_ALTFP, "closing ]");
    828     0    stevel 		fmd_case_close(hdl, bad->fmcase);
    829     0    stevel 	}
    830     0    stevel }
    831     0    stevel 
    832  1414     cindi /*ARGSUSED*/
    833  1414     cindi static void
    834  1414     cindi globals_destructor(void *left, void *right, void *arg)
    835  1414     cindi {
    836  1414     cindi 	struct evalue *evp = (struct evalue *)right;
    837  1414     cindi 	if (evp->t == NODEPTR)
    838  1717  wesolows 		tree_free((struct node *)(uintptr_t)evp->v);
    839  6277  cy152378 	evp->v = (uintptr_t)NULL;
    840  1414     cindi 	FREE(evp);
    841  1414     cindi }
    842  1414     cindi 
    843     0    stevel void
    844     0    stevel destroy_fme(struct fme *f)
    845     0    stevel {
    846     0    stevel 	stats_delete(f->Rcount);
    847     0    stevel 	stats_delete(f->Hcallcount);
    848     0    stevel 	stats_delete(f->Rcallcount);
    849     0    stevel 	stats_delete(f->Ccallcount);
    850     0    stevel 	stats_delete(f->Ecallcount);
    851     0    stevel 	stats_delete(f->Tcallcount);
    852     0    stevel 	stats_delete(f->Marrowcount);
    853     0    stevel 	stats_delete(f->diags);
    854     0    stevel 
    855  2914    stephh 	if (f->eventtree != NULL)
    856  2914    stephh 		itree_free(f->eventtree);
    857  5204    stephh 	if (f->config)
    858  5204    stephh 		structconfig_free(f->config);
    859  1414     cindi 	lut_free(f->globals, globals_destructor, NULL);
    860     0    stevel 	FREE(f);
    861     0    stevel }
    862     0    stevel 
    863     0    stevel static const char *
    864     0    stevel fme_state2str(enum fme_state s)
    865     0    stevel {
    866     0    stevel 	switch (s) {
    867     0    stevel 	case FME_NOTHING:	return ("NOTHING");
    868     0    stevel 	case FME_WAIT:		return ("WAIT");
    869     0    stevel 	case FME_CREDIBLE:	return ("CREDIBLE");
    870     0    stevel 	case FME_DISPROVED:	return ("DISPROVED");
    871  1414     cindi 	case FME_DEFERRED:	return ("DEFERRED");
    872     0    stevel 	default:		return ("UNKNOWN");
    873     0    stevel 	}
    874     0    stevel }
    875     0    stevel 
    876     0    stevel static int
    877     0    stevel is_problem(enum nametype t)
    878     0    stevel {
    879     0    stevel 	return (t == N_FAULT || t == N_DEFECT || t == N_UPSET);
    880     0    stevel }
    881     0    stevel 
    882     0    stevel static int
    883     0    stevel is_defect(enum nametype t)
    884     0    stevel {
    885     0    stevel 	return (t == N_DEFECT);
    886     0    stevel }
    887     0    stevel 
    888     0    stevel static int
    889     0    stevel is_upset(enum nametype t)
    890     0    stevel {
    891     0    stevel 	return (t == N_UPSET);
    892     0    stevel }
    893     0    stevel 
    894     0    stevel static void
    895     0    stevel fme_print(int flags, struct fme *fmep)
    896     0    stevel {
    897     0    stevel 	struct event *ep;
    898     0    stevel 
    899     0    stevel 	out(flags, "Fault Management Exercise %d", fmep->id);
    900     0    stevel 	out(flags, "\t       State: %s", fme_state2str(fmep->state));
    901     0    stevel 	out(flags|O_NONL, "\t  Start time: ");
    902     0    stevel 	ptree_timeval(flags|O_NONL, &fmep->ull);
    903     0    stevel 	out(flags, NULL);
    904     0    stevel 	if (fmep->wull) {
    905     0    stevel 		out(flags|O_NONL, "\t   Wait time: ");
    906     0    stevel 		ptree_timeval(flags|O_NONL, &fmep->wull);
    907     0    stevel 		out(flags, NULL);
    908     0    stevel 	}
    909     0    stevel 	out(flags|O_NONL, "\t          E0: ");
    910     0    stevel 	if (fmep->e0)
    911     0    stevel 		itree_pevent_brief(flags|O_NONL, fmep->e0);
    912     0    stevel 	else
    913     0    stevel 		out(flags|O_NONL, "NULL");
    914     0    stevel 	out(flags, NULL);
    915     0    stevel 	out(flags|O_NONL, "\tObservations:");
    916     0    stevel 	for (ep = fmep->observations; ep; ep = ep->observations) {
    917     0    stevel 		out(flags|O_NONL, " ");
    918     0    stevel 		itree_pevent_brief(flags|O_NONL, ep);
    919     0    stevel 	}
    920     0    stevel 	out(flags, NULL);
    921     0    stevel 	out(flags|O_NONL, "\tSuspect list:");
    922     0    stevel 	for (ep = fmep->suspects; ep; ep = ep->suspects) {
    923     0    stevel 		out(flags|O_NONL, " ");
    924     0    stevel 		itree_pevent_brief(flags|O_NONL, ep);
    925     0    stevel 	}
    926     0    stevel 	out(flags, NULL);
    927  2914    stephh 	if (fmep->eventtree != NULL) {
    928  2914    stephh 		out(flags|O_VERB2, "\t        Tree:");
    929  2914    stephh 		itree_ptree(flags|O_VERB2, fmep->eventtree);
    930  2914    stephh 	}
    931     0    stevel }
    932     0    stevel 
    933     0    stevel static struct node *
    934     0    stevel pathstring2epnamenp(char *path)
    935     0    stevel {
    936     0    stevel 	char *sep = "/";
    937     0    stevel 	struct node *ret;
    938     0    stevel 	char *ptr;
    939     0    stevel 
    940     0    stevel 	if ((ptr = strtok(path, sep)) == NULL)
    941     0    stevel 		out(O_DIE, "pathstring2epnamenp: invalid empty class");
    942     0    stevel 
    943     0    stevel 	ret = tree_iname(stable(ptr), NULL, 0);
    944     0    stevel 
    945     0    stevel 	while ((ptr = strtok(NULL, sep)) != NULL)
    946     0    stevel 		ret = tree_name_append(ret,
    947     0    stevel 		    tree_iname(stable(ptr), NULL, 0));
    948     0    stevel 
    949     0    stevel 	return (ret);
    950     0    stevel }
    951     0    stevel 
    952     0    stevel /*
    953     0    stevel  * for a given upset sp, increment the corresponding SERD engine.  if the
    954     0    stevel  * SERD engine trips, return the ename and ipp of the resulting ereport.
    955     0    stevel  * returns true if engine tripped and *enamep and *ippp were filled in.
    956     0    stevel  */
    957     0    stevel static int
    958  1414     cindi serd_eval(struct fme *fmep, fmd_hdl_t *hdl, fmd_event_t *ffep,
    959  1414     cindi     fmd_case_t *fmcase, struct event *sp, const char **enamep,
    960  1414     cindi     const struct ipath **ippp)
    961     0    stevel {
    962     0    stevel 	struct node *serdinst;
    963     0    stevel 	char *serdname;
    964  7337     Scott 	char *serdresource;
    965  8245   Stephen 	char *serdclass;
    966  1414     cindi 	struct node *nid;
    967  4436    stephh 	struct serd_entry *newentp;
    968  7337     Scott 	int i, serdn = -1, serdincrement = 1, len = 0;
    969  8245   Stephen 	char *serdsuffix = NULL, *serdt = NULL;
    970  7197    stephh 	struct evalue *ep;
    971     0    stevel 
    972     0    stevel 	ASSERT(sp->t == N_UPSET);
    973     0    stevel 	ASSERT(ffep != NULL);
    974     0    stevel 
    975  7197    stephh 	if ((ep = (struct evalue *)lut_lookup(sp->serdprops,
    976  7197    stephh 	    (void *)"n", (lut_cmp)strcmp)) != NULL) {
    977  7197    stephh 		ASSERT(ep->t == UINT64);
    978  7197    stephh 		serdn = (int)ep->v;
    979  7197    stephh 	}
    980  7197    stephh 	if ((ep = (struct evalue *)lut_lookup(sp->serdprops,
    981  7197    stephh 	    (void *)"t", (lut_cmp)strcmp)) != NULL) {
    982  7197    stephh 		ASSERT(ep->t == STRING);
    983  7197    stephh 		serdt = (char *)(uintptr_t)ep->v;
    984  7197    stephh 	}
    985  7197    stephh 	if ((ep = (struct evalue *)lut_lookup(sp->serdprops,
    986  7197    stephh 	    (void *)"suffix", (lut_cmp)strcmp)) != NULL) {
    987  7197    stephh 		ASSERT(ep->t == STRING);
    988  7197    stephh 		serdsuffix = (char *)(uintptr_t)ep->v;
    989  7197    stephh 	}
    990  7197    stephh 	if ((ep = (struct evalue *)lut_lookup(sp->serdprops,
    991  7197    stephh 	    (void *)"increment", (lut_cmp)strcmp)) != NULL) {
    992  7197    stephh 		ASSERT(ep->t == UINT64);
    993  7197    stephh 		serdincrement = (int)ep->v;
    994  7197    stephh 	}
    995  7197    stephh 
    996     0    stevel 	/*
    997     0    stevel 	 * obtain instanced SERD engine from the upset sp.  from this
    998     0    stevel 	 * derive serdname, the string used to identify the SERD engine.
    999     0    stevel 	 */
   1000     0    stevel 	serdinst = eventprop_lookup(sp, L_engine);
   1001     0    stevel 
   1002     0    stevel 	if (serdinst == NULL)
   1003  7197    stephh 		return (-1);
   1004     0    stevel 
   1005  8245   Stephen 	len = strlen(serdinst->u.stmt.np->u.event.ename->u.name.s) + 1;
   1006  8245   Stephen 	if (serdsuffix != NULL)
   1007  8245   Stephen 		len += strlen(serdsuffix);
   1008  8245   Stephen 	serdclass = MALLOC(len);
   1009  8245   Stephen 	if (serdsuffix != NULL)
   1010  8245   Stephen 		(void) snprintf(serdclass, len, "%s%s",
   1011  8245   Stephen 		    serdinst->u.stmt.np->u.event.ename->u.name.s, serdsuffix);
   1012  8245   Stephen 	else
   1013  8245   Stephen 		(void) snprintf(serdclass, len, "%s",
   1014  8245   Stephen 		    serdinst->u.stmt.np->u.event.ename->u.name.s);
   1015  7337     Scott 	serdresource = ipath2str(NULL,
   1016     0    stevel 	    ipath(serdinst->u.stmt.np->u.event.epname));
   1017  8245   Stephen 	len += strlen(serdresource) + 1;
   1018  8245   Stephen 	serdname = MALLOC(len);
   1019  8245   Stephen 	(void) snprintf(serdname, len, "%s@%s", serdclass, serdresource);
   1020  7337     Scott 	FREE(serdresource);
   1021  1414     cindi 
   1022  1414     cindi 	/* handle serd engine "id" property, if there is one */
   1023  1414     cindi 	if ((nid =
   1024  1414     cindi 	    lut_lookup(serdinst->u.stmt.lutp, (void *)L_id, NULL)) != NULL) {
   1025  1414     cindi 		struct evalue *gval;
   1026  1414     cindi 		char suffixbuf[200];
   1027  1414     cindi 		char *suffix;
   1028  1414     cindi 		char *nserdname;
   1029  1414     cindi 		size_t nname;
   1030  1414     cindi 
   1031  1414     cindi 		out(O_ALTFP|O_NONL, "serd \"%s\" id: ", serdname);
   1032  1414     cindi 		ptree_name_iter(O_ALTFP|O_NONL, nid);
   1033  1414     cindi 
   1034  1414     cindi 		ASSERTinfo(nid->t == T_GLOBID, ptree_nodetype2str(nid->t));
   1035  1414     cindi 
   1036  1414     cindi 		if ((gval = lut_lookup(fmep->globals,
   1037  1414     cindi 		    (void *)nid->u.globid.s, NULL)) == NULL) {
   1038  1414     cindi 			out(O_ALTFP, " undefined");
   1039  1414     cindi 		} else if (gval->t == UINT64) {
   1040  1414     cindi 			out(O_ALTFP, " %llu", gval->v);
   1041  1414     cindi 			(void) sprintf(suffixbuf, "%llu", gval->v);
   1042  1414     cindi 			suffix = suffixbuf;
   1043  1414     cindi 		} else {
   1044  1717  wesolows 			out(O_ALTFP, " \"%s\"", (char *)(uintptr_t)gval->v);
   1045  1717  wesolows 			suffix = (char *)(uintptr_t)gval->v;
   1046  1414     cindi 		}
   1047  1414     cindi 
   1048  1414     cindi 		nname = strlen(serdname) + strlen(suffix) + 2;
   1049  1414     cindi 		nserdname = MALLOC(nname);
   1050  1414     cindi 		(void) snprintf(nserdname, nname, "%s:%s", serdname, suffix);
   1051  1414     cindi 		FREE(serdname);
   1052  1414     cindi 		serdname = nserdname;
   1053  1414     cindi 	}
   1054  7197    stephh 
   1055  7197    stephh 	/*
   1056  7197    stephh 	 * if the engine is empty, and we have an override for n/t then
   1057  7197    stephh 	 * destroy and recreate it.
   1058  7197    stephh 	 */
   1059  7197    stephh 	if ((serdn != -1 || serdt != NULL) && fmd_serd_exists(hdl, serdname) &&
   1060  7197    stephh 	    fmd_serd_empty(hdl, serdname))
   1061  7197    stephh 		fmd_serd_destroy(hdl, serdname);
   1062     0    stevel 
   1063     0    stevel 	if (!fmd_serd_exists(hdl, serdname)) {
   1064     0    stevel 		struct node *nN, *nT;
   1065  5204    stephh 		const char *s;
   1066  5204    stephh 		struct node *nodep;
   1067  5204    stephh 		struct config *cp;
   1068  5204    stephh 		char *path;
   1069  5204    stephh 		uint_t nval;
   1070  5204    stephh 		hrtime_t tval;
   1071  5204    stephh 		int i;
   1072  5204    stephh 		char *ptr;
   1073  5204    stephh 		int got_n_override = 0, got_t_override = 0;
   1074     0    stevel 
   1075     0    stevel 		/* no SERD engine yet, so create it */
   1076  5204    stephh 		nodep = serdinst->u.stmt.np->u.event.epname;
   1077  5204    stephh 		path = ipath2str(NULL, ipath(nodep));
   1078  5204    stephh 		cp = config_lookup(fmep->config, path, 0);
   1079  5204    stephh 		FREE((void *)path);
   1080     0    stevel 
   1081  5204    stephh 		/*
   1082  5204    stephh 		 * We allow serd paramaters to be overridden, either from
   1083  5204    stephh 		 * eft.conf file values (if Serd_Override is set) or from
   1084  5204    stephh 		 * driver properties (for "serd.io.device" engines).
   1085  5204    stephh 		 */
   1086  5204    stephh 		if (Serd_Override != NULL) {
   1087  5204    stephh 			char *save_ptr, *ptr1, *ptr2, *ptr3;
   1088  5204    stephh 			ptr3 = save_ptr = STRDUP(Serd_Override);
   1089  5204    stephh 			while (*ptr3 != '\0') {
   1090  5204    stephh 				ptr1 = strchr(ptr3, ',');
   1091  5204    stephh 				*ptr1 = '\0';
   1092  8245   Stephen 				if (strcmp(ptr3, serdclass) == 0) {
   1093  5204    stephh 					ptr2 =  strchr(ptr1 + 1, ',');
   1094  5204    stephh 					*ptr2 = '\0';
   1095  5204    stephh 					nval = atoi(ptr1 + 1);
   1096  5204    stephh 					out(O_ALTFP, "serd override %s_n %d",
   1097  8245   Stephen 					    serdclass, nval);
   1098  5204    stephh 					ptr3 =  strchr(ptr2 + 1, ' ');
   1099  5204    stephh 					if (ptr3)
   1100  5204    stephh 						*ptr3 = '\0';
   1101  5204    stephh 					ptr = STRDUP(ptr2 + 1);
   1102  5204    stephh 					out(O_ALTFP, "serd override %s_t %s",
   1103  8245   Stephen 					    serdclass, ptr);
   1104  5204    stephh 					got_n_override = 1;
   1105  5204    stephh 					got_t_override = 1;
   1106  5204    stephh 					break;
   1107  5204    stephh 				} else {
   1108  5204    stephh 					ptr2 =  strchr(ptr1 + 1, ',');
   1109  5204    stephh 					ptr3 =  strchr(ptr2 + 1, ' ');
   1110  5204    stephh 					if (ptr3 == NULL)
   1111  5204    stephh 						break;
   1112  5204    stephh 				}
   1113  5204    stephh 				ptr3++;
   1114  5204    stephh 			}
   1115  5204    stephh 			FREE(save_ptr);
   1116  5204    stephh 		}
   1117     0    stevel 
   1118  5204    stephh 		if (cp && got_n_override == 0) {
   1119  5204    stephh 			/*
   1120  8245   Stephen 			 * convert serd engine class into property name
   1121  8245   Stephen 			 */
   1122  8245   Stephen 			char *prop_name = MALLOC(strlen(serdclass) + 3);
   1123  8245   Stephen 			for (i = 0; i < strlen(serdclass); i++) {
   1124  8245   Stephen 				if (serdclass[i] == '.')
   1125  8245   Stephen 					prop_name[i] = '_';
   1126  5204    stephh 				else
   1127  8245   Stephen 					prop_name[i] = serdclass[i];
   1128  8245   Stephen 			}
   1129  8245   Stephen 			prop_name[i++] = '_';
   1130  8245   Stephen 			prop_name[i++] = 'n';
   1131  8245   Stephen 			prop_name[i] = '\0';
   1132  8245   Stephen 			if (s = config_getprop(cp, prop_name)) {
   1133  5204    stephh 				nval = atoi(s);
   1134  8245   Stephen 				out(O_ALTFP, "serd override %s_n %s",
   1135  8245   Stephen 				    serdclass, s);
   1136  5204    stephh 				got_n_override = 1;
   1137  5204    stephh 			}
   1138  8245   Stephen 			prop_name[i - 1] = 't';
   1139  8245   Stephen 			if (s = config_getprop(cp, prop_name)) {
   1140  5204    stephh 				ptr = STRDUP(s);
   1141  8245   Stephen 				out(O_ALTFP, "serd override %s_t %s",
   1142  8245   Stephen 				    serdclass, s);
   1143  5204    stephh 				got_t_override = 1;
   1144  5204    stephh 			}
   1145  8245   Stephen 			FREE(prop_name);
   1146  5204    stephh 		}
   1147  5204    stephh 
   1148  7197    stephh 		if (serdn != -1 && got_n_override == 0) {
   1149  7197    stephh 			nval = serdn;
   1150  8245   Stephen 			out(O_ALTFP, "serd override %s_n %d", serdclass, serdn);
   1151  7197    stephh 			got_n_override = 1;
   1152  7197    stephh 		}
   1153  7197    stephh 		if (serdt != NULL && got_t_override == 0) {
   1154  7197    stephh 			ptr = STRDUP(serdt);
   1155  8245   Stephen 			out(O_ALTFP, "serd override %s_t %s", serdclass, serdt);
   1156  7197    stephh 			got_t_override = 1;
   1157  7197    stephh 		}
   1158  7197    stephh 
   1159  5204    stephh 		if (!got_n_override) {
   1160  5204    stephh 			nN = lut_lookup(serdinst->u.stmt.lutp, (void *)L_N,
   1161  5204    stephh 			    NULL);
   1162  5204    stephh 			ASSERT(nN->t == T_NUM);
   1163  5204    stephh 			nval = (uint_t)nN->u.ull;
   1164  5204    stephh 		}
   1165  5204    stephh 		if (!got_t_override) {
   1166  5204    stephh 			nT = lut_lookup(serdinst->u.stmt.lutp, (void *)L_T,
   1167  5204    stephh 			    NULL);
   1168  5204    stephh 			ASSERT(nT->t == T_TIMEVAL);
   1169  5204    stephh 			tval = (hrtime_t)nT->u.ull;
   1170  5204    stephh 		} else {
   1171  5204    stephh 			const unsigned long long *ullp;
   1172  5204    stephh 			const char *suffix;
   1173  5204    stephh 			int len;
   1174  5204    stephh 
   1175  5204    stephh 			len = strspn(ptr, "0123456789");
   1176  5204    stephh 			suffix = stable(&ptr[len]);
   1177  5204    stephh 			ullp = (unsigned long long *)lut_lookup(Timesuffixlut,
   1178  5204    stephh 			    (void *)suffix, NULL);
   1179  5204    stephh 			ptr[len] = '\0';
   1180  7197    stephh 			tval = strtoull(ptr, NULL, 0) * (ullp ? *ullp : 1ll);
   1181  5204    stephh 			FREE(ptr);
   1182  5204    stephh 		}
   1183  5204    stephh 		fmd_serd_create(hdl, serdname, nval, tval);
   1184  4436    stephh 	}
   1185  4436    stephh 
   1186  4436    stephh 	newentp = MALLOC(sizeof (*newentp));
   1187  8245   Stephen 	newentp->ename = stable(serdclass);
   1188  8245   Stephen 	FREE(serdclass);
   1189  4436    stephh 	newentp->ipath = ipath(serdinst->u.stmt.np->u.event.epname);
   1190  4436    stephh 	newentp->hdl = hdl;
   1191  4436    stephh 	if (lut_lookup(SerdEngines, newentp, (lut_cmp)serd_cmp) == NULL) {
   1192  4436    stephh 		SerdEngines = lut_add(SerdEngines, (void *)newentp,
   1193  5204    stephh 		    (void *)newentp, (lut_cmp)serd_cmp);
   1194  4436    stephh 		Serd_need_save = 1;
   1195  4436    stephh 		serd_save();
   1196  4436    stephh 	} else {
   1197  4436    stephh 		FREE(newentp);
   1198     0    stevel 	}
   1199     0    stevel 
   1200     0    stevel 
   1201     0    stevel 	/*
   1202     0    stevel 	 * increment SERD engine.  if engine fires, reset serd
   1203  7197    stephh 	 * engine and return trip_strcode if required.
   1204  7197    stephh 	 */
   1205  7197    stephh 	for (i = 0; i < serdincrement; i++) {
   1206  7197    stephh 		if (fmd_serd_record(hdl, serdname, ffep)) {
   1207  7197    stephh 			fmd_case_add_serd(hdl, fmcase, serdname);
   1208  7197    stephh 			fmd_serd_reset(hdl, serdname);
   1209  7197    stephh 
   1210  7197    stephh 			if (ippp) {
   1211  7197    stephh 				struct node *tripinst =
   1212  7197    stephh 				    lut_lookup(serdinst->u.stmt.lutp,
   1213  7197    stephh 				    (void *)L_trip, NULL);
   1214  7197    stephh 				ASSERT(tripinst != NULL);
   1215  7197    stephh 				*enamep = tripinst->u.event.ename->u.name.s;
   1216  7197    stephh 				*ippp = ipath(tripinst->u.event.epname);
   1217  7197    stephh 				out(O_ALTFP|O_NONL,
   1218  7197    stephh 				    "[engine fired: %s, sending: ", serdname);
   1219  7197    stephh 				ipath_print(O_ALTFP|O_NONL, *enamep, *ippp);
   1220  7197    stephh 				out(O_ALTFP, "]");
   1221  7197    stephh 			} else {
   1222  7197    stephh 				out(O_ALTFP, "[engine fired: %s, no trip]",
   1223  7197    stephh 				    serdname);
   1224  7197    stephh 			}
   1225  7197    stephh 			FREE(serdname);
   1226  7197    stephh 			return (1);
   1227  7197    stephh 		}
   1228     0    stevel 	}
   1229     0    stevel 
   1230     0    stevel 	FREE(serdname);
   1231     0    stevel 	return (0);
   1232     0    stevel }
   1233     0    stevel 
   1234     0    stevel /*
   1235     0    stevel  * search a suspect list for upsets.  feed each upset to serd_eval() and
   1236     0    stevel  * build up tripped[], an array of ereports produced by the firing of
   1237     0    stevel  * any SERD engines.  then feed each ereport back into
   1238     0    stevel  * fme_receive_report().
   1239     0    stevel  *
   1240     0    stevel  * returns ntrip, the number of these ereports produced.
   1241     0    stevel  */
   1242     0    stevel static int
   1243     0    stevel upsets_eval(struct fme *fmep, fmd_event_t *ffep)
   1244     0    stevel {
   1245     0    stevel 	/* we build an array of tripped ereports that we send ourselves */
   1246     0    stevel 	struct {
   1247     0    stevel 		const char *ename;
   1248     0    stevel 		const struct ipath *ipp;
   1249     0    stevel 	} *tripped;
   1250     0    stevel 	struct event *sp;
   1251     0    stevel 	int ntrip, nupset, i;
   1252     0    stevel 
   1253     0    stevel 	/*
   1254     0    stevel 	 * count the number of upsets to determine the upper limit on
   1255     0    stevel 	 * expected trip ereport strings.  remember that one upset can
   1256     0    stevel 	 * lead to at most one ereport.
   1257     0    stevel 	 */
   1258     0    stevel 	nupset = 0;
   1259     0    stevel 	for (sp = fmep->suspects; sp; sp = sp->suspects) {
   1260     0    stevel 		if (sp->t == N_UPSET)
   1261     0    stevel 			nupset++;
   1262     0    stevel 	}
   1263     0    stevel 
   1264     0    stevel 	if (nupset == 0)
   1265     0    stevel 		return (0);
   1266     0    stevel 
   1267     0    stevel 	/*
   1268     0    stevel 	 * get to this point if we have upsets and expect some trip
   1269     0    stevel 	 * ereports
   1270     0    stevel 	 */
   1271     0    stevel 	tripped = alloca(sizeof (*tripped) * nupset);
   1272     0    stevel 	bzero((void *)tripped, sizeof (*tripped) * nupset);
   1273     0    stevel 
   1274     0    stevel 	ntrip = 0;
   1275     0    stevel 	for (sp = fmep->suspects; sp; sp = sp->suspects)
   1276   186   db35262 		if (sp->t == N_UPSET &&
   1277  1414     cindi 		    serd_eval(fmep, fmep->hdl, ffep, fmep->fmcase, sp,
   1278  7197    stephh 		    &tripped[ntrip].ename, &tripped[ntrip].ipp) == 1)
   1279     0    stevel 			ntrip++;
   1280     0    stevel 
   1281  5947    stephh 	for (i = 0; i < ntrip; i++) {
   1282  5947    stephh 		struct event *ep, *nep;
   1283  5947    stephh 		struct fme *nfmep;
   1284  5947    stephh 		fmd_case_t *fmcase;
   1285  5947    stephh 		const struct ipath *ipp;
   1286  5947    stephh 		const char *eventstring;
   1287  5947    stephh 		int prev_verbose;
   1288  5947    stephh 		unsigned long long my_delay = TIMEVAL_EVENTUALLY;
   1289  5947    stephh 		enum fme_state state;
   1290  5947    stephh 
   1291  5947    stephh 		/*
   1292  5947    stephh 		 * First try and evaluate a case with the trip ereport plus
   1293  5947    stephh 		 * all the other ereports that cause the trip. If that fails
   1294  5947    stephh 		 * to evaluate then try again with just this ereport on its own.
   1295  5947    stephh 		 */
   1296  5947    stephh 		out(O_ALTFP|O_NONL, "fme_receive_report_serd: ");
   1297  5947    stephh 		ipath_print(O_ALTFP|O_NONL, tripped[i].ename, tripped[i].ipp);
   1298  5947    stephh 		out(O_ALTFP|O_STAMP, NULL);
   1299  5947    stephh 		ep = fmep->e0;
   1300  5947    stephh 		eventstring = ep->enode->u.event.ename->u.name.s;
   1301  5947    stephh 		ipp = ep->ipp;
   1302  5947    stephh 		prune_propagations(eventstring, ipp);
   1303  5947    stephh 
   1304  5947    stephh 		/*
   1305  5947    stephh 		 * create a duplicate fme and case
   1306  5947    stephh 		 */
   1307  5947    stephh 		fmcase = fmd_case_open(fmep->hdl, NULL);
   1308  5947    stephh 		out(O_ALTFP|O_NONL, "duplicate fme for event [");
   1309  5947    stephh 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
   1310  5947    stephh 		out(O_ALTFP, " ]");
   1311  5947    stephh 		if ((nfmep = newfme(eventstring, ipp, fmep->hdl,
   1312  5947    stephh 		    fmcase)) == NULL) {
   1313  5947    stephh 			out(O_ALTFP|O_NONL, "[");
   1314  5947    stephh 			ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
   1315  5947    stephh 			out(O_ALTFP, " CANNOT DIAGNOSE]");
   1316  5947    stephh 			publish_undiagnosable(fmep->hdl, ffep, fmcase);
   1317  5947    stephh 			continue;
   1318  5947    stephh 		}
   1319  5947    stephh 		Open_fme_count++;
   1320  5947    stephh 		nfmep->pull = fmep->pull;
   1321  5947    stephh 		init_fme_bufs(nfmep);
   1322  5947    stephh 		out(O_ALTFP|O_NONL, "[");
   1323  5947    stephh 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
   1324  5947    stephh 		out(O_ALTFP, " created FME%d, case %s]", nfmep->id,
   1325  5947    stephh 		    fmd_case_uuid(nfmep->hdl, nfmep->fmcase));
   1326  5947    stephh 		if (ffep) {
   1327  5947    stephh 			fmd_case_setprincipal(nfmep->hdl, nfmep->fmcase, ffep);
   1328  7197    stephh 			fmd_case_add_ereport(nfmep->hdl, nfmep->fmcase, ffep);
   1329  5947    stephh 			nfmep->e0r = ffep;
   1330  5947    stephh 		}
   1331  5947    stephh 
   1332  5947    stephh 		/*
   1333  5947    stephh 		 * add the original ereports
   1334  5947    stephh 		 */
   1335  5947    stephh 		for (ep = fmep->observations; ep; ep = ep->observations) {
   1336  5947    stephh 			eventstring = ep->enode->u.event.ename->u.name.s;
   1337  5947    stephh 			ipp = ep->ipp;
   1338  5947    stephh 			out(O_ALTFP|O_NONL, "adding event [");
   1339  5947    stephh 			ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
   1340  5947    stephh 			out(O_ALTFP, " ]");
   1341  5947    stephh 			nep = itree_lookup(nfmep->eventtree, eventstring, ipp);
   1342  5947    stephh 			if (nep->count++ == 0) {
   1343  5947    stephh 				nep->observations = nfmep->observations;
   1344  5947    stephh 				nfmep->observations = nep;
   1345  5947    stephh 				serialize_observation(nfmep, eventstring, ipp);
   1346  5947    stephh 				nep->nvp = evnv_dupnvl(ep->nvp);
   1347  5947    stephh 			}
   1348  7197    stephh 			if (ep->ffep && ep->ffep != ffep)
   1349  5947    stephh 				fmd_case_add_ereport(nfmep->hdl, nfmep->fmcase,
   1350  7197    stephh 				    ep->ffep);
   1351  5947    stephh 			stats_counter_bump(nfmep->Rcount);
   1352  5947    stephh 		}
   1353  5947    stephh 
   1354  5947    stephh 		/*
   1355  5947    stephh 		 * add the serd trigger ereport
   1356  5947    stephh 		 */
   1357  5947    stephh 		if ((ep = itree_lookup(nfmep->eventtree, tripped[i].ename,
   1358  5947    stephh 		    tripped[i].ipp)) == NULL) {
   1359  5947    stephh 			/*
   1360  5947    stephh 			 * The trigger ereport is not in the instance tree. It
   1361  5947    stephh 			 * was presumably removed by prune_propagations() as
   1362  5947    stephh 			 * this combination of events is not present in the
   1363  5947    stephh 			 * rules.
   1364  5947    stephh 			 */
   1365  5947    stephh 			out(O_ALTFP, "upsets_eval: e0 not in instance tree");
   1366  7748     Tarik 			Undiag_reason = UD_VAL_BADEVENTI;
   1367  5947    stephh 			goto retry_lone_ereport;
   1368  5947    stephh 		}
   1369  5947    stephh 		out(O_ALTFP|O_NONL, "adding event [");
   1370  5947    stephh 		ipath_print(O_ALTFP|O_NONL, tripped[i].ename, tripped[i].ipp);
   1371  5947    stephh 		out(O_ALTFP, " ]");
   1372  5947    stephh 		nfmep->ecurrent = ep;
   1373  5947    stephh 		ep->nvp = NULL;
   1374  5947    stephh 		ep->count = 1;
   1375  5947    stephh 		ep->observations = nfmep->observations;
   1376  5947    stephh 		nfmep->observations = ep;
   1377  5947    stephh 
   1378  5947    stephh 		/*
   1379  5947    stephh 		 * just peek first.
   1380  5947    stephh 		 */
   1381  5947    stephh 		nfmep->peek = 1;
   1382  5947    stephh 		prev_verbose = Verbose;
   1383  5947    stephh 		if (Debug == 0)
   1384  5947    stephh 			Verbose = 0;
   1385  5947    stephh 		lut_walk(nfmep->eventtree, (lut_cb)clear_arrows, (void *)nfmep);
   1386  5947    stephh 		state = hypothesise(nfmep, nfmep->e0, nfmep->ull, &my_delay);
   1387  5947    stephh 		nfmep->peek = 0;
   1388  5947    stephh 		Verbose = prev_verbose;
   1389  5947    stephh 		if (state == FME_DISPROVED) {
   1390  5947    stephh 			out(O_ALTFP, "upsets_eval: hypothesis disproved");
   1391  7748     Tarik 			Undiag_reason = UD_VAL_UNSOLVD;
   1392  5947    stephh retry_lone_ereport:
   1393  5947    stephh 			/*
   1394  5947    stephh 			 * However the trigger ereport on its own might be
   1395  5947    stephh 			 * diagnosable, so check for that. Undo the new fme
   1396  5947    stephh 			 * and case we just created and call fme_receive_report.
   1397  5947    stephh 			 */
   1398  5947    stephh 			out(O_ALTFP|O_NONL, "[");
   1399  5947    stephh 			ipath_print(O_ALTFP|O_NONL, tripped[i].ename,
   1400  5947    stephh 			    tripped[i].ipp);
   1401  5947    stephh 			out(O_ALTFP, " retrying with just trigger ereport]");
   1402  5947    stephh 			itree_free(nfmep->eventtree);
   1403  5947    stephh 			nfmep->eventtree = NULL;
   1404  5947    stephh 			structconfig_free(nfmep->config);
   1405  5947    stephh 			nfmep->config = NULL;
   1406  5947    stephh 			destroy_fme_bufs(nfmep);
   1407  5947    stephh 			fmd_case_close(nfmep->hdl, nfmep->fmcase);
   1408  5947    stephh 			fme_receive_report(fmep->hdl, ffep,
   1409  5947    stephh 			    tripped[i].ename, tripped[i].ipp, NULL);
   1410  5947    stephh 			continue;
   1411  5947    stephh 		}
   1412  5947    stephh 
   1413  5947    stephh 		/*
   1414  5947    stephh 		 * and evaluate
   1415  5947    stephh 		 */
   1416  5947    stephh 		serialize_observation(nfmep, tripped[i].ename, tripped[i].ipp);
   1417  5947    stephh 		fme_eval(nfmep, ffep);
   1418  5947    stephh 	}
   1419     0    stevel 
   1420     0    stevel 	return (ntrip);
   1421     0    stevel }
   1422     0    stevel 
   1423     0    stevel /*
   1424     0    stevel  * fme_receive_external_report -- call when an external ereport comes in
   1425     0    stevel  *
   1426     0    stevel  * this routine just converts the relevant information from the ereport
   1427     0    stevel  * into a format used internally and passes it on to fme_receive_report().
   1428     0    stevel  */
   1429     0    stevel void
   1430     0    stevel fme_receive_external_report(fmd_hdl_t *hdl, fmd_event_t *ffep, nvlist_t *nvl,
   1431  6640       cth     const char *class)
   1432  6640       cth {
   1433  6640       cth 	struct node		*epnamenp;
   1434  6640       cth 	fmd_case_t		*fmcase;
   1435  6640       cth 	const struct ipath	*ipp;
   1436  6640       cth 
   1437  6640       cth 	class = stable(class);
   1438  6640       cth 
   1439  6640       cth 	/* Get the component path from the ereport */
   1440  6640       cth 	epnamenp = platform_getpath(nvl);
   1441  6640       cth 
   1442  6640       cth 	/* See if we ended up without a path. */
   1443     0    stevel 	if (epnamenp == NULL) {
   1444  6640       cth 		/* See if class permits silent discard on unknown component. */
   1445  6640       cth 		if (lut_lookup(Ereportenames_discard, (void *)class, NULL)) {
   1446  6640       cth 			out(O_ALTFP|O_VERB2, "Unable to map \"%s\" ereport "
   1447  6640       cth 			    "to component path, but silent discard allowed.",
   1448  6640       cth 			    class);
   1449  6640       cth 		} else {
   1450  6640       cth 			/*
   1451  6640       cth 			 * XFILE: Failure to find a component is bad unless
   1452  6640       cth 			 * 'discard_if_config_unknown=1' was specified in the
   1453  6640       cth 			 * ereport definition. Indicate undiagnosable.
   1454  6640       cth 			 */
   1455  6640       cth 			out(O_ALTFP, "XFILE: Unable to map \"%s\" ereport "
   1456  6640       cth 			    "to component path.", class);
   1457  7748     Tarik 			Undiag_reason = UD_VAL_NOPATH;
   1458  6640       cth 			fmcase = fmd_case_open(hdl, NULL);
   1459  6640       cth 			publish_undiagnosable(hdl, ffep, fmcase);
   1460  6640       cth 		}
   1461     0    stevel 		return;
   1462     0    stevel 	}
   1463     0    stevel 
   1464     0    stevel 	ipp = ipath(epnamenp);
   1465     0    stevel 	tree_free(epnamenp);
   1466  6640       cth 	fme_receive_report(hdl, ffep, class, ipp, nvl);
   1467  2120    gavinm }
   1468  2120    gavinm 
   1469  2120    gavinm /*ARGSUSED*/
   1470  2120    gavinm void
   1471  2120    gavinm fme_receive_repair_list(fmd_hdl_t *hdl, fmd_event_t *ffep, nvlist_t *nvl,
   1472  2120    gavinm     const char *eventstring)
   1473  2120    gavinm {
   1474  2120    gavinm 	char *uuid;
   1475  2120    gavinm 	nvlist_t **nva;
   1476  2120    gavinm 	uint_t nvc;
   1477  2120    gavinm 	const struct ipath *ipp;
   1478  2120    gavinm 
   1479  2120    gavinm 	if (nvlist_lookup_string(nvl, FM_SUSPECT_UUID, &uuid) != 0 ||
   1480  2120    gavinm 	    nvlist_lookup_nvlist_array(nvl, FM_SUSPECT_FAULT_LIST,
   1481  2120    gavinm 	    &nva, &nvc) != 0) {
   1482  2120    gavinm 		out(O_ALTFP, "No uuid or fault list for list.repaired event");
   1483  2120    gavinm 		return;
   1484  2120    gavinm 	}
   1485  2120    gavinm 
   1486  2120    gavinm 	out(O_ALTFP, "Processing list.repaired from case %s", uuid);
   1487  2120    gavinm 
   1488  2120    gavinm 	while (nvc-- != 0) {
   1489  2120    gavinm 		/*
   1490  4436    stephh 		 * Reset any istat or serd engine associated with this path.
   1491  2120    gavinm 		 */
   1492  2120    gavinm 		char *path;
   1493  2120    gavinm 
   1494  2120    gavinm 		if ((ipp = platform_fault2ipath(*nva++)) == NULL)
   1495  2120    gavinm 			continue;
   1496  2120    gavinm 
   1497  2120    gavinm 		path = ipath2str(NULL, ipp);
   1498  2120    gavinm 		out(O_ALTFP, "fme_receive_repair_list: resetting state for %s",
   1499  2120    gavinm 		    path);
   1500  2120    gavinm 		FREE(path);
   1501  2120    gavinm 
   1502  2120    gavinm 		lut_walk(Istats, (lut_cb)istat_counter_reset_cb, (void *)ipp);
   1503  2120    gavinm 		istat_save();
   1504  2120    gavinm 
   1505  4436    stephh 		lut_walk(SerdEngines, (lut_cb)serd_reset_cb, (void *)ipp);
   1506  4436    stephh 		serd_save();
   1507  2120    gavinm 	}
   1508     0    stevel }
   1509     0    stevel 
   1510  5204    stephh /*ARGSUSED*/
   1511  5204    stephh void
   1512  5204    stephh fme_receive_topology_change(void)
   1513  5204    stephh {
   1514  5204    stephh 	lut_walk(Istats, (lut_cb)istat_counter_topo_chg_cb, NULL);
   1515  5204    stephh 	istat_save();
   1516  5204    stephh 
   1517  5204    stephh 	lut_walk(SerdEngines, (lut_cb)serd_topo_chg_cb, NULL);
   1518  5204    stephh 	serd_save();
   1519  5204    stephh }
   1520  5204    stephh 
   1521  1414     cindi static int mark_arrows(struct fme *fmep, struct event *ep, int mark,
   1522  1865  dilpreet     unsigned long long at_latest_by, unsigned long long *pdelay, int keep);
   1523  1414     cindi 
   1524  1414     cindi /* ARGSUSED */
   1525  1414     cindi static void
   1526  1414     cindi clear_arrows(struct event *ep, struct event *ep2, struct fme *fmep)
   1527  1414     cindi {
   1528  1414     cindi 	struct bubble *bp;
   1529  1414     cindi 	struct arrowlist *ap;
   1530  1414     cindi 
   1531  1414     cindi 	ep->cached_state = 0;
   1532  1865  dilpreet 	ep->keep_in_tree = 0;
   1533  1414     cindi 	for (bp = itree_next_bubble(ep, NULL); bp;
   1534  1414     cindi 	    bp = itree_next_bubble(ep, bp)) {
   1535  1414     cindi 		if (bp->t != B_FROM)
   1536  1414     cindi 			continue;
   1537  1414     cindi 		bp->mark = 0;
   1538  1414     cindi 		for (ap = itree_next_arrow(bp, NULL); ap;
   1539  1414     cindi 		    ap = itree_next_arrow(bp, ap))
   1540  1414     cindi 			ap->arrowp->mark = 0;
   1541  1414     cindi 	}
   1542  4436    stephh }
   1543  4436    stephh 
   1544  4436    stephh static void
   1545     0    stevel fme_receive_report(fmd_hdl_t *hdl, fmd_event_t *ffep,
   1546     0    stevel     const char *eventstring, const struct ipath *ipp, nvlist_t *nvl)
   1547     0    stevel {
   1548     0    stevel 	struct event *ep;
   1549     0    stevel 	struct fme *fmep = NULL;
   1550   814     jrutt 	struct fme *ofmep = NULL;
   1551   814     jrutt 	struct fme *cfmep, *svfmep;
   1552     0    stevel 	int matched = 0;
   1553   814     jrutt 	nvlist_t *defect;
   1554  4436    stephh 	fmd_case_t *fmcase;
   1555     0    stevel 
   1556     0    stevel 	out(O_ALTFP|O_NONL, "fme_receive_report: ");
   1557     0    stevel 	ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
   1558     0    stevel 	out(O_ALTFP|O_STAMP, NULL);
   1559     0    stevel 
   1560     0    stevel 	/* decide which FME it goes to */
   1561     0    stevel 	for (fmep = FMElist; fmep; fmep = fmep->next) {
   1562     0    stevel 		int prev_verbose;
   1563     0    stevel 		unsigned long long my_delay = TIMEVAL_EVENTUALLY;
   1564     0    stevel 		enum fme_state state;
   1565  1414     cindi 		nvlist_t *pre_peek_nvp = NULL;
   1566   814     jrutt 
   1567   814     jrutt 		if (fmep->overflow) {
   1568   814     jrutt 			if (!(fmd_case_closed(fmep->hdl, fmep->fmcase)))
   1569   814     jrutt 				ofmep = fmep;
   1570   814     jrutt 
   1571   814     jrutt 			continue;
   1572   814     jrutt 		}
   1573     0    stevel 
   1574  2318    stephh 		/*
   1575  2318    stephh 		 * ignore solved or closed cases
   1576  2318    stephh 		 */
   1577  2318    stephh 		if (fmep->posted_suspects ||
   1578  2318    stephh 		    fmd_case_solved(fmep->hdl, fmep->fmcase) ||
   1579  2318    stephh 		    fmd_case_closed(fmep->hdl, fmep->fmcase))
   1580  2318    stephh 			continue;
   1581  2318    stephh 
   1582     0    stevel 		/* look up event in event tree for this FME */
   1583     0    stevel 		if ((ep = itree_lookup(fmep->eventtree,
   1584     0    stevel 		    eventstring, ipp)) == NULL)
   1585     0    stevel 			continue;
   1586     0    stevel 
   1587     0    stevel 		/* note observation */
   1588     0    stevel 		fmep->ecurrent = ep;
   1589     0    stevel 		if (ep->count++ == 0) {
   1590     0    stevel 			/* link it into list of observations seen */
   1591     0    stevel 			ep->observations = fmep->observations;
   1592     0    stevel 			fmep->observations = ep;
   1593     0    stevel 			ep->nvp = evnv_dupnvl(nvl);
   1594  1414     cindi 		} else {
   1595  1414     cindi 			/* use new payload values for peek */
   1596  1414     cindi 			pre_peek_nvp = ep->nvp;
   1597  1414     cindi 			ep->nvp = evnv_dupnvl(nvl);
   1598     0    stevel 		}
   1599     0    stevel 
   1600     0    stevel 		/* tell hypothesise() not to mess with suspect list */
   1601     0    stevel 		fmep->peek = 1;
   1602     0    stevel 
   1603     0    stevel 		/* don't want this to be verbose (unless Debug is set) */
   1604     0    stevel 		prev_verbose = Verbose;
   1605     0    stevel 		if (Debug == 0)
   1606     0    stevel 			Verbose = 0;
   1607     0    stevel 
   1608  1414     cindi 		lut_walk(fmep->eventtree, (lut_cb)clear_arrows, (void *)fmep);
   1609  1414     cindi 		state = hypothesise(fmep, fmep->e0, fmep->ull, &my_delay);
   1610     0    stevel 
   1611     0    stevel 		fmep->peek = 0;
   1612     0    stevel 
   1613     0    stevel 		/* put verbose flag back */
   1614     0    stevel 		Verbose = prev_verbose;
   1615     0    stevel 
   1616     0    stevel 		if (state != FME_DISPROVED) {
   1617     0    stevel 			/* found an FME that explains the ereport */
   1618     0    stevel 			matched++;
   1619     0    stevel 			out(O_ALTFP|O_NONL, "[");
   1620     0    stevel 			ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
   1621     0    stevel 			out(O_ALTFP, " explained by FME%d]", fmep->id);
   1622  1414     cindi 
   1623  1414     cindi 			if (pre_peek_nvp)
   1624  1414     cindi 				nvlist_free(pre_peek_nvp);
   1625     0    stevel 
   1626     0    stevel 			if (ep->count == 1)
   1627     0    stevel 				serialize_observation(fmep, eventstring, ipp);
   1628     0    stevel 
   1629  7197    stephh 			if (ffep) {
   1630     0    stevel 				fmd_case_add_ereport(hdl, fmep->fmcase, ffep);
   1631  7197    stephh 				ep->ffep = ffep;
   1632  7197    stephh 			}
   1633     0    stevel 
   1634     0    stevel 			stats_counter_bump(fmep->Rcount);
   1635     0    stevel 
   1636     0    stevel 			/* re-eval FME */
   1637     0    stevel 			fme_eval(fmep, ffep);
   1638     0    stevel 		} else {
   1639     0    stevel 
   1640     0    stevel 			/* not a match, undo noting of observation */
   1641     0    stevel 			fmep->ecurrent = NULL;
   1642     0    stevel 			if (--ep->count == 0) {
   1643     0    stevel 				/* unlink it from observations */
   1644     0    stevel 				fmep->observations = ep->observations;
   1645     0    stevel 				ep->observations = NULL;
   1646     0    stevel 				nvlist_free(ep->nvp);
   1647     0    stevel 				ep->nvp = NULL;
   1648  1414     cindi 			} else {
   1649  1414     cindi 				nvlist_free(ep->nvp);
   1650  1414     cindi 				ep->nvp = pre_peek_nvp;
   1651     0    stevel 			}
   1652     0    stevel 		}
   1653     0    stevel 	}
   1654     0    stevel 
   1655     0    stevel 	if (matched)
   1656     0    stevel 		return;	/* explained by at least one existing FME */
   1657     0    stevel 
   1658     0    stevel 	/* clean up closed fmes */
   1659   814     jrutt 	cfmep = ClosedFMEs;
   1660   814     jrutt 	while (cfmep != NULL) {
   1661   814     jrutt 		svfmep = cfmep->next;
   1662   814     jrutt 		destroy_fme(cfmep);
   1663   814     jrutt 		cfmep = svfmep;
   1664     0    stevel 	}
   1665     0    stevel 	ClosedFMEs = NULL;
   1666  4436    stephh 	prune_propagations(eventstring, ipp);
   1667   814     jrutt 
   1668   814     jrutt 	if (ofmep) {
   1669   814     jrutt 		out(O_ALTFP|O_NONL, "[");
   1670   814     jrutt 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
   1671   814     jrutt 		out(O_ALTFP, " ADDING TO OVERFLOW FME]");
   1672   814     jrutt 		if (ffep)
   1673   814     jrutt 			fmd_case_add_ereport(hdl, ofmep->fmcase, ffep);
   1674   814     jrutt 
   1675   814     jrutt 		return;
   1676   814     jrutt 
   1677   814     jrutt 	} else if (Max_fme && (Open_fme_count >= Max_fme)) {
   1678   814     jrutt 		out(O_ALTFP|O_NONL, "[");
   1679   814     jrutt 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
   1680   814     jrutt 		out(O_ALTFP, " MAX OPEN FME REACHED]");
   1681  4436    stephh 
   1682  4436    stephh 		fmcase = fmd_case_open(hdl, NULL);
   1683  4436    stephh 
   1684   814     jrutt 		/* Create overflow fme */
   1685  4436    stephh 		if ((fmep = newfme(eventstring, ipp, hdl, fmcase)) == NULL) {
   1686   814     jrutt 			out(O_ALTFP|O_NONL, "[");
   1687   814     jrutt 			ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
   1688   814     jrutt 			out(O_ALTFP, " CANNOT OPEN OVERFLOW FME]");
   1689  4436    stephh 			publish_undiagnosable(hdl, ffep, fmcase);
   1690   814     jrutt 			return;
   1691   814     jrutt 		}
   1692   814     jrutt 
   1693   814     jrutt 		Open_fme_count++;
   1694   814     jrutt 
   1695   814     jrutt 		init_fme_bufs(fmep);
   1696   814     jrutt 		fmep->overflow = B_TRUE;
   1697   814     jrutt 
   1698   814     jrutt 		if (ffep)
   1699   814     jrutt 			fmd_case_add_ereport(hdl, fmep->fmcase, ffep);
   1700   814     jrutt 
   1701  7748     Tarik 		Undiag_reason = UD_VAL_MAXFME;
   1702  7748     Tarik 		defect = fmd_nvl_create_fault(hdl,
   1703  7748     Tarik 		    undiag_2defect_str(Undiag_reason), 100, NULL, NULL, NULL);
   1704  7748     Tarik 		(void) nvlist_add_string(defect, UNDIAG_REASON,
   1705  7748     Tarik 		    undiag_2reason_str(Undiag_reason));
   1706   814     jrutt 		fmd_case_add_suspect(hdl, fmep->fmcase, defect);
   1707   814     jrutt 		fmd_case_solve(hdl, fmep->fmcase);
   1708  7748     Tarik 		Undiag_reason = UD_VAL_UNKNOWN;
   1709   814     jrutt 		return;
   1710   814     jrutt 	}
   1711     0    stevel 
   1712  4436    stephh 	/* open a case */
   1713  4436    stephh 	fmcase = fmd_case_open(hdl, NULL);
   1714  4436    stephh 
   1715     0    stevel 	/* start a new FME */
   1716  4436    stephh 	if ((fmep = newfme(eventstring, ipp, hdl, fmcase)) == NULL) {
   1717     0    stevel 		out(O_ALTFP|O_NONL, "[");
   1718     0    stevel 		ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
   1719     0    stevel 		out(O_ALTFP, " CANNOT DIAGNOSE]");
   1720  4436    stephh 		publish_undiagnosable(hdl, ffep, fmcase);
   1721     0    stevel 		return;
   1722     0    stevel 	}
   1723   814     jrutt 
   1724   814     jrutt 	Open_fme_count++;
   1725     0    stevel 
   1726     0    stevel 	init_fme_bufs(fmep);
   1727     0    stevel 
   1728     0    stevel 	out(O_ALTFP|O_NONL, "[");
   1729     0    stevel 	ipath_print(O_ALTFP|O_NONL, eventstring, ipp);
   1730     0    stevel 	out(O_ALTFP, " created FME%d, case %s]", fmep->id,
   1731     0    stevel 	    fmd_case_uuid(hdl, fmep->fmcase));
   1732     0    stevel 
   1733     0    stevel 	ep = fmep->e0;
   1734     0    stevel 	ASSERT(ep != NULL);
   1735     0    stevel 
   1736     0    stevel 	/* note observation */
   1737     0    stevel 	fmep->ecurrent = ep;
   1738     0    stevel 	if (ep->count++ == 0) {
   1739     0    stevel 		/* link it into list of observations seen */
   1740     0    stevel 		ep->observations = fmep->observations;
   1741     0    stevel 		fmep->observations = ep;
   1742     0    stevel 		ep->nvp = evnv_dupnvl(nvl);
   1743     0    stevel 		serialize_observation(fmep, eventstring, ipp);
   1744  1414     cindi 	} else {
   1745  1414     cindi 		/* new payload overrides any previous */
   1746  1414     cindi 		nvlist_free(ep->nvp);
   1747  1414     cindi 		ep->nvp = evnv_dupnvl(nvl);
   1748     0    stevel 	}
   1749     0    stevel 
   1750     0    stevel 	stats_counter_bump(fmep->Rcount);
   1751     0    stevel 
   1752     0    stevel 	if (ffep) {
   1753     0    stevel 		fmd_case_add_ereport(hdl, fmep->fmcase, ffep);
   1754     0    stevel 		fmd_case_setprincipal(hdl, fmep->fmcase, ffep);
   1755     0    stevel 		fmep->e0r = ffep;
   1756  7197    stephh 		ep->ffep = ffep;
   1757     0    stevel 	}
   1758     0    stevel 
   1759     0    stevel 	/* give the diagnosis algorithm a shot at the new FME state */
   1760     0    stevel 	fme_eval(fmep, ffep);
   1761     0    stevel }
   1762     0    stevel 
   1763     0    stevel void
   1764     0    stevel fme_status(int flags)
   1765     0    stevel {
   1766     0    stevel 	struct fme *fmep;
   1767     0    stevel 
   1768     0    stevel 	if (FMElist == NULL) {
   1769     0    stevel 		out(flags, "No fault management exercises underway.");
   1770     0    stevel 		return;
   1771     0    stevel 	}
   1772     0    stevel 
   1773     0    stevel 	for (fmep = FMElist; fmep; fmep = fmep->next)
   1774     0    stevel 		fme_print(flags, fmep);
   1775     0    stevel }
   1776     0    stevel 
   1777     0    stevel /*
   1778     0    stevel  * "indent" routines used mostly for nicely formatted debug output, but also
   1779     0    stevel  * for sanity checking for infinite recursion bugs.
   1780     0    stevel  */
   1781     0    stevel 
   1782     0    stevel #define	MAX_INDENT 1024
   1783     0    stevel static const char *indent_s[MAX_INDENT];
   1784     0    stevel static int current_indent;
   1785     0    stevel 
   1786     0    stevel static void
   1787     0    stevel indent_push(const char *s)
   1788     0    stevel {
   1789     0    stevel 	if (current_indent < MAX_INDENT)
   1790     0    stevel 		indent_s[current_indent++] = s;
   1791     0    stevel 	else
   1792     0    stevel 		out(O_DIE, "unexpected recursion depth (%d)", current_indent);
   1793     0    stevel }
   1794     0    stevel 
   1795     0    stevel static void
   1796     0    stevel indent_set(const char *s)
   1797     0    stevel {
   1798     0    stevel 	current_indent = 0;
   1799     0    stevel 	indent_push(s);
   1800     0    stevel }
   1801     0    stevel 
   1802     0    stevel static void
   1803     0    stevel indent_pop(void)
   1804     0    stevel {
   1805     0    stevel 	if (current_indent > 0)
   1806     0    stevel 		current_indent--;
   1807     0    stevel 	else
   1808     0    stevel 		out(O_DIE, "recursion underflow");
   1809     0    stevel }
   1810     0    stevel 
   1811     0    stevel static void
   1812     0    stevel indent(void)
   1813     0    stevel {
   1814     0    stevel 	int i;
   1815     0    stevel 	if (!Verbose)
   1816     0    stevel 		return;
   1817     0    stevel 	for (i = 0; i < current_indent; i++)
   1818     0    stevel 		out(O_ALTFP|O_VERB|O_NONL, indent_s[i]);
   1819     0    stevel }
   1820     0    stevel 
   1821     0    stevel #define	SLNEW		1
   1822     0    stevel #define	SLCHANGED	2
   1823     0    stevel #define	SLWAIT		3
   1824     0    stevel #define	SLDISPROVED	4
   1825     0    stevel 
   1826     0    stevel static void
   1827     0    stevel print_suspects(int circumstance, struct fme *fmep)
   1828     0    stevel {
   1829     0    stevel 	struct event *ep;
   1830     0    stevel 
   1831     0    stevel 	out(O_ALTFP|O_NONL, "[");
   1832     0    stevel 	if (circumstance == SLCHANGED) {
   1833     0    stevel 		out(O_ALTFP|O_NONL, "FME%d diagnosis changed. state: %s, "
   1834     0    stevel 		    "suspect list:", fmep->id, fme_state2str(fmep->state));
   1835     0    stevel 	} else if (circumstance == SLWAIT) {
   1836  4436    stephh 		out(O_ALTFP|O_NONL, "FME%d set wait timer %ld ", fmep->id,
   1837  4436    stephh 		    fmep->timer);
   1838     0    stevel 		ptree_timeval(O_ALTFP|O_NONL, &fmep->wull);
   1839     0    stevel 	} else if (circumstance == SLDISPROVED) {
   1840     0    stevel 		out(O_ALTFP|O_NONL, "FME%d DIAGNOSIS UNKNOWN", fmep->id);
   1841     0    stevel 	} else {
   1842     0    stevel 		out(O_ALTFP|O_NONL, "FME%d DIAGNOSIS PRODUCED:", fmep->id);
   1843     0    stevel 	}
   1844     0    stevel 
   1845     0    stevel 	if (circumstance == SLWAIT || circumstance == SLDISPROVED) {
   1846     0    stevel 		out(O_ALTFP, "]");
   1847     0    stevel 		return;
   1848     0    stevel 	}
   1849     0    stevel 
   1850     0    stevel 	for (ep = fmep->suspects; ep; ep = ep->suspects) {
   1851     0    stevel 		out(O_ALTFP|O_NONL, " ");
   1852     0    stevel 		itree_pevent_brief(O_ALTFP|O_NONL, ep);
   1853     0    stevel 	}
   1854     0    stevel 	out(O_ALTFP, "]");
   1855     0    stevel }
   1856     0    stevel 
   1857     0    stevel static struct node *
   1858     0    stevel eventprop_lookup(struct event *ep, const char *propname)
   1859     0    stevel {
   1860     0    stevel 	return (lut_lookup(ep->props, (void *)propname, NULL));
   1861     0    stevel }
   1862     0    stevel 
   1863     0    stevel #define	MAXDIGITIDX	23
   1864     0    stevel static char numbuf[MAXDIGITIDX + 1];
   1865     0    stevel 
   1866     0    stevel static int
   1867     0    stevel node2uint(struct node *n, uint_t *valp)
   1868     0    stevel {
   1869     0    stevel 	struct evalue value;
   1870     0    stevel 	struct lut *globals = NULL;
   1871     0    stevel 
   1872     0    stevel 	if (n == NULL)
   1873     0    stevel 		return (1);
   1874     0    stevel 
   1875     0    stevel 	/*
   1876     0    stevel 	 * check value.v since we are being asked to convert an unsigned
   1877     0    stevel 	 * long long int to an unsigned int
   1878     0    stevel 	 */
   1879     0    stevel 	if (! eval_expr(n, NULL, NULL, &globals, NULL, NULL, 0, &value) ||
   1880     0    stevel 	    value.t != UINT64 || value.v > (1ULL << 32))
   1881     0    stevel 		return (1);
   1882     0    stevel 
   1883     0    stevel 	*valp = (uint_t)value.v;
   1884     0    stevel 
   1885     0    stevel 	return (0);
   1886     0    stevel }
   1887     0    stevel 
   1888     0    stevel static nvlist_t *
   1889     0    stevel node2fmri(struct node *n)
   1890     0    stevel {
   1891     0    stevel 	nvlist_t **pa, *f, *p;
   1892     0    stevel 	struct node *nc;
   1893     0    stevel 	uint_t depth = 0;
   1894     0    stevel 	char *numstr, *nullbyte;
   1895     0    stevel 	char *failure;
   1896     0    stevel 	int err, i;
   1897     0    stevel 
   1898     0    stevel 	/* XXX do we need to be able to handle a non-T_NAME node? */
   1899     0    stevel 	if (n == NULL || n->t != T_NAME)
   1900     0    stevel 		return (NULL);
   1901     0    stevel 
   1902     0    stevel 	for (nc = n; nc != NULL; nc = nc->u.name.next) {
   1903     0    stevel 		if (nc->u.name.child == NULL || nc->u.name.child->t != T_NUM)
   1904     0    stevel 			break;
   1905     0    stevel 		depth++;
   1906     0    stevel 	}
   1907     0    stevel 
   1908     0    stevel 	if (nc != NULL) {
   1909     0    stevel 		/* We bailed early, something went wrong */
   1910     0    stevel 		return (NULL);
   1911     0    stevel 	}
   1912     0    stevel 
   1913     0    stevel 	if ((err = nvlist_xalloc(&f, NV_UNIQUE_NAME, &Eft_nv_hdl)) != 0)
   1914     0    stevel 		out(O_DIE|O_SYS, "alloc of fmri nvl failed");
   1915     0    stevel 	pa = alloca(depth * sizeof (nvlist_t *));
   1916     0    stevel 	for (i = 0; i < depth; i++)
   1917     0    stevel 		pa[i] = NULL;
   1918     0    stevel 
   1919     0    stevel 	err = nvlist_add_string(f, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC);
   1920     0    stevel 	err |= nvlist_add_uint8(f, FM_VERSION, FM_HC_SCHEME_VERSION);
   1921     0    stevel 	err |= nvlist_add_string(f, FM_FMRI_HC_ROOT, "");
   1922     0    stevel 	err |= nvlist_add_uint32(f, FM_FMRI_HC_LIST_SZ, depth);
   1923     0    stevel 	if (err != 0) {
   1924     0    stevel 		failure = "basic construction of FMRI failed";
   1925     0    stevel 		goto boom;
   1926     0    stevel 	}
   1927     0    stevel 
   1928     0    stevel 	numbuf[MAXDIGITIDX] = '\0';
   1929     0    stevel 	nullbyte = &numbuf[MAXDIGITIDX];
   1930     0    stevel 	i = 0;
   1931     0    stevel 
   1932     0    stevel 	for (nc = n; nc != NULL; nc = nc->u.name.next) {
   1933     0    stevel 		err = nvlist_xalloc(&p, NV_UNIQUE_NAME, &Eft_nv_hdl);
   1934     0    stevel 		if (err != 0) {
   1935     0    stevel 			failure = "alloc of an hc-pair failed";
   1936     0    stevel 			goto boom;
   1937     0    stevel 		}
   1938     0    stevel 		err = nvlist_add_string(p, FM_FMRI_HC_NAME, nc->u.name.s);
   1939     0    stevel 		numstr = ulltostr(nc->u.name.child->u.ull, nullbyte);
   1940     0    stevel 		err |= nvlist_add_string(p, FM_FMRI_HC_ID, numstr);
   1941     0    stevel 		if (err != 0) {
   1942     0    stevel 			failure = "construction of an hc-pair failed";
   1943     0    stevel 			goto boom;
   1944     0    stevel 		}
   1945     0    stevel 		pa[i++] = p;
   1946     0    stevel 	}
   1947     0    stevel 
   1948     0    stevel 	err = nvlist_add_nvlist_array(f, FM_FMRI_HC_LIST, pa, depth);
   1949     0    stevel 	if (err == 0) {
   1950     0    stevel 		for (i = 0; i < depth; i++)
   1951     0    stevel 			if (pa[i] != NULL)
   1952     0    stevel 				nvlist_free(pa[i]);
   1953     0    stevel 		return (f);
   1954     0    stevel 	}
   1955     0    stevel 	failure = "addition of hc-pair array to FMRI failed";
   1956     0    stevel 
   1957     0    stevel boom:
   1958     0    stevel 	for (i = 0; i < depth; i++)
   1959     0    stevel 		if (pa[i] != NULL)
   1960     0    stevel 			nvlist_free(pa[i]);
   1961     0    stevel 	nvlist_free(f);
   1962     0    stevel 	out(O_DIE, "%s", failure);
   1963     0    stevel 	/*NOTREACHED*/
   1964  1717  wesolows 	return (NULL);
   1965     0    stevel }
   1966     0    stevel 
   1967  5204    stephh /* an ipath cache entry is an array of these, with s==NULL at the end */
   1968  5204    stephh struct ipath {
   1969  5204    stephh 	const char *s;	/* component name (in stable) */
   1970  5204    stephh 	int i;		/* instance number */
   1971  5204    stephh };
   1972  5204    stephh 
   1973  5204    stephh static nvlist_t *
   1974  5204    stephh ipath2fmri(struct ipath *ipath)
   1975  5204    stephh {
   1976  5204    stephh 	nvlist_t **pa, *f, *p;
   1977  5204    stephh 	uint_t depth = 0;
   1978  5204    stephh 	char *numstr, *nullbyte;
   1979  5204    stephh 	char *failure;
   1980  5204    stephh 	int err, i;
   1981  5204    stephh 	struct ipath *ipp;
   1982  5204    stephh 
   1983  5204    stephh 	for (ipp = ipath; ipp->s != NULL; ipp++)
   1984  5204    stephh 		depth++;
   1985  5204    stephh 
   1986  5204    stephh 	if ((err = nvlist_xalloc(&f, NV_UNIQUE_NAME, &Eft_nv_hdl)) != 0)
   1987  5204    stephh 		out(O_DIE|O_SYS, "alloc of fmri nvl failed");
   1988  5204    stephh 	pa = alloca(depth * sizeof (nvlist_t *));
   1989  5204    stephh 	for (i = 0; i < depth; i++)
   1990  5204    stephh 		pa[i] = NULL;
   1991  5204    stephh 
   1992  5204    stephh 	err = nvlist_add_string(f, FM_FMRI_SCHEME, FM_FMRI_SCHEME_HC);
   1993  5204    stephh 	err |= nvlist_add_uint8(f, FM_VERSION, FM_HC_SCHEME_VERSION);
   1994  5204    stephh 	err |= nvlist_add_string(f, FM_FMRI_HC_ROOT, "");
   1995  5204    stephh 	err |= nvlist_add_uint32(f, FM_FMRI_HC_LIST_SZ, depth);
   1996  5204    stephh 	if (err != 0) {
   1997  5204    stephh 		failure = "basic construction of FMRI failed";
   1998  5204    stephh 		goto boom;
   1999  5204    stephh 	}
   2000  5204    stephh 
   2001  5204    stephh 	numbuf[MAXDIGITIDX] = '\0';
   2002  5204    stephh 	nullbyte = &numbuf[MAXDIGITIDX];
   2003  5204    stephh 	i = 0;
   2004  5204    stephh 
   2005  5204    stephh 	for (ipp = ipath; ipp->s != NULL; ipp++) {
   2006  5204    stephh 		err = nvlist_xalloc(&p, NV_UNIQUE_NAME, &Eft_nv_hdl);
   2007  5204    stephh 		if (err != 0) {
   2008  5204    stephh 			failure = "alloc of an hc-pair failed";
   2009  5204    stephh 			goto boom;
   2010  5204    stephh 		}
   2011  5204    stephh 		err = nvlist_add_string(p, FM_FMRI_HC_NAME, ipp->s);
   2012  5204    stephh 		numstr = ulltostr(ipp->i, nullbyte);
   2013  5204    stephh 		err |= nvlist_add_string(p, FM_FMRI_HC_ID, numstr);
   2014  5204    stephh 		if (err != 0) {
   2015  5204    stephh 			failure = "construction of an hc-pair failed";
   2016  5204    stephh 			goto boom;
   2017  5204    stephh 		}
   2018  5204    stephh 		pa[i++] = p;
   2019  5204    stephh 	}
   2020  5204    stephh 
   2021  5204    stephh 	err = nvlist_add_nvlist_array(f, FM_FMRI_HC_LIST, pa, depth);
   2022  5204    stephh 	if (err == 0) {
   2023  5204    stephh 		for (i = 0; i < depth; i++)
   2024  5204    stephh 			if (pa[i] != NULL)
   2025  5204    stephh 				nvlist_free(pa[i]);
   2026  5204    stephh 		return (f);
   2027  5204    stephh 	}
   2028  5204    stephh 	failure = "addition of hc-pair array to FMRI failed";
   2029  5204    stephh 
   2030  5204    stephh boom:
   2031  5204    stephh 	for (i = 0; i < depth; i++)
   2032  5204    stephh 		if (pa[i] != NULL)
   2033  5204    stephh 			nvlist_free(pa[i]);
   2034  5204    stephh 	nvlist_free(f);
   2035  5204    stephh 	out(O_DIE, "%s", failure);
   2036  5204    stephh 	/*NOTREACHED*/
   2037  5204    stephh 	return (NULL);
   2038  5204    stephh }
   2039  5204    stephh 
   2040     0    stevel static uint8_t
   2041     0    stevel percentof(uint_t part, uint_t whole)
   2042     0    stevel {
   2043     0    stevel 	unsigned long long p = part * 1000;
   2044     0    stevel 
   2045     0    stevel 	return ((p / whole / 10) + (((p / whole % 10) >= 5) ? 1 : 0));
   2046     0    stevel }
   2047     0    stevel 
   2048  1717  wesolows struct rsl {
   2049     0    stevel 	struct event *suspect;
   2050     0    stevel 	nvlist_t *asru;
   2051     0    stevel 	nvlist_t *fru;
   2052     0    stevel 	nvlist_t *rsrc;
   2053     0    stevel };
   2054     0    stevel 
   2055  7197    stephh static void publish_suspects(struct fme *fmep, struct rsl *srl);
   2056  7197    stephh 
   2057     0    stevel /*
   2058     0    stevel  *  rslfree -- free internal members of struct rsl not expected to be
   2059     0    stevel  *	freed elsewhere.
   2060     0    stevel  */
   2061     0    stevel static void
   2062     0    stevel rslfree(struct rsl *freeme)
   2063     0    stevel {
   2064     0    stevel 	if (freeme->asru != NULL)
   2065     0    stevel 		nvlist_free(freeme->asru);
   2066     0    stevel 	if (freeme->fru != NULL)
   2067     0    stevel 		nvlist_free(freeme->fru);
   2068     0    stevel 	if (freeme->rsrc != NULL && freeme->rsrc != freeme->asru)
   2069     0    stevel 		nvlist_free(freeme->rsrc);
   2070     0    stevel }
   2071     0    stevel 
   2072     0    stevel /*
   2073     0    stevel  *  rslcmp -- compare two rsl structures.  Use the following
   2074     0    stevel  *	comparisons to establish cardinality:
   2075     0    stevel  *
   2076     0    stevel  *	1. Name of the suspect's class. (simple strcmp)
   2077     0    stevel  *	2. Name of the suspect's ASRU. (trickier, since nvlist)
   2078     0    stevel  *
   2079     0    stevel  */
   2080     0    stevel static int
   2081     0    stevel rslcmp(const void *a, const void *b)
   2082     0    stevel {
   2083     0    stevel 	struct rsl *r1 = (struct rsl *)a;
   2084     0    stevel 	struct rsl *r2 = (struct rsl *)b;
   2085     0    stevel 	int rv;
   2086     0    stevel 
   2087     0    stevel 	rv = strcmp(r1->suspect->enode->u.event.ename->u.name.s,
   2088     0    stevel 	    r2->suspect->enode->u.event.ename->u.name.s);
   2089     0    stevel 	if (rv != 0)
   2090     0    stevel 		return (rv);
   2091     0    stevel 
   2092  7197    stephh 	if (r1->rsrc == NULL && r2->rsrc == NULL)
   2093  7197    stephh 		return (0);
   2094  7197    stephh 	if (r1->rsrc == NULL)
   2095     0    stevel 		return (-1);
   2096  7197    stephh 	if (r2->rsrc == NULL)
   2097  7197    stephh 		return (1);
   2098  7197    stephh 	return (evnv_cmpnvl(r1->rsrc, r2->rsrc, 0));
   2099     0    stevel }
   2100     0    stevel 
   2101     0    stevel /*
   2102     0    stevel  * get_resources -- for a given suspect, determine what ASRU, FRU and
   2103     0    stevel  *     RSRC nvlists should be advertised in the final suspect list.
   2104     0    stevel  */
   2105     0    stevel void
   2106     0    stevel get_resources(struct event *sp, struct rsl *rsrcs, struct config *croot)
   2107     0    stevel {
   2108     0    stevel 	struct node *asrudef, *frudef;
   2109     0    stevel 	nvlist_t *asru, *fru;
   2110     0    stevel 	nvlist_t *rsrc = NULL;
   2111     0    stevel 	char *pathstr;
   2112     0    stevel 
   2113     0    stevel 	/*
   2114     0    stevel 	 * First find any ASRU and/or FRU defined in the
   2115     0    stevel 	 * initial fault tree.
   2116     0    stevel 	 */
   2117     0    stevel 	asrudef = eventprop_lookup(sp, L_ASRU);
   2118     0    stevel 	frudef = eventprop_lookup(sp, L_FRU);
   2119     0    stevel 
   2120     0    stevel 	/*
   2121     0    stevel 	 * Create FMRIs based on those definitions
   2122     0    stevel 	 */
   2123     0    stevel 	asru = node2fmri(asrudef);
   2124     0    stevel 	fru = node2fmri(frudef);
   2125     0    stevel 	pathstr = ipath2str(NULL, sp->ipp);
   2126     0    stevel 
   2127     0    stevel 	/*
   2128  7197    stephh 	 *  Allow for platform translations of the FMRIs
   2129     0    stevel 	 */
   2130     0    stevel 	platform_units_translate(is_defect(sp->t), croot, &asru, &fru, &rsrc,
   2131     0    stevel 	    pathstr);
   2132     0    stevel 
   2133     0    stevel 	FREE(pathstr);
   2134     0    stevel 	rsrcs->suspect = sp;
   2135     0    stevel 	rsrcs->asru = asru;
   2136     0    stevel 	rsrcs->fru = fru;
   2137     0    stevel 	rsrcs->rsrc = rsrc;
   2138     0    stevel }
   2139     0    stevel 
   2140     0    stevel /*
   2141     0    stevel  * trim_suspects -- prior to publishing, we may need to remove some
   2142     0    stevel  *    suspects from the list.  If we're auto-closing upsets, we don't
   2143     0    stevel  *    want any of those in the published list.  If the ASRUs for multiple
   2144     0    stevel  *    defects resolve to the same ASRU (driver) we only want to publish
   2145     0    stevel  *    that as a single suspect.
   2146     0    stevel  */
   2147  7197    stephh static int
   2148  7197    stephh trim_suspects(struct fme *fmep, struct rsl *begin, struct rsl *begin2,
   2149  8245   Stephen     fmd_event_t *ffep)
   2150  7197    stephh {
   2151  7197    stephh 	struct event *ep;
   2152  7197    stephh 	struct rsl *rp = begin;
   2153  7197    stephh 	struct rsl *rp2 = begin2;
   2154  7197    stephh 	int mess_zero_count = 0;
   2155  7197    stephh 	int serd_rval;
   2156  7197    stephh 	uint_t messval;
   2157  7197    stephh 
   2158  7197    stephh 	/* remove any unwanted upsets and populate our array */
   2159     0    stevel 	for (ep = fmep->psuspects; ep; ep = ep->psuspects) {
   2160  7197    stephh 		if (is_upset(ep->t))
   2161  7197    stephh 			continue;
   2162  7197    stephh 		serd_rval = serd_eval(fmep, fmep->hdl, ffep, fmep->fmcase, ep,
   2163  7197    stephh 		    NULL, NULL);
   2164  7197    stephh 		if (serd_rval == 0)
   2165  7197    stephh 			continue;
   2166  7197    stephh 		if (node2uint(eventprop_lookup(ep, L_message),
   2167  7197    stephh 		    &messval) == 0 && messval == 0) {
   2168  7197    stephh 			get_resources(ep, rp2, fmep->config);
   2169  7197    stephh 			rp2++;
   2170  7197    stephh 			mess_zero_count++;
   2171  7197    stephh 		} else {
   2172  7197    stephh 			get_resources(ep, rp, fmep->config);
   2173  7197    stephh 			rp++;
   2174  7197    stephh 			fmep->nsuspects++;
   2175  7197    stephh 		}
   2176  7197    stephh 	}
   2177  7197    stephh 	return (mess_zero_count);
   2178     0    stevel }
   2179     0    stevel 
   2180  1414     cindi /*
   2181  1414     cindi  * addpayloadprop -- add a payload prop to a problem
   2182  1414     cindi  */
   2183  1414     cindi static void
   2184  1414     cindi addpayloadprop(const char *lhs, struct evalue *rhs, nvlist_t *fault)
   2185  1414     cindi {
   2186  7197    stephh 	nvlist_t *rsrc, *hcs;
   2187  7197    stephh 
   2188  1414     cindi 	ASSERT(fault != NULL);
   2189  1414     cindi 	ASSERT(lhs != NULL);
   2190  1414     cindi 	ASSERT(rhs != NULL);
   2191  7197    stephh 
   2192  7197    stephh 	if (nvlist_lookup_nvlist(fault, FM_FAULT_RESOURCE, &rsrc) != 0)
   2193  7197    stephh 		out(O_DIE, "cannot add payloadprop \"%s\" to fault", lhs);
   2194  7197    stephh 
   2195  7197    stephh 	if (nvlist_lookup_nvlist(rsrc, FM_FMRI_HC_SPECIFIC, &hcs) != 0) {
   2196  7197    stephh 		out(O_ALTFP|O_VERB2, "addpayloadprop: create hc_specific");
   2197  7197    stephh 		if (nvlist_xalloc(&hcs, NV_UNIQUE_NAME, &Eft_nv_hdl) != 0)
   2198  7197    stephh 			out(O_DIE,
   2199  7197    stephh 			    "cannot add payloadprop \"%s\" to fault", lhs);
   2200  7197    stephh 		if (nvlist_add_nvlist(rsrc, FM_FMRI_HC_SPECIFIC, hcs) != 0)
   2201  7197    stephh 			out(O_DIE,
   2202  7197    stephh 			    "cannot add payloadprop \"%s\" to fault", lhs);
   2203  7197    stephh 		nvlist_free(hcs);
   2204  7197    stephh 		if (nvlist_lookup_nvlist(rsrc, FM_FMRI_HC_SPECIFIC, &hcs) != 0)
   2205  7197    stephh 			out(O_DIE,
   2206  7197    stephh 			    "cannot add payloadprop \"%s\" to fault", lhs);
   2207  7197    stephh 	} else
   2208  7197    stephh 		out(O_ALTFP|O_VERB2, "addpayloadprop: reuse hc_specific");
   2209  1414     cindi 
   2210  1414     cindi 	if (rhs->t == UINT64) {
   2211  1414     cindi 		out(O_ALTFP|O_VERB2, "addpayloadprop: %s=%llu", lhs, rhs->v);
   2212  1414     cindi 
   2213  7197    stephh 		if (nvlist_add_uint64(hcs, lhs, rhs->v) != 0)
   2214  1414     cindi 			out(O_DIE,
   2215  1414     cindi 			    "cannot add payloadprop \"%s\" to fault", lhs);
   2216  1414     cindi 	} else {
   2217  1414     cindi 		out(O_ALTFP|O_VERB2, "addpayloadprop: %s=\"%s\"",
   2218  1717  wesolows 		    lhs, (char *)(uintptr_t)rhs->v);
   2219  1414     cindi 
   2220  7197    stephh 		if (nvlist_add_string(hcs, lhs, (char *)(uintptr_t)rhs->v) != 0)
   2221  1414     cindi 			out(O_DIE,
   2222  1414     cindi 			    "cannot add payloadprop \"%s\" to fault", lhs);
   2223  1414     cindi 	}
   2224  1414     cindi }
   2225  1414     cindi 
   2226  1414     cindi static char *Istatbuf;
   2227  1414     cindi static char *Istatbufptr;
   2228  1414     cindi static int Istatsz;
   2229  1414     cindi 
   2230  1414     cindi /*
   2231  1414     cindi  * istataddsize -- calculate size of istat and add it to Istatsz
   2232  1414     cindi  */
   2233  1414     cindi /*ARGSUSED2*/
   2234  1414     cindi static void
   2235  1414     cindi istataddsize(const struct istat_entry *lhs, struct stats *rhs, void *arg)
   2236  1414     cindi {
   2237  1414     cindi 	int val;
   2238  1414     cindi 
   2239  1414     cindi 	ASSERT(lhs != NULL);
   2240  1414     cindi 	ASSERT(rhs != NULL);
   2241  1414     cindi 
   2242  1414     cindi 	if ((val = stats_counter_value(rhs)) == 0)
   2243  1414     cindi 		return;	/* skip zero-valued stats */
   2244  1414     cindi 
   2245  1414     cindi 	/* count up the size of the stat name */
   2246  1414     cindi 	Istatsz += ipath2strlen(lhs->ename, lhs->ipath);
   2247  1414     cindi 	Istatsz++;	/* for the trailing NULL byte */
   2248  1414     cindi 
   2249  1414     cindi 	/* count up the size of the stat value */
   2250  1414     cindi 	Istatsz += snprintf(NULL, 0, "%d", val);
   2251  1414     cindi 	Istatsz++;	/* for the trailing NULL byte */
   2252  1414     cindi }
   2253  1414     cindi 
   2254  1414     cindi /*
   2255  1414     cindi  * istat2str -- serialize an istat, writing result to *Istatbufptr
   2256  1414     cindi  */
   2257  1414     cindi /*ARGSUSED2*/
   2258  1414     cindi static void
   2259  1414     cindi istat2str(const struct istat_entry *lhs, struct stats *rhs, void *arg)
   2260  1414     cindi {
   2261  1414     cindi 	char *str;
   2262  1414     cindi 	int len;
   2263  1414     cindi 	int val;
   2264  1414     cindi 
   2265  1414     cindi 	ASSERT(lhs != NULL);
   2266  1414     cindi 	ASSERT(rhs != NULL);
   2267  1414     cindi 
   2268  1414     cindi 	if ((val = stats_counter_value(rhs)) == 0)
   2269  1414     cindi 		return;	/* skip zero-valued stats */
   2270  1414     cindi 
   2271  1414     cindi 	/* serialize the stat name */
   2272  1414     cindi 	str = ipath2str(lhs->ename, lhs->ipath);
   2273  1414     cindi 	len = strlen(str);
   2274  1414     cindi 
   2275  1414     cindi 	ASSERT(Istatbufptr + len + 1 < &Istatbuf[Istatsz]);
   2276  1414     cindi 	(void) strlcpy(Istatbufptr, str, &Istatbuf[Istatsz] - Istatbufptr);
   2277  1414     cindi 	Istatbufptr += len;
   2278  1414     cindi 	FREE(str);
   2279  1414     cindi 	*Istatbufptr++ = '\0';
   2280  1414     cindi 
   2281  1414     cindi 	/* serialize the stat value */
   2282  1414     cindi 	Istatbufptr += snprintf(Istatbufptr, &Istatbuf[Istatsz] - Istatbufptr,
   2283  1414     cindi 	    "%d", val);
   2284  1414     cindi 	*Istatbufptr++ = '\0';
   2285  1414     cindi 
   2286  1414     cindi 	ASSERT(Istatbufptr <= &Istatbuf[Istatsz]);
   2287  1414     cindi }
   2288  1414     cindi 
   2289  1414     cindi void
   2290  1414     cindi istat_save()
   2291  1414     cindi {
   2292  1414     cindi 	if (Istat_need_save == 0)
   2293  1414     cindi 		return;
   2294  1414     cindi 
   2295  1414     cindi 	/* figure out how big the serialzed info is */
   2296  1414     cindi 	Istatsz = 0;
   2297  1414     cindi 	lut_walk(Istats, (lut_cb)istataddsize, NULL);
   2298  1414     cindi 
   2299  1414     cindi 	if (Istatsz == 0) {
   2300  1414     cindi 		/* no stats to save */
   2301  1414     cindi 		fmd_buf_destroy(Hdl, NULL, WOBUF_ISTATS);
   2302  1414     cindi 		return;
   2303  1414     cindi 	}
   2304  1414     cindi 
   2305  1414     cindi 	/* create the serialized buffer */
   2306  1414     cindi 	Istatbufptr = Istatbuf = MALLOC(Istatsz);
   2307  1414     cindi 	lut_walk(Istats, (lut_cb)istat2str, NULL);
   2308  1414     cindi 
   2309  1414     cindi 	/* clear out current saved stats */
   2310  1414     cindi 	fmd_buf_destroy(Hdl, NULL, WOBUF_ISTATS);
   2311  1414     cindi 
   2312  1414     cindi 	/* write out the new version */
   2313  1414     cindi 	fmd_buf_write(Hdl, NULL, WOBUF_ISTATS, Istatbuf, Istatsz);
   2314  1414     cindi 	FREE(Istatbuf);
   2315  1414     cindi 
   2316  1414     cindi 	Istat_need_save = 0;
   2317  1414     cindi }
   2318  1414     cindi 
   2319  1414     cindi int
   2320  1414     cindi istat_cmp(struct istat_entry *ent1, struct istat_entry *ent2)
   2321  1414     cindi {
   2322  1414     cindi 	if (ent1->ename != ent2->ename)
   2323  1414     cindi 		return (ent2->ename - ent1->ename);
   2324  1414     cindi 	if (ent1->ipath != ent2->ipath)
   2325  1414     cindi 		return ((char *)ent2->ipath - (char *)ent1->ipath);
   2326  1414     cindi 
   2327  1414     cindi 	return (0);
   2328  1414     cindi }
   2329  1414     cindi 
   2330  1414     cindi /*
   2331  1414     cindi  * istat-verify -- verify the component associated with a stat still exists
   2332  1414     cindi  *
   2333  1414     cindi  * if the component no longer exists, this routine resets the stat and
   2334  1414     cindi  * returns 0.  if the component still exists, it returns 1.
   2335  1414     cindi  */
   2336  1414     cindi static int
   2337  1414     cindi istat_verify(struct node *snp, struct istat_entry *entp)
   2338  1414     cindi {
   2339  1414     cindi 	struct stats *statp;
   2340  1414     cindi 	nvlist_t *fmri;
   2341  1414     cindi 
   2342  1414     cindi 	fmri = node2fmri(snp->u.event.epname);
   2343  1414     cindi 	if (platform_path_exists(fmri)) {
   2344  1414     cindi 		nvlist_free(fmri);
   2345  1414     cindi 		return (1);
   2346  1414     cindi 	}
   2347  1414     cindi 	nvlist_free(fmri);
   2348  1414     cindi 
   2349  1414     cindi 	/* component no longer in system.  zero out the associated stats */
   2350  1414     cindi 	if ((statp = (struct stats *)
   2351  1414     cindi 	    lut_lookup(Istats, entp, (lut_cmp)istat_cmp)) == NULL ||
   2352  1414     cindi 	    stats_counter_value(statp) == 0)
   2353  1414     cindi 		return (0);	/* stat is already reset */
   2354  1414     cindi 
   2355  1414     cindi 	Istat_need_save = 1;
   2356  1414     cindi 	stats_counter_reset(statp);
   2357  1414     cindi 	return (0);
   2358  1414     cindi }
   2359  1414     cindi 
   2360  1414     cindi static void
   2361  1414     cindi istat_bump(struct node *snp, int n)
   2362  1414     cindi {
   2363  1414     cindi 	struct stats *statp;
   2364  1414     cindi 	struct istat_entry ent;
   2365  1414     cindi 
   2366  1414     cindi 	ASSERT(snp != NULL);
   2367  1414     cindi 	ASSERTinfo(snp->t == T_EVENT, ptree_nodetype2str(snp->t));
   2368  1414     cindi 	ASSERT(snp->u.event.epname != NULL);
   2369  1414     cindi 
   2370  1414     cindi 	/* class name should be hoisted into a single stable entry */
   2371  1414     cindi 	ASSERT(snp->u.event.ename->u.name.next == NULL);
   2372  1414     cindi 	ent.ename = snp->u.event.ename->u.name.s;
   2373  1414     cindi 	ent.ipath = ipath(snp->u.event.epname);
   2374  1414     cindi 
   2375  1414     cindi 	if (!istat_verify(snp, &ent)) {
   2376  1414     cindi 		/* component no longer exists in system, nothing to do */
   2377  1414     cindi 		return;
   2378  1414     cindi 	}
   2379  1414     cindi 
   2380  1414     cindi 	if ((statp = (struct stats *)
   2381  1414     cindi 	    lut_lookup(Istats, &ent, (lut_cmp)istat_cmp)) == NULL) {
   2382  1414     cindi 		/* need to create the counter */
   2383  1414     cindi 		int cnt = 0;
   2384  1414     cindi 		struct node *np;
   2385  1414     cindi 		char *sname;
   2386  1414     cindi 		char *snamep;
   2387  1414     cindi 		struct istat_entry *newentp;
   2388  1414     cindi 
   2389  1414     cindi 		/* count up the size of the stat name */
   2390  1414     cindi 		np = snp->u.event.ename;
   2391  1414     cindi 		while (np != NULL) {
   2392  1414     cindi 			cnt += strlen(np->u.name.s);
   2393  1414     cindi 			cnt++;	/* for the '.' or '@' */
   2394  1414     cindi 			np = np->u.name.next;
   2395  1414     cindi 		}
   2396  1414     cindi 		np = snp->u.event.epname;
   2397  1414     cindi 		while (np != NULL) {
   2398  1414     cindi 			cnt += snprintf(NULL, 0, "%s%llu",
   2399  1414     cindi 			    np->u.name.s, np->u.name.child->u.ull);
   2400  1414     cindi 			cnt++;	/* for the '/' or trailing NULL byte */
   2401  1414     cindi 			np = np->u.name.next;
   2402  1414     cindi 		}
   2403  1414     cindi 
   2404  1414     cindi 		/* build the stat name */
   2405  1414     cindi 		snamep = sname = alloca(cnt);
   2406  1414     cindi 		np = snp->u.event.ename;
   2407  1414     cindi 		while (np != NULL) {
   2408  1414     cindi 			snamep += snprintf(snamep, &sname[cnt] - snamep,
   2409  1414     cindi 			    "%s", np->u.name.s);
   2410  1414     cindi 			np = np->u.name.next;
   2411  1414     cindi 			if (np)
   2412  1414     cindi 				*snamep++ = '.';
   2413  1414     cindi 		}
   2414  1414     cindi 		*snamep++ = '@';
   2415  1414     cindi 		np = snp->u.event.epname;
   2416  1414     cindi 		while (np != NULL) {
   2417  1414     cindi 			snamep += snprintf(snamep, &sname[cnt] - snamep,
   2418  1414     cindi 			    "%s%llu", np->u.name.s, np->u.name.child->u.ull);
   2419  1414     cindi 			np = np->u.name.next;
   2420  1414     cindi 			if (np)
   2421  1414     cindi 				*snamep++ = '/';
   2422  1414     cindi 		}
   2423  1414     cindi 		*snamep++ = '\0';
   2424  1414     cindi 
   2425  1414     cindi 		/* create the new stat & add it to our list */
   2426  1414     cindi 		newentp = MALLOC(sizeof (*newentp));
   2427  1414     cindi 		*newentp = ent;
   2428  1414     cindi 		statp = stats_new_counter(NULL, sname, 0);
   2429  1414     cindi 		Istats = lut_add(Istats, (void *)newentp, (void *)statp,
   2430  1414     cindi 		    (lut_cmp)istat_cmp);
   2431  1414     cindi 	}
   2432  1414     cindi 
   2433  1414     cindi 	/* if n is non-zero, set that value instead of bumping */
   2434  1414     cindi 	if (n) {
   2435  1414     cindi 		stats_counter_reset(statp);
   2436  1414     cindi 		stats_counter_add(statp, n);
   2437  1414     cindi 	} else
   2438  1414     cindi 		stats_counter_bump(statp);
   2439  1414     cindi 	Istat_need_save = 1;
   2440  2869    gavinm 
   2441  2869    gavinm 	ipath_print(O_ALTFP|O_VERB2, ent.ename, ent.ipath);
   2442  2869    gavinm 	out(O_ALTFP|O_VERB2, " %s to value %d", n ? "set" : "incremented",
   2443  2869    gavinm 	    stats_counter_value(statp));
   2444  1414     cindi }
   2445  1414     cindi 
   2446  1414     cindi /*ARGSUSED*/
   2447  1414     cindi static void
   2448  1414     cindi istat_destructor(void *left, void *right, void *arg)
   2449  1414     cindi {
   2450  1414     cindi 	struct istat_entry *entp = (struct istat_entry *)left;
   2451  1414     cindi 	struct stats *statp = (struct stats *)right;
   2452  1414     cindi 	FREE(entp);
   2453  1414     cindi 	stats_delete(statp);
   2454  2120    gavinm }
   2455  2120    gavinm 
   2456  2120    gavinm /*
   2457  2120    gavinm  * Callback used in a walk of the Istats to reset matching stat counters.
   2458  2120    gavinm  */
   2459  2120    gavinm static void
   2460  2120    gavinm istat_counter_reset_cb(struct istat_entry *entp, struct stats *statp,
   2461  2120    gavinm     const struct ipath *ipp)
   2462  2120    gavinm {
   2463  2120    gavinm 	char *path;
   2464  2120    gavinm 
   2465  2120    gavinm 	if (entp->ipath == ipp) {
   2466  2120    gavinm 		path = ipath2str(entp->ename, ipp);
   2467  2120    gavinm 		out(O_ALTFP, "istat_counter_reset_cb: resetting %s", path);
   2468  2120    gavinm 		FREE(path);
   2469  2120    gavinm 		stats_counter_reset(statp);
   2470  2120    gavinm 		Istat_need_save = 1;
   2471  2120    gavinm 	}
   2472  1414     cindi }
   2473  1414     cindi 
   2474  5204    stephh /*ARGSUSED*/
   2475  5204    stephh static void
   2476  5204    stephh istat_counter_topo_chg_cb(struct istat_entry *entp, struct stats *statp,
   2477  5204    stephh     void *unused)
   2478  5204    stephh {
   2479  5204    stephh 	char *path;
   2480  5204    stephh 	nvlist_t *fmri;
   2481  5204    stephh 
   2482  5204    stephh 	fmri = ipath2fmri((struct ipath *)(entp->ipath));
   2483  5204    stephh 	if (!platform_path_exists(fmri)) {
   2484  5204    stephh 		path = ipath2str(entp->ename, entp->ipath);
   2485  5204    stephh 		out(O_ALTFP, "istat_counter_topo_chg_cb: not present %s", path);
   2486  5204    stephh 		FREE(path);
   2487  5204    stephh 		stats_counter_reset(statp);
   2488  5204    stephh 		Istat_need_save = 1;
   2489  5204    stephh 	}
   2490  5204    stephh 	nvlist_free(fmri);
   2491  5204    stephh }
   2492  5204    stephh 
   2493  1414     cindi void
   2494  1414     cindi istat_fini(void)
   2495  1414     cindi {
   2496  1414     cindi 	lut_free(Istats, istat_destructor, NULL);
   2497  1414     cindi }
   2498  1414     cindi 
   2499  4436    stephh static char *Serdbuf;
   2500  4436    stephh static char *Serdbufptr;
   2501  4436    stephh static int Serdsz;
   2502  4436    stephh 
   2503  4436    stephh /*
   2504  4436    stephh  * serdaddsize -- calculate size of serd and add it to Serdsz
   2505  4436    stephh  */
   2506  4436    stephh /*ARGSUSED*/
   2507  4436    stephh static void
   2508  4436    stephh serdaddsize(const struct serd_entry *lhs, struct stats *rhs, void *arg)
   2509  4436    stephh {
   2510  4436    stephh 	ASSERT(lhs != NULL);
   2511  4436    stephh 
   2512  4436    stephh 	/* count up the size of the stat name */
   2513  4436    stephh 	Serdsz += ipath2strlen(lhs->ename, lhs->ipath);
   2514  4436    stephh 	Serdsz++;	/* for the trailing NULL byte */
   2515  4436    stephh }
   2516  4436    stephh 
   2517  4436    stephh /*
   2518  4436    stephh  * serd2str -- serialize a serd engine, writing result to *Serdbufptr
   2519  4436    stephh  */
   2520  4436    stephh /*ARGSUSED*/
   2521  4436    stephh static void
   2522  4436    stephh serd2str(const struct serd_entry *lhs, struct stats *rhs, void *arg)
   2523  4436    stephh {
   2524  4436    stephh 	char *str;
   2525  4436    stephh 	int len;
   2526  4436    stephh 
   2527  4436    stephh 	ASSERT(lhs != NULL);
   2528  4436    stephh 
   2529  4436    stephh 	/* serialize the serd engine name */
   2530  4436    stephh 	str = ipath2str(lhs->ename, lhs->ipath);
   2531  4436    stephh 	len = strlen(str);
   2532  4436    stephh 
   2533  4436    stephh 	ASSERT(Serdbufptr + len + 1 <= &Serdbuf[Serdsz]);
   2534  4436    stephh 	(void) strlcpy(Serdbufptr, str, &Serdbuf[Serdsz] - Serdbufptr);
   2535  4436    stephh 	Serdbufptr += len;
   2536  4436    stephh 	FREE(str);
   2537  4436    stephh 	*Serdbufptr++ = '\0';
   2538  4436    stephh 	ASSERT(Serdbufptr <= &Serdbuf[Serdsz]);
   2539  4436    stephh }
   2540  4436    stephh 
   2541  4436    stephh void
   2542  4436    stephh serd_save()
   2543  4436    stephh {
   2544  4436    stephh 	if (Serd_need_save == 0)
   2545  4436    stephh 		return;
   2546  4436    stephh 
   2547  4436    stephh 	/* figure out how big the serialzed info is */
   2548  4436    stephh 	Serdsz = 0;
   2549  4436    stephh 	lut_walk(SerdEngines, (lut_cb)serdaddsize, NULL);
   2550  4436    stephh 
   2551  4436    stephh 	if (Serdsz == 0) {
   2552  4436    stephh 		/* no serd engines to save */
   2553  4436    stephh 		fmd_buf_destroy(Hdl, NULL, WOBUF_SERDS);
   2554  4436    stephh 		return;
   2555  4436    stephh 	}
   2556  4436    stephh 
   2557  4436    stephh 	/* create the serialized buffer */
   2558  4436    stephh 	Serdbufptr = Serdbuf = MALLOC(Serdsz);
   2559  4436    stephh 	lut_walk(SerdEngines, (lut_cb)serd2str, NULL);
   2560  4436    stephh 
   2561  4436    stephh 	/* clear out current saved stats */
   2562  4436    stephh 	fmd_buf_destroy(Hdl, NULL, WOBUF_SERDS);
   2563  4436    stephh 
   2564  4436    stephh 	/* write out the new version */
   2565  4436    stephh 	fmd_buf_write(Hdl, NULL, WOBUF_SERDS, Serdbuf, Serdsz);
   2566  4436    stephh 	FREE(Serdbuf);
   2567  4436    stephh 	Serd_need_save = 0;
   2568  4436    stephh }
   2569  4436    stephh 
   2570  4436    stephh int
   2571  4436    stephh serd_cmp(struct serd_entry *ent1, struct serd_entry *ent2)
   2572  4436    stephh {
   2573  4436    stephh 	if (ent1->ename != ent2->ename)
   2574  4436    stephh 		return (ent2->ename - ent1->ename);
   2575  4436    stephh 	if (ent1->ipath != ent2->ipath)
   2576  4436    stephh 		return ((char *)ent2->ipath - (char *)ent1->ipath);
   2577  4436    stephh 
   2578  4436    stephh 	return (0);
   2579  4436    stephh }
   2580  4436    stephh 
   2581  4436    stephh void
   2582  4436    stephh fme_serd_load(fmd_hdl_t *hdl)
   2583  4436    stephh {
   2584  4436    stephh 	int sz;
   2585  4436    stephh 	char *sbuf;
   2586  4436    stephh 	char *sepptr;
   2587  4436    stephh 	char *ptr;
   2588  4436    stephh 	struct serd_entry *newentp;
   2589  4436    stephh 	struct node *epname;
   2590  4436    stephh 	nvlist_t *fmri;
   2591  4436    stephh 	char *namestring;
   2592  4436    stephh 
   2593  4436    stephh 	if ((sz = fmd_buf_size(hdl, NULL, WOBUF_SERDS)) == 0)
   2594  4436    stephh 		return;
   2595  4436    stephh 	sbuf = alloca(sz);
   2596  4436    stephh 	fmd_buf_read(hdl, NULL, WOBUF_SERDS, sbuf, sz);
   2597  4436    stephh 	ptr = sbuf;
   2598  4436    stephh 	while (ptr < &sbuf[sz]) {
   2599  4436    stephh 		sepptr = strchr(ptr, '@');
   2600  4436    stephh 		*sepptr = '\0';
   2601  4436    stephh 		namestring = ptr;
   2602  4436    stephh 		sepptr++;
   2603  4436    stephh 		ptr = sepptr;
   2604  4436    stephh 		ptr += strlen(ptr);
   2605  4436    stephh 		ptr++;	/* move past the '\0' separating paths */
   2606  4436    stephh 		epname = pathstring2epnamenp(sepptr);
   2607  4436    stephh 		fmri = node2fmri(epname);
   2608  4436    stephh 		if (platform_path_exists(fmri)) {
   2609  4436    stephh 			newentp = MALLOC(sizeof (*newentp));
   2610  4436    stephh 			newentp->hdl = hdl;
   2611  4436    stephh 			newentp->ipath = ipath(epname);
   2612  4436    stephh 			newentp->ename = stable(namestring);
   2613  4436    stephh 			SerdEngines = lut_add(SerdEngines, (void *)newentp,
   2614  5204    stephh 			    (void *)newentp, (lut_cmp)serd_cmp);
   2615  4436    stephh 		} else
   2616  4436    stephh 			Serd_need_save = 1;
   2617  5204    stephh 		tree_free(epname);
   2618  4436    stephh 		nvlist_free(fmri);
   2619  4436    stephh 	}
   2620  4436    stephh 	/* save it back again in case some of the paths no longer exist */
   2621  4436    stephh 	serd_save();
   2622  4436    stephh }
   2623  4436    stephh 
   2624  4436    stephh /*ARGSUSED*/
   2625  4436    stephh static void
   2626  4436    stephh serd_destructor(void *left, void *right, void *arg)
   2627  4436    stephh {
   2628  4436    stephh 	struct serd_entry *entp = (struct serd_entry *)left;
   2629  4436    stephh 	FREE(entp);
   2630  4436    stephh }
   2631  4436    stephh 
   2632  4436    stephh /*
   2633  4436    stephh  * Callback used in a walk of the SerdEngines to reset matching serd engines.
   2634  4436    stephh  */
   2635  4436    stephh /*ARGSUSED*/
   2636  4436    stephh static void
   2637  4436    stephh serd_reset_cb(struct serd_entry *entp, void *unused, const struct ipath *ipp)
   2638  4436    stephh {
   2639  4436    stephh 	char *path;
   2640  4436    stephh 
   2641  4436    stephh 	if (entp->ipath == ipp) {
   2642  4436    stephh 		path = ipath2str(entp->ename, ipp);
   2643  4436    stephh 		out(O_ALTFP, "serd_reset_cb: resetting %s", path);
   2644  4436    stephh 		fmd_serd_reset(entp->hdl, path);
   2645  4436    stephh 		FREE(path);
   2646  4436    stephh 		Serd_need_save = 1;
   2647  4436    stephh 	}
   2648  5204    stephh }
   2649  5204    stephh 
   2650  5204    stephh /*ARGSUSED*/
   2651  5204    stephh static void
   2652  5204    stephh serd_topo_chg_cb(struct serd_entry *entp, void *unused, void *unused2)
   2653  5204    stephh {
   2654  5204    stephh 	char *path;
   2655  5204    stephh 	nvlist_t *fmri;
   2656  5204    stephh 
   2657  5204    stephh 	fmri = ipath2fmri((struct ipath *)(entp->ipath));
   2658  5204    stephh 	if (!platform_path_exists(fmri)) {
   2659  5204    stephh 		path = ipath2str(entp->ename, entp->ipath);
   2660  5204    stephh 		out(O_ALTFP, "serd_topo_chg_cb: not present %s", path);
   2661  5204    stephh 		fmd_serd_reset(entp->hdl, path);
   2662  5204    stephh 		FREE(path);
   2663  5204    stephh 		Serd_need_save = 1;
   2664  5204    stephh 	}
   2665  5204    stephh 	nvlist_free(fmri);
   2666  4436    stephh }
   2667  4436    stephh 
   2668  4436    stephh void
   2669  4436    stephh serd_fini(void)
   2670  4436    stephh {
   2671  4436    stephh 	lut_free(SerdEngines, serd_destructor, NULL);
   2672  4436    stephh }
   2673  4436    stephh 
   2674     0    stevel static void
   2675  7197    stephh publish_suspects(struct fme *fmep, struct rsl *srl)
   2676  7197    stephh {
   2677     0    stevel 	struct rsl *rp;
   2678     0    stevel 	nvlist_t *fault;
   2679     0    stevel 	uint8_t cert;
   2680     0    stevel 	uint_t *frs;
   2681  8245   Stephen 	uint_t frsum, fr;
   2682  1414     cindi 	uint_t messval;
   2683  7197    stephh 	uint_t retireval;
   2684  7197    stephh 	uint_t responseval;
   2685  1414     cindi 	struct node *snp;
   2686     0    stevel 	int frcnt, fridx;
   2687  1414     cindi 	boolean_t allfaulty = B_TRUE;
   2688  7197    stephh 	struct rsl *erl = srl + fmep->nsuspects - 1;
   2689  7197    stephh 
   2690  7197    stephh 	/*
   2691  7197    stephh 	 * sort the array
   2692  7197    stephh 	 */
   2693  7197    stephh 	qsort(srl, fmep->nsuspects, sizeof (struct rsl), rslcmp);
   2694  8245   Stephen 
   2695  8245   Stephen 	/* sum the fitrates */
   2696  8245   Stephen 	frs = alloca(fmep->nsuspects * sizeof (uint_t));
   2697  8245   Stephen 	fridx = frcnt = frsum = 0;
   2698  8245   Stephen 
   2699  8245   Stephen 	for (rp = srl; rp <= erl; rp++) {
   2700  8245   Stephen 		struct node *n;
   2701  8245   Stephen 
   2702  8245   Stephen 		n = eventprop_lookup(rp->suspect, L_FITrate);
   2703  8245   Stephen 		if (node2uint(n, &fr) != 0) {
   2704  8245   Stephen 			out(O_DEBUG|O_NONL, "event ");
   2705  8245   Stephen 			ipath_print(O_DEBUG|O_NONL,
   2706  8245   Stephen 			    rp->suspect->enode->u.event.ename->u.name.s,
   2707  8245   Stephen 			    rp->suspect->ipp);
   2708  8245   Stephen 			out(O_DEBUG, " has no FITrate (using 1)");
   2709  8245   Stephen 			fr = 1;
   2710  8245   Stephen 		} else if (fr == 0) {
   2711  8245   Stephen 			out(O_DEBUG|O_NONL, "event ");
   2712  8245   Stephen 			ipath_print(O_DEBUG|O_NONL,
   2713  8245   Stephen 			    rp->suspect->enode->u.event.ename->u.name.s,
   2714  8245   Stephen 			    rp->suspect->ipp);
   2715  8245   Stephen 			out(O_DEBUG, " has zero FITrate (using 1)");
   2716  8245   Stephen 			fr = 1;
   2717  8245   Stephen 		}
   2718  8245   Stephen 
   2719  8245   Stephen 		frs[fridx++] = fr;
   2720  8245   Stephen 		frsum += fr;
   2721  8245   Stephen 		frcnt++;
   2722     0    stevel 	}
   2723     0    stevel 
   2724     0    stevel 	/* Add them in reverse order of our sort, as fmd reverses order */
   2725     0    stevel 	for (rp = erl; rp >= srl; rp--) {
   2726  8245   Stephen 		cert = percentof(frs[--fridx], frsum);
   2727     0    stevel 		fault = fmd_nvl_create_fault(fmep->hdl,
   2728     0    stevel 		    rp->suspect->enode->u.event.ename->u.name.s,
   2729     0    stevel 		    cert,
   2730     0    stevel 		    rp->asru,
   2731     0    stevel 		    rp->fru,
   2732     0    stevel 		    rp->rsrc);
   2733     0    stevel 		if (fault == NULL)
   2734     0    stevel 			out(O_DIE, "fault creation failed");
   2735  1414     cindi 		/* if "message" property exists, add it to the fault */
   2736  1414     cindi 		if (node2uint(eventprop_lookup(rp->suspect, L_message),
   2737  1414     cindi 		    &messval) == 0) {
   2738  1414     cindi 
   2739  1414     cindi 			out(O_ALTFP,
   2740  1414     cindi 			    "[FME%d, %s adds message=%d to suspect list]",
   2741  1414     cindi 			    fmep->id,
   2742  1414     cindi 			    rp->suspect->enode->u.event.ename->u.name.s,
   2743  1414     cindi 			    messval);
   2744  1414     cindi 			if (nvlist_add_boolean_value(fault,
   2745  1414     cindi 			    FM_SUSPECT_MESSAGE,
   2746  1414     cindi 			    (messval) ? B_TRUE : B_FALSE) != 0) {
   2747  1414     cindi 				out(O_DIE, "cannot add no-message to fault");
   2748  1414     cindi 			}
   2749  1414     cindi 		}
   2750  7197    stephh 
   2751  7197    stephh 		/* if "retire" property exists, add it to the fault */
   2752  7197    stephh 		if (node2uint(eventprop_lookup(rp->suspect, L_retire),
   2753  7197    stephh 		    &retireval) == 0) {
   2754  7197    stephh 
   2755  7197    stephh 			out(O_ALTFP,
   2756  7197    stephh 			    "[FME%d, %s adds retire=%d to suspect list]",
   2757  7197    stephh 			    fmep->id,
   2758  7197    stephh 			    rp->suspect->enode->u.event.ename->u.name.s,
   2759  7197    stephh 			    retireval);
   2760  7197    stephh 			if (nvlist_add_boolean_value(fault,
   2761  7197    stephh 			    FM_SUSPECT_RETIRE,
   2762  7197    stephh 			    (retireval) ? B_TRUE : B_FALSE) != 0) {
   2763  7197    stephh 				out(O_DIE, "cannot add no-retire to fault");
   2764  7197    stephh 			}
   2765  7197    stephh 		}
   2766  7197    stephh 
   2767  7197    stephh 		/* if "response" property exists, add it to the fault */
   2768  7197    stephh 		if (node2uint(eventprop_lookup(rp->suspect, L_response),
   2769  7197    stephh 		    &responseval) == 0) {
   2770  7197    stephh 
   2771  7197    stephh 			out(O_ALTFP,
   2772  7197    stephh 			    "[FME%d, %s adds response=%d to suspect list]",
   2773  7197    stephh 			    fmep->id,
   2774  7197    stephh 			    rp->suspect->enode->u.event.ename->u.name.s,
   2775  7197    stephh 			    responseval);
   2776  7197    stephh 			if (nvlist_add_boolean_value(fault,
   2777  7197    stephh 			    FM_SUSPECT_RESPONSE,
   2778  7197    stephh 			    (responseval) ? B_TRUE : B_FALSE) != 0) {
   2779  7197    stephh 				out(O_DIE, "cannot add no-response to fault");
   2780  7197    stephh 			}
   2781  7197    stephh 		}
   2782  7197    stephh 
   2783  1414     cindi 		/* add any payload properties */
   2784  1414     cindi 		lut_walk(rp->suspect->payloadprops,
   2785  1414     cindi 		    (lut_cb)addpayloadprop, (void *)fault);
   2786     0    stevel 		rslfree(rp);
   2787  1493    gavinm 
   2788  1493    gavinm 		/*
   2789  1493    gavinm 		 * If "action" property exists, evaluate it;  this must be done
   2790  7197    stephh 		 * before the allfaulty check below since some actions may
   2791  7275    stephh 		 * modify the asru to be used in fmd_nvl_fmri_has_fault.  This
   2792  1493    gavinm 		 * needs to be restructured if any new actions are introduced
   2793  1493    gavinm 		 * that have effects that we do not want to be visible if
   2794  1493    gavinm 		 * we decide not to publish in the dupclose check below.
   2795  1493    gavinm 		 */
   2796  1414     cindi 		if ((snp = eventprop_lookup(rp->suspect, L_action)) != NULL) {
   2797  1414     cindi 			struct evalue evalue;
   2798  1414     cindi 
   2799  1414     cindi 			out(O_ALTFP|O_NONL,
   2800  1414     cindi 			    "[FME%d, %s action ", fmep->id,
   2801  1414     cindi 			    rp->suspect->enode->u.event.ename->u.name.s);
   2802  1414     cindi 			ptree_name_iter(O_ALTFP|O_NONL, snp);
   2803  1414     cindi 			out(O_ALTFP, "]");
   2804  1414     cindi 			Action_nvl = fault;
   2805  1414     cindi 			(void) eval_expr(snp, NULL, NULL, NULL, NULL,
   2806  1414     cindi 			    NULL, 0, &evalue);
   2807  1414     cindi 		}
   2808  1493    gavinm 
   2809  7197    stephh 		fmd_case_add_suspect(fmep->hdl, fmep->fmcase, fault);
   2810  7197    stephh 
   2811  1414     cindi 		/*
   2812  6228    stephh 		 * check if the asru is already marked as "faulty".
   2813  6228    stephh 		 */
   2814  6228    stephh 		if (allfaulty) {
   2815  1414     cindi 			nvlist_t *asru;
   2816  1414     cindi 
   2817  7197    stephh 			out(O_ALTFP|O_VERB, "FME%d dup check ", fmep->id);
   2818  1414     cindi 			itree_pevent_brief(O_ALTFP|O_VERB|O_NONL, rp->suspect);
   2819  1414     cindi 			out(O_ALTFP|O_VERB|O_NONL, " ");
   2820  1414     cindi 			if (nvlist_lookup_nvlist(fault,
   2821  1414     cindi 			    FM_FAULT_ASRU, &asru) != 0) {
   2822  1414     cindi 				out(O_ALTFP|O_VERB, "NULL asru");
   2823  1414     cindi 				allfaulty = B_FALSE;
   2824  7275    stephh 			} else if (fmd_nvl_fmri_has_fault(fmep->hdl, asru,
   2825  7275    stephh 			    FMD_HAS_FAULT_ASRU, NULL)) {
   2826  1414     cindi 				out(O_ALTFP|O_VERB, "faulty");
   2827  1414     cindi 			} else {
   2828  1414     cindi 				out(O_ALTFP|O_VERB, "not faulty");
   2829  1414     cindi 				allfaulty = B_FALSE;
   2830  1414     cindi 			}
   2831  1414     cindi 		}
   2832  1414     cindi 
   2833     0    stevel 	}
   2834  1493    gavinm 
   2835  6228    stephh 	if (!allfaulty) {
   2836  6228    stephh 		/*
   2837  6228    stephh 		 * don't update the count stat if all asrus are already
   2838  6228    stephh 		 * present and unrepaired in the asru cache
   2839  6228    stephh 		 */
   2840  1493    gavinm 		for (rp = erl; rp >= srl; rp--) {
   2841  1493    gavinm 			struct event *suspect = rp->suspect;
   2842  1493    gavinm 
   2843  1493    gavinm 			if (suspect == NULL)
   2844  1493    gavinm 				continue;
   2845  1493    gavinm 
   2846  1493    gavinm 			/* if "count" exists, increment the appropriate stat */
   2847  1493    gavinm 			if ((snp = eventprop_lookup(suspect,
   2848  1493    gavinm 			    L_count)) != NULL) {
   2849  1493    gavinm 				out(O_ALTFP|O_NONL,
   2850  1493    gavinm 				    "[FME%d, %s count ", fmep->id,
   2851  1493    gavinm 				    suspect->enode->u.event.ename->u.name.s);
   2852  1493    gavinm 				ptree_name_iter(O_ALTFP|O_NONL, snp);
   2853  1493    gavinm 				out(O_ALTFP, "]");
   2854  1493    gavinm 				istat_bump(snp, 0);
   2855  1493    gavinm 
   2856  1493    gavinm 			}
   2857  1493    gavinm 		}
   2858  1493    gavinm 		istat_save();	/* write out any istat changes */
   2859  6228    stephh 	}
   2860     0    stevel }
   2861     0    stevel 
   2862  7748     Tarik static const char *
   2863  7748     Tarik undiag_2defect_str(int ud)
   2864  7748     Tarik {
   2865  7748     Tarik 	switch (ud) {
   2866  7748     Tarik 	case UD_VAL_MISSINGINFO:
   2867  7748     Tarik 	case UD_VAL_MISSINGOBS:
   2868  7748     Tarik 	case UD_VAL_MISSINGPATH:
   2869  7748     Tarik 	case UD_VAL_MISSINGZERO:
   2870  7748     Tarik 	case UD_VAL_BADOBS:
   2871  7748     Tarik 	case UD_VAL_CFGMISMATCH:
   2872  7748     Tarik 		return (UNDIAG_DEFECT_CHKPT);
   2873  7748     Tarik 		break;
   2874  7748     Tarik 
   2875  7748     Tarik 	case UD_VAL_BADEVENTI:
   2876  7748     Tarik 	case UD_VAL_INSTFAIL:
   2877  7748     Tarik 	case UD_VAL_NOPATH:
   2878  7748     Tarik 	case UD_VAL_UNSOLVD:
   2879  7748     Tarik 		return (UNDIAG_DEFECT_FME);
   2880  7748     Tarik 		break;
   2881  7748     Tarik 
   2882  7748     Tarik 	case UD_VAL_MAXFME:
   2883  7748     Tarik 		return (UNDIAG_DEFECT_LIMIT);
   2884  7748     Tarik 		break;
   2885  7748     Tarik 
   2886  7748     Tarik 	case UD_VAL_UNKNOWN:
   2887  7748     Tarik 	default:
   2888  7748     Tarik 		return (UNDIAG_DEFECT_UNKNOWN);
   2889  7748     Tarik 		break;
   2890  7748     Tarik 	}
   2891  7748     Tarik }
   2892  7748     Tarik 
   2893  7748     Tarik const char *
   2894  7748     Tarik undiag_2reason_str(int ud)
   2895  7748     Tarik {
   2896  7748     Tarik 	switch (ud) {
   2897  7748     Tarik 	case UD_VAL_BADEVENTI:
   2898  7748     Tarik 		return (UD_STR_BADEVENTI);
   2899  7748     Tarik 	case UD_VAL_BADOBS:
   2900  7748     Tarik 		return (UD_STR_BADOBS);
   2901  7748     Tarik 	case UD_VAL_CFGMISMATCH:
   2902  7748     Tarik 		return (UD_STR_CFGMISMATCH);
   2903  7748     Tarik 	case UD_VAL_INSTFAIL:
   2904  7748     Tarik 		return (UD_STR_INSTFAIL);
   2905  7748     Tarik 	case UD_VAL_MAXFME:
   2906  7748     Tarik 		return (UD_STR_MAXFME);
   2907  7748     Tarik 	case UD_VAL_MISSINGINFO:
   2908  7748     Tarik 		return (UD_STR_MISSINGINFO);
   2909  7748     Tarik 	case UD_VAL_MISSINGOBS:
   2910  7748     Tarik 		return (UD_STR_MISSINGOBS);
   2911  7748     Tarik 	case UD_VAL_MISSINGPATH:
   2912  7748     Tarik 		return (UD_STR_MISSINGPATH);
   2913  7748     Tarik 	case UD_VAL_MISSINGZERO:
   2914  7748     Tarik 		return (UD_STR_MISSINGZERO);
   2915  7748     Tarik 	case UD_VAL_NOPATH:
   2916  7748     Tarik 		return (UD_STR_NOPATH);
   2917  7748     Tarik 	case UD_VAL_UNSOLVD:
   2918  7748     Tarik 		return (UD_STR_UNSOLVD);
   2919  7748     Tarik 	case UD_VAL_UNKNOWN:
   2920  7748     Tarik 	default:
   2921  7748     Tarik 		return (UD_STR_UNKNOWN);
   2922  7748     Tarik 	}
   2923  7748     Tarik }
   2924  7748     Tarik 
   2925     0    stevel static void
   2926  4436    stephh publish_undiagnosable(fmd_hdl_t *hdl, fmd_event_t *ffep, fmd_case_t *fmcase)
   2927     0    stevel {
   2928     0    stevel 	struct case_list *newcase;
   2929     0    stevel 	nvlist_t *defect;
   2930     0    stevel 
   2931     0    stevel 	out(O_ALTFP,
   2932     0    stevel 	    "[undiagnosable ereport received, "
   2933     0    stevel 	    "creating and closing a new case (%s)]",
   2934  7748     Tarik 	    undiag_2reason_str(Undiag_reason));
   2935     0    stevel 
   2936     0    stevel 	newcase = MALLOC(sizeof (struct case_list));
   2937     0    stevel 	newcase->next = NULL;
   2938  4436    stephh 	newcase->fmcase = fmcase;
   2939     0    stevel 	if (Undiagablecaselist != NULL)
   2940     0    stevel 		newcase->next = Undiagablecaselist;
   2941     0    stevel 	Undiagablecaselist = newcase;
   2942     0    stevel 
   2943     0    stevel 	if (ffep != NULL)
   2944     0    stevel 		fmd_case_add_ereport(hdl, newcase->fmcase, ffep);
   2945     0    stevel 
   2946  7748     Tarik 	defect = fmd_nvl_create_fault(hdl,
   2947  7748     Tarik 	    undiag_2defect_str(Undiag_reason), 100, NULL, NULL, NULL);
   2948  7748     Tarik 	(void) nvlist_add_string(defect, UNDIAG_REASON,
   2949  7748     Tarik 	    undiag_2reason_str(Undiag_reason));
   2950     0    stevel 	fmd_case_add_suspect(hdl, newcase->fmcase, defect);
   2951     0