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