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