xref: /illumos-gate/usr/src/cmd/fm/modules/common/fabric-xlate/fabric-xlate.c (revision 67dbe2be0c0f1e2eb428b89088bb5667e8f0b9f6)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #include <assert.h>
27 #include <stddef.h>
28 #include <errno.h>
29 #include <strings.h>
30 #include <fm/fmd_api.h>
31 #include <fm/libtopo.h>
32 #include <sys/fm/util.h>
33 #include <sys/fm/protocol.h>
34 #include <sys/fm/io/pci.h>
35 #include <sys/fm/io/sun4_fire.h>
36 #include <sys/pci.h>
37 #include <sys/pcie.h>
38 #include <sys/nvpair.h>
39 #include <sys/nvpair_impl.h>
40 
41 #include <libxml/xpath.h>
42 #include <libxml/parser.h>
43 #include <libxml/xpathInternals.h>
44 #include <libxml/tree.h>
45 
46 /* PCI-E config space data for error handling and fabric ereports */
47 typedef struct fab_data {
48 	/* Original ereport NVL */
49 	nvlist_t	*nvl;
50 
51 	/* Device Information */
52 	uint16_t bdf;
53 	uint16_t device_id;
54 	uint16_t vendor_id;
55 	uint8_t rev_id;
56 	uint16_t dev_type;
57 	uint16_t pcie_off;
58 	uint16_t pcix_off;
59 	uint16_t aer_off;
60 	uint16_t ecc_ver;
61 
62 	/* Ereport Information */
63 	uint32_t remainder;
64 	uint32_t severity;
65 
66 	/* Error Registers */
67 	uint16_t pci_err_status;	/* pci status register */
68 	uint16_t pci_cfg_comm;		/* pci command register */
69 
70 	uint16_t pci_bdg_sec_stat;	/* PCI secondary status reg */
71 	uint16_t pci_bdg_ctrl;		/* PCI bridge control reg */
72 
73 	uint16_t pcix_command;		/* pcix command register */
74 	uint32_t pcix_status;		/* pcix status register */
75 
76 	uint16_t pcix_bdg_sec_stat;	/* pcix bridge secondary status reg */
77 	uint32_t pcix_bdg_stat;		/* pcix bridge status reg */
78 
79 	uint16_t pcix_ecc_control_0;	/* pcix ecc control status reg */
80 	uint16_t pcix_ecc_status_0;	/* pcix ecc control status reg */
81 	uint32_t pcix_ecc_fst_addr_0;	/* pcix ecc first address reg */
82 	uint32_t pcix_ecc_sec_addr_0;	/* pcix ecc second address reg */
83 	uint32_t pcix_ecc_attr_0;	/* pcix ecc attributes reg */
84 	uint16_t pcix_ecc_control_1;	/* pcix ecc control status reg */
85 	uint16_t pcix_ecc_status_1;	/* pcix ecc control status reg */
86 	uint32_t pcix_ecc_fst_addr_1;	/* pcix ecc first address reg */
87 	uint32_t pcix_ecc_sec_addr_1;	/* pcix ecc second address reg */
88 	uint32_t pcix_ecc_attr_1;	/* pcix ecc attributes reg */
89 
90 	uint16_t pcie_err_status;	/* pcie device status register */
91 	uint16_t pcie_err_ctl;		/* pcie error control register */
92 	uint32_t pcie_dev_cap;		/* pcie device capabilities register */
93 
94 	uint32_t pcie_adv_ctl;		/* pcie advanced control reg */
95 	uint32_t pcie_ue_status;	/* pcie ue error status reg */
96 	uint32_t pcie_ue_mask;		/* pcie ue error mask reg */
97 	uint32_t pcie_ue_sev;		/* pcie ue error severity reg */
98 	uint32_t pcie_ue_hdr[4];	/* pcie ue header log */
99 	uint32_t pcie_ce_status;	/* pcie ce error status reg */
100 	uint32_t pcie_ce_mask;		/* pcie ce error mask reg */
101 	uint32_t pcie_ue_tgt_trans;	/* Fault trans type from AER Logs */
102 	uint64_t pcie_ue_tgt_addr;	/* Fault addr from AER Logs */
103 	pcie_req_id_t pcie_ue_tgt_bdf;	/* Fault bdf from SAER Logs */
104 
105 	uint32_t pcie_sue_ctl;		/* pcie bridge secondary ue control */
106 	uint32_t pcie_sue_status;	/* pcie bridge secondary ue status */
107 	uint32_t pcie_sue_mask;		/* pcie bridge secondary ue mask */
108 	uint32_t pcie_sue_sev;		/* pcie bridge secondary ue severity */
109 	uint32_t pcie_sue_hdr[4];	/* pcie bridge secondary ue hdr log */
110 	uint32_t pcie_sue_tgt_trans;	/* Fault trans type from AER Logs */
111 	uint64_t pcie_sue_tgt_addr;	/* Fault addr from AER Logs */
112 	pcie_req_id_t pcie_sue_tgt_bdf;	/* Fault bdf from SAER Logs */
113 
114 	uint32_t pcie_rp_status;	/* root complex status register */
115 	uint16_t pcie_rp_ctl;		/* root complex control register */
116 	uint32_t pcie_rp_err_status;	/* pcie root complex error status reg */
117 	uint32_t pcie_rp_err_cmd;	/* pcie root complex error cmd reg */
118 	uint16_t pcie_rp_ce_src_id;	/* pcie root complex ce sourpe id */
119 	uint16_t pcie_rp_ue_src_id;	/* pcie root complex ue sourpe id */
120 } fab_data_t;
121 
122 /*
123  * These values are used for the xxx_tgt_trans value in fab_data_t.  They are
124  * originally set in pcie_fault.c and originally defined in pcie_impl.h.
125  */
126 #define	PF_ADDR_DMA		(1 << 0)
127 #define	PF_ADDR_PIO		(1 << 1)
128 #define	PF_ADDR_CFG		(1 << 2)
129 
130 typedef struct fab_erpt_tbl {
131 	const char	*err_class;	/* Final Ereport Class */
132 	uint32_t	reg_bit;	/* Error Bit Mask */
133 	/* Pointer to function that prepares the ereport body */
134 	const char	*tgt_class;	/* Target Ereport Class */
135 } fab_erpt_tbl_t;
136 
137 typedef struct fab_err_tbl {
138 	fab_erpt_tbl_t	*erpt_tbl;	/* ereport table */
139 	uint32_t	reg_offset;	/* sts reg for ereport table offset */
140 	uint32_t	reg_size;	/* size of the status register */
141 	/* Pointer to function that prepares the ereport body */
142 	int		(*fab_prep)(fmd_hdl_t *, fab_data_t *, nvlist_t *,
143 	    fab_erpt_tbl_t *);
144 } fab_err_tbl_t;
145 
146 typedef struct fab_fire_tbl {
147 	const char	*err_class;
148 	uint32_t	fire_bit;	/* Fire error bit */
149 	uint16_t	pci_err_sts;	/* Equivalent PCI Error Status */
150 	uint16_t	pci_bdg_sts;	/* Equivalent PCI Bridge Status */
151 } fab_fire_tbl_t;
152 
153 /* Static FM Topo XML Format and XML XPath Context  */
154 static xmlDocPtr		fab_doc = NULL;
155 static xmlXPathContextPtr	fab_xpathCtx = NULL;
156 static int			fab_valid_topo = 0;
157 #define	XMLTOPOFILE "/tmp/fab-xlate-topo.xml"
158 
159 /* Functions that convert ereports to a common C data structure */
160 static void fab_pci_fabric_to_data(fmd_hdl_t *hdl, nvlist_t *nvl,
161     fab_data_t *data);
162 static void fab_fire_to_data(fmd_hdl_t *hdl, nvlist_t *nvl, fab_data_t *data);
163 
164 /* Common functions for sending translated ereports */
165 static int fab_prep_basic_erpt(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *erpt,
166     boolean_t isRC);
167 static boolean_t fab_get_rcpath(fmd_hdl_t *hdl, nvlist_t *nvl, char *rcpath);
168 static char *fab_find_addr(fmd_hdl_t *hdl, nvlist_t *nvl, uint64_t addr);
169 static char *fab_find_bdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf);
170 static void fab_send_tgt_erpt(fmd_hdl_t *hdl, fab_data_t *data,
171     const char *class, boolean_t isPrimary);
172 static void fab_send_erpt(fmd_hdl_t *hdl, fab_data_t *data, fab_err_tbl_t *tbl);
173 
174 /*
175  * Common functions for converting  pci.fabric classes of
176  * ereports
177  */
178 static int fab_prep_pci_erpt(fmd_hdl_t *hdl, fab_data_t *data,
179     nvlist_t *erpt, fab_erpt_tbl_t *table);
180 static int fab_prep_pci_bdg_erpt(fmd_hdl_t *hdl, fab_data_t *data,
181     nvlist_t *erpt, fab_erpt_tbl_t *table);
182 static int fab_prep_pci_bdg_ctl_erpt(fmd_hdl_t *hdl, fab_data_t *data,
183     nvlist_t *erpt, fab_erpt_tbl_t *table);
184 static int fab_prep_pcie_ce_erpt(fmd_hdl_t *hdl, fab_data_t *data,
185     nvlist_t *erpt, fab_erpt_tbl_t *table);
186 static int fab_prep_pcie_ue_erpt(fmd_hdl_t *hdl, fab_data_t *data,
187     nvlist_t *erpt, fab_erpt_tbl_t *table);
188 static int fab_prep_pcie_sue_erpt(fmd_hdl_t *hdl, fab_data_t *data,
189     nvlist_t *erpt, fab_erpt_tbl_t *table);
190 static int fab_prep_pcie_nadv_erpt(fmd_hdl_t *hdl, fab_data_t *data,
191     nvlist_t *erpt, fab_erpt_tbl_t *table);
192 static int fab_prep_pcix_erpt(fmd_hdl_t *hdl, fab_data_t *data,
193     nvlist_t *erpt, fab_erpt_tbl_t *table);
194 static void fab_send_pcix_ecc_erpt(fmd_hdl_t *hdl, fab_data_t *data);
195 static int fab_prep_pcix_bdg_erpt(fmd_hdl_t *hdl, fab_data_t *data,
196     nvlist_t *erpt, fab_erpt_tbl_t *table);
197 static void fab_send_pcix_bdg_ecc_erpt(fmd_hdl_t *hdl, fab_data_t *data);
198 static int fab_prep_pcie_rc_erpt(fmd_hdl_t *hdl, fab_data_t *data,
199     nvlist_t *erpt, fab_erpt_tbl_t *table);
200 static int fab_prep_pcie_fake_rc_erpt(fmd_hdl_t *hdl, fab_data_t *data,
201     nvlist_t *erpt, fab_erpt_tbl_t *table);
202 
203 /* Functions for converting fire specific error registers */
204 static int fab_xlate_fire_ce(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
205     const char *class);
206 static int fab_xlate_fire_ue(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
207     const char *class);
208 static int fab_xlate_fire_oe(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
209     const char *class);
210 static int fab_xlate_fire_dmc(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
211     const char *class);
212 
213 /* Main functions for converting "fabric" ereports */
214 static void fab_xlate_pcie_erpts(fmd_hdl_t *hdl, fab_data_t *data);
215 static void fab_xlate_fire_erpts(fmd_hdl_t *hdl, fab_data_t *data,
216     nvlist_t *nvl, const char *class);
217 
218 /*
219  * Translation tables for converting "fabric" error bits into "pci" ereports.
220  * <Ereport Class Name>, <Error Bit Mask>, <Preparation Function>
221  */
222 
223 /* MACRO for table entries with no TGT ereports */
224 #define	NT(class, bit, prep) class, bit, prep, NULL
225 /* Translate Fabric ereports to ereport.io.pci.* */
226 static fab_erpt_tbl_t fab_pci_erpt_tbl[] = {
227 	PCI_DET_PERR,		PCI_STAT_PERROR,	NULL,
228 	PCI_MDPE,		PCI_STAT_S_PERROR,	NULL,
229 	PCI_SIG_SERR,		PCI_STAT_S_SYSERR,	NULL,
230 	PCI_MA,			PCI_STAT_R_MAST_AB,	NULL,
231 	PCI_REC_TA,		PCI_STAT_R_TARG_AB,	NULL,
232 	PCI_SIG_TA,		PCI_STAT_S_TARG_AB,	NULL,
233 	NULL, NULL, NULL
234 };
235 
236 /* Translate Fabric ereports to ereport.io.pci.sec-* */
237 static fab_erpt_tbl_t fab_pci_bdg_erpt_tbl[] = {
238 	PCI_DET_PERR,		PCI_STAT_PERROR,	NULL,
239 	PCI_MDPE,		PCI_STAT_S_PERROR,	NULL,
240 	PCI_REC_SERR,		PCI_STAT_S_SYSERR,	NULL,
241 #ifdef sparc
242 	PCI_MA,			PCI_STAT_R_MAST_AB,	NULL,
243 #endif
244 	PCI_REC_TA,		PCI_STAT_R_TARG_AB,	NULL,
245 	PCI_SIG_TA,		PCI_STAT_S_TARG_AB,	NULL,
246 	NULL, NULL, NULL, NULL,
247 };
248 
249 
250 /* Translate Fabric ereports to ereport.io.pci.dto */
251 static fab_erpt_tbl_t fab_pci_bdg_ctl_erpt_tbl[] = {
252 	PCI_DTO,	PCI_BCNF_BCNTRL_DTO_STAT,	NULL,
253 	NULL, NULL, NULL
254 };
255 
256 /* Translate Fabric ereports to ereport.io.pciex.* */
257 static fab_erpt_tbl_t fab_pcie_ce_erpt_tbl[] = {
258 	PCIEX_RE,	PCIE_AER_CE_RECEIVER_ERR,	NULL,
259 	PCIEX_RNR,	PCIE_AER_CE_REPLAY_ROLLOVER,	NULL,
260 	PCIEX_RTO,	PCIE_AER_CE_REPLAY_TO,		NULL,
261 	PCIEX_BDP,	PCIE_AER_CE_BAD_DLLP,		NULL,
262 	PCIEX_BTP,	PCIE_AER_CE_BAD_TLP,		NULL,
263 	PCIEX_ANFE,	PCIE_AER_CE_AD_NFE,		NULL,
264 	NULL, NULL, NULL
265 };
266 
267 /* Translate Fabric ereports to ereport.io.pciex.* */
268 static fab_erpt_tbl_t fab_pcie_ue_erpt_tbl[] = {
269 	PCIEX_TE,	PCIE_AER_UCE_TRAINING,		NULL,
270 	PCIEX_DLP,	PCIE_AER_UCE_DLP,		NULL,
271 	PCIEX_SD,	PCIE_AER_UCE_SD,		NULL,
272 	PCIEX_ROF,	PCIE_AER_UCE_RO,		NULL,
273 	PCIEX_FCP,	PCIE_AER_UCE_FCP,		NULL,
274 	PCIEX_MFP,	PCIE_AER_UCE_MTLP,		NULL,
275 	PCIEX_CTO,	PCIE_AER_UCE_TO,		PCI_TARG_MA,
276 	PCIEX_UC,	PCIE_AER_UCE_UC,		NULL,
277 	PCIEX_ECRC,	PCIE_AER_UCE_ECRC,		NULL,
278 	PCIEX_CA,	PCIE_AER_UCE_CA,		PCI_TARG_REC_TA,
279 #ifdef sparc
280 	PCIEX_UR,	PCIE_AER_UCE_UR,		PCI_TARG_MA,
281 #endif
282 	PCIEX_POIS,	PCIE_AER_UCE_PTLP,		PCI_TARG_MDPE,
283 	NULL, NULL, NULL
284 };
285 
286 /* Translate Fabric ereports to ereport.io.pciex.* */
287 static fab_erpt_tbl_t fab_pcie_sue_erpt_tbl[] = {
288 	PCIEX_S_TA_SC,	PCIE_AER_SUCE_TA_ON_SC,		PCI_TARG_REC_TA,
289 	PCIEX_S_MA_SC,	PCIE_AER_SUCE_MA_ON_SC,		PCI_TARG_MA,
290 	PCIEX_S_RTA,	PCIE_AER_SUCE_RCVD_TA,		PCI_TARG_REC_TA,
291 #ifdef sparc
292 	PCIEX_S_RMA,	PCIE_AER_SUCE_RCVD_MA,		PCI_TARG_MA,
293 #endif
294 	PCIEX_S_USC,	PCIE_AER_SUCE_USC_ERR,		NULL,
295 	PCIEX_S_USCMD,	PCIE_AER_SUCE_USC_MSG_DATA_ERR,	PCI_TARG_REC_TA,
296 	PCIEX_S_UDE,	PCIE_AER_SUCE_UC_DATA_ERR,	PCI_TARG_MDPE,
297 	PCIEX_S_UAT,	PCIE_AER_SUCE_UC_ATTR_ERR,	PCI_TARG_MDPE,
298 	PCIEX_S_UADR,	PCIE_AER_SUCE_UC_ADDR_ERR,	PCI_TARG_MDPE,
299 	PCIEX_S_TEX,	PCIE_AER_SUCE_TIMER_EXPIRED,	NULL,
300 	PCIEX_S_PERR,	PCIE_AER_SUCE_PERR_ASSERT,	PCI_TARG_MDPE,
301 	PCIEX_S_SERR,	PCIE_AER_SUCE_SERR_ASSERT,	NULL,
302 	PCIEX_INTERR,	PCIE_AER_SUCE_INTERNAL_ERR,	NULL,
303 	NULL, NULL, NULL
304 };
305 
306 /* Translate Fabric ereports to ereport.io.pcix.* */
307 static fab_erpt_tbl_t fab_pcix_erpt_tbl[] = {
308 	PCIX_SPL_DIS,		PCI_PCIX_SPL_DSCD,	NULL,
309 	PCIX_UNEX_SPL,		PCI_PCIX_UNEX_SPL,	NULL,
310 	PCIX_RX_SPL_MSG,	PCI_PCIX_RX_SPL_MSG,	NULL,
311 	NULL, NULL, NULL
312 };
313 static fab_erpt_tbl_t *fab_pcix_bdg_erpt_tbl = fab_pcix_erpt_tbl;
314 
315 /* Translate Fabric ereports to ereport.io.pcix.sec-* */
316 static fab_erpt_tbl_t fab_pcix_bdg_sec_erpt_tbl[] = {
317 	PCIX_SPL_DIS,		PCI_PCIX_BSS_SPL_DSCD,	NULL,
318 	PCIX_UNEX_SPL,		PCI_PCIX_BSS_UNEX_SPL,	NULL,
319 	PCIX_BSS_SPL_OR,	PCI_PCIX_BSS_SPL_OR,	NULL,
320 	PCIX_BSS_SPL_DLY,	PCI_PCIX_BSS_SPL_DLY,	NULL,
321 	NULL, NULL, NULL
322 };
323 
324 /* Translate Fabric ereports to ereport.io.pciex.* */
325 static fab_erpt_tbl_t fab_pcie_nadv_erpt_tbl[] = {
326 #ifdef sparc
327 	PCIEX_UR,		PCIE_DEVSTS_UR_DETECTED,	NULL,
328 #endif
329 	PCIEX_FAT,		PCIE_DEVSTS_FE_DETECTED,	NULL,
330 	PCIEX_NONFAT,		PCIE_DEVSTS_NFE_DETECTED,	NULL,
331 	PCIEX_CORR,		PCIE_DEVSTS_CE_DETECTED,	NULL,
332 	NULL, NULL, NULL
333 };
334 
335 /* Translate Fabric ereports to ereport.io.pciex.* */
336 static fab_erpt_tbl_t fab_pcie_rc_erpt_tbl[] = {
337 	PCIEX_RC_FE_MSG,	PCIE_AER_RE_STS_FE_MSGS_RCVD,	NULL,
338 	PCIEX_RC_NFE_MSG,	PCIE_AER_RE_STS_NFE_MSGS_RCVD,	NULL,
339 	PCIEX_RC_CE_MSG,	PCIE_AER_RE_STS_CE_RCVD,	NULL,
340 	PCIEX_RC_MCE_MSG,	PCIE_AER_RE_STS_MUL_CE_RCVD,	NULL,
341 	PCIEX_RC_MUE_MSG,	PCIE_AER_RE_STS_MUL_FE_NFE_RCVD, NULL,
342 	NULL, NULL, NULL
343 };
344 
345 /*
346  * Translate Fabric ereports to pseudo ereport.io.pciex.* RC Fabric Messages.
347  * If the RP is not a PCIe compliant RP or does not support AER, rely on the
348  * leaf fabric ereport to help create a xxx_MSG ereport coming from the RC.
349  */
350 static fab_erpt_tbl_t fab_pcie_fake_rc_erpt_tbl[] = {
351 	PCIEX_RC_FE_MSG,	PCIE_DEVSTS_FE_DETECTED,	NULL,
352 	PCIEX_RC_NFE_MSG,	PCIE_DEVSTS_NFE_DETECTED,	NULL,
353 	PCIEX_RC_CE_MSG,	PCIE_DEVSTS_CE_DETECTED,	NULL,
354 	NULL, NULL, NULL,
355 };
356 
357 static fab_err_tbl_t *fab_master_err_tbl;
358 
359 /*
360  * Translation tables for converting fire error bits into "pci" ereports.
361  * <Fire Bit>
362  * <pci ereport Class>
363  * <pci error status reg>
364  * <pci bridge status reg>
365  * <pci target class>
366  */
367 #define	FAB_FIRE_PEC_BIT(fb) "ereport.io." PCIEX_FIRE "." FIRE_PEC_ ## fb
368 #define	FAB_FIRE_DMC_BIT(fb) "ereport.io." PCIEX_FIRE "." FIRE_DMC_ ## fb
369 #define	FAB_N2_DMU_BIT(fb) "ereport.io.n2.dmu." fb
370 #define	FAB_OB_PEC_BIT(fb) "ereport.io." PCIEX_OBERON "." FIRE_PEC_ ## fb
371 
372 #define	FAB_FIRE_UE(fb, bit, sts, bdg) \
373 	FAB_FIRE_PEC_BIT(fb), PCIE_AER_UCE_ ## bit, sts, bdg
374 #define	FAB_OB_UE(fb, bit, sts, bdg) \
375 	FAB_OB_PEC_BIT(fb), PCIE_AER_UCE_ ## bit, sts, bdg
376 static fab_fire_tbl_t fab_fire_pec_ue_tbl[] = {
377 	FAB_FIRE_UE(UR,	 UR,	   PCI_STAT_S_SYSERR,	0),
378 	FAB_FIRE_UE(UC,	 UC,	   PCI_STAT_S_SYSERR,	0),
379 	FAB_OB_UE(ECRC,	 ECRC,	   PCI_STAT_S_SYSERR,	0),
380 	FAB_FIRE_UE(CTO, TO,	   PCI_STAT_S_SYSERR,	0),
381 	FAB_FIRE_UE(ROF, RO,	   PCI_STAT_S_SYSERR,	0),
382 	FAB_FIRE_UE(MFP, MTLP,	   PCI_STAT_S_SYSERR,	0),
383 	FAB_FIRE_UE(PP,	 PTLP,	   PCI_STAT_S_PERROR,
384 	    (PCI_STAT_S_SYSERR | PCI_STAT_PERROR)),
385 	FAB_FIRE_UE(FCP, FCP,	   PCI_STAT_S_SYSERR,	0),
386 	FAB_FIRE_UE(DLP, DLP,	   PCI_STAT_S_SYSERR,	0),
387 	FAB_FIRE_UE(TE,	 TRAINING, PCI_STAT_S_SYSERR,	0),
388 	FAB_FIRE_UE(CA,	 CA,	   PCI_STAT_S_TARG_AB,
389 	    PCI_STAT_S_TARG_AB),
390 	NULL, NULL, NULL,
391 };
392 
393 #define	FAB_FIRE_CE(fb, bit) \
394 	FAB_FIRE_PEC_BIT(fb), PCIE_AER_CE_ ## bit, 0, 0
395 static fab_fire_tbl_t fab_fire_pec_ce_tbl[] = {
396 	FAB_FIRE_CE(RTO,	REPLAY_TO),
397 	FAB_FIRE_CE(RNR,	REPLAY_ROLLOVER),
398 	FAB_FIRE_CE(BDP,	BAD_DLLP),
399 	FAB_FIRE_CE(BTP,	BAD_TLP),
400 	FAB_FIRE_CE(RE,		RECEIVER_ERR),
401 	NULL, NULL, NULL,
402 };
403 
404 /*
405  * WUC/RUC will need to be special cased for the target ereports, because you
406  * need to decode the tlp log.
407  */
408 #define	FAB_FIRE_WUCRUC(fb) \
409 	FAB_FIRE_PEC_BIT(fb), 0, 0, (PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR)
410 #define	FAB_FIRE_OE(fb, bit) \
411 	FAB_FIRE_PEC_BIT(fb), PCIE_AER_UCE_ ## bit, PCI_STAT_S_SYSERR, 0
412 #define	FAB_OB_OE(fb, bit) \
413 	FAB_FIRE_PEC_BIT(fb), PCIE_AER_UCE_ ## bit, PCI_STAT_S_SYSERR, 0
414 static fab_fire_tbl_t fab_fire_pec_oe_tbl[] = {
415 	FAB_FIRE_WUCRUC(WUC),
416 	FAB_FIRE_WUCRUC(RUC),
417 	FAB_FIRE_OE(ERU, DLP),
418 	FAB_FIRE_OE(ERO, DLP),
419 	FAB_FIRE_OE(EMP, DLP),
420 	FAB_FIRE_OE(EPE, DLP),
421 	NULL, NULL, NULL,
422 };
423 
424 #define	FAB_FIRE_DMC(fb) \
425 	FAB_FIRE_DMC_BIT(fb), PCIE_AER_UCE_CA, 0, PCI_STAT_S_TARG_AB
426 #define	FAB_N2_DMU(fb) \
427 	FAB_N2_DMU_BIT(fb), PCIE_AER_UCE_CA, 0, PCI_STAT_S_TARG_AB
428 static fab_fire_tbl_t fab_fire_dmc_tbl[] = {
429 	FAB_FIRE_DMC(BYP_ERR),
430 	FAB_FIRE_DMC(BYP_OOR),
431 	FAB_FIRE_DMC(TRN_OOR),
432 	FAB_FIRE_DMC(TTE_INV),
433 	FAB_FIRE_DMC(TTE_PRT),
434 	FAB_N2_DMU("iotsbdesc_inv"),
435 	FAB_N2_DMU("sun4v_adj_va_uf"),
436 	FAB_N2_DMU("sun4v_inv_pg_sz"),
437 	FAB_N2_DMU("sun4v_key_err"),
438 	FAB_N2_DMU("sun4v_va_oor"),
439 	NULL, NULL, NULL
440 };
441 
442 static fmd_xprt_t *fab_fmd_xprt = NULL;	/* FMD transport layer handle */
443 static char fab_buf[FM_MAX_CLASS];
444 static boolean_t fab_xlate_fake_rp = B_TRUE;
445 
446 #define	HAS_PROP(node, name) xmlHasProp(node, (const xmlChar *)name)
447 #define	GET_PROP(node, name) ((char *)xmlGetProp(node, (const xmlChar *)name))
448 #define	FREE_PROP(prop) xmlFree((xmlChar *)prop)
449 #define	STRCMP(s1, s2) (strcmp((const char *)s1, (const char *)s2) == 0)
450 
451 #define	FAB_LOOKUP(sz, name, field) \
452 	(void) nvlist_lookup_uint ## sz(nvl, name, field)
453 /* ARGSUSED */
454 static void
455 fab_pci_fabric_to_data(fmd_hdl_t *hdl, nvlist_t *nvl, fab_data_t *data) {
456 	data->nvl = nvl;
457 
458 	/* Generic PCI device information */
459 	FAB_LOOKUP(16,	"bdf",			&data->bdf);
460 	FAB_LOOKUP(16,	"device_id",		&data->device_id);
461 	FAB_LOOKUP(16,	"vendor_id",		&data->vendor_id);
462 	FAB_LOOKUP(8,	"rev_id",		&data->rev_id);
463 	FAB_LOOKUP(16,	"dev_type",		&data->dev_type);
464 	FAB_LOOKUP(16,	"pcie_off",		&data->pcie_off);
465 	FAB_LOOKUP(16,	"pcix_off",		&data->pcix_off);
466 	FAB_LOOKUP(16,	"aer_off",		&data->aer_off);
467 	FAB_LOOKUP(16,	"ecc_ver",		&data->ecc_ver);
468 
469 	/* Misc ereport information */
470 	FAB_LOOKUP(32,	"remainder",		&data->remainder);
471 	FAB_LOOKUP(32,	"severity",		&data->severity);
472 
473 	/* PCI registers */
474 	FAB_LOOKUP(16,	"pci_status",		&data->pci_err_status);
475 	FAB_LOOKUP(16,	"pci_command",		&data->pci_cfg_comm);
476 
477 	/* PCI bridge registers */
478 	FAB_LOOKUP(16,	"pci_bdg_sec_status",	&data->pci_bdg_sec_stat);
479 	FAB_LOOKUP(16,	"pci_bdg_ctrl",		&data->pci_bdg_ctrl);
480 
481 	/* PCIx registers */
482 	FAB_LOOKUP(32,	"pcix_status",		&data->pcix_status);
483 	FAB_LOOKUP(16,	"pcix_command",		&data->pcix_command);
484 
485 	/* PCIx ECC Registers */
486 	FAB_LOOKUP(16,	"pcix_ecc_control_0",	&data->pcix_ecc_control_0);
487 	FAB_LOOKUP(16,	"pcix_ecc_status_0",	&data->pcix_ecc_status_0);
488 	FAB_LOOKUP(32,	"pcix_ecc_fst_addr_0",	&data->pcix_ecc_fst_addr_0);
489 	FAB_LOOKUP(32,	"pcix_ecc_sec_addr_0",	&data->pcix_ecc_sec_addr_0);
490 	FAB_LOOKUP(32,	"pcix_ecc_attr_0",	&data->pcix_ecc_attr_0);
491 
492 	/* PCIx ECC Bridge Registers */
493 	FAB_LOOKUP(16,	"pcix_ecc_control_1",	&data->pcix_ecc_control_1);
494 	FAB_LOOKUP(16,	"pcix_ecc_status_1",	&data->pcix_ecc_status_1);
495 	FAB_LOOKUP(32,	"pcix_ecc_fst_addr_1",	&data->pcix_ecc_fst_addr_1);
496 	FAB_LOOKUP(32,	"pcix_ecc_sec_addr_1",	&data->pcix_ecc_sec_addr_1);
497 	FAB_LOOKUP(32,	"pcix_ecc_attr_1",	&data->pcix_ecc_attr_1);
498 
499 	/* PCIx Bridge */
500 	FAB_LOOKUP(32,	"pcix_bdg_status",	&data->pcix_bdg_stat);
501 	FAB_LOOKUP(16,	"pcix_bdg_sec_status",	&data->pcix_bdg_sec_stat);
502 
503 	/* PCIe registers */
504 	FAB_LOOKUP(16,	"pcie_status",		&data->pcie_err_status);
505 	FAB_LOOKUP(16,	"pcie_command",		&data->pcie_err_ctl);
506 	FAB_LOOKUP(32,	"pcie_dev_cap",		&data->pcie_dev_cap);
507 
508 	/* PCIe AER registers */
509 	FAB_LOOKUP(32,	"pcie_adv_ctl",		&data->pcie_adv_ctl);
510 	FAB_LOOKUP(32,	"pcie_ue_status",	&data->pcie_ue_status);
511 	FAB_LOOKUP(32,	"pcie_ue_mask",		&data->pcie_ue_mask);
512 	FAB_LOOKUP(32,	"pcie_ue_sev",		&data->pcie_ue_sev);
513 	FAB_LOOKUP(32,	"pcie_ue_hdr0",		&data->pcie_ue_hdr[0]);
514 	FAB_LOOKUP(32,	"pcie_ue_hdr1",		&data->pcie_ue_hdr[1]);
515 	FAB_LOOKUP(32,	"pcie_ue_hdr2",		&data->pcie_ue_hdr[2]);
516 	FAB_LOOKUP(32,	"pcie_ue_hdr3",		&data->pcie_ue_hdr[3]);
517 	FAB_LOOKUP(32,	"pcie_ce_status",	&data->pcie_ce_status);
518 	FAB_LOOKUP(32,	"pcie_ce_mask",		&data->pcie_ce_mask);
519 	FAB_LOOKUP(32,	"pcie_ue_tgt_trans",	&data->pcie_ue_tgt_trans);
520 	FAB_LOOKUP(64,	"pcie_ue_tgt_addr",	&data->pcie_ue_tgt_addr);
521 	FAB_LOOKUP(16,	"pcie_ue_tgt_bdf",	&data->pcie_ue_tgt_bdf);
522 
523 	/* PCIe BDG AER registers */
524 	FAB_LOOKUP(32,	"pcie_sue_adv_ctl",	&data->pcie_sue_ctl);
525 	FAB_LOOKUP(32,	"pcie_sue_status",	&data->pcie_sue_status);
526 	FAB_LOOKUP(32,	"pcie_sue_mask",	&data->pcie_sue_mask);
527 	FAB_LOOKUP(32,	"pcie_sue_sev",		&data->pcie_sue_sev);
528 	FAB_LOOKUP(32,	"pcie_sue_hdr0",	&data->pcie_sue_hdr[0]);
529 	FAB_LOOKUP(32,	"pcie_sue_hdr1",	&data->pcie_sue_hdr[1]);
530 	FAB_LOOKUP(32,	"pcie_sue_hdr2",	&data->pcie_sue_hdr[2]);
531 	FAB_LOOKUP(32,	"pcie_sue_hdr3",	&data->pcie_sue_hdr[3]);
532 	FAB_LOOKUP(32,	"pcie_sue_tgt_trans",	&data->pcie_sue_tgt_trans);
533 	FAB_LOOKUP(64,	"pcie_sue_tgt_addr",	&data->pcie_sue_tgt_addr);
534 	FAB_LOOKUP(16,	"pcie_sue_tgt_bdf",	&data->pcie_sue_tgt_bdf);
535 
536 	/* PCIe RP registers */
537 	FAB_LOOKUP(32,	"pcie_rp_status",	&data->pcie_rp_status);
538 	FAB_LOOKUP(16,	"pcie_rp_control",	&data->pcie_rp_ctl);
539 
540 	/* PCIe RP AER registers */
541 	FAB_LOOKUP(32,	"pcie_adv_rp_status",	&data->pcie_rp_err_status);
542 	FAB_LOOKUP(32,	"pcie_adv_rp_command",	&data->pcie_rp_err_cmd);
543 	FAB_LOOKUP(16,	"pcie_adv_rp_ce_src_id", &data->pcie_rp_ce_src_id);
544 	FAB_LOOKUP(16,	"pcie_adv_rp_ue_src_id", &data->pcie_rp_ue_src_id);
545 
546 	/*
547 	 * If the system has a PCIe complaint RP with AER, turn off translating
548 	 * fake RP ereports.
549 	 */
550 	if (fab_xlate_fake_rp &&
551 	    (data->dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) &&
552 	    data->aer_off)
553 		fab_xlate_fake_rp = B_FALSE;
554 }
555 
556 /* ARGSUSED */
557 static void
558 fab_fire_to_data(fmd_hdl_t *hdl, nvlist_t *nvl, fab_data_t *data) {
559 	data->nvl = nvl;
560 
561 	/* Always Root Complex */
562 	data->dev_type = PCIE_PCIECAP_DEV_TYPE_ROOT;
563 
564 	data->pcie_ue_sev = (PCIE_AER_UCE_DLP | PCIE_AER_UCE_SD |
565 	    PCIE_AER_UCE_FCP | PCIE_AER_UCE_RO | PCIE_AER_UCE_MTLP);
566 }
567 
568 /* ARGSUSED */
569 static int
570 fab_prep_basic_erpt(fmd_hdl_t *hdl, nvlist_t *nvl, nvlist_t *erpt,
571     boolean_t isRC) {
572 	uint64_t	*now;
573 	uint64_t	ena;
574 	uint_t		nelem;
575 	nvlist_t	*detector, *new_detector;
576 	char		rcpath[255];
577 	int		err = 0;
578 
579 	/* Grab the tod, ena and detector(FMRI) */
580 	err |= nvlist_lookup_uint64_array(nvl, "__tod", &now, &nelem);
581 	err |= nvlist_lookup_uint64(nvl, "ena", &ena);
582 	err |= nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &detector);
583 	if (err)
584 		return (err);
585 
586 	/* Make a copy of the detector */
587 	err = nvlist_dup(detector, &new_detector, NV_UNIQUE_NAME);
588 	if (err)
589 		return (err);
590 
591 	/* Copy the tod and ena to erpt */
592 	(void) nvlist_add_uint64(erpt, FM_EREPORT_ENA, ena);
593 	(void) nvlist_add_uint64_array(erpt, "__tod", now, nelem);
594 
595 	/*
596 	 * Create the correct ROOT FMRI from PCIe leaf fabric ereports.	 Used
597 	 * only by fab_prep_fake_rc_erpt.  See the fab_pciex_fake_rc_erpt_tbl
598 	 * comments for more information.
599 	 */
600 	if (isRC && fab_get_rcpath(hdl, nvl, rcpath)) {
601 		/* Create the correct PCIe RC new_detector aka FMRI */
602 		(void) nvlist_remove(new_detector, FM_FMRI_DEV_PATH,
603 		    DATA_TYPE_STRING);
604 		(void) nvlist_add_string(new_detector, FM_FMRI_DEV_PATH,
605 		    rcpath);
606 	}
607 
608 	/* Copy the FMRI to erpt */
609 	(void) nvlist_add_nvlist(erpt, FM_EREPORT_DETECTOR, new_detector);
610 
611 	nvlist_free(new_detector);
612 	return (err);
613 }
614 
615 static void
616 fab_send_tgt_erpt(fmd_hdl_t *hdl, fab_data_t *data, const char *class,
617     boolean_t isPrimary)
618 {
619 	nvlist_t	*nvl = data->nvl;
620 	nvlist_t	*erpt;
621 	char		*fmri = NULL;
622 	uint32_t	tgt_trans;
623 	uint64_t	tgt_addr;
624 	uint16_t	tgt_bdf;
625 
626 	if (isPrimary) {
627 		tgt_trans = data->pcie_ue_tgt_trans;
628 		tgt_addr = data->pcie_ue_tgt_addr;
629 		tgt_bdf = data->pcie_ue_tgt_bdf;
630 	} else {
631 		tgt_trans = data->pcie_sue_tgt_trans;
632 		tgt_addr = data->pcie_sue_tgt_addr;
633 		tgt_bdf = data->pcie_sue_tgt_bdf;
634 	}
635 
636 	fmd_hdl_debug(hdl, "Sending Target Ereport: "
637 	    "type 0x%x addr 0x%llx fltbdf 0x%x\n",
638 	    tgt_trans, tgt_addr, tgt_bdf);
639 
640 	if (!tgt_trans)
641 		return;
642 
643 	if ((tgt_trans == PF_ADDR_PIO) && tgt_addr)
644 		fmri = fab_find_addr(hdl, nvl, tgt_addr);
645 	else if ((tgt_trans == PF_ADDR_CFG) && tgt_bdf)
646 		fmri = fab_find_bdf(hdl, nvl, tgt_bdf);
647 
648 	if (fmri) {
649 		uint64_t	*now;
650 		uint64_t	ena;
651 		uint_t		nelem;
652 		nvlist_t	*detector;
653 		int		err = 0;
654 
655 		/* Allocate space for new erpt */
656 		if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
657 			goto done;
658 
659 		/* Generate the target ereport class */
660 		(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
661 		    PCI_ERROR_SUBCLASS, class);
662 		(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
663 
664 		/* Grab the tod, ena and detector(FMRI) */
665 		err |= nvlist_lookup_uint64_array(nvl, "__tod", &now, &nelem);
666 		err |= nvlist_lookup_uint64(nvl, "ena", &ena);
667 
668 		/* Copy the tod and ena to erpt */
669 		(void) nvlist_add_uint64(erpt, FM_EREPORT_ENA, ena);
670 		(void) nvlist_add_uint64_array(erpt, "__tod", now, nelem);
671 
672 		/* Create the correct FMRI */
673 		if (nvlist_alloc(&detector, NV_UNIQUE_NAME, 0) != 0) {
674 			nvlist_free(erpt);
675 			goto done;
676 		}
677 		(void) nvlist_add_uint8(detector, FM_VERSION,
678 		    FM_DEV_SCHEME_VERSION);
679 		(void) nvlist_add_string(detector, FM_FMRI_SCHEME,
680 		    FM_FMRI_SCHEME_DEV);
681 		(void) nvlist_add_string(detector, FM_FMRI_DEV_PATH, fmri);
682 		(void) nvlist_add_nvlist(erpt, FM_EREPORT_DETECTOR, detector);
683 		nvlist_free(detector);
684 
685 		/* Add the address payload */
686 		(void) nvlist_add_uint64(erpt, PCI_PA, tgt_addr);
687 
688 		fmd_hdl_debug(hdl, "Sending target ereport: %s 0x%x\n",
689 		    fab_buf, tgt_addr);
690 		fmd_xprt_post(hdl, fab_fmd_xprt, erpt, 0);
691 		if (fmd_xprt_error(hdl, fab_fmd_xprt))
692 			goto done;
693 		xmlFree(fmri);
694 	} else {
695 		fmd_hdl_debug(hdl, "Cannot find Target FMRI addr:0x%llx",
696 		    tgt_addr);
697 	}
698 
699 	return;
700 done:
701 	if (fmri)
702 		xmlFree(fmri);
703 	fmd_hdl_debug(hdl, "Failed to send Target PCI ereport\n");
704 }
705 
706 static void
707 fab_send_erpt(fmd_hdl_t *hdl, fab_data_t *data, fab_err_tbl_t *tbl)
708 {
709 	fab_erpt_tbl_t	*erpt_tbl, *entry;
710 	nvlist_t	*erpt;
711 	uint32_t	reg;
712 
713 	erpt_tbl = tbl->erpt_tbl;
714 	if (tbl->reg_size == 16) {
715 		reg = (uint32_t)*((uint16_t *)
716 		    ((uint32_t)data + tbl->reg_offset));
717 	} else {
718 		reg = *((uint32_t *)((uint32_t)data + tbl->reg_offset));
719 	}
720 
721 	for (entry = erpt_tbl; entry->err_class; entry++) {
722 		if (!(reg & entry->reg_bit))
723 			continue;
724 
725 		if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
726 			goto done;
727 		if (tbl->fab_prep(hdl, data, erpt, entry) != 0) {
728 			fmd_hdl_debug(hdl, "Prepping ereport failed\n");
729 			nvlist_free(erpt);
730 			continue;
731 		}
732 
733 		fmd_hdl_debug(hdl, "Sending ereport: %s 0x%x\n", fab_buf, reg);
734 		fmd_xprt_post(hdl, fab_fmd_xprt, erpt, 0);
735 		if (fmd_xprt_error(hdl, fab_fmd_xprt)) {
736 			fmd_hdl_debug(hdl, "Failed to send PCI ereport\n");
737 			return;
738 		}
739 	}
740 
741 	return;
742 done:
743 	fmd_hdl_debug(hdl, "Failed  to send PCI ereport\n");
744 }
745 
746 static int
747 fab_prep_pci_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
748     fab_erpt_tbl_t *tbl)
749 {
750 	const char *class = tbl->err_class;
751 	int err = fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
752 
753 	/* Generate an ereport for this error bit. */
754 	(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
755 	    PCI_ERROR_SUBCLASS, class);
756 	(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
757 
758 	(void) nvlist_add_uint16(erpt, PCI_CONFIG_STATUS, data->pci_err_status);
759 	(void) nvlist_add_uint16(erpt, PCI_CONFIG_COMMAND, data->pci_cfg_comm);
760 
761 	return (err);
762 }
763 
764 static int
765 fab_prep_pci_bdg_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
766     fab_erpt_tbl_t *tbl)
767 {
768 	const char *class = tbl->err_class;
769 	int err = fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
770 
771 	/* Generate an ereport for this error bit. */
772 	(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s-%s",
773 	    PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS, class);
774 	(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
775 
776 	(void) nvlist_add_uint16(erpt, PCI_SEC_CONFIG_STATUS,
777 	    data->pci_bdg_sec_stat);
778 	(void) nvlist_add_uint16(erpt, PCI_BCNTRL, data->pci_bdg_ctrl);
779 
780 	return (err);
781 }
782 
783 static int
784 fab_prep_pci_bdg_ctl_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
785     fab_erpt_tbl_t *tbl)
786 {
787 	const char *class = tbl->err_class;
788 	int err = fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
789 
790 	/* Generate an ereport for this error bit. */
791 	(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
792 	    PCI_ERROR_SUBCLASS, class);
793 	(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
794 
795 	(void) nvlist_add_uint16(erpt, PCI_SEC_CONFIG_STATUS,
796 	    data->pci_bdg_sec_stat);
797 	(void) nvlist_add_uint16(erpt, PCI_BCNTRL, data->pci_bdg_ctrl);
798 
799 	return (err);
800 }
801 
802 
803 static int
804 fab_prep_pcie_ce_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
805     fab_erpt_tbl_t *tbl)
806 {
807 	const char *class = tbl->err_class;
808 	int err = fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
809 
810 	/* Generate an ereport for this error bit. */
811 	(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
812 	    PCIEX_ERROR_SUBCLASS, class);
813 	(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
814 
815 	(void) nvlist_add_uint16(erpt, PCIEX_DEVSTS_REG, data->pcie_err_status);
816 	(void) nvlist_add_uint32(erpt, PCIEX_CE_STATUS_REG,
817 	    data->pcie_ce_status);
818 
819 	return (err);
820 }
821 
822 static int
823 fab_prep_pcie_ue_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
824     fab_erpt_tbl_t *tbl)
825 {
826 	const char *class = tbl->err_class;
827 	uint32_t first_err = 1 << (data->pcie_adv_ctl &
828 	    PCIE_AER_CTL_FST_ERR_PTR_MASK);
829 	int err = fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
830 
831 	/* Generate an ereport for this error bit. */
832 	(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
833 	    PCIEX_ERROR_SUBCLASS, class);
834 	(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
835 
836 	(void) nvlist_add_uint16(erpt, PCIEX_DEVSTS_REG, data->pcie_err_status);
837 	(void) nvlist_add_uint32(erpt, PCIEX_UE_STATUS_REG,
838 	    data->pcie_ue_status);
839 	(void) nvlist_add_uint32(erpt, PCIEX_UE_SEV_REG, data->pcie_ue_sev);
840 	(void) nvlist_add_uint32(erpt, PCIEX_ADV_CTL, data->pcie_adv_ctl);
841 
842 	fmd_hdl_debug(hdl, "Bit 0x%x First Err 0x%x", tbl->reg_bit, first_err);
843 
844 	if ((tbl->reg_bit == first_err) && data->pcie_ue_tgt_bdf) {
845 		(void) nvlist_add_uint16(erpt, PCIEX_SRC_ID,
846 		    data->pcie_ue_tgt_bdf);
847 		(void) nvlist_add_boolean_value(erpt, PCIEX_SRC_VALID, B_TRUE);
848 	} else {
849 		(void) nvlist_add_uint16(erpt, PCIEX_SRC_ID, 0);
850 		(void) nvlist_add_boolean_value(erpt, PCIEX_SRC_VALID, B_FALSE);
851 	}
852 
853 	if ((tbl->reg_bit == first_err) && data->pcie_ue_tgt_trans) {
854 		if (tbl->tgt_class)
855 			fab_send_tgt_erpt(hdl, data, tbl->tgt_class, B_TRUE);
856 	}
857 
858 	return (err);
859 }
860 
861 static int
862 fab_prep_pcie_sue_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
863     fab_erpt_tbl_t *tbl)
864 {
865 	const char *class = tbl->err_class;
866 	uint32_t first_err = 1 << (data->pcie_sue_ctl &
867 	    PCIE_AER_SCTL_FST_ERR_PTR_MASK);
868 	int err = fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
869 
870 	/* Generate an ereport for this error bit. */
871 	(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
872 	    PCIEX_ERROR_SUBCLASS, class);
873 	(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
874 
875 	(void) nvlist_add_uint32(erpt, PCIEX_SEC_UE_STATUS,
876 	    data->pcie_sue_status);
877 
878 	fmd_hdl_debug(hdl, "Bit 0x%x First Err 0x%x", tbl->reg_bit, first_err);
879 
880 	if ((tbl->reg_bit == first_err) && data->pcie_sue_tgt_bdf) {
881 		(void) nvlist_add_uint16(erpt, PCIEX_SRC_ID,
882 		    data->pcie_sue_tgt_bdf);
883 		(void) nvlist_add_boolean_value(erpt, PCIEX_SRC_VALID, B_TRUE);
884 	} else {
885 		(void) nvlist_add_uint16(erpt, PCIEX_SRC_ID, 0);
886 		(void) nvlist_add_boolean_value(erpt, PCIEX_SRC_VALID, B_FALSE);
887 	}
888 
889 	if ((tbl->reg_bit == first_err) && data->pcie_sue_tgt_trans) {
890 		if (tbl->tgt_class)
891 			fab_send_tgt_erpt(hdl, data, tbl->tgt_class, B_FALSE);
892 	}
893 
894 	return (err);
895 }
896 
897 static int
898 fab_prep_pcix_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
899     fab_erpt_tbl_t *tbl)
900 {
901 	const char *class = tbl->err_class;
902 	int err = 0;
903 
904 	/* Only send if this is not a bridge */
905 	if (!data->pcix_status || data->pcix_bdg_sec_stat)
906 		return (1);
907 
908 	err = fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
909 
910 	/* Generate an ereport for this error bit. */
911 	(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
912 	    PCIX_ERROR_SUBCLASS, class);
913 	(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
914 
915 	(void) nvlist_add_uint8(erpt, PCIX_COMMAND, data->pcix_command);
916 	(void) nvlist_add_uint32(erpt, PCIX_STATUS, data->pcix_status);
917 
918 	return (err);
919 }
920 
921 static void
922 fab_send_pcix_ecc_erpt(fmd_hdl_t *hdl, fab_data_t *data)
923 {
924 	nvlist_t *erpt;
925 	int ecc_phase = (data->pcix_ecc_status_0 & PCI_PCIX_ECC_PHASE) >> 0x4;
926 	int ecc_corr = data->pcix_ecc_status_0 & PCI_PCIX_ECC_CORR;
927 	int sec_ue = data->pcix_ecc_status_0 & PCI_PCIX_ECC_S_UE;
928 	int sec_ce = data->pcix_ecc_status_0 & PCI_PCIX_ECC_S_CE;
929 	uint32_t ctlstat = (data->pcix_ecc_control_0 << 16) |
930 	    data->pcix_ecc_status_0;
931 
932 	switch (ecc_phase) {
933 	case PCI_PCIX_ECC_PHASE_NOERR:
934 		break;
935 	case PCI_PCIX_ECC_PHASE_FADDR:
936 	case PCI_PCIX_ECC_PHASE_SADDR:
937 		(void) snprintf(fab_buf, FM_MAX_CLASS,
938 		    "%s.%s", PCIX_ERROR_SUBCLASS,
939 		    ecc_corr ? PCIX_ECC_CE_ADDR : PCIX_ECC_UE_ADDR);
940 		break;
941 	case PCI_PCIX_ECC_PHASE_ATTR:
942 		(void) snprintf(fab_buf, FM_MAX_CLASS,
943 		    "%s.%s", PCIX_ERROR_SUBCLASS,
944 		    ecc_corr ? PCIX_ECC_CE_ATTR : PCIX_ECC_UE_ATTR);
945 		break;
946 	case PCI_PCIX_ECC_PHASE_DATA32:
947 	case PCI_PCIX_ECC_PHASE_DATA64:
948 		(void) snprintf(fab_buf, FM_MAX_CLASS,
949 		    "%s.%s", PCIX_ERROR_SUBCLASS,
950 		    ecc_corr ? PCIX_ECC_CE_DATA : PCIX_ECC_UE_DATA);
951 		break;
952 	}
953 
954 	if (ecc_phase) {
955 		if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
956 			goto done;
957 		(void) fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
958 		(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
959 		(void) nvlist_add_uint16(erpt, PCIX_COMMAND,
960 		    data->pcix_command);
961 		(void) nvlist_add_uint32(erpt, PCIX_STATUS, data->pcix_status);
962 		(void) nvlist_add_uint32(erpt, PCIX_ECC_CTLSTAT, ctlstat);
963 		(void) nvlist_add_uint32(erpt, PCIX_ECC_ATTR,
964 		    data->pcix_ecc_attr_0);
965 		fmd_hdl_debug(hdl, "Sending ecc ereport: %s\n", fab_buf);
966 		fmd_xprt_post(hdl, fab_fmd_xprt, erpt, 0);
967 		if (fmd_xprt_error(hdl, fab_fmd_xprt))
968 			fmd_hdl_debug(hdl, "Failed to send ECC ereport\n");
969 	}
970 
971 	if (sec_ce || sec_ue) {
972 		(void) snprintf(fab_buf, FM_MAX_CLASS,
973 		    "%s.%s", PCIX_ERROR_SUBCLASS,
974 		    sec_ce ? PCIX_ECC_S_CE : PCIX_ECC_S_UE);
975 		if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
976 			goto done;
977 		(void) fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
978 		(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
979 		(void) nvlist_add_uint16(erpt, PCIX_COMMAND,
980 		    data->pcix_command);
981 		(void) nvlist_add_uint32(erpt, PCIX_STATUS, data->pcix_status);
982 		(void) nvlist_add_uint32(erpt, PCIX_ECC_CTLSTAT, ctlstat);
983 		(void) nvlist_add_uint32(erpt, PCIX_ECC_ATTR,
984 		    data->pcix_ecc_attr_0);
985 		fmd_hdl_debug(hdl, "Sending ecc ereport: %s\n", fab_buf);
986 		fmd_xprt_post(hdl, fab_fmd_xprt, erpt, 0);
987 		if (fmd_xprt_error(hdl, fab_fmd_xprt))
988 			fmd_hdl_debug(hdl, "Failed to send ECC ereport\n");
989 	}
990 
991 	return;
992 done:
993 	fmd_hdl_debug(hdl, "Failed to send ECC ereport\n");
994 }
995 
996 static int
997 fab_prep_pcix_bdg_sec_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
998     fab_erpt_tbl_t *tbl)
999 {
1000 	const char *class = tbl->err_class;
1001 	int err = fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
1002 
1003 	/* Generate an ereport for this error bit. */
1004 	(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s%s",
1005 	    PCIX_ERROR_SUBCLASS, PCIX_SEC_ERROR_SUBCLASS, class);
1006 	(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
1007 
1008 	(void) nvlist_add_uint16(erpt, PCIX_SEC_STATUS,
1009 	    data->pcix_bdg_sec_stat);
1010 	(void) nvlist_add_uint32(erpt, PCIX_BDG_STAT, data->pcix_bdg_stat);
1011 
1012 	return (err);
1013 }
1014 
1015 static int
1016 fab_prep_pcix_bdg_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
1017     fab_erpt_tbl_t *tbl)
1018 {
1019 	const char *class = tbl->err_class;
1020 	int err = fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
1021 
1022 	/* Generate an ereport for this error bit. */
1023 	(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
1024 	    PCIX_ERROR_SUBCLASS, class);
1025 	(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
1026 
1027 	(void) nvlist_add_uint16(erpt, PCIX_SEC_STATUS,
1028 	    data->pcix_bdg_sec_stat);
1029 	(void) nvlist_add_uint32(erpt, PCIX_BDG_STAT, data->pcix_bdg_stat);
1030 
1031 	return (err);
1032 }
1033 
1034 static void
1035 fab_send_pcix_bdg_ecc_erpt(fmd_hdl_t *hdl, fab_data_t *data)
1036 {
1037 	nvlist_t *erpt;
1038 	int ecc_phase = (data->pcix_ecc_status_1 & PCI_PCIX_ECC_PHASE) >> 0x4;
1039 	int ecc_corr = data->pcix_ecc_status_1 & PCI_PCIX_ECC_CORR;
1040 	int sec_ue = data->pcix_ecc_status_1 & PCI_PCIX_ECC_S_UE;
1041 	int sec_ce = data->pcix_ecc_status_1 & PCI_PCIX_ECC_S_CE;
1042 	uint32_t ctlstat = (data->pcix_ecc_control_1 << 16) |
1043 	    data->pcix_ecc_status_1;
1044 
1045 	switch (ecc_phase) {
1046 	case PCI_PCIX_ECC_PHASE_NOERR:
1047 		break;
1048 	case PCI_PCIX_ECC_PHASE_FADDR:
1049 	case PCI_PCIX_ECC_PHASE_SADDR:
1050 		(void) snprintf(fab_buf, FM_MAX_CLASS,
1051 		    "%s.%s%s", PCIX_ERROR_SUBCLASS, PCIX_SEC_ERROR_SUBCLASS,
1052 		    ecc_corr ? PCIX_ECC_CE_ADDR : PCIX_ECC_UE_ADDR);
1053 		break;
1054 	case PCI_PCIX_ECC_PHASE_ATTR:
1055 		(void) snprintf(fab_buf, FM_MAX_CLASS,
1056 		    "%s.%s%s", PCIX_ERROR_SUBCLASS, PCIX_SEC_ERROR_SUBCLASS,
1057 		    ecc_corr ? PCIX_ECC_CE_ATTR : PCIX_ECC_UE_ATTR);
1058 		break;
1059 	case PCI_PCIX_ECC_PHASE_DATA32:
1060 	case PCI_PCIX_ECC_PHASE_DATA64:
1061 		(void) snprintf(fab_buf, FM_MAX_CLASS,
1062 		    "%s.%s%s", PCIX_ERROR_SUBCLASS, PCIX_SEC_ERROR_SUBCLASS,
1063 		    ecc_corr ? PCIX_ECC_CE_DATA : PCIX_ECC_UE_DATA);
1064 		break;
1065 	}
1066 	if (ecc_phase) {
1067 		if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
1068 			goto done;
1069 		(void) fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
1070 		(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
1071 		(void) nvlist_add_uint16(erpt, PCIX_SEC_STATUS,
1072 		    data->pcix_bdg_sec_stat);
1073 		(void) nvlist_add_uint32(erpt, PCIX_BDG_STAT,
1074 		    data->pcix_bdg_stat);
1075 		(void) nvlist_add_uint32(erpt, PCIX_ECC_CTLSTAT, ctlstat);
1076 		(void) nvlist_add_uint32(erpt, PCIX_ECC_ATTR,
1077 		    data->pcix_ecc_attr_1);
1078 		fmd_hdl_debug(hdl, "Sending ecc ereport: %s\n", fab_buf);
1079 		fmd_xprt_post(hdl, fab_fmd_xprt, erpt, 0);
1080 		if (fmd_xprt_error(hdl, fab_fmd_xprt))
1081 			fmd_hdl_debug(hdl, "Failed to send ECC ereport\n");
1082 	}
1083 
1084 	if (sec_ce || sec_ue) {
1085 		(void) snprintf(fab_buf, FM_MAX_CLASS,
1086 		    "%s.%s%s", PCIX_ERROR_SUBCLASS, PCIX_SEC_ERROR_SUBCLASS,
1087 		    sec_ce ? PCIX_ECC_S_CE : PCIX_ECC_S_UE);
1088 		if (nvlist_alloc(&erpt, NV_UNIQUE_NAME, 0) != 0)
1089 			goto done;
1090 		(void) fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
1091 		(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
1092 		(void) nvlist_add_uint16(erpt, PCIX_SEC_STATUS,
1093 		    data->pcix_bdg_sec_stat);
1094 		(void) nvlist_add_uint32(erpt, PCIX_BDG_STAT,
1095 		    data->pcix_bdg_stat);
1096 		(void) nvlist_add_uint32(erpt, PCIX_ECC_CTLSTAT, ctlstat);
1097 		(void) nvlist_add_uint32(erpt, PCIX_ECC_ATTR,
1098 		    data->pcix_ecc_attr_1);
1099 		fmd_hdl_debug(hdl, "Sending ecc ereport: %s\n", fab_buf);
1100 		fmd_xprt_post(hdl, fab_fmd_xprt, erpt, 0);
1101 		if (fmd_xprt_error(hdl, fab_fmd_xprt))
1102 			fmd_hdl_debug(hdl, "Failed to send ECC ereport\n");
1103 	}
1104 	return;
1105 done:
1106 	fmd_hdl_debug(hdl, "Failed to send ECC ereport\n");
1107 }
1108 
1109 static int
1110 fab_prep_pcie_nadv_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
1111     fab_erpt_tbl_t *tbl)
1112 {
1113 	const char *class = tbl->err_class;
1114 	int err = 0;
1115 
1116 	/* Don't send this for PCI device, Root Ports, or PCIe with AER */
1117 	if ((data->dev_type == PCIE_PCIECAP_DEV_TYPE_PCI_DEV) ||
1118 	    (data->dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
1119 	    data->aer_off)
1120 		return (1);
1121 
1122 	err = fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
1123 
1124 	/* Generate an ereport for this error bit. */
1125 	(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
1126 	    PCIEX_ERROR_SUBCLASS, class);
1127 	(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
1128 
1129 	(void) nvlist_add_uint16(erpt, PCIEX_DEVSTS_REG, data->pcie_err_status);
1130 
1131 	return (err);
1132 }
1133 
1134 static int
1135 fab_prep_pcie_rc_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
1136     fab_erpt_tbl_t *tbl)
1137 {
1138 	const char *class = tbl->err_class;
1139 	uint32_t status = data->pcie_rp_err_status;
1140 	int err = 0;
1141 	int isFE = 0, isNFE = 0;
1142 
1143 	fmd_hdl_debug(hdl, "XLATE RP Error Class %s", class);
1144 
1145 	if (!data->aer_off)
1146 		return (-1);
1147 
1148 	/* Only send a FE Msg if the 1st UE error is FE */
1149 	if (STRCMP(class, PCIEX_RC_FE_MSG))
1150 		if (!(status & PCIE_AER_RE_STS_FIRST_UC_FATAL))
1151 			return (-1);
1152 		else
1153 			isFE = 1;
1154 
1155 	/* Only send a NFE Msg is the 1st UE error is NFE */
1156 	if (STRCMP(class, PCIEX_RC_NFE_MSG))
1157 		if (status & PCIE_AER_RE_STS_FIRST_UC_FATAL)
1158 			return (-1);
1159 		else
1160 			isNFE = 1;
1161 
1162 	fmd_hdl_debug(hdl, "XLATE RP Error");
1163 
1164 	err |= fab_prep_basic_erpt(hdl, data->nvl, erpt, B_FALSE);
1165 
1166 	/* Generate an ereport for this error bit. */
1167 	(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
1168 	    PCIEX_ERROR_SUBCLASS, class);
1169 	(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
1170 
1171 	(void) nvlist_add_uint32(erpt, PCIEX_ROOT_ERRSTS_REG, status);
1172 	if ((isFE || isNFE) && data->pcie_rp_ue_src_id) {
1173 		(void) nvlist_add_uint16(erpt, PCIEX_SRC_ID,
1174 		    data->pcie_rp_ue_src_id);
1175 		(void) nvlist_add_boolean_value(erpt, PCIEX_SRC_VALID, B_TRUE);
1176 	}
1177 	if (STRCMP(class, PCIEX_RC_CE_MSG) && data->pcie_rp_ce_src_id) {
1178 		(void) nvlist_add_uint16(erpt, PCIEX_SRC_ID,
1179 		    data->pcie_rp_ce_src_id);
1180 		(void) nvlist_add_boolean_value(erpt, PCIEX_SRC_VALID, B_TRUE);
1181 	}
1182 
1183 	return (err);
1184 }
1185 
1186 static int
1187 fab_prep_pcie_fake_rc_erpt(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
1188     fab_erpt_tbl_t *tbl)
1189 {
1190 	const char *class = tbl->err_class;
1191 	uint32_t rc_err_sts = 0;
1192 	int err = 0;
1193 
1194 	/*
1195 	 * Don't send this for PCI device or Root Ports.  Only send it on
1196 	 * systems with non-compliant RPs.
1197 	 */
1198 	if ((data->dev_type == PCIE_PCIECAP_DEV_TYPE_PCI_DEV) ||
1199 	    (data->dev_type == PCIE_PCIECAP_DEV_TYPE_ROOT) ||
1200 	    (!fab_xlate_fake_rp))
1201 		return (-1);
1202 
1203 	err = fab_prep_basic_erpt(hdl, data->nvl, erpt, B_TRUE);
1204 
1205 	/* Generate an ereport for this error bit. */
1206 	(void) snprintf(fab_buf, FM_MAX_CLASS, "ereport.io.%s.%s",
1207 	    PCIEX_ERROR_SUBCLASS, class);
1208 	(void) nvlist_add_string(erpt, FM_CLASS, fab_buf);
1209 
1210 	/* Send PCIe RC Ereports */
1211 	if (data->pcie_err_status & PCIE_DEVSTS_CE_DETECTED) {
1212 		rc_err_sts |= PCIE_AER_RE_STS_CE_RCVD;
1213 	}
1214 
1215 	/* NFE/FE src id takes precedence over CE src id */
1216 	if (data->pcie_err_status & PCIE_DEVSTS_NFE_DETECTED) {
1217 		rc_err_sts |= PCIE_AER_RE_STS_NFE_MSGS_RCVD;
1218 		rc_err_sts |= PCIE_AER_RE_STS_FE_NFE_RCVD;
1219 	}
1220 	if (data->pcie_err_status & PCIE_DEVSTS_FE_DETECTED) {
1221 		rc_err_sts |= PCIE_AER_RE_STS_FE_MSGS_RCVD;
1222 		rc_err_sts |= PCIE_AER_RE_STS_FE_NFE_RCVD;
1223 	}
1224 	if ((data->pcie_err_status & PCIE_DEVSTS_NFE_DETECTED) &&
1225 	    (data->pcie_err_status & PCIE_DEVSTS_FE_DETECTED)) {
1226 		rc_err_sts |= PCIE_AER_RE_STS_FIRST_UC_FATAL;
1227 		rc_err_sts |= PCIE_AER_RE_STS_MUL_FE_NFE_RCVD;
1228 	}
1229 
1230 	(void) nvlist_add_uint32(erpt, PCIEX_ROOT_ERRSTS_REG, rc_err_sts);
1231 
1232 	if (!(rc_err_sts & PCIE_AER_RE_STS_MUL_FE_NFE_RCVD)) {
1233 		(void) nvlist_add_uint16(erpt, PCIEX_SRC_ID, data->bdf);
1234 		(void) nvlist_add_boolean_value(erpt, PCIEX_SRC_VALID, B_TRUE);
1235 	}
1236 
1237 	return (err);
1238 }
1239 
1240 static int
1241 fab_xlate_fire_ce(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
1242     const char *class)
1243 {
1244 	fab_fire_tbl_t	*entry;
1245 	uint64_t	reg;
1246 
1247 	for (entry = fab_fire_pec_ce_tbl; entry->err_class; entry++) {
1248 		if (STRCMP(class, entry->err_class))
1249 			goto send;
1250 	}
1251 
1252 	return (0);
1253 
1254 send:
1255 	fmd_hdl_debug(hdl, "Translate Fire CE %s\n", class);
1256 
1257 	/* Fill in the device status register */
1258 	data->pcie_err_status = PCIE_DEVSTS_CE_DETECTED;
1259 
1260 	/* Fill in the AER CE register */
1261 	if (nvlist_lookup_uint64(erpt, "tlu-cess", &reg) == 0) {
1262 		data->pcie_ce_status = (uint32_t)reg | (uint32_t)(reg >> 32);
1263 	}
1264 
1265 	return (1);
1266 }
1267 
1268 static int
1269 fab_xlate_fire_ue(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
1270     const char *class)
1271 {
1272 	fab_fire_tbl_t	*entry;
1273 	uint64_t	reg;
1274 	uint32_t	temp;
1275 	pcie_tlp_hdr_t	*hdr;
1276 
1277 	for (entry = fab_fire_pec_ue_tbl; entry->err_class; entry++) {
1278 		if (STRCMP(class, entry->err_class))
1279 			goto send;
1280 	}
1281 
1282 	return (0);
1283 
1284 send:
1285 	fmd_hdl_debug(hdl, "Translate Fire UE %s\n", class);
1286 
1287 	/* Fill in PCI Status Register */
1288 	data->pci_err_status = entry->pci_err_sts;
1289 	data->pci_bdg_sec_stat = entry->pci_bdg_sts;
1290 
1291 	/* Fill in the device status register */
1292 	if (entry->fire_bit & data->pcie_ue_sev)
1293 		data->pcie_err_status = PCIE_DEVSTS_FE_DETECTED;
1294 	else
1295 		data->pcie_err_status = PCIE_DEVSTS_NFE_DETECTED;
1296 
1297 	if (entry->fire_bit == PCIE_AER_UCE_UR)
1298 		data->pcie_err_status |= PCIE_DEVSTS_UR_DETECTED;
1299 
1300 	/* Fill in the AER UE register */
1301 	if (nvlist_lookup_uint64(erpt, "tlu-uess", &reg) == 0) {
1302 		data->pcie_ue_status = (uint32_t)reg | (uint32_t)(reg >> 32);
1303 	}
1304 
1305 	/* Fill in the AER Control register */
1306 	if ((reg & (uint64_t)entry->fire_bit) &&
1307 	    nvlist_lookup_boolean(erpt, "primary")) {
1308 		temp = entry->fire_bit;
1309 		for (data->pcie_adv_ctl = (uint32_t)-1; temp;
1310 		    data->pcie_adv_ctl++)
1311 			temp = temp >> 1;
1312 	}
1313 
1314 	/* If CTO create target information */
1315 	if (entry->fire_bit == PCIE_AER_UCE_TO &&
1316 	    nvlist_lookup_boolean(erpt, "primary")) {
1317 		if (nvlist_lookup_uint64(erpt, "tlu-tueh1l", &reg) == 0) {
1318 			data->pcie_ue_hdr[0] = (uint32_t)(reg >> 32);
1319 			data->pcie_ue_hdr[1] = (uint32_t)(reg);
1320 		}
1321 		if (nvlist_lookup_uint64(erpt, "tlu-tueh2l", &reg) == 0) {
1322 			data->pcie_ue_hdr[2] = (uint32_t)(reg >> 32);
1323 			data->pcie_ue_hdr[3] = (uint32_t)(reg);
1324 		}
1325 
1326 		hdr = (pcie_tlp_hdr_t *)(&data->pcie_ue_hdr[0]);
1327 		switch (hdr->type) {
1328 		case PCIE_TLP_TYPE_IO:
1329 		case PCIE_TLP_TYPE_MEM:
1330 		case PCIE_TLP_TYPE_MEMLK:
1331 			data->pcie_ue_tgt_trans = PF_ADDR_PIO;
1332 			if (hdr->fmt & 0x1) {
1333 				data->pcie_ue_tgt_addr = reg;
1334 			} else {
1335 				data->pcie_ue_tgt_addr = data->pcie_ue_hdr[2];
1336 			}
1337 			break;
1338 		case PCIE_TLP_TYPE_CFG0:
1339 		case PCIE_TLP_TYPE_CFG1:
1340 			data->pcie_ue_tgt_trans = PF_ADDR_CFG;
1341 			data->pcie_ue_tgt_bdf = data->pcie_ue_hdr[2] >> 16;
1342 			break;
1343 		}
1344 	}
1345 
1346 	/* Fill in the AER Header registers */
1347 	if (nvlist_lookup_uint64(erpt, "tlu-rueh1l", &reg) == 0) {
1348 		data->pcie_ue_hdr[0] = (uint32_t)(reg >> 32);
1349 		data->pcie_ue_hdr[1] = (uint32_t)(reg);
1350 	}
1351 	if (nvlist_lookup_uint64(erpt, "tlu-rueh2l", &reg) == 0) {
1352 		data->pcie_ue_hdr[2] = (uint32_t)(reg >> 32);
1353 		data->pcie_ue_hdr[3] = (uint32_t)(reg);
1354 	}
1355 
1356 	return (1);
1357 }
1358 
1359 static int
1360 fab_xlate_fire_oe(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
1361     const char *class)
1362 {
1363 	fab_fire_tbl_t	*entry;
1364 	uint64_t	reg;
1365 
1366 	for (entry = fab_fire_pec_oe_tbl; entry->err_class; entry++) {
1367 		if (STRCMP(class, entry->err_class))
1368 			goto send;
1369 	}
1370 
1371 	return (0);
1372 
1373 send:
1374 	fmd_hdl_debug(hdl, "Translate Fire OE %s\n", class);
1375 
1376 	/* Fill in PCI Status Register */
1377 	if (entry->fire_bit) {
1378 		data->pci_err_status = entry->pci_err_sts;
1379 		data->pci_bdg_sec_stat = entry->pci_bdg_sts;
1380 	} else {
1381 		if (nvlist_lookup_uint64(erpt, "tlu-roeeh1l", &reg) == 0) {
1382 			data->pcie_ue_hdr[0] = (uint32_t)(reg >> 32);
1383 			data->pcie_ue_hdr[1] = (uint32_t)(reg);
1384 		}
1385 		if (nvlist_lookup_uint64(erpt, "tlu-roeeh2l", &reg) == 0) {
1386 			data->pcie_ue_hdr[2] = (uint32_t)(reg >> 32);
1387 			data->pcie_ue_hdr[3] = (uint32_t)(reg);
1388 		}
1389 
1390 		if (((pcie_tlp_hdr_t *)(&data->pcie_ue_hdr[0]))->type ==
1391 		    PCIE_TLP_TYPE_CPL) {
1392 			pcie_cpl_t *cpl = (pcie_cpl_t *)&data->pcie_ue_hdr[1];
1393 			switch (cpl->status) {
1394 			case PCIE_CPL_STS_UR:
1395 				data->pci_err_status = 0;
1396 				data->pci_bdg_sec_stat = PCI_STAT_R_MAST_AB |
1397 				    PCI_STAT_S_SYSERR;
1398 				break;
1399 			case PCIE_CPL_STS_CA:
1400 				data->pci_err_status = 0;
1401 				data->pci_bdg_sec_stat = PCI_STAT_R_TARG_AB |
1402 				    PCI_STAT_S_SYSERR;
1403 				break;
1404 			}
1405 		}
1406 	}
1407 
1408 	/* Fill in the device status register */
1409 	if (entry->fire_bit & data->pcie_ue_sev)
1410 		data->pcie_err_status = PCIE_DEVSTS_FE_DETECTED;
1411 	else
1412 		data->pcie_err_status = PCIE_DEVSTS_NFE_DETECTED;
1413 
1414 	/* Fill in the AER UE register */
1415 	data->pcie_ue_status = entry->fire_bit;
1416 
1417 	return (1);
1418 }
1419 
1420 static int
1421 fab_xlate_fire_dmc(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
1422     const char *class)
1423 {
1424 	fab_fire_tbl_t	*entry;
1425 	uint64_t	reg;
1426 	uint32_t	temp;
1427 
1428 	for (entry = fab_fire_dmc_tbl; entry->err_class; entry++) {
1429 		fmd_hdl_debug(hdl, "Matching %s\n", entry->err_class);
1430 		if (STRCMP(class, entry->err_class) &&
1431 		    nvlist_lookup_boolean(erpt, "primary"))
1432 				goto send;
1433 	}
1434 
1435 	return (0);
1436 
1437 send:
1438 	fmd_hdl_debug(hdl, "Translate Fire DMC %s\n", class);
1439 
1440 	/* Fill in PCI Status Register */
1441 	data->pci_err_status = entry->pci_err_sts;
1442 	data->pci_bdg_sec_stat = entry->pci_bdg_sts;
1443 
1444 	/* Fill in the device status register */
1445 	data->pcie_err_status = PCIE_DEVSTS_NFE_DETECTED;
1446 
1447 	/* Fill in the AER UE register */
1448 	data->pcie_ue_status = entry->fire_bit;
1449 
1450 	/* Fill in the AER Control register */
1451 	temp = entry->fire_bit;
1452 	for (data->pcie_adv_ctl = (uint32_t)-1; temp; data->pcie_adv_ctl++)
1453 		temp = temp >> 1;
1454 
1455 	/* Fill in the AER Header registers */
1456 	if (nvlist_lookup_uint64(erpt, "mmu-tfsr", &reg) == 0) {
1457 		fmd_hdl_debug(hdl, "tfsr 0x%llx\n", reg);
1458 		/* Get the trans type */
1459 		temp = (reg & 0x3F0000) >> 16;
1460 		data->pcie_ue_hdr[0] = (uint32_t)(temp << 24);
1461 		data->pcie_ue_tgt_trans = PF_ADDR_DMA;
1462 		/* Get the req id */
1463 		temp = (reg & 0xFFFF);
1464 		data->pcie_ue_hdr[1] = (uint32_t)(temp << 16);
1465 		data->pcie_ue_tgt_bdf = temp;
1466 	}
1467 
1468 	if (nvlist_lookup_uint64(erpt, "mmu-tfar", &reg) == 0) {
1469 		fmd_hdl_debug(hdl, "tfar 0x%llx\n", reg);
1470 		/* Get the address */
1471 		data->pcie_ue_hdr[2] = reg;
1472 		data->pcie_ue_hdr[3] = 0;
1473 		data->pcie_ue_tgt_addr = reg;
1474 	}
1475 
1476 	fmd_hdl_debug(hdl, "HEADER 0 0x%x\n", data->pcie_ue_hdr[0]);
1477 	fmd_hdl_debug(hdl, "HEADER 1 0x%x\n", data->pcie_ue_hdr[1]);
1478 	fmd_hdl_debug(hdl, "HEADER 2 0x%x\n", data->pcie_ue_hdr[2]);
1479 	fmd_hdl_debug(hdl, "HEADER 3 0x%x\n", data->pcie_ue_hdr[3]);
1480 
1481 	return (1);
1482 }
1483 
1484 static void
1485 fab_xlate_pcie_erpts(fmd_hdl_t *hdl, fab_data_t *data)
1486 {
1487 	fab_err_tbl_t *tbl;
1488 
1489 	fmd_hdl_debug(hdl, "Sending Ereports Now");
1490 
1491 	/* Go through the error logs and send the relavant reports */
1492 	for (tbl = fab_master_err_tbl; tbl->erpt_tbl; tbl++) {
1493 		fab_send_erpt(hdl, data, tbl);
1494 	}
1495 
1496 	/* Send PCI-X ECC Ereports */
1497 	fab_send_pcix_ecc_erpt(hdl, data);
1498 	fab_send_pcix_bdg_ecc_erpt(hdl, data);
1499 }
1500 
1501 static void
1502 fab_xlate_fire_erpts(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *nvl,
1503     const char *class)
1504 {
1505 	if (fmd_nvl_class_match(hdl, nvl, "ereport.io.fire.pec.*")) {
1506 		if (fab_xlate_fire_ce(hdl, data, nvl, class))
1507 			return;
1508 
1509 		if (fab_xlate_fire_ue(hdl, data, nvl, class))
1510 			return;
1511 
1512 		if (fab_xlate_fire_oe(hdl, data, nvl, class))
1513 			return;
1514 	} else if (fmd_nvl_class_match(hdl, nvl, "ereport.io.fire.dmc.*") ||
1515 	    fmd_nvl_class_match(hdl, nvl, "ereport.io.n2.dmu.*")) {
1516 		if (fab_xlate_fire_dmc(hdl, data, nvl, class))
1517 			return;
1518 	}
1519 }
1520 
1521 static void
1522 fab_update_topo(fmd_hdl_t *hdl)
1523 {
1524 	topo_hdl_t	*thp = NULL;
1525 	FILE		*fp;
1526 	int		err = 0;
1527 
1528 	if ((thp = fmd_hdl_topo_hold(hdl, TOPO_VERSION)) == NULL) {
1529 		fmd_hdl_debug(hdl, "Failed to hold topo\n");
1530 	}
1531 
1532 	fp = fopen(XMLTOPOFILE, "w");
1533 
1534 	if (topo_xml_print(thp, fp, FM_FMRI_SCHEME_HC, &err) < 0) {
1535 		fmd_hdl_debug(hdl, "Failed to get XML topo\n");
1536 	}
1537 
1538 	(void) fclose(fp);
1539 
1540 	fmd_hdl_topo_rele(hdl, thp);
1541 
1542 	if (fab_xpathCtx)
1543 		xmlXPathFreeContext(fab_xpathCtx);
1544 	if (fab_doc)
1545 		xmlFreeDoc(fab_doc);
1546 
1547 	/* Load xml document */
1548 	fab_doc = xmlParseFile(XMLTOPOFILE);
1549 
1550 	/* Init xpath */
1551 	fab_xpathCtx = xmlXPathNewContext(fab_doc);
1552 
1553 	fab_valid_topo = 1;
1554 }
1555 
1556 #define	FAB_HC2DEV_QUERY_SIZE_MIN 160
1557 #define	FAB_HC2DEV_QUERY_SIZE(sz) \
1558 	((sz + FAB_HC2DEV_QUERY_SIZE_MIN) * sizeof (char))
1559 
1560 static boolean_t
1561 fab_hc2dev(fmd_hdl_t *hdl, nvlist_t *detector, char **dev_path,
1562     uint_t *dev_path_size) {
1563 	xmlXPathObjectPtr xpathObj;
1564 	xmlNodeSetPtr	nodes;
1565 	char 		*query, *query_end, *temp;
1566 	uint_t 		i, size;
1567 	size_t		query_size = 0;
1568 	nvlist_t	**hcl;
1569 
1570 	if (nvlist_lookup_nvlist_array(detector, FM_FMRI_HC_LIST, &hcl,
1571 		&size) != 0)
1572 		goto fail;
1573 
1574 	for (i = 0; i < size; i++) {
1575 		if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &temp) != 0)
1576 			goto fail;
1577 		query_size += strlen(temp);
1578 		if (nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &temp) != 0)
1579 			goto fail;
1580 		query_size += strlen(temp);
1581 		/* Adjust for '=' and '/' later */
1582 		query_size += 2;
1583 	}
1584 
1585 	query = fmd_hdl_alloc(hdl, FAB_HC2DEV_QUERY_SIZE(query_size),
1586 	    FMD_SLEEP);
1587 	(void) sprintf(query, "//propval[@name='resource' and "
1588 	    "contains(substring(@value, string-length(@value) - %d), '",
1589 	    query_size);
1590 
1591 	query_end = query;
1592 	query_end += strlen(query);
1593 
1594 	for (i = 0; i < size; i++) {
1595 		(void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_NAME, &temp);
1596 		(void) snprintf(query_end, query_size, "%s=", temp);
1597 		query_end += strlen(temp) + 1;
1598 		(void) nvlist_lookup_string(hcl[i], FM_FMRI_HC_ID, &temp);
1599 		(void) snprintf(query_end, query_size, "%s", temp);
1600 		query_end += strlen(temp);
1601 		if (i != (size - 1)) {
1602 			(void) sprintf(query_end++, "/");
1603 		}
1604 	}
1605 
1606 	(void) sprintf(query_end, "')]/parent::*/following-sibling::*/"
1607 	    "propval[@name='dev']/@value");
1608 
1609 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
1610 
1611 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query,
1612 	    fab_xpathCtx);
1613 	fmd_hdl_free(hdl, query, FAB_HC2DEV_QUERY_SIZE(query_size));
1614 
1615 	if (xpathObj == NULL)
1616 		goto fail;
1617 
1618 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d\n", xpathObj,
1619 	    xpathObj->type);
1620 	nodes = xpathObj->nodesetval;
1621 
1622 	if (nodes) {
1623 		temp = (char *)xmlNodeGetContent(nodes->nodeTab[0]);
1624 		fmd_hdl_debug(hdl, "HC Dev Path: %s\n", temp);
1625 		*dev_path_size = strlen(temp) + 1;
1626 		*dev_path = fmd_hdl_alloc(hdl, *dev_path_size, FMD_SLEEP);
1627 		(void) strlcpy(*dev_path, (char *)temp, *dev_path_size);
1628 		xmlFree(temp);
1629 		xmlXPathFreeObject(xpathObj);
1630 		return (B_TRUE);
1631 	}
1632 	xmlXPathFreeObject(xpathObj);
1633 fail:
1634 	return (B_FALSE);
1635 }
1636 
1637 /* ARGSUSED */
1638 static boolean_t
1639 fab_get_rcpath(fmd_hdl_t *hdl, nvlist_t *nvl, char *rcpath) {
1640 	nvlist_t	*detector;
1641 	char		*path, *scheme;
1642 	uint_t		size;
1643 
1644 	if (nvlist_lookup_nvlist(nvl, FM_EREPORT_DETECTOR, &detector) != 0)
1645 		goto fail;
1646 	if (nvlist_lookup_string(detector, FM_FMRI_SCHEME, &scheme) != 0)
1647 		goto fail;
1648 
1649 	if (STRCMP(scheme, FM_FMRI_SCHEME_DEV)) {
1650 		if (nvlist_lookup_string(detector, FM_FMRI_DEV_PATH,
1651 			&path) != 0)
1652 			goto fail;
1653 		(void) strncpy(rcpath, path, FM_MAX_CLASS);
1654 	} else if (STRCMP(scheme, FM_FMRI_SCHEME_HC)) {
1655 		/*
1656 		 * This should only occur for ereports that come from the RC
1657 		 * itself.  In this case convert HC scheme to dev path.
1658 		 */
1659 		if (fab_hc2dev(hdl, detector, &path, &size)) {
1660 			(void) strncpy(rcpath, path, FM_MAX_CLASS);
1661 			fmd_hdl_free(hdl, path, size);
1662 		} else {
1663 			goto fail;
1664 		}
1665 	} else {
1666 		return (B_FALSE);
1667 	}
1668 
1669 	/*
1670 	 * Extract the RC path by taking the first device in the dev path
1671 	 *
1672 	 * /pci@0,0/pci8086,3605@2/pci8086,3500@0/pci8086,3514@1/pci8086,105e@0
1673 	 * - to -
1674 	 * /pci@0,0
1675 	 */
1676 	path = strchr(rcpath + 1, '/');
1677 	if (path)
1678 		path[0] = '\0';
1679 
1680 	return (B_TRUE);
1681 fail:
1682 	return (B_FALSE);
1683 }
1684 
1685 static char *
1686 fab_find_bdf(fmd_hdl_t *hdl, nvlist_t *nvl, pcie_req_id_t bdf) {
1687 	xmlXPathObjectPtr xpathObj;
1688 	xmlNodeSetPtr	nodes;
1689 	xmlChar 	*retval;
1690 	char		query[500];
1691 	int		bus, dev, fn;
1692 	char		rcpath[255];
1693 
1694 	if (bdf != (uint16_t)-1) {
1695 		bus = (bdf & PCIE_REQ_ID_BUS_MASK) >> PCIE_REQ_ID_BUS_SHIFT;
1696 		dev = (bdf & PCIE_REQ_ID_DEV_MASK) >> PCIE_REQ_ID_DEV_SHIFT;
1697 		fn = (bdf & PCIE_REQ_ID_FUNC_MASK) >> PCIE_REQ_ID_FUNC_SHIFT;
1698 	}
1699 
1700 	if (!fab_get_rcpath(hdl, nvl, rcpath))
1701 		goto fail;
1702 
1703 	/*
1704 	 * Explanation of the XSL XPATH Query
1705 	 * Line 1: Look at all nodes with the node name "propval"
1706 	 * Line 2-3: See if the "value" of the node ends with correct PCIEx BDF
1707 	 * Line 4-5: See if the "value" of the node ends with correct PCI BDF
1708 	 * Line 6: Go up one level to the parent of the current node
1709 	 * Line 7: See if child node contains "ASRU" with the same PCIe Root
1710 	 * Line 8: Traverse up the parent and the other siblings and look for
1711 	 *	   the io "propgroup" and get the value of the dev "propval"
1712 	 */
1713 	(void) snprintf(query, sizeof (query), "//propval["
1714 	    "contains(substring(@value, string-length(@value) - 34), "
1715 	    "'pciexbus=%d/pciexdev=%d/pciexfn=%d') or "
1716 	    "contains(substring(@value, string-length(@value) - 28), "
1717 	    "'pcibus=%d/pcidev=%d/pcifn=%d')"
1718 	    "]/parent::"
1719 	    "*/propval[@name='ASRU' and contains(@value, '%s')]"
1720 	    "/parent::*/following-sibling::*[@name='io']/propval[@name='dev']/"
1721 	    "@value", bus, dev, fn, bus, dev, fn, rcpath);
1722 
1723 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
1724 
1725 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query, fab_xpathCtx);
1726 
1727 	if (xpathObj == NULL)
1728 		goto fail;
1729 
1730 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d\n", xpathObj, xpathObj->type);
1731 
1732 	nodes = xpathObj->nodesetval;
1733 	if (nodes) {
1734 		retval = xmlNodeGetContent(nodes->nodeTab[0]);
1735 		fmd_hdl_debug(hdl, "BDF Dev Path: %s\n", retval);
1736 		xmlXPathFreeObject(xpathObj);
1737 		return ((char *)retval);
1738 	}
1739 fail:
1740 	return (NULL);
1741 }
1742 
1743 static char *
1744 fab_find_addr(fmd_hdl_t *hdl, nvlist_t *nvl, uint64_t addr) {
1745 	xmlXPathObjectPtr xpathObj;
1746 	xmlNodeSetPtr nodes;
1747 	xmlNodePtr devNode;
1748 	char *retval;
1749 	char query[500];
1750 	int size, i, j;
1751 	uint32_t prop[50];
1752 	char *token;
1753 	pci_regspec_t *assign_p;
1754 	uint64_t low, hi;
1755 	char rcpath[255];
1756 
1757 	if (!fab_get_rcpath(hdl, nvl, rcpath))
1758 		goto fail;
1759 
1760 	(void) snprintf(query, sizeof (query), "//propval["
1761 	    "@name='ASRU' and contains(@value, '%s')]/"
1762 	    "parent::*/following-sibling::*[@name='pci']/"
1763 	    "propval[@name='assigned-addresses']", rcpath);
1764 
1765 	fmd_hdl_debug(hdl, "xpathObj query %s\n", query);
1766 
1767 	xpathObj = xmlXPathEvalExpression((const xmlChar *)query, fab_xpathCtx);
1768 
1769 	if (xpathObj == NULL)
1770 		goto fail;
1771 
1772 	fmd_hdl_debug(hdl, "xpathObj 0x%p type %d\n", xpathObj, xpathObj->type);
1773 
1774 	nodes = xpathObj->nodesetval;
1775 	size = (nodes) ? nodes->nodeNr : 0;
1776 
1777 	/* Decode the list of assigned addresses xml nodes for each device */
1778 	for (i = 0; i < size; i++) {
1779 		char *tprop;
1780 
1781 		devNode = nodes->nodeTab[i];
1782 		if (!HAS_PROP(devNode, "value"))
1783 			continue;
1784 
1785 		/* Convert "string" assigned-addresses to pci_regspec_t */
1786 		j = 0;
1787 		tprop = GET_PROP(devNode, "value");
1788 		for (token = strtok(tprop, " "); token;
1789 		    token = strtok(NULL, " ")) {
1790 			prop[j++] = strtoul(token, (char **)NULL, 16);
1791 		}
1792 		prop[j] = (uint32_t)-1;
1793 		FREE_PROP(tprop);
1794 
1795 		/* Check if address belongs to this device */
1796 		for (assign_p = (pci_regspec_t *)prop;
1797 		    assign_p->pci_phys_hi != (uint_t)-1; assign_p++) {
1798 			low = assign_p->pci_phys_low;
1799 			hi = low + assign_p->pci_size_low;
1800 			if ((addr < hi) && (addr >= low)) {
1801 				fmd_hdl_debug(hdl, "Found Address\n");
1802 				goto found;
1803 			}
1804 		}
1805 	}
1806 	goto fail;
1807 
1808 found:
1809 	/* Traverse up the xml tree and back down to find the right propgroup */
1810 	for (devNode = devNode->parent->parent->children;
1811 	    devNode; devNode = devNode->next) {
1812 		char	*tprop;
1813 
1814 		tprop = GET_PROP(devNode, "name");
1815 		if (STRCMP(devNode->name, "propgroup") &&
1816 		    STRCMP(tprop, "io")) {
1817 			FREE_PROP(tprop);
1818 			goto propgroup;
1819 		}
1820 		FREE_PROP(tprop);
1821 	}
1822 	goto fail;
1823 
1824 propgroup:
1825 	/* Retrive the "dev" propval and return */
1826 	for (devNode = devNode->children; devNode; devNode = devNode->next) {
1827 		char	*tprop;
1828 
1829 		tprop = GET_PROP(devNode, "name");
1830 		if (STRCMP(devNode->name, "propval") &&
1831 		    STRCMP(tprop, "dev")) {
1832 			FREE_PROP(tprop);
1833 			retval = GET_PROP(devNode, "value");
1834 			fmd_hdl_debug(hdl, "Addr Dev Path: %s\n", retval);
1835 			xmlXPathFreeObject(xpathObj);
1836 			return (retval);
1837 		}
1838 		FREE_PROP(tprop);
1839 	}
1840 fail:
1841 	if (xpathObj != NULL)
1842 		xmlXPathFreeObject(xpathObj);
1843 	return (NULL);
1844 }
1845 
1846 static void
1847 fab_pr(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl) {
1848 	nvpair_t *nvp;
1849 
1850 	for (nvp = nvlist_next_nvpair(nvl, NULL);
1851 	    nvp != NULL;
1852 	    nvp = nvlist_next_nvpair(nvl, nvp)) {
1853 
1854 		data_type_t type = nvpair_type(nvp);
1855 		const char *name = nvpair_name(nvp);
1856 
1857 		boolean_t b;
1858 		uint8_t i8;
1859 		uint16_t i16;
1860 		uint32_t i32;
1861 		uint64_t i64;
1862 		char *str;
1863 		nvlist_t *cnv;
1864 
1865 		nvlist_t **nvlarr;
1866 		uint_t arrsize;
1867 		int arri;
1868 
1869 
1870 		if (STRCMP(name, FM_CLASS))
1871 			continue; /* already printed by caller */
1872 
1873 		fmd_hdl_debug(hdl, " %s=", name);
1874 
1875 		switch (type) {
1876 		case DATA_TYPE_BOOLEAN:
1877 			fmd_hdl_debug(hdl, "DATA_TYPE_BOOLEAN 1");
1878 			break;
1879 
1880 		case DATA_TYPE_BOOLEAN_VALUE:
1881 			(void) nvpair_value_boolean_value(nvp, &b);
1882 			fmd_hdl_debug(hdl, "DATA_TYPE_BOOLEAN_VALUE %d",
1883 			    b ? "1" : "0");
1884 			break;
1885 
1886 		case DATA_TYPE_BYTE:
1887 			(void) nvpair_value_byte(nvp, &i8);
1888 			fmd_hdl_debug(hdl, "DATA_TYPE_BYTE 0x%x", i8);
1889 			break;
1890 
1891 		case DATA_TYPE_INT8:
1892 			(void) nvpair_value_int8(nvp, (void *)&i8);
1893 			fmd_hdl_debug(hdl, "DATA_TYPE_INT8 0x%x", i8);
1894 			break;
1895 
1896 		case DATA_TYPE_UINT8:
1897 			(void) nvpair_value_uint8(nvp, &i8);
1898 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT8 0x%x", i8);
1899 			break;
1900 
1901 		case DATA_TYPE_INT16:
1902 			(void) nvpair_value_int16(nvp, (void *)&i16);
1903 			fmd_hdl_debug(hdl, "DATA_TYPE_INT16 0x%x", i16);
1904 			break;
1905 
1906 		case DATA_TYPE_UINT16:
1907 			(void) nvpair_value_uint16(nvp, &i16);
1908 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT16 0x%x", i16);
1909 			break;
1910 
1911 		case DATA_TYPE_INT32:
1912 			(void) nvpair_value_int32(nvp, (void *)&i32);
1913 			fmd_hdl_debug(hdl, "DATA_TYPE_INT32 0x%x", i32);
1914 			break;
1915 
1916 		case DATA_TYPE_UINT32:
1917 			(void) nvpair_value_uint32(nvp, &i32);
1918 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT32 0x%x", i32);
1919 			break;
1920 
1921 		case DATA_TYPE_INT64:
1922 			(void) nvpair_value_int64(nvp, (void *)&i64);
1923 			fmd_hdl_debug(hdl, "DATA_TYPE_INT64 0x%llx",
1924 			    (u_longlong_t)i64);
1925 			break;
1926 
1927 		case DATA_TYPE_UINT64:
1928 			(void) nvpair_value_uint64(nvp, &i64);
1929 			fmd_hdl_debug(hdl, "DATA_TYPE_UINT64 0x%llx",
1930 			    (u_longlong_t)i64);
1931 			break;
1932 
1933 		case DATA_TYPE_HRTIME:
1934 			(void) nvpair_value_hrtime(nvp, (void *)&i64);
1935 			fmd_hdl_debug(hdl, "DATA_TYPE_HRTIME 0x%llx",
1936 			    (u_longlong_t)i64);
1937 			break;
1938 
1939 		case DATA_TYPE_STRING:
1940 			(void) nvpair_value_string(nvp, &str);
1941 			fmd_hdl_debug(hdl, "DATA_TYPE_STRING \"%s\"",
1942 			    str ? str : "<NULL>");
1943 			break;
1944 
1945 		case DATA_TYPE_NVLIST:
1946 			fmd_hdl_debug(hdl, "[");
1947 			(void) nvpair_value_nvlist(nvp, &cnv);
1948 			fab_pr(hdl, NULL, cnv);
1949 			fmd_hdl_debug(hdl, " ]");
1950 			break;
1951 
1952 		case DATA_TYPE_BOOLEAN_ARRAY:
1953 		case DATA_TYPE_BYTE_ARRAY:
1954 		case DATA_TYPE_INT8_ARRAY:
1955 		case DATA_TYPE_UINT8_ARRAY:
1956 		case DATA_TYPE_INT16_ARRAY:
1957 		case DATA_TYPE_UINT16_ARRAY:
1958 		case DATA_TYPE_INT32_ARRAY:
1959 		case DATA_TYPE_UINT32_ARRAY:
1960 		case DATA_TYPE_INT64_ARRAY:
1961 		case DATA_TYPE_UINT64_ARRAY:
1962 		case DATA_TYPE_STRING_ARRAY:
1963 			fmd_hdl_debug(hdl, "[...]");
1964 			break;
1965 		case DATA_TYPE_NVLIST_ARRAY:
1966 			arrsize = 0;
1967 			(void) nvpair_value_nvlist_array(nvp, &nvlarr,
1968 			    &arrsize);
1969 
1970 			for (arri = 0; arri < arrsize; arri++) {
1971 				fab_pr(hdl, ep, nvlarr[arri]);
1972 			}
1973 
1974 			break;
1975 		case DATA_TYPE_UNKNOWN:
1976 			fmd_hdl_debug(hdl, "<unknown>");
1977 			break;
1978 		}
1979 	}
1980 }
1981 
1982 /*ARGSUSED*/
1983 static void
1984 fab_recv(fmd_hdl_t *hdl, fmd_event_t *ep, nvlist_t *nvl, const char *class)
1985 {
1986 	fab_data_t fab_data = {0};
1987 
1988 	if (!fab_valid_topo)
1989 		fab_update_topo(hdl);
1990 
1991 	if (fmd_nvl_class_match(hdl, nvl, "ereport.io.pci.fabric")) {
1992 		fmd_hdl_debug(hdl, "PCI ereport received: %s\n", class);
1993 		fab_pci_fabric_to_data(hdl, nvl, &fab_data);
1994 		fab_xlate_pcie_erpts(hdl, &fab_data);
1995 	} else {
1996 		fab_pr(hdl, ep, nvl);
1997 		fmd_hdl_debug(hdl, "Fire RC ereport received: %s\n", class);
1998 		fab_fire_to_data(hdl, nvl, &fab_data);
1999 		fab_xlate_fire_erpts(hdl, &fab_data, nvl, class);
2000 		fab_xlate_pcie_erpts(hdl, &fab_data);
2001 	}
2002 }
2003 
2004 /* ARGSUSED */
2005 static void
2006 fab_topo(fmd_hdl_t *hdl, topo_hdl_t *topo)
2007 {
2008 	fab_valid_topo = 0;
2009 }
2010 
2011 static const fmd_hdl_ops_t fmd_ops = {
2012 	fab_recv,	/* fmdo_recv */
2013 	NULL,		/* fmdo_timeout */
2014 	NULL,		/* fmdo_close */
2015 	NULL,		/* fmdo_stats */
2016 	NULL,		/* fmdo_gc */
2017 	NULL,		/* fmdo_send */
2018 	fab_topo,	/* fmdo_topo */
2019 };
2020 
2021 static const fmd_hdl_info_t fmd_info = {
2022 	"Fabric Ereport Translater", "1.0", &fmd_ops, NULL
2023 };
2024 
2025 #define	REG_OFF(reg) ((uint32_t)(uint32_t)&fab_data.reg - (uint32_t)&fab_data)
2026 #define	SET_TBL(n, err, reg, sz) \
2027 	fab_master_err_tbl[n].erpt_tbl = fab_ ## err ## _erpt_tbl; \
2028 	fab_master_err_tbl[n].reg_offset = REG_OFF(reg); \
2029 	fab_master_err_tbl[n].reg_size = sz; \
2030 	fab_master_err_tbl[n].fab_prep = fab_prep_ ## err ## _erpt;
2031 
2032 void
2033 _fmd_init(fmd_hdl_t *hdl)
2034 {
2035 	fab_data_t fab_data;
2036 
2037 	if (fmd_hdl_register(hdl, FMD_API_VERSION, &fmd_info) != 0)
2038 		return;
2039 
2040 	/* Init libxml */
2041 	xmlInitParser();
2042 
2043 	fab_fmd_xprt = fmd_xprt_open(hdl, FMD_XPRT_RDONLY, NULL, NULL);
2044 	fmd_hdl_debug(hdl, "Fabric Translater Started\n");
2045 
2046 	/* Setup the master error table */
2047 	fab_master_err_tbl = (fab_err_tbl_t *)calloc(13,
2048 	    sizeof (fab_err_tbl_t));
2049 
2050 	SET_TBL(0, pci,			pci_err_status,	    16);
2051 	SET_TBL(1, pci_bdg,		pci_bdg_sec_stat,   16);
2052 	SET_TBL(2, pci_bdg_ctl,		pci_bdg_ctrl,	    16);
2053 	SET_TBL(3, pcie_ce,		pcie_ce_status,	    32);
2054 	SET_TBL(4, pcie_ue,		pcie_ue_status,	    32);
2055 	SET_TBL(5, pcie_sue,		pcie_sue_status,    32);
2056 	SET_TBL(6, pcix,		pcix_status,	    32);
2057 	SET_TBL(7, pcix_bdg_sec,	pcix_bdg_sec_stat,  16);
2058 	SET_TBL(8, pcix_bdg,		pcix_bdg_stat,	    32);
2059 	SET_TBL(9, pcie_nadv,		pcie_err_status,    16);
2060 	SET_TBL(10, pcie_rc,		pcie_rp_err_status, 32);
2061 	SET_TBL(11, pcie_fake_rc,	pcie_err_status,    16);
2062 }
2063 
2064 void
2065 _fmd_fini(fmd_hdl_t *hdl)
2066 {
2067 	/* Fini xpath */
2068 	if (fab_xpathCtx)
2069 		xmlXPathFreeContext(fab_xpathCtx);
2070 	/* Free xml document */
2071 	if (fab_doc)
2072 		xmlFreeDoc(fab_doc);
2073 	/* Fini libxml */
2074 	xmlCleanupParser();
2075 
2076 	fmd_xprt_close(hdl, fab_fmd_xprt);
2077 }
2078