# # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # debug : TARGET += debug SUBDIRS = esc eftinfo native files include ../Makefile.subdirs debug: $(SUBDIRS) files: native # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # Copyright 2007 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Copyright 2018 RackTop Systems. # Copyright (c) 2018, Joyent, Inc. # FMADIR = $(SRC)/cmd/fm EVERDIR = $(FMADIR)/eversholt EVERCMNSRC = $(EVERDIR)/common EFTCLASS = reader writer_WRTOBJ = eftwrite.o reader_WRTOBJ = CMNOBJS = alloc.o check.o eftread.o esclex.o io.o literals.o lut.o \ out.o ptree.o stable.o stats.o tree.o $($(EFTCLASS)_WRTOBJ) COMMONOBJS = escparse.o $(CMNOBJS) COMMONSRCS = $(COMMONOBJS:%.o=$(EVERCMNSRC)/%.c) BASECPPFLAGS = -I$(EVERCMNSRC) -I. $(NOT_RELEASE_BUILD)BASECPPFLAGS += -DDEBUG CPPFLAGS += $(BASECPPFLAGS) CFLAGS += $(CCVERBOSE) CERRWARN += $(CNOWARN_UNINIT) CERRWARN += -Wno-parentheses CERRWARN += -Wno-switch # because of labels from yacc escparse.o : CERRWARN += -Wno-unused-label SMOFF += all_func_returns CTFCONVO = $(CTFCONVERT_O) CTFMRG = $(CTFMERGE) -L VERSION -o $@ $(OBJS) debug : COPTFLAG = debug : COPTFLAG64 = ROOTPDIR = $(ROOT)/usr/lib/fm ROOTPROG = $(ROOTPDIR)/$(PROG) install_h: $(ROOTHDIR) $(ROOTHDRS) %.o: %.c $(COMPILE.c) $< $(CTFCONVO) %.o: $(EVERCMNSRC)/%.c $(COMPILE.c) $< $(CTFCONVO) escparse.o: $(EVERCMNSRC)/escparse.y $(YACC) -dtv $(EVERCMNSRC)/escparse.y $(COMPILE.c) -DYYDEBUG -c -o $@ y.tab.c $(CTFCONVO) $(ROOTPDIR): $(INS.dir) $(ROOTPDIR)/%: % $(ROOTPDIR) $(INS.file) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" $(ROOT)/usr/lib/fm: $(INS.dir) $(ROOT_EFT_ROOT): $(ROOT)/usr/lib/fm $(INS.dir) # Hammerhead: order-only prerequisite so $< is the file, not the directory $(ROOT_EFT_ROOT)/%: % | $(ROOT_EFT_ROOT) $(INS.file) # Hammerhead: order-only prerequisite so $< is the file, not the directory $(ROOT_EFT_DIR)/%: % | $(ROOT_EFT_DIR) $(INS.file) $(USR_PLAT_FM_DIR): $(INS.dir) $(USR_PLAT_EFT_DIR): $(USR_PLAT_FM_DIR) $(INS.dir) # Hammerhead: order-only prerequisite so $< is the file, not the directory $(USR_PLAT_EFT_DIR)/%: % | $(USR_PLAT_EFT_DIR) $(INS.file) # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # Copyright 2004 Sun Microsystems, Inc. All rights reserved. Use is subject to license terms. This file is usr/src/cmd/fma/eversholt/README. This is the top-level source directory for the eversholt fault diagnosis technology. The common directory contains files shared by the various eversholt components. The esc directory contains files specific to the eversholt compiler. On Solaris, the diagnosis engine is build as a plugin to the fault management daemon (fmd) in the directory: usr/src/cmd/fma/modules/common/eversholt /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * alloc.c -- memory allocation wrapper functions, replacable in more * constrained environments, such as within a DE. */ #include #include #include "alloc.h" #include "out.h" #include "stats.h" static struct stats *Malloctotal; static struct stats *Malloccount; void alloc_init(void) { Malloctotal = stats_new_counter("alloc.total", "bytes allocated", 1); Malloccount = stats_new_counter("alloc.calls", "total calls", 1); } void alloc_fini(void) { struct stats *mt, *mc; mt = Malloctotal; mc = Malloccount; Malloctotal = NULL; Malloccount = NULL; stats_delete(mt); stats_delete(mc); } /* * alloc_malloc -- a malloc() with checks * * this routine is typically called via the MALLOC() macro in alloc.h */ void * alloc_malloc(size_t nbytes, const char *fname, int line) { void *retval = malloc(nbytes); if (retval == NULL) outfl(O_DIE, fname, line, "malloc: out of memory"); if (Malloctotal) stats_counter_add(Malloctotal, nbytes); if (Malloccount) stats_counter_bump(Malloccount); return (retval); } /* * alloc_realloc -- a realloc() with checks * * this routine is typically called via the REALLOC() macro in alloc.h */ void * alloc_realloc(void *ptr, size_t nbytes, const char *fname, int line) { void *retval = realloc(ptr, nbytes); if (retval == NULL) out(O_DIE, fname, line, "realloc: out of memory"); return (retval); } /* * alloc_strdup -- a strdup() with checks * * this routine is typically called via the STRDUP() macro in alloc.h */ char * alloc_strdup(const char *ptr, const char *fname, int line) { char *retval = strdup(ptr); if (retval == NULL) outfl(O_DIE, fname, line, "strdup: out of memory"); return (retval); } /* * alloc_free -- a free() with checks * * this routine is typically called via the FREE() macro in alloc.h */ /*ARGSUSED1*/ void alloc_free(void *ptr, const char *fname, int line) { /* nothing to check in this version */ free(ptr); } /* * variants that don't maintain size in header - saves space */ void * alloc_xmalloc(size_t nbytes) { void *retval; retval = malloc(nbytes); if (retval == NULL) out(O_DIE, "malloc: out of memory"); if (Malloctotal) stats_counter_add(Malloctotal, nbytes); if (Malloccount) stats_counter_bump(Malloccount); return (retval); } /*ARGSUSED*/ void alloc_xfree(void *ptr, size_t size) { free(ptr); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * alloc.h -- public definitions for memory allocation module * */ #ifndef _ESC_COMMON_ALLOC_H #define _ESC_COMMON_ALLOC_H #ifdef __cplusplus extern "C" { #endif void alloc_init(void); void alloc_fini(void); void *alloc_realloc(void *ptr, size_t nbytes, const char *fname, int line); void *alloc_malloc(size_t nbytes, const char *fname, int line); void alloc_free(void *ptr, const char *fname, int line); char *alloc_strdup(const char *ptr, const char *fname, int line); void *alloc_xmalloc(size_t size); void alloc_xfree(void *ptr, size_t size); #ifdef DEBUG #define MALLOC(nbytes) alloc_malloc(nbytes, __FILE__, __LINE__) #define REALLOC(ptr, nbytes) alloc_realloc(ptr, nbytes, __FILE__, __LINE__) #define FREE(ptr) alloc_free(ptr, __FILE__, __LINE__) #define STRDUP(ptr) alloc_strdup(ptr, __FILE__, __LINE__) #else #define MALLOC(nbytes) alloc_malloc(nbytes, "???", __LINE__) #define REALLOC(ptr, nbytes) alloc_realloc(ptr, nbytes, "???", __LINE__) #define FREE(ptr) alloc_free(ptr, "???", __LINE__) #define STRDUP(ptr) alloc_strdup(ptr, "???", __LINE__) #endif #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_ALLOC_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * check.c -- routines for checking the prop tree * * this module provides semantic checks on the parse tree. most of * these checks happen during the construction of the parse tree, * when the various tree_X() routines call the various check_X() * routines. in a couple of special cases, a check function will * process the parse tree after it has been fully constructed. these * cases are noted in the comments above the check function. */ #include #include "out.h" #include "stable.h" #include "literals.h" #include "lut.h" #include "tree.h" #include "ptree.h" #include "check.h" static int check_reportlist(enum nodetype t, const char *s, struct node *np); static int check_num(enum nodetype t, const char *s, struct node *np); static int check_quote(enum nodetype t, const char *s, struct node *np); static int check_action(enum nodetype t, const char *s, struct node *np); static int check_num_func(enum nodetype t, const char *s, struct node *np); static int check_fru_asru(enum nodetype t, const char *s, struct node *np); static int check_engine(enum nodetype t, const char *s, struct node *np); static int check_count(enum nodetype t, const char *s, struct node *np); static int check_timeval(enum nodetype t, const char *s, struct node *np); static int check_id(enum nodetype t, const char *s, struct node *np); static int check_serd_method(enum nodetype t, const char *s, struct node *np); static int check_serd_id(enum nodetype t, const char *s, struct node *np); static int check_nork(struct node *np); static void check_cycle_lhs(struct node *stmtnp, struct node *arrow); static void check_cycle_lhs_try(struct node *stmtnp, struct node *lhs, struct node *rhs); static void check_cycle_rhs(struct node *rhs); static void check_proplists_lhs(enum nodetype t, struct node *lhs); static struct { enum nodetype t; const char *name; int required; int (*checker)(enum nodetype t, const char *s, struct node *np); int outflags; } Allowednames[] = { { T_FAULT, "FITrate", 0, check_num_func, O_ERR }, { T_FAULT, "FRU", 0, check_fru_asru, O_ERR }, { T_FAULT, "ASRU", 0, check_fru_asru, O_ERR }, { T_FAULT, "message", 0, check_num_func, O_ERR }, { T_FAULT, "retire", 0, check_num_func, O_ERR }, { T_FAULT, "response", 0, check_num_func, O_ERR }, { T_FAULT, "action", 0, check_action, O_ERR }, { T_FAULT, "count", 0, check_count, O_ERR }, { T_FAULT, "engine", 0, check_engine, O_ERR }, { T_UPSET, "engine", 0, check_engine, O_ERR }, { T_DEFECT, "FRU", 0, check_fru_asru, O_ERR }, { T_DEFECT, "ASRU", 0, check_fru_asru, O_ERR }, { T_DEFECT, "engine", 0, check_engine, O_ERR }, { T_DEFECT, "FITrate", 0, check_num_func, O_ERR }, { T_EREPORT, "poller", 0, check_id, O_ERR }, { T_EREPORT, "delivery", 0, check_timeval, O_ERR }, { T_EREPORT, "discard_if_config_unknown", 0, check_num, O_ERR }, { T_SERD, "N", 1, check_num, O_ERR }, { T_SERD, "T", 1, check_timeval, O_ERR }, { T_SERD, "method", 0, check_serd_method, O_ERR }, { T_SERD, "trip", 0, check_reportlist, O_ERR }, { T_SERD, "FRU", 0, check_fru_asru, O_ERR }, { T_SERD, "id", 0, check_serd_id, O_ERR }, { T_ERROR, "ASRU", 0, check_fru_asru, O_ERR }, { T_CONFIG, NULL, 0, check_quote, O_ERR }, { 0, NULL, 0 }, }; void check_init(void) { int i; for (i = 0; Allowednames[i].t; i++) if (Allowednames[i].name != NULL) Allowednames[i].name = stable(Allowednames[i].name); } void check_fini(void) { } /*ARGSUSED*/ void check_report_combination(struct node *np) { /* nothing to check for here. poller is only prop and it is optional */ } /* * check_path_iterators -- verify all iterators are explicit */ static void check_path_iterators(struct node *np) { if (np == NULL) return; switch (np->t) { case T_ARROW: check_path_iterators(np->u.arrow.lhs); check_path_iterators(np->u.arrow.rhs); break; case T_LIST: check_path_iterators(np->u.expr.left); check_path_iterators(np->u.expr.right); break; case T_EVENT: check_path_iterators(np->u.event.epname); break; case T_NAME: if (np->u.name.child == NULL) outfl(O_DIE, np->file, np->line, "internal error: check_path_iterators: " "unexpected implicit iterator: %s", np->u.name.s); check_path_iterators(np->u.name.next); break; default: outfl(O_DIE, np->file, np->line, "internal error: check_path_iterators: " "unexpected type: %s", ptree_nodetype2str(np->t)); } } void check_arrow(struct node *np) { ASSERTinfo(np->t == T_ARROW, ptree_nodetype2str(np->t)); if (np->u.arrow.lhs->t != T_ARROW && np->u.arrow.lhs->t != T_LIST && np->u.arrow.lhs->t != T_EVENT) { outfl(O_ERR, np->u.arrow.lhs->file, np->u.arrow.lhs->line, "%s not allowed on left-hand side of arrow", ptree_nodetype2str(np->u.arrow.lhs->t)); } if (!check_nork(np->u.arrow.nnp) || !check_nork(np->u.arrow.knp)) outfl(O_ERR, np->file, np->line, "counts associated with propagation arrows " "must be integers"); check_path_iterators(np); } /* * make sure the nork values are valid. * Nork values must be "A" for all(T_NAME), * a number(T_NUM), or a simple * expression(T_SUB, T_ADD, T_MUL, T_DIV) */ static int check_nork(struct node *np) { int rval = 0; /* NULL means no nork value which is allowed */ if (np == NULL) { rval = 1; } else { /* if the nork is a name it must be A for "All" */ if (np->t == T_NAME) if (*np->u.name.s == 'A') return (1); /* T_NUM allowed */ if (np->t == T_NUM) rval = 1; /* simple expressions allowed */ if (np->t == T_SUB || np->t == T_ADD || np->t == T_MUL || np->t == T_DIV) rval = 1; } return (rval); } static int check_reportlist(enum nodetype t, const char *s, struct node *np) { if (np == NULL) return (1); else if (np->t == T_EVENT) { if (np->u.event.ename->u.name.t != N_EREPORT) { outfl(O_ERR, np->file, np->line, "%s %s property must begin with \"ereport.\"", ptree_nodetype2str(t), s); } else if (tree_event2np_lut_lookup(Ereports, np) == NULL) { outfl(O_ERR, np->file, np->line, "%s %s property contains undeclared name", ptree_nodetype2str(t), s); } check_type_iterator(np); } else if (np->t == T_LIST) { (void) check_reportlist(t, s, np->u.expr.left); (void) check_reportlist(t, s, np->u.expr.right); } return (1); } static int check_num(enum nodetype t, const char *s, struct node *np) { ASSERTinfo(np != NULL, ptree_nodetype2str(t)); if (np->t != T_NUM) outfl(O_ERR, np->file, np->line, "%s %s property must be a single number", ptree_nodetype2str(t), s); return (1); } /*ARGSUSED1*/ static int check_quote(enum nodetype t, const char *s, struct node *np) { ASSERTinfo(np != NULL, ptree_nodetype2str(t)); if (np->t != T_QUOTE) outfl(O_ERR, np->file, np->line, "%s properties must be quoted strings", ptree_nodetype2str(t)); return (1); } static int check_action(enum nodetype t, const char *s, struct node *np) { ASSERTinfo(np != NULL, ptree_nodetype2str(t)); if (np->t != T_FUNC) outfl(O_ERR, np->file, np->line, "%s %s property must be a function or list of functions", ptree_nodetype2str(t), s); return (1); } static int check_num_func(enum nodetype t, const char *s, struct node *np) { ASSERTinfo(np != NULL, ptree_nodetype2str(t)); if (np->t != T_NUM && np->t != T_FUNC) outfl(O_ERR, np->file, np->line, "%s %s property must be a number or function", ptree_nodetype2str(t), s); return (1); } static int check_fru_asru(enum nodetype t, const char *s, struct node *np) { ASSERT(s != NULL); /* make sure it is a node type T_NAME? */ if (np->t == T_NAME) { if (s == L_ASRU) { if (tree_name2np_lut_lookup_name(ASRUs, np) == NULL) outfl(O_ERR, np->file, np->line, "ASRU property contains undeclared asru"); } else if (s == L_FRU) { if (tree_name2np_lut_lookup_name(FRUs, np) == NULL) outfl(O_ERR, np->file, np->line, "FRU property contains undeclared fru"); } else { outfl(O_ERR, np->file, np->line, "illegal property name in %s declaration: %s", ptree_nodetype2str(t), s); } check_type_iterator(np); } else outfl(O_ERR, np->file, np->line, "illegal type used for %s property: %s", s, ptree_nodetype2str(np->t)); return (1); } static int check_engine(enum nodetype t, const char *s, struct node *np) { ASSERTinfo(np != NULL, ptree_nodetype2str(t)); if (np->t != T_EVENT) outfl(O_ERR, np->file, np->line, "%s %s property must be an engine name " "(i.e. serd.x or serd.x@a/b)", ptree_nodetype2str(t), s); return (1); } static int check_count(enum nodetype t, const char *s, struct node *np) { ASSERTinfo(np != NULL, ptree_nodetype2str(t)); if (np->t != T_EVENT) outfl(O_ERR, np->file, np->line, "%s %s property must be an engine name " "(i.e. stat.x or stat.x@a/b)", ptree_nodetype2str(t), s); /* XXX confirm engine has been declared */ return (1); } static int check_timeval(enum nodetype t, const char *s, struct node *np) { ASSERTinfo(np != NULL, ptree_nodetype2str(t)); if (np->t != T_TIMEVAL) outfl(O_ERR, np->file, np->line, "%s %s property must be a number with time units", ptree_nodetype2str(t), s); return (1); } static int check_id(enum nodetype t, const char *s, struct node *np) { ASSERTinfo(np != NULL, ptree_nodetype2str(t)); if (np->t != T_NAME || np->u.name.next || np->u.name.child) outfl(O_ERR, np->file, np->line, "%s %s property must be simple name", ptree_nodetype2str(t), s); return (1); } static int check_serd_method(enum nodetype t, const char *s, struct node *np) { ASSERTinfo(np != NULL, ptree_nodetype2str(t)); if (np->t != T_NAME || np->u.name.next || np->u.name.child || (np->u.name.s != L_volatile && np->u.name.s != L_persistent)) outfl(O_ERR, np->file, np->line, "%s %s property must be \"volatile\" or \"persistent\"", ptree_nodetype2str(t), s); return (1); } static int check_serd_id(enum nodetype t, const char *s, struct node *np) { ASSERTinfo(np != NULL, ptree_nodetype2str(t)); if (np->t != T_GLOBID) outfl(O_ERR, np->file, np->line, "%s %s property must be a global ID", ptree_nodetype2str(t), s); return (1); } void check_stmt_required_properties(struct node *stmtnp) { struct lut *lutp = stmtnp->u.stmt.lutp; struct node *np = stmtnp->u.stmt.np; int i; for (i = 0; Allowednames[i].t; i++) if (stmtnp->t == Allowednames[i].t && Allowednames[i].required && tree_s2np_lut_lookup(lutp, Allowednames[i].name) == NULL) outfl(Allowednames[i].outflags, np->file, np->line, "%s statement missing property: %s", ptree_nodetype2str(stmtnp->t), Allowednames[i].name); } void check_stmt_allowed_properties(enum nodetype t, struct node *nvpairnp, struct lut *lutp) { int i; const char *s = nvpairnp->u.expr.left->u.name.s; struct node *np; for (i = 0; Allowednames[i].t; i++) if (t == Allowednames[i].t && Allowednames[i].name == NULL) { /* NULL name means just call checker */ (*Allowednames[i].checker)(t, s, nvpairnp->u.expr.right); return; } else if (t == Allowednames[i].t && s == Allowednames[i].name) break; if (Allowednames[i].name == NULL) outfl(O_ERR, nvpairnp->file, nvpairnp->line, "illegal property name in %s declaration: %s", ptree_nodetype2str(t), s); else if ((np = tree_s2np_lut_lookup(lutp, s)) != NULL) { /* * redeclaring prop is allowed if value is the same */ if (np->t != nvpairnp->u.expr.right->t) outfl(O_ERR, nvpairnp->file, nvpairnp->line, "property redeclared (with differnt type) " "in %s declaration: %s", ptree_nodetype2str(t), s); switch (np->t) { case T_NUM: case T_TIMEVAL: if (np->u.ull == nvpairnp->u.expr.right->u.ull) return; break; case T_NAME: if (tree_namecmp(np, nvpairnp->u.expr.right) == 0) return; break; case T_EVENT: if (tree_eventcmp(np, nvpairnp->u.expr.right) == 0) return; break; default: outfl(O_ERR, nvpairnp->file, nvpairnp->line, "value for property \"%s\" is an " "invalid type: %s", nvpairnp->u.expr.left->u.name.s, ptree_nodetype2str(np->t)); return; } outfl(O_ERR, nvpairnp->file, nvpairnp->line, "property redeclared in %s declaration: %s", ptree_nodetype2str(t), s); } else (*Allowednames[i].checker)(t, s, nvpairnp->u.expr.right); } void check_propnames(enum nodetype t, struct node *np, int from, int to) { struct node *dnp; struct lut *lutp; ASSERT(np != NULL); ASSERTinfo(np->t == T_EVENT || np->t == T_LIST || np->t == T_ARROW, ptree_nodetype2str(np->t)); if (np->t == T_EVENT) { switch (np->u.event.ename->u.name.t) { case N_UNSPEC: outfl(O_ERR, np->file, np->line, "name in %s statement must begin with " "type (example: \"error.\")", ptree_nodetype2str(t)); return; case N_FAULT: lutp = Faults; if (to) { outfl(O_ERR, np->file, np->line, "%s has fault on right side of \"->\"", ptree_nodetype2str(t)); return; } if (!from) { outfl(O_DIE, np->file, np->line, "internal error: %s has fault without " "from flag", ptree_nodetype2str(t)); } break; case N_UPSET: lutp = Upsets; if (to) { outfl(O_ERR, np->file, np->line, "%s has upset on right side of \"->\"", ptree_nodetype2str(t)); return; } if (!from) outfl(O_DIE, np->file, np->line, "internal error: %s has upset without " "from flag", ptree_nodetype2str(t)); break; case N_DEFECT: lutp = Defects; if (to) { outfl(O_ERR, np->file, np->line, "%s has defect on right side of \"->\"", ptree_nodetype2str(t)); return; } if (!from) { outfl(O_DIE, np->file, np->line, "internal error: %s has defect without " "from flag", ptree_nodetype2str(t)); } break; case N_ERROR: lutp = Errors; if (!from && !to) outfl(O_DIE, np->file, np->line, "%s has error without from or to flags", ptree_nodetype2str(t)); break; case N_EREPORT: lutp = Ereports; if (from) { outfl(O_ERR, np->file, np->line, "%s has report on left side of \"->\"", ptree_nodetype2str(t)); return; } if (!to) outfl(O_DIE, np->file, np->line, "internal error: %s has report without " "to flag", ptree_nodetype2str(t)); break; default: outfl(O_DIE, np->file, np->line, "internal error: check_propnames: " "unexpected type: %d", np->u.name.t); } if ((dnp = tree_event2np_lut_lookup(lutp, np)) == NULL) { outfl(O_ERR, np->file, np->line, "%s statement contains undeclared event", ptree_nodetype2str(t)); } else dnp->u.stmt.flags |= STMT_REF; np->u.event.declp = dnp; } else if (np->t == T_LIST) { check_propnames(t, np->u.expr.left, from, to); check_propnames(t, np->u.expr.right, from, to); } else if (np->t == T_ARROW) { check_propnames(t, np->u.arrow.lhs, 1, to); check_propnames(t, np->u.arrow.rhs, from, 1); } } static struct lut * record_iterators(struct node *np, struct lut *ex) { if (np == NULL) return (ex); switch (np->t) { case T_ARROW: ex = record_iterators(np->u.arrow.lhs, ex); ex = record_iterators(np->u.arrow.rhs, ex); break; case T_LIST: ex = record_iterators(np->u.expr.left, ex); ex = record_iterators(np->u.expr.right, ex); break; case T_EVENT: ex = record_iterators(np->u.event.epname, ex); break; case T_NAME: if (np->u.name.child && np->u.name.child->t == T_NAME) ex = lut_add(ex, (void *) np->u.name.child->u.name.s, (void *) np, NULL); ex = record_iterators(np->u.name.next, ex); break; default: outfl(O_DIE, np->file, np->line, "record_iterators: internal error: unexpected type: %s", ptree_nodetype2str(np->t)); } return (ex); } void check_exprscope(struct node *np, struct lut *ex) { if (np == NULL) return; switch (np->t) { case T_EVENT: check_exprscope(np->u.event.eexprlist, ex); break; case T_ARROW: check_exprscope(np->u.arrow.lhs, ex); check_exprscope(np->u.arrow.rhs, ex); break; case T_NAME: if (np->u.name.child && np->u.name.child->t == T_NAME) { if (lut_lookup(ex, (void *) np->u.name.child->u.name.s, NULL) == NULL) outfl(O_ERR, np->file, np->line, "constraint contains undefined" " iterator: %s", np->u.name.child->u.name.s); } check_exprscope(np->u.name.next, ex); break; case T_QUOTE: case T_GLOBID: break; case T_ASSIGN: case T_NE: case T_EQ: case T_LIST: case T_AND: case T_OR: case T_NOT: case T_ADD: case T_SUB: case T_MUL: case T_DIV: case T_MOD: case T_LT: case T_LE: case T_GT: case T_GE: case T_BITAND: case T_BITOR: case T_BITXOR: case T_BITNOT: case T_LSHIFT: case T_RSHIFT: case T_CONDIF: case T_CONDELSE: check_exprscope(np->u.expr.left, ex); check_exprscope(np->u.expr.right, ex); break; case T_FUNC: check_exprscope(np->u.func.arglist, ex); break; case T_NUM: case T_TIMEVAL: break; default: outfl(O_DIE, np->file, np->line, "check_exprscope: internal error: unexpected type: %s", ptree_nodetype2str(np->t)); } } /* * check_propscope -- check constraints for out of scope variable refs */ void check_propscope(struct node *np) { struct lut *ex; ex = record_iterators(np, NULL); check_exprscope(np, ex); lut_free(ex, NULL, NULL); } /* * check_upset_engine -- validate the engine property in an upset statement * * we do this after the full parse tree has been constructed rather than while * building the parse tree because it is inconvenient for the user if we * require SERD engines to be declared before used in an upset "engine" * property. */ /*ARGSUSED*/ void check_upset_engine(struct node *lhs, struct node *rhs, void *arg) { enum nodetype t = (enum nodetype)arg; struct node *engnp; struct node *declp; ASSERTeq(rhs->t, t, ptree_nodetype2str); if ((engnp = tree_s2np_lut_lookup(rhs->u.stmt.lutp, L_engine)) == NULL) return; ASSERT(engnp->t == T_EVENT); if ((declp = tree_event2np_lut_lookup(SERDs, engnp)) == NULL) { outfl(O_ERR, engnp->file, engnp->line, "%s %s property contains undeclared name", ptree_nodetype2str(t), L_engine); return; } engnp->u.event.declp = declp; } /* * check_refcount -- see if declared names are used * * this is run after the entire parse tree is constructed, so a refcount * of zero means the name has been declared but otherwise not used. */ void check_refcount(struct node *lhs, struct node *rhs, void *arg) { enum nodetype t = (enum nodetype)arg; ASSERTeq(rhs->t, t, ptree_nodetype2str); if (rhs->u.stmt.flags & STMT_REF) return; outfl(O_WARN|O_NONL, rhs->file, rhs->line, "%s name declared but not used: ", ptree_nodetype2str(t)); ptree_name(O_WARN|O_NONL, lhs); out(O_WARN, NULL); } /* * set check_cycle_warninglevel only for val >= 0 */ int check_cycle_level(long long val) { static int check_cycle_warninglevel = -1; if (val == 0) check_cycle_warninglevel = 0; else if (val > 0) check_cycle_warninglevel = 1; return (check_cycle_warninglevel); } /* * check_cycle -- see props from an error have cycles * * this is run after the entire parse tree is constructed, for * each error that has been declared. */ /*ARGSUSED*/ void check_cycle(struct node *lhs, struct node *rhs, void *arg) { struct node *np; ASSERTeq(rhs->t, T_ERROR, ptree_nodetype2str); if (rhs->u.stmt.flags & STMT_CYCLE) return; /* already reported this cycle */ if (rhs->u.stmt.flags & STMT_CYMARK) { #ifdef ESC int warninglevel; warninglevel = check_cycle_level(-1); if (warninglevel <= 0) { int olevel = O_ERR; if (warninglevel == 0) olevel = O_WARN; out(olevel|O_NONL, "cycle in propagation tree: "); ptree_name(olevel|O_NONL, rhs->u.stmt.np); out(olevel, NULL); } #endif /* ESC */ rhs->u.stmt.flags |= STMT_CYCLE; } rhs->u.stmt.flags |= STMT_CYMARK; /* for each propagation */ for (np = Props; np; np = np->u.stmt.next) check_cycle_lhs(rhs, np->u.stmt.np); rhs->u.stmt.flags &= ~STMT_CYMARK; } /* * check_cycle_lhs -- find the lhs of an arrow for cycle checking */ static void check_cycle_lhs(struct node *stmtnp, struct node *arrow) { struct node *trylhs; struct node *tryrhs; /* handle cascaded arrows */ switch (arrow->u.arrow.lhs->t) { case T_ARROW: /* first recurse left */ check_cycle_lhs(stmtnp, arrow->u.arrow.lhs); /* * return if there's a list of events internal to * cascaded props (which is not allowed) */ if (arrow->u.arrow.lhs->u.arrow.rhs->t != T_EVENT) return; /* then try this arrow (thing cascaded *to*) */ trylhs = arrow->u.arrow.lhs->u.arrow.rhs; tryrhs = arrow->u.arrow.rhs; break; case T_EVENT: case T_LIST: trylhs = arrow->u.arrow.lhs; tryrhs = arrow->u.arrow.rhs; break; default: out(O_DIE, "lhs: unexpected type: %s", ptree_nodetype2str(arrow->u.arrow.lhs->t)); /*NOTREACHED*/ } check_cycle_lhs_try(stmtnp, trylhs, tryrhs); } /* * check_cycle_lhs_try -- try matching an event name on lhs of an arrow */ static void check_cycle_lhs_try(struct node *stmtnp, struct node *lhs, struct node *rhs) { if (lhs->t == T_LIST) { check_cycle_lhs_try(stmtnp, lhs->u.expr.left, rhs); check_cycle_lhs_try(stmtnp, lhs->u.expr.right, rhs); return; } ASSERT(lhs->t == T_EVENT); if (tree_eventcmp(stmtnp->u.stmt.np, lhs) != 0) return; /* no match */ check_cycle_rhs(rhs); } /* * check_cycle_rhs -- foreach error on rhs, see if we cycle to a marked error */ static void check_cycle_rhs(struct node *rhs) { struct node *dnp; if (rhs->t == T_LIST) { check_cycle_rhs(rhs->u.expr.left); check_cycle_rhs(rhs->u.expr.right); return; } ASSERT(rhs->t == T_EVENT); if (rhs->u.event.ename->u.name.t != N_ERROR) return; if ((dnp = tree_event2np_lut_lookup(Errors, rhs)) == NULL) { outfl(O_ERR|O_NONL, rhs->file, rhs->line, "unexpected undeclared event during cycle check"); ptree_name(O_ERR|O_NONL, rhs); out(O_ERR, NULL); return; } check_cycle(NULL, dnp, 0); } /* * Force iterators to be simple names, expressions, or numbers */ void check_name_iterator(struct node *np) { if (np->u.name.child->t != T_NUM && np->u.name.child->t != T_NAME && np->u.name.child->t != T_CONDIF && np->u.name.child->t != T_SUB && np->u.name.child->t != T_ADD && np->u.name.child->t != T_MUL && np->u.name.child->t != T_DIV && np->u.name.child->t != T_MOD && np->u.name.child->t != T_LSHIFT && np->u.name.child->t != T_RSHIFT) { outfl(O_ERR|O_NONL, np->file, np->line, "invalid iterator: "); ptree_name_iter(O_ERR|O_NONL, np); out(O_ERR, NULL); } } /* * Iterators on a declaration may only be implicit */ void check_type_iterator(struct node *np) { while (np != NULL) { if (np->t == T_EVENT) { np = np->u.event.epname; } else if (np->t == T_NAME) { if (np->u.name.child != NULL && np->u.name.child->t != T_NUM) { outfl(O_ERR|O_NONL, np->file, np->line, "explicit iterators disallowed " "in declarations: "); ptree_name_iter(O_ERR|O_NONL, np); out(O_ERR, NULL); } np = np->u.name.next; } else { break; } } } void check_cat_list(struct node *np) { if (np->t == T_FUNC) check_func(np); else if (np->t == T_LIST) { check_cat_list(np->u.expr.left); check_cat_list(np->u.expr.right); } } void check_func(struct node *np) { struct node *arglist = np->u.func.arglist; ASSERTinfo(np->t == T_FUNC, ptree_nodetype2str(np->t)); if (np->u.func.s == L_within) { switch (arglist->t) { case T_NUM: if (arglist->u.ull != 0ULL) { outfl(O_ERR, arglist->file, arglist->line, "parameter of within must be 0" ", \"infinity\" or a time value."); } break; case T_NAME: if (arglist->u.name.s != L_infinity) { outfl(O_ERR, arglist->file, arglist->line, "parameter of within must be 0" ", \"infinity\" or a time value."); } break; case T_LIST: /* * if two parameters, the left or min must be * either T_NUM or T_TIMEVAL */ if (arglist->u.expr.left->t != T_NUM && arglist->u.expr.left->t != T_TIMEVAL) { outfl(O_ERR, arglist->file, arglist->line, "first parameter of within must be" " either a time value or zero."); } /* * if two parameters, the right or max must * be either T_NUM, T_NAME or T_TIMEVAL */ if (arglist->u.expr.right->t != T_NUM && arglist->u.expr.right->t != T_TIMEVAL && arglist->u.expr.right->t != T_NAME) { outfl(O_ERR, arglist->file, arglist->line, "second parameter of within must " "be 0, \"infinity\" or time value."); } /* * if right or left is a T_NUM it must * be zero */ if ((arglist->u.expr.left->t == T_NUM) && (arglist->u.expr.left->u.ull != 0ULL)) { outfl(O_ERR, arglist->file, arglist->line, "within parameter must be " "0 or a time value."); } if ((arglist->u.expr.right->t == T_NUM) && (arglist->u.expr.right->u.ull != 0ULL)) { outfl(O_ERR, arglist->file, arglist->line, "within parameter must be " "0 or a time value."); } /* if right is a T_NAME it must be "infinity" */ if ((arglist->u.expr.right->t == T_NAME) && (arglist->u.expr.right->u.name.s != L_infinity)) { outfl(O_ERR, arglist->file, arglist->line, "\"infinity\" is the only " "valid name for within parameter."); } /* * the first parameter [min] must not be greater * than the second parameter [max]. */ if (arglist->u.expr.left->u.ull > arglist->u.expr.right->u.ull) { outfl(O_ERR, arglist->file, arglist->line, "the first value (min) of" " within must be less than" " the second (max) value"); } break; case T_TIMEVAL: break; /* no restrictions on T_TIMEVAL */ default: outfl(O_ERR, arglist->file, arglist->line, "parameter of within must be 0" ", \"infinity\" or a time value."); } } else if (np->u.func.s == L_call) { if (arglist->t != T_QUOTE && arglist->t != T_LIST && arglist->t != T_GLOBID && arglist->t != T_CONDIF && arglist->t != T_LIST && arglist->t != T_FUNC) outfl(O_ERR, arglist->file, arglist->line, "invalid first argument to call()"); } else if (np->u.func.s == L_fru) { if (arglist->t != T_NAME) outfl(O_ERR, arglist->file, arglist->line, "argument to fru() must be a path"); } else if (np->u.func.s == L_asru) { if (arglist->t != T_NAME) outfl(O_ERR, arglist->file, arglist->line, "argument to asru() must be a path"); } else if (np->u.func.s == L_is_connected || np->u.func.s == L_is_under) { if (arglist->t == T_LIST && (arglist->u.expr.left->t == T_NAME || arglist->u.expr.left->t == T_FUNC) && (arglist->u.expr.right->t == T_NAME || arglist->u.expr.right->t == T_FUNC)) { if (arglist->u.expr.left->t == T_FUNC) check_func(arglist->u.expr.left); if (arglist->u.expr.right->t == T_FUNC) check_func(arglist->u.expr.right); } else { outfl(O_ERR, arglist->file, arglist->line, "%s() must have paths or calls to " "fru() and/or asru() as arguments", np->u.func.s); } } else if (np->u.func.s == L_is_on) { if (arglist->t == T_NAME || arglist->t == T_FUNC) { if (arglist->t == T_FUNC) check_func(arglist); } else { outfl(O_ERR, arglist->file, arglist->line, "argument to is_on() must be a path or a call to " "fru() or asru()"); } } else if (np->u.func.s == L_is_present) { if (arglist->t == T_NAME || arglist->t == T_FUNC) { if (arglist->t == T_FUNC) check_func(arglist); } else { outfl(O_ERR, arglist->file, arglist->line, "argument to is_present() must be a path or a call " "to fru() or asru()"); } } else if (np->u.func.s == L_has_fault) { if (arglist->t == T_LIST && (arglist->u.expr.left->t == T_NAME || arglist->u.expr.left->t == T_FUNC) && arglist->u.expr.right->t == T_QUOTE) { if (arglist->u.expr.left->t == T_FUNC) check_func(arglist->u.expr.left); } else { outfl(O_ERR, arglist->file, arglist->line, "%s() must have path or call to " "fru() and/or asru() as first argument; " "second argument must be a string", np->u.func.s); } } else if (np->u.func.s == L_is_type) { if (arglist->t == T_NAME || arglist->t == T_FUNC) { if (arglist->t == T_FUNC) check_func(arglist); } else { outfl(O_ERR, arglist->file, arglist->line, "argument to is_type() must be a path or a call to " "fru() or asru()"); } } else if (np->u.func.s == L_confcall) { if (arglist->t != T_QUOTE && (arglist->t != T_LIST || arglist->u.expr.left->t != T_QUOTE)) outfl(O_ERR, arglist->file, arglist->line, "confcall(): first argument must be a string " "(the name of the operation)"); } else if (np->u.func.s == L_confprop || np->u.func.s == L_confprop_defined) { if (arglist->t == T_LIST && (arglist->u.expr.left->t == T_NAME || arglist->u.expr.left->t == T_FUNC) && arglist->u.expr.right->t == T_QUOTE) { if (arglist->u.expr.left->t == T_FUNC) check_func(arglist->u.expr.left); } else { outfl(O_ERR, arglist->file, arglist->line, "%s(): first argument must be a path or a call to " "fru() or asru(); " "second argument must be a string", np->u.func.s); } } else if (np->u.func.s == L_count) { if (arglist->t != T_EVENT) { outfl(O_ERR, arglist->file, arglist->line, "count(): argument must be an engine name"); } } else if (np->u.func.s == L_defined) { if (arglist->t != T_GLOBID) outfl(O_ERR, arglist->file, arglist->line, "argument to defined() must be a global"); } else if (np->u.func.s == L_payloadprop) { if (arglist->t != T_QUOTE) outfl(O_ERR, arglist->file, arglist->line, "argument to payloadprop() must be a string"); } else if (np->u.func.s == L_payloadprop_contains) { if (arglist->t != T_LIST || arglist->u.expr.left->t != T_QUOTE || arglist->u.expr.right == NULL) outfl(O_ERR, arglist->file, arglist->line, "args to payloadprop_contains(): must be a quoted " "string (property name) and an expression " "(to match)"); } else if (np->u.func.s == L_payloadprop_defined) { if (arglist->t != T_QUOTE) outfl(O_ERR, arglist->file, arglist->line, "arg to payloadprop_defined(): must be a quoted " "string"); } else if (np->u.func.s == L_setpayloadprop) { if (arglist->t == T_LIST && arglist->u.expr.left->t == T_QUOTE) { if (arglist->u.expr.right->t == T_FUNC) check_func(arglist->u.expr.right); } else { outfl(O_ERR, arglist->file, arglist->line, "setpayloadprop(): " "first arg must be a string, " "second arg a value"); } } else if (np->u.func.s == L_setserdn || np->u.func.s == L_setserdt || np->u.func.s == L_setserdsuffix || np->u.func.s == L_setserdincrement) { if (arglist->t == T_FUNC) check_func(arglist); } else if (np->u.func.s == L_cat) { check_cat_list(arglist); } else if (np->u.func.s == L_envprop) { if (arglist->t != T_QUOTE) outfl(O_ERR, arglist->file, arglist->line, "argument to envprop() must be a string"); } else outfl(O_WARN, np->file, np->line, "possible platform-specific function: %s", np->u.func.s); } void check_expr(struct node *np) { ASSERT(np != NULL); switch (np->t) { case T_ASSIGN: ASSERT(np->u.expr.left != NULL); if (np->u.expr.left->t != T_GLOBID) outfl(O_ERR, np->file, np->line, "assignment only allowed to globals (e.g. $a)"); break; } } void check_event(struct node *np) { ASSERT(np != NULL); ASSERTinfo(np->t == T_EVENT, ptree_nodetype2str(np->t)); if (np->u.event.epname == NULL) { outfl(O_ERR|O_NONL, np->file, np->line, "pathless events not allowed: "); ptree_name(O_ERR|O_NONL, np->u.event.ename); out(O_ERR, NULL); } } /* * check for properties that are required on declarations. This * should be done after all declarations since they can be * redeclared with a different set of properties. */ /*ARGSUSED*/ void check_required_props(struct node *lhs, struct node *rhs, void *arg) { ASSERTeq(rhs->t, (enum nodetype)arg, ptree_nodetype2str); check_stmt_required_properties(rhs); } /* * check that cascading prop statements do not contain lists internally. * the first and last event lists in the cascading prop may be single * events or lists of events. */ /*ARGSUSED*/ void check_proplists(enum nodetype t, struct node *np) { ASSERT(np->t == T_ARROW); /* * not checking the right hand side of the top level prop * since it is the last part of the propagation and can be * an event or list of events */ check_proplists_lhs(t, np->u.arrow.lhs); } /*ARGSUSED*/ static void check_proplists_lhs(enum nodetype t, struct node *lhs) { if (lhs->t == T_ARROW) { if (lhs->u.arrow.rhs->t == T_LIST) { outfl(O_ERR, lhs->file, lhs->line, "lists are not allowed internally on cascading %s", (t == T_PROP) ? "propagations" : "masks"); } check_proplists_lhs(t, lhs->u.arrow.lhs); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * check.h -- public definitions for check module * * the checking functions are called by the tree_X() functions * in tree.c. this header file exports the checking functions * from check.c so that tree.c can see them. nobody else uses them. */ #ifndef _ESC_COMMON_CHECK_H #define _ESC_COMMON_CHECK_H #ifdef __cplusplus extern "C" { #endif void check_init(void); void check_fini(void); void check_report_combination(struct node *np); void check_arrow(struct node *np); void check_stmt_required_properties(struct node *stmtnp); void check_stmt_allowed_properties(enum nodetype t, struct node *nvpairnp, struct lut *lutp); void check_propnames(enum nodetype t, struct node *np, int from, int to); void check_propscope(struct node *np); void check_proplists(enum nodetype t, struct node *np); void check_upset_engine(struct node *lhs, struct node *rhs, void *arg); void check_refcount(struct node *lhs, struct node *rhs, void *arg); int check_cycle_level(long long val); void check_cycle(struct node *lhs, struct node *rhs, void *arg); void check_type_iterator(struct node *np); void check_name_iterator(struct node *np); void check_func(struct node *np); void check_expr(struct node *np); void check_event(struct node *np); void check_required_props(struct node *lhs, struct node *rhs, void *arg); #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_CHECK_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * eft.h -- public definitions for eft files * */ #ifndef _ESC_COMMON_EFT_H #define _ESC_COMMON_EFT_H #ifdef __cplusplus extern "C" { #endif #include /* eft file header */ #define EFT_HDR_MAGIC 0x45465400 #define EFT_HDR_MAJOR 3 #define EFT_HDR_MINOR 1 #define EFT_HDR_MAXCOMMENT 256 struct eftheader { uint32_t magic; uint16_t major; uint16_t minor; uint16_t cmajor; uint16_t cminor; uint32_t identlen; uint32_t dictlen; uint32_t unused[2]; uint32_t csum; char comment[EFT_HDR_MAXCOMMENT]; }; #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_EFT_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * eftread.c -- routines for reading .eft files * */ #include #include #include #include #include #include #include #include #include "out.h" #include "stable.h" #include "lut.h" #include "tree.h" #include "eft.h" #include "eftread.h" #include "esclex.h" #include "version.h" #include "ptree.h" /* for uintX_t, htonl(), etc */ #include #include #include #ifndef MIN #define MIN(x, y) ((x) <= (y) ? (x) : (y)) #endif static int Showheader; /* * eftread_showheader -- set showheader flag * */ void eftread_showheader(int newval) { Showheader = newval; } /* * eftread_fopen -- fopen an EFT file for reading * */ FILE * eftread_fopen(const char *fname, char *idbuf, size_t idbufsz) { FILE *fp; FILE *tfp; struct eftheader hdr; #define BUFLEN 8192 char buf[BUFLEN]; int cc; uint32_t csum = 0; char *ptr; if ((ptr = strrchr(fname, '.')) == NULL || strcmp(ptr, ".eft") != 0) { out(O_ERR, "%s: not a valid EFT (bad extension)", fname); return (NULL); } if ((fp = fopen(fname, "r")) == NULL) { out(O_ERR|O_SYS, "%s", fname); return (NULL); } if (fread(&hdr, 1, sizeof (hdr), fp) < sizeof (hdr)) { (void) fclose(fp); out(O_ERR, "%s: not a valid EFT (too short)", fname); return (NULL); } hdr.magic = ntohl(hdr.magic); hdr.major = ntohs(hdr.major); hdr.minor = ntohs(hdr.minor); hdr.cmajor = ntohs(hdr.cmajor); hdr.cminor = ntohs(hdr.cminor); hdr.identlen = ntohl(hdr.identlen); hdr.dictlen = ntohl(hdr.dictlen); hdr.csum = ntohl(hdr.csum); if (Showheader) out(O_VERB, "%s: magic %x EFT version %d.%d esc version %d.%d", fname, hdr.magic, hdr.major, hdr.minor, hdr.cmajor, hdr.cminor); if (hdr.magic != EFT_HDR_MAGIC) { (void) fclose(fp); out(O_ERR, "%s: not a valid EFT (bad magic)", fname); return (NULL); } if (hdr.major != EFT_HDR_MAJOR || hdr.minor > EFT_HDR_MINOR) { (void) fclose(fp); out(O_ERR, "%s is version %d.%d, " "this program supports up to %d.%d", fname, hdr.major, hdr.minor, EFT_HDR_MAJOR, EFT_HDR_MINOR); return (NULL); } bzero(idbuf, idbufsz); if (hdr.identlen != 0) { long npos = ftell(fp) + (long)hdr.identlen; /* after ident */ size_t rsz = MIN(hdr.identlen, idbufsz - 1); if (fread(idbuf, 1, rsz, fp) != rsz) out(O_DIE|O_SYS, "%s: fread", fname); if (fseek(fp, npos, SEEK_SET) == -1) out(O_DIE|O_SYS, "%s: fseek", fname); } if (hdr.dictlen && (hdr.dictlen < 2 || hdr.dictlen > 1000)) { (void) fclose(fp); out(O_ERR, "%s: bad dictlen: %d", fname, hdr.dictlen); return (NULL); } /* read in dict strings */ if (hdr.dictlen) { char *dbuf = alloca(hdr.dictlen); char *dptr; if ((cc = fread(dbuf, 1, hdr.dictlen, fp)) != hdr.dictlen) out(O_DIE|O_SYS, "short fread on %s (dictlen %d)", fname, hdr.dictlen); /* work from end of string array backwards, finding names */ for (dptr = &dbuf[hdr.dictlen - 2]; dptr > dbuf; dptr--) if (*dptr == '\0') { /* found separator, record string */ Dicts = lut_add(Dicts, (void *)stable(dptr + 1), (void *)0, NULL); } /* record the first string */ Dicts = lut_add(Dicts, (void *)stable(dptr), (void *)0, NULL); } if ((tfp = tmpfile()) == NULL) out(O_DIE|O_SYS, "cannot create temporary file"); while ((cc = fread(buf, 1, BUFLEN, fp)) > 0) { char *ptr; for (ptr = buf; ptr < &buf[cc]; ptr++) { *ptr = ~((unsigned char)*ptr); csum += (uint32_t)*ptr; } if (cc != fwrite(buf, 1, cc, tfp) || ferror(tfp)) out(O_DIE|O_SYS, "fwrite on tmpfile"); } if (ferror(fp)) out(O_DIE|O_SYS, "fread on %s", fname); (void) fclose(fp); if (hdr.csum != csum) { out(O_ERR, "%s: bad checksum (%x != %x)", fname, hdr.csum, csum); (void) fclose(tfp); return (NULL); } if (Showheader) { int len = strlen(hdr.comment); if (len > 0 && hdr.comment[len - 1] == '\n') hdr.comment[len - 1] = '\0'; out(O_OK, "%s:\n\t%s", fname, hdr.comment); } rewind(tfp); return (tfp); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * eftread.h -- public definitions for eftread module * */ #ifndef _ESC_COMMON_EFTREAD_H #define _ESC_COMMON_EFTREAD_H #ifdef __cplusplus extern "C" { #endif void eftread_showheader(int newval); FILE *eftread_fopen(const char *fname, char *idbuf, size_t idbufsz); #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_EFTREAD_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * eftwrite.c -- routines for writing .eft files * * this module emits the table resulting from compilation of the * source files. this code done nothing unless the -o option * was given on the command line. */ #include #include #include #include #include #include "out.h" #include "stats.h" #include "stable.h" #include "lut.h" #include "tree.h" #include "eft.h" #include "eftwrite.h" #include "esclex.h" #include "version.h" #include "ptree.h" /* for uintX_t, htonl(), etc */ #include #include #include extern char Args[]; static struct stats *Outbytes; static int Identlen; static int Dictlen; void eftwrite_init(void) { Outbytes = stats_new_counter("eftwrite.total", "bytes written", 1); } /*ARGSUSED*/ static void ident_lencalc(const char *s, void *rhs, void *arg) { Identlen += strlen(s) + 1; } /*ARGSUSED*/ static void dict_lencalc(const char *s, void *rhs, void *arg) { Dictlen += strlen(s) + 1; } /*ARGSUSED*/ static void ident_printer(const char *s, void *rhs, void *arg) { FILE *fp = (FILE *)arg; (void) fwrite(s, strlen(s) + 1, 1, fp); } /*ARGSUSED*/ static void dict_printer(const char *s, void *rhs, void *arg) { FILE *fp = (FILE *)arg; (void) fwrite(s, strlen(s) + 1, 1, fp); } void eftwrite(const char *fname) { FILE *fp; FILE *tfp; struct eftheader hdr; #define BUFLEN 8192 char buf[BUFLEN]; int cc; if ((tfp = tmpfile()) == NULL) out(O_DIE|O_SYS, "cannot create temporary file"); /* XXX switch stdout to tfp temporarily */ /* XXX for now */ out_altfp(tfp); ptree(O_ALTFP, tree_root(NULL), 0, 1); rewind(tfp); lut_walk(Ident, (lut_cb)ident_lencalc, (void *)0); lut_walk(Dicts, (lut_cb)dict_lencalc, (void *)0); bzero(&hdr, sizeof (hdr)); hdr.magic = EFT_HDR_MAGIC; hdr.major = EFT_HDR_MAJOR; hdr.minor = EFT_HDR_MINOR; hdr.cmajor = VERSION_MAJOR; hdr.cminor = VERSION_MINOR; hdr.identlen = Identlen; hdr.dictlen = Dictlen; buf[BUFLEN - 1] = '\0'; #ifdef DEBUG (void) snprintf(hdr.comment, EFT_HDR_MAXCOMMENT, "Built using esc-%d.%d\tArgs: \"%s\"\n", VERSION_MAJOR, VERSION_MINOR, Args); #else (void) snprintf(hdr.comment, EFT_HDR_MAXCOMMENT, "Built using esc-%d.%d\n", VERSION_MAJOR, VERSION_MINOR); #endif if ((fp = fopen(fname, "w")) == NULL) out(O_DIE|O_SYS, "can't open output file: %s", fname); while ((cc = fread(buf, 1, BUFLEN, tfp)) > 0) { char *ptr; for (ptr = buf; ptr < &buf[cc]; ptr++) hdr.csum += (uint32_t)*ptr; } if (ferror(tfp)) out(O_DIE|O_SYS, "fread on tmpfile"); rewind(tfp); hdr.magic = htonl(hdr.magic); hdr.major = htons(hdr.major); hdr.minor = htons(hdr.minor); hdr.cmajor = htons(hdr.cmajor); hdr.cminor = htons(hdr.cminor); hdr.identlen = htonl(hdr.identlen); hdr.dictlen = htonl(hdr.dictlen); hdr.csum = htonl(hdr.csum); (void) fwrite(&hdr, sizeof (hdr), 1, fp); if (ferror(fp)) out(O_DIE|O_SYS, "%s: can't write header", fname); stats_counter_add(Outbytes, sizeof (hdr)); lut_walk(Ident, (lut_cb)ident_printer, (void *)fp); stats_counter_add(Outbytes, Identlen); lut_walk(Dicts, (lut_cb)dict_printer, (void *)fp); stats_counter_add(Outbytes, Dictlen); while ((cc = fread(buf, 1, BUFLEN, tfp)) > 0) { char *ptr; for (ptr = buf; ptr < &buf[cc]; ptr++) *ptr = ~((unsigned char)*ptr); if (cc != fwrite(buf, 1, cc, fp) || ferror(fp)) out(O_DIE|O_SYS, "fwrite on %s", fname); stats_counter_add(Outbytes, cc); } if (ferror(tfp)) out(O_DIE|O_SYS, "fread on tmpfile"); (void) fclose(tfp); (void) fclose(fp); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * eftwrite.h -- public definitions for eftwrite module * */ #ifndef _ESC_COMMON_EFTWRITE_H #define _ESC_COMMON_EFTWRITE_H #ifdef __cplusplus extern "C" { #endif void eftwrite_init(void); void eftwrite(const char *fname); #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_EFTWRITE_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * esclex.c -- lexer for esc * * this module provides lexical analysis and error handling routine * expected by the yacc-generated parser (i.e. yylex() and yyerror()). * it also does lots of tracking of things like filenames, line numbers, * and what tokens are seen on a line up to the point where a syntax error * was found. this module also arranges for the input source files to * be run through cpp. */ #include #include #include #include #include #include #include #include "out.h" #include "alloc.h" #include "stats.h" #include "stable.h" #include "lut.h" #include "literals.h" #include "tree.h" #include "esclex.h" #include "eftread.h" #include "check.h" #include "y.tab.h" struct lut *Dicts; struct lut *Ident; struct lut *Timesuffixlut; int Pragma_trust_ereports; int Pragma_new_errors_only; /* ridiculously long token buffer -- disallow any token longer than this */ #define MAXTOK 8192 static char Tok[MAXTOK]; /* some misc stats we keep on the lexer & parser */ static struct stats *Tokcount; static struct stats *Lexelapse; struct stats *Filecount; struct filestats { struct filestats *next; struct stats *stats; struct stats *idstats; } *Fstats; static int Errcount; /* input file state */ static char **Files; static const char *Fileopened; static FILE *Fp; static int Line; static const char *File; static const char *Cpp = "/usr/lib/cpp"; #ifdef ESC static const char *Cppargs; static const char *Cppstdargs = "-undef"; #endif /* ESC */ /* for debugging */ static int Lexecho; /* echo tokens as we read them */ /* forward declarations of our internal routines */ static int record(int tok, const char *s); static void dumpline(int flags); static void doident(); static void dopragma(const char *tok); /* * table of reserved words. this table is only used by lex_init() * to intialize the Rwords lookup table. */ static const struct { const char *word; const int val; } Rwords[] = { { "asru", ASRU }, { "count", COUNT }, { "div", DIV }, { "engine", ENGINE }, { "event", EVENT }, { "fru", FRU }, { "if", IF }, { "mask", MASK }, { "prop", PROP }, { "config", CONFIG }, /* * PATHFUNC indicates functions that operate only on paths * and quotes */ { "is_connected", PATHFUNC }, { "is_under", PATHFUNC }, { "is_on", PATHFUNC }, { "is_present", PATHFUNC }, { "is_type", PATHFUNC }, { "has_fault", PATHFUNC }, { "confprop", PATHFUNC }, { "confprop_defined", PATHFUNC }, }; /* * Rwordslut is a lookup table of reserved words. lhs is the word * (in the string table) and the rhs is the token value returned * by the yylex() for that word. */ static struct lut *Rwordslut; static const struct { const char *suffix; const unsigned long long nsec; } Timesuffix[] = { { "nanosecond", 1ULL }, { "nanoseconds", 1ULL }, { "nsec", 1ULL }, { "nsecs", 1ULL }, { "ns", 1ULL }, { "microsecond", 1000ULL }, { "microseconds", 1000ULL }, { "usec", 1000ULL }, { "usecs", 1000ULL }, { "us", 1000ULL }, { "millisecond", 1000000ULL }, { "milliseconds", 1000000ULL }, { "msec", 1000000ULL }, { "msecs", 1000000ULL }, { "ms", 1000000ULL }, { "second", 1000000000ULL }, { "seconds", 1000000000ULL }, { "s", 1000000000ULL }, { "minute", 1000000000ULL * 60 }, { "minutes", 1000000000ULL * 60 }, { "min", 1000000000ULL * 60 }, { "mins", 1000000000ULL * 60 }, { "m", 1000000000ULL * 60 }, { "hour", 1000000000ULL * 60 * 60 }, { "hours", 1000000000ULL * 60 * 60 }, { "hr", 1000000000ULL * 60 * 60 }, { "hrs", 1000000000ULL * 60 * 60 }, { "h", 1000000000ULL * 60 * 60 }, { "day", 1000000000ULL * 60 * 60 * 24 }, { "days", 1000000000ULL * 60 * 60 * 24 }, { "d", 1000000000ULL * 60 * 60 * 24 }, { "week", 1000000000ULL * 60 * 60 * 24 * 7 }, { "weeks", 1000000000ULL * 60 * 60 * 24 * 7 }, { "wk", 1000000000ULL * 60 * 60 * 24 * 7 }, { "wks", 1000000000ULL * 60 * 60 * 24 * 7 }, { "month", 1000000000ULL * 60 * 60 * 24 * 30 }, { "months", 1000000000ULL * 60 * 60 * 24 * 30 }, { "year", 1000000000ULL * 60 * 60 * 24 * 365 }, { "years", 1000000000ULL * 60 * 60 * 24 * 365 }, { "yr", 1000000000ULL * 60 * 60 * 24 * 365 }, { "yrs", 1000000000ULL * 60 * 60 * 24 * 365 }, }; /* * some wrappers around the general lut functions to provide type checking... */ static struct lut * lex_s2i_lut_add(struct lut *root, const char *s, intptr_t i) { return (lut_add(root, (void *)s, (void *)i, NULL)); } static int lex_s2i_lut_lookup(struct lut *root, const char *s) { return ((intptr_t)lut_lookup(root, (void *)s, NULL)); } static struct lut * lex_s2ullp_lut_add(struct lut *root, const char *s, const unsigned long long *ullp) { return (lut_add(root, (void *)s, (void *)ullp, NULL)); } const unsigned long long * lex_s2ullp_lut_lookup(struct lut *root, const char *s) { return ((unsigned long long *)lut_lookup(root, (void *)s, NULL)); } /* * lex_init -- initialize the lexer with appropriate filenames & debug flags */ /*ARGSUSED*/ void lex_init(char **av, const char *cppargs, int lexecho) { int i; #ifdef ESC const char *ptr; #endif /* ESC */ Lexecho = lexecho; Tokcount = stats_new_counter("lex.tokens", "total tokens in", 1); Filecount = stats_new_counter("lex.files", "total files read", 0); Lexelapse = stats_new_elapse("lex.time", "elapsed lex/parse time", 1); #ifdef ESC Cppargs = cppargs; /* allow user to tell us where cpp is if it is some weird place */ if (ptr = getenv("_ESC_CPP")) Cpp = ptr; /* and in case it takes some special stdargs */ if (ptr = getenv("_ESC_CPP_STDARGS")) Cppstdargs = ptr; /* verify we can find cpp */ if (access(Cpp, X_OK) < 0) { Cpp = "/usr/lib/cpp"; if (access(Cpp, X_OK) < 0) out(O_DIE, "can't locate cpp"); } #endif /* ESC */ Files = av; /* verify we can find all the input files */ while (*av) { if (strlen(*av) >= MAXTOK - strlen(Cpp) - 3) out(O_DIE, "filename too long: %.100s...", *av); if (access(*av, R_OK) < 0) out(O_DIE|O_SYS, "%s", *av); av++; stats_counter_bump(Filecount); } /* put reserved words into the string table & a lookup table */ for (i = 0; i < sizeof (Rwords) / sizeof (*Rwords); i++) Rwordslut = lex_s2i_lut_add(Rwordslut, stable(Rwords[i].word), Rwords[i].val); /* initialize table of timeval suffixes */ for (i = 0; i < sizeof (Timesuffix) / sizeof (*Timesuffix); i++) { Timesuffixlut = lex_s2ullp_lut_add(Timesuffixlut, stable(Timesuffix[i].suffix), &Timesuffix[i].nsec); } /* record start time */ stats_elapse_start(Lexelapse); } void closefile(void) { if (Fp != NULL) { #ifdef ESC if (pclose(Fp) > 0) out(O_DIE, "cpp errors while reading \"%s\", " "bailing out.", Fileopened); #else (void) fclose(Fp); #endif /* ESC */ } Fp = NULL; } /* * yylex -- the lexer, called yylex() because that's what yacc wants */ int yylex(void) { int c; int nextc; char *ptr = Tok; char *eptr = &Tok[MAXTOK]; const char *cptr; int startline; int val; static int bol = 1; /* true if we're at beginning of line */ for (;;) { while (Fp == NULL) { char ibuf[80]; if (*Files == NULL) return (record(EOF, NULL)); Fileopened = stable(*Files++); #ifdef ESC sprintf(Tok, "%s %s %s %s", Cpp, Cppstdargs, Cppargs, Fileopened); if ((Fp = popen(Tok, "r")) == NULL) out(O_DIE|O_SYS, "%s", Tok); #else Fp = eftread_fopen(Fileopened, ibuf, sizeof (ibuf)); #endif /* ESC */ Line = 1; bol = 1; /* add name to stats for visibility */ if (Fp != NULL) { static int fnum; char nbuf[100]; struct filestats *nfs = MALLOC(sizeof (*nfs)); (void) sprintf(nbuf, "lex.file%d", fnum); nfs->stats = stats_new_string(nbuf, "", 0); stats_string_set(nfs->stats, Fileopened); if (ibuf[0] != '\0') { (void) sprintf(nbuf, "lex.file%d-ident", fnum); nfs->idstats = stats_new_string(nbuf, "", 0); stats_string_set(nfs->idstats, ibuf); } else { nfs->idstats = NULL; } nfs->next = Fstats; Fstats = nfs; fnum++; } } switch (c = getc(Fp)) { case '#': /* enforce that we're at beginning of line */ if (!bol) return (record(c, NULL)); while ((c = getc(Fp)) != EOF && (c == ' ' || c == '\t')) ; if (!isdigit(c)) { /* * three cases here: * #pragma * #ident * #something-we-don't-understand * anything we don't expect we just ignore. */ *ptr++ = c; while ((c = getc(Fp)) != EOF && isalnum(c)) if (ptr < eptr - 1) *ptr++ = c; *ptr++ = '\0'; if (strcmp(Tok, "pragma") == 0) { /* skip white space */ while ((c = getc(Fp)) != EOF && (c == ' ' || c == '\t')) ; if (c == EOF || c == '\n') outfl(O_DIE, File, Line, "bad #pragma"); /* pull in next token */ ptr = Tok; *ptr++ = c; while ((c = getc(Fp)) != EOF && !isspace(c)) if (ptr < eptr - 1) *ptr++ = c; *ptr++ = '\0'; (void) ungetc(c, Fp); dopragma(Tok); } else if (strcmp(Tok, "ident") == 0) doident(); } else { /* handle file & line info from cpp */ Line = 0; do { if (!isdigit(c)) break; Line = Line * 10 + c - '0'; } while ((c = getc(Fp)) != EOF); Line--; /* newline will increment it */ while (c != EOF && isspace(c)) c = getc(Fp); if (c != '"') outfl(O_DIE, File, Line, "bad # statement (file name)"); while ((c = getc(Fp)) != EOF && c != '"') if (ptr < eptr - 1) *ptr++ = c; *ptr++ = '\0'; if (c != '"') outfl(O_DIE, File, Line, "bad # statement (quotes)"); File = stable(Tok); } /* skip the rest of the cpp line */ while ((c = getc(Fp)) != EOF && c != '\n' && c != '\r') ; if (c == EOF) return (record(c, NULL)); else (void) ungetc(c, Fp); ptr = Tok; break; case EOF: closefile(); continue; case '\n': Line++; bol = 1; break; case '\r': case ' ': case '\t': bol = 0; break; case '/': bol = 0; /* comment handling */ if ((nextc = getc(Fp)) == EOF) outfl(O_DIE, File, Line, "unexpected EOF"); else if (nextc == '*') { startline = Line; while ((c = getc(Fp)) != EOF) { if (c == '\n') Line++; else if (c == '*' && (((c = getc(Fp)) == EOF) || (c == '/'))) break; } if (c == EOF) { outfl(O_DIE, File, Line, "end of comment not seen " "(started on line %d)", startline); } } else { /* wasn't a comment, return the '/' token */ (void) ungetc(nextc, Fp); return (record(c, NULL)); } break; case '"': { int prevc; bol = 0; prevc = '\0'; /* quoted string handling */ startline = Line; for (;;) { c = getc(Fp); if (c == EOF) outfl(O_DIE, File, Line, "end of string not seen " "(started on line %d)", startline); else if (c == '\n') Line++; else if (c == '"' && prevc != '\\') break; else if (ptr < eptr) *ptr++ = c; prevc = c; } if (ptr >= eptr) out(O_DIE, File, Line, "string too long"); *ptr++ = '\0'; return (record(QUOTE, stable(Tok))); } case '&': bol = 0; /* && */ if ((nextc = getc(Fp)) == '&') return (record(AND, NULL)); else { (void) ungetc(nextc, Fp); return (record(c, NULL)); } /*NOTREACHED*/ break; case '|': bol = 0; /* || */ if ((nextc = getc(Fp)) == '|') return (record(OR, NULL)); else { (void) ungetc(nextc, Fp); return (record(c, NULL)); } /*NOTREACHED*/ break; case '!': bol = 0; /* ! or != */ if ((nextc = getc(Fp)) == '=') return (record(NE, NULL)); else { (void) ungetc(nextc, Fp); return (record(c, NULL)); } /*NOTREACHED*/ break; case '=': bol = 0; /* == */ if ((nextc = getc(Fp)) == '=') return (record(EQ, NULL)); else { (void) ungetc(nextc, Fp); return (record(c, NULL)); } /*NOTREACHED*/ break; case '-': bol = 0; /* -> */ if ((nextc = getc(Fp)) == '>') return (record(ARROW, stable(Tok))); else { (void) ungetc(nextc, Fp); return (record(c, NULL)); } /*NOTREACHED*/ break; case '<': bol = 0; if ((nextc = getc(Fp)) == '=') /* <= */ return (record(LE, NULL)); else if (nextc == '<') /* << */ return (record(LSHIFT, NULL)); else { (void) ungetc(nextc, Fp); return (record(c, NULL)); } /*NOTREACHED*/ break; case '>': bol = 0; if ((nextc = getc(Fp)) == '=') /* >= */ return (record(GE, NULL)); else if (nextc == '>') /* >> */ return (record(RSHIFT, NULL)); else { (void) ungetc(nextc, Fp); return (record(c, NULL)); } /*NOTREACHED*/ break; default: bol = 0; if (isdigit(c)) { int base; /* collect rest of number */ if (c == '0') { *ptr++ = c; if ((c = getc(Fp)) == EOF) { *ptr++ = '\0'; return (record(NUMBER, stable(Tok))); } else if (c == 'x' || c == 'X') { *ptr++ = c; base = 16; } else { (void) ungetc(c, Fp); base = 8; } } else { *ptr++ = c; base = 10; } while ((c = getc(Fp)) != EOF) { if (ptr >= eptr) out(O_DIE, File, Line, "number too long"); switch (base) { case 16: if (c >= 'a' && c <= 'f' || c >= 'A' && c <= 'F') { *ptr++ = c; continue; } /*FALLTHRU*/ case 10: if (c >= '8' && c <= '9') { *ptr++ = c; continue; } /*FALLTHRU*/ case 8: if (c >= '0' && c <= '7') { *ptr++ = c; continue; } /* not valid for this base */ *ptr++ = '\0'; (void) ungetc(c, Fp); return (record(NUMBER, stable(Tok))); } } *ptr++ = '\0'; return (record(NUMBER, stable(Tok))); } else if (isalpha(c)) { /* collect identifier */ *ptr++ = c; for (;;) { c = getc(Fp); if ((isalnum(c) || c == '_') && ptr < eptr) *ptr++ = c; else { (void) ungetc(c, Fp); break; } } if (ptr >= eptr) out(O_DIE, File, Line, "identifier too long"); *ptr++ = '\0'; cptr = stable(Tok); if (val = lex_s2i_lut_lookup(Rwordslut, cptr)) { return (record(val, cptr)); } return (record(ID, cptr)); } else return (record(c, NULL)); } /*NOTREACHED*/ } } /* * the record()/dumpline() routines are used to track & report * the list of tokens seen on a given line. this is used in two ways. * first, syntax errors found by the parser are reported by us (via * yyerror()) and we tack on the tokens processed so far on the current * line to help indicate exactly where the error is. second, if "lexecho" * debugging is turned on, these routines provide it. */ #define MAXRECORD 1000 static int Recordedline; static struct { int tok; const char *s; } Recorded[MAXRECORD]; static int Recordnext; static int record(int tok, const char *s) { stats_counter_bump(Tokcount); if (Line != Recordedline) { /* starting new line, dump out the previous line */ if (Lexecho && Recordedline) { outfl(O_NONL, File, Recordedline, "lex: "); dumpline(O_OK); } Recordedline = Line; Recordnext = 0; } if (Recordnext >= MAXRECORD) outfl(O_DIE, File, Line, "line too long, bailing out"); Recorded[Recordnext].tok = tok; Recorded[Recordnext++].s = s; yylval.tok.s = s; yylval.tok.file = File; yylval.tok.line = Line; return (tok); } /*ARGSUSED*/ static void dumpline(int flags) { int i; for (i = 0; i < Recordnext; i++) if (Recorded[i].s && Recorded[i].tok != ARROW) switch (Recorded[i].tok) { case T_QUOTE: out(flags|O_NONL, " \"%s\"", Recorded[i].s); break; default: out(flags|O_NONL, " %s", Recorded[i].s); break; } else switch (Recorded[i].tok) { case EOF: out(flags|O_NONL, " EOF"); break; case ARROW: out(flags|O_NONL, " ->%s", Recorded[i].s); break; case EQ: out(flags|O_NONL, " =="); break; case NE: out(flags|O_NONL, " !="); break; case OR: out(flags|O_NONL, " ||"); break; case AND: out(flags|O_NONL, " &&"); break; case LE: out(flags|O_NONL, " <="); break; case GE: out(flags|O_NONL, " >="); break; case LSHIFT: out(flags|O_NONL, " <<"); break; case RSHIFT: out(flags|O_NONL, " >>"); break; default: if (isprint(Recorded[i].tok)) out(flags|O_NONL, " %c", Recorded[i].tok); else out(flags|O_NONL, " '\\%03o'", Recorded[i].tok); break; } out(flags, NULL); } /* * yyerror -- report a pareser error, called yyerror because yacc wants it */ int yyerror(const char *s) { Errcount++; outfl(O_ERR|O_NONL, File, Line, "%s, tokens: ", s); dumpline(O_ERR); return (0); } /* * doident -- handle "#pragma ident" directives */ static void doident() { int c; char *ptr = Tok; char *eptr = &Tok[MAXTOK]; /* skip white space and quotes */ while ((c = getc(Fp)) != EOF && (c == ' ' || c == '\t' || c == '"')) ; if (c == EOF || c == '\n') outfl(O_DIE, File, Line, "bad ident"); /* pull in next token */ ptr = Tok; *ptr++ = c; while ((c = getc(Fp)) != EOF && c != '"' && c != '\n') if (ptr < eptr - 1) *ptr++ = c; *ptr++ = '\0'; if (c != '\n') { /* skip to end of line (including close quote, if any) */ while ((c = getc(Fp)) != EOF && c != '\n') ; } (void) ungetc(c, Fp); Ident = lut_add(Ident, (void *)stable(Tok), (void *)0, NULL); outfl(O_VERB, File, Line, "pragma set: ident \"%s\"", Tok); } /* * dodictionary -- handle "#pragma dictionary" directives */ static void dodictionary() { int c; char *ptr = Tok; char *eptr = &Tok[MAXTOK]; /* skip white space and quotes */ while ((c = getc(Fp)) != EOF && (c == ' ' || c == '\t' || c == '"')) ; if (c == EOF || c == '\n') outfl(O_DIE, File, Line, "bad dictionary"); /* pull in next token */ ptr = Tok; *ptr++ = c; while ((c = getc(Fp)) != EOF && c != '"' && c != '\n') if (ptr < eptr - 1) *ptr++ = c; *ptr++ = '\0'; if (c != '\n') { /* skip to end of line (including close quote, if any) */ while ((c = getc(Fp)) != EOF && c != '\n') ; } (void) ungetc(c, Fp); Dicts = lut_add(Dicts, (void *)stable(Tok), (void *)0, NULL); outfl(O_VERB, File, Line, "pragma set: dictionary \"%s\"", Tok); } /* * doallow_cycles -- handle "#pragma allow_cycles" directives */ static void doallow_cycles() { int c; char *ptr = Tok; char *eptr = &Tok[MAXTOK]; unsigned long long newlevel; /* * by default the compiler does not allow cycles or loops * in propagations. when cycles are encountered, the * compiler prints out an error message. * * "#pragma allow_cycles" and * "#pragma allow_cycles 0" * allow cycles, but any such cycle will produce a warning * message. * * "#pragma allow_cycles N" * with N > 0 will allow cycles and not produce any * warning messages. */ /* skip white space and quotes */ while ((c = getc(Fp)) != EOF && (c == ' ' || c == '\t' || c == '"')) ; if (c == EOF || c == '\n') newlevel = 0ULL; else { /* pull in next token */ ptr = Tok; *ptr++ = c; while ((c = getc(Fp)) != EOF && c != '"' && c != '\n') if (ptr < eptr - 1) *ptr++ = c; *ptr++ = '\0'; if (c != '\n') { /* skip to end of line */ while ((c = getc(Fp)) != EOF && c != '\n') ; } newlevel = strtoll(Tok, NULL, 0); } (void) ungetc(c, Fp); (void) check_cycle_level(newlevel); outfl(O_VERB, File, Line, "pragma set: allow_cycles (%s)", newlevel ? "no warnings" : "with warnings"); } /* * dopragma -- handle #pragma directives */ static void dopragma(const char *tok) { if (strcmp(tok, "ident") == 0) doident(); else if (strcmp(tok, "dictionary") == 0) dodictionary(); else if (strcmp(tok, "new_errors_only") == 0) { if (Pragma_new_errors_only++ == 0) outfl(O_VERB, File, Line, "pragma set: new_errors_only"); } else if (strcmp(tok, "trust_ereports") == 0) { if (Pragma_trust_ereports++ == 0) outfl(O_VERB, File, Line, "pragma set: trust_ereports"); } else if (strcmp(tok, "allow_cycles") == 0) doallow_cycles(); else outfl(O_VERB, File, Line, "unknown pragma ignored: \"%s\"", tok); } /* * lex_fini -- finalize the lexer */ int lex_fini(void) { stats_elapse_stop(Lexelapse); closefile(); if (Lexecho) { outfl(O_OK, File, Line, "lex: "); dumpline(O_OK); } return (Errcount); } void lex_free(void) { struct filestats *nfstats = Fstats; /* * Free up memory consumed by the lexer */ stats_delete(Tokcount); stats_delete(Filecount); stats_delete(Lexelapse); while (nfstats != NULL) { Fstats = nfstats->next; stats_delete(nfstats->stats); if (nfstats->idstats != NULL) stats_delete(nfstats->idstats); FREE(nfstats); nfstats = Fstats; } lut_free(Timesuffixlut, NULL, NULL); lut_free(Rwordslut, NULL, NULL); lut_free(Ident, NULL, NULL); lut_free(Dicts, NULL, NULL); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * esclex.h -- public definitions for esclex module * * this module provides lexical analysis (i.e. tokenizing the * input files) and the lex-level error routines expected by * yacc like yyerror(). yylex() and yyerror() are called only * by yacc-generated code. the lex_X() routines are called * only by main(). * * the tokstr struct is the communication mechanism between the lexer * and the parser. */ #ifndef _ESC_COMMON_ESCLEX_H #define _ESC_COMMON_ESCLEX_H #ifdef __cplusplus extern "C" { #endif /* information returned by lexer for tokens with string table entries */ struct tokstr { const char *s; /* the string (in the string table) */ const char *file; /* file where this token appeared */ int line; /* line where this token appeared */ }; void lex_init(char **av, const char *cppargs, int lexecho); int lex_fini(void); void lex_free(void); const unsigned long long *lex_s2ullp_lut_lookup(struct lut *root, const char *s); /* lut containing "ident" strings */ extern struct lut *Ident; /* lut containing "dictionary" strings */ extern struct lut *Dicts; /* lut containing valid timeval suffixes */ extern struct lut *Timesuffixlut; /* flags set by #pragmas */ extern int Pragma_new_errors_only; extern int Pragma_trust_ereports; extern int Pragma_allow_cycles; /* exported by esclex.c but names are mandated by the way yacc works... */ int yylex(void); int yyerror(const char *s); #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_ESCLEX_H */ %{ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END * * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * escparse.y -- parser for esc * * this is the yacc-based parser for Eversholt. the syntax is simple * and is defined by the LALR(1) grammar described by this file. there * should be no shift/reduce or reduce/reduce messages when building this * file. * * as the input is parsed, a parse tree is built by calling the * tree_X() functions defined in tree.c. any syntax errors cause * us to skip to the next semicolon, achieved via the "error" clause * in the stmt rule below. the yacc state machine code will call * yyerror() in esclex.c and that will keep count of the errors and * display the filename, line number, and current input stream of tokens * to help the user figure out the problem. the -Y flag to this program * turns on the yacc debugging output which is quite large. you probably * only need to do that if you're debugging the grammar below. * */ #include #include #include #include #include #include #include #include "out.h" #include "stable.h" #include "literals.h" #include "lut.h" #include "esclex.h" #include "tree.h" %} %union { struct tokstr tok; struct node *np; } %right '=' /* * make sure ':' comes immediately after '?' in precedence declarations */ %right '?' %nonassoc ':' %left OR %left AND %left '|' %left '^' %left '&' %left EQ NE %left LE GE '<' '>' %left LSHIFT RSHIFT %left '-' '+' %left '*' '%' DIV '/' %right '!' '~' %left '.' %token PROP MASK ARROW EVENT ENGINE ASRU FRU COUNT CONFIG %token ID QUOTE NUMBER IF PATHFUNC %type enameid %type root stmtlist stmt nvpairlist nvpair nvname nvexpr %type exprlist expr iterid ename pname epname eexprlist ipname iname %type numexpr cexpr func pfunc parglist parg %type eventlist event nork norkexpr globid propbody %% root : stmtlist { (void)tree_root($1); } ; stmtlist : /*empty*/ { $$ = NULL; } | stmtlist stmt { $$ = tree_expr(T_LIST, $1, $2); } ; stmt : error ';' { $$ = tree_nothing(); } | IF '(' expr ')' stmt { $$ = $5; } | IF '(' expr ')' '{' stmtlist '}' { $$ = $6; } | EVENT event nvpairlist ';' { $$ = tree_decl(T_EVENT, $2, $3, $1.file, $1.line); } | ENGINE event nvpairlist ';' { $$ = tree_decl(T_ENGINE, $2, $3, $1.file, $1.line); } | PROP propbody ';' { $$ = tree_stmt(T_PROP, $2, $1.file, $1.line); } | MASK propbody ';' { $$ = tree_stmt(T_MASK, $2, $1.file, $1.line); } | ASRU pname nvpairlist ';' { $$ = tree_decl(T_ASRU, $2, $3, $1.file, $1.line); } | FRU pname nvpairlist ';' { $$ = tree_decl(T_FRU, $2, $3, $1.file, $1.line); } | CONFIG ipname nvpairlist ';' { $$ = tree_decl(T_CONFIG, $2, $3, $1.file, $1.line); } | /*superfluous semicolons are ignored*/ ';' { $$ = tree_nothing(); } ; propbody: eventlist nork ARROW nork eventlist { $$ = tree_arrow($1, $2, $4, $5); } | propbody nork ARROW nork eventlist { $$ = tree_arrow($1, $2, $4, $5); } ; nork : /* empty */ { $$ = NULL; } | '(' norkexpr ')' { $$ = $2; } ; norkexpr: NUMBER { $$ = tree_num($1.s, $1.file, $1.line); } | ID /* really can only be 'A', enforced by check_arrow() later */ { $$ = tree_name($1.s, IT_NONE, $1.file, $1.line); } | '(' norkexpr ')' { $$ = $2; } | norkexpr '-' norkexpr { $$ = tree_expr(T_SUB, $1, $3); } | norkexpr '+' norkexpr { $$ = tree_expr(T_ADD, $1, $3); } | norkexpr '*' norkexpr { $$ = tree_expr(T_MUL, $1, $3); } | norkexpr DIV norkexpr { $$ = tree_expr(T_DIV, $1, $3); } | norkexpr '%' norkexpr { $$ = tree_expr(T_MOD, $1, $3); } ; nvpairlist: /* empty */ { $$ = NULL; } | nvpair | nvpairlist ',' nvpair { $$ = tree_expr(T_LIST, $1, $3); } ; nvpair : nvname '=' nvexpr { $$ = tree_expr(T_NVPAIR, $1, $3); } | ENGINE '=' nvexpr /* "engine" is a reserved word, but a valid property name */ { $$ = tree_expr(T_NVPAIR, tree_name($1.s, IT_NONE, $1.file, $1.line), $3); } | COUNT '=' nvexpr /* "count" is a reserved word, but a valid property name */ { $$ = tree_expr(T_NVPAIR, tree_name($1.s, IT_NONE, $1.file, $1.line), $3); } ; nvname : ID { $$ = tree_name($1.s, IT_NONE, $1.file, $1.line); } | nvname '-' ID { /* hack to allow dashes in property names */ $$ = tree_name_repairdash($1, $3.s); } ; /* the RHS of an nvpair can be a value, or an ename, or an ename@pname */ nvexpr : numexpr | ename epname { $$ = tree_event($1, $2, NULL); } | pname | globid | func | NUMBER ID /* * ID must be timevals only ("ms", "us", etc.). * enforced by tree_timeval(). */ { $$ = tree_timeval($1.s, $2.s, $1.file, $1.line); } | QUOTE { $$ = tree_quote($1.s, $1.file, $1.line); } ; /* arithmetic operations, no variables or symbols */ numexpr : numexpr '-' numexpr { $$ = tree_expr(T_SUB, $1, $3); } | numexpr '+' numexpr { $$ = tree_expr(T_ADD, $1, $3); } | numexpr '*' numexpr { $$ = tree_expr(T_MUL, $1, $3); } | numexpr DIV numexpr { $$ = tree_expr(T_DIV, $1, $3); } | numexpr '/' numexpr { $$ = tree_expr(T_DIV, $1, $3); } | numexpr '%' numexpr { $$ = tree_expr(T_MOD, $1, $3); } | '(' numexpr ')' { $$ = $2; } | NUMBER { $$ = tree_num($1.s, $1.file, $1.line); } ; eventlist: event | eventlist ',' event { $$ = tree_expr(T_LIST, $1, $3); } ; event : ename epname eexprlist { $$ = tree_event($1, $2, $3); } ; epname : /* empty */ { $$ = NULL; } | '@' pname { $$ = $2; } ; eexprlist: /* empty */ { $$ = NULL; } | '{' exprlist '}' { $$ = $2; } ; exprlist: expr | exprlist ',' expr { $$ = tree_expr(T_LIST, $1, $3); } ; /* * note that expr does not include pname, to avoid reduce/reduce * conflicts between cexpr and iterid involving the use of ID */ expr : cexpr | NUMBER ID /* * ID must be timevals only ("ms", "us", etc.). * enforced by tree_timeval(). */ { $$ = tree_timeval($1.s, $2.s, $1.file, $1.line); } ; cexpr : cexpr '=' cexpr { $$ = tree_expr(T_ASSIGN, $1, $3); } | cexpr '?' cexpr { $$ = tree_expr(T_CONDIF, $1, $3); } | cexpr ':' cexpr { $$ = tree_expr(T_CONDELSE, $1, $3); } | cexpr OR cexpr { $$ = tree_expr(T_OR, $1, $3); } | cexpr AND cexpr { $$ = tree_expr(T_AND, $1, $3); } | cexpr '|' cexpr { $$ = tree_expr(T_BITOR, $1, $3); } | cexpr '^' cexpr { $$ = tree_expr(T_BITXOR, $1, $3); } | cexpr '&' cexpr { $$ = tree_expr(T_BITAND, $1, $3); } | cexpr EQ cexpr { $$ = tree_expr(T_EQ, $1, $3); } | cexpr NE cexpr { $$ = tree_expr(T_NE, $1, $3); } | cexpr '<' cexpr { $$ = tree_expr(T_LT, $1, $3); } | cexpr LE cexpr { $$ = tree_expr(T_LE, $1, $3); } | cexpr '>' cexpr { $$ = tree_expr(T_GT, $1, $3); } | cexpr GE cexpr { $$ = tree_expr(T_GE, $1, $3); } | cexpr LSHIFT cexpr { $$ = tree_expr(T_LSHIFT, $1, $3); } | cexpr RSHIFT cexpr { $$ = tree_expr(T_RSHIFT, $1, $3); } | cexpr '-' cexpr { $$ = tree_expr(T_SUB, $1, $3); } | cexpr '+' cexpr { $$ = tree_expr(T_ADD, $1, $3); } | cexpr '*' cexpr { $$ = tree_expr(T_MUL, $1, $3); } | cexpr DIV cexpr { $$ = tree_expr(T_DIV, $1, $3); } | cexpr '/' cexpr { $$ = tree_expr(T_DIV, $1, $3); } | cexpr '%' cexpr { $$ = tree_expr(T_MOD, $1, $3); } | '!' cexpr { $$ = tree_expr(T_NOT, $2, NULL); } | '~' cexpr { $$ = tree_expr(T_BITNOT, $2, NULL); } | '(' cexpr ')' { $$ = $2; } | func | NUMBER { $$ = tree_num($1.s, $1.file, $1.line); } | ID { /* iteration variable */ $$ = tree_name($1.s, IT_NONE, $1.file, $1.line); } | globid | QUOTE { $$ = tree_quote($1.s, $1.file, $1.line); } ; func : ID '(' ')' { $$ = tree_func($1.s, NULL, $1.file, $1.line); } | ID '(' exprlist ')' { $$ = tree_func($1.s, $3, $1.file, $1.line); } | PATHFUNC '(' parglist ')' { $$ = tree_func($1.s, $3, $1.file, $1.line); } | pfunc ; parglist: parg | parglist ',' parg { $$ = tree_expr(T_LIST, $1, $3); } ; parg : pfunc | pname { $$ = tree_pname($1); } | QUOTE { $$ = tree_quote($1.s, $1.file, $1.line); } | ID '(' exprlist ')' { $$ = tree_func($1.s, $3, $1.file, $1.line); } ; /* * these functions are in the grammar so we can force the arg to be * a path or an event. they show up as functions in the parse tree. */ pfunc : ASRU '(' pname ')' { $$ = tree_func($1.s, tree_pname($3), $1.file, $1.line); } | FRU '(' pname ')' { $$ = tree_func($1.s, tree_pname($3), $1.file, $1.line); } | COUNT '(' event ')' { $$ = tree_func($1.s, $3, $1.file, $1.line); } ; globid : '$' ID { $$ = tree_globid($2.s, $2.file, $2.line); } ; iterid : ID { $$ = tree_name($1.s, IT_VERTICAL, $1.file, $1.line); } | ID '[' ']' { $$ = tree_name($1.s, IT_VERTICAL, $1.file, $1.line); } | ID '[' cexpr ']' { $$ = tree_name_iterator( tree_name($1.s, IT_VERTICAL, $1.file, $1.line), $3); } | ID '<' '>' { $$ = tree_name($1.s, IT_HORIZONTAL, $1.file, $1.line); } | ID '<' ID '>' { $$ = tree_name_iterator( tree_name($1.s, IT_HORIZONTAL, $1.file, $1.line), tree_name($3.s, IT_NONE, $3.file, $3.line)); } | ID '-' iterid { /* hack to allow dashes in path name components */ $$ = tree_name_repairdash2($1.s, $3); } ; /* iname is an ID where we can peel numbers off the end */ iname : ID { $$ = tree_iname($1.s, $1.file, $1.line); } ; /* base case of ID.ID instead of just ID requires ename to contain one dot */ ename : ID '.' enameid { $$ = tree_name_append( tree_name($1.s, IT_ENAME, $1.file, $1.line), tree_name($3.s, IT_NONE, $3.file, $3.line)); } | ename '.' enameid { $$ = tree_name_append($1, tree_name($3.s, IT_NONE, $3.file, $3.line)); } | ename '-' enameid { /* * hack to allow dashes in class names. when we * detect the dash here, we know we're in a class * name because the left recursion of this rule * means we've already matched at least: * ID '.' ID * so the ename here has an incomplete final * component (because the lexer stopped at the * dash). so we repair that final component here. */ $$ = tree_name_repairdash($1, $3.s); } ; /* like an ID, but we let reserved words act unreserved in enames */ enameid : ID | PROP | MASK | EVENT | ENGINE | ASRU | FRU | CONFIG | IF ; /* pname is a pathname, like x/y, x/y[0], etc */ pname : iterid | pname '/' iterid { $$ = tree_name_append($1, $3); } ; /* ipname is an "instanced" pathname, like x0/y1 */ ipname : iname | ipname '/' iname { $$ = tree_name_append($1, $3); } ; %% /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * io.c -- io wrapper functions, replacable in more constrained * environments, such as within a DE. */ #include #include void io_abort(const char *buf) { (void) fprintf(stderr, "%s\n", buf); abort(); } void io_die(const char *buf) { (void) fprintf(stderr, "%s\n", buf); exit(1); } void io_err(const char *buf) { (void) fprintf(stderr, "%s\n", buf); } void io_out(const char *buf) { (void) printf("%s\n", buf); } void io_exit(int code) { exit(code); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * io -- input/output routines */ #ifndef _ESC_COMMON_IO_H #define _ESC_COMMON_IO_H #ifdef __cplusplus extern "C" { #endif void io_abort(const char *buf) __NORETURN; void io_die(const char *buf) __NORETURN; void io_err(const char *buf); void io_out(const char *buf); void io_exit(int code) __NORETURN; #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_IO_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * literals.c -- literals initialization module * * this file intializes all the literals so they are stored in the * string table. instead of using: * stable("fault") * other modules can use: * L_fault * and avoid repeated calls to stable(). */ #include #include "out.h" #include "stable.h" #define L_DECL(s) const char *L_##s #include "literals.h" void literals_init() { /* * this turns the statements like: * extern const char *L_something; * in literals.h into initialization statements like: * L_something = stable("something"); * */ #undef _ESC_COMMON_LITERALS_H #undef L_DECL #define L_DECL(s) L_##s = stable(#s) #include "literals.h" } void literals_fini(void) { } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * literals.h -- public definitions for literals in string table * * all strings in this program are kept in the string table provided * by the routines in stable.c. this allows us to see if two strings * are equal by checking their pointers rather than calling strcmp(). * when we want to check for a specific string we can either do this: * if (s == stable("word")) * or define the literal here in this file and then do this: * if (s == L_word) * * the macro L_DECL() below expands to an extern const char * declaration * for files that include it. the exception is some cpp statements done by * literals.c which change L_DECL() to initialize the string by calling * stable(). */ #ifndef _ESC_COMMON_LITERALS_H #define _ESC_COMMON_LITERALS_H #ifdef __cplusplus extern "C" { #endif #ifndef L_DECL #define L_DECL(s) extern const char *L_##s #endif /* reserved words */ L_DECL(asru); L_DECL(div); L_DECL(engine); L_DECL(event); L_DECL(fru); L_DECL(if); L_DECL(mask); L_DECL(prop); L_DECL(config); /* event types */ L_DECL(fault); L_DECL(upset); L_DECL(defect); L_DECL(error); L_DECL(ereport); /* engine types */ L_DECL(serd); L_DECL(stat); /* timeval suffixes */ L_DECL(nanosecond); L_DECL(nanoseconds); L_DECL(nsec); L_DECL(nsecs); L_DECL(ns); L_DECL(microsecond); L_DECL(microseconds); L_DECL(usec); L_DECL(usecs); L_DECL(us); L_DECL(millisecond); L_DECL(milliseconds); L_DECL(msec); L_DECL(msecs); L_DECL(ms); L_DECL(second); L_DECL(seconds); L_DECL(s); L_DECL(minute); L_DECL(minutes); L_DECL(min); L_DECL(mins); L_DECL(m); L_DECL(hour); L_DECL(hours); L_DECL(hr); L_DECL(hrs); L_DECL(h); L_DECL(day); L_DECL(days); L_DECL(d); L_DECL(week); L_DECL(weeks); L_DECL(wk); L_DECL(wks); L_DECL(month); L_DECL(months); L_DECL(year); L_DECL(years); L_DECL(yr); L_DECL(yrs); L_DECL(infinity); /* property names */ L_DECL(ASRU); L_DECL(action); L_DECL(FITrate); L_DECL(FRU); L_DECL(id); L_DECL(message); L_DECL(retire); L_DECL(response); L_DECL(FRUID); L_DECL(N); L_DECL(T); L_DECL(count); L_DECL(method); L_DECL(poller); L_DECL(timeout); L_DECL(trip); L_DECL(discard_if_config_unknown); /* property values */ L_DECL(A); L_DECL(volatile); L_DECL(persistent); /* event bubble types */ L_DECL(from); L_DECL(to); L_DECL(inhibit); /* * internal function names. note that "fru" and "asru" are also function * names. */ L_DECL(within); L_DECL(call); L_DECL(cat); L_DECL(confcall); L_DECL(confprop); L_DECL(confprop_defined); L_DECL(defined); L_DECL(payloadprop); L_DECL(payloadprop_contains); L_DECL(payloadprop_defined); L_DECL(setpayloadprop); L_DECL(setserdsuffix); L_DECL(setserdincrement); L_DECL(setserdn); L_DECL(setserdt); L_DECL(envprop); L_DECL(is_connected); L_DECL(is_under); L_DECL(is_on); L_DECL(is_present); L_DECL(has_fault); L_DECL(is_type); L_DECL(count); /* our enumerated types (used for debugging) */ L_DECL(T_NOTHING); L_DECL(T_NAME); L_DECL(T_GLOBID); L_DECL(T_ENAME); L_DECL(T_EVENT); L_DECL(T_ENGINE); L_DECL(T_ASRU); L_DECL(T_FRU); L_DECL(T_TIMEVAL); L_DECL(T_NUM); L_DECL(T_QUOTE); L_DECL(T_FUNC); L_DECL(T_NVPAIR); L_DECL(T_ASSIGN); L_DECL(T_CONDIF); L_DECL(T_CONDELSE); L_DECL(T_NOT); L_DECL(T_AND); L_DECL(T_OR); L_DECL(T_EQ); L_DECL(T_NE); L_DECL(T_SUB); L_DECL(T_ADD); L_DECL(T_MUL); L_DECL(T_DIV); L_DECL(T_MOD); L_DECL(T_LT); L_DECL(T_LE); L_DECL(T_GT); L_DECL(T_GE); L_DECL(T_BITAND); L_DECL(T_BITOR); L_DECL(T_BITXOR); L_DECL(T_BITNOT); L_DECL(T_LSHIFT); L_DECL(T_RSHIFT); L_DECL(T_ARROW); L_DECL(T_LIST); L_DECL(T_FAULT); L_DECL(T_UPSET); L_DECL(T_DEFECT); L_DECL(T_ERROR); L_DECL(T_EREPORT); L_DECL(T_SERD); L_DECL(T_STAT); L_DECL(T_PROP); L_DECL(T_MASK); L_DECL(N_UNSPEC); L_DECL(N_FAULT); L_DECL(N_UPSET); L_DECL(N_DEFECT); L_DECL(N_ERROR); L_DECL(N_EREPORT); L_DECL(N_SERD); L_DECL(IT_NONE); L_DECL(IT_VERTICAL); L_DECL(IT_HORIZONTAL); L_DECL(IT_ENAME); /* misc */ L_DECL(nofile); #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_LITERALS_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * lut.c -- simple lookup table module * * this file contains a very simple lookup table (lut) implementation. * the tables only support insert & lookup, no delete, and can * only be walked in one order. if the key already exists * for something being inserted, the previous entry is simply * replaced. */ #include #include "alloc.h" #include "out.h" #include "stats.h" #include "lut.h" #include "lut_impl.h" #include "tree.h" static struct stats *Addtotal; static struct stats *Lookuptotal; static struct stats *Freetotal; void lut_init(void) { Addtotal = stats_new_counter("lut.adds", "total adds", 1); Lookuptotal = stats_new_counter("lut.lookup", "total lookups", 1); Freetotal = stats_new_counter("lut.frees", "total frees", 1); } void lut_fini(void) { stats_delete(Addtotal); stats_delete(Lookuptotal); stats_delete(Freetotal); } /* * lut_add -- add an entry to the table * * use it like this: * struct lut *root = NULL; * root = lut_add(root, key, value, cmp_func); * * the cmp_func can be strcmp(). pass in NULL and instead of * calling a cmp_func the routine will just look at the difference * between key pointers (useful when all strings are kept in a * string table so they are equal if their pointers are equal). * */ struct lut * lut_add(struct lut *root, void *lhs, void *rhs, lut_cmp cmp_func) { int diff; struct lut **tmp_hdl = &root, *parent = NULL, *tmp = root; while (tmp) { if (cmp_func) diff = (*cmp_func)(tmp->lut_lhs, lhs); else diff = (const char *)lhs - (const char *)tmp->lut_lhs; if (diff == 0) { /* already in tree, replace node */ tmp->lut_rhs = rhs; return (root); } else if (diff > 0) { tmp_hdl = &(tmp->lut_left); parent = tmp; tmp = tmp->lut_left; } else { tmp_hdl = &(tmp->lut_right); parent = tmp; tmp = tmp->lut_right; } } /* either empty tree or not in tree, so create new node */ *tmp_hdl = MALLOC(sizeof (*root)); (*tmp_hdl)->lut_lhs = lhs; (*tmp_hdl)->lut_rhs = rhs; (*tmp_hdl)->lut_parent = parent; (*tmp_hdl)->lut_left = (*tmp_hdl)->lut_right = NULL; stats_counter_bump(Addtotal); return (root); } void * lut_lookup(struct lut *root, void *lhs, lut_cmp cmp_func) { int diff; stats_counter_bump(Lookuptotal); while (root) { if (cmp_func) diff = (*cmp_func)(root->lut_lhs, lhs); else diff = (const char *)lhs - (const char *)root->lut_lhs; if (diff == 0) return (root->lut_rhs); else if (diff > 0) root = root->lut_left; else root = root->lut_right; } return (NULL); } void * lut_lookup_lhs(struct lut *root, void *lhs, lut_cmp cmp_func) { int diff; stats_counter_bump(Lookuptotal); while (root) { if (cmp_func) diff = (*cmp_func)(root->lut_lhs, lhs); else diff = (const char *)lhs - (const char *)root->lut_lhs; if (diff == 0) return (root->lut_lhs); else if (diff > 0) root = root->lut_left; else root = root->lut_right; } return (NULL); } /* * lut_walk -- walk the table in lexical order */ void lut_walk(struct lut *root, lut_cb callback, void *arg) { struct lut *tmp = root; struct lut *prev_child = NULL; if (root == NULL) return; while (tmp->lut_left != NULL) tmp = tmp->lut_left; /* do callback on leftmost node */ (*callback)(tmp->lut_lhs, tmp->lut_rhs, arg); for (;;) { if (tmp->lut_right != NULL && tmp->lut_right != prev_child) { tmp = tmp->lut_right; while (tmp->lut_left != NULL) tmp = tmp->lut_left; /* do callback on leftmost node */ (*callback)(tmp->lut_lhs, tmp->lut_rhs, arg); } else if (tmp->lut_parent != NULL) { prev_child = tmp; tmp = tmp->lut_parent; /* * do callback on parent only if we're coming up * from the left */ if (tmp->lut_right != prev_child) (*callback)(tmp->lut_lhs, tmp->lut_rhs, arg); } else return; } } /* * lut_free -- free the lut */ void lut_free(struct lut *root, lut_cb callback, void *arg) { struct lut *tmp = root; struct lut *prev_child = NULL; if (root == NULL) return; while (tmp->lut_left != NULL) tmp = tmp->lut_left; /* do callback on leftmost node */ if (callback) (*callback)(tmp->lut_lhs, tmp->lut_rhs, arg); for (;;) { if (tmp->lut_right != NULL && tmp->lut_right != prev_child) { tmp = tmp->lut_right; while (tmp->lut_left != NULL) tmp = tmp->lut_left; /* do callback on leftmost node */ if (callback) (*callback)(tmp->lut_lhs, tmp->lut_rhs, arg); } else if (tmp->lut_parent != NULL) { prev_child = tmp; tmp = tmp->lut_parent; FREE(prev_child); /* * do callback on parent only if we're coming up * from the left */ if (tmp->lut_right != prev_child && callback) (*callback)(tmp->lut_lhs, tmp->lut_rhs, arg); } else { /* * free the root node and then we're done */ FREE(tmp); return; } } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * lut.h -- public definitions for lookup table module * * this module is a very simple look-up table implementation. used * all over this program to implement tables of various sorts. */ #ifndef _ESC_COMMON_LUT_H #define _ESC_COMMON_LUT_H #ifdef __cplusplus extern "C" { #endif #include "tree.h" void lut_init(void); void lut_fini(void); typedef int (*lut_cmp)(void *lhs, void *rhs); struct lut *lut_add(struct lut *root, void *lhs, void *rhs, int (*cmp_func)(void *old_lhs, void *new_lhs)); void *lut_lookup(struct lut *root, void *lhs, lut_cmp cmp_func); void *lut_lookup_lhs(struct lut *root, void *lhs, lut_cmp cmp_func); typedef void (*lut_cb)(void *lhs, void *rhs, void *arg); void lut_walk(struct lut *root, lut_cb callback, void *arg); void lut_free(struct lut *root, lut_cb callback, void *arg); #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_LUT_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #ifndef _LUT_IMPL_H #define _LUT_IMPL_H #ifdef __cplusplus extern "C" { #endif /* * ipath_impl.h -- ipath private data shared with mdb module */ /* info created by lut_add(), private to lut.c and its mdb module */ struct lut { struct lut *lut_left; struct lut *lut_right; struct lut *lut_parent; void *lut_lhs; /* search key */ void *lut_rhs; /* the datum */ }; #ifdef __cplusplus } #endif #endif /* _LUT_IMPL_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * out.c -- some basic output routines * */ #include #include #include #include #include #include #include #include #include #include "out.h" #include "stats.h" #include "io.h" /* stats we keep for "out" module */ static struct stats *Outcount; static struct stats *Errcount; static struct stats *Warncount; static int Exitcode; static const char *Myname; static FILE *Altfp; /* buffer used to format all prints */ #define MAXOUT 8192 static char Outbuf[MAXOUT]; static int Outidx; /* next unused char in Outbuf[] */ /* * out_init -- initialize this module */ void out_init(const char *myname) { Outcount = stats_new_counter("output.calls", "total calls", 1); Errcount = stats_new_counter("output.errors", "total errors", 0); Warncount = stats_new_counter("output.warnings", "total warnings", 0); if (myname == NULL) return; if ((Myname = strrchr(myname, '/')) == NULL && (Myname = strrchr(myname, '\\')) == NULL) Myname = myname; else Myname++; } void out_fini(void) { stats_delete(Outcount); Outcount = NULL; stats_delete(Errcount); Errcount = NULL; stats_delete(Warncount); Warncount = NULL; } /* * out_altfp -- store an alternate fp for O_ALTFP */ void out_altfp(FILE *fp) { Altfp = fp; } /* * voutbufprintf -- like vprintf, but appends to Outbuf */ static void voutbufprintf(const char *fmt, va_list ap) { int len = vsnprintf(&Outbuf[Outidx], MAXOUT - Outidx, fmt, ap); Outidx += len; if (Outidx >= MAXOUT) Outidx = MAXOUT - 1; } /* * outbufprintf -- like printf, but appends to Outbuf */ /*PRINTFLIKE1*/ static void outbufprintf(const char *fmt, ...) { va_list ap; va_start(ap, fmt); voutbufprintf(fmt, ap); va_end(ap); } /* * vout -- va_list version of out() * * all the output processing work is done here. */ static void vout(int flags, const char *fmt, va_list ap) { int safe_errno = errno; stats_counter_bump(Outcount); /* * just return if called with a disabled output type. this * prevents debug prints when Debug is off, verbose prints * when Verbose is off, and language warnings when warnings * are quenched (which they are when we're loading a .eft file). * */ if ((flags & O_DEBUG) && Debug == 0) return; if ((flags & O_VERB) && Verbose == 0) return; if ((flags & O_VERB2) && Verbose < 2) return; if ((flags & O_VERB3) && Verbose < 3) return; if ((flags & O_WARN) && Warn == 0) return; if ((flags & O_ALTFP) && Altfp == NULL) return; /* some things only happen at the beginning of a print */ if (Outidx == 0) { if (flags & O_USAGE) { Exitcode++; outbufprintf("usage: %s ", Myname); } else { if (Myname && flags & (O_DIE|O_ERR|O_WARN|O_PROG)) outbufprintf("%s: ", Myname); if (flags & O_DIE) { Exitcode++; outbufprintf("fatal error: "); } else if (flags & O_ERR) { Exitcode++; stats_counter_bump(Errcount); outbufprintf("error: "); } else if (flags & O_WARN) { stats_counter_bump(Warncount); outbufprintf("warning: "); } } } /* fmt can be NULL if the caller just wanted flags processed */ if (fmt != NULL) voutbufprintf(fmt, ap); /* O_SYS means convert errno to a string and append it */ if (flags & O_SYS) { const char *msg = strerror(safe_errno); if (Outidx != 0) outbufprintf(": "); if (msg) outbufprintf("%s", msg); else outbufprintf("(error %d)", safe_errno); } /* O_STAMP means convert add a timestamp */ if (flags & O_STAMP) { time_t clock; char *tmsg; (void) time(&clock); tmsg = ctime(&clock); if (tmsg && *tmsg) { tmsg[strlen(tmsg) - 1] = '\0'; if (Outidx != 0) outbufprintf(" "); outbufprintf("%s", tmsg); } } if (flags & O_NONL) return; /* not done filling Outbuf */ /* done filling Outbuf, platform calls will add newline */ if (flags & O_ALTFP) (void) fprintf(Altfp, "%s\n", Outbuf); else if (flags & O_ABORT) io_abort(Outbuf); else if (flags & O_DIE) io_die(Outbuf); else if (flags & O_ERR) io_err(Outbuf); else io_out(Outbuf); /* reset output buffer */ Outidx = 0; Outbuf[0] = '\0'; } /* * out -- spew a line of output, with various options */ /*PRINTFLIKE2*/ void out(int flags, const char *fmt, ...) { va_list ap; va_start(ap, fmt); vout(flags, fmt, ap); va_end(ap); } /* * outfl -- spew a filename:linenumber message */ /*PRINTFLIKE4*/ void outfl(int flags, const char *fname, int line, const char *fmt, ...) { va_list ap; va_start(ap, fmt); if (fname) out(flags|O_NONL, "%s:%d: ", fname, line); vout(flags, fmt, ap); va_end(ap); } /* * out_exit -- exit the program */ void out_exit(int code) { io_exit(Exitcode + code); } /* * out_errcount -- return the number of O_ERR messages issued so far */ int out_errcount(void) { return (stats_counter_value(Errcount)); } /* * out_warncount -- return the number of O_WARN messages issued so far */ int out_warncount(void) { return (stats_counter_value(Warncount)); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * out.h -- public definitions for output module * * general output & error handling routines. the routine out() is * the most commonly used routine in this module -- called by virtually * all other modules. */ #ifndef _ESC_COMMON_OUT_H #define _ESC_COMMON_OUT_H #include #include #include #ifdef __cplusplus extern "C" { #endif void out_init(const char *myname); void out_fini(void); void out(int flags, const char *fmt, ...); void outfl(int flags, const char *fname, int line, const char *fmt, ...); void out_exit(int code) __NORETURN; void out_altfp(FILE *fp); int out_errcount(void); int out_warncount(void); /* flags for out() */ #define O_OK 0x0000 /* simple output pseudo-flag */ #define O_DIE 0x0001 /* O_PROG, stderr, bump exit code, call out_exit() */ #define O_ERR 0x0002 /* O_PROG, stderr, bump exit code */ #define O_WARN 0x0004 /* O_PROG, stderr, do nothing unless Warn is set */ #define O_SYS 0x0008 /* append errno text to message */ #define O_STAMP 0x0010 /* append a timestamp */ #define O_ALTFP 0x0020 /* write output to alternate file pointer */ #define O_PROG 0x0040 /* prepend program name to message */ #define O_NONL 0x0080 /* don't append a newline to message */ #define O_DEBUG 0x0100 /* do nothing unless Debug is set */ #define O_VERB 0x0200 /* do nothing unless Verbose is set */ #define O_VERB2 0x0400 /* do nothing unless Verbose >= 2 */ #define O_VERB3 0x2000 /* do nothing unless Verbose >= 3 */ #define O_USAGE 0x0800 /* stderr, usage message */ #define O_ABORT 0x1000 /* call abort() after issuing any output */ #ifdef DEBUG #define ASSERT(cnd) \ ((void)((cnd) || (outfl(O_ABORT, __FILE__, __LINE__, \ "assertion failure: %s", #cnd), 0))) #define ASSERTinfo(cnd, info) \ ((void)((cnd) || (outfl(O_ABORT, __FILE__, __LINE__, \ "assertion failure: %s (%s = %s)", #cnd, #info, info), 0))) #define ASSERTeq(lhs, rhs, tostring) \ ((void)(((lhs) == (rhs)) || (outfl(O_ABORT, __FILE__, __LINE__, \ "assertion failure: %s (%s) == %s (%s)", #lhs, \ tostring(lhs), #rhs, tostring(rhs)), 0))) #define ASSERTne(lhs, rhs, tostring) \ ((void)(((lhs) != (rhs)) || (outfl(O_ABORT, __FILE__, __LINE__, \ "assertion failure: %s (%s) != %s (%s)", #lhs, \ tostring(lhs), #rhs, tostring(rhs)), 0))) #else #define ASSERT(cnd) ((void)0) #define ASSERTinfo(cnd, info) ((void)0) #define ASSERTeq(lhs, rhs, tostring) ((void)0) #define ASSERTne(lhs, rhs, tostring) ((void)0) #endif extern int Debug; extern int Verbose; extern int Warn; /* * so you can say things like: * printf("\t%10d fault statement%s\n", OUTS(Faultcount)); */ #define OUTS(i) (i), ((i) == 1) ? "" : "s" #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_OUT_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * ptree.c -- routines for printing the prop tree * * this module contains routines to print portions of the parse tree. */ #include #include #include #include #include "out.h" #include "stable.h" #include "literals.h" #include "lut.h" #include "tree.h" #include "ptree.h" int Pchildgen; #ifdef FMAPLUGIN #include "itree.h" #include "eval.h" #include "config.h" static void cp2num(struct config *cp, int *num) { config_getcompname(cp, NULL, num); } #else /*ARGSUSED*/ static void cp2num(struct config *cp, int *num) { out(O_DIE, "ptree: non-NULL cp"); } #endif /* FMAPLUGIN */ static int is_stmt(struct node *np) { switch (np->t) { case T_FAULT: case T_UPSET: case T_DEFECT: case T_ERROR: case T_EREPORT: case T_SERD: case T_STAT: case T_PROP: case T_MASK: case T_ASRU: case T_FRU: case T_CONFIG: return (1); /*NOTREACHED*/ break; default: break; } return (0); } void ptree(int flags, struct node *np, int no_iterators, int fileline) { if (np == NULL) return; switch (np->t) { case T_NOTHING: break; case T_NAME: out(flags|O_NONL, "%s", np->u.name.s); if (!no_iterators) { if (np->u.name.cp != NULL) { int num; cp2num(np->u.name.cp, &num); out(flags|O_NONL, "%d", num); } else if (np->u.name.it == IT_HORIZONTAL) { if (np->u.name.child == NULL || (np->u.name.childgen && !Pchildgen)) out(flags|O_NONL, "<>"); else { out(flags|O_NONL, "<"); ptree(flags, np->u.name.child, no_iterators, fileline); out(flags|O_NONL, ">"); } } else if (np->u.name.child && (!np->u.name.childgen || Pchildgen)) { if (np->u.name.it != IT_NONE) out(flags|O_NONL, "["); ptree(flags, np->u.name.child, no_iterators, fileline); if (np->u.name.it != IT_NONE) out(flags|O_NONL, "]"); } } if (np->u.name.next) { ASSERT(np->u.name.next->t == T_NAME); if (np->u.name.it == IT_ENAME) out(flags|O_NONL, "."); else out(flags|O_NONL, "/"); ptree(flags, np->u.name.next, no_iterators, fileline); } break; case T_TIMEVAL: ptree_timeval(flags, &np->u.ull); break; case T_NUM: out(flags|O_NONL, "%llu", np->u.ull); break; case T_QUOTE: out(flags|O_NONL, "\"%s\"", np->u.quote.s); break; case T_GLOBID: out(flags|O_NONL, "$%s", np->u.globid.s); break; case T_FUNC: out(flags|O_NONL, "%s(", np->u.func.s); ptree(flags, np->u.func.arglist, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_NVPAIR: ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "="); ptree(flags, np->u.expr.right, no_iterators, fileline); break; case T_EVENT: ptree(flags, np->u.event.ename, no_iterators, fileline); if (np->u.event.epname) { out(flags|O_NONL, "@"); ptree(flags, np->u.event.epname, no_iterators, fileline); } if (np->u.event.eexprlist) { out(flags|O_NONL, "{"); ptree(flags, np->u.event.eexprlist, no_iterators, fileline); out(flags|O_NONL, "}"); } break; case T_ASSIGN: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "="); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_NOT: out(flags|O_NONL, "("); out(flags|O_NONL, "!"); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_AND: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "&&"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_OR: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "||"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_EQ: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "=="); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_NE: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "!="); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_SUB: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "-"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_ADD: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "+"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_MUL: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "*"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_DIV: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "/"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_MOD: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "%%"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_LT: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "<"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_LE: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "<="); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_GT: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, ">"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_GE: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, ">="); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_BITNOT: out(flags|O_NONL, "("); out(flags|O_NONL, "~"); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_BITAND: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "&"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_BITOR: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "|"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_BITXOR: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "^"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_LSHIFT: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "<<"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_RSHIFT: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, ">>"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_CONDIF: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, "?"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_CONDELSE: out(flags|O_NONL, "("); ptree(flags, np->u.expr.left, no_iterators, fileline); out(flags|O_NONL, ":"); ptree(flags, np->u.expr.right, no_iterators, fileline); out(flags|O_NONL, ")"); break; case T_ARROW: ptree(flags, np->u.arrow.lhs, no_iterators, fileline); if (np->u.arrow.nnp) { out(flags|O_NONL, "("); ptree(flags, np->u.arrow.nnp, no_iterators, fileline); out(flags|O_NONL, ")"); } out(flags|O_NONL, "->"); if (np->u.arrow.knp) { out(flags|O_NONL, "("); ptree(flags, np->u.arrow.knp, no_iterators, fileline); out(flags|O_NONL, ")"); } ptree(flags, np->u.arrow.rhs, no_iterators, fileline); break; case T_LIST: ptree(flags, np->u.expr.left, no_iterators, fileline); if (np->u.expr.left && np->u.expr.right && (np->u.expr.left->t != T_LIST || ! is_stmt(np->u.expr.right))) out(flags|O_NONL, ","); ptree(flags, np->u.expr.right, no_iterators, fileline); break; case T_FAULT: case T_UPSET: case T_DEFECT: case T_ERROR: case T_EREPORT: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "event "); ptree(flags, np->u.stmt.np, no_iterators, fileline); if (np->u.stmt.nvpairs) { out(flags|O_NONL, " "); ptree(flags, np->u.stmt.nvpairs, no_iterators, fileline); } out(flags, ";"); break; case T_SERD: case T_STAT: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "engine "); ptree(flags, np->u.stmt.np, no_iterators, fileline); if (np->u.stmt.nvpairs) { out(flags|O_NONL, " "); ptree(flags, np->u.stmt.nvpairs, no_iterators, fileline); } else if (np->u.stmt.lutp) { struct plut_wlk_data pd; pd.flags = flags; pd.first = 0; lut_walk(np->u.stmt.lutp, ptree_plut, &pd); } out(flags, ";"); break; case T_ASRU: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "asru "); ptree(flags, np->u.stmt.np, no_iterators, fileline); if (np->u.stmt.nvpairs) { out(flags|O_NONL, " "); ptree(flags, np->u.stmt.nvpairs, no_iterators, fileline); } out(flags, ";"); break; case T_FRU: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "fru "); ptree(flags, np->u.stmt.np, no_iterators, fileline); if (np->u.stmt.nvpairs) { out(flags|O_NONL, " "); ptree(flags, np->u.stmt.nvpairs, no_iterators, fileline); } out(flags, ";"); break; case T_CONFIG: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "config "); ptree(flags, np->u.stmt.np, no_iterators, fileline); if (np->u.stmt.nvpairs) { out(flags|O_NONL, " "); ptree(flags, np->u.stmt.nvpairs, no_iterators, fileline); } out(flags, ";"); break; case T_PROP: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "prop "); ptree(flags, np->u.stmt.np, no_iterators, fileline); out(flags, ";"); break; case T_MASK: if (fileline) out(flags, "# %d \"%s\"", np->line, np->file); out(flags|O_NONL, "mask "); ptree(flags, np->u.stmt.np, no_iterators, fileline); out(flags, ";"); break; default: out(O_DIE, "internal error: ptree unexpected nodetype: %d", np->t); /*NOTREACHED*/ } } void ptree_plut(void *name, void *val, void *arg) { struct plut_wlk_data *pd = (struct plut_wlk_data *)arg; int c; static int indent; indent++; if (pd->first == 0) out(pd->flags, ","); else pd->first = 0; for (c = indent; c > 0; c--) out(pd->flags|O_NONL, "\t"); out(pd->flags|O_NONL, "%s", (char *)name); out(pd->flags|O_NONL, "="); ptree(pd->flags, val, 0, 0); indent--; } void ptree_name(int flags, struct node *np) { ptree(flags, np, 1, 0); } void ptree_name_iter(int flags, struct node *np) { ptree(flags, np, 0, 0); } const char * ptree_nodetype2str(enum nodetype t) { static char buf[100]; switch (t) { case T_NOTHING: return L_T_NOTHING; case T_NAME: return L_T_NAME; case T_GLOBID: return L_T_GLOBID; case T_EVENT: return L_T_EVENT; case T_ENGINE: return L_T_ENGINE; case T_ASRU: return L_asru; case T_FRU: return L_fru; case T_CONFIG: return L_config; case T_TIMEVAL: return L_T_TIMEVAL; case T_NUM: return L_T_NUM; case T_QUOTE: return L_T_QUOTE; case T_FUNC: return L_T_FUNC; case T_NVPAIR: return L_T_NVPAIR; case T_ASSIGN: return L_T_ASSIGN; case T_CONDIF: return L_T_CONDIF; case T_CONDELSE: return L_T_CONDELSE; case T_NOT: return L_T_NOT; case T_AND: return L_T_AND; case T_OR: return L_T_OR; case T_EQ: return L_T_EQ; case T_NE: return L_T_NE; case T_SUB: return L_T_SUB; case T_ADD: return L_T_ADD; case T_MUL: return L_T_MUL; case T_DIV: return L_T_DIV; case T_MOD: return L_T_MOD; case T_LT: return L_T_LT; case T_LE: return L_T_LE; case T_GT: return L_T_GT; case T_GE: return L_T_GE; case T_BITAND: return L_T_BITAND; case T_BITOR: return L_T_BITOR; case T_BITXOR: return L_T_BITXOR; case T_BITNOT: return L_T_BITNOT; case T_LSHIFT: return L_T_LSHIFT; case T_RSHIFT: return L_T_RSHIFT; case T_ARROW: return L_T_ARROW; case T_LIST: return L_T_LIST; case T_FAULT: return L_fault; case T_UPSET: return L_upset; case T_DEFECT: return L_defect; case T_ERROR: return L_error; case T_EREPORT: return L_ereport; case T_SERD: return L_serd; case T_STAT: return L_stat; case T_PROP: return L_prop; case T_MASK: return L_mask; default: (void) sprintf(buf, "[unexpected nodetype: %d]", t); return (buf); } } const char * ptree_nametype2str(enum nametype t) { static char buf[100]; switch (t) { case N_UNSPEC: return L_N_UNSPEC; case N_FAULT: return L_fault; case N_DEFECT: return L_defect; case N_UPSET: return L_upset; case N_ERROR: return L_error; case N_EREPORT: return L_ereport; case N_SERD: return L_serd; case N_STAT: return L_stat; default: (void) sprintf(buf, "[unexpected nametype: %d]", t); return (buf); } } struct printer_info { enum nodetype t; const char *pat; int flags; }; static int name_pattern_match(struct node *np, const char *pat) { const char *cend; /* first character not in component in pat */ if (pat == NULL || *pat == '\0') return (1); /* either no pattern or we've matched it all */ if (np == NULL) return (0); /* there's more pattern and nothing to match */ ASSERTeq(np->t, T_NAME, ptree_nodetype2str); cend = strchr(pat, '/'); if (cend == NULL) cend = strchr(pat, '.'); if (cend == NULL) cend = &pat[strlen(pat)]; while (np) { const char *s = np->u.name.s; while (*s) { const char *cstart = pat; while (*s && tolower(*s) == tolower(*cstart)) { cstart++; if (cstart == cend) { /* component matched */ while (*cend == '/') cend++; return name_pattern_match(np->u.name.next, cend); } s++; } if (*s) s++; } np = np->u.name.next; } return (0); } static int name_pattern_match_in_subtree(struct node *np, const char *pat) { if (pat == NULL || *pat == '\0') return (1); if (np == NULL) return (0); if (np->t == T_NAME) return (name_pattern_match(np, pat)); else if (np->t == T_EVENT) return (name_pattern_match_in_subtree(np->u.event.ename, pat) || name_pattern_match_in_subtree(np->u.event.epname, pat) || name_pattern_match_in_subtree(np->u.event.eexprlist, pat)); else if (np->t == T_ARROW) return (name_pattern_match_in_subtree(np->u.arrow.lhs, pat) || name_pattern_match_in_subtree(np->u.arrow.rhs, pat)); else if (np->t == T_ASSIGN || np->t == T_CONDIF || np->t == T_CONDELSE || np->t == T_NOT || np->t == T_AND || np->t == T_OR || np->t == T_EQ || np->t == T_NE || np->t == T_SUB || np->t == T_ADD || np->t == T_MUL || np->t == T_DIV || np->t == T_MOD || np->t == T_LT || np->t == T_LE || np->t == T_GT || np->t == T_GE || np->t == T_BITAND || np->t == T_BITOR || np->t == T_BITXOR || np->t == T_BITNOT || np->t == T_LSHIFT || np->t == T_RSHIFT || np->t == T_LIST) { return (name_pattern_match_in_subtree(np->u.expr.left, pat) || name_pattern_match_in_subtree(np->u.expr.right, pat)); } else if (np->t == T_FUNC) { return (name_pattern_match_in_subtree(np->u.func.arglist, pat)); } return (0); } static void byname_printer(struct node *lhs, struct node *rhs, void *arg) { struct printer_info *infop = (struct printer_info *)arg; if (infop->t != T_NOTHING && rhs->t != infop->t) return; if (!name_pattern_match(lhs, infop->pat)) return; ptree(infop->flags, rhs, 0, 0); } static void ptree_type_pattern(int flags, enum nodetype t, const char *pat) { struct printer_info info; struct node *np; info.flags = flags; info.pat = pat; info.t = t; switch (t) { case T_FAULT: lut_walk(Faults, (lut_cb)byname_printer, (void *)&info); return; case T_UPSET: lut_walk(Upsets, (lut_cb)byname_printer, (void *)&info); return; case T_DEFECT: lut_walk(Defects, (lut_cb)byname_printer, (void *)&info); return; case T_ERROR: lut_walk(Errors, (lut_cb)byname_printer, (void *)&info); return; case T_EREPORT: lut_walk(Ereports, (lut_cb)byname_printer, (void *)&info); return; case T_SERD: lut_walk(SERDs, (lut_cb)byname_printer, (void *)&info); return; case T_STAT: lut_walk(STATs, (lut_cb)byname_printer, (void *)&info); return; case T_ASRU: lut_walk(ASRUs, (lut_cb)byname_printer, (void *)&info); return; case T_FRU: lut_walk(FRUs, (lut_cb)byname_printer, (void *)&info); return; case T_CONFIG: lut_walk(Configs, (lut_cb)byname_printer, (void *)&info); return; case T_PROP: for (np = Props; np; np = np->u.stmt.next) if (name_pattern_match_in_subtree(np->u.stmt.np, pat)) ptree(flags, np, 0, 0); return; case T_MASK: for (np = Masks; np; np = np->u.stmt.next) if (name_pattern_match_in_subtree(np->u.stmt.np, pat)) ptree(flags, np, 0, 0); return; default: ptree(flags, tree_root(NULL), 0, 0); } } void ptree_all(int flags, const char *pat) { ptree_type_pattern(flags, T_NOTHING, pat); } void ptree_fault(int flags, const char *pat) { ptree_type_pattern(flags, T_FAULT, pat); } void ptree_upset(int flags, const char *pat) { ptree_type_pattern(flags, T_UPSET, pat); } void ptree_defect(int flags, const char *pat) { ptree_type_pattern(flags, T_DEFECT, pat); } void ptree_error(int flags, const char *pat) { ptree_type_pattern(flags, T_ERROR, pat); } void ptree_ereport(int flags, const char *pat) { ptree_type_pattern(flags, T_EREPORT, pat); } void ptree_serd(int flags, const char *pat) { ptree_type_pattern(flags, T_SERD, pat); } void ptree_stat(int flags, const char *pat) { ptree_type_pattern(flags, T_STAT, pat); } void ptree_asru(int flags, const char *pat) { ptree_type_pattern(flags, T_ASRU, pat); } void ptree_fru(int flags, const char *pat) { ptree_type_pattern(flags, T_FRU, pat); } void ptree_prop(int flags, const char *pat) { ptree_type_pattern(flags, T_PROP, pat); } void ptree_mask(int flags, const char *pat) { ptree_type_pattern(flags, T_MASK, pat); } void ptree_timeval(int flags, unsigned long long *ullp) { unsigned long long val; #define NOREMAINDER(den, num, val) (((val) = ((den) / (num))) * (num) == (den)) if (*ullp == 0) out(flags|O_NONL, "0us"); else if (*ullp >= TIMEVAL_EVENTUALLY) out(flags|O_NONL, "infinity"); else if (NOREMAINDER(*ullp, 1000000000ULL*60*60*24*365, val)) out(flags|O_NONL, "%lluyear%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000000ULL*60*60*24*30, val)) out(flags|O_NONL, "%llumonth%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000000ULL*60*60*24*7, val)) out(flags|O_NONL, "%lluweek%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000000ULL*60*60*24, val)) out(flags|O_NONL, "%lluday%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000000ULL*60*60, val)) out(flags|O_NONL, "%lluhour%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000000ULL*60, val)) out(flags|O_NONL, "%lluminute%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000000ULL, val)) out(flags|O_NONL, "%llusecond%s", val, (val == 1) ? "" : "s"); else if (NOREMAINDER(*ullp, 1000000ULL, val)) out(flags|O_NONL, "%llums", val); else if (NOREMAINDER(*ullp, 1000ULL, val)) out(flags|O_NONL, "%lluus", val); else out(flags|O_NONL, "%lluns", *ullp); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * ptree.h -- public definitions for tree print module * * these routines are used to print the "struct node" data * structures from tree.h. they call out() to do the printing. */ #ifndef _ESC_COMMON_PTREE_H #define _ESC_COMMON_PTREE_H #ifdef __cplusplus extern "C" { #endif #include /* * Use a pointer to one of these structs as the "arg" argument when * lut_walk()-ing with ptree_plut() as the callback. "plut" is a * property lut, where the lhs is expected to be a const char * and * the rhs is a struct node. * * flags is passed to out() * first = 1 indicates the first in a list, first != 1 implies a later * element and thus ptree_plut() adds a preceding comma * */ struct plut_wlk_data { int flags; int first; }; void ptree(int flags, struct node *np, int no_iterators, int fileline); void ptree_name(int flags, struct node *np); void ptree_name_iter(int flags, struct node *np); void ptree_all(int flags, const char *pat); void ptree_fault(int flags, const char *pat); void ptree_upset(int flags, const char *pat); void ptree_defect(int flags, const char *pat); void ptree_error(int flags, const char *pat); void ptree_ereport(int flags, const char *pat); void ptree_serd(int flags, const char *pat); void ptree_stat(int flags, const char *pat); void ptree_config(int flags, const char *pat); void ptree_prop(int flags, const char *pat); void ptree_mask(int flags, const char *pat); void ptree_timeval(int flags, unsigned long long *ullp); void ptree_plut(void *name, void *val, void *arg); const char *ptree_nodetype2str(enum nodetype t); const char *ptree_nametype2str(enum nametype t); #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_PTREE_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * stable.c -- string table module * * simple string table module. all read-only strings are entered in * this table, allowing us to compare pointers rather than characters * to see if two strings are equal. * */ #include #include #include "alloc.h" #include "out.h" #include "stats.h" #include "stable.h" #define MINPTR_ALIGN sizeof (char *) /* alignment boundary for pointers */ #define DEF_HASH_SIZE 11113 /* default hash table size */ #define CHUNK_SIZE 8192 /* grab more memory with this chunk size */ static char **Stable; /* the hash table */ static unsigned Stablesz; static char *Stableblock; static char *Stablenext; static struct stats *Stablecount; static struct stats *Blockcount; static struct stats *Add0; static struct stats *Add1; static struct stats *Add2; static struct stats *Add3; static struct stats *Addn; struct chunklst { struct chunklst *next; char *chunkp; }; struct chunklst *Stablechunks; /* * stable_init -- initialize the stable module * * hash table is sized according to sz. sz of zero means pick * reasonable default size. */ void stable_init(unsigned sz) { /* allocate hash table */ if (sz == 0) Stablesz = DEF_HASH_SIZE; else Stablesz = sz; Stable = MALLOC(Stablesz * sizeof (*Stable)); bzero((void *)Stable, Stablesz * sizeof (*Stable)); Stablecount = stats_new_counter("stable.size", "hash table size", 1); Blockcount = stats_new_counter("stable.blocks", "blocks allocated", 1); Add0 = stats_new_counter("stable.add0", "adds to empty buckets", 1); Add1 = stats_new_counter("stable.add1", "adds to 1-entry buckets", 1); Add2 = stats_new_counter("stable.add2", "adds to 2-entry buckets", 1); Add3 = stats_new_counter("stable.add3", "adds to 3-entry buckets", 1); Addn = stats_new_counter("stable.addn", "adds to n-entry buckets", 1); stats_counter_add(Stablecount, Stablesz); } void stable_fini(void) { struct chunklst *cp, *nc; stats_delete(Stablecount); stats_delete(Blockcount); stats_delete(Add0); stats_delete(Add1); stats_delete(Add2); stats_delete(Add3); stats_delete(Addn); FREE(Stable); cp = Stablechunks; nc = NULL; while (cp != NULL) { nc = cp->next; FREE(cp->chunkp); FREE(cp); cp = nc; } Stablechunks = NULL; } static char * stable_newchunk(void) { struct chunklst *save = Stablechunks; char *n; n = MALLOC(CHUNK_SIZE); bzero((void *)n, CHUNK_SIZE); stats_counter_bump(Blockcount); Stablechunks = MALLOC(sizeof (struct chunklst)); Stablechunks->next = save; Stablechunks->chunkp = n; return (n); } /* * stable -- create/lookup a string table entry */ const char * stable(const char *s) { unsigned slen = 0; unsigned hash = DEF_HASH_SIZE ^ ((unsigned)*s << 2); char **ptrp; char *ptr; char *eptr; const char *sptr; int collisions = 0; if (Stablesz == 0) out(O_DIE, "internal error: Stablesz not set"); for (sptr = &s[1]; *sptr; sptr++) { slen++; hash ^= (((unsigned)*sptr) << (slen % 3)) + ((unsigned)*(sptr - 1) << ((slen % 3 + 7))); } hash ^= slen; if (slen > CHUNK_SIZE - sizeof (char *) - 1 - 4) out(O_DIE, "too big for string table %.20s...", s); hash %= Stablesz; ptrp = &Stable[hash]; ptr = *ptrp; while (ptr) { /* hash brought us to something, see if it is the string */ sptr = s; eptr = ptr; while (*sptr && *eptr && *sptr++ == *eptr++) ; if (*sptr == '\0' && *eptr == '\0') return (ptr); /* found it */ /* strings didn't match, advance eptr to end of string */ while (*eptr) eptr++; eptr++; /* move past '\0' */ while ((uintptr_t)eptr % MINPTR_ALIGN) eptr++; /* pull in next pointer in bucket */ ptrp = (char **)(void *)eptr; ptr = *ptrp; collisions++; } /* string wasn't in table, add it and point ptr to it */ if (Stablenext == NULL || (&Stableblock[CHUNK_SIZE] - Stablenext) < (slen + sizeof (char *) + MINPTR_ALIGN + 4)) { /* need more room */ Stablenext = Stableblock = stable_newchunk(); } /* current chunk has room in it */ ptr = *ptrp = Stablenext; sptr = s; while (*Stablenext++ = *sptr++) ; while ((uintptr_t)Stablenext % MINPTR_ALIGN) Stablenext++; ptrp = (char **)(void *)Stablenext; Stablenext += sizeof (char *); *ptrp = NULL; /* just did an add, update stats */ if (collisions == 0) stats_counter_bump(Add0); else if (collisions == 1) stats_counter_bump(Add1); else if (collisions == 2) stats_counter_bump(Add2); else if (collisions == 3) stats_counter_bump(Add3); else stats_counter_bump(Addn); return (ptr); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2004 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * stable.h -- public definitions for string table module * * simple string table module. all calls to stable() with the same * input string will return the same string pointer. all strings * contained in the input file are stored in the string table. comparing * two strings is usually done by comparing their pointers, rather than * by calling strcmp(). */ #ifndef _ESC_COMMON_STABLE_H #define _ESC_COMMON_STABLE_H #ifdef __cplusplus extern "C" { #endif void stable_init(unsigned sz); void stable_fini(void); const char *stable(const char *s); #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_STABLE_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * stats.c -- simple stats tracking table module * */ #include #include #include "stats.h" #include "alloc.h" #include "out.h" struct stats { struct stats *next; const char *name; const char *desc; enum stats_type { STATS_COUNTER = 3000, STATS_ELAPSE, STATS_STRING } t; union { int counter; struct { hrtime_t start; hrtime_t stop; } elapse; const char *string; } u; }; static int Ext; /* true if extended stats are enabled */ static struct stats *Statslist; static struct stats *Laststats; /* * stats_init -- initialize the stats module * */ void stats_init(int ext) { Ext = ext; } void stats_fini(void) { } static struct stats * stats_new(const char *name, const char *desc, enum stats_type t) { struct stats *ret = MALLOC(sizeof (*ret)); bzero(ret, sizeof (*ret)); ret->t = t; ret->name = STRDUP(name); ret->desc = STRDUP(desc); if (Laststats == NULL) Statslist = ret; else Laststats->next = ret; Laststats = ret; return (ret); } void stats_delete(struct stats *sp) { struct stats *p, *s; if (sp == NULL) return; for (p = NULL, s = Statslist; s != NULL; s = s->next) if (s == sp) break; if (s == NULL) return; if (p == NULL) Statslist = s->next; else p->next = s->next; if (s == Laststats) Laststats = p; FREE((void *)sp->name); FREE((void *)sp->desc); FREE(sp); } struct stats * stats_new_counter(const char *name, const char *desc, int ext) { if (ext && !Ext) return (NULL); /* extended stats not enabled */ return (stats_new(name, desc, STATS_COUNTER)); } void stats_counter_bump(struct stats *sp) { if (sp == NULL) return; ASSERT(sp->t == STATS_COUNTER); sp->u.counter++; } void stats_counter_add(struct stats *sp, int n) { if (sp == NULL) return; ASSERT(sp->t == STATS_COUNTER); sp->u.counter += n; } void stats_counter_reset(struct stats *sp) { if (sp == NULL) return; ASSERT(sp->t == STATS_COUNTER); sp->u.counter = 0; } int stats_counter_value(struct stats *sp) { if (sp == NULL) return (0); ASSERT(sp->t == STATS_COUNTER); return (sp->u.counter); } struct stats * stats_new_elapse(const char *name, const char *desc, int ext) { if (ext && !Ext) return (NULL); /* extended stats not enabled */ return (stats_new(name, desc, STATS_ELAPSE)); } void stats_elapse_start(struct stats *sp) { if (sp == NULL) return; ASSERT(sp->t == STATS_ELAPSE); sp->u.elapse.start = gethrtime(); } void stats_elapse_stop(struct stats *sp) { if (sp == NULL) return; ASSERT(sp->t == STATS_ELAPSE); sp->u.elapse.stop = gethrtime(); } struct stats * stats_new_string(const char *name, const char *desc, int ext) { if (ext && !Ext) return (NULL); /* extended stats not enabled */ return (stats_new(name, desc, STATS_STRING)); } void stats_string_set(struct stats *sp, const char *s) { if (sp == NULL) return; ASSERT(sp->t == STATS_STRING); sp->u.string = s; } /* * stats_publish -- spew all stats * */ void stats_publish(void) { struct stats *sp; for (sp = Statslist; sp; sp = sp->next) switch (sp->t) { case STATS_COUNTER: out(O_OK, "%32s %13d %s", sp->name, sp->u.counter, sp->desc); break; case STATS_ELAPSE: if (sp->u.elapse.start && sp->u.elapse.stop) { hrtime_t delta = sp->u.elapse.stop - sp->u.elapse.start; out(O_OK, "%32s %11lldns %s", sp->name, delta, sp->desc); } break; case STATS_STRING: out(O_OK, "%32s %13s %s", sp->name, sp->u.string, sp->desc); break; default: out(O_DIE, "stats_publish: unknown type %d", sp->t); } } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * stats.h -- public definitions for stats module * */ #ifndef _ESC_COMMON_STATS_H #define _ESC_COMMON_STATS_H #ifdef __cplusplus extern "C" { #endif void stats_init(int ext); void stats_fini(void); void stats_publish(void); struct stats *stats_new_counter(const char *name, const char *desc, int ext); void stats_delete(struct stats *sp); void stats_counter_bump(struct stats *sp); void stats_counter_add(struct stats *sp, int n); void stats_counter_reset(struct stats *sp); int stats_counter_value(struct stats *sp); struct stats *stats_new_elapse(const char *name, const char *desc, int ext); void stats_elapse_start(struct stats *sp); void stats_elapse_stop(struct stats *sp); struct stats *stats_new_string(const char *name, const char *desc, int ext); void stats_string_set(struct stats *sp, const char *s); #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_STATS_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * tree.c -- routines for manipulating the prop tree * * the actions in escparse.y call these routines to construct * the parse tree. these routines, in turn, call the check_X() * routines for semantic checking. */ #include #include #include #include #include #include "alloc.h" #include "out.h" #include "stats.h" #include "stable.h" #include "literals.h" #include "lut.h" #include "esclex.h" #include "tree.h" #include "check.h" #include "ptree.h" struct lut *Faults; struct lut *Upsets; struct lut *Defects; struct lut *Errors; struct lut *Ereports; struct lut *Ereportenames; struct lut *Ereportenames_discard; struct lut *SERDs; struct lut *STATs; struct lut *ASRUs; struct lut *FRUs; struct lut *Configs; struct node *Props; struct node *Lastprops; struct node *Masks; struct node *Lastmasks; struct node *Problems; struct node *Lastproblems; static struct node *Root; static char *Newname; static struct stats *Faultcount; static struct stats *Upsetcount; static struct stats *Defectcount; static struct stats *Errorcount; static struct stats *Ereportcount; static struct stats *SERDcount; static struct stats *STATcount; static struct stats *ASRUcount; static struct stats *FRUcount; static struct stats *Configcount; static struct stats *Propcount; static struct stats *Maskcount; static struct stats *Nodecount; static struct stats *Namecount; static struct stats *Nodesize; struct lut *Usedprops; void tree_init(void) { Faultcount = stats_new_counter("parser.fault", "fault decls", 1); Upsetcount = stats_new_counter("parser.upset", "upset decls", 1); Defectcount = stats_new_counter("parser.defect", "defect decls", 1); Errorcount = stats_new_counter("parser.error", "error decls", 1); Ereportcount = stats_new_counter("parser.ereport", "ereport decls", 1); SERDcount = stats_new_counter("parser.SERD", "SERD engine decls", 1); STATcount = stats_new_counter("parser.STAT", "STAT engine decls", 1); ASRUcount = stats_new_counter("parser.ASRU", "ASRU decls", 1); FRUcount = stats_new_counter("parser.FRU", "FRU decls", 1); Configcount = stats_new_counter("parser.config", "config stmts", 1); Propcount = stats_new_counter("parser.prop", "prop stmts", 1); Maskcount = stats_new_counter("parser.mask", "mask stmts", 1); Nodecount = stats_new_counter("parser.node", "nodes created", 1); Namecount = stats_new_counter("parser.name", "names created", 1); Nodesize = stats_new_counter("parser.nodesize", "sizeof(struct node)", 1); stats_counter_add(Nodesize, sizeof (struct node)); } void tree_fini(void) { stats_delete(Faultcount); stats_delete(Upsetcount); stats_delete(Defectcount); stats_delete(Errorcount); stats_delete(Ereportcount); stats_delete(SERDcount); stats_delete(STATcount); stats_delete(ASRUcount); stats_delete(FRUcount); stats_delete(Configcount); stats_delete(Propcount); stats_delete(Maskcount); stats_delete(Nodecount); stats_delete(Namecount); stats_delete(Nodesize); /* free entire parse tree */ tree_free(Root); /* free up the luts we keep for decls */ lut_free(Faults, NULL, NULL); Faults = NULL; lut_free(Upsets, NULL, NULL); Upsets = NULL; lut_free(Defects, NULL, NULL); Defects = NULL; lut_free(Errors, NULL, NULL); Errors = NULL; lut_free(Ereports, NULL, NULL); Ereports = NULL; lut_free(Ereportenames, NULL, NULL); Ereportenames = NULL; lut_free(Ereportenames_discard, NULL, NULL); Ereportenames_discard = NULL; lut_free(SERDs, NULL, NULL); SERDs = NULL; lut_free(STATs, NULL, NULL); STATs = NULL; lut_free(ASRUs, NULL, NULL); ASRUs = NULL; lut_free(FRUs, NULL, NULL); FRUs = NULL; lut_free(Configs, NULL, NULL); Configs = NULL; lut_free(Usedprops, NULL, NULL); Usedprops = NULL; Props = Lastprops = NULL; Masks = Lastmasks = NULL; Problems = Lastproblems = NULL; if (Newname != NULL) { FREE(Newname); Newname = NULL; } } /*ARGSUSED*/ static int nodesize(enum nodetype t, struct node *ret) { int size = sizeof (struct node); switch (t) { case T_NAME: size += sizeof (ret->u.name) - sizeof (ret->u); break; case T_GLOBID: size += sizeof (ret->u.globid) - sizeof (ret->u); break; case T_TIMEVAL: case T_NUM: size += sizeof (ret->u.ull) - sizeof (ret->u); break; case T_QUOTE: size += sizeof (ret->u.quote) - sizeof (ret->u); break; case T_FUNC: size += sizeof (ret->u.func) - sizeof (ret->u); break; case T_FAULT: case T_UPSET: case T_DEFECT: case T_ERROR: case T_EREPORT: case T_ASRU: case T_FRU: case T_SERD: case T_STAT: case T_CONFIG: case T_PROP: case T_MASK: size += sizeof (ret->u.stmt) - sizeof (ret->u); break; case T_EVENT: size += sizeof (ret->u.event) - sizeof (ret->u); break; case T_ARROW: size += sizeof (ret->u.arrow) - sizeof (ret->u); break; default: size += sizeof (ret->u.expr) - sizeof (ret->u); break; } return (size); } struct node * newnode(enum nodetype t, const char *file, int line) { struct node *ret = NULL; int size = nodesize(t, ret); ret = alloc_xmalloc(size); stats_counter_bump(Nodecount); bzero(ret, size); ret->t = t; ret->file = (file == NULL) ? "" : file; ret->line = line; return (ret); } /*ARGSUSED*/ void tree_free(struct node *root) { if (root == NULL) return; switch (root->t) { case T_NAME: tree_free(root->u.name.child); tree_free(root->u.name.next); break; case T_FUNC: tree_free(root->u.func.arglist); break; case T_AND: case T_OR: case T_EQ: case T_NE: case T_ADD: case T_DIV: case T_MOD: case T_MUL: case T_SUB: case T_LT: case T_LE: case T_GT: case T_GE: case T_BITAND: case T_BITOR: case T_BITXOR: case T_BITNOT: case T_LSHIFT: case T_RSHIFT: case T_NVPAIR: case T_ASSIGN: case T_CONDIF: case T_CONDELSE: case T_LIST: tree_free(root->u.expr.left); tree_free(root->u.expr.right); break; case T_EVENT: tree_free(root->u.event.ename); tree_free(root->u.event.epname); tree_free(root->u.event.eexprlist); break; case T_NOT: tree_free(root->u.expr.left); break; case T_ARROW: tree_free(root->u.arrow.lhs); tree_free(root->u.arrow.nnp); tree_free(root->u.arrow.knp); tree_free(root->u.arrow.rhs); break; case T_PROP: case T_MASK: tree_free(root->u.stmt.np); break; case T_FAULT: case T_UPSET: case T_DEFECT: case T_ERROR: case T_EREPORT: case T_ASRU: case T_FRU: case T_SERD: case T_STAT: case T_CONFIG: tree_free(root->u.stmt.np); if (root->u.stmt.nvpairs) tree_free(root->u.stmt.nvpairs); if (root->u.stmt.lutp) lut_free(root->u.stmt.lutp, NULL, NULL); break; case T_TIMEVAL: case T_NUM: case T_QUOTE: case T_GLOBID: case T_NOTHING: break; default: out(O_DIE, "internal error: tree_free unexpected nodetype: %d", root->t); /*NOTREACHED*/ } alloc_xfree((char *)root, nodesize(root->t, root)); } static int tree_treecmp(struct node *np1, struct node *np2, enum nodetype t, lut_cmp cmp_func) { if (np1 == NULL || np2 == NULL) return (0); if (np1->t != np2->t) return (1); ASSERT(cmp_func != NULL); if (np1->t == t) return ((*cmp_func)(np1, np2)); switch (np1->t) { case T_NAME: if (tree_treecmp(np1->u.name.child, np2->u.name.child, t, cmp_func)) return (1); return (tree_treecmp(np1->u.name.next, np2->u.name.next, t, cmp_func)); /*NOTREACHED*/ break; case T_FUNC: return (tree_treecmp(np1->u.func.arglist, np2->u.func.arglist, t, cmp_func)); /*NOTREACHED*/ break; case T_AND: case T_OR: case T_EQ: case T_NE: case T_ADD: case T_DIV: case T_MOD: case T_MUL: case T_SUB: case T_LT: case T_LE: case T_GT: case T_GE: case T_BITAND: case T_BITOR: case T_BITXOR: case T_BITNOT: case T_LSHIFT: case T_RSHIFT: case T_NVPAIR: case T_ASSIGN: case T_CONDIF: case T_CONDELSE: case T_LIST: if (tree_treecmp(np1->u.expr.left, np2->u.expr.left, t, cmp_func)) return (1); return (tree_treecmp(np1->u.expr.right, np2->u.expr.right, t, cmp_func)); /*NOTREACHED*/ break; case T_EVENT: if (tree_treecmp(np1->u.event.ename, np2->u.event.ename, t, cmp_func)) return (1); if (tree_treecmp(np1->u.event.epname, np2->u.event.epname, t, cmp_func)) return (1); return (tree_treecmp(np1->u.event.eexprlist, np2->u.event.eexprlist, t, cmp_func)); /*NOTREACHED*/ break; case T_NOT: return (tree_treecmp(np1->u.expr.left, np2->u.expr.left, t, cmp_func)); /*NOTREACHED*/ break; case T_ARROW: if (tree_treecmp(np1->u.arrow.lhs, np2->u.arrow.lhs, t, cmp_func)) return (1); if (tree_treecmp(np1->u.arrow.nnp, np2->u.arrow.nnp, t, cmp_func)) return (1); if (tree_treecmp(np1->u.arrow.knp, np2->u.arrow.knp, t, cmp_func)) return (1); return (tree_treecmp(np1->u.arrow.rhs, np2->u.arrow.rhs, t, cmp_func)); /*NOTREACHED*/ break; case T_PROP: case T_MASK: return (tree_treecmp(np1->u.stmt.np, np2->u.stmt.np, t, cmp_func)); /*NOTREACHED*/ break; case T_FAULT: case T_UPSET: case T_DEFECT: case T_ERROR: case T_EREPORT: case T_ASRU: case T_FRU: case T_SERD: case T_STAT: if (tree_treecmp(np1->u.stmt.np, np2->u.stmt.np, t, cmp_func)) return (1); return (tree_treecmp(np1->u.stmt.nvpairs, np2->u.stmt.nvpairs, t, cmp_func)); /*NOTREACHED*/ break; case T_TIMEVAL: case T_NUM: case T_QUOTE: case T_GLOBID: case T_NOTHING: break; default: out(O_DIE, "internal error: tree_treecmp unexpected nodetype: %d", np1->t); /*NOTREACHED*/ break; } return (0); } struct node * tree_root(struct node *np) { if (np) Root = np; return (Root); } struct node * tree_nothing(void) { return (newnode(T_NOTHING, L_nofile, 0)); } struct node * tree_expr(enum nodetype t, struct node *left, struct node *right) { struct node *ret; ASSERTinfo(left != NULL || right != NULL, ptree_nodetype2str(t)); ret = newnode(t, (left) ? left->file : right->file, (left) ? left->line : right->line); ret->u.expr.left = left; ret->u.expr.right = right; check_expr(ret); return (ret); } /* * ename_compress -- convert event class name in to more space-efficient form * * this routine is called after the parser has completed an "ename", which * is that part of an event that contains the class name (like ereport.x.y.z). * after this routine gets done with the ename, two things are true: * 1. the ename uses only a single struct node * 2. ename->u.name.s contains the *complete* class name, dots and all, * entered into the string table. * * so in addition to saving space by using fewer struct nodes, this routine * allows consumers of the fault tree to assume the ename is a single * string, rather than a linked list of strings. */ static struct node * ename_compress(struct node *ename) { char *buf; char *cp; int len = 0; struct node *np; if (ename == NULL) return (ename); ASSERT(ename->t == T_NAME); if (ename->u.name.next == NULL) return (ename); /* no compression to be applied here */ for (np = ename; np != NULL; np = np->u.name.next) { ASSERT(np->t == T_NAME); len++; /* room for '.' and final '\0' */ len += strlen(np->u.name.s); } cp = buf = alloca(len); for (np = ename; np != NULL; np = np->u.name.next) { ASSERT(np->t == T_NAME); if (np != ename) *cp++ = '.'; (void) strcpy(cp, np->u.name.s); cp += strlen(cp); } ename->u.name.s = stable(buf); tree_free(ename->u.name.next); ename->u.name.next = NULL; ename->u.name.last = ename; return (ename); } struct node * tree_event(struct node *ename, struct node *epname, struct node *eexprlist) { struct node *ret; ASSERT(ename != NULL); ret = newnode(T_EVENT, ename->file, ename->line); ret->u.event.ename = ename_compress(ename); ret->u.event.epname = epname; ret->u.event.eexprlist = eexprlist; check_event(ret); return (ret); } struct node * tree_name(const char *s, enum itertype it, const char *file, int line) { struct node *ret = newnode(T_NAME, file, line); ASSERT(s != NULL); stats_counter_bump(Namecount); ret->u.name.t = N_UNSPEC; ret->u.name.s = stable(s); ret->u.name.it = it; ret->u.name.last = ret; if (it == IT_ENAME) { /* PHASE2, possible optimization: convert to table driven */ if (s == L_fault) ret->u.name.t = N_FAULT; else if (s == L_upset) ret->u.name.t = N_UPSET; else if (s == L_defect) ret->u.name.t = N_DEFECT; else if (s == L_error) ret->u.name.t = N_ERROR; else if (s == L_ereport) ret->u.name.t = N_EREPORT; else if (s == L_serd) ret->u.name.t = N_SERD; else if (s == L_stat) ret->u.name.t = N_STAT; else outfl(O_ERR, file, line, "unknown class: %s", s); } return (ret); } struct node * tree_iname(const char *s, const char *file, int line) { struct node *ret; char *ss; char *ptr; ASSERT(s != NULL && *s != '\0'); ss = STRDUP(s); ptr = &ss[strlen(ss) - 1]; if (!isdigit(*ptr)) { outfl(O_ERR, file, line, "instanced name expected (i.e. \"x0/y1\")"); FREE(ss); return (tree_name(s, IT_NONE, file, line)); } while (ptr > ss && isdigit(*(ptr - 1))) ptr--; ret = newnode(T_NAME, file, line); stats_counter_bump(Namecount); ret->u.name.child = tree_num(ptr, file, line); *ptr = '\0'; ret->u.name.t = N_UNSPEC; ret->u.name.s = stable(ss); ret->u.name.it = IT_NONE; ret->u.name.last = ret; FREE(ss); return (ret); } struct node * tree_globid(const char *s, const char *file, int line) { struct node *ret = newnode(T_GLOBID, file, line); ASSERT(s != NULL); ret->u.globid.s = stable(s); return (ret); } struct node * tree_name_append(struct node *np1, struct node *np2) { ASSERT(np1 != NULL && np2 != NULL); if (np1->t != T_NAME) outfl(O_DIE, np1->file, np1->line, "tree_name_append: internal error (np1 type %d)", np1->t); if (np2->t != T_NAME) outfl(O_DIE, np2->file, np2->line, "tree_name_append: internal error (np2 type %d)", np2->t); ASSERT(np1->u.name.last != NULL); np1->u.name.last->u.name.next = np2; np1->u.name.last = np2; return (np1); } /* * tree_name_repairdash -- repair a class name that contained a dash * * this routine is called by the parser when a dash is encountered * in a class name. the event protocol allows the dashes but our * lexer considers them a separate token (arithmetic minus). an extra * rule in the parser catches this case and calls this routine to fixup * the last component of the class name (so far) by constructing the * new stable entry for a name including the dash. */ struct node * tree_name_repairdash(struct node *np, const char *s) { int len; char *buf; ASSERT(np != NULL && s != NULL); if (np->t != T_NAME) outfl(O_DIE, np->file, np->line, "tree_name_repairdash: internal error (np type %d)", np->t); ASSERT(np->u.name.last != NULL); len = strlen(np->u.name.last->u.name.s) + 1 + strlen(s) + 1; buf = MALLOC(len); (void) snprintf(buf, len, "%s-%s", np->u.name.last->u.name.s, s); np->u.name.last->u.name.s = stable(buf); FREE(buf); return (np); } struct node * tree_name_repairdash2(const char *s, struct node *np) { int len; char *buf; ASSERT(np != NULL && s != NULL); if (np->t != T_NAME) outfl(O_DIE, np->file, np->line, "tree_name_repairdash: internal error (np type %d)", np->t); ASSERT(np->u.name.last != NULL); len = strlen(np->u.name.last->u.name.s) + 1 + strlen(s) + 1; buf = MALLOC(len); (void) snprintf(buf, len, "%s-%s", s, np->u.name.last->u.name.s); np->u.name.last->u.name.s = stable(buf); FREE(buf); return (np); } struct node * tree_name_iterator(struct node *np1, struct node *np2) { ASSERT(np1 != NULL); ASSERT(np2 != NULL); ASSERTinfo(np1->t == T_NAME, ptree_nodetype2str(np1->t)); np1->u.name.child = np2; check_name_iterator(np1); return (np1); } struct node * tree_timeval(const char *s, const char *suffix, const char *file, int line) { struct node *ret = newnode(T_TIMEVAL, file, line); const unsigned long long *ullp; ASSERT(s != NULL); ASSERT(suffix != NULL); if ((ullp = lex_s2ullp_lut_lookup(Timesuffixlut, suffix)) == NULL) { outfl(O_ERR, file, line, "unrecognized number suffix: %s", suffix); /* still construct a valid timeval node so parsing continues */ ret->u.ull = 1; } else { ret->u.ull = (unsigned long long)strtoul(s, NULL, 0) * *ullp; } return (ret); } struct node * tree_num(const char *s, const char *file, int line) { struct node *ret = newnode(T_NUM, file, line); ret->u.ull = (unsigned long long)strtoul(s, NULL, 0); return (ret); } struct node * tree_quote(const char *s, const char *file, int line) { struct node *ret = newnode(T_QUOTE, file, line); ret->u.quote.s = stable(s); return (ret); } struct node * tree_func(const char *s, struct node *np, const char *file, int line) { struct node *ret = newnode(T_FUNC, file, line); const char *ptr; ret->u.func.s = s; ret->u.func.arglist = np; check_func(ret); /* * keep track of the properties we're interested in so we can ignore the * rest */ if (strcmp(s, L_confprop) == 0 || strcmp(s, L_confprop_defined) == 0) { ptr = stable(np->u.expr.right->u.quote.s); Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); } else if (strcmp(s, L_is_connected) == 0) { ptr = stable("connected"); Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); ptr = stable("CONNECTED"); Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); } else if (strcmp(s, L_is_type) == 0) { ptr = stable("type"); Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); ptr = stable("TYPE"); Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); } else if (strcmp(s, L_is_on) == 0) { ptr = stable("on"); Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); ptr = stable("ON"); Usedprops = lut_add(Usedprops, (void *)ptr, (void *)ptr, NULL); } return (ret); } /* * given a list from a prop or mask statement or a function argument, * convert all iterators to explicit iterators by inventing appropriate * iterator names. */ static void make_explicit(struct node *np, int eventonly) { struct node *pnp; /* component of pathname */ struct node *pnp2; int count; static size_t namesz; if (Newname == NULL) { namesz = 200; Newname = MALLOC(namesz); } if (np == NULL) return; /* all done */ switch (np->t) { case T_ASSIGN: case T_CONDIF: case T_CONDELSE: case T_NE: case T_EQ: case T_LT: case T_LE: case T_GT: case T_GE: case T_BITAND: case T_BITOR: case T_BITXOR: case T_BITNOT: case T_LSHIFT: case T_RSHIFT: case T_LIST: case T_AND: case T_OR: case T_NOT: case T_ADD: case T_SUB: case T_MUL: case T_DIV: case T_MOD: make_explicit(np->u.expr.left, eventonly); make_explicit(np->u.expr.right, eventonly); break; case T_EVENT: make_explicit(np->u.event.epname, 0); make_explicit(np->u.event.eexprlist, 1); break; case T_FUNC: make_explicit(np->u.func.arglist, eventonly); break; case T_NAME: if (eventonly) return; for (pnp = np; pnp != NULL; pnp = pnp->u.name.next) if (pnp->u.name.child == NULL) { /* * found implicit iterator. convert * it to an explicit iterator by * using the name of the component * appended with '#' and the number * of times we've seen this same * component name in this path so far. */ count = 0; for (pnp2 = np; pnp2 != NULL; pnp2 = pnp2->u.name.next) if (pnp2 == pnp) break; else if (pnp2->u.name.s == pnp->u.name.s) count++; if (namesz < strlen(pnp->u.name.s) + 100) { namesz = strlen(pnp->u.name.s) + 100; FREE(Newname); Newname = MALLOC(namesz); } /* * made up interator name is: * name#ordinal * or * name##ordinal * the first one is used for vertical * expansion, the second for horizontal. * either way, the '#' embedded in * the name makes it impossible to * collide with an actual iterator * given to us in the eversholt file. */ (void) snprintf(Newname, namesz, "%s#%s%d", pnp->u.name.s, (pnp->u.name.it == IT_HORIZONTAL) ? "#" : "", count); pnp->u.name.child = tree_name(Newname, IT_NONE, pnp->file, pnp->line); pnp->u.name.childgen = 1; } break; } } struct node * tree_pname(struct node *np) { make_explicit(np, 0); return (np); } struct node * tree_arrow(struct node *lhs, struct node *nnp, struct node *knp, struct node *rhs) { struct node *ret; ASSERT(lhs != NULL || rhs != NULL); ret = newnode(T_ARROW, (lhs) ? lhs->file : rhs->file, (lhs) ? lhs->line : rhs->line); ret->u.arrow.lhs = lhs; ret->u.arrow.nnp = nnp; ret->u.arrow.knp = knp; ret->u.arrow.rhs = rhs; make_explicit(lhs, 0); make_explicit(rhs, 0); check_arrow(ret); return (ret); } static struct lut * nvpair2lut(struct node *np, struct lut *lutp, enum nodetype t) { if (np) { if (np->t == T_NVPAIR) { ASSERTeq(np->u.expr.left->t, T_NAME, ptree_nodetype2str); check_stmt_allowed_properties(t, np, lutp); lutp = tree_s2np_lut_add(lutp, np->u.expr.left->u.name.s, np->u.expr.right); } else if (np->t == T_LIST) { lutp = nvpair2lut(np->u.expr.left, lutp, t); lutp = nvpair2lut(np->u.expr.right, lutp, t); } else outfl(O_DIE, np->file, np->line, "internal error: nvpair2lut type %s", ptree_nodetype2str(np->t)); } return (lutp); } struct lut * tree_s2np_lut_add(struct lut *root, const char *s, struct node *np) { return (lut_add(root, (void *)s, (void *)np, NULL)); } struct node * tree_s2np_lut_lookup(struct lut *root, const char *s) { return (struct node *)lut_lookup(root, (void *)s, NULL); } struct lut * tree_name2np_lut_add(struct lut *root, struct node *namep, struct node *np) { return (lut_add(root, (void *)namep, (void *)np, (lut_cmp)tree_namecmp)); } struct node * tree_name2np_lut_lookup(struct lut *root, struct node *namep) { return (struct node *) lut_lookup(root, (void *)namep, (lut_cmp)tree_namecmp); } struct node * tree_name2np_lut_lookup_name(struct lut *root, struct node *namep) { return (struct node *) lut_lookup_lhs(root, (void *)namep, (lut_cmp)tree_namecmp); } struct lut * tree_event2np_lut_add(struct lut *root, struct node *enp, struct node *np) { return (lut_add(root, (void *)enp, (void *)np, (lut_cmp)tree_eventcmp)); } struct node * tree_event2np_lut_lookup(struct lut *root, struct node *enp) { return ((struct node *) lut_lookup(root, (void *)enp, (lut_cmp)tree_eventcmp)); } struct node * tree_event2np_lut_lookup_event(struct lut *root, struct node *enp) { return ((struct node *) lut_lookup_lhs(root, (void *)enp, (lut_cmp)tree_eventcmp)); } static struct node * dodecl(enum nodetype t, const char *file, int line, struct node *np, struct node *nvpairs, struct lut **lutpp, struct stats *countp, int justpath) { struct node *ret; struct node *decl; /* allocate parse tree node */ ret = newnode(t, file, line); ret->u.stmt.np = np; ret->u.stmt.nvpairs = nvpairs; /* * the global lut pointed to by lutpp (Faults, Defects, Upsets, * Errors, Ereports, Serds, FRUs, or ASRUs) keeps the first decl. * if this isn't the first declr, we merge the * nvpairs into the first decl so we have a * merged table to look up properties from. * if this is the first time we've seen this fault, * we add it to the global lut and start lutp * off with any nvpairs from this declaration statement. */ if (justpath && (decl = tree_name2np_lut_lookup(*lutpp, np)) == NULL) { /* this is the first time name is declared */ stats_counter_bump(countp); *lutpp = tree_name2np_lut_add(*lutpp, np, ret); ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, t); } else if (!justpath && (decl = tree_event2np_lut_lookup(*lutpp, np)) == NULL) { /* this is the first time event is declared */ stats_counter_bump(countp); *lutpp = tree_event2np_lut_add(*lutpp, np, ret); ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, t); } else { /* was declared before, just add new nvpairs to its lutp */ decl->u.stmt.lutp = nvpair2lut(nvpairs, decl->u.stmt.lutp, t); } return (ret); } /*ARGSUSED*/ static void update_serd_refstmt(void *lhs, void *rhs, void *arg) { struct node *serd; ASSERT(rhs != NULL); serd = tree_s2np_lut_lookup(((struct node *)rhs)->u.stmt.lutp, L_engine); if (serd == NULL) return; ASSERT(serd->t == T_EVENT); if (arg != NULL && tree_eventcmp(serd, (struct node *)arg) != 0) return; serd = tree_event2np_lut_lookup(SERDs, serd); if (serd != NULL) serd->u.stmt.flags |= STMT_REF; } struct node * tree_decl(enum nodetype t, struct node *np, struct node *nvpairs, const char *file, int line) { struct node *decl; struct node *ret; ASSERT(np != NULL); check_type_iterator(np); switch (t) { case T_EVENT: /* determine the type of event being declared */ ASSERT(np->u.event.ename->t == T_NAME); switch (np->u.event.ename->u.name.t) { case N_FAULT: ret = dodecl(T_FAULT, file, line, np, nvpairs, &Faults, Faultcount, 0); /* increment serd statement reference */ decl = tree_event2np_lut_lookup(Faults, np); update_serd_refstmt(NULL, decl, NULL); break; case N_UPSET: ret = dodecl(T_UPSET, file, line, np, nvpairs, &Upsets, Upsetcount, 0); /* increment serd statement reference */ decl = tree_event2np_lut_lookup(Upsets, np); update_serd_refstmt(NULL, decl, NULL); break; case N_DEFECT: ret = dodecl(T_DEFECT, file, line, np, nvpairs, &Defects, Defectcount, 0); /* increment serd statement reference */ decl = tree_event2np_lut_lookup(Defects, np); update_serd_refstmt(NULL, decl, NULL); break; case N_ERROR: ret = dodecl(T_ERROR, file, line, np, nvpairs, &Errors, Errorcount, 0); break; case N_EREPORT: ret = dodecl(T_EREPORT, file, line, np, nvpairs, &Ereports, Ereportcount, 0); /* * Keep a lut of just the enames, so that the DE * can subscribe to a uniqified list of event * classes. */ Ereportenames = tree_name2np_lut_add(Ereportenames, np->u.event.ename, np); /* * Keep a lut of the enames (event classes) to * silently discard if we can't find a matching * configuration node when an ereport of of a given * class is received. Such events are declaired * with 'discard_if_config_unknown=1'. */ if (tree_s2np_lut_lookup(ret->u.stmt.lutp, L_discard_if_config_unknown)) { Ereportenames_discard = lut_add( Ereportenames_discard, (void *)np->u.event.ename->u.name.s, (void *)np->u.event.ename->u.name.s, NULL); } break; default: outfl(O_ERR, file, line, "tree_decl: internal error, event name type %s", ptree_nametype2str(np->u.event.ename->u.name.t)); } break; case T_ENGINE: /* determine the type of engine being declared */ ASSERT(np->u.event.ename->t == T_NAME); switch (np->u.event.ename->u.name.t) { case N_SERD: ret = dodecl(T_SERD, file, line, np, nvpairs, &SERDs, SERDcount, 0); lut_walk(Upsets, update_serd_refstmt, np); break; case N_STAT: ret = dodecl(T_STAT, file, line, np, nvpairs, &STATs, STATcount, 0); break; default: outfl(O_ERR, file, line, "tree_decl: internal error, engine name type %s", ptree_nametype2str(np->u.event.ename->u.name.t)); } break; case T_ASRU: ret = dodecl(T_ASRU, file, line, np, nvpairs, &ASRUs, ASRUcount, 1); break; case T_FRU: ret = dodecl(T_FRU, file, line, np, nvpairs, &FRUs, FRUcount, 1); break; case T_CONFIG: /* * config statements are different from above: they * are not merged at all (until the configuration cache * code does its own style of merging. and the properties * are a free-for-all -- we don't check for allowed or * required config properties. */ ret = newnode(T_CONFIG, file, line); ret->u.stmt.np = np; ret->u.stmt.nvpairs = nvpairs; ret->u.stmt.lutp = nvpair2lut(nvpairs, NULL, T_CONFIG); if (lut_lookup(Configs, np, (lut_cmp)tree_namecmp) == NULL) stats_counter_bump(Configcount); Configs = lut_add(Configs, (void *)np, (void *)ret, NULL); break; default: out(O_DIE, "tree_decl: internal error, type %s", ptree_nodetype2str(t)); } return (ret); } /* keep backpointers in arrows to the prop they belong to (used for scoping) */ static void set_arrow_prop(struct node *prop, struct node *np) { if (np == NULL) return; if (np->t == T_ARROW) { np->u.arrow.prop = prop; set_arrow_prop(prop, np->u.arrow.lhs); /* * no need to recurse right or handle T_LIST since * T_ARROWs always cascade left and are at the top * of the parse tree. (you can see this in the rule * for "propbody" in escparse.y.) */ } } struct node * tree_stmt(enum nodetype t, struct node *np, const char *file, int line) { struct node *ret = newnode(t, file, line); struct node *pp; int inlist = 0; ret->u.stmt.np = np; switch (t) { case T_PROP: check_proplists(t, np); check_propnames(t, np, 0, 0); check_propscope(np); set_arrow_prop(ret, np); for (pp = Props; pp; pp = pp->u.stmt.next) { if (tree_treecmp(pp, ret, T_NAME, (lut_cmp)tree_namecmp) == 0) { inlist = 1; break; } } if (inlist == 0) stats_counter_bump(Propcount); /* "Props" is a linked list of all prop statements */ if (Lastprops) Lastprops->u.stmt.next = ret; else Props = ret; Lastprops = ret; break; case T_MASK: check_proplists(t, np); check_propnames(t, np, 0, 0); check_propscope(np); set_arrow_prop(ret, np); for (pp = Masks; pp; pp = pp->u.stmt.next) { if (tree_treecmp(pp, ret, T_NAME, (lut_cmp)tree_namecmp) == 0) { inlist = 1; break; } } if (inlist == 0) stats_counter_bump(Maskcount); /* "Masks" is a linked list of all mask statements */ if (Lastmasks) Lastmasks->u.stmt.next = ret; else Masks = ret; Lastmasks = ret; stats_counter_bump(Maskcount); break; default: outfl(O_DIE, np->file, np->line, "tree_stmt: internal error (t %d)", t); } return (ret); } void tree_report() { /* * The only declarations with required properties * currently are faults and serds. Make sure the * the declarations have the required properties. */ lut_walk(Faults, (lut_cb)check_required_props, (void *)T_FAULT); lut_walk(Upsets, (lut_cb)check_required_props, (void *)T_UPSET); lut_walk(Errors, (lut_cb)check_required_props, (void *)T_ERROR); lut_walk(Ereports, (lut_cb)check_required_props, (void *)T_EREPORT); lut_walk(SERDs, (lut_cb)check_required_props, (void *)T_SERD); lut_walk(STATs, (lut_cb)check_required_props, (void *)T_STAT); /* * we do this now rather than while building the parse * tree because it is inconvenient for the user if we * require SERD engines to be declared before used in * an upset "engine" property. */ lut_walk(Faults, (lut_cb)check_refcount, (void *)T_FAULT); lut_walk(Faults, (lut_cb)check_upset_engine, (void *)T_FAULT); lut_walk(Defects, (lut_cb)check_upset_engine, (void *)T_DEFECT); lut_walk(Upsets, (lut_cb)check_upset_engine, (void *)T_UPSET); lut_walk(Upsets, (lut_cb)check_refcount, (void *)T_UPSET); lut_walk(Errors, (lut_cb)check_refcount, (void *)T_ERROR); lut_walk(Ereports, (lut_cb)check_refcount, (void *)T_EREPORT); lut_walk(SERDs, (lut_cb)check_refcount, (void *)T_SERD); /* check for cycles */ lut_walk(Errors, (lut_cb)check_cycle, (void *)0); } /* compare two T_NAMES by only looking at components, not iterators */ int tree_namecmp(struct node *np1, struct node *np2) { ASSERT(np1 != NULL); ASSERT(np2 != NULL); ASSERTinfo(np1->t == T_NAME, ptree_nodetype2str(np1->t)); ASSERTinfo(np2->t == T_NAME, ptree_nodetype2str(np1->t)); while (np1 && np2 && np1->u.name.s == np2->u.name.s) { np1 = np1->u.name.next; np2 = np2->u.name.next; } if (np1 == NULL) if (np2 == NULL) return (0); else return (-1); else if (np2 == NULL) return (1); else return (np2->u.name.s - np1->u.name.s); } int tree_eventcmp(struct node *np1, struct node *np2) { int ret; ASSERT(np1 != NULL); ASSERT(np2 != NULL); ASSERTinfo(np1->t == T_EVENT, ptree_nodetype2str(np1->t)); ASSERTinfo(np2->t == T_EVENT, ptree_nodetype2str(np2->t)); if ((ret = tree_namecmp(np1->u.event.ename, np2->u.event.ename)) == 0) { if (np1->u.event.epname == NULL && np2->u.event.epname == NULL) return (0); else if (np1->u.event.epname == NULL) return (-1); else if (np2->u.event.epname == NULL) return (1); else return tree_namecmp(np1->u.event.epname, np2->u.event.epname); } else return (ret); } /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2008 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * tree.h -- public definitions for tree module * * the parse tree is made up of struct node's. the struct is * a "variant record" with a type, the filename and line number * related to the node, and then type-specific node data. */ #ifndef _ESC_COMMON_TREE_H #define _ESC_COMMON_TREE_H #ifdef __cplusplus extern "C" { #endif struct node { enum nodetype { T_NOTHING, /* used to keep going on error cases */ T_NAME, /* identifiers, sometimes chained */ T_GLOBID, /* globals (e.g. $a) */ T_EVENT, /* class@path{expr} */ T_ENGINE, /* upset threshold engine (e.g. SERD) */ T_ASRU, /* ASRU declaration */ T_FRU, /* FRU declaration */ T_TIMEVAL, /* num w/time suffix (ns internally) */ T_NUM, /* num (ull internally) */ T_QUOTE, /* quoted string */ T_FUNC, /* func(arglist) */ T_NVPAIR, /* name=value pair in decl */ T_ASSIGN, /* assignment statement */ T_CONDIF, /* a and T_CONDELSE in (a ? b : c ) */ T_CONDELSE, /* lists b and c in (a ? b : c ) */ T_NOT, /* boolean ! operator */ T_AND, /* boolean && operator */ T_OR, /* boolean || operator */ T_EQ, /* boolean == operator */ T_NE, /* boolean != operator */ T_SUB, /* integer - operator */ T_ADD, /* integer + operator */ T_MUL, /* integer * operator */ T_DIV, /* integer / operator */ T_MOD, /* integer % operator */ T_LT, /* boolean < operator */ T_LE, /* boolean <= operator */ T_GT, /* boolean > operator */ T_GE, /* boolean >= operator */ T_BITAND, /* bitwise & operator */ T_BITOR, /* bitwise | operator */ T_BITXOR, /* bitwise ^ operator */ T_BITNOT, /* bitwise ~ operator */ T_LSHIFT, /* bitwise << operator */ T_RSHIFT, /* bitwise >> operator */ T_ARROW, /* lhs (N)->(K) rhs */ T_LIST, /* comma-separated list */ T_FAULT, /* fault declaration */ T_UPSET, /* upset declaration */ T_DEFECT, /* defect declaration */ T_ERROR, /* error declaration */ T_EREPORT, /* ereport declaration */ T_SERD, /* SERD engine declaration */ T_STAT, /* STAT engine declaration */ T_PROP, /* prop statement */ T_MASK, /* mask statement */ T_CONFIG /* config statement */ } t:8; /* * regardless of the type of node, filename and line number * information from the original .esc file is tracked here. */ int line:24; const char *file; /* * the variant part of a struct node... */ union { struct { /* * info kept for T_NAME, used in several ways: * * 1 for simple variable names. * example: j * * 2 for event class names, with component * names chained together via the "next" * pointers. * example: fault.fan.broken * * 3 for component pathnames, with component * names chained together via the "next" * pointers and iterators or instance numbers * attached via the "child" pointers. * example: sysboard[0]/cpu[n] * * case 3 is the most interesting. * - if child is set, there's an iterator * - if child is a T_NAME, it is x[j] or x and * iterator type tells you vertical or horizontal * - if child is a T_NUM, it is x[0] or x<0> or * x0 and iterator type tells you which one * - if cp pointer is set, then we recently * matched it to a config cache entry and one * can ignore child for now because it still * represents the *pattern* you're matching. * cp represents what you matched. ptree() * knows that if cp is set, to print that number * instead of following child. * * when T_NAME nodes are chained: * the "last" pointer takes you to the end of the * chain, but only the first component's last pointer * is kept up to date. it is used to determine * where to append newly-created T_NAME nodes (see * tree_name_append()). */ const char *s; /* the name itself */ struct node *child; struct node *next; struct node *last; /* opaque pointer used during config matching */ struct config *cp; /* * note nametype is also declared as a three bit enum * in itree.h, so if this ever needs expanding that * will need changing too. */ enum nametype { N_UNSPEC, N_FAULT, N_UPSET, N_DEFECT, N_ERROR, N_EREPORT, N_SERD, N_STAT } t:3; enum itertype { IT_NONE, IT_VERTICAL, IT_HORIZONTAL, IT_ENAME } it:2; unsigned childgen:1; /* child was auto-generated */ } name; struct { /* * info kept for T_GLOBID */ const char *s; /* the name itself */ } globid; /* * info kept for T_TIMEVAL and T_NUM * * timevals are kept in nanoseconds. */ unsigned long long ull; struct { /* * info kept for T_QUOTE */ const char *s; /* the quoted string */ } quote; struct { /* * info kept for T_FUNC */ const char *s; /* name of function */ struct node *arglist; } func; struct { /* * info kept for T_PROP and T_MASK statements * as well as declarations for: * T_FAULT * T_UPSET * T_DEFECT * T_ERROR * T_EREPORT * T_ASRU * T_FRU * T_CONFIG */ struct node *np; struct node *nvpairs; /* for declarations */ struct lut *lutp; /* for declarations */ struct node *next; /* for Props & Masks lists */ struct node *expr; /* for if statements */ unsigned char flags; /* see STMT_ flags below */ } stmt; /* used for stmt */ struct { /* * info kept for T_EVENT */ struct node *ename; /* event class name */ struct node *epname; /* component path name */ struct node *oldepname; /* unwildcarded path name */ struct node *ewname; /* wildcarded portion */ struct node *eexprlist; /* constraint expression */ struct node *declp; /* event declaration */ } event; struct { /* * info kept for T_ARROW */ struct node *lhs; /* left side of arrow */ struct node *rhs; /* right side of arrow */ struct node *nnp; /* N value */ struct node *knp; /* K value */ struct node *prop; /* arrow is part of this prop */ int needed; struct node *parent; } arrow; struct { /* * info kept for everything else (T_ADD, T_LIST, etc.) */ struct node *left; struct node *right; int temp; } expr; } u; /* * Note to save memory the nodesize() function trims the end of this * structure, so best not to add anything after this point */ }; /* flags we keep with stmts */ #define STMT_REF 0x01 /* declared item is referenced */ #define STMT_CYMARK 0x02 /* declared item is marked for cycle check */ #define STMT_CYCLE 0x04 /* cycle detected and already reported */ #define TIMEVAL_EVENTUALLY (1000000000ULL*60*60*24*365*100) /* 100 years */ void tree_init(void); void tree_fini(void); struct node *newnode(enum nodetype t, const char *file, int line); void tree_free(struct node *root); struct node *tree_root(struct node *np); struct node *tree_nothing(void); struct node *tree_expr(enum nodetype t, struct node *left, struct node *right); struct node *tree_event(struct node *ename, struct node *epname, struct node *eexprlist); struct node *tree_if(struct node *expr, struct node *stmts, const char *file, int line); struct node *tree_name(const char *s, enum itertype it, const char *file, int line); struct node *tree_iname(const char *s, const char *file, int line); struct node *tree_globid(const char *s, const char *file, int line); struct node *tree_name_append(struct node *np1, struct node *np2); struct node *tree_name_repairdash(struct node *np1, const char *s); struct node *tree_name_repairdash2(const char *s, struct node *np1); struct node *tree_name_iterator(struct node *np1, struct node *np2); struct node *tree_timeval(const char *s, const char *suffix, const char *file, int line); struct node *tree_num(const char *s, const char *file, int line); struct node *tree_quote(const char *s, const char *file, int line); struct node *tree_func(const char *s, struct node *np, const char *file, int line); struct node *tree_pname(struct node *np); struct node *tree_arrow(struct node *lhs, struct node *nnp, struct node *knp, struct node *rhs); struct lut *tree_s2np_lut_add(struct lut *root, const char *s, struct node *np); struct node *tree_s2np_lut_lookup(struct lut *root, const char *s); struct lut *tree_name2np_lut_add(struct lut *root, struct node *namep, struct node *np); struct node *tree_name2np_lut_lookup(struct lut *root, struct node *namep); struct node *tree_name2np_lut_lookup_name(struct lut *root, struct node *namep); struct lut *tree_event2np_lut_add(struct lut *root, struct node *enp, struct node *np); struct node *tree_event2np_lut_lookup(struct lut *root, struct node *enp); struct node *tree_event2np_lut_lookup_event(struct lut *root, struct node *enp); struct node *tree_decl(enum nodetype t, struct node *enp, struct node *nvpairs, const char *file, int line); struct node *tree_stmt(enum nodetype t, struct node *np, const char *file, int line); void tree_report(); int tree_namecmp(struct node *np1, struct node *np2); int tree_eventcmp(struct node *np1, struct node *np2); extern struct lut *Faults; extern struct lut *Upsets; extern struct lut *Defects; extern struct lut *Errors; extern struct lut *Ereports; extern struct lut *Ereportenames; extern struct lut *Ereportenames_discard; extern struct lut *SERDs; extern struct lut *STATs; extern struct lut *ASRUs; extern struct lut *FRUs; extern struct lut *Configs; extern struct node *Props; extern struct node *Lastprops; extern struct node *Masks; extern struct node *Lastmasks; extern struct node *Problems; extern struct node *Lastproblems; #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_TREE_H */ /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License, Version 1.0 only * (the "License"). You may not use this file except in compliance * with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * verion.h -- define current version numbers for eversholt * */ #ifndef _ESC_COMMON_VERSION_H #define _ESC_COMMON_VERSION_H #ifdef __cplusplus extern "C" { #endif #define VERSION_MAJOR 1 #define VERSION_MINOR 16 #ifdef __cplusplus } #endif #endif /* _ESC_COMMON_VERSION_H */ # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" debug : TARGET += debug # Hammerhead: amd64-only SUBDIRS = $(MACH64) debug: $(SUBDIRS) include ../../Makefile.subdirs # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # .KEEP_STATE: PROG = eftinfo LOCALOBJS = eftinfo.o OBJS = $(LOCALOBJS) $(COMMONOBJS) SRCS = $(LOCALOBJS:.o=.c) $(COMMONSRCS) CPPFLAGS += -I../common CFLAGS += $(CTF_FLAGS) CFLAGS64 += $(CTF_FLAGS_64) LDLIBS += -lumem all: $(PROG) debug: $(PROG) include $(SRC)/cmd/fm/eversholt/Makefile.esc.com install: all $(ROOTPROG) LINTSRCS += $(LOCALOBJS:%.o=../common/%.c) LINTFLAGS = -mnux $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(CTFMRG) $(POST_PROCESS) clean: $(RM) $(OBJS) y.output y.tab.c y.tab.h clobber: clean $(RM) $(PROG) esclex.o: escparse.o %.o: ../common/%.c $(COMPILE.c) $< $(CTFCONVO) # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # Copyright 2025 Hammerhead Project # # Hammerhead: Include Makefile.cmd first to load Makefile.master # (defines COMPILE.c, COMPILE64.c needed by Makefile.esc.com's pattern rules) include $(SRC)/cmd/Makefile.cmd include ../Makefile.com include $(SRC)/cmd/Makefile.cmd.64 install: all $(ROOTPROG64) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * eftinfo.c -- main routine for eftinfo command * * argument processing and the general flow through all the other * modules is driven by this file. */ #include #include #ifdef sun #include #else #include #endif /* sun */ #include "out.h" #include "alloc.h" #include "stats.h" #include "stable.h" #include "literals.h" #include "lut.h" #include "esclex.h" #include "ptree.h" #include "tree.h" #include "check.h" #include "version.h" #include "eftread.h" /* stuff exported by yacc-generated parsers */ extern void yyparse(void); extern int yydebug; /* * This external definition has to be here. If we put it in literals.h * lint complains about the declaration not being used within the block * when compiling literals.c. */ extern void literals_init(void); static const char *Usage = "[-DEPghpqvw] eft-files..."; static const char *Help = "\t-D Print dictionaries EFT references.\n" "\t-E Print ereports EFT will consume.\n" "\t-P Print problems EFT can diagnose.\n" "\t-g Print generated iterators (use with -p)\n" "\t-h Print this help message\n" "\t-p Print complete propagation tree\n" "\t-q Quiet mode, no header info printed\n" "\t-v Enable verbose output\n" "\t-w Enable language warnings"; /* * and some undocumented extras... * "\t-S Print stats for compiler memory usage, etc.\n" * "\t-Y Enable parser debug output\n" * "\t-d Enable general debug output\n" * "\t-y Enable lexer debug output\n" * */ int Debug; int Verbose; int Warn; extern int Pchildgen; /* flag to ptree for printing generated interators */ extern struct lut *Dicts; /*ARGSUSED*/ static void dictprint(const char *s, void *rhs, void *arg) { static char *sep = ""; out(O_OK|O_NONL, "%s%s", sep, s); sep = ":"; } int main(int argc, char *argv[]) { int c; int count; int Dflag = 0; int Eflag = 0; int yflag = 0; int Pflag = 0; int Sflag = 0; int pflag = 0; int qflag = 0; alloc_init(); out_init(argv[0]); stats_init(1); /* extended stats always enabled for eftinfo */ stable_init(0); literals_init(); lut_init(); tree_init(); while ((c = getopt(argc, argv, "DEPSYdghpqvwy")) != EOF) { switch (c) { case 'D': Dflag++; break; case 'E': Eflag++; break; case 'y': yflag++; break; case 'P': Pflag++; break; case 'S': Sflag++; break; case 'Y': yydebug++; break; case 'd': Debug++; break; case 'g': Pchildgen++; break; case 'h': case '?': out(O_PROG, "version %d.%d", VERSION_MAJOR, VERSION_MINOR); out(O_DIE|O_USAGE, "%s\n%s", Usage, Help); /*NOTREACHED*/ break; case 'p': pflag++; break; case 'q': qflag++; break; case 'v': Verbose++; break; case 'w': Warn++; break; default: out(O_DIE|O_USAGE, Usage); /*NOTREACHED*/ } } out(O_PROG|O_VERB, "version %d.%d", VERSION_MAJOR, VERSION_MINOR); argc -= optind; if (argc < 1) out(O_DIE|O_USAGE, Usage); if (!qflag) eftread_showheader(1); lex_init(&argv[optind], NULL, yflag); check_init(); yyparse(); (void) lex_fini(); tree_report(); if (count = out_errcount()) out(O_DIE, "%d error%s encountered, exiting.", OUTS(count)); if (Dflag) { out(O_OK|O_NONL, "Dictionaries: "); lut_walk(Dicts, (lut_cb)dictprint, (void *)0); out(O_OK, NULL); } if (Eflag) ptree_ereport(O_OK, NULL); if (Pflag) { ptree_fault(O_OK, NULL); ptree_upset(O_OK, NULL); ptree_defect(O_OK, NULL); } if (pflag) ptree_name_iter(O_OK, tree_root(NULL)); if (Sflag) { out(O_OK, "Stats:"); stats_publish(); } out_exit(0); /*NOTREACHED*/ return (0); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # #ident "%Z%%M% %I% %E% SMI" debug : TARGET += debug # Hammerhead: amd64-only SUBDIRS = $(MACH64) debug: $(SUBDIRS) include ../../Makefile.subdirs # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # .KEEP_STATE: PROG = esc include $(SRC)/cmd/fm/eversholt/Makefile.esc.com EFTCLASS = writer LOCALOBJS = escmain.o OBJS = $(LOCALOBJS) $(COMMONOBJS) SRCS = $(LOCALOBJS:.o=.c) $(COMMONSRCS) CPPFLAGS += -I../common CFLAGS += -DESC $(CTF_FLAGS) CFLAGS64 += -DESC $(CTF_FLAGS_64) LDLIBS += -lumem all debug: $(PROG) install: all $(ROOTPROG) $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(CTFMRG) $(POST_PROCESS) clean: $(RM) $(OBJS) y.output y.tab.c y.tab.h clobber: clean $(RM) $(PROG) esclex.o: escparse.o %.o: ../common/%.c $(COMPILE.c) $< $(CTFCONVO) # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # Copyright 2025 Hammerhead Project # # Hammerhead: Include Makefile.cmd first to load Makefile.master # (defines COMPILE.c, COMPILE64.c needed by Makefile.esc.com's pattern rules) include $(SRC)/cmd/Makefile.cmd include ../Makefile.com include $(SRC)/cmd/Makefile.cmd.64 install: all $(ROOTPROG64) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2006 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. * * escmain.c -- main routine for esc, the eversholt compiler * * argument processing and the general flow through all the other * modules is driven by this file. */ #include #include #ifdef sun #include #else #include #endif /* sun */ #include "out.h" #include "stats.h" #include "alloc.h" #include "stable.h" #include "literals.h" #include "lut.h" #include "esclex.h" #include "eftwrite.h" #include "ptree.h" #include "tree.h" #include "check.h" #include "version.h" /* stuff exported by yacc-generated parsers */ extern void yyparse(void); extern int yydebug; /* * This external definition has to be here. If we put it in literals.h * lint complains about the declaration not being used within the block * when compiling literals.c. */ extern void literals_init(void); static const char *Usage = "[-SYdghpqvy] [-Dname[=def]] [-I dir] [-Uname] [-o outfile] esc-files..."; static const char *Help = "\tinput files are run through cpp and concatenated.\n" "\t-D name[=def] Pass to cpp\n" "\t-I dir Pass to cpp\n" "\t-S Print stats for compiler memory usage, etc.\n" "\t-U name Pass to cpp\n" "\t-Y Enable parser debug output\n" "\t-d Enable general debug output\n" "\t-g Print generated iterators (use with -p)\n" "\t-h Print this help message\n" "\t-o outfile Emit compiled EFT to \"outfile\"\n" "\t-p Print complete parse tree\n" "\t-q Quiet mode: suppress warnings\n" "\t-v Enable verbose output\n" "\t-y Enable lexer debug output"; int Debug; int Verbose; int Warn = 1; /* the esc compiler should issue language warnings */ extern int Pchildgen; /* flag to ptree for printing generated iterators */ #define MAXARGS 8192 char Args[MAXARGS]; #define MAXCPPARGS 4000 static char Cppargs[MAXCPPARGS]; int main(int argc, char *argv[]) { char flagbuf[] = " -D"; char **av; int c; int stats = 0; int lexecho = 0; const char *outfile = NULL; int count; int i; int pflag = 0; alloc_init(); out_init(argv[0]); stats_init(1); /* extended stats always enabled for esc */ stable_init(0); literals_init(); lut_init(); tree_init(); eftwrite_init(); /* built a best effort summary of args for eftwrite() */ count = 0; for (i = 1; i < argc; i++) { char *ptr = argv[i]; if (count < MAXARGS - 1) Args[count++] = ' '; while (count < MAXARGS - 1 && *ptr) Args[count++] = *ptr++; } Args[count] = '\0'; while ((c = getopt(argc, argv, "D:I:SU:Ydgho:pqvy")) != EOF) { switch (c) { case 'D': case 'I': case 'U': if (strlen(optarg) + strlen(Cppargs) + 4 >= MAXCPPARGS) out(O_DIE, "cpp args too long (max %d bytes)", MAXCPPARGS); flagbuf[2] = c; (void) strcat(Cppargs, flagbuf); (void) strcat(Cppargs, optarg); break; case 'S': stats++; break; case 'Y': yydebug++; break; case 'd': Debug++; break; case 'g': Pchildgen++; break; case 'h': case '?': out(O_PROG, "eversholt compiler version %d.%d", VERSION_MAJOR, VERSION_MINOR); out(O_DIE|O_USAGE, "%s\n%s", Usage, Help); /*NOTREACHED*/ break; case 'o': outfile = optarg; break; case 'p': pflag++; break; case 'q': Warn = 0; break; case 'v': Verbose++; break; case 'y': lexecho++; break; default: out(O_DIE|O_USAGE, Usage); /*NOTREACHED*/ } } out(O_PROG|O_VERB, "eversholt compiler version %d.%d", VERSION_MAJOR, VERSION_MINOR); argc -= optind; av = &argv[optind]; if (argc < 1) { out(O_ERR, "no esc source files given"); out(O_DIE|O_USAGE, Usage); /*NOTREACHED*/ } lex_init(av, Cppargs, lexecho); check_init(); yyparse(); (void) lex_fini(); tree_report(); if (count = out_errcount()) out(O_DIE, "%d language error%s encountered, exiting.", OUTS(count)); if (outfile) eftwrite(outfile); if (pflag) ptree_name_iter(O_OK, tree_root(NULL)); if (stats) { out(O_OK, "Stats:"); stats_publish(); } out_exit(0); /*NOTREACHED*/ return (0); } # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Hammerhead: amd64-only SUBDIRS=$(MACH64) include ../../Makefile.subdirs # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License (the "License"). # You may not use this file except in compliance with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2009 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # .SUFFIXES: .eft .esc ESC=$(SRC)/cmd/fm/eversholt/native/$(MACH64)/esc include $(SRC)/cmd/Makefile.cmd ROOT_EFT_ROOT= $(ROOT)/usr/lib/fm/eft ROOT_COMMON_EFT_FILES= $(EFT_COMMON_FILES:%=$(ROOT_EFT_ROOT)/%) USR_PLAT_FM_DIR= $(ROOT)/usr/platform/$(EFT_PLAT)/lib/fm USR_PLAT_EFT_DIR= $(USR_PLAT_FM_DIR)/eft USR_PLAT_EFT_FILES= $(EFT_PLAT_FILES:%=$(USR_PLAT_EFT_DIR)/%) # # Override the built-in ESC pre-processor with a reference to the one we # have set in Makefile.master. This ensures that we use the same cpp # throughout the build. # ESC_ENV=_ESC_CPP=$(CPP) # # Default target - specify before including Makefile.rootdirs which would # otherwise provide a default # install: all include $(SRC)/cmd/fm/eversholt/Makefile.rootdirs all: FILEMODE = 0444 all: $(ROOT_EFT_ROOT) $(USR_PLAT_EFT_FILES) $(ROOT_COMMON_EFT_FILES) install_h lint _msg: clean clobber: $(RM) $(EFT_PLAT_FILES) $(EFT_COMMON_FILES) \ $(USR_PLAT_EFT_FILES) $(ROOT_COMMON_EFT_FILES) ESCFLAGS= -D_ESC -I$(ROOT)/usr/include pciexrc.eft : ESCFLAGS += -I$(SRC)/uts/sun4v/io/px %.eft: ../common/%.esc $(ESC_ENV) $(ESC) $(ESCFLAGS) -o $@ $< %.eft: %.esc $(ESC_ENV) $(ESC) $(ESCFLAGS) -o $@ $< # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # Copyright 2025 Hammerhead Project # # Hammerhead: pciexrc.eft excluded - requires SPARC sun4v px_err.h header EFT_COMMON_FILES = \ disk.eft \ neptune_xaui.eft \ neptune_xfp.eft \ nic.eft \ pci.eft \ pciex.eft \ sca1000.eft \ sca500.eft \ sensor.eft \ storage.eft # No platform-specific files for amd64 EFT_PLAT_FILES = EFT_PLAT = include ../Makefile.com include $(SRC)/cmd/Makefile.cmd.64 install: all $(ROOTPROG64) /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. * Copyright 2016 Nexenta Systems, Inc. All rights reserved. */ #pragma dictionary "DISK" #define P disk fru P; asru P; /* * Over all comments for this file: * The disk-as-detector DE provides the mapping between * ereports generated by a kernel disk driver sd(4D) and resulting faults. */ /* * SERD engine for media error fault propagation: * * This strategy is designed to give a file system, like ZFS, the * ability to attempt data recovery/relocation without faulting a disk. * This implementation depends on a file system retry to the same lba * to trigger a fault when recovery/relocation is not possible. * * We let the engine propagate one error only once every 1 minute and then if we * still get 2 or more errors within 24 hours for the same LBA, * there is a fault. */ engine serd.io.scsi.cmd.disk.dev.rqs.merr@P, N=1, T=24h; /* * disk-as-detector: fault events. */ event fault.io.scsi.cmd.disk.dev.rqs.derr@P; event fault.io.scsi.cmd.disk.dev.rqs.merr@P, engine=serd.io.scsi.cmd.disk.dev.rqs.merr@P; /* * The uderr fault will be defined at some future time. * event fault.io.scsi.cmd.disk.dev.uderr@P; */ /* * disk-as-detector: upset events. * NOTE: For now we define an upset to implement discard. */ event upset.io.scsi.cmd.disk.dev.rqs.derr@P; event upset.io.scsi.cmd.disk.dev.rqs.merr@P; event upset.io.scsi.cmd.disk.dev.uderr@P; event upset.io.scsi.cmd.disk.dev.serr@P; event upset.io.scsi.cmd.disk.tran@P; event upset.io.scsi.cmd.disk.recovered@P; /* * disk-as-detector: ereports from the kernel. * * We don't know the topology for all scsi disks, but the kernel will always * generate ereport telemetry assuming that we do. We define these ereports * with 'discard_if_config_unknown=1', which permits ereports against things * with unknown topology to be silently discarded. The ereport data is logged * in either case, and can be viewed via 'fmdump -eV'. */ event ereport.io.scsi.cmd.disk.dev.rqs.derr@P, discard_if_config_unknown=1; event ereport.io.scsi.cmd.disk.dev.rqs.merr@P, discard_if_config_unknown=1; event ereport.io.scsi.cmd.disk.dev.serr@P, discard_if_config_unknown=1; event ereport.io.scsi.cmd.disk.dev.uderr@P, discard_if_config_unknown=1; event ereport.io.scsi.cmd.disk.recovered@P, discard_if_config_unknown=1; event ereport.io.scsi.cmd.disk.tran@P, discard_if_config_unknown=1; /* * For some ereports we let the 'driver-assessment', communicated as part of * the ereport payload, determine fault .vs. upset via propagation constraints. */ #define DRIVER_ASSESSMENT_FATAL \ (payloadprop_contains("driver-assessment", "fatal")) #define DRIVER_ASSESSMENT_NONFATAL (!DRIVER_ASSESSMENT_FATAL) /* * disk-as-detector: propagations from faults(based on * DRIVER_ASSESSMENT_FATAL). * We need to set additional fault payloads to indicate fault details. * The payload we may need are listed as following: * fault.io.scsi.cmd.disk.dev.rqs.derr * op_code, key, asc, ascq * fault.io.scsi.cmd.disk.dev.rqs.merr * op_code, key, asc, ascq, lba */ prop fault.io.scsi.cmd.disk.dev.rqs.derr@P-> ereport.io.scsi.cmd.disk.dev.rqs.derr@P{ DRIVER_ASSESSMENT_FATAL && setpayloadprop("key", payloadprop("key")) && setpayloadprop("asc", payloadprop("asc")) && setpayloadprop("ascq", payloadprop("ascq"))}; /* * Utilize setserdsuffix with specific LBA, * the serd engine would only trigger if the fault recurred on the same LBA */ prop fault.io.scsi.cmd.disk.dev.rqs.merr@P-> ereport.io.scsi.cmd.disk.dev.rqs.merr@P{ DRIVER_ASSESSMENT_FATAL && setserdsuffix(payloadprop("lba")) && setpayloadprop("key", payloadprop("key")) && setpayloadprop("asc", payloadprop("asc")) && setpayloadprop("ascq", payloadprop("ascq")) && setpayloadprop("lba", payloadprop("lba"))}; /* * NOTE: this propagation uses the "may" propagation of eversholt. * The ereport need never exist. It's just a way of making * the diagnosis wait for the within time on that ereport * to complete. Once it has completed the diagnosis continues * even though the dummy ereport didn't occur. */ event ereport.io.scsi.cmd.disk.dev.rqs.merr.dummy@P {within(60s)}; prop fault.io.scsi.cmd.disk.dev.rqs.merr@P (0) -> ereport.io.scsi.cmd.disk.dev.rqs.merr.dummy@P; /* * The uderr fault will be propagated at some future time. * prop fault.io.scsi.cmd.disk.dev.uderr@P-> * ereport.io.scsi.cmd.disk.dev.uderr@P{ DRIVER_ASSESSMENT_FATAL }; */ /* * disk-as-detector: propagations from upsets(based on * DRIVER_ASSESSMENT_NONFATAL). */ prop upset.io.scsi.cmd.disk.dev.rqs.derr@P-> ereport.io.scsi.cmd.disk.dev.rqs.derr@P{ DRIVER_ASSESSMENT_NONFATAL }; prop upset.io.scsi.cmd.disk.dev.rqs.merr@P-> ereport.io.scsi.cmd.disk.dev.rqs.merr@P{ DRIVER_ASSESSMENT_NONFATAL }; /* * disk-as-detector: propagations from upsets(independent of * driver-assessment) */ prop upset.io.scsi.cmd.disk.dev.serr@P-> ereport.io.scsi.cmd.disk.dev.serr@P; prop upset.io.scsi.cmd.disk.dev.uderr@P-> ereport.io.scsi.cmd.disk.dev.uderr@P; prop upset.io.scsi.cmd.disk.recovered@P-> ereport.io.scsi.cmd.disk.recovered@P; prop upset.io.scsi.cmd.disk.tran@P-> ereport.io.scsi.cmd.disk.tran@P; /* * -------------------------------------- * The remainder of this file contains rules associated with the operation of * cmd/fm/modules/common/disk-monitor/disk_monitor.c code. * * The disk DE provides a very simple 1-to-1 mapping between SCSI disk events * generated by the disk-transport fmd module, and the resulting faults. */ /* * Fault events. */ event fault.io.disk.over-temperature@P, FITrate=10, FRU=P, ASRU=P; event fault.io.disk.predictive-failure@P, FITrate=10, FITrate=10, FRU=P, ASRU=P; event fault.io.disk.self-test-failure@P, FITrate=10, FITrate=10, FRU=P, ASRU=P; event fault.io.disk.ssm-wearout@P; /* * ereports. */ event ereport.io.scsi.disk.over-temperature@P; event ereport.io.scsi.disk.predictive-failure@P; event ereport.io.scsi.disk.self-test-failure@P; event ereport.io.scsi.disk.ssm-wearout@P; /* * Propagations. */ prop fault.io.disk.over-temperature@P -> ereport.io.scsi.disk.over-temperature@P; prop fault.io.disk.self-test-failure@P -> ereport.io.scsi.disk.self-test-failure@P; prop fault.io.disk.predictive-failure@P -> ereport.io.scsi.disk.predictive-failure@P { setpayloadprop("asc", payloadprop("additional-sense-code")) && setpayloadprop("ascq", payloadprop("additional-sense-code-qualifier")) }; prop fault.io.disk.ssm-wearout@P -> ereport.io.scsi.disk.ssm-wearout@P { setpayloadprop("current-wearout-percentage", payloadprop("current-ssm-wearout")) && setpayloadprop("threshold-wearout-percentage", payloadprop("threshold-ssm-wearout")) }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma dictionary "NXGE" /* * Eversholt rules for a XAUI card inserted in a PCI-Express slot. */ #define PCIEX_DEV_FIT 1000 asru pciexbus/pciexdev/pciexfn; fru pciexbus/pciexdev; event fault.io.pciex.device-interr@pciexbus/pciexdev/pciexfn, FITrate=PCIEX_DEV_FIT, FRU=pciexbus/pciexdev, ASRU=pciexbus/pciexdev/pciexfn; event error.io.device.nxge.xaui-err@pciexbus/pciexdev/pciexfn; event ereport.io.device.nxge.xaui-err@pciexbus/pciexdev/pciexfn {within(10s)}; event ereport.io.service.lost@pciexbus/pciexdev/pciexfn {within(10s)}; prop fault.io.pciex.device-interr@pciexbus/pciexdev/pciexfn (0) -> error.io.device.nxge.xaui-err@pciexbus/pciexdev/pciexfn; prop error.io.device.nxge.xaui-err@pciexbus/pciexdev/pciexfn (2) -> ereport.io.device.nxge.xaui-err@pciexbus/pciexdev/pciexfn, ereport.io.service.lost@pciexbus/pciexdev/pciexfn; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2007 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma dictionary "NXGE" /* * Eversholt rules for the XFP optical transceiver inserted into * a Neptune based NIC card. */ #define XFP_FIT 100 asru pciexbus/pciexdev/pciexfn; fru pciexbus/pciexdev/pciexfn/xfp; event fault.io.n2.niu-xfp@pciexbus/pciexdev/pciexfn/xfp FITrate=XFP_FIT, FRU=pciexbus/pciexdev/pciexfn/xfp, ASRU=pciexbus/pciexdev/pciexfn; /* * Add 5 seconds constraint so that multiple identical ereports * occuring within 10 seconds are considered symptoms of a single fault */ event error.io.device.nxge.xfp-err@pciexbus/pciexdev/pciexfn; event ereport.io.device.nxge.xfp-err@pciexbus/pciexdev/pciexfn {within(10s)}; event ereport.io.service.lost@pciexbus/pciexdev/pciexfn {within(10s)}; /* * Events ereport.io.device.nxge.xfp-err and ereport.io.service.lost are * related because the driver calls ddi_fm_service_impact right after * generating the xfp-err ereport. A internal error.io.device.nxge.xfp-err * is generated only after the FMD has received both ereport.io.device. * nxge.xfp-err and ereport.io.service.lost, then the error event will * trigger fault.io.n2.niu-xfp. Based on the following rules, the diagnose * engine will generate only one fault (fault.io.n2.niu-xfp) instead of two * (associated with ereport.io.device.nxge.xfp-err and ereport.io.service.lost * respectively). */ prop fault.io.n2.niu-xfp@pciexbus/pciexdev/pciexfn/xfp (1) -> error.io.device.nxge.xfp-err@pciexbus/pciexdev/pciexfn; prop error.io.device.nxge.xfp-err@pciexbus/pciexdev/pciexfn (2) -> ereport.io.device.nxge.xfp-err@pciexbus/pciexdev/pciexfn, ereport.io.service.lost@pciexbus/pciexdev/pciexfn; /* * This file and its contents are supplied under the terms of the * Common Development and Distribution License ("CDDL"), version 1.0. * You may only use this file in accordance with the terms of version * 1.0 of the CDDL. * * A full copy of the text of the CDDL should have accompanied this * source. A copy of the CDDL is also available via the Internet at * http://www.illumos.org/license/CDDL. */ /* * Copyright 2020, the University of Queensland */ #pragma dictionary "NIC" /* * Rules for the generic NIC (non-driver-specific) fault events. */ /* * Transceiver events are emitted by drivers under ereport.io.nic.txr-err. * * These are emitted with detector = the PCI/PCIex function of the NIC. * They must always have a string property "error", set to one of the * generic transceiver fault type names (notsupp, whitelist, overtemp etc). * * As well as "error", they must have both the "port_index" and "txr_index" * properties set in the event payload (both integer types). * * It is expected that drivers will call ddi_fm_service_impact() immediately * after noticing a transceiver error, with an argument of DDI_SERVICE_LOST or * DDI_SERVICE_DEGRADED (depending on the specific error -- at time of writing * all the supported events expect DDI_SERVICE_LOST). */ asru pcifn; fru pcifn/port/transceiver; asru pciexfn; fru pciexfn/port/transceiver; #define EV_DECL_TXR_FAULT(TYPE) \ event fault.io.nic.transceiver.TYPE@pcifn/port/transceiver \ FRU=pcifn/port/transceiver, ASRU=pcifn; \ event fault.io.nic.transceiver.TYPE@pciexfn/port/transceiver \ FRU=pciexfn/port/transceiver, ASRU=pciexfn; EV_DECL_TXR_FAULT(notsupp) EV_DECL_TXR_FAULT(whitelist) EV_DECL_TXR_FAULT(overtemp) EV_DECL_TXR_FAULT(hwfail) EV_DECL_TXR_FAULT(unknown) event ereport.io.nic.txr-err@pcifn; event ereport.io.service.lost@pcifn; event ereport.io.nic.txr-err@pciexfn; event ereport.io.service.lost@pciexfn; #define EV_PROP_TXR_FAULT(TYPE) \ prop fault.io.nic.transceiver.TYPE@pcifn/port[pn]/transceiver[tn] (2) -> \ ereport.io.nic.txr-err@pcifn { \ payloadprop("txr_index") == tn && \ payloadprop("port_index") == pn && \ payloadprop("error") == "TYPE" && \ setpayloadprop("txr_index", tn) && \ setpayloadprop("link-name", confprop(pcifn/port[pn], "link-name")) && \ setpayloadprop("primary-mac-address", confprop(pcifn/port[pn], "primary-mac-address")) && \ (!confprop_defined(pcifn/port[pn]/transceiver[tn], "vendor") || \ setpayloadprop("vendor", confprop(pcifn/port[pn]/transceiver[tn], "vendor"))) \ }, \ ereport.io.service.lost@pcifn { within(1s) }; \ prop fault.io.nic.transceiver.TYPE@pciexfn/port[pn]/transceiver[tn] (2) -> \ ereport.io.nic.txr-err@pciexfn { \ payloadprop("txr_index") == tn && \ payloadprop("port_index") == pn && \ payloadprop("error") == "TYPE" && \ setpayloadprop("txr_index", tn) && \ setpayloadprop("link-name", confprop(pciexfn/port[pn], "link-name")) && \ setpayloadprop("primary-mac-address", confprop(pciexfn/port[pn], "primary-mac-address")) && \ (!confprop_defined(pciexfn/port[pn]/transceiver[tn], "vendor") || \ setpayloadprop("vendor", confprop(pciexfn/port[pn]/transceiver[tn], "vendor"))) \ }, \ ereport.io.service.lost@pciexfn { within(1s) }; EV_PROP_TXR_FAULT(notsupp) EV_PROP_TXR_FAULT(whitelist) EV_PROP_TXR_FAULT(overtemp) EV_PROP_TXR_FAULT(hwfail) EV_PROP_TXR_FAULT(unknown) /* * Allow drivers (e.g. i40e) which can't tell the difference between the events * notsupp/unknown/whitelist to generate a single ereport covering all 3. * * If transceiver information is available in topo, we will turn it into * a "notsupp" fault. If it isn't, we'll turn it into an "unknown" fault * instead. The text in "notsupp" explicitly notes that certain drivers might * have difficulty telling the difference between it and "whitelist". * * If you want this for a pcifn driver rather than pciexfn, you'll have to * make another copy. */ prop fault.io.nic.transceiver.notsupp@pciexfn/port[pn]/transceiver[tn] (2) -> ereport.io.nic.txr-err@pciexfn { payloadprop("txr_index") == tn && payloadprop("port_index") == pn && payloadprop("error") == "notsupp/unknown" && confprop_defined(pciexfn/port[pn]/transceiver[tn], "vendor") && setpayloadprop("txr_index", tn) && setpayloadprop("link-name", confprop(pciexfn/port[pn], "link-name")) && setpayloadprop("primary-mac-address", confprop(pciexfn/port[pn], "primary-mac-address")) && setpayloadprop("vendor", confprop(pciexfn/port[pn]/transceiver[tn], "vendor")) }, ereport.io.service.lost@pciexfn { within(1s) }; prop fault.io.nic.transceiver.unknown@pciexfn/port[pn]/transceiver[tn] (2) -> ereport.io.nic.txr-err@pciexfn { payloadprop("txr_index") == tn && payloadprop("port_index") == pn && payloadprop("error") == "notsupp/unknown" && !confprop_defined(pciexfn/port[pn]/transceiver[tn], "vendor") && setpayloadprop("txr_index", tn) && setpayloadprop("link-name", confprop(pciexfn/port[pn], "link-name")) && setpayloadprop("primary-mac-address", confprop(pciexfn/port[pn], "primary-mac-address")) }, ereport.io.service.lost@pciexfn { within(1s) }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma dictionary "PCI" #include #define PCI_DEV_FIT 1000 #define PCI_BUS_FIT 500 /* * SERD parameters. * * Nonfatal dpe errors have to be recovered by the hardened driver which may * cause intermittant performance/responsiveness problems, so we have tighter * serd parameters for these. These are most likely errors in buffers/caches * within devices and bridges, so use similar rates to cpu data cache parity * errors. * * We will be more conservative about nonfatal internal errors reported * by the driver. */ #define NONFATAL_COUNT 6 #define NONFATAL_TIME 2h #define NONFATAL_DPE_COUNT 3 #define NONFATAL_DPE_TIME 168h #define PCIFN pcibus/pcidev/pcifn #define PCIFNHZ pcibus<>/pcidev<>/pcifn<> engine serd.io.device.nonfatal@PCIFN, N=NONFATAL_COUNT, T=NONFATAL_TIME; engine serd.io.pci.nf-dpe@PCIFN, N=NONFATAL_DPE_COUNT, T=NONFATAL_DPE_TIME; engine serd.io.pci.nf-dpe-bus@pcibus, N=NONFATAL_DPE_COUNT, T=NONFATAL_DPE_TIME; #define IS_LEAF \ (confprop_defined(PCIFN, TOPO_PCI_CLASS) && \ confprop(PCIFN, TOPO_PCI_CLASS) != "60400" && \ confprop(PCIFN, TOPO_PCI_CLASS) != "60401") #define IS_BDG \ (confprop(PCIFN, TOPO_PCI_CLASS) == "60400" || \ confprop(PCIFN, TOPO_PCI_CLASS) == "60401") #define FD_IS_LEAF \ (confprop_defined(pcibus/pcidev[fromdev]/pcifn, TOPO_PCI_CLASS) && \ confprop(pcibus/pcidev[fromdev]/pcifn, TOPO_PCI_CLASS) != "60400" && \ confprop(pcibus/pcidev[fromdev]/pcifn, TOPO_PCI_CLASS) != "60401") #define IS_LF(f) (confprop_defined(f, TOPO_PCI_CLASS) && \ confprop(f, TOPO_PCI_CLASS) != "60400" && \ confprop(f, TOPO_PCI_CLASS) != "60401") /* * note general rule for errors is that for upstream propagations * @PCIFN is the sending device while for downstream * propagations it is the receiving device. */ event fault.io.pci.device-interr-corr@PCIFN, engine=serd.io.device.nonfatal@PCIFN, FITrate=PCI_DEV_FIT; event fault.io.pci.device-interr-unaf@PCIFN, engine=serd.io.pci.nf-dpe@PCIFN, FITrate=PCI_DEV_FIT; event fault.io.pci.device-interr-deg@PCIFN, FITrate=PCI_DEV_FIT, retire=0; event fault.io.pci.device-interr@PCIFN, FITrate=PCI_DEV_FIT; event fault.io.pci.device-invreq@PCIFN, FITrate=PCI_DEV_FIT; event fault.io.pci.device-noresp@PCIFN, FITrate=PCI_DEV_FIT; event fault.io.pci.fw_corrupt@PCIFN, FITrate=PCI_DEV_FIT, retire=0; event fault.io.pci.fw_mismatch@PCIFN, FITrate=PCI_DEV_FIT, retire=0; /* * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * A faulty hostbridge may cause: * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * - nr-pw-d: the device not to respond to an upstream request * - nr-drw-d: the device not to respond to an upstream request * - ta-pw-d: the device to send a target abort to an upstream request * - ta-drw-d: the device to send a target abort to an upstream request * - serr-u: the device to report itself in error * - badreq-pw-d:a bad downstream request - not parity error (may cause target * to target abort or master abort) * - badreq-drw-d:a bad downstream request - not parity error (may cause * target to target abort or master abort) * - ape-d: address/parity to get corrupted during downstream transmission * - scpe-d: split completion to get corrupted during downstream transmission * - dpe-d: the device to transfer bad data and/or bad parity downstream * - retry-to-d: the device to exceed the set timeout for a delayed * transaction retry. */ #define PCI_TO_HB pcibus/pcidev/pcifn<> {fromdev != 32 && todev == 32} #define PCI_FROM_HB pcibus/pcidev/pcifn<> {fromdev == 32 && todev != 32} event error.io.pci.retry-to-d@PCIFN; event error.io.pci.nr-pw-d@PCIFN; event error.io.pci.nr-drw-d@PCIFN; event error.io.pci.ta-pw-d@PCIFN; event error.io.pci.ta-drw-d@PCIFN; event error.io.pci.badreq-pw-d@PCIFN; event error.io.pci.badreq-drw-d@PCIFN; event error.io.pci.f-dpe-d@PCIFN; event error.io.pci.deg-dpe-d@PCIFN; event error.io.pci.nf-dpe-d@PCIFN; event error.io.pci.ape-d@PCIFN; event error.io.pci.ape-u@PCIFN; event error.io.pci.dpdata-dw-d@PCIFN; event error.io.pci.dpdata-pw-d@PCIFN; event error.io.pci.dpdata-dr-d@PCIFN; event error.io.pci.dpdata-pw-u@PCIFN; event error.io.pci.dpdata-dw-u@PCIFN; event error.io.pci.dpdata-dr-u@PCIFN; event error.io.pci.ta-u@PCIFN; event error.io.pci.ma-u@PCIFN; event error.io.pci.perr-dw-u@PCIFN; event error.io.pci.perr-pw-u@PCIFN; event error.io.pci.perr-dr-u@PCIFN; event error.io.pci.badreq-drw-u@PCIFN; event error.io.pci.badreq-pw-u@PCIFN; event error.io.pci.device-serr@PCIFN; event error.io.pci.device-ta@PCIFN; event error.io.pci.device-par@PCIFN; event error.io.pci.serr-u@PCIFN; event error.io.pcix.scpe-d@PCIFN; event error.io.pcix.scpe-u@PCIFN; event error.io.pcix.spl-comp-ma-u@PCIFN; event error.io.pcix.spl-comp-ta-u@PCIFN; event error.io.pcix.spl-comp-ma-d@PCIFN; event error.io.pcix.spl-comp-ta-d@PCIFN; event ereport.io.pci.ma@PCIFN{within(5s)}; event ereport.io.pci.rta@PCIFN{within(5s)}; event ereport.io.pci.mdpe@PCIFN{within(5s)}; event ereport.io.pci.sta@PCIFN{within(5s)}; event ereport.io.pci.sserr@PCIFN{within(5s)}; event ereport.io.pci.dpe@PCIFN{within(5s)}; event ereport.io.pci.target-mdpe@PCIFN{within(5s)}; event ereport.io.pci.target-rta@PCIFN{within(5s)}; event ereport.io.pci.target-ma@PCIFN{within(5s)}; event ereport.io.pcix.discard@PCIFN{within(5s)}; prop fault.io.pci.device-noresp@pcibus/pcidev[fromdev]/pcifn (0)-> error.io.pci.nr-pw-d@PCI_FROM_HB, error.io.pci.nr-drw-d@PCI_FROM_HB, error.io.pci.retry-to-d@PCI_FROM_HB; prop fault.io.pci.device-invreq@pcibus/pcidev[fromdev]/pcifn (0)-> error.io.pci.badreq-pw-d@PCI_FROM_HB, error.io.pci.badreq-drw-d@PCI_FROM_HB; prop fault.io.pci.device-interr-unaf@pcibus/pcidev[fromdev]/pcifn (0)-> error.io.pci.nf-dpe-d@PCI_FROM_HB; prop fault.io.pci.device-interr-deg@pcibus/pcidev[fromdev]/pcifn (0)-> error.io.pci.deg-dpe-d@PCI_FROM_HB; prop fault.io.pci.device-interr@PCIFN (0)-> error.io.pci.device-par@PCIFN, error.io.pci.device-ta@PCIFN, error.io.pci.device-serr@PCIFN; prop error.io.pci.device-par@pcibus/pcidev[fromdev]/pcifn (1)-> error.io.pci.f-dpe-d@PCI_FROM_HB, error.io.pcix.scpe-d@PCI_FROM_HB, error.io.pci.ape-d@PCI_FROM_HB; prop error.io.pci.device-ta@pcibus/pcidev[fromdev]/pcifn (1)-> error.io.pci.ta-pw-d@PCI_FROM_HB, error.io.pci.ta-drw-d@PCI_FROM_HB; prop error.io.pci.device-ta@pcibus/pcidev[fromdev]/pcifn (1)-> ereport.io.pci.sta@pcibus/pcidev/pcifn { todev == fromdev && fromdev == 32 }; prop error.io.pci.device-serr@PCIFN (2)-> error.io.pci.serr-u@PCIFN, ereport.io.pci.sserr@PCIFN; /* * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * ereport generation rules for hostbridge * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ prop error.io.pci.dpdata-pw-u@pcibus/pcidev[fromdev]/pcifn (1)-> ereport.io.pci.dpe@PCI_TO_HB; prop error.io.pci.dpdata-dw-u@pcibus/pcidev[fromdev]/pcifn (1)-> ereport.io.pci.dpe@PCI_TO_HB; prop error.io.pci.dpdata-dr-u@pcibus/pcidev[fromdev]/pcifn (2)-> ereport.io.pci.mdpe@PCI_TO_HB, ereport.io.pci.dpe@PCI_TO_HB; prop error.io.pci.ape-u@pcibus/pcidev[fromdev]/pcifn (3)-> ereport.io.pci.dpe@PCI_TO_HB, error.io.pci.serr-u@PCI_TO_HB, ereport.io.pci.sserr@PCI_TO_HB; prop error.io.pci.ape-u@pcibus/pcidev[fromdev]/pcifn (0)-> ereport.io.pci.sta@PCI_TO_HB; prop error.io.pci.ma-u@pcibus/pcidev[fromdev]/pcifn (1)-> ereport.io.pci.ma@PCI_TO_HB; prop error.io.pci.ta-u@pcibus/pcidev[fromdev]/pcifn (1)-> ereport.io.pci.rta@PCI_TO_HB; prop error.io.pci.perr-dw-u@pcibus/pcidev[fromdev]/pcifn (1)-> ereport.io.pci.mdpe@PCI_TO_HB; prop error.io.pci.perr-pw-u@pcibus/pcidev[fromdev]/pcifn (1)-> ereport.io.pci.mdpe@PCI_TO_HB; prop error.io.pci.badreq-drw-u@pcibus/pcidev[fromdev]/pcifn (0)-> ereport.io.pci.sta@PCI_TO_HB; prop error.io.pci.badreq-pw-u@pcibus/pcidev[fromdev]/pcifn (0)-> ereport.io.pci.sta@PCI_TO_HB; prop error.io.pcix.scpe-u@PCIFN (1)-> error.io.pcix.spl-comp-ma-d@PCIFN, error.io.pcix.spl-comp-ta-d@PCIFN; prop error.io.pcix.scpe-u@pcibus/pcidev[fromdev]/pcifn (0)-> ereport.io.pci.dpe@PCI_TO_HB, error.io.pci.serr-u@PCI_TO_HB, ereport.io.pci.sserr@PCI_TO_HB, ereport.io.pci.sta@PCI_TO_HB; prop error.io.pcix.spl-comp-ma-u@pcibus/pcidev[fromdev]/pcifn (3)-> ereport.io.pcix.discard@PCI_TO_HB, error.io.pci.serr-u@PCI_TO_HB, ereport.io.pci.sserr@PCI_TO_HB; prop error.io.pcix.spl-comp-ta-u@pcibus/pcidev[fromdev]/pcifn (3)-> ereport.io.pcix.discard@PCI_TO_HB, error.io.pci.serr-u@PCI_TO_HB, ereport.io.pci.sserr@PCI_TO_HB; /* * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * A faulty PCI leaf device or pci-pci bridge may cause: * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * - nr-pw-u: the device not to respond to a valid downstream request * - nr-drw-u: the device not to respond to a valid downstream request * - ta-pw-u: the device responds with a ta to a valid downstream * request * - ta-drw-u: the device responds with a ta to a valid downstream * request * - serr-u: the device to report itself in error * - badreq-pw-u: a bad upstream request (may cause target to target * abort or master abort) * - badreq-drw-u: a bad upstream request (may cause target to target * abort or master abort) * - ape-u: the transfer of bad address/parity upstream. * - scpe-u: the transfer of bad split completion upstream. * - dpe-u: the device to deliver bad data/parity upstream. * - retry-to-u: the device to exceed the set timeout for a delayed * transaction retry. * * A faulty PCI-X leaf device or bridge may also cause: * * - tx-oor: the device sends a byte count larger than the completers * address range. * - rx-unex-sc: the device recieved a split completion with a tag * which does not match any outstanding transaction. */ #define PCI_NOT_HB pcibus/pcidev[fromdev]/pcifn {fromdev != 32} event error.io.pci.retry-to-u@PCIFN; event error.io.pci.nr-pw-u@PCIFN; event error.io.pci.nr-drw-u@PCIFN; event error.io.pci.ta-pw-u@PCIFN; event error.io.pci.ta-drw-u@PCIFN; event error.io.pci.f-dpe-u@PCIFN; event error.io.pci.deg-dpe-u@PCIFN; event error.io.pci.nf-dpe-u@PCIFN; event error.io.pci.flt-dpdata-pw-u@PCIFN; event error.io.pci.flt-dpdata-dw-u@PCIFN; event error.io.pci.flt-dpdata-dr-u@PCIFN; event error.io.pci.source-dpdata-u@PCIFN; event error.io.pci.f-source-dpdata-u@PCIFN; event error.io.pci.f-source-dpdata-u@PCIFN/PCIFN; event error.io.pci.deg-source-dpdata-u@PCIFN; event error.io.pci.deg-source-dpdata-u@PCIFN/PCIFN; event error.io.pci.nf-source-dpdata-u@PCIFN; event error.io.pci.nf-source-dpdata-u@PCIFN/PCIFN; event error.io.pci.perr-d@PCIFN; event error.io.pci.target-mdpe-d@PCIFN; event error.io.pci.target-mdpe-d@PCIFN/PCIFN; event error.io.pci.target-rta-d@PCIFN/PCIFN; event error.io.pci.target-ma-d@PCIFN/PCIFN; event error.io.pcix.tx-oor@PCIFN; event error.io.pcix.rx-unex-sc@PCIFN; event error.io.device.nf-device@PCIFN; event error.io.device.f-device@PCIFN; event error.io.device.deg-device@PCIFN; event error.io.service.restored@PCIFN; event ereport.io.pcix.oor@PCIFN{within(5s)}; event ereport.io.pcix.unex-sc@PCIFN{within(5s)}; event ereport.io.device.fw_corrupt@PCIFN{within(5s)}; event ereport.io.device.fw_mismatch@PCIFN{within(5s)}; event ereport.io.service.lost@PCIFN{within(5s)}; event ereport.io.service.degraded@PCIFN{within(5s)}; event ereport.io.service.unaffected@PCIFN{within(5s)}; event ereport.io.service.restored@PCIFN{within(30s)}; prop fault.io.pci.device-noresp@pcibus/pcidev[fromdev]/pcifn (0)-> error.io.pci.nr-pw-u@PCI_NOT_HB, error.io.pci.nr-drw-u@PCI_NOT_HB, error.io.pci.retry-to-u@PCI_NOT_HB; prop fault.io.pci.device-interr-corr@pcibus/pcidev[fromdev]/pcifn (0)-> error.io.device.nf-device@PCI_NOT_HB; prop fault.io.pci.device-interr-unaf@pcibus/pcidev[fromdev]/pcifn (0)-> error.io.pci.nf-dpe-u@PCI_NOT_HB; prop fault.io.pci.device-interr-deg@pcibus/pcidev[fromdev]/pcifn (0)-> error.io.device.deg-device@PCI_NOT_HB, error.io.pci.deg-dpe-u@PCI_NOT_HB; prop fault.io.pci.device-interr@pcibus/pcidev[fromdev]/pcifn (0)-> error.io.pci.ta-pw-u@PCI_NOT_HB, error.io.pci.ta-drw-u@PCI_NOT_HB, error.io.pci.serr-u@PCI_NOT_HB, error.io.pci.ape-u@PCI_NOT_HB, error.io.pci.f-dpe-u@PCI_NOT_HB, error.io.device.f-device@PCI_NOT_HB, error.io.pcix.scpe-u@PCI_NOT_HB, error.io.pcix.tx-oor@PCI_NOT_HB, error.io.pcix.rx-unex-sc@PCI_NOT_HB; prop fault.io.pci.fw_corrupt@PCIFN {IS_LEAF} (1)-> ereport.io.device.fw_corrupt@PCIFN; prop fault.io.pci.fw_corrupt@PCIFN {IS_LEAF} (0)-> ereport.io.service.lost@PCIFN, ereport.io.service.degraded@PCIFN; prop fault.io.pci.fw_mismatch@PCIFN {IS_LEAF} (1)-> ereport.io.device.fw_mismatch@PCIFN; prop fault.io.pci.fw_mismatch@PCIFN {IS_LEAF} (0)-> ereport.io.service.lost@PCIFN, ereport.io.service.degraded@PCIFN; prop fault.io.pci.device-invreq@pcibus/pcidev[fromdev]/pcifn {FD_IS_LEAF} (0)-> error.io.pci.badreq-drw-u@PCI_NOT_HB, error.io.pci.badreq-pw-u@PCI_NOT_HB; prop error.io.pcix.tx-oor@PCIFN (1)-> ereport.io.pcix.oor@PCIFN; prop error.io.pcix.rx-unex-sc@pcibus/pcidev[fromdev]/pcifn (1)-> ereport.io.pcix.unex-sc@pcibus/pcidev/pcifn<> {fromdev != todev}; prop error.io.pci.f-dpe-u@PCIFN (1)-> error.io.pci.flt-dpdata-pw-u@PCIFN, error.io.pci.flt-dpdata-dw-u@PCIFN, error.io.pci.flt-dpdata-dr-u@PCIFN; prop error.io.pci.f-dpe-u@PCIFN (1)-> error.io.pci.f-source-dpdata-u@PCIFN; prop error.io.pci.f-source-dpdata-u@PCIFN (1)-> error.io.pci.f-source-dpdata-u@PCIFN/PCIFNHZ; prop error.io.pci.f-source-dpdata-u@PCIFN { IS_LF(PCIFN) } (1)-> error.io.pci.source-dpdata-u@PCIFN; prop error.io.pci.f-source-dpdata-u@PCIFN { IS_LF(PCIFN) } (0)-> ereport.io.service.lost@PCIFN; prop error.io.pci.deg-dpe-u@PCIFN (1)-> error.io.pci.flt-dpdata-pw-u@PCIFN, error.io.pci.flt-dpdata-dw-u@PCIFN, error.io.pci.flt-dpdata-dr-u@PCIFN; prop error.io.pci.deg-dpe-u@PCIFN (1)-> error.io.pci.deg-source-dpdata-u@PCIFN; prop error.io.pci.deg-source-dpdata-u@PCIFN (1)-> error.io.pci.deg-source-dpdata-u@PCIFN/PCIFNHZ; prop error.io.pci.deg-source-dpdata-u@PCIFN { IS_LF(PCIFN) } (1)-> error.io.pci.source-dpdata-u@PCIFN; prop error.io.pci.deg-source-dpdata-u@PCIFN { IS_LF(PCIFN) } (1)-> ereport.io.service.degraded@PCIFN; prop error.io.pci.nf-dpe-u@PCIFN (1)-> error.io.pci.flt-dpdata-pw-u@PCIFN, error.io.pci.flt-dpdata-dw-u@PCIFN, error.io.pci.flt-dpdata-dr-u@PCIFN; prop error.io.pci.nf-dpe-u@PCIFN (1)-> error.io.pci.nf-source-dpdata-u@PCIFN; prop error.io.pci.nf-source-dpdata-u@PCIFN (1)-> error.io.pci.nf-source-dpdata-u@PCIFN/PCIFNHZ; prop error.io.pci.nf-source-dpdata-u@PCIFN { IS_LF(PCIFN) } (1)-> error.io.pci.source-dpdata-u@PCIFN; prop error.io.pci.nf-source-dpdata-u@PCIFN { IS_LF(PCIFN) } (1)-> ereport.io.service.unaffected@PCIFN, error.io.service.restored@PCIFN; prop error.io.pci.flt-dpdata-pw-u@PCIFN (1)-> error.io.pci.dpdata-pw-u@PCIFN; prop error.io.pci.flt-dpdata-pw-u@PCIFN { IS_BDG } (1)-> error.io.pci.serr-u@PCIFN; prop error.io.pci.flt-dpdata-dw-u@PCIFN (2)-> error.io.pci.perr-d@PCIFN, error.io.pci.dpdata-dw-u@PCIFN; prop error.io.pci.flt-dpdata-dr-u@PCIFN (2)-> error.io.pci.dpdata-dr-u@PCIFN, error.io.pci.target-mdpe-d@PCIFN; /* * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * A faulty pci-pci bridge may also cause * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * - nr-pw-d: the device not to respond to a valid upstream request * - nr-drw-d: the device not to respond to a valid upstream request * - ta-pw-d: the device responds with a ta to a valid upstream * request * - ta-drw-d: the device responds with a ta to a valid upstream * request * - ape-d: address/parity to get corrupted during downstream transmission. * - scpe-d: split completion gets corrupted during downstream transmission. * - dpe-d: data/parity to get corrupted during downstream transmission. * - retry-to-d: the device to exceed the set timeout for a delayed * transaction retry. */ event error.io.pci.ape-d@PCIFN/PCIFN; event error.io.pci.f-dpe-d@PCIFN/PCIFN; event error.io.pci.deg-dpe-d@PCIFN/PCIFN; event error.io.pci.nf-dpe-d@PCIFN/PCIFN; event error.io.pci.retry-to-d@PCIFN/PCIFN; event error.io.pci.nr-pw-d@PCIFN/PCIFN; event error.io.pci.nr-drw-d@PCIFN/PCIFN; event error.io.pci.ta-pw-d@PCIFN/PCIFN; event error.io.pci.ta-drw-d@PCIFN/PCIFN; event error.io.pcix.scpe-d@PCIFN/PCIFN; prop fault.io.pci.device-noresp@PCIFN (0)-> error.io.pci.nr-pw-d@PCIFN/PCIFN, error.io.pci.nr-drw-d@PCIFN/PCIFN, error.io.pci.retry-to-d@PCIFN/PCIFN; prop fault.io.pci.device-interr-unaf@PCIFN (0)-> error.io.pci.nf-dpe-d@PCIFN/PCIFN; prop fault.io.pci.device-interr-deg@PCIFN (0)-> error.io.pci.deg-dpe-d@PCIFN/PCIFN; prop fault.io.pci.device-interr@PCIFN (0)-> error.io.pci.ta-pw-d@PCIFN/PCIFN, error.io.pci.ta-drw-d@PCIFN/PCIFN, error.io.pci.ape-d@PCIFN/PCIFN, error.io.pcix.scpe-d@PCIFN/PCIFN, error.io.pci.f-dpe-d@PCIFN/PCIFN; /* * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * A faulty PCI bus may cause: * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * - ape-d: address/parity to get corrupted during downstream transmission. * - scpe-d: split completion gets corrupted during downstream transmission. * - dpe-d: data/parity to get corrupted during downstream transmission. * - ape-u: address/parity to get corrupted during upstream transmission. * - dpe-u: data/parity to get corrupted during read upstream transmission. * - scpe-u: split completion to get corrupted during upstream transmission. */ event fault.io.pci.bus-linkerr-unaf@pcibus, engine=serd.io.pci.nf-dpe-bus@pcibus, FITrate=PCI_BUS_FIT; event fault.io.pci.bus-linkerr-deg@pcibus, FITrate=PCI_BUS_FIT, retire=0; event fault.io.pci.bus-linkerr@pcibus, FITrate=PCI_BUS_FIT; prop fault.io.pci.bus-linkerr-unaf@pcibus (0)-> error.io.pci.nf-dpe-d@pcibus/pcidev/pcifn { todev != 32}, error.io.pci.nf-dpe-u@pcibus/pcidev/pcifn { todev != 32}; prop fault.io.pci.bus-linkerr-deg@pcibus (0)-> error.io.pci.deg-dpe-d@pcibus/pcidev/pcifn { todev != 32}, error.io.pci.deg-dpe-u@pcibus/pcidev/pcifn { todev != 32}; prop fault.io.pci.bus-linkerr@pcibus (0)-> error.io.pci.ape-d@pcibus/pcidev/pcifn { todev != 32}, error.io.pci.f-dpe-d@pcibus/pcidev/pcifn { todev != 32}, error.io.pci.ape-u@pcibus/pcidev/pcifn { todev != 32}, error.io.pci.f-dpe-u@pcibus/pcidev/pcifn { todev != 32}, error.io.pcix.scpe-d@pcibus/pcidev/pcifn { todev != 32}, error.io.pcix.scpe-u@pcibus/pcidev/pcifn { todev != 32}, error.io.pcix.tx-oor@pcibus/pcidev/pcifn { todev != 32}, error.io.pcix.rx-unex-sc@pcibus/pcidev/pcifn { todev != 32}; /* * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * recursive rules for pci-pci bridges * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ event error.io.pci.serr-u@PCIFN/PCIFN; event error.io.pci.perr-dw-u@PCIFN/PCIFN; event error.io.pci.perr-pw-u@PCIFN/PCIFN; event error.io.pci.perr-d@PCIFN/PCIFN; event error.io.pci.dpdata-pw-u@PCIFN/PCIFN; event error.io.pci.dpdata-dw-u@PCIFN/PCIFN; event error.io.pci.dpdata-dr-u@PCIFN/PCIFN; event error.io.pci.dpdata-pw-fwd-d@PCIFN; event error.io.pci.dpdata-pw-fwd-d@PCIFN/PCIFN; event error.io.pci.dpdata-dw-fwd-d@PCIFN; event error.io.pci.dpdata-dw-fwd-d@PCIFN/PCIFN; event error.io.pci.dpdata-dr-fwd-d@PCIFN; event error.io.pci.dpdata-dr-fwd-d@PCIFN/PCIFN; event error.io.pci.source-perr-u@PCIFN; event error.io.pci.leaf-ape-d@PCIFN; event error.io.pci.ape-u@PCIFN/PCIFN; event error.io.pci.source-ape-u@PCIFN; event error.io.pci.badreq-pw-d@PCIFN/PCIFN; event error.io.pci.badreq-drw-d@PCIFN/PCIFN; event error.io.pci.badreq-pw-u@PCIFN/PCIFN; event error.io.pci.badreq-drw-u@PCIFN/PCIFN; event error.io.pci.ta-d@PCIFN; event error.io.pci.ta-d@PCIFN/PCIFN; event error.io.pci.ta-u@PCIFN/PCIFN; event error.io.pci.target-rta-d@PCIFN; event error.io.pci.target-ma-d@PCIFN; event error.io.pci.nr-pw-u@PCIFN/PCIFN; event error.io.pci.ta-pw-u@PCIFN/PCIFN; event error.io.pci.retry-to-u@PCIFN/PCIFN; event error.io.pcix.scpe-u@PCIFN/PCIFN; event error.io.pcix.source-scpe-u@PCIFN; event error.io.pcix.spl-comp-ma-u@PCIFN/PCIFN; event error.io.pcix.spl-comp-ta-u@PCIFN/PCIFN; event error.io.pci.ma-u@PCIFN/PCIFN; event ereport.io.pci.sec-ma@PCIFN{within(5s)}; event ereport.io.pci.sec-sta@PCIFN{within(5s)}; event ereport.io.pci.sec-rta@PCIFN{within(5s)}; event ereport.io.pci.sec-mdpe@PCIFN{within(5s)}; event ereport.io.pci.sec-dpe@PCIFN{within(5s)}; event ereport.io.pci.sec-rserr@PCIFN{within(5s)}; event ereport.io.pci.dto@PCIFN{within(5s)}; event ereport.io.pcix.sec-spl-dis@PCIFN{within(5s)}; event ereport.io.pcix.spl-dis@PCIFN{within(5s)}; /* * SERR# can propagate upstream and may be seen by other devices on the bus */ prop error.io.pci.serr-u@pcibus/pcidev[fromdev]/pcifn (0)-> ereport.io.pci.sserr@pcibus/pcidev/pcifn<> {todev!=fromdev}; prop error.io.pci.serr-u@PCIFN { IS_BDG } (1)-> ereport.io.pci.sserr@PCIFN; prop error.io.pci.serr-u@PCIFN/PCIFN (2)-> ereport.io.pci.sec-rserr@PCIFN, error.io.pci.serr-u@PCIFN; /* * PERR# can propagate upstream for delayed writes. For posted writes * it turns into an SERR#. */ prop error.io.pci.perr-dw-u@PCIFN/PCIFN (2)-> ereport.io.pci.sec-mdpe@PCIFN, error.io.pci.perr-dw-u@PCIFN; prop error.io.pci.perr-pw-u@PCIFN/PCIFN (2)-> ereport.io.pci.sec-mdpe@PCIFN, error.io.pci.serr-u@PCIFN; /* * PERR# can propagate downstream (only for downstream dw parity error) */ prop error.io.pci.perr-d@PCIFN { IS_LEAF } (0)-> ereport.io.pci.mdpe@PCIFN; prop error.io.pci.perr-d@PCIFN { IS_BDG } (1)-> ereport.io.pci.mdpe@PCIFN; prop error.io.pci.perr-d@PCIFN (1)-> error.io.pci.perr-d@PCIFN/PCIFNHZ; /* * downstream target ereports are for any descendant device * * A hostbridge driver may generate "target-" ereports when knowledge of the * physical address associated with a fault allows the target device to be * determined. This is not a requirement of the Diagnosis Engine, but can be * valuable when available. */ prop error.io.pci.target-mdpe-d@PCIFN (0)-> ereport.io.pci.target-mdpe@PCIFN; prop error.io.pci.target-mdpe-d@PCIFN (1)-> error.io.pci.target-mdpe-d@PCIFN/PCIFNHZ; prop error.io.pci.target-rta-d@PCIFN (0)-> ereport.io.pci.target-rta@PCIFN; prop error.io.pci.target-rta-d@PCIFN (1)-> error.io.pci.target-rta-d@PCIFN/PCIFNHZ; prop error.io.pci.target-ma-d@PCIFN (0)-> ereport.io.pci.target-ma@PCIFN; prop error.io.pci.target-ma-d@PCIFN (1)-> error.io.pci.target-ma-d@PCIFN/PCIFNHZ; /* * target aborts propagate upstream */ prop error.io.pci.ta-u@PCIFN { IS_BDG } (1)-> ereport.io.pci.sta@PCIFN; prop error.io.pci.ta-u@PCIFN { IS_LEAF } (0)-> ereport.io.pci.sta@PCIFN; prop error.io.pci.ta-u@PCIFN/PCIFN (2)-> ereport.io.pci.sec-rta@PCIFN, error.io.pci.ta-u@PCIFN; /* * bad data (ie invalid but not an ape or dpe) can propagate downstream, * and at some point may result in a target or master abort */ prop error.io.pci.badreq-pw-d@PCIFN (1)-> error.io.pci.badreq-pw-d@PCIFN/PCIFNHZ, error.io.pci.nr-pw-u@PCIFN, error.io.pci.ta-pw-u@PCIFN; prop error.io.pci.badreq-pw-d@PCIFN { IS_LEAF } (0)-> error.io.pci.nr-pw-u@PCIFN, error.io.pci.ta-pw-u@PCIFN; prop error.io.pci.badreq-drw-d@PCIFN (1)-> error.io.pci.badreq-drw-d@PCIFN/PCIFNHZ, error.io.pci.nr-drw-u@PCIFN, error.io.pci.ta-drw-u@PCIFN; prop error.io.pci.badreq-drw-d@PCIFN { IS_LEAF } (0)-> error.io.pci.nr-drw-u@PCIFN, error.io.pci.ta-drw-u@PCIFN; prop error.io.pci.nr-pw-u@PCIFN/PCIFN (2)-> ereport.io.pci.sec-ma@PCIFN, error.io.pci.serr-u@PCIFN; prop error.io.pci.ta-pw-u@PCIFN { IS_LEAF } (0)-> ereport.io.pci.sta@PCIFN; prop error.io.pci.ta-pw-u@PCIFN { IS_BDG } (1)-> ereport.io.pci.sta@PCIFN; prop error.io.pci.ta-pw-u@PCIFN/PCIFN (2)-> ereport.io.pci.sec-rta@PCIFN, error.io.pci.serr-u@PCIFN; prop error.io.pci.nr-drw-u@PCIFN (1)-> error.io.pci.ma-u@PCIFN; prop error.io.pci.nr-drw-u@PCIFN (1)-> error.io.pci.target-rta-d@PCIFN, error.io.pci.target-ma-d@PCIFN; prop error.io.pci.ma-u@PCIFN/PCIFN (1)-> ereport.io.pci.sec-ma@PCIFN; prop error.io.pci.ma-u@PCIFN/PCIFN (1)-> error.io.pci.ma-u@PCIFN, error.io.pci.ta-u@PCIFN; prop error.io.pci.ta-drw-u@PCIFN (1)-> error.io.pci.ta-u@PCIFN; prop error.io.pci.ta-drw-u@PCIFN (1)-> error.io.pci.target-rta-d@PCIFN; /* * bad data (ie invalid but not an ape or dpe) can propagate upstream, * and at some point may result in a target or master abort */ prop error.io.pci.badreq-pw-u@PCIFN/PCIFN (1)-> error.io.pci.badreq-pw-u@PCIFN, error.io.pci.nr-pw-d@PCIFN/PCIFN, error.io.pci.ta-pw-d@PCIFN/PCIFN; prop error.io.pci.badreq-pw-u@PCIFN (0)-> error.io.pci.nr-pw-d@PCIFN, error.io.pci.ta-pw-d@PCIFN; prop error.io.pci.nr-pw-d@PCIFN { IS_LEAF } (0)-> ereport.io.pci.ma@PCIFN; prop error.io.pci.nr-pw-d@PCIFN { IS_BDG } (2)-> ereport.io.pci.ma@PCIFN, error.io.pci.serr-u@PCIFN; prop error.io.pci.ta-pw-d@PCIFN/PCIFN (1)-> ereport.io.pci.sec-sta@PCIFN; prop error.io.pci.ta-pw-d@PCIFN { IS_LEAF } (0)-> ereport.io.pci.rta@PCIFN; prop error.io.pci.ta-pw-d@PCIFN { IS_BDG } (2)-> ereport.io.pci.rta@PCIFN, error.io.pci.serr-u@PCIFN; /* * for delayed writes we treat upstream badreq specially as rta always * propagates back downstream to the leaf */ prop error.io.pci.badreq-drw-u@PCIFN { IS_LEAF } (0)-> ereport.io.pci.rta@PCIFN, ereport.io.pci.ma@PCIFN; prop error.io.pci.badreq-drw-u@PCIFN/PCIFN (1)-> ereport.io.pci.ma@PCIFN, ereport.io.pci.rta@PCIFN; prop error.io.pci.badreq-drw-u@PCIFN/PCIFN (0)-> ereport.io.pci.sec-sta@PCIFN; prop error.io.pci.badreq-drw-u@PCIFN/PCIFN (0)-> error.io.pci.badreq-drw-u@PCIFN; prop error.io.pci.nr-drw-d@PCIFN { IS_LEAF } (0)-> ereport.io.pci.ma@PCIFN; prop error.io.pci.nr-drw-d@PCIFN { IS_BDG } (1)-> ereport.io.pci.ma@PCIFN; prop error.io.pci.nr-drw-d@PCIFN { IS_BDG } (0)-> ereport.io.pci.sec-sta@PCIFN; prop error.io.pci.nr-drw-d@PCIFN (1)-> error.io.pci.ta-d@PCIFN/PCIFNHZ, error.io.pci.nr-drw-d@PCIFN/PCIFNHZ; prop error.io.pci.ta-drw-d@PCIFN/PCIFN (1)-> ereport.io.pci.sec-sta@PCIFN; prop error.io.pci.ta-drw-d@PCIFN (1)-> error.io.pci.ta-d@PCIFN; prop error.io.pci.ta-d@PCIFN { IS_LEAF } (0)-> ereport.io.pci.rta@PCIFN; prop error.io.pci.ta-d@PCIFN { IS_BDG } (2)-> ereport.io.pci.sec-sta@PCIFN, ereport.io.pci.rta@PCIFN; prop error.io.pci.ta-d@PCIFN (1)-> error.io.pci.ta-d@PCIFN/PCIFNHZ; /* * Request with address parity error must be detected by parent device * and can optionally result in a target or master abort. * It may also be detected by sibling devices on a bus */ prop error.io.pci.ape-u@PCIFN/PCIFN (3)-> ereport.io.pci.sec-dpe@PCIFN, ereport.io.pci.sec-rserr@PCIFN, error.io.pci.serr-u@PCIFN; prop error.io.pci.ape-u@PCIFN (0)-> error.io.pci.nr-drw-d@PCIFN, error.io.pci.ta-drw-d@PCIFN, error.io.pci.nr-pw-d@PCIFN, error.io.pci.ta-pw-d@PCIFN; prop error.io.pci.ape-u@PCIFN (0)-> ereport.io.pci.mdpe@PCIFN; prop error.io.pci.ape-u@pcibus/pcidev[fromdev]/pcifn (0)-> ereport.io.pci.dpe@pcibus/pcidev/pcifn<> {fromdev != todev}, ereport.io.pci.sserr@pcibus/pcidev/pcifn<> {fromdev != todev}; prop error.io.pci.ape-u@PCIFN (1)-> error.io.pci.source-ape-u@PCIFN; /* * If the bridge sees an upstream split completion error (pci-x only) it could * result in a number of things * - for various faults in the split completion (eg address parity error) * we will respond with a target abort (which the child device will treat * as a split completion ta) * - for other faults we can't tell who send the split completion and so * just drop the request (which the child device sees as a split * completion ma) */ prop error.io.pcix.scpe-u@PCIFN/PCIFN (0)-> ereport.io.pci.sec-sta@PCIFN, ereport.io.pci.sec-dpe@PCIFN, ereport.io.pci.sec-rserr@PCIFN, error.io.pci.serr-u@PCIFN; prop error.io.pcix.scpe-u@PCIFN (1)-> error.io.pcix.spl-comp-ma-d@PCIFN, error.io.pcix.spl-comp-ta-d@PCIFN; prop error.io.pcix.spl-comp-ma-d@PCIFN (1)-> error.io.pci.serr-u@PCIFN; prop error.io.pcix.spl-comp-ma-d@PCIFN { IS_LEAF } (0)-> ereport.io.pci.sserr@PCIFN, ereport.io.pcix.spl-dis@PCIFN; prop error.io.pcix.spl-comp-ma-d@PCIFN { IS_BDG } (2)-> ereport.io.pcix.spl-dis@PCIFN, ereport.io.pci.ma@PCIFN; prop error.io.pcix.spl-comp-ta-d@PCIFN (1)-> error.io.pci.serr-u@PCIFN; prop error.io.pcix.spl-comp-ta-d@PCIFN { IS_LEAF } (0)-> ereport.io.pci.sserr@PCIFN, ereport.io.pcix.spl-dis@PCIFN; prop error.io.pcix.spl-comp-ta-d@PCIFN { IS_BDG } (2)-> ereport.io.pcix.spl-dis@PCIFN, ereport.io.pci.rta@PCIFN; prop error.io.pcix.scpe-u@PCIFN (1)-> error.io.pcix.source-scpe-u@PCIFN; /* * request with address parity error must be detected by child device * and can optionally result in a target or master abort. */ prop error.io.pci.ape-d@PCIFN (1)-> error.io.pci.serr-u@PCIFN; prop error.io.pci.ape-d@PCIFN { IS_LEAF } (0)-> error.io.pci.leaf-ape-d@PCIFN; prop error.io.pci.leaf-ape-d@PCIFN { IS_LEAF } (2)-> ereport.io.pci.sserr@PCIFN, ereport.io.pci.dpe@PCIFN; prop error.io.pci.ape-d@PCIFN { IS_BDG } (1)-> ereport.io.pci.dpe@PCIFN; prop error.io.pci.ape-d@PCIFN (0)-> error.io.pci.ta-pw-u@PCIFN, error.io.pci.ta-drw-u@PCIFN, error.io.pci.nr-pw-u@PCIFN, error.io.pci.nr-drw-u@PCIFN; /* * If the device sees a downstream split completion error (pci-x only) it could * result in a number of things * - for various faults in the split completion (eg address parity error) * we will respond with a target abort (which the parent bridge will treat * as a split completion ta) * - for other faults we can't tell who send the split completion and so * just drop the request (which the parent bridge sees as a split * completion ma) */ prop error.io.pcix.scpe-d@PCIFN (0)-> ereport.io.pci.sta@PCIFN, ereport.io.pci.dpe@PCIFN, ereport.io.pci.sserr@PCIFN, error.io.pci.serr-u@PCIFN; prop error.io.pcix.scpe-d@PCIFN (1)-> error.io.pcix.spl-comp-ma-u@PCIFN, error.io.pcix.spl-comp-ta-u@PCIFN; prop error.io.pcix.spl-comp-ma-u@PCIFN/PCIFN (2)-> ereport.io.pcix.sec-spl-dis@PCIFN, error.io.pci.serr-u@PCIFN; prop error.io.pcix.spl-comp-ma-u@PCIFN/PCIFN (0)-> ereport.io.pci.sec-ma@PCIFN; prop error.io.pcix.spl-comp-ta-u@PCIFN/PCIFN (3)-> ereport.io.pcix.sec-spl-dis@PCIFN, error.io.pci.serr-u@PCIFN, ereport.io.pci.sec-rta@PCIFN; /* * request with data parity error can propagate upstream * * for PCI/X (but not PCI) the split write can optionally be forwarded across * the bridge, maintaining bad parity/ecc * * if there is a dpe on a retry on a delayed write, we don't send another * retry, and eventually the dto timer will expire */ prop error.io.pci.dpdata-pw-u@PCIFN { IS_LEAF } (0)-> ereport.io.pci.mdpe@PCIFN; prop error.io.pci.dpdata-pw-u@PCIFN/PCIFN (3)-> ereport.io.pci.mdpe@PCIFN, ereport.io.pci.sec-dpe@PCIFN, error.io.pci.dpdata-pw-u@PCIFN; prop error.io.pci.dpdata-dw-u@PCIFN/PCIFN (1)-> ereport.io.pci.sec-dpe@PCIFN; prop error.io.pci.dpdata-dw-u@PCIFN/PCIFN (0)-> ereport.io.pci.mdpe@PCIFN, error.io.pci.dpdata-dw-u@PCIFN; prop error.io.pci.dpdata-dw-u@PCIFN/PCIFN (0)-> error.io.pci.retry-to-u@PCIFN/PCIFN; prop error.io.pci.dpdata-dr-u@PCIFN/PCIFN (3)-> ereport.io.pci.sec-dpe@PCIFN, ereport.io.pci.sec-mdpe@PCIFN, error.io.pci.dpdata-dr-u@PCIFN; /* * Request with data parity error can propagate downstream. A hardened * leaf driver should handle the error, but may or may not be able to * avoid service impact. We handle to two cases separately. If there is * service impact we will fail immediately, if not we will feed into a SERD * engine. * * for PCI/X (but not PCI) the split write can optionally be forwarded across * the bridge, maintaining bad parity/ecc * * if there is a dpe on a retry on a delayed write, we don't send another * retry, and eventually the dto timer will expire */ prop error.io.pci.f-dpe-d@PCIFN (1)-> error.io.pci.dpdata-pw-d@PCIFN, error.io.pci.dpdata-dw-d@PCIFN, error.io.pci.dpdata-dr-d@PCIFN; prop error.io.pci.f-dpe-d@PCIFN (1)-> error.io.pci.f-source-dpdata-u@PCIFN; prop error.io.pci.deg-dpe-d@PCIFN (1)-> error.io.pci.dpdata-pw-d@PCIFN, error.io.pci.dpdata-dw-d@PCIFN, error.io.pci.dpdata-dr-d@PCIFN; prop error.io.pci.deg-dpe-d@PCIFN (1)-> error.io.pci.deg-source-dpdata-u@PCIFN; prop error.io.pci.nf-dpe-d@PCIFN (1)-> error.io.pci.dpdata-pw-d@PCIFN, error.io.pci.dpdata-dw-d@PCIFN, error.io.pci.dpdata-dr-d@PCIFN; prop error.io.pci.nf-dpe-d@PCIFN (1)-> error.io.pci.nf-source-dpdata-u@PCIFN; prop error.io.pci.dpdata-pw-d@PCIFN (2)-> error.io.pci.perr-pw-u@PCIFN, error.io.pci.dpdata-pw-fwd-d@PCIFN; prop error.io.pci.dpdata-pw-fwd-d@PCIFN { IS_LEAF } (1)-> error.io.pci.source-perr-u@PCIFN; prop error.io.pci.dpdata-pw-fwd-d@PCIFN { IS_LEAF } (0)-> ereport.io.pci.dpe@PCIFN; prop error.io.pci.dpdata-pw-fwd-d@PCIFN { IS_BDG } (2)-> ereport.io.pci.dpe@PCIFN, ereport.io.pci.sec-mdpe@PCIFN; prop error.io.pci.dpdata-pw-fwd-d@PCIFN (1)-> error.io.pci.dpdata-pw-fwd-d@PCIFN/PCIFNHZ; prop error.io.pci.dpdata-dw-d@PCIFN (3)-> error.io.pci.perr-dw-u@PCIFN, error.io.pci.target-mdpe-d@PCIFN, error.io.pci.dpdata-dw-fwd-d@PCIFN; prop error.io.pci.dpdata-dw-d@PCIFN { IS_BDG } (1)-> ereport.io.pci.dpe@PCIFN; prop error.io.pci.dpdata-dw-d@PCIFN { IS_BDG } (0)-> error.io.pci.retry-to-d@PCIFN; prop error.io.pci.dpdata-dw-fwd-d@PCIFN { IS_LEAF } (1)-> error.io.pci.source-perr-u@PCIFN; prop error.io.pci.dpdata-dw-fwd-d@PCIFN { IS_LEAF } (0)-> ereport.io.pci.dpe@PCIFN; prop error.io.pci.dpdata-dw-fwd-d@PCIFN { IS_BDG } (0)-> ereport.io.pci.dpe@PCIFN, ereport.io.pci.sec-mdpe@PCIFN; prop error.io.pci.dpdata-dw-fwd-d@PCIFN (0)-> error.io.pci.dpdata-dw-fwd-d@PCIFN/PCIFNHZ; prop error.io.pci.dpdata-dr-d@PCIFN (2)-> error.io.pci.dpdata-dr-fwd-d@PCIFN, error.io.pci.perr-dr-u@PCIFN; prop error.io.pci.dpdata-dr-fwd-d@PCIFN { IS_LEAF } (1)-> error.io.pci.source-perr-u@PCIFN; prop error.io.pci.dpdata-dr-fwd-d@PCIFN { IS_LEAF } (0)-> ereport.io.pci.dpe@PCIFN, ereport.io.pci.mdpe@PCIFN; prop error.io.pci.dpdata-dr-fwd-d@PCIFN { IS_BDG } (2)-> ereport.io.pci.dpe@PCIFN, ereport.io.pci.mdpe@PCIFN; prop error.io.pci.dpdata-dr-fwd-d@PCIFN (1)-> error.io.pci.dpdata-dr-fwd-d@PCIFN/PCIFNHZ; /* * delayed read/write retry timeout can cause dto at a bridge */ prop error.io.pci.retry-to-u@PCIFN/PCIFN (0)-> error.io.pci.retry-to-u@PCIFN; prop error.io.pci.retry-to-u@PCIFN/PCIFN (1)-> ereport.io.pci.dto@PCIFN; prop error.io.pci.retry-to-u@PCIFN/PCIFN (0)-> error.io.pci.serr-u@PCIFN; prop error.io.pci.retry-to-d@PCIFN (0)-> error.io.pci.retry-to-d@PCIFN/PCIFN; prop error.io.pci.retry-to-d@PCIFN { IS_BDG } (1)-> ereport.io.pci.dto@PCIFN; prop error.io.pci.retry-to-d@PCIFN { IS_BDG } (0)-> error.io.pci.serr-u@PCIFN; /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * source- propagations. * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ event error.io.pci.source-ape-u@PCIFN/PCIFN; event error.io.pcix.source-scpe-u@PCIFN/PCIFN; prop error.io.pci.source-ape-u@PCIFN (1)-> error.io.pci.source-ape-u@PCIFN/PCIFNHZ; prop error.io.pcix.source-scpe-u@PCIFN (1)-> error.io.pcix.source-scpe-u@PCIFN/PCIFNHZ; /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * Handling of leaf driver detected internal errors. Use serd engine if * no service impact - otherwise fail immediately * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ event ereport.io.device.inval_state@PCIFN{within(5s)}; event ereport.io.device.no_response@PCIFN{within(5s)}; event ereport.io.device.stall@PCIFN{within(5s)}; event ereport.io.device.badint_limit@PCIFN{within(5s)}; event ereport.io.device.intern_corr@PCIFN{within(5s)}; event ereport.io.device.intern_uncorr@PCIFN{within(5s)}; prop error.io.service.restored@PCIFN { IS_LEAF } (1)-> ereport.io.service.lost@PCIFN, ereport.io.service.degraded@PCIFN; prop error.io.service.restored@PCIFN { IS_LEAF } (1)-> ereport.io.service.restored@PCIFN; prop error.io.device.f-device@PCIFN { IS_LEAF } (1)-> ereport.io.device.inval_state@PCIFN, ereport.io.device.no_response@PCIFN, ereport.io.device.stall@PCIFN, ereport.io.device.badint_limit@PCIFN, ereport.io.device.intern_corr@PCIFN, ereport.io.device.intern_uncorr@PCIFN; prop error.io.device.f-device@PCIFN { IS_LEAF } (1)-> ereport.io.service.lost@PCIFN; prop error.io.device.deg-device@PCIFN { IS_LEAF } (1)-> ereport.io.device.inval_state@PCIFN, ereport.io.device.no_response@PCIFN, ereport.io.device.stall@PCIFN, ereport.io.device.badint_limit@PCIFN, ereport.io.device.intern_corr@PCIFN, ereport.io.device.intern_uncorr@PCIFN; prop error.io.device.deg-device@PCIFN { IS_LEAF } (1)-> ereport.io.service.degraded@PCIFN; prop error.io.device.nf-device@PCIFN { IS_LEAF } (1)-> ereport.io.device.inval_state@PCIFN, ereport.io.device.no_response@PCIFN, ereport.io.device.stall@PCIFN, ereport.io.device.badint_limit@PCIFN, ereport.io.device.intern_corr@PCIFN, ereport.io.device.intern_uncorr@PCIFN; prop error.io.device.nf-device@PCIFN { IS_LEAF } (1)-> ereport.io.service.unaffected@PCIFN, error.io.service.restored@PCIFN; /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * stub unused ereports * - ignore rx-spl as we can't tell what message it was (and we should have * diagnosed the problem anyway from standard pci ereports) * - ignore sec-spl-or/sec-spl-dly as these aren't really faults (tuning info) * - ignore unex-spl/sec-unex-spl * - ignore ecc.ue ereports (we get everything we need from dpe/mdpe) * - ignore ecc.ce ereports for now (could do serd on these) * - ignore nr ereport * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ event ereport.io.pci.nr@PCIFN{within(5s)}; event ereport.io.pcix.unex-spl@PCIFN{within(5s)}; event ereport.io.pcix.rx-spl@PCIFN{within(5s)}; event ereport.io.pcix.sec-unex-spl@PCIFN{within(5s)}; event ereport.io.pcix.sec-spl-or@PCIFN{within(5s)}; event ereport.io.pcix.sec-spl-dly@PCIFN{within(5s)}; event ereport.io.pcix.ecc.ce-addr@PCIFN{within(5s)}; event ereport.io.pcix.ecc.ce-attr@PCIFN{within(5s)}; event ereport.io.pcix.ecc.ce-data@PCIFN{within(5s)}; event ereport.io.pcix.ecc.ue-addr@PCIFN{within(5s)}; event ereport.io.pcix.ecc.ue-attr@PCIFN{within(5s)}; event ereport.io.pcix.ecc.ue-data@PCIFN{within(5s)}; event ereport.io.pcix.s-ce@PCIFN{within(5s)}; event ereport.io.pcix.s-ue@PCIFN{within(5s)}; event ereport.io.pcix.sec-ecc.ce-addr@PCIFN{within(5s)}; event ereport.io.pcix.sec-ecc.ce-attr@PCIFN{within(5s)}; event ereport.io.pcix.sec-ecc.ce-data@PCIFN{within(5s)}; event ereport.io.pcix.sec-ecc.ue-addr@PCIFN{within(5s)}; event ereport.io.pcix.sec-ecc.ue-attr@PCIFN{within(5s)}; event ereport.io.pcix.sec-ecc.ue-data@PCIFN{within(5s)}; event ereport.io.pcix.sec-s-ce@PCIFN{within(5s)}; event ereport.io.pcix.sec-s-ue@PCIFN{within(5s)}; event upset.io.pcix.discard@PCIFN; prop upset.io.pcix.discard@PCIFN (1)-> ereport.io.pci.nr@PCIFN, ereport.io.pcix.rx-spl@PCIFN, ereport.io.pcix.unex-spl@PCIFN, ereport.io.pcix.sec-unex-spl@PCIFN, ereport.io.pcix.sec-spl-or@PCIFN, ereport.io.pcix.sec-spl-dly@PCIFN, ereport.io.pcix.ecc.ce-addr@PCIFN, ereport.io.pcix.ecc.ce-attr@PCIFN, ereport.io.pcix.ecc.ce-data@PCIFN, ereport.io.pcix.ecc.ue-addr@PCIFN, ereport.io.pcix.ecc.ue-attr@PCIFN, ereport.io.pcix.ecc.ue-data@PCIFN, ereport.io.pcix.s-ce@PCIFN, ereport.io.pcix.s-ue@PCIFN, ereport.io.pcix.sec-ecc.ce-addr@PCIFN, ereport.io.pcix.sec-ecc.ce-attr@PCIFN, ereport.io.pcix.sec-ecc.ce-data@PCIFN, ereport.io.pcix.sec-ecc.ue-addr@PCIFN, ereport.io.pcix.sec-ecc.ue-attr@PCIFN, ereport.io.pcix.sec-ecc.ue-data@PCIFN, ereport.io.pcix.sec-s-ce@PCIFN, ereport.io.pcix.sec-s-ue@PCIFN; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma dictionary "PCIEX" #include /* * FIT rates - assume leaf devices are somewhat less reliable than * root complexes, switches and bridges */ #define PCIEX_RC_FIT 500 #define PCIEX_SW_FIT 500 #define PCIEX_BDG_FIT 500 #define PCIEX_DEV_FIT 1000 #define PCIEX_RC_INV_FIT 500 #define PCIEX_DEV_INV_FIT 1000 #define PCIEX_RC_NR_FIT 500 #define PCIEX_SW_NR_FIT 500 #define PCIEX_BDG_NR_FIT 500 #define PCIEX_DEV_NR_FIT 1000 #define PCIEX_BUS_FIT 500 #define PCIEX_BUS_NR_FIT 500 /* * SERD parameters. * * PCI Express correctable link errors are automatically handled by the * hardware, so have relatively little impact and we can allow quite a * high frequency. We will also be quite conservative about nonfatal internal * errors reported by the driver. * * Nonfatal dpe errors (ptlp/ecrc errors) have to be recovered by the hardened * driver which may cause intermittant performance/responsiveness problems, so * we have tighter serd parameters for these. These are most likely errors in * buffers/caches within devices and bridges, so use similar rates to cpu * data cache parity errors. */ #define CORRLINK_COUNT 6 #define CORRLINK_TIME 2h #define BTLP_COUNT 6 #define BTLP_TIME 2h #define BDLLP_COUNT 6 #define BDLLP_TIME 2h #define RTO_COUNT 6 #define RTO_TIME 2h #define RNR_COUNT 6 #define RNR_TIME 2h #define RE_COUNT 6 #define RE_TIME 2h #define NONFATAL_DPE_COUNT 3 #define NONFATAL_DPE_TIME 168h /* * if the source-id payload is valid, then check it matches */ #define SOURCE_ID_MATCHES_BDF \ (!payloadprop_defined("source-valid") || \ payloadprop("source-valid") == 0 || \ payloadprop("source-id") == ((b << 8) | (d << 3) | f)) #define SOURCE_ID_MATCHES_OWN_BDF \ (payloadprop_defined("source-valid") && \ payloadprop("source-valid") == 1 && \ payloadprop("source-id") == (confprop(pciexrc, TOPO_PCI_BDF) + 0)) /* * Other useful macros. These use the EXCAP property (PCI Express Capabilities * register) to find the type for PCI Express devices, and the CLASS-CODE * property (PCI Class Code register) for to find the type of PCI devices behind * a PCI Express-PCI bridge - note that 60400 and 60401 are defined as PCI-PCI * bridges, everything else is consider a PCI leaf device. */ #define PCIEXFN pciexbus/pciexdev/pciexfn #define PCIEXFNHZ pciexbus<>/pciexdev<>/pciexfn<> #define PCIEXFN1 pciexbus[b]/pciexdev[d]/pciexfn[f] #define PCIFN pcibus/pcidev/pcifn #define PCIFNHZ pcibus<>/pcidev<>/pcifn<> #define PCIFN1 pcibus[b]/pcidev[d]/pcifn[f] #define IS_LF(f) (confprop(f, TOPO_PCI_EXCAP) == "pciexdev") #define IS_BG(f) (confprop(f, TOPO_PCI_EXCAP) == "pcibus") #define IS_SD(f) (confprop(f, TOPO_PCI_EXCAP) == "pciexswd") #define IS_SU(f) (confprop(f, TOPO_PCI_EXCAP) == "pciexswu") #define IS_PCI_LF(f) (confprop_defined(f, TOPO_PCI_CLASS) && \ confprop(f, TOPO_PCI_CLASS) != "60400" && \ confprop(f, TOPO_PCI_CLASS) != "60401") /* * define faults */ event fault.io.pciex.fw_corrupt@PCIEXFN, FITrate=PCIEX_DEV_FIT, retire=0; event fault.io.pciex.fw_mismatch@PCIEXFN, FITrate=PCIEX_DEV_FIT, retire=0; event fault.io.pciex.device-interr@PCIEXFN, FITrate=PCIEX_DEV_FIT; event fault.io.pciex.device-interr-deg@PCIEXFN, FITrate=PCIEX_DEV_FIT, retire=0; engine serd.io.pciex.flt-nf@PCIEXFN, N=NONFATAL_DPE_COUNT, T=NONFATAL_DPE_TIME; event fault.io.pciex.device-interr-unaf@PCIEXFN, FITrate=PCIEX_DEV_FIT, engine=serd.io.pciex.flt-nf@PCIEXFN; engine serd.io.device.nonfatal@PCIEXFN, N=CORRLINK_COUNT, T=CORRLINK_TIME; event fault.io.pciex.device-interr-corr@PCIEXFN, FITrate=PCIEX_DEV_FIT, engine=serd.io.device.nonfatal@PCIEXFN; engine serd.io.device.nonfatal@PCIEXFN/PCIEXFN, N=CORRLINK_COUNT, T=CORRLINK_TIME; event fault.io.pciex.device-interr-corr@PCIEXFN/PCIEXFN, FITrate=PCIEX_DEV_FIT, engine=serd.io.device.nonfatal@PCIEXFN/PCIEXFN; engine serd.io.device.nonfatal@pciexrc/PCIEXFN, N=CORRLINK_COUNT, T=CORRLINK_TIME; event fault.io.pciex.device-interr-corr@pciexrc/PCIEXFN, FITrate=PCIEX_DEV_FIT, engine=serd.io.device.nonfatal@pciexrc/PCIEXFN; event fault.io.pciex.device-interr@pciexrc, FITrate=PCIEX_RC_FIT; event fault.io.pciex.device-interr-deg@pciexrc, FITrate=PCIEX_RC_FIT, retire=0; engine serd.io.pciex.flt-nf@pciexrc, N=NONFATAL_DPE_COUNT, T=NONFATAL_DPE_TIME; event fault.io.pciex.device-interr-unaf@pciexrc, FITrate=PCIEX_RC_FIT, engine=serd.io.pciex.flt-nf@pciexrc; engine serd.io.device.nonfatal@pciexrc, N=CORRLINK_COUNT, T=CORRLINK_TIME; event fault.io.pciex.device-interr-corr@pciexrc, FITrate=PCIEX_RC_FIT, engine=serd.io.device.nonfatal@pciexrc; event fault.io.pciex.device-invreq@PCIEXFN, FITrate=PCIEX_DEV_INV_FIT; event fault.io.pciex.device-invreq@pciexrc, FITrate=PCIEX_RC_FIT; event fault.io.pciex.device-noresp@PCIEXFN, FITrate=PCIEX_DEV_NR_FIT; event fault.io.pciex.device-noresp@pciexrc, FITrate=PCIEX_RC_NR_FIT; event fault.io.pciex.bus-noresp@PCIEXFN, FITrate=PCIEX_BUS_NR_FIT; event fault.io.pciex.bus-linkerr@PCIEXFN, FITrate=PCIEX_BUS_FIT; engine serd.io.pciex.corrlink-bus@pciexrc/PCIEXFN, N=CORRLINK_COUNT, T=CORRLINK_TIME; event fault.io.pciex.bus-linkerr-corr@pciexrc/PCIEXFN, FITrate=PCIEX_BUS_FIT, engine=serd.io.pciex.corrlink-bus@pciexrc/PCIEXFN; engine serd.io.pciex.corrlink-bus@PCIEXFN/PCIEXFN, N=CORRLINK_COUNT, T=CORRLINK_TIME; event fault.io.pciex.bus-linkerr-corr@PCIEXFN/PCIEXFN, FITrate=PCIEX_BUS_FIT, engine=serd.io.pciex.corrlink-bus@PCIEXFN/PCIEXFN; /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * Handling of leaf driver detected internal errors. Use serd engine if * no service impact - otherwise fail immediately * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ event ereport.io.device.inval_state@PCIEXFN{within(5s)}; event ereport.io.device.no_response@PCIEXFN{within(5s)}; event ereport.io.device.stall@PCIEXFN{within(5s)}; event ereport.io.device.badint_limit@PCIEXFN{within(5s)}; event ereport.io.device.intern_corr@PCIEXFN{within(5s)}; event ereport.io.device.intern_uncorr@PCIEXFN{within(5s)}; event ereport.io.service.lost@PCIEXFN{within(5s)}; event ereport.io.service.degraded@PCIEXFN{within(5s)}; event ereport.io.service.unaffected@PCIEXFN{within(5s)}; event ereport.io.service.restored@PCIEXFN{within(30s)}; event ereport.io.service.lost@PCIFN{within(5s)}; event ereport.io.service.degraded@PCIFN{within(5s)}; event ereport.io.service.unaffected@PCIFN{within(5s)}; event error.io.pciex.noimpact-d@PCIEXFN; event error.io.pciex.degraded-d@PCIEXFN; event error.io.pciex.lost-d@PCIEXFN; event error.io.service.restored@PCIEXFN; event error.io.service.restored@PCIFN; event error.io.device.nf-device@PCIEXFN; event error.io.device.deg-device@PCIEXFN; event error.io.device.f-device@PCIEXFN; prop error.io.device.f-device@PCIEXFN (1)-> ereport.io.device.inval_state@PCIEXFN, ereport.io.device.no_response@PCIEXFN, ereport.io.device.stall@PCIEXFN, ereport.io.device.badint_limit@PCIEXFN, ereport.io.device.intern_corr@PCIEXFN, ereport.io.device.intern_uncorr@PCIEXFN; prop error.io.device.f-device@PCIEXFN (0)-> error.io.pciex.lost-d@PCIEXFN; prop error.io.device.deg-device@PCIEXFN (1)-> ereport.io.device.inval_state@PCIEXFN, ereport.io.device.no_response@PCIEXFN, ereport.io.device.stall@PCIEXFN, ereport.io.device.badint_limit@PCIEXFN, ereport.io.device.intern_corr@PCIEXFN, ereport.io.device.intern_uncorr@PCIEXFN; prop error.io.device.deg-device@PCIEXFN (1)-> error.io.pciex.degraded-d@PCIEXFN; prop error.io.device.nf-device@PCIEXFN (1)-> ereport.io.device.inval_state@PCIEXFN, ereport.io.device.no_response@PCIEXFN, ereport.io.device.stall@PCIEXFN, ereport.io.device.badint_limit@PCIEXFN, ereport.io.device.intern_corr@PCIEXFN, ereport.io.device.intern_uncorr@PCIEXFN; prop error.io.device.nf-device@PCIEXFN (1)-> error.io.pciex.noimpact-d@PCIEXFN; /* * handling of service impact ereports. */ prop error.io.pciex.lost-d@PCIEXFN (1)-> ereport.io.service.lost@PCIEXFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }, ereport.io.service.lost@PCIFNHZ { is_under(PCIEXFN, PCIFNHZ) }; prop error.io.pciex.lost-d@PCIEXFN (0)-> ereport.io.service.unaffected@PCIEXFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }, ereport.io.service.unaffected@PCIFNHZ { is_under(PCIEXFN, PCIFNHZ) }, ereport.io.service.degraded@PCIEXFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }, ereport.io.service.degraded@PCIFNHZ { is_under(PCIEXFN, PCIFNHZ) }; prop error.io.pciex.degraded-d@PCIEXFN (1)-> ereport.io.service.degraded@PCIEXFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }, ereport.io.service.degraded@PCIFNHZ { is_under(PCIEXFN, PCIFNHZ) }; prop error.io.pciex.degraded-d@PCIEXFN (0)-> ereport.io.service.unaffected@PCIEXFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }, ereport.io.service.unaffected@PCIFNHZ { is_under(PCIEXFN, PCIFNHZ) }; prop error.io.pciex.noimpact-d@PCIEXFN (1)-> ereport.io.service.unaffected@PCIEXFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }, ereport.io.service.unaffected@PCIFNHZ { is_under(PCIEXFN, PCIFNHZ) }, error.io.service.restored@PCIEXFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }, error.io.service.restored@PCIFNHZ { is_under(PCIEXFN, PCIFNHZ) }; prop error.io.service.restored@PCIEXFN (1)-> ereport.io.service.lost@PCIEXFN, ereport.io.service.degraded@PCIEXFN; prop error.io.service.restored@PCIEXFN (1)-> ereport.io.service.restored@PCIEXFN; /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * A faulty PCI Express hostbridge (root complex) may cause: * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * - nr-d: the device not to respond to a valid upstream request * - ca-d: the device to completer abort a valid upstream request * - mtlp-d: a malformed tlp to be transmitted downstream * - badreq-d: a bad downstream request - not CRC error (may cause * completer to respond with ur or ca) * - ecrcreq-d: TLP with end-to-end CRC error transmitted downstream * - ecrccomp-d: TLP with end-to-end CRC error transmitted downstream * - poisreq-d: poisoned request transmitted downstream * - poiscomp-d: poisoned completion transmitted downstream * - corrlink: correctable link or physical level error * - fatlink: fatal link or physical level error */ event error.io.pciex.nr-d@pciexrc/PCIEXFN; event error.io.pciex.ca-d@pciexrc/PCIEXFN; event error.io.pciex.mtlp-d@pciexrc/PCIEXFN; event error.io.pciex.fatlink@pciexrc/PCIEXFN; event error.io.pciex.badreq-d@pciexrc/PCIEXFN; event error.io.pciex.nf-poisecrc-d@pciexrc/PCIEXFN; event error.io.pciex.f-poisecrc-d@pciexrc/PCIEXFN; event error.io.pciex.deg-poisecrc-d@pciexrc/PCIEXFN; event ereport.io.pciex.dl.btlp@pciexrc{within(5s)}; event ereport.io.pciex.dl.bdllp@pciexrc{within(5s)}; event ereport.io.pciex.dl.rto@pciexrc{within(5s)}; event ereport.io.pciex.dl.rnr@pciexrc{within(5s)}; event ereport.io.pciex.pl.re@pciexrc{within(5s)}; event ereport.io.pciex.dl.btlp@pciexrc/PCIEXFN{within(5s)}; event ereport.io.pciex.dl.bdllp@pciexrc/PCIEXFN{within(5s)}; event ereport.io.pciex.dl.rto@pciexrc/PCIEXFN{within(5s)}; event ereport.io.pciex.dl.rnr@pciexrc/PCIEXFN{within(5s)}; event ereport.io.pciex.pl.re@pciexrc/PCIEXFN{within(5s)}; prop fault.io.pciex.device-noresp@pciexrc (1)-> error.io.pciex.nr-d@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-invreq@pciexrc (1)-> error.io.pciex.badreq-d@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@pciexrc { payloadprop_defined("detector") && setserdsuffix("_btlp") && setserdn(BTLP_COUNT) && setserdt(BTLP_TIME) } (0)-> ereport.io.pciex.dl.btlp@pciexrc, ereport.io.pciex.dl.btlp@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@pciexrc { payloadprop_defined("detector") && setserdsuffix("_bdllp") && setserdn(BDLLP_COUNT) && setserdt(BDLLP_TIME) } (0)-> ereport.io.pciex.dl.bdllp@pciexrc, ereport.io.pciex.dl.bdllp@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@pciexrc { payloadprop_defined("detector") && setserdsuffix("_rto") && setserdn(RTO_COUNT) && setserdt(RTO_TIME) } (0)-> ereport.io.pciex.dl.rto@pciexrc, ereport.io.pciex.dl.rto@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@pciexrc { payloadprop_defined("detector") && setserdsuffix("_rnr") && setserdn(RNR_COUNT) && setserdt(RNR_TIME) } (0)-> ereport.io.pciex.dl.rnr@pciexrc, ereport.io.pciex.dl.rnr@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@pciexrc { payloadprop_defined("detector") && setserdsuffix("_re") && setserdn(RE_COUNT) && setserdt(RE_TIME) } (0)-> ereport.io.pciex.pl.re@pciexrc, ereport.io.pciex.pl.re@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-interr-unaf@pciexrc (1)-> error.io.pciex.nf-poisecrc-d@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-interr-deg@pciexrc (1)-> error.io.pciex.deg-poisecrc-d@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-interr@pciexrc (1)-> error.io.pciex.f-poisecrc-d@pciexrc/PCIEXFNHZ, error.io.pciex.ca-d@pciexrc/PCIEXFNHZ, error.io.pciex.mtlp-d@pciexrc/PCIEXFNHZ, error.io.pciex.fatlink@pciexrc/PCIEXFNHZ; /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * A faulty PCI Express leaf device or upstream switch port may cause: * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * - flt-nr-u: the device not to respond to a valid downstream request * - flt-ca-u: the device to completer abort a valid downstream request * - flt-badreq-u: a bad upstream request - not CRC error (may cause * completer to respond with ur or ca) - leaf only * - flt-mtlp-u: a malformed tlp transmitted upstream - leaf only * - flt-ecrcreq-u: request with end-to-end CRC error transmitted upstream * - flt-ecrccomp-u: compl with end-to-end CRC error transmitted upstream * - flt-poisreq-u: poisoned request transmitted upstream * - flt-poiscomp-u: poisoned completion transmitted upstream * - device: internal error reported by leaf device * - corrlink: correctable link or physical level error * - fatlink: fatal link or physical level error */ event error.io.pciex.flt-nr-u@PCIEXFN; event error.io.pciex.flt-ca-u@PCIEXFN; event error.io.pciex.flt-mtlp-u@PCIEXFN; event error.io.pciex.fatlink@PCIEXFN; event error.io.pciex.flt-badreq-u@PCIEXFN; event error.io.pciex.flt-nf-poisecrc-u@PCIEXFN; event error.io.pciex.flt-f-poisecrc-u@PCIEXFN; event error.io.pciex.flt-deg-poisecrc-u@PCIEXFN; event ereport.io.pciex.dl.btlp@PCIEXFN{within(5s)}; event ereport.io.pciex.dl.bdllp@PCIEXFN{within(5s)}; event ereport.io.pciex.dl.rto@PCIEXFN{within(5s)}; event ereport.io.pciex.dl.rnr@PCIEXFN{within(5s)}; event ereport.io.pciex.pl.re@PCIEXFN{within(5s)}; event ereport.io.pciex.dl.btlp@PCIEXFN/PCIEXFN{within(5s)}; event ereport.io.pciex.dl.bdllp@PCIEXFN/PCIEXFN{within(5s)}; event ereport.io.pciex.dl.rto@PCIEXFN/PCIEXFN{within(5s)}; event ereport.io.pciex.dl.rnr@PCIEXFN/PCIEXFN{within(5s)}; event ereport.io.pciex.pl.re@PCIEXFN/PCIEXFN{within(5s)}; event ereport.io.device.fw_corrupt@PCIEXFN{within(5s)}; event ereport.io.device.fw_mismatch@PCIEXFN{within(5s)}; prop fault.io.pciex.device-noresp@PCIEXFN { IS_LF(PCIEXFN) } (1)-> error.io.pciex.flt-nr-u@PCIEXFN; prop fault.io.pciex.device-noresp@PCIEXFN { IS_SU(PCIEXFN) } (1)-> error.io.pciex.flt-nr-u@PCIEXFN; prop fault.io.pciex.device-invreq@PCIEXFN { IS_LF(PCIEXFN) } (1)-> error.io.pciex.flt-badreq-u@PCIEXFN; prop fault.io.pciex.device-interr-corr@pciexrc/PCIEXFN { payloadprop_defined("detector") && setserdsuffix("_btlp") && setserdn(BTLP_COUNT) && setserdt(BTLP_TIME) } (0)-> ereport.io.pciex.dl.btlp@pciexrc, ereport.io.pciex.dl.btlp@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@pciexrc/PCIEXFN { payloadprop_defined("detector") && setserdsuffix("_bdllp") && setserdn(BDLLP_COUNT) && setserdt(BDLLP_TIME) } (0)-> ereport.io.pciex.dl.bdllp@pciexrc, ereport.io.pciex.dl.bdllp@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@pciexrc/PCIEXFN { payloadprop_defined("detector") && setserdsuffix("_rto") && setserdn(RTO_COUNT) && setserdt(RTO_TIME) } (0)-> ereport.io.pciex.dl.rto@pciexrc, ereport.io.pciex.dl.rto@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@pciexrc/PCIEXFN { payloadprop_defined("detector") && setserdsuffix("_rnr") && setserdn(RNR_COUNT) && setserdt(RNR_TIME) } (0)-> ereport.io.pciex.dl.rnr@pciexrc, ereport.io.pciex.dl.rnr@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@pciexrc/PCIEXFN { payloadprop_defined("detector") && setserdsuffix("_re") && setserdn(RE_COUNT) && setserdt(RE_TIME) } (0)-> ereport.io.pciex.pl.re@pciexrc, ereport.io.pciex.pl.re@pciexrc/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@PCIEXFN/PCIEXFN { !IS_SD(PCIEXFN/PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_btlp") && setserdn(BTLP_COUNT) && setserdt(BTLP_TIME) } (0)-> ereport.io.pciex.dl.btlp@PCIEXFN, ereport.io.pciex.dl.btlp@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@PCIEXFN/PCIEXFN { !IS_SD(PCIEXFN/PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_bdllp") && setserdn(BDLLP_COUNT) && setserdt(BDLLP_TIME) } (0)-> ereport.io.pciex.dl.bdllp@PCIEXFN, ereport.io.pciex.dl.bdllp@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@PCIEXFN/PCIEXFN { !IS_SD(PCIEXFN/PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_rto") && setserdn(RTO_COUNT) && setserdt(RTO_TIME) } (0)-> ereport.io.pciex.dl.rto@PCIEXFN, ereport.io.pciex.dl.rto@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@PCIEXFN/PCIEXFN { !IS_SD(PCIEXFN/PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_rnr") && setserdn(RNR_COUNT) && setserdt(RNR_TIME) } (0)-> ereport.io.pciex.dl.rnr@PCIEXFN, ereport.io.pciex.dl.rnr@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@PCIEXFN/PCIEXFN { !IS_SD(PCIEXFN/PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_re") && setserdn(RE_COUNT) && setserdt(RE_TIME) } (0)-> ereport.io.pciex.pl.re@PCIEXFN, ereport.io.pciex.pl.re@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.device-interr-unaf@PCIEXFN { IS_SU(PCIEXFN) } (1)-> error.io.pciex.flt-nf-poisecrc-u@PCIEXFN; prop fault.io.pciex.device-interr-corr@PCIEXFN { IS_LF(PCIEXFN) } (0)-> error.io.device.nf-device@PCIEXFN; prop fault.io.pciex.device-interr-unaf@PCIEXFN { IS_LF(PCIEXFN) } (1)-> error.io.pciex.flt-nf-poisecrc-u@PCIEXFN; prop fault.io.pciex.device-interr-deg@PCIEXFN { IS_SU(PCIEXFN) } (1)-> error.io.pciex.flt-deg-poisecrc-u@PCIEXFN; prop fault.io.pciex.device-interr@PCIEXFN { IS_SU(PCIEXFN) } (1)-> error.io.pciex.flt-f-poisecrc-u@PCIEXFN, error.io.pciex.flt-ca-u@PCIEXFN, error.io.pciex.fatlink@PCIEXFN; prop fault.io.pciex.device-interr-deg@PCIEXFN { IS_LF(PCIEXFN) } (1)-> error.io.pciex.flt-deg-poisecrc-u@PCIEXFN, error.io.device.deg-device@PCIEXFN; prop fault.io.pciex.device-interr@PCIEXFN { IS_LF(PCIEXFN) } (1)-> error.io.pciex.flt-f-poisecrc-u@PCIEXFN, error.io.device.f-device@PCIEXFN, error.io.pciex.flt-ca-u@PCIEXFN, error.io.pciex.flt-mtlp-u@PCIEXFN, error.io.pciex.fatlink@PCIEXFN; prop fault.io.pciex.fw_corrupt@PCIEXFN { IS_LF(PCIEXFN) } (1)-> ereport.io.device.fw_corrupt@PCIEXFN; prop fault.io.pciex.fw_corrupt@PCIEXFN { IS_LF(PCIEXFN) } (0)-> ereport.io.service.lost@PCIEXFN, ereport.io.service.degraded@PCIEXFN; prop fault.io.pciex.fw_mismatch@PCIEXFN { IS_LF(PCIEXFN) } (1)-> ereport.io.device.fw_mismatch@PCIEXFN; prop fault.io.pciex.fw_mismatch@PCIEXFN { IS_LF(PCIEXFN) } (0)-> ereport.io.service.lost@PCIEXFN, ereport.io.service.degraded@PCIEXFN; /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * A faulty PCI Express downstream switch port may cause * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * - nr-d: the device not to respond to an upstream request * - ca-d: the device to completer abort an upstream request * - ecrcreq-d: TLP with end-to-end CRC error transmitted upstream * - ecrccomp-d: TLP with end-to-end CRC error transmitted upstream * - poisreq-d: poisoned request transmitted upstream * - poiscomp-d: poisoned completion transmitted upstream * - corrlink: correctable link or physical level error * - fatlink: fatal link or physical level error */ event error.io.pciex.nr-d@PCIEXFN/PCIEXFN; event error.io.pciex.ca-d@PCIEXFN/PCIEXFN; event error.io.pciex.fatlink@PCIEXFN/PCIEXFN; event error.io.pciex.nf-poisecrc-d@PCIEXFN/PCIEXFN; event error.io.pciex.f-poisecrc-d@PCIEXFN/PCIEXFN; event error.io.pciex.deg-poisecrc-d@PCIEXFN/PCIEXFN; prop fault.io.pciex.device-noresp@PCIEXFN { IS_SD(PCIEXFN) } (1)-> error.io.pciex.nr-d@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@PCIEXFN { IS_SD(PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_btlp") && setserdn(BTLP_COUNT) && setserdt(BTLP_TIME) } (0)-> ereport.io.pciex.dl.btlp@PCIEXFN, ereport.io.pciex.dl.btlp@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@PCIEXFN { IS_SD(PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_bdllp") && setserdn(BDLLP_COUNT) && setserdt(BDLLP_TIME) } (0)-> ereport.io.pciex.dl.bdllp@PCIEXFN, ereport.io.pciex.dl.bdllp@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@PCIEXFN { IS_SD(PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_rto") && setserdn(RTO_COUNT) && setserdt(RTO_TIME) } (0)-> ereport.io.pciex.dl.rto@PCIEXFN, ereport.io.pciex.dl.rto@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@PCIEXFN { IS_SD(PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_rnr") && setserdn(RNR_COUNT) && setserdt(RNR_TIME) } (0)-> ereport.io.pciex.dl.rnr@PCIEXFN, ereport.io.pciex.dl.rnr@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.device-interr-corr@PCIEXFN { IS_SD(PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_re") && setserdn(RE_COUNT) && setserdt(RE_TIME) } (0)-> ereport.io.pciex.pl.re@PCIEXFN, ereport.io.pciex.pl.re@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.device-interr-unaf@PCIEXFN { IS_SD(PCIEXFN) } (1)-> error.io.pciex.nf-poisecrc-d@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.device-interr-deg@PCIEXFN { IS_SD(PCIEXFN) } (1)-> error.io.pciex.deg-poisecrc-d@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.device-interr@PCIEXFN { IS_SD(PCIEXFN) } (1)-> error.io.pciex.ca-d@PCIEXFN/PCIEXFNHZ, error.io.pciex.f-poisecrc-d@PCIEXFN/PCIEXFNHZ, error.io.pciex.fatlink@PCIEXFN/PCIEXFNHZ; /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * A faulty PCIEX bus may cause: * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * - flt-nr-u: a device to not respond because the link is down * - nr-d: a device to not respond because the link is down * - corrlink: correctable link or physical level error * - fatlink: fatal link or physical level error */ event error.io.pciex.nr-d@PCIEXFN; prop fault.io.pciex.bus-noresp@PCIEXFN { !IS_SD(PCIEXFN) } (0)-> error.io.pciex.flt-nr-u@PCIEXFN, error.io.pciex.nr-d@PCIEXFN; prop fault.io.pciex.bus-linkerr-corr@PCIEXFN/PCIEXFN { !IS_SD(PCIEXFN/PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_btlp") && setserdn(BTLP_COUNT) && setserdt(BTLP_TIME) } (0)-> ereport.io.pciex.dl.btlp@PCIEXFN, ereport.io.pciex.dl.btlp@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.bus-linkerr-corr@PCIEXFN/PCIEXFN { !IS_SD(PCIEXFN/PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_bdllp") && setserdn(BDLLP_COUNT) && setserdt(BDLLP_TIME) } (0)-> ereport.io.pciex.dl.bdllp@PCIEXFN, ereport.io.pciex.dl.bdllp@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.bus-linkerr-corr@PCIEXFN/PCIEXFN { !IS_SD(PCIEXFN/PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_rto") && setserdn(RTO_COUNT) && setserdt(RTO_TIME) } (0)-> ereport.io.pciex.dl.rto@PCIEXFN, ereport.io.pciex.dl.rto@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.bus-linkerr-corr@PCIEXFN/PCIEXFN { !IS_SD(PCIEXFN/PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_rnr") && setserdn(RNR_COUNT) && setserdt(RNR_TIME) } (0)-> ereport.io.pciex.dl.rnr@PCIEXFN, ereport.io.pciex.dl.rnr@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.bus-linkerr-corr@PCIEXFN/PCIEXFN { !IS_SD(PCIEXFN/PCIEXFN) && payloadprop_defined("detector") && setserdsuffix("_re") && setserdn(RE_COUNT) && setserdt(RE_TIME) } (0)-> ereport.io.pciex.pl.re@PCIEXFN, ereport.io.pciex.pl.re@PCIEXFN/PCIEXFNHZ; prop fault.io.pciex.bus-linkerr-corr@pciexrc/PCIEXFN { payloadprop_defined("detector") && setserdsuffix("_btlp") && setserdn(BTLP_COUNT) && setserdt(BTLP_TIME) } (0)-> ereport.io.pciex.dl.btlp@pciexrc, ereport.io.pciex.dl.btlp@pciexrc/PCIEXFNHZ; prop fault.io.pciex.bus-linkerr-corr@pciexrc/PCIEXFN { payloadprop_defined("detector") && setserdsuffix("_bdllp") && setserdn(BDLLP_COUNT) && setserdt(BDLLP_TIME) } (0)-> ereport.io.pciex.dl.bdllp@pciexrc, ereport.io.pciex.dl.bdllp@pciexrc/PCIEXFNHZ; prop fault.io.pciex.bus-linkerr-corr@pciexrc/PCIEXFN { payloadprop_defined("detector") && setserdsuffix("_rto") && setserdn(RTO_COUNT) && setserdt(RTO_TIME) } (0)-> ereport.io.pciex.dl.rto@pciexrc, ereport.io.pciex.dl.rto@pciexrc/PCIEXFNHZ; prop fault.io.pciex.bus-linkerr-corr@pciexrc/PCIEXFN { payloadprop_defined("detector") && setserdsuffix("_rnr") && setserdn(RNR_COUNT) && setserdt(RNR_TIME) } (0)-> ereport.io.pciex.dl.rnr@pciexrc, ereport.io.pciex.dl.rnr@pciexrc/PCIEXFNHZ; prop fault.io.pciex.bus-linkerr-corr@pciexrc/PCIEXFN { payloadprop_defined("detector") && setserdsuffix("_re") && setserdn(RE_COUNT) && setserdt(RE_TIME) } (0)-> ereport.io.pciex.pl.re@pciexrc, ereport.io.pciex.pl.re@pciexrc/PCIEXFNHZ; prop fault.io.pciex.bus-linkerr@PCIEXFN { !IS_SD(PCIEXFN) } (0)-> error.io.pciex.fatlink@PCIEXFN; /* * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * A faulty pciex-pci bridge may cause * ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * The following errors to propagate onto the PCI Express fabric * - flt-nr-u: the device not to respond to a valid downstream request * - flt-ca-u: the device to completer abort a valid downstream request * - flt-ecrcreq-u: request with end-to-end CRC error transmitted upstream * - flt-ecrccomp-u: compl with end-to-end CRC error transmitted upstream * - flt-poisreq-u: poisoned request transmitted upstream * - flt-poiscomp-u: poisoned completion transmitted upstream * - corrlink: correctable link or physical level error upstream * - fatlink: fatal link or physical level error upstream * - sec-interr: internal error on pci express to pci bridge * * And the following errors to propagate onto the secondary pci or pci/x bus * (these will be handled by code in the pci.esc file). * - nr-pw-d: the device not to respond to a valid upstream request * - nr-drw-d: the device not to respond to a valid upstream request * - retry-to-d: failure to retry an downstream delayed request * - ta-pw-d: the device responds with a ta to a valid upstream * request * - ta-drw-d: the device responds with a ta to a valid upstream * request * - ape-d: address/parity to get corrupted during downstream transmission. * - dpe-d: data/parity to get corrupted during downstream transmission. * - scpe-d: split completion to get corrupted during downstream transmission */ event error.io.pci.ape-d@PCIEXFN/PCIFN; event error.io.pci.f-dpe-d@PCIEXFN/PCIFN; event error.io.pci.deg-dpe-d@PCIEXFN/PCIFN; event error.io.pci.nf-dpe-d@PCIEXFN/PCIFN; event error.io.pci.retry-to-d@PCIEXFN/PCIFN; event error.io.pci.nr-pw-d@PCIEXFN/PCIFN; event error.io.pci.nr-drw-d@PCIEXFN/PCIFN; event error.io.pci.ta-pw-d@PCIEXFN/PCIFN; event error.io.pci.ta-drw-d@PCIEXFN/PCIFN; event error.io.pcix.scpe-d@PCIEXFN/PCIFN; event error.io.pciex.sec-interr@PCIEXFN; event ereport.io.pci.sec-sta@PCIEXFN{within(5s)}; prop fault.io.pciex.device-noresp@PCIEXFN { IS_BG(PCIEXFN) } (1)-> error.io.pciex.flt-nr-u@PCIEXFN, error.io.pci.retry-to-d@PCIEXFN/PCIFNHZ, error.io.pci.nr-pw-d@PCIEXFN/PCIFNHZ, error.io.pci.nr-drw-d@PCIEXFN/PCIFNHZ; prop fault.io.pciex.device-interr-unaf@PCIEXFN { IS_BG(PCIEXFN) } (1)-> error.io.pciex.flt-nf-poisecrc-u@PCIEXFN, error.io.pci.nf-dpe-d@PCIEXFN/PCIFNHZ; prop fault.io.pciex.device-interr-deg@PCIEXFN { IS_BG(PCIEXFN) } (1)-> error.io.pciex.flt-deg-poisecrc-u@PCIEXFN, error.io.pci.deg-dpe-d@PCIEXFN/PCIFNHZ; prop fault.io.pciex.device-interr@PCIEXFN { IS_BG(PCIEXFN) } (1)-> error.io.pciex.flt-f-poisecrc-u@PCIEXFN, error.io.pciex.flt-ca-u@PCIEXFN, error.io.pciex.flt-mtlp-u@PCIEXFN, error.io.pciex.sec-interr@PCIEXFN, error.io.pciex.fatlink@PCIEXFN, error.io.pci.ta-pw-d@PCIEXFN/PCIFNHZ, error.io.pci.ta-drw-d@PCIEXFN/PCIFNHZ, error.io.pci.ape-d@PCIEXFN/PCIFNHZ, error.io.pcix.scpe-d@PCIEXFN/PCIFNHZ, error.io.pci.f-dpe-d@PCIEXFN/PCIFNHZ; prop fault.io.pciex.device-interr-unaf@PCIEXFN { IS_BG(PCIEXFN) } (0)-> ereport.io.pci.sec-sta@PCIEXFN; prop fault.io.pciex.device-interr@PCIEXFN { IS_BG(PCIEXFN) } (0)-> ereport.io.pci.sec-sta@PCIEXFN; /* * the following rules for ptlp and ecrc faults are split into fatal and * nonfatal, depending on the service impact reported by the leaf driver */ event error.io.pciex.nf-poisecrc-d@PCIEXFN; event error.io.pciex.deg-poisecrc-d@PCIEXFN; event error.io.pciex.f-poisecrc-d@PCIEXFN; event error.io.pciex.ecrcreq-d@PCIEXFN; event error.io.pciex.ecrccomp-d@PCIEXFN; event error.io.pciex.poisreq-d@PCIEXFN; event error.io.pciex.poiscomp-d@PCIEXFN; event error.io.pciex.flt-poisreq-u@PCIEXFN; event error.io.pciex.flt-poiscomp-u@PCIEXFN; event error.io.pciex.flt-ecrcreq-u@PCIEXFN; event error.io.pciex.flt-ecrccomp-u@PCIEXFN; prop error.io.pciex.nf-poisecrc-d@PCIEXFN (1)-> error.io.pciex.ecrcreq-d@PCIEXFN, error.io.pciex.ecrccomp-d@PCIEXFN, error.io.pciex.poisreq-d@PCIEXFN, error.io.pciex.poiscomp-d@PCIEXFN; prop error.io.pciex.nf-poisecrc-d@PCIEXFN (1)-> error.io.pciex.noimpact-d@PCIEXFN; prop error.io.pciex.f-poisecrc-d@PCIEXFN (1)-> error.io.pciex.ecrcreq-d@PCIEXFN, error.io.pciex.ecrccomp-d@PCIEXFN, error.io.pciex.poisreq-d@PCIEXFN, error.io.pciex.poiscomp-d@PCIEXFN; prop error.io.pciex.f-poisecrc-d@PCIEXFN (0)-> error.io.pciex.lost-d@PCIEXFN; prop error.io.pciex.deg-poisecrc-d@PCIEXFN (1)-> error.io.pciex.ecrcreq-d@PCIEXFN, error.io.pciex.ecrccomp-d@PCIEXFN, error.io.pciex.poisreq-d@PCIEXFN, error.io.pciex.poiscomp-d@PCIEXFN; prop error.io.pciex.deg-poisecrc-d@PCIEXFN (1)-> error.io.pciex.degraded-d@PCIEXFN; prop error.io.pciex.flt-nf-poisecrc-u@PCIEXFN (1)-> error.io.pciex.flt-ecrcreq-u@PCIEXFN, error.io.pciex.flt-ecrccomp-u@PCIEXFN, error.io.pciex.flt-poisreq-u@PCIEXFN, error.io.pciex.flt-poiscomp-u@PCIEXFN; prop error.io.pciex.flt-nf-poisecrc-u@PCIEXFN (1)-> error.io.pciex.noimpact-d@PCIEXFN; prop error.io.pciex.flt-deg-poisecrc-u@PCIEXFN (1)-> error.io.pciex.flt-ecrcreq-u@PCIEXFN, error.io.pciex.flt-ecrccomp-u@PCIEXFN, error.io.pciex.flt-poisreq-u@PCIEXFN, error.io.pciex.flt-poiscomp-u@PCIEXFN; prop error.io.pciex.flt-deg-poisecrc-u@PCIEXFN (1)-> error.io.pciex.degraded-d@PCIEXFN; prop error.io.pciex.flt-f-poisecrc-u@PCIEXFN (1)-> error.io.pciex.flt-ecrcreq-u@PCIEXFN, error.io.pciex.flt-ecrccomp-u@PCIEXFN, error.io.pciex.flt-poisreq-u@PCIEXFN, error.io.pciex.flt-poiscomp-u@PCIEXFN; prop error.io.pciex.flt-f-poisecrc-u@PCIEXFN (0)-> error.io.pciex.lost-d@PCIEXFN; /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * declarations * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ event error.io.pciex.fatal@PCIEXFN; event error.io.pciex.nonfatal@PCIEXFN; event error.io.pciex.nr-fwd-d@PCIEXFN; event error.io.pciex.mtlp-fwd-d@PCIEXFN; event error.io.pciex.flt-ur-u@PCIEXFN; event error.io.pciex.mtlp-d@PCIEXFN; event error.io.pciex.ca-d@PCIEXFN; event error.io.pciex.ca-fwd-d@PCIEXFN; event error.io.pciex.poisreq-fwd-d@PCIEXFN; event error.io.pciex.poisreq-fwd-d@pciexrc/PCIEXFN; event error.io.pciex.poisreq-fwd-d@PCIEXFN/PCIEXFN; event error.io.pciex.poiscomp-fwd-d@PCIEXFN; event error.io.pciex.poiscomp-fwd-d@PCIEXFN/PCIEXFN; event error.io.pciex.ecrcreq-fwd-d@PCIEXFN; event error.io.pciex.ecrccomp-fwd-d@PCIEXFN; event error.io.pciex.source-ecrcreq-u@PCIEXFN; event error.io.pciex.source-ecrccomp-u@PCIEXFN; event error.io.pciex.source-poiscomp-u@PCIEXFN; event error.io.pciex.source-poisreq-u@PCIEXFN; event error.io.pciex.badreq-d@PCIEXFN; event error.io.pci.badreq-pw-d@PCIEXFN/PCIFN; event error.io.pci.badreq-drw-d@PCIEXFN/PCIFN; event error.io.pci.target-ma-d@PCIEXFN; event error.io.pci.target-rta-d@PCIEXFN; event error.io.pci.dpdata-pw-d@PCIEXFN/PCIFN; event error.io.pci.dpdata-dw-d@PCIEXFN/PCIFN; event error.io.pci.dpdata-dr-d@PCIEXFN/PCIFN; event error.io.pciex.ca-u@PCIEXFN; event error.io.pciex.ca-u@PCIEXFN/PCIEXFN; event error.io.pciex.ca-u@pciexrc/PCIEXFN; event error.io.pciex.ur-u@PCIEXFN; event error.io.pciex.ur-u@PCIEXFN/PCIEXFN; event error.io.pciex.ur-u@pciexrc/PCIEXFN; event error.io.pciex.nr-u@PCIEXFN; event error.io.pciex.nr-u@PCIEXFN/PCIEXFN; event error.io.pciex.nr-u@pciexrc/PCIEXFN; event error.io.pciex.mtlp-u@PCIEXFN; event error.io.pciex.mtlp-u@PCIEXFN/PCIEXFN; event error.io.pciex.mtlp-u@pciexrc/PCIEXFN; event error.io.pciex.badreq-u@PCIEXFN; event error.io.pciex.badreq-u@PCIEXFN/PCIEXFN; event error.io.pciex.badreq-u@pciexrc/PCIEXFN; event error.io.pciex.poisreq-u@PCIEXFN; event error.io.pciex.poisreq-u@PCIEXFN/PCIEXFN; event error.io.pciex.poisreq-u@pciexrc/PCIEXFN; event error.io.pciex.poiscomp-u@PCIEXFN; event error.io.pciex.poiscomp-u@PCIEXFN/PCIEXFN; event error.io.pciex.poiscomp-u@pciexrc/PCIEXFN; event error.io.pciex.ecrcreq-u@PCIEXFN; event error.io.pciex.ecrcreq-u@PCIEXFN/PCIEXFN; event error.io.pciex.ecrccomp-u@PCIEXFN; event error.io.pciex.ecrccomp-u@PCIEXFN/PCIEXFN; event ereport.io.pci.ma@PCIEXFN{within(5s)}; event ereport.io.pci.mdpe@PCIEXFN{within(5s)}; event ereport.io.pci.dpe@PCIEXFN{within(5s)}; event ereport.io.pci.rta@PCIEXFN{within(5s)}; event ereport.io.pci.sta@PCIEXFN{within(5s)}; event ereport.io.pciex.dl.dllp@PCIEXFN{within(5s)}; event ereport.io.pciex.pl.te@PCIEXFN{within(5s)}; event ereport.io.pciex.pl.sd@PCIEXFN{within(5s)}; event ereport.io.pciex.tl.fcp@PCIEXFN{within(5s)}; event ereport.io.pciex.tl.rof@PCIEXFN{within(5s)}; event ereport.io.pciex.tl.mtlp@PCIEXFN{within(5s)}; event ereport.io.pciex.tl.ur@PCIEXFN{within(5s)}; event ereport.io.pciex.tl.ca@PCIEXFN{within(5s)}; event ereport.io.pciex.tl.ptlp@PCIEXFN{within(5s)}; event ereport.io.pciex.tl.ecrc@PCIEXFN{within(5s)}; event ereport.io.pciex.tl.uc@PCIEXFN{within(5s)}; event ereport.io.pciex.tl.cto@PCIEXFN{within(5s)}; event ereport.io.pciex.dl.dllp@pciexrc{within(5s)}; event ereport.io.pciex.pl.te@pciexrc{within(5s)}; event ereport.io.pciex.pl.sd@pciexrc{within(5s)}; event ereport.io.pciex.tl.fcp@pciexrc{within(5s)}; event ereport.io.pciex.tl.rof@pciexrc{within(5s)}; event ereport.io.pciex.tl.mtlp@pciexrc{within(5s)}; event ereport.io.pciex.tl.ur@pciexrc{within(5s)}; event ereport.io.pciex.tl.ca@pciexrc{within(5s)}; event ereport.io.pciex.tl.ptlp@pciexrc{within(5s)}; event ereport.io.pciex.tl.ecrc@pciexrc{within(5s)}; event ereport.io.pciex.tl.cto@pciexrc{within(5s)}; event ereport.io.pci.sec-ma@pciexrc{within(5s)}; event ereport.io.pci.sec-mdpe@pciexrc{within(5s)}; event ereport.io.pci.sec-dpe@pciexrc{within(5s)}; event ereport.io.pci.sec-rta@pciexrc{within(5s)}; event ereport.io.pci.sec-sta@pciexrc{within(5s)}; event ereport.io.pci.sec-mdpe@PCIEXFN{within(5s)}; event ereport.io.pci.sec-dpe@PCIEXFN{within(5s)}; event ereport.io.pci.sec-rserr@PCIEXFN{within(5s)}; event ereport.io.pci.sserr@PCIEXFN{within(5s)}; event ereport.io.pci.sec-rserr@pciexrc{within(5s)}; event ereport.io.pciex.rc.fe-msg@pciexrc{within(5s)}; event ereport.io.pciex.rc.nfe-msg@pciexrc{within(5s)}; event ereport.io.pciex.rc.mue-msg@pciexrc{within(5s)}; event ereport.io.pciex.bdg.sec-interr@PCIEXFN{within(5s)}; event ereport.io.pciex.bdg.sec-ude@PCIEXFN{within(5s)}; event ereport.io.pci.target-mdpe@PCIEXFN{within(5s)}; event ereport.io.pci.target-mdpe@PCIFN{within(5s)}; /* * handling of fatal and nonfatal error messages propagated up to root complex * * Use these for errors reported by root-complex on behalf of another device. * Can use source-id payload to identify where the message came from. */ prop error.io.pciex.fatal@PCIEXFN1 (1)-> ereport.io.pciex.rc.mue-msg@pciexrc { is_under(pciexrc, PCIEXFN1) }, ereport.io.pciex.rc.fe-msg@pciexrc { is_under(pciexrc, PCIEXFN1) && SOURCE_ID_MATCHES_BDF }; prop error.io.pciex.fatal@PCIEXFN (0)-> ereport.io.pci.sserr@PCIEXFN; prop error.io.pciex.fatal@PCIEXFN { is_under(PCIEXFN1, PCIEXFN) } (0)-> ereport.io.pci.sserr@PCIEXFN1, ereport.io.pci.sec-rserr@PCIEXFN1; prop error.io.pciex.fatal@PCIEXFN { is_under(pciexrc, PCIEXFN) } (0)-> ereport.io.pci.sec-rserr@pciexrc; prop error.io.pciex.nonfatal@PCIEXFN1 (1)-> ereport.io.pciex.rc.mue-msg@pciexrc { is_under(pciexrc, PCIEXFN1) }, ereport.io.pciex.rc.nfe-msg@pciexrc { is_under(pciexrc, PCIEXFN1) && SOURCE_ID_MATCHES_BDF }; prop error.io.pciex.nonfatal@PCIEXFN (0)-> ereport.io.pci.sserr@PCIEXFN; prop error.io.pciex.nonfatal@PCIEXFN { is_under(PCIEXFN1, PCIEXFN) } (0)-> ereport.io.pci.sserr@PCIEXFN1, ereport.io.pci.sec-rserr@PCIEXFN1; prop error.io.pciex.nonfatal@PCIEXFN { is_under(pciexrc, PCIEXFN) } (0)-> ereport.io.pci.sec-rserr@pciexrc; /* * link-level errors - could generate ereports at either end of link * * can use may propagations here as these ereports are only seen for these * faults. */ prop error.io.pciex.fatlink@PCIEXFN { !IS_SD(PCIEXFN) } (0)-> error.io.pciex.fatal@PCIEXFN; prop error.io.pciex.fatlink@PCIEXFN { !IS_SD(PCIEXFN) } (0)-> ereport.io.pciex.dl.dllp@PCIEXFN, ereport.io.pciex.tl.fcp@PCIEXFN, ereport.io.pciex.tl.rof@PCIEXFN; prop error.io.pciex.fatlink@PCIEXFN/PCIEXFN { IS_SD(PCIEXFN) } (0)-> error.io.pciex.fatal@PCIEXFN; prop error.io.pciex.fatlink@PCIEXFN/PCIEXFN { IS_SD(PCIEXFN) } (0)-> ereport.io.pciex.dl.dllp@PCIEXFN, ereport.io.pciex.pl.te@PCIEXFN, ereport.io.pciex.pl.sd@PCIEXFN, ereport.io.pciex.tl.fcp@PCIEXFN, ereport.io.pciex.tl.rof@PCIEXFN; prop error.io.pciex.fatlink@pciexrc/PCIEXFN (0)-> ereport.io.pciex.dl.dllp@pciexrc, ereport.io.pciex.pl.te@pciexrc, ereport.io.pciex.pl.sd@pciexrc, ereport.io.pciex.tl.fcp@pciexrc, ereport.io.pciex.tl.rof@pciexrc; /* * bridge internal error */ prop error.io.pciex.sec-interr@PCIEXFN { IS_BG(PCIEXFN) } (2) -> error.io.pciex.nonfatal@PCIEXFN, ereport.io.pciex.bdg.sec-interr@PCIEXFN; /* * downstream poisoned request * * - poisreq-d cascades down to the leaf device/bridge and any switch ports * on route must raise a ptlp ereport while any switch ports forwarding * the poisoned request must raise sec-mdpe ereports. The originator of the * poisoning (be it root complex or downstream port of a switch) also raises * sec-mdpe. A hardened leaf driver will also raise ptlp. A target-mdpe may * be seen at the leaf (which may be a pci device beyond the bridge). * * Additionally, the leaf/bridge may treat the request as a ur, which the * root complex will see and report an ma. Use flt-ur-u to represent this. * * The fault can always be recognized and the source identified using the ptlp * and sec-mdpe ereports. */ prop error.io.pciex.poisreq-d@PCIEXFN (1)-> error.io.pciex.poisreq-fwd-d@PCIEXFN; prop error.io.pciex.poisreq-fwd-d@PCIEXFN { IS_SD(PCIEXFN) || IS_SU(PCIEXFN) } (1)-> error.io.pciex.flt-ur-u@PCIEXFN, error.io.pciex.poisreq-fwd-d@PCIEXFN/PCIEXFNHZ; prop error.io.pciex.poisreq-fwd-d@pciexrc/PCIEXFN (1)-> ereport.io.pci.sec-mdpe@pciexrc; prop error.io.pciex.poisreq-fwd-d@PCIEXFN/PCIEXFN { IS_SU(PCIEXFN) } (0)-> ereport.io.pci.sec-mdpe@PCIEXFN; prop error.io.pciex.poisreq-fwd-d@PCIEXFN { IS_SU(PCIEXFN) } (2)-> ereport.io.pci.dpe@PCIEXFN, ereport.io.pciex.tl.ptlp@PCIEXFN; prop error.io.pciex.poisreq-fwd-d@PCIEXFN { IS_SU(PCIEXFN) } (0)-> error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.poisreq-fwd-d@PCIEXFN/PCIEXFN { IS_SD(PCIEXFN) } (1)-> ereport.io.pci.sec-mdpe@PCIEXFN; prop error.io.pciex.poisreq-fwd-d@PCIEXFN { IS_SD(PCIEXFN) } (0)-> ereport.io.pci.dpe@PCIEXFN, ereport.io.pciex.tl.ptlp@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.poisreq-fwd-d@PCIEXFN { IS_BG(PCIEXFN) } (3)-> ereport.io.pci.dpe@PCIEXFN, ereport.io.pciex.tl.ptlp@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.poisreq-fwd-d@PCIEXFN { IS_BG(PCIEXFN) } (1)-> error.io.pci.dpdata-pw-d@PCIEXFN/PCIFNHZ, error.io.pci.dpdata-dw-d@PCIEXFN/PCIFNHZ; prop error.io.pciex.poisreq-fwd-d@PCIEXFN { IS_LF(PCIEXFN) } (1)-> error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.poisreq-fwd-d@PCIEXFN { IS_LF(PCIEXFN) } (0)-> ereport.io.pci.dpe@PCIEXFN, ereport.io.pciex.tl.ptlp@PCIEXFN, error.io.pciex.flt-ur-u@PCIEXFN; prop error.io.pciex.poisreq-fwd-d@PCIEXFN (0)-> ereport.io.pci.target-mdpe@PCIEXFN; /* * downstream poisoned completion * * - poiscomp-d cascades down to the leaf device/bridge and any switch ports on * route must raise ptlp and mdpe ereports. A hardened leaf driver will also * raise pltp and mdpe. For non-hardened leaf devices, no ptlp/mdpe may be * reported, and though we should still see a nonfatal error reported from * the root complex identifying the leaf device, we won't actually be informed * that the error was an ptlp. */ prop error.io.pciex.poiscomp-d@PCIEXFN (1)-> error.io.pciex.poiscomp-fwd-d@PCIEXFN; prop error.io.pciex.poiscomp-fwd-d@PCIEXFN (1)-> error.io.pciex.poiscomp-fwd-d@PCIEXFN/PCIEXFNHZ; prop error.io.pciex.poiscomp-fwd-d@PCIEXFN { IS_SU(PCIEXFN) } (2)-> ereport.io.pci.dpe@PCIEXFN, ereport.io.pciex.tl.ptlp@PCIEXFN; prop error.io.pciex.poiscomp-fwd-d@PCIEXFN { IS_SU(PCIEXFN) } (1)-> ereport.io.pci.mdpe@PCIEXFN, ereport.io.pci.sec-mdpe@PCIEXFN; prop error.io.pciex.poiscomp-fwd-d@PCIEXFN { IS_SU(PCIEXFN) } (0)-> error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.poiscomp-fwd-d@PCIEXFN { IS_SD(PCIEXFN) } (0)-> ereport.io.pci.mdpe@PCIEXFN, ereport.io.pci.sec-mdpe@PCIEXFN, ereport.io.pci.dpe@PCIEXFN, ereport.io.pciex.tl.ptlp@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.poiscomp-fwd-d@PCIEXFN { IS_BG(PCIEXFN) } (4)-> ereport.io.pci.mdpe@PCIEXFN, ereport.io.pci.dpe@PCIEXFN, ereport.io.pciex.tl.ptlp@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.poiscomp-fwd-d@PCIEXFN { IS_BG(PCIEXFN) } (1)-> error.io.pci.dpdata-dr-d@PCIEXFN/PCIFNHZ; prop error.io.pciex.poiscomp-fwd-d@PCIEXFN { IS_LF(PCIEXFN) } (1)-> error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.poiscomp-fwd-d@PCIEXFN { IS_LF(PCIEXFN) } (0)-> ereport.io.pci.mdpe@PCIEXFN, ereport.io.pci.dpe@PCIEXFN, ereport.io.pciex.tl.ptlp@PCIEXFN; /* * downstream request with ecrc error. * * - ecrcreq-d cascades down to the leaf device/bridge and any switches on * route can optionally raise an ecrc ereport. A hardened leaf driver may also * raise ecrc. For non-hardened leaf devices, no ecrc may be reported, and * though we should still see a nonfatal error reported from the root complex * identifying the leaf device, we won't actually be informed that the error * was an ecrc. * * Additionally, as the leaf/bridge will just throw away the packet, we should * eventually get a cto at the root complex - so use an nr-u at the pciex * leaf or bridge to get the appropriate behaviour. For the case where the leaf * driver wasn't hardened we may be able to identify the leaf device (and * therefore any intermediate switches which might have caused the problem) * either via a target-ma ereport if available or via the nonfatal error * reported from the root complex identifying the leaf device. The combination * of a nonfatal error reported from the root complex and a cto from the root * complex is sufficient to positively identify this case. */ prop error.io.pciex.ecrcreq-d@PCIEXFN (1)-> error.io.pciex.ecrcreq-fwd-d@PCIEXFN, error.io.pciex.ecrcreq-fwd-d@PCIEXFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }; prop error.io.pciex.ecrcreq-fwd-d@PCIEXFN { IS_SU(PCIEXFN) || IS_SD(PCIEXFN) } (1)-> error.io.pciex.flt-nr-u@PCIEXFN; prop error.io.pciex.ecrcreq-fwd-d@PCIEXFN { IS_SU(PCIEXFN) || IS_SD(PCIEXFN) } (0)-> ereport.io.pciex.tl.ecrc@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.ecrcreq-fwd-d@PCIEXFN { IS_BG(PCIEXFN) } (3)-> error.io.pciex.nonfatal@PCIEXFN, ereport.io.pciex.tl.ecrc@PCIEXFN, error.io.pciex.flt-nr-u@PCIEXFN; prop error.io.pciex.ecrcreq-fwd-d@PCIEXFN { IS_LF(PCIEXFN) } (2)-> error.io.pciex.nonfatal@PCIEXFN, error.io.pciex.flt-nr-u@PCIEXFN; prop error.io.pciex.ecrcreq-fwd-d@PCIEXFN { IS_LF(PCIEXFN) } (0)-> ereport.io.pciex.tl.ecrc@PCIEXFN; /* * downstream completion with ecrc error. * * - ecrccomp-d cascades down to the leaf device/bridge and any switches on * route can optionally raise an ecrc ereport. A hardened leaf driver may * also raise ecrc. For non-hardened leaf devices, no ecrc may be reported, * and though we should still see a nonfatal error reported from the root * complex identifying the leaf device, we won't actually be informed that * the error was an ecrc. * * Additionally, as the leaf/bridge will just throw away the packet, we should * eventually get a cto. Note the leaf ereports are optional (ie in case driver * not hardened) but if we get both ecrc and cto we need to distinguish from * cto only which would be an nr-d. */ prop error.io.pciex.ecrccomp-d@PCIEXFN (1)-> error.io.pciex.ecrccomp-fwd-d@PCIEXFN, error.io.pciex.ecrccomp-fwd-d@PCIEXFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }; prop error.io.pciex.ecrccomp-fwd-d@PCIEXFN { IS_SU(PCIEXFN) || IS_SD(PCIEXFN) } (0)-> error.io.pciex.nonfatal@PCIEXFN, ereport.io.pciex.tl.ecrc@PCIEXFN; prop error.io.pciex.ecrccomp-fwd-d@PCIEXFN { IS_BG(PCIEXFN) } (3)-> error.io.pciex.nonfatal@PCIEXFN, ereport.io.pciex.tl.ecrc@PCIEXFN, error.io.pciex.nr-d@PCIEXFN; prop error.io.pciex.ecrccomp-fwd-d@PCIEXFN { IS_LF(PCIEXFN) } (1)-> error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.ecrccomp-fwd-d@PCIEXFN { IS_LF(PCIEXFN) } (0)-> ereport.io.pciex.tl.ecrc@PCIEXFN, error.io.pciex.nr-d@PCIEXFN; /* * upstream poisoned request * * - flt-poisreq-u is on the pciex node which generated the fault * - source-poisreq-u refers to at least one leaf or bridge device * whose bdf (if leaf) must match the source-id in the payload of the * ereport generated from the root complex. * - poisreq-u propagates up to the root complex and any switch ports on * route will raise a ptlp ereport, while any upstream devices generating * or forwarding the poisoned packed will raise an mdpe ereport. The root * complex should also report a ptlp. * * Additionally, as the root complex may treat the request as a ur, which the * leaf/bridge will see (and if hardened report) as an ma (including sending a * ta onto the child pci bus if this was a delayed write). * * We can always recognize what sort of fault this is from the ptlp (with no * sec-mdpe) at the root complex. Recognizing which originating devices may be * implicated can be done using the mdpe ereport (for a hardened leaf driver), * or for a non-hardened leaf driver by using the source-id payload in the ptlp * ereport to identify the originator of the request. The ptlp/mdpe ereports * at the intervening switches will narrow the fault down to a single suspect. */ prop error.io.pciex.flt-poisreq-u@PCIEXFN1 { (IS_LF(PCIEXFN) || IS_BG(PCIEXFN)) && is_under(PCIEXFN1, PCIEXFN) } (0)-> error.io.pciex.source-poisreq-u@PCIEXFN; prop error.io.pciex.source-poisreq-u@PCIEXFN1 { IS_LF(PCIEXFN1) && SOURCE_ID_MATCHES_BDF && is_under(pciexrc, PCIEXFN1) } (0)-> ereport.io.pciex.tl.ptlp@pciexrc, ereport.io.pciex.tl.ur@pciexrc; prop error.io.pciex.source-poisreq-u@PCIEXFN { IS_LF(PCIEXFN) } (0)-> ereport.io.pci.ma@PCIEXFN; prop error.io.pciex.source-poisreq-u@PCIEXFN { IS_BG(PCIEXFN) && is_under(pciexrc, PCIEXFN) } (0)-> ereport.io.pciex.tl.ptlp@pciexrc, ereport.io.pciex.tl.ur@pciexrc; prop error.io.pciex.source-poisreq-u@PCIEXFN { IS_BG(PCIEXFN) } (0)-> ereport.io.pci.ma@PCIEXFN, ereport.io.pci.sec-sta@PCIEXFN, error.io.pci.ta-drw-d@PCIEXFN/PCIFN; prop error.io.pciex.flt-poisreq-u@PCIEXFN (1)-> error.io.pciex.poisreq-u@PCIEXFN; /* * the remaining propagations are also used for poisoned requests propagating * up due to a fault behind a pcie-pci bridge */ prop error.io.pciex.poisreq-u@PCIEXFN/PCIEXFN (1)-> error.io.pciex.poisreq-u@PCIEXFN; prop error.io.pciex.poisreq-u@PCIEXFN { IS_BG(PCIEXFN) } (1)-> ereport.io.pci.mdpe@PCIEXFN; prop error.io.pciex.poisreq-u@PCIEXFN { IS_LF(PCIEXFN) } (0)-> ereport.io.pci.mdpe@PCIEXFN; prop error.io.pciex.poisreq-u@PCIEXFN { IS_SD(PCIEXFN) } (2)-> ereport.io.pci.sec-dpe@PCIEXFN, ereport.io.pciex.tl.ptlp@PCIEXFN; prop error.io.pciex.poisreq-u@PCIEXFN { IS_SD(PCIEXFN) } (0)-> ereport.io.pci.mdpe@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.poisreq-u@PCIEXFN { IS_SU(PCIEXFN) } (1)-> ereport.io.pci.mdpe@PCIEXFN; prop error.io.pciex.poisreq-u@PCIEXFN { IS_SU(PCIEXFN) } (0)-> ereport.io.pci.sec-dpe@PCIEXFN, ereport.io.pciex.tl.ptlp@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.poisreq-u@pciexrc/PCIEXFN (1)-> ereport.io.pci.sec-dpe@pciexrc; /* * upstream poisoned completion * * - flt-poiscomp-u is on the pciex node which generated the fault. There will * be a target-mdpe downstream from here. * - source-poiscomp-u refers to at least one leaf or bridge device * whose bdf (if leaf) must match the source-id in the payload of the * ereport generated from the root complex. * - poiscomp-u propagates up to the root complex and any switches on * route will raise ptlp and sec-mdpe ereports. The root complex will also * raise a sec-mdpe and ptlp. * * We can always recognize what sort of fault this is from the ptlp/sec-mdpe at * the root complex. Recognizing which originating devices may be implicated * can be done using the source-id payload in the ptlp ereport to identify the * originator of the completion. The ptlp/sec-mdpe ereports at the intervening * switches will narrow the fault down to a single suspect. */ prop error.io.pciex.flt-poiscomp-u@PCIEXFN { IS_LF(PCIEXFN1) && is_under(PCIEXFN, PCIEXFN1) } (0)-> ereport.io.pci.target-mdpe@PCIEXFN1; prop error.io.pciex.flt-poiscomp-u@PCIEXFN { IS_PCI_LF(PCIFN) && is_under(PCIEXFN, PCIFN) } (0)-> ereport.io.pci.target-mdpe@PCIFN; prop error.io.pciex.flt-poiscomp-u@PCIEXFN1 { (IS_LF(PCIEXFN) || IS_BG(PCIEXFN)) && is_under(PCIEXFN1, PCIEXFN) } (0)-> error.io.pciex.source-poiscomp-u@PCIEXFN; prop error.io.pciex.source-poiscomp-u@PCIEXFN1 { IS_LF(PCIEXFN1) && SOURCE_ID_MATCHES_BDF && is_under(pciexrc, PCIEXFN1) } (0)-> ereport.io.pciex.tl.ptlp@pciexrc; prop error.io.pciex.source-poiscomp-u@PCIEXFN1 { IS_BG(PCIEXFN1) && is_under(pciexrc, PCIEXFN1) } (0)-> ereport.io.pciex.tl.ptlp@pciexrc; prop error.io.pciex.flt-poiscomp-u@PCIEXFN (1)-> error.io.pciex.poiscomp-u@PCIEXFN; /* * the remaining propagations are also used for poisoned completions propagating * up due to a fault behind a pcie-pci bridge */ prop error.io.pciex.poiscomp-u@PCIEXFN/PCIEXFN (1)-> error.io.pciex.poiscomp-u@PCIEXFN; prop error.io.pciex.poiscomp-u@PCIEXFN { IS_SD(PCIEXFN) } (2)-> ereport.io.pci.sec-dpe@PCIEXFN, ereport.io.pciex.tl.ptlp@PCIEXFN; prop error.io.pciex.poiscomp-u@PCIEXFN { IS_SD(PCIEXFN) } (1)-> ereport.io.pci.sec-mdpe@PCIEXFN, ereport.io.pci.mdpe@PCIEXFN; prop error.io.pciex.poiscomp-u@PCIEXFN { IS_SD(PCIEXFN) } (0)-> error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.poiscomp-u@PCIEXFN { IS_SU(PCIEXFN) } (0)-> ereport.io.pci.mdpe@PCIEXFN, ereport.io.pci.sec-mdpe@PCIEXFN, ereport.io.pci.sec-dpe@PCIEXFN, ereport.io.pciex.tl.ptlp@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.poiscomp-u@pciexrc/PCIEXFN (1)-> ereport.io.pci.sec-dpe@pciexrc; prop error.io.pciex.poiscomp-u@pciexrc/PCIEXFN (0)-> ereport.io.pci.sec-mdpe@pciexrc; /* * upstream request with ecrc error. * * - flt-ecrcreq-u is on the pciex node which generated the fault. * - source-ecrcreq-u cascades down to at least one leaf device (pciex or pci), * whose bdf (if pciex) must match the source-id in the payload of the * ereport generated from the root complex. * - ecrcreq-u propagates up to the root complex which must report it with an * ecrc ereport and any switches on route can optionally raise an ecrc ereport * * Additionally, as the root complex will just throw away the packet, we may * eventually get a cto - so use an nr-d at the pciex leaf or bridge to get * the appropriate behaviour. * * We can always recognize what sort of fault this is from the ecrc (with no * cto) at the root complex. Recognizing which leaf device may be implicated * can be done from the cto ereport (for a hardened leaf driver) or for a * non-hardened leaf using the source-id payload of the ecrc. */ prop error.io.pciex.flt-ecrcreq-u@PCIEXFN1 { (IS_LF(PCIEXFN) || IS_BG(PCIEXFN)) && is_under(PCIEXFN1, PCIEXFN) } (0)-> error.io.pciex.source-ecrcreq-u@PCIEXFN; prop error.io.pciex.source-ecrcreq-u@PCIEXFN (0)-> error.io.pciex.nr-d@PCIEXFN; prop error.io.pciex.source-ecrcreq-u@PCIEXFN1 { IS_LF(PCIEXFN1) && SOURCE_ID_MATCHES_BDF && is_under(pciexrc, PCIEXFN1) } (0)-> ereport.io.pciex.tl.ecrc@pciexrc; prop error.io.pciex.source-ecrcreq-u@PCIEXFN { IS_BG(PCIEXFN) && is_under(pciexrc, PCIEXFN) } (0)-> ereport.io.pciex.tl.ecrc@pciexrc; prop error.io.pciex.flt-ecrcreq-u@PCIEXFN (1)-> error.io.pciex.ecrcreq-u@PCIEXFN; prop error.io.pciex.ecrcreq-u@PCIEXFN/PCIEXFN (1)-> error.io.pciex.ecrcreq-u@PCIEXFN; prop error.io.pciex.ecrcreq-u@PCIEXFN { IS_SD(PCIEXFN)||IS_SU(PCIEXFN) } (0)-> ereport.io.pciex.tl.ecrc@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; /* * upstream completion with ecrc error. * * - flt-ecrccomp-u is on the pciex node which generated the fault. * - source-ecrccomp-u cascades down to at least one leaf device (pciex or pci), * whose bdf (if pciex) must match the source-id in the payload of the * ereport generated from the root complex. * - ecrccomp-u propagates up to the root complex, which should report it with * an ecrc ereport and any switches on route can optionally raise an ecrc * ereport. * * Additionally, as the root complex will just throw away the packet, we'll * eventually get a cto - so use an flt-nr-u at the pciex leaf or bridge to get * the appropriate behaviour. * * We can always recognize what sort of fault this from the ecrc/cto from the * root complex. Recognizing which leaf device may be implicated can be done * using either the source-id payload of the ecrc or the target-ma ereport if * available. */ prop error.io.pciex.flt-ecrccomp-u@PCIEXFN1 { (IS_LF(PCIEXFN) || IS_BG(PCIEXFN)) && is_under(PCIEXFN1, PCIEXFN) } (0)-> error.io.pciex.source-ecrccomp-u@PCIEXFN; prop error.io.pciex.source-ecrccomp-u@PCIEXFN (0)-> error.io.pciex.flt-nr-u@PCIEXFN; prop error.io.pciex.source-ecrccomp-u@PCIEXFN1 { IS_LF(PCIEXFN1) && SOURCE_ID_MATCHES_BDF && is_under(pciexrc, PCIEXFN1) } (0)-> ereport.io.pciex.tl.ecrc@pciexrc; prop error.io.pciex.source-ecrccomp-u@PCIEXFN { IS_BG(PCIEXFN) && is_under(pciexrc, PCIEXFN) } (0)-> ereport.io.pciex.tl.ecrc@pciexrc; prop error.io.pciex.flt-ecrccomp-u@PCIEXFN (1)-> error.io.pciex.ecrccomp-u@PCIEXFN; prop error.io.pciex.ecrccomp-u@PCIEXFN/PCIEXFN (1)-> error.io.pciex.ecrccomp-u@PCIEXFN; prop error.io.pciex.ecrccomp-u@PCIEXFN { IS_SD(PCIEXFN)||IS_SU(PCIEXFN) } (0)-> ereport.io.pciex.tl.ecrc@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; /* * no response to downstream requester * * - nr-d will effectively cascade downstream to the requester. The fault here * is always at the root complex. For a hardened leaf device driver, we will * always be able to recognize this as the requester will report this as a * cto. For non-hardened leaf devices, no cto will be reported, and though we * should still see a nonfatal error reported from the root complex * identifying the leaf device, we won't actually be informed that the error * was a cto. */ prop error.io.pciex.nr-d@PCIEXFN (1)-> error.io.pciex.nr-fwd-d@PCIEXFN { IS_BG(PCIEXFN) || IS_LF(PCIEXFN) }, error.io.pciex.nr-fwd-d@PCIEXFNHZ { (IS_BG(PCIEXFNHZ) || IS_LF(PCIEXFNHZ)) && is_under(PCIEXFN, PCIEXFNHZ) }; prop error.io.pciex.nr-fwd-d@PCIEXFN { IS_BG(PCIEXFN) } (2)-> error.io.pciex.nonfatal@PCIEXFN, ereport.io.pciex.tl.cto@PCIEXFN; prop error.io.pciex.nr-fwd-d@PCIEXFN { IS_BG(PCIEXFN) } (0)-> ereport.io.pci.ma@PCIEXFN, ereport.io.pci.sec-sta@PCIEXFN, error.io.pci.nr-drw-d@PCIEXFN/PCIFN, error.io.pci.ta-drw-d@PCIEXFN/PCIFN; prop error.io.pciex.nr-fwd-d@PCIEXFN { IS_LF(PCIEXFN) } (1)-> error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.nr-fwd-d@PCIEXFN { IS_LF(PCIEXFN) } (0)-> ereport.io.pci.ma@PCIEXFN, ereport.io.pciex.tl.cto@PCIEXFN; /* * no response to upstream requester * * - flt-nr-u will effectively cascade upstream to the root complex which will * report it as a cto. * * We have to use target-ma to informs us which device failed to respond. */ prop error.io.pciex.flt-nr-u@PCIEXFN (1)-> error.io.pci.target-ma-d@PCIEXFN; prop error.io.pciex.flt-nr-u@PCIEXFN (1)-> error.io.pciex.nr-u@PCIEXFN; prop error.io.pciex.nr-u@PCIEXFN/PCIEXFN (1)-> error.io.pciex.nr-u@PCIEXFN; prop error.io.pciex.nr-u@pciexrc/PCIEXFN (1)-> ereport.io.pciex.tl.cto@pciexrc; prop error.io.pciex.nr-u@pciexrc/PCIEXFN (0)-> ereport.io.pci.sec-ma@pciexrc; /* * downstream malformed tlp * * This will cascade downstream to the receiver which will report it as an mtlp. * For non-hardened leaf drivers, no mtlp will be reported, and though we should * still see a fatal error reported from the root complex identifying the leaf * device, we won't actually be informed that the error was a mtlp. * Note that sw-mtlp-d is to handle the case where the switch is actually * the target of the packet (config request etc). */ prop error.io.pciex.mtlp-d@PCIEXFN (1)-> error.io.pciex.mtlp-fwd-d@PCIEXFN { !IS_SD(PCIEXFN) }, error.io.pciex.mtlp-fwd-d@PCIEXFNHZ { !IS_SD(PCIEXFNHZ) && is_under(PCIEXFN, PCIEXFNHZ) }; prop error.io.pciex.mtlp-fwd-d@PCIEXFN { IS_SU(PCIEXFN) } (2)-> error.io.pciex.fatal@PCIEXFN, ereport.io.pciex.tl.mtlp@PCIEXFN; prop error.io.pciex.mtlp-fwd-d@PCIEXFN { IS_BG(PCIEXFN) } (2)-> error.io.pciex.fatal@PCIEXFN, ereport.io.pciex.tl.mtlp@PCIEXFN; prop error.io.pciex.mtlp-fwd-d@PCIEXFN { IS_LF(PCIEXFN) } (1)-> error.io.pciex.fatal@PCIEXFN; prop error.io.pciex.mtlp-fwd-d@PCIEXFN { IS_LF(PCIEXFN) } (0)-> ereport.io.pciex.tl.mtlp@PCIEXFN; /* * upstream malformed tlp * * This will cascade upstream to the receiver which will report it as an mtlp. */ prop error.io.pciex.flt-mtlp-u@PCIEXFN (1)-> error.io.pciex.mtlp-u@PCIEXFN; prop error.io.pciex.mtlp-u@PCIEXFN/PCIEXFN (1)-> error.io.pciex.mtlp-u@PCIEXFN; prop error.io.pciex.mtlp-u@pciexrc/PCIEXFN (1)-> ereport.io.pciex.tl.mtlp@pciexrc; /* * downstream completer aborts * * This could be the fault of the root complex or a switch reporting an internal * error, or of the leaf device sending an invalid request (the latter is * handled by the flt-badreq-u case below). * * This is reported by the completer or by an intervening downstream switch * port. The completer abort response propagates down to the initiator which * will set the legacy pci bit rta. * * The fault can always be recognized by the ca ereport from the root complex * or downstream switch port. The originator of the request can be recognized * by the rta for a hardened driver or by using the source-id payload of the * ca ereport for a non-hardened driver. */ prop error.io.pciex.ca-d@pciexrc/PCIEXFN (0)-> ereport.io.pciex.tl.ca@pciexrc; prop error.io.pciex.ca-d@pciexrc/PCIEXFN (1)-> ereport.io.pci.sec-sta@pciexrc; prop error.io.pciex.ca-d@PCIEXFN/PCIEXFN (0)-> ereport.io.pci.sec-sta@PCIEXFN; prop error.io.pciex.ca-d@PCIEXFN/PCIEXFN (2)-> ereport.io.pciex.tl.ca@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.ca-d@PCIEXFN (1)-> error.io.pciex.ca-fwd-d@PCIEXFN { IS_BG(PCIEXFN) || IS_LF(PCIEXFN) }, error.io.pciex.ca-fwd-d@PCIEXFNHZ { (IS_BG(PCIEXFNHZ) || IS_LF(PCIEXFNHZ)) && is_under(PCIEXFN, PCIEXFNHZ) }; prop error.io.pciex.ca-fwd-d@PCIEXFN { IS_BG(PCIEXFN) } (1)-> ereport.io.pci.rta@PCIEXFN; prop error.io.pciex.ca-fwd-d@PCIEXFN { IS_BG(PCIEXFN) } (0)-> ereport.io.pci.sec-sta@PCIEXFN, error.io.pci.ta-drw-d@PCIEXFN/PCIFN; prop error.io.pciex.ca-fwd-d@PCIEXFN { IS_LF(PCIEXFN) } (0)-> ereport.io.pci.rta@PCIEXFN; /* * upstream completer aborts * * This could be the fault of the leaf device/bridge/upstream switch port * reporting an internal error, or of the root complex sending an invalid * request (the latter case is handled by badreq-d below). * * This is reported as a ca by the completer. The completer (for non-posted * requests) sends the appropriate error bits in the completion message to * the initiator which will set the legacy pci bit sec-rta. * * The fault can always be recognized from the sec-rta bit at the root complex. * * If the fault was with a PCI Express leaf with a hardened driver, then we * will identify the device from the ca ereport. * * If the fault was with a PCI Express leaf with a non-hardened driver, then we * can still identify the leaf device from the source-id payload of the nonfatal * message ereport from the root complex or from the target-rta ereport. */ prop error.io.pciex.flt-ca-u@PCIEXFN { !IS_LF(PCIEXFN) } (1)-> ereport.io.pciex.tl.ca@PCIEXFN; prop error.io.pciex.flt-ca-u@PCIEXFN { IS_LF(PCIEXFN) } (0)-> ereport.io.pciex.tl.ca@PCIEXFN; prop error.io.pciex.flt-ca-u@PCIEXFN (0)-> error.io.pciex.nonfatal@PCIEXFN, ereport.io.pci.sta@PCIEXFN; prop error.io.pciex.flt-ca-u@PCIEXFN (2)-> error.io.pci.target-rta-d@PCIEXFN, error.io.pciex.ca-u@PCIEXFN; prop error.io.pciex.ca-u@PCIEXFN/PCIEXFN (1)-> error.io.pciex.ca-u@PCIEXFN; prop error.io.pciex.ca-u@pciexrc/PCIEXFN (0)-> ereport.io.pci.sec-rta@pciexrc; /* * upstream bad request * * When detecting bad data on a request the completer (or any switch on the * way to the completer) may report ur or ca. If the switch detects the problem * first then the request doesn't get forwarded on to the completer. * * These are reported as ur/ca ereports. For non-posted requests, the reporter * then sends the appropriate error bits in the completion message to the * initiator which will set the legacy pci bits ma or rta. * * For flt-badreq-u, the ca/ur ereports contain a source-id payload that * identifies the initiator. * * The fault can always be recognized by the ca/ur ereport from the root * complex or downstream switch port. The originator of the request can be * recognized by the rta/ma for a hardened driver or by using the source-id * payload of the ca/ur ereport for a non-hardened driver. */ prop error.io.pciex.flt-badreq-u@PCIEXFN (0)-> ereport.io.pci.ma@PCIEXFN, ereport.io.pci.rta@PCIEXFN; prop error.io.pciex.flt-badreq-u@PCIEXFN1 { SOURCE_ID_MATCHES_BDF && is_under(pciexrc, PCIEXFN1) } (0)-> ereport.io.pciex.tl.ur@pciexrc, ereport.io.pciex.tl.ca@pciexrc; prop error.io.pciex.flt-badreq-u@PCIEXFN (1)-> error.io.pciex.badreq-u@PCIEXFN; prop error.io.pciex.badreq-u@PCIEXFN/PCIEXFN (1)-> error.io.pciex.badreq-u@PCIEXFN; prop error.io.pciex.badreq-u@pciexrc/PCIEXFN (0)-> ereport.io.pci.sec-sta@pciexrc; prop error.io.pciex.flt-badreq-u@PCIEXFN1 { IS_SD(PCIEXFN) && SOURCE_ID_MATCHES_BDF && is_under(PCIEXFN, PCIEXFN1) } (0)-> ereport.io.pciex.tl.ur@PCIEXFN, ereport.io.pciex.tl.ca@PCIEXFN; prop error.io.pciex.flt-badreq-u@PCIEXFN1 { IS_SD(PCIEXFN) && is_under(PCIEXFN, PCIEXFN1) } (0)-> ereport.io.pci.sec-sta@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; /* * downstream bad request * * When detecting bad data on a request the completer (or any switch on the * way to the completer) may report ur or ca. If the switch detects the problem * first then the request doesn't get forwarded on to the completer. * * These are reported as ur/ca ereports (except where the completer is a non- * hardened leaf driver when all we get is a nonfatal error from the root * complex identifying the leaf device). The reporter then sends the appropriate * error bits in the completion message to the initiator which will set the * legacy pci bits ma or rta (oddly there is no equivalent in pcie error * reporting). */ prop error.io.pciex.badreq-d@PCIEXFN (1)-> error.io.pciex.flt-ur-u@PCIEXFN, error.io.pciex.flt-ca-u@PCIEXFN, error.io.pciex.flt-ur-u@PCIEXFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }, error.io.pciex.flt-ca-u@PCIEXFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }, error.io.pci.badreq-pw-d@PCIEXFNHZ/PCIFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }, error.io.pci.badreq-drw-d@PCIEXFNHZ/PCIFNHZ { is_under(PCIEXFN,PCIEXFNHZ) }; prop error.io.pciex.flt-ur-u@PCIEXFN { !IS_LF(PCIEXFN) } (1)-> ereport.io.pciex.tl.ur@PCIEXFN; prop error.io.pciex.flt-ur-u@PCIEXFN { IS_LF(PCIEXFN) } (0)-> ereport.io.pciex.tl.ur@PCIEXFN; prop error.io.pciex.flt-ur-u@PCIEXFN (2)-> error.io.pci.target-ma-d@PCIEXFN, error.io.pciex.ur-u@PCIEXFN; prop error.io.pciex.flt-ur-u@PCIEXFN (0)-> error.io.pciex.nonfatal@PCIEXFN; prop error.io.pciex.ur-u@PCIEXFN/PCIEXFN (1)-> error.io.pciex.ur-u@PCIEXFN; prop error.io.pciex.ur-u@pciexrc/PCIEXFN (0)-> ereport.io.pci.sec-ma@pciexrc; /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * Stub unused legacy pci ereports at root complex. * Stub tl.uc as we can't do anything useful with it (we should eventually * get a cto which we can do something with - a uc without a cto is a genuinely * spurious completion which is at least harmless). * Stub messages that the root complex sends to itself. * Stub mce/mue/ce/nr/noadverr. * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ event error.io.pciex.discard_rc@pciexrc; event ereport.io.pciex.noadverr@PCIEXFN{within(5s)}; event ereport.io.pciex.correctable@PCIEXFN{within(5s)}; event ereport.io.pciex.nonfatal@PCIEXFN{within(5s)}; event ereport.io.pciex.a-nonfatal@PCIEXFN{within(5s)}; event ereport.io.pciex.fatal@PCIEXFN{within(5s)}; event ereport.io.pci.nr@PCIEXFN{within(5s)}; event ereport.io.pci.nr@pciexrc{within(5s)}; event ereport.io.pci.ma@pciexrc{within(5s)}; event ereport.io.pci.rta@pciexrc{within(5s)}; event ereport.io.pci.sta@pciexrc{within(5s)}; event ereport.io.pci.dpe@pciexrc{within(5s)}; event ereport.io.pci.mdpe@pciexrc{within(5s)}; event ereport.io.pci.sserr@pciexrc{within(5s)}; event ereport.io.pciex.tl.uc@pciexrc{within(5s)}; event ereport.io.pciex.noadverr@pciexrc{within(5s)}; event ereport.io.pciex.a-nonfatal@pciexrc{within(5s)}; event ereport.io.pciex.rc.ce-msg@pciexrc{within(5s)}; event ereport.io.pciex.rc.mce-msg@pciexrc{within(5s)}; event upset.io.pciex.discard_uc@PCIEXFN; event upset.io.pciex.discard@PCIEXFN; event upset.io.pciex.discard@pciexrc; prop upset.io.pciex.discard_uc@PCIEXFN { IS_BG(PCIEXFN) } (1)-> ereport.io.pciex.tl.uc@PCIEXFN; prop upset.io.pciex.discard_uc@PCIEXFN { IS_LF(PCIEXFN) } (1)-> ereport.io.pciex.tl.uc@PCIEXFN; prop upset.io.pciex.discard@PCIEXFN (1)-> ereport.io.pci.nr@PCIEXFN, ereport.io.pciex.noadverr@PCIEXFN, ereport.io.pciex.correctable@PCIEXFN, ereport.io.pciex.nonfatal@PCIEXFN, ereport.io.pciex.a-nonfatal@PCIEXFN, ereport.io.pciex.fatal@PCIEXFN; prop error.io.pciex.discard_rc@pciexrc (0)-> ereport.io.pciex.rc.mue-msg@pciexrc, ereport.io.pciex.rc.fe-msg@pciexrc { SOURCE_ID_MATCHES_OWN_BDF }, ereport.io.pciex.rc.nfe-msg@pciexrc { SOURCE_ID_MATCHES_OWN_BDF }; prop upset.io.pciex.discard@pciexrc (1)-> error.io.pciex.discard_rc@pciexrc, ereport.io.pci.nr@pciexrc, ereport.io.pciex.noadverr@pciexrc, ereport.io.pciex.a-nonfatal@pciexrc, ereport.io.pciex.rc.ce-msg@pciexrc, ereport.io.pciex.rc.mce-msg@pciexrc, ereport.io.pciex.tl.uc@pciexrc, ereport.io.pci.ma@pciexrc, ereport.io.pci.rta@pciexrc, ereport.io.pci.sta@pciexrc, ereport.io.pci.dpe@pciexrc, ereport.io.pci.mdpe@pciexrc, ereport.io.pci.sserr@pciexrc; /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * rules for propagations from child PCI bus * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ event error.io.pci.retry-to-u@PCIEXFN/PCIFN; event error.io.pci.ma-u@PCIEXFN/PCIFN; event error.io.pci.ta-u@PCIEXFN/PCIFN; event error.io.pci.ape-u@PCIEXFN/PCIFN; event error.io.pci.source-ape-u@PCIFN; event error.io.pci.target-ma-d@PCIFN; event error.io.pci.target-rta-d@PCIFN; event error.io.pci.badreq-pw-u@PCIEXFN/PCIFN; event error.io.pci.badreq-drw-u@PCIEXFN/PCIFN; event error.io.pci.source-perr-u@PCIFN; event error.io.pci.source-dpdata-u@PCIFN; event error.io.pci.dpdata-pw-u@PCIEXFN/PCIFN; event error.io.pci.dpdata-dw-u@PCIEXFN/PCIFN; event error.io.pci.dpdata-dr-u@PCIEXFN/PCIFN; event error.io.pci.perr-pw-u@PCIEXFN/PCIFN; event error.io.pci.perr-dw-u@PCIEXFN/PCIFN; event error.io.pci.perr-dr-u@PCIEXFN/PCIFN; event error.io.pci.serr-u@PCIEXFN/PCIFN; event error.io.pcix.scpe-u@PCIEXFN/PCIFN; event error.io.pcix.source-scpe-u@PCIFN; event error.io.pcix.spl-comp-ma-u@PCIEXFN/PCIFN; event error.io.pcix.spl-comp-ta-u@PCIEXFN/PCIFN; event error.io.pcix.spl-comp-ma-d@PCIEXFN/PCIFN; event error.io.pcix.spl-comp-ta-d@PCIEXFN/PCIFN; event error.io.pcix.uscmd@PCIEXFN; event ereport.io.pcix.sec-spl-dis@PCIEXFN{within(5s)}; event ereport.io.pciex.bdg.uscmd@PCIEXFN{within(5s)}; event ereport.io.pciex.bdg.sec-perr@PCIEXFN{within(5s)}; event ereport.io.pciex.bdg.sec-uadr@PCIEXFN{within(5s)}; event ereport.io.pciex.bdg.sec-uat@PCIEXFN{within(5s)}; event ereport.io.pciex.bdg.sec-serr@PCIEXFN{within(5s)}; event ereport.io.pciex.bdg.sec-tex@PCIEXFN{within(5s)}; event ereport.io.pciex.bdg.sec-rma@PCIEXFN{within(5s)}; event ereport.io.pciex.bdg.sec-rta@PCIEXFN{within(5s)}; event ereport.io.pciex.bdg.sec-ma-sc@PCIEXFN{within(5s)}; event ereport.io.pciex.bdg.sec-ta-sc@PCIEXFN{within(5s)}; event ereport.io.pci.dto@PCIEXFN{within(5s)}; event ereport.io.pci.sec-rta@PCIEXFN{within(5s)}; event ereport.io.pci.sec-ma@PCIEXFN{within(5s)}; /* * ma-u will only propagate on to pciex bus for non-posted accesses. It * is then represented as an unsupported request. */ prop error.io.pci.ma-u@PCIEXFN/PCIFN (0)-> ereport.io.pciex.tl.ur@PCIEXFN, error.io.pciex.ur-u@PCIEXFN; prop error.io.pci.ma-u@PCIEXFN/PCIFN (2)-> ereport.io.pci.sec-ma@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; prop error.io.pci.target-ma-d@PCIFN1 { IS_BG(PCIEXFN) && IS_PCI_LF(PCIFN1) && SOURCE_ID_MATCHES_BDF && is_under(PCIEXFN, PCIFN1) } (0)-> ereport.io.pciex.bdg.sec-rma@PCIEXFN; /* * ta-u will only propagate on to pciex bus for non-posted accesses. It is * then represented as a completer abort. */ prop error.io.pci.ta-u@PCIEXFN/PCIFN (0)-> ereport.io.pci.sta@PCIEXFN, ereport.io.pciex.tl.ca@PCIEXFN, error.io.pciex.ca-u@PCIEXFN; prop error.io.pci.ta-u@PCIEXFN/PCIFN (2)-> ereport.io.pci.sec-rta@PCIEXFN, error.io.pciex.nonfatal@PCIEXFN; prop error.io.pci.target-rta-d@PCIFN1 { IS_BG(PCIEXFN) && IS_PCI_LF(PCIFN1) && SOURCE_ID_MATCHES_BDF && is_under(PCIEXFN, PCIFN1) } (0)-> ereport.io.pciex.bdg.sec-rta@PCIEXFN; /* * PERR# on a delayed write is represented as an unsupported request */ prop error.io.pci.perr-dw-u@PCIEXFN/PCIFN (1)-> ereport.io.pci.sec-mdpe@PCIEXFN; prop error.io.pci.perr-dw-u@PCIEXFN/PCIFN (0)-> error.io.pciex.flt-ur-u@PCIEXFN; prop error.io.pci.perr-pw-u@PCIEXFN/PCIFN (1)-> ereport.io.pci.sec-mdpe@PCIEXFN; prop error.io.pci.perr-pw-u@PCIEXFN/PCIFN (0)-> error.io.pciex.nonfatal@PCIEXFN; prop error.io.pci.perr-dr-u@PCIEXFN/PCIFN (1)-> error.io.pciex.nonfatal@PCIEXFN; prop error.io.pci.source-perr-u@PCIFN1 { IS_BG(PCIEXFN) && IS_PCI_LF(PCIFN1) && SOURCE_ID_MATCHES_BDF && is_under(PCIEXFN, PCIFN1) } (0)-> ereport.io.pciex.bdg.sec-perr@PCIEXFN; /* * If the bridge receives data with bad ecc/parity from pci/pci-x, it will * propagate onto pci express as a poisoned tlp */ prop error.io.pci.dpdata-dr-u@PCIEXFN/PCIFN (2)-> ereport.io.pci.sec-dpe@PCIEXFN, error.io.pciex.poiscomp-u@PCIEXFN; prop error.io.pci.dpdata-dr-u@PCIEXFN/PCIFN (0)-> error.io.pciex.nonfatal@PCIEXFN; prop error.io.pci.dpdata-dr-u@PCIEXFN/PCIFN (1)-> ereport.io.pci.sec-mdpe@PCIEXFN, ereport.io.pci.mdpe@PCIEXFN; prop error.io.pci.dpdata-dw-u@PCIEXFN/PCIFN (1)-> ereport.io.pci.sec-dpe@PCIEXFN; prop error.io.pci.dpdata-dw-u@PCIEXFN/PCIFN (0)-> error.io.pciex.nonfatal@PCIEXFN, error.io.pciex.poisreq-u@PCIEXFN, ereport.io.pci.ma@PCIEXFN, ereport.io.pci.sec-sta@PCIEXFN, error.io.pci.ta-drw-d@PCIEXFN/PCIFN; prop error.io.pci.dpdata-pw-u@PCIEXFN/PCIFN (2)-> ereport.io.pci.sec-dpe@PCIEXFN, error.io.pciex.poisreq-u@PCIEXFN; prop error.io.pci.dpdata-pw-u@PCIEXFN/PCIFN (0)-> error.io.pciex.nonfatal@PCIEXFN, ereport.io.pci.ma@PCIEXFN; prop error.io.pci.source-dpdata-u@PCIFN { is_under(pciexrc, PCIFN) } (0)-> ereport.io.pciex.tl.ptlp@pciexrc, ereport.io.pciex.tl.ur@pciexrc; prop error.io.pci.source-dpdata-u@PCIFN1 { IS_BG(PCIEXFN) && IS_PCI_LF(PCIFN1) && SOURCE_ID_MATCHES_BDF && is_under(PCIEXFN, PCIFN1) } (0)-> ereport.io.pciex.bdg.sec-ude@PCIEXFN; /* * If the bridge sees an address or attribute parity error it is considered * a fatal error. */ prop error.io.pci.ape-u@PCIEXFN/PCIFN (2)-> ereport.io.pci.sec-dpe@PCIEXFN, error.io.pciex.fatal@PCIEXFN; prop error.io.pci.source-ape-u@PCIFN1 { IS_BG(PCIEXFN) && IS_PCI_LF(PCIFN1) && SOURCE_ID_MATCHES_BDF && is_under(PCIEXFN, PCIFN1) } (0)-> ereport.io.pciex.bdg.sec-uat@PCIEXFN, ereport.io.pciex.bdg.sec-uadr@PCIEXFN; prop error.io.pci.ape-u@PCIEXFN/PCIFN (0)-> ereport.io.pci.sec-rserr@PCIEXFN, ereport.io.pciex.bdg.sec-serr@PCIEXFN, ereport.io.pci.sec-sta@PCIEXFN; /* * If the bridge sees a split completion error (pci-x only) it could * result in a number of things * - unrecovered split completion message data error (uscmd). This would * happen on a pio write. A completer abort is returned to the initiator. * - for various faults in the split completion (eg address parity error) * we will respond with a target abort (which the child device will treat * as a split completion ta) * - for other faults we can't tell who send the split completion and so * just drop the request (which the child device sees as a split * completion ma) */ prop error.io.pcix.scpe-u@PCIEXFN/PCIFN (0)-> ereport.io.pci.sec-dpe@PCIEXFN, ereport.io.pci.sec-rserr@PCIEXFN, ereport.io.pciex.bdg.sec-serr@PCIEXFN, ereport.io.pci.sec-sta@PCIEXFN, error.io.pciex.fatal@PCIEXFN; prop error.io.pcix.source-scpe-u@PCIFN1 { IS_BG(PCIEXFN) && IS_PCI_LF(PCIFN1) && SOURCE_ID_MATCHES_BDF && is_under(PCIEXFN, PCIFN1) } (0)-> ereport.io.pciex.bdg.sec-uat@PCIEXFN, ereport.io.pciex.bdg.sec-uadr@PCIEXFN; prop error.io.pcix.scpe-u@PCIEXFN/PCIFN (1)-> error.io.pcix.uscmd@PCIEXFN, error.io.pcix.spl-comp-ma-d@PCIEXFN/PCIFN, error.io.pcix.spl-comp-ta-d@PCIEXFN/PCIFN; prop error.io.pcix.uscmd@PCIEXFN (4)-> error.io.pciex.fatal@PCIEXFN, ereport.io.pci.sta@PCIEXFN, ereport.io.pciex.tl.ca@PCIEXFN, ereport.io.pciex.bdg.uscmd@PCIEXFN; prop error.io.pcix.uscmd@PCIEXFN (0)-> error.io.pciex.ca-u@PCIEXFN; /* * Similarly a child device may have responded with a master abort or * target abort to one of our split competions. The hardware just logs these. */ prop error.io.pcix.spl-comp-ma-u@PCIEXFN/PCIFN (3)-> error.io.pciex.nonfatal@PCIEXFN, ereport.io.pcix.sec-spl-dis@PCIEXFN, ereport.io.pciex.bdg.sec-ma-sc@PCIEXFN; prop error.io.pcix.spl-comp-ma-u@PCIEXFN/PCIFN (0)-> ereport.io.pci.sec-ma@PCIEXFN; prop error.io.pcix.spl-comp-ta-u@PCIEXFN/PCIFN (4)-> error.io.pciex.nonfatal@PCIEXFN, ereport.io.pcix.sec-spl-dis@PCIEXFN, ereport.io.pciex.bdg.sec-ta-sc@PCIEXFN, ereport.io.pci.sec-rta@PCIEXFN; /* * SERR# is considered fatal */ prop error.io.pci.serr-u@PCIEXFN/PCIFN (3)-> error.io.pciex.fatal@PCIEXFN, ereport.io.pci.sec-rserr@PCIEXFN, ereport.io.pciex.bdg.sec-serr@PCIEXFN; /* * Retry time-out is nonfatal. The initial requester has stopped retrying so * there's nothing else the hardware can do but flag the error. */ prop error.io.pci.retry-to-u@PCIEXFN/PCIFN (2)-> error.io.pciex.nonfatal@PCIEXFN, ereport.io.pciex.bdg.sec-tex@PCIEXFN; prop error.io.pci.retry-to-u@PCIEXFN/PCIFN (0)-> ereport.io.pci.sta@PCIEXFN, ereport.io.pci.dto@PCIEXFN, error.io.pciex.ca-u@PCIEXFN; /* * A bad dma request (eg with invalid address) propagates onto pci express * as a bad dma request. The end result may be a master abort or target abort * (depending on whether the child is pci-x or pci). */ prop error.io.pci.badreq-pw-u@PCIEXFN/PCIFN (0)-> ereport.io.pci.ma@PCIEXFN, ereport.io.pci.rta@PCIEXFN, error.io.pciex.badreq-u@PCIEXFN, ereport.io.pci.sec-sta@PCIEXFN; prop error.io.pci.badreq-pw-u@PCIEXFN/PCIFN { is_under(pciexrc, PCIEXFN/PCIFN) } (0)-> ereport.io.pciex.tl.ur@pciexrc, ereport.io.pciex.tl.ca@pciexrc; prop error.io.pci.badreq-pw-u@PCIEXFN/PCIFN { IS_SD(PCIEXFN1) && is_under(PCIEXFN1, PCIEXFN/PCIFN) } (0)-> ereport.io.pciex.tl.ur@PCIEXFN1, ereport.io.pciex.tl.ca@PCIEXFN1, ereport.io.pci.sec-sta@PCIEXFN1, error.io.pciex.nonfatal@PCIEXFN1; prop error.io.pci.badreq-drw-u@PCIEXFN/PCIFN (0)-> ereport.io.pci.ma@PCIEXFN, ereport.io.pci.rta@PCIEXFN, error.io.pciex.badreq-u@PCIEXFN, ereport.io.pci.sec-sta@PCIEXFN; prop error.io.pci.badreq-drw-u@PCIEXFN/PCIFN { is_under(pciexrc, PCIEXFN/PCIFN) } (0)-> ereport.io.pciex.tl.ur@pciexrc, ereport.io.pciex.tl.ca@pciexrc; prop error.io.pci.badreq-drw-u@PCIEXFN/PCIFN { IS_SD(PCIEXFN1) && is_under(PCIEXFN1, PCIEXFN/PCIFN) } (0)-> ereport.io.pciex.tl.ur@PCIEXFN1, ereport.io.pciex.tl.ca@PCIEXFN1, ereport.io.pci.sec-sta@PCIEXFN1, error.io.pciex.nonfatal@PCIEXFN1; /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * target- propagations * * A Root Complex driver may generate "target-" ereports when knowledge of the * physical address associated with a fault allows the target device to be * determined. This is not a requirement of the Diagnosis Engine, but can be * valuable when available. * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ event error.io.pci.target-ma-d@PCIEXFN/PCIFN; event error.io.pci.target-rta-d@PCIEXFN/PCIFN; event ereport.io.pci.target-rta@PCIEXFN{within(5s)}; event ereport.io.pci.target-ma@PCIEXFN{within(5s)}; prop error.io.pci.target-ma-d@PCIEXFN (0)-> ereport.io.pci.target-ma@PCIEXFN, ereport.io.pci.target-ma@PCIEXFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }, error.io.pci.target-ma-d@PCIEXFNHZ/PCIFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }; prop error.io.pci.target-rta-d@PCIEXFN (0)-> ereport.io.pci.target-rta@PCIEXFN, ereport.io.pci.target-rta@PCIEXFNHZ { is_under(PCIEXFN, PCIEXFNHZ) }, error.io.pci.target-rta-d@PCIEXFNHZ/PCIFNHZ { is_under(PCIEXFN,PCIEXFNHZ) }; /* * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ * stub unused pciex-pci bridge ereports * - ignore usc/sec-unex-spl * - ignore sec-spl-or/sec-spl-dly as these aren't really faults (tuning info) * - ignore ecc.ue ereports (we get everything we need from dpe/mdpe) * - ignore ecc.ce ereports for now (could do serd on these) * +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ */ event ereport.io.pciex.bdg.usc@PCIEXFN{within(5s)}; event ereport.io.pcix.sec-unex-spl@PCIEXFN{within(5s)}; event ereport.io.pcix.sec-spl-or@PCIEXFN{within(5s)}; event ereport.io.pcix.sec-spl-dly@PCIEXFN{within(5s)}; event ereport.io.pcix.sec-ecc.ce-addr@PCIEXFN{within(5s)}; event ereport.io.pcix.sec-ecc.ce-attr@PCIEXFN{within(5s)}; event ereport.io.pcix.sec-ecc.ce-data@PCIEXFN{within(5s)}; event ereport.io.pcix.sec-ecc.ue-addr@PCIEXFN{within(5s)}; event ereport.io.pcix.sec-ecc.ue-attr@PCIEXFN{within(5s)}; event ereport.io.pcix.sec-ecc.ue-data@PCIEXFN{within(5s)}; event ereport.io.pcix.sec-s-ce@PCIEXFN{within(5s)}; event ereport.io.pcix.sec-s-ue@PCIEXFN{within(5s)}; event upset.io.pciex.discard-bdg@PCIEXFN; prop upset.io.pciex.discard-bdg@PCIEXFN (1)-> ereport.io.pciex.bdg.usc@PCIEXFN, ereport.io.pcix.sec-unex-spl@PCIEXFN, ereport.io.pcix.sec-spl-or@PCIEXFN, ereport.io.pcix.sec-spl-dly@PCIEXFN, ereport.io.pcix.sec-ecc.ce-addr@PCIEXFN, ereport.io.pcix.sec-ecc.ce-attr@PCIEXFN, ereport.io.pcix.sec-ecc.ce-data@PCIEXFN, ereport.io.pcix.sec-ecc.ue-addr@PCIEXFN, ereport.io.pcix.sec-ecc.ue-attr@PCIEXFN, ereport.io.pcix.sec-ecc.ue-data@PCIEXFN, ereport.io.pcix.sec-s-ce@PCIEXFN, ereport.io.pcix.sec-s-ue@PCIEXFN; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ #pragma dictionary "PCIEX" #include /* * generic root complex/root port diagnosis rules */ #define PCIEXFN pciexbus/pciexdev/pciexfn #define PCIEXFNHZ pciexbus<>/pciexdev<>/pciexfn<> #define RC_N 5 #define RC_T 72h #define SW_FIT 5000 #define FW_FIT 5000 #define HB_FIT 400 #define EPKT_DESC (payloadprop("desc") >> 12) #define EPKT_B_BIT (payloadprop("desc") & (1 << 7)) #define EPKT_C_BIT (payloadprop("desc") & (1 << 5)) #define EPKT_H_BIT (payloadprop("desc") & (1 << 4)) #define MATCHES_DESC(b, o, p, c, d) \ (EPKT_DESC == (b << 16 | o << 12 | p << 8 | c << 4 | d)) #define IS_CE (EPKT_C_BIT != 0 && setserdsuffix(EPKT_DESC)) #define IS_UE (EPKT_C_BIT == 0) /* * BLOCK bit set means the error may cause a pipe stall and thus a CTO * in the fabric */ #define IS_BLOCKED (EPKT_B_BIT != 0) #define EPKT(b, o, p, c, d) \ ereport.io.pciex.rc.epkt@hostbridge { MATCHES_DESC(b, o, p, c, d) } /* Errors that will be diagnosed by the fabric DE (pciex.esc) */ #define DIAG_BY_FAB \ (MATCHES_DESC(BLOCK_INTR,OP_MSI32,PH_DATA,CND_ILL,DIR_IRR) || \ MATCHES_DESC(BLOCK_PORT,OP_LINK,PH_FC,CND_TO,DIR_IRR) || \ MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_IRR,CND_INV,DIR_RDWR) || \ MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_IRR,CND_RCA,DIR_WRITE) || \ MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_IRR,CND_RUR,DIR_WRITE) || \ MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_IRR,CND_TO,DIR_READ) || \ MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_IRR,CND_TO,DIR_WRITE) || \ MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_IRR,CND_UC,DIR_IRR)) /* Ereport Events */ event ereport.io.pciex.rc.epkt@hostbridge {within(5s)}; /* Internal Events */ event error.io.pciex.rc.stall@hostbridge; event error.io.pciex.rc.poiscomp@hostbridge; event error.io.pciex.nr-d@hostbridge/pciexrc/PCIEXFN; event error.io.pciex.badreq-u@hostbridge/pciexrc/PCIEXFN; event error.io.pciex.poiscomp-d@hostbridge/pciexrc/PCIEXFN; event error.io.pciex.noimpact-d@hostbridge/pciexrc/PCIEXFN; event error.io.pciex.lost-d@hostbridge/pciexrc/PCIEXFN; event error.io.pciex.degraded-d@hostbridge/pciexrc/PCIEXFN; /* Upset event */ event upset.io.pciex.rc.stall@hostbridge; event upset.io.pciex.rc.discard@hostbridge; /* * Fault Events * Do no retire and FRUs for SW/FW faults */ event fault.io.pciex.rc.generic-ue@hostbridge, FITrate=HB_FIT, retire=0, response=0; event fault.io.pciex.rc.generic-sw@hostbridge, FITrate=SW_FIT, retire=0, response=0; event fault.io.pciex.rc.generic-fw@hostbridge, FITrate=FW_FIT, retire=0, response=0; /* Serd engine for CE errors */ engine serd.io.pciex.rc.generic-ce@hostbridge, N=RC_N, T=RC_T; event fault.io.pciex.rc.generic-ce@hostbridge, FITrate=HB_FIT, engine=serd.io.pciex.rc.generic-ce@hostbridge; /* Fire faults */ event fault.io.fire.pciex.device@PCIEXFN, FITrate=1000; event fault.io.fire.pci.device@pcibus/pcidev/pcifn, FITrate=1000; /* Generic Root Complex Software faults */ prop fault.io.pciex.rc.generic-sw@hostbridge -> ereport.io.pciex.rc.epkt@hostbridge { MATCHES_DESC(BLOCK_INTR,OP_FIXED,PH_UNKNOWN,CND_ILL,DIR_INGRESS) || MATCHES_DESC(BLOCK_INTR,OP_MSI32,PH_UNKNOWN,CND_ILL,DIR_IRR) || MATCHES_DESC(BLOCK_INTR,OP_PCIEMSG,PH_UNKNOWN,CND_ILL,DIR_INGRESS) }; /* Generic Root Complex Firmware faults */ prop fault.io.pciex.rc.generic-fw@hostbridge -> ereport.io.pciex.rc.epkt@hostbridge { MATCHES_DESC(BLOCK_HOSTBUS,OP_PIO,PH_ADDR,CND_UNMAP,DIR_WRITE) }; /* Generic Root Complex CE faults */ prop fault.io.pciex.rc.generic-ce@hostbridge { IS_CE } -> ereport.io.pciex.rc.epkt@hostbridge; /* Generic Root Complex UE faults from propagations */ event error.io.pciex.rc.generic-ue1@hostbridge; event error.io.pciex.rc.generic-ue2@hostbridge; prop fault.io.pciex.rc.generic-ue@hostbridge -> error.io.pciex.rc.generic-ue1@hostbridge, error.io.pciex.rc.generic-ue2@hostbridge, error.io.pciex.rc.stall@hostbridge, error.io.pciex.rc.poiscomp@hostbridge; /* Generic Root Complex UE propagations */ prop error.io.pciex.rc.generic-ue1@hostbridge { IS_UE && !IS_BLOCKED } -> ereport.io.pciex.rc.epkt@hostbridge { MATCHES_DESC(BLOCK_HOSTBUS,OP_DMA,PH_DATA,CND_INT,DIR_READ) || MATCHES_DESC(BLOCK_HOSTBUS,OP_DMA,PH_DATA,CND_INT,DIR_UNKNOWN) || MATCHES_DESC(BLOCK_HOSTBUS,OP_DMA,PH_DATA,CND_INT,DIR_WRITE) || MATCHES_DESC(BLOCK_HOSTBUS,OP_DMA,PH_DATA,CND_TO,DIR_READ) || MATCHES_DESC(BLOCK_HOSTBUS,OP_DMA,PH_DATA,CND_TO,DIR_WRITE) || MATCHES_DESC(BLOCK_HOSTBUS,OP_PIO,PH_DATA,CND_INT,DIR_UNKNOWN) || MATCHES_DESC(BLOCK_HOSTBUS,OP_UNKNOWN,PH_DATA,CND_INT,DIR_UNKNOWN) || MATCHES_DESC(BLOCK_HOSTBUS,OP_UNKNOWN,PH_DATA,CND_INT,DIR_UNKNOWN) || MATCHES_DESC(BLOCK_INTR,OP_MSI32,PH_DATA,CND_INT,DIR_UNKNOWN) || MATCHES_DESC(BLOCK_INTR,OP_MSIQ,PH_DATA,CND_INT,DIR_UNKNOWN) }; prop error.io.pciex.rc.generic-ue2@hostbridge { IS_UE && !IS_BLOCKED } -> ereport.io.pciex.rc.epkt@hostbridge { MATCHES_DESC(BLOCK_MMU,OP_TBW,PH_ADDR,CND_UNKNOWN,DIR_UNKNOWN) || MATCHES_DESC(BLOCK_MMU,OP_TBW,PH_ADDR,CND_UNMAP,DIR_UNKNOWN) || MATCHES_DESC(BLOCK_MMU,OP_TBW,PH_DATA,CND_INT,DIR_IRR) || MATCHES_DESC(BLOCK_MMU,OP_TBW,PH_UNKNOWN,CND_UNKNOWN,DIR_UNKNOWN) || MATCHES_DESC(BLOCK_MMU,OP_XLAT,PH_DATA,CND_INT,DIR_UNKNOWN) || MATCHES_DESC(BLOCK_PORT,OP_DMA,PH_DATA,CND_INT,DIR_READ) || MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_DATA,CND_INT,DIR_READ) || MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_DATA,CND_INT,DIR_UNKNOWN) || MATCHES_DESC(BLOCK_PORT,OP_UNKNOWN,PH_DATA,CND_INT,DIR_UNKNOWN) || MATCHES_DESC(BLOCK_PORT,OP_UNKNOWN,PH_DATA,CND_INT,DIR_UNKNOWN) }; /* Errors that will cause a pipe stall and thus a CTO in the fabric */ prop error.io.pciex.rc.stall@hostbridge (0) -> error.io.pciex.nr-d@hostbridge/pciexrc<>/PCIEXFNHZ; prop error.io.pciex.rc.stall@hostbridge { IS_UE && IS_BLOCKED } -> ereport.io.pciex.rc.epkt@hostbridge { !DIAG_BY_FAB }; /* * Errors that will send a poisoned data to the fabric * Also the poiscomp-d could represent a fault that a hardened driver * handled and reported a service impact. */ prop error.io.pciex.rc.poiscomp@hostbridge (0) -> error.io.pciex.poiscomp-d@hostbridge/pciexrc<>/PCIEXFNHZ, error.io.pciex.noimpact-d@hostbridge/pciexrc<>/PCIEXFNHZ, error.io.pciex.lost-d@hostbridge/pciexrc<>/PCIEXFNHZ, error.io.pciex.degraded-d@hostbridge/pciexrc<>/PCIEXFNHZ; prop error.io.pciex.rc.poiscomp@hostbridge { IS_UE && !IS_BLOCKED } -> ereport.io.pciex.rc.epkt@hostbridge { MATCHES_DESC(BLOCK_HOSTBUS,OP_DMA,PH_DATA,CND_INT,DIR_READ) }; prop error.io.pciex.badreq-u@hostbridge/pciexrc/PCIEXFN { IS_UE && !IS_BLOCKED } (0) -> ereport.io.pciex.rc.epkt@hostbridge { MATCHES_DESC(BLOCK_MMU,OP_XLAT,PH_ADDR,CND_UNMAP,DIR_RDWR) || MATCHES_DESC(BLOCK_MMU,OP_XLAT,PH_DATA,CND_INV,DIR_RDWR) || MATCHES_DESC(BLOCK_MMU,OP_XLAT,PH_DATA,CND_PROT,DIR_RDWR) }; /* * The errors will be diagnosed by pciex.esc but may also cause a CTO * in the fabric. */ prop upset.io.pciex.rc.stall@hostbridge -> ereport.io.pciex.rc.epkt@hostbridge { IS_BLOCKED && DIAG_BY_FAB }; prop upset.io.pciex.rc.stall@hostbridge (0) -> error.io.pciex.nr-d@hostbridge/pciexrc<>/PCIEXFNHZ; /* The errors will be discarded here and diagnosed by pciex.esc. */ prop upset.io.pciex.rc.discard@hostbridge -> ereport.io.pciex.rc.epkt@hostbridge { !IS_BLOCKED && DIAG_BY_FAB }; /* Event queue overflow */ #define PROP_PLAT_FRU "FRU" #define GET_HB_FRU (confprop(asru(hostbridge), PROP_PLAT_FRU)) #define GET_PCIE_FRU (confprop(asru(pciexbus[b]/pciexdev[d]/pciexfn[0]), PROP_PLAT_FRU)) #define GET_PCI_FRU (confprop(asru(pcibus[b]/pcidev[d]/pcifn[0]), PROP_PLAT_FRU)) prop fault.io.fire.pciex.device@pciexbus[b]/pciexdev[d]/pciexfn[0] { /* * Indict PCI-E FRU(s) under this root complex excluding the * one that the Fire ASIC resides on. */ is_under(hostbridge, pciexbus[b]/pciexdev[d]/pciexfn[0]) && (GET_HB_FRU != GET_PCIE_FRU) } (0) -> EPKT(BLOCK_INTR,OP_MSIQ,PH_UNKNOWN,CND_OV,DIR_IRR); prop fault.io.fire.pci.device@pcibus[b]/pcidev[d]/pcifn[0] { /* * Indict PCI FRU(s) under this root complex excluding the * one that the Fire ASIC resides on. */ is_under(hostbridge, pcibus[b]/pcidev[d]/pcifn[0]) && (GET_HB_FRU != GET_PCI_FRU) } (0) -> EPKT(BLOCK_INTR,OP_MSIQ,PH_UNKNOWN,CND_OV,DIR_IRR); /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * sca1000.esc: Deimos eversholt source code */ #pragma dictionary "SCA1000" /* * For Deimos, there is one ASRU that includes both the driver and the card, * and there are two FRUs, the driver and the card. */ #define P pcibus/pcidev/pcifn asru P; fru P; /* * The hardware card may generate faults. * The driver passes the user data to the hardware and returns the hardware * generated results to the user. It does check input and output data errors. * However, it returns these errors to the calling application. Since the * driver itself does not do any data manipulation or generation, it does not * have upsets. */ /* * Declare faults */ event fault.io.sca1000.hw@P, FITrate=50, ASRU=P, FRU=P; /* * Hardware faults lead to the following error */ event error.io.sca1000.hw.device@P; /* DMA device errors */ event error.io.sca1000.hw.timeout@P; /* Device hang */ /* * Declare ereports */ event ereport.io.sca1000.hw.device@P; event ereport.io.sca1000.hw.timeout@P; /* * Declear event propagations for faults */ prop fault.io.sca1000.hw@P(0) -> error.io.sca1000.hw.device@P, error.io.sca1000.hw.timeout@P; prop error.io.sca1000.hw.device@P -> ereport.io.sca1000.hw.device@P; prop error.io.sca1000.hw.timeout@P -> ereport.io.sca1000.hw.timeout@P; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2005 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ /* * sca500.esc: Deimos eversholt source code */ #pragma dictionary "SCA500" /* * For Deimos, there is one ASRU that includes both the driver and the card, * and there are two FRUs, the driver and the card. */ #define P pcibus/pcidev/pcifn asru P; fru P; /* * The hardware card may generate faults. * The driver passes the user data to the hardware and returns the hardware * generated results to the user. It does check input and output data errors. * However, it returns these errors to the calling application. Since the * driver itself does not do any data manipulation or generation, it does not * have upsets. */ /* * Declare faults */ event fault.io.sca500.hw@P, FITrate=50, ASRU=P, FRU=P; /* * Hardware faults lead to the following error */ event error.io.sca500.hw.device@P; /* DMA device errors */ event error.io.sca500.hw.timeout@P; /* Device hang */ /* * Declare ereports */ event ereport.io.sca500.hw.device@P; event ereport.io.sca500.hw.timeout@P; /* * Declear event propagations for faults */ prop fault.io.sca500.hw@P(0) -> error.io.sca500.hw.device@P, error.io.sca500.hw.timeout@P; prop error.io.sca500.hw.device@P -> ereport.io.sca500.hw.device@P; prop error.io.sca500.hw.timeout@P -> ereport.io.sca500.hw.timeout@P; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright 2009 Sun Microsystems, Inc. All rights reserved. * Use is subject to license terms. */ #pragma dictionary "SENSOR" #define TOPO_SENSOR_ERRSRC_UNKNOWN 0 #define TOPO_SENSOR_ERRSRC_INTERNAL 1 #define TOPO_SENSOR_ERRSRC_EXTERNAL 2 fru fan; fru psu; /* * Generic fan/psu fault events. */ event fault.fan.failed@fan; event fault.psu.failed@psu; /* * Fine-grained fan/psu fault events */ event fault.fan.failed-pred@fan; event fault.psu.failed-int@psu; event fault.psu.failed-ext@psu; event fault.psu.failed-pred@psu; /* * fan and psu ereports. */ event ereport.sensor.failure@fan; event ereport.sensor.failure@psu; /* * Propagations. */ prop fault.fan.failed@fan -> ereport.sensor.failure@fan { payloadprop("type") == "fan" && payloadprop("predictive") == 0 }; prop fault.fan.failed-pred@fan -> ereport.sensor.failure@fan { payloadprop("type") == "fan" && payloadprop("predictive") == 1 }; prop fault.psu.failed@psu -> ereport.sensor.failure@psu { payloadprop("type") == "psu" && payloadprop("source") == TOPO_SENSOR_ERRSRC_UNKNOWN && payloadprop("predictive") == 0 }; prop fault.psu.failed-int@psu -> ereport.sensor.failure@psu { payloadprop("type") == "psu" && payloadprop("source") == TOPO_SENSOR_ERRSRC_INTERNAL && payloadprop("predictive") == 0 }; prop fault.psu.failed-ext@psu -> ereport.sensor.failure@psu { payloadprop("type") == "psu" && payloadprop("source") == TOPO_SENSOR_ERRSRC_EXTERNAL && payloadprop("predictive") == 0 }; prop fault.psu.failed-pred@psu -> ereport.sensor.failure@psu { payloadprop("type") == "psu" && payloadprop("predictive") == 1 }; /* * CDDL HEADER START * * The contents of this file are subject to the terms of the * Common Development and Distribution License (the "License"). * You may not use this file except in compliance with the License. * * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE * or http://www.opensolaris.org/os/licensing. * See the License for the specific language governing permissions * and limitations under the License. * * When distributing Covered Code, include this CDDL HEADER in each * file and include the License file at usr/src/OPENSOLARIS.LICENSE. * If applicable, add the following below this CDDL HEADER, with the * fields enclosed by brackets "[]" replaced with your own identifying * information: Portions Copyright [yyyy] [name of copyright owner] * * CDDL HEADER END */ /* * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved. */ #pragma dictionary "STORAGE" /* * Fault event definitions. */ event fault.config.fan-fail@ses-enclosure; event fault.config.fantray-fail@ses-enclosure; event fault.config.psu-fail@ses-enclosure; event fault.device.controller.fail@controller; event fault.device.ethernet.fail@controller; event fault.device.ethernet.fail@sas-expander; event fault.device.fan.fail@fan; event fault.device.fan.fail@fanmodule; event fault.device.psu.fail@psu; event fault.device.psu.fail@psu; event fault.device.sas-expander.fail@sas-expander; event fault.device.unusable-chassis-id@fanboard; event fault.io.i2c.fail@controller; event fault.io.i2c.fail@fanboard; event fault.io.i2c.fail@fanmodule; event fault.io.i2c.fail@powerboard; event fault.io.i2c.fail@psu; event fault.io.sas.log.fatal@sas-expander; event fault.io.sas.log.non-fatal@sas-expander; event fault.power.ext-fail@ses-enclosure; event fault.power.fail@controller; event fault.power.fail@controller; event fault.power.fail@controller; event fault.power.fail@fanmodule; event fault.power.fail@fanmodule; event fault.power.fail@psu; event fault.power.fail@psu; event fault.sensor.read-fail@controller; event fault.sensor.read-fail@fanmodule; event fault.sensor.read-fail@fan; event fault.sensor.read-fail@psu; event fault.sp.fail@controller; event fault.sp.svc-fail@controller; event fault.sp.unavailable@controller; event fault.temp.fail@controller; event fault.temp.fail@fanmodule; event fault.temp.fail@psu; /* * Error event definitions. */ event ereport.chassis.config.missing-fan@ses-enclosure; event ereport.chassis.config.missing-fantray@ses-enclosure; event ereport.chassis.config.missing-psu@ses-enclosure; event ereport.chassis.device.ecb.shutoff@controller; event ereport.chassis.device.ethernet.link-down@controller; event ereport.chassis.device.ethernet.link-down@sas-expander; event ereport.chassis.device.psu.dc-fail@psu; event ereport.chassis.device.psu.dc-oc@psu; event ereport.chassis.device.psu.dc-ov@psu; event ereport.chassis.device.psu.dc-uv@psu; event ereport.chassis.device.psu.ext-ac-fail@psu; event ereport.chassis.device.psu.ot@psu; event ereport.chassis.device.sas-expander.fail@sas-expander; event ereport.chassis.device.unusable-chassis-id@fanboard; event ereport.chassis.io.i2c.fail@controller; event ereport.chassis.io.i2c.fail@fanboard; event ereport.chassis.io.i2c.fail@fanmodule; event ereport.chassis.io.i2c.fail@powerboard; event ereport.chassis.io.i2c.fail@psu; event ereport.chassis.post.device.fail@controller; event ereport.chassis.post.device.fail@fan; event ereport.chassis.post.device.fail@fanmodule; event ereport.chassis.post.device.fail@psu; event ereport.chassis.post.sp.fail@controller; event ereport.chassis.sensor.current.oc@controller; event ereport.chassis.sensor.current.oc@fanmodule; event ereport.chassis.sensor.current.oc@psu; event ereport.chassis.sensor.current.uc@controller; event ereport.chassis.sensor.current.uc@fanmodule; event ereport.chassis.sensor.current.uc@psu; event ereport.chassis.sensor.fanspeed.us@fan; event ereport.chassis.sensor.read-fail@controller; event ereport.chassis.sensor.read-fail@fanmodule; event ereport.chassis.sensor.read-fail@fan; event ereport.chassis.sensor.read-fail@psu; event ereport.chassis.sensor.temp.ot@controller; event ereport.chassis.sensor.temp.ot@fanmodule; event ereport.chassis.sensor.temp.ot@psu; event ereport.chassis.sensor.temp.ut@controller; event ereport.chassis.sensor.temp.ut@fanmodule; event ereport.chassis.sensor.temp.ut@psu; event ereport.chassis.sensor.voltage.ov@controller; event ereport.chassis.sensor.voltage.ov@fanmodule; event ereport.chassis.sensor.voltage.ov@psu; event ereport.chassis.sensor.voltage.uv@controller; event ereport.chassis.sensor.voltage.uv@fanmodule; event ereport.chassis.sensor.voltage.uv@psu; event ereport.chassis.sp.svc-restart@controller; event ereport.chassis.sp.unavailable@controller; event ereport.io.sas.log.fatal@sas-expander; event ereport.io.sas.log.non-fatal@sas-expander; /* * Service Processor failure */ prop fault.sp.fail@controller -> ereport.chassis.post.sp.fail@controller; /* * Controller failure */ prop fault.device.controller.fail@controller -> ereport.chassis.post.device.fail@controller; /* * Fan module failure */ prop fault.device.fan.fail@fanmodule -> ereport.chassis.post.device.fail@fanmodule; /* * I2C transaction failure */ prop fault.io.i2c.fail@controller -> ereport.chassis.io.i2c.fail@controller; prop fault.io.i2c.fail@fanboard -> ereport.chassis.io.i2c.fail@fanboard; prop fault.io.i2c.fail@fanmodule -> ereport.chassis.io.i2c.fail@fanmodule; prop fault.io.i2c.fail@powerboard -> ereport.chassis.io.i2c.fail@powerboard; prop fault.io.i2c.fail@psu -> ereport.chassis.io.i2c.fail@psu; /* * Chassis ID unusable failure */ prop fault.device.unusable-chassis-id@fanboard -> ereport.chassis.device.unusable-chassis-id@fanboard; /* * Configuration failure */ prop fault.config.psu-fail@ses-enclosure -> ereport.chassis.config.missing-psu@ses-enclosure{ setpayloadprop("min-required", payloadprop("min-required")) && setpayloadprop("devices", payloadprop("devices"))}; prop fault.config.fan-fail@ses-enclosure -> ereport.chassis.config.missing-fan@ses-enclosure{ setpayloadprop("min-required", payloadprop("min-required")) && setpayloadprop("devices", payloadprop("devices"))}; prop fault.config.fantray-fail@ses-enclosure -> ereport.chassis.config.missing-fantray@ses-enclosure{ setpayloadprop("min-required", payloadprop("min-required")) && setpayloadprop("devices", payloadprop("devices"))}; /* * Fan failure */ prop fault.device.fan.fail@fan -> ereport.chassis.sensor.fanspeed.us@fan, ereport.chassis.post.device.fail@fan; /* * Sensor reading failure */ prop fault.sensor.read-fail@controller -> ereport.chassis.sensor.read-fail@controller; prop fault.sensor.read-fail@fanmodule -> ereport.chassis.sensor.read-fail@fanmodule; prop fault.sensor.read-fail@fan -> ereport.chassis.sensor.read-fail@fan; prop fault.sensor.read-fail@psu -> ereport.chassis.sensor.read-fail@psu; /* * Temperature failure */ prop fault.temp.fail@controller -> ereport.chassis.sensor.temp.ot@controller, ereport.chassis.sensor.temp.ut@controller; prop fault.temp.fail@fanmodule -> ereport.chassis.sensor.temp.ot@fanmodule, ereport.chassis.sensor.temp.ut@fanmodule; prop fault.temp.fail@psu -> ereport.chassis.sensor.temp.ot@psu, ereport.chassis.sensor.temp.ut@psu; /* * Power failure */ prop fault.power.fail@controller -> ereport.chassis.device.ecb.shutoff@controller, ereport.chassis.sensor.current.oc@controller, ereport.chassis.sensor.current.uc@controller, ereport.chassis.sensor.voltage.ov@controller, ereport.chassis.sensor.voltage.uv@controller; prop fault.power.fail@fanmodule -> ereport.chassis.sensor.current.oc@fanmodule, ereport.chassis.sensor.current.uc@fanmodule, ereport.chassis.sensor.voltage.ov@fanmodule, ereport.chassis.sensor.voltage.uv@fanmodule; prop fault.power.fail@psu -> ereport.chassis.sensor.current.oc@psu, ereport.chassis.sensor.current.uc@psu, ereport.chassis.sensor.voltage.ov@psu, ereport.chassis.sensor.voltage.uv@psu; /* * Power supply unit failure */ prop fault.device.psu.fail@psu -> ereport.chassis.device.psu.dc-fail@psu, ereport.chassis.device.psu.dc-ov@psu, ereport.chassis.device.psu.dc-uv@psu, ereport.chassis.device.psu.dc-oc@psu, ereport.chassis.device.psu.ot@psu, ereport.chassis.post.device.fail@psu; /* * External power failure */ prop fault.power.ext-fail@ses-enclosure -> ereport.chassis.device.psu.ext-ac-fail@psu<>; /* * SAS Expander failure */ prop fault.device.sas-expander.fail@sas-expander -> ereport.chassis.device.sas-expander.fail@sas-expander; /* * Ethernet failure */ prop fault.device.ethernet.fail@controller -> ereport.chassis.device.ethernet.link-down@controller; prop fault.device.ethernet.fail@sas-expander -> ereport.chassis.device.ethernet.link-down@sas-expander; /* * Service Processor unavailable failure */ prop fault.sp.unavailable@controller -> ereport.chassis.sp.unavailable@controller; /* * Service Processor service failure */ prop fault.sp.svc-fail@controller -> ereport.chassis.sp.svc-restart@controller{ setpayloadprop("service", payloadprop("service"))}; /* * SAS Expander Log failure */ prop fault.io.sas.log.non-fatal@sas-expander -> ereport.io.sas.log.non-fatal@sas-expander; prop fault.io.sas.log.fatal@sas-expander -> ereport.io.sas.log.fatal@sas-expander; # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2004 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # # Hammerhead: amd64-only SUBDIRS = $(MACH64) # # We don't currently support the debug target for the native build. # debug: include ../../Makefile.subdirs # # CDDL HEADER START # # The contents of this file are subject to the terms of the # Common Development and Distribution License, Version 1.0 only # (the "License"). You may not use this file except in compliance # with the License. # # You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE # or http://www.opensolaris.org/os/licensing. # See the License for the specific language governing permissions # and limitations under the License. # # When distributing Covered Code, include this CDDL HEADER in each # file and include the License file at usr/src/OPENSOLARIS.LICENSE. # If applicable, add the following below this CDDL HEADER, with the # fields enclosed by brackets "[]" replaced with your own identifying # information: Portions Copyright [yyyy] [name of copyright owner] # # CDDL HEADER END # # # Copyright 2005 Sun Microsystems, Inc. All rights reserved. # Use is subject to license terms. # .KEEP_STATE: PROG = esc include $(SRC)/cmd/fm/eversholt/Makefile.esc.com include $(SRC)/cmd/Makefile.ctf include $(SRC)/Makefile.native EFTCLASS = writer LOCALOBJS = escmain.o OBJS = $(LOCALOBJS) $(COMMONOBJS) SRCS = $(LOCALOBJS:.o=.c) $(COMMONSRCS) CPPFLAGS += $(BASECPPFLAGS) -I../../esc/common CFLAGS += -DESC CFLAGS64 += -DESC LDLIBS = -lumem NATIVE_LIBS = libumem.so libc.so all: $(PROG) install: all $(PROG): $(OBJS) $(LINK.c) -o $@ $(OBJS) $(LDLIBS) $(POST_PROCESS) clean: $(RM) $(OBJS) y.output y.tab.c y.tab.h clobber: clean $(RM) $(PROG) esclex.o: escparse.o %.o: ../../esc/common/%.c $(COMPILE.c) $< $(POST_PROCESS_O) # # This file and its contents are supplied under the terms of the # Common Development and Distribution License ("CDDL"), version 1.0. # You may only use this file in accordance with the terms of version # 1.0 of the CDDL. # # A full copy of the text of the CDDL should have accompanied this # source. A copy of the CDDL is also available via the Internet at # http://www.illumos.org/license/CDDL. # # Copyright 2025 Hammerhead Project # # Hammerhead: Include Makefile.cmd first to load Makefile.master # (defines COMPILE.c, COMPILE64.c needed by Makefile.esc.com's pattern rules) include $(SRC)/cmd/Makefile.cmd include ../Makefile.com include $(SRC)/cmd/Makefile.cmd.64 install: all $(ROOTPROG64)