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 <strings.h>
27 #include <sys/fm/io/sun4_fire.h>
28 
29 #include "fabric-xlate.h"
30 
31 typedef struct fab_fire_tbl {
32 	const char	*err_class;
33 	uint32_t	fire_bit;	/* Fire error bit */
34 	uint16_t	pci_err_sts;	/* Equivalent PCI Error Status */
35 	uint16_t	pci_bdg_sts;	/* Equivalent PCI Bridge Status */
36 } fab_fire_tbl_t;
37 
38 /*
39  * Translation tables for converting fire error bits into "pci" ereports.
40  * <Fire Bit>
41  * <pci ereport Class>
42  * <pci error status reg>
43  * <pci bridge status reg>
44  * <pci target class>
45  */
46 #define	FAB_FIRE_PEC_BIT(fb) "ereport.io." PCIEX_FIRE "." FIRE_PEC_ ## fb
47 #define	FAB_FIRE_DMC_BIT(fb) "ereport.io." PCIEX_FIRE "." FIRE_DMC_ ## fb
48 #define	FAB_N2_DMU_BIT(fb) "ereport.io.n2.dmu." fb
49 #define	FAB_OB_PEC_BIT(fb) "ereport.io." PCIEX_OBERON "." FIRE_PEC_ ## fb
50 
51 #define	FAB_FIRE_UE(fb, bit, sts, bdg) \
52 	FAB_FIRE_PEC_BIT(fb), PCIE_AER_UCE_ ## bit, sts, bdg
53 #define	FAB_OB_UE(fb, bit, sts, bdg) \
54 	FAB_OB_PEC_BIT(fb), PCIE_AER_UCE_ ## bit, sts, bdg
55 static fab_fire_tbl_t fab_fire_pec_ue_tbl[] = {
56 	FAB_FIRE_UE(UR,	 UR,	   PCI_STAT_S_SYSERR,	0),
57 	FAB_FIRE_UE(UC,	 UC,	   PCI_STAT_S_SYSERR,	0),
58 	FAB_OB_UE(ECRC,	 ECRC,	   PCI_STAT_S_SYSERR,	0),
59 	FAB_FIRE_UE(CTO, TO,	   PCI_STAT_S_SYSERR,	0),
60 	FAB_FIRE_UE(ROF, RO,	   PCI_STAT_S_SYSERR,	0),
61 	FAB_FIRE_UE(MFP, MTLP,	   PCI_STAT_S_SYSERR,	0),
62 	FAB_FIRE_UE(PP,	 PTLP,	   PCI_STAT_S_PERROR,
63 	    (PCI_STAT_S_SYSERR | PCI_STAT_PERROR)),
64 	FAB_FIRE_UE(FCP, FCP,	   PCI_STAT_S_SYSERR,	0),
65 	FAB_FIRE_UE(DLP, DLP,	   PCI_STAT_S_SYSERR,	0),
66 	FAB_FIRE_UE(TE,	 TRAINING, PCI_STAT_S_SYSERR,	0),
67 	FAB_FIRE_UE(CA,	 CA,	   PCI_STAT_S_TARG_AB,
68 	    PCI_STAT_S_TARG_AB),
69 	NULL, 0, 0,
70 };
71 
72 #define	FAB_FIRE_CE(fb, bit) \
73 	FAB_FIRE_PEC_BIT(fb), PCIE_AER_CE_ ## bit, 0, 0
74 static fab_fire_tbl_t fab_fire_pec_ce_tbl[] = {
75 	FAB_FIRE_CE(RTO,	REPLAY_TO),
76 	FAB_FIRE_CE(RNR,	REPLAY_ROLLOVER),
77 	FAB_FIRE_CE(BDP,	BAD_DLLP),
78 	FAB_FIRE_CE(BTP,	BAD_TLP),
79 	FAB_FIRE_CE(RE,		RECEIVER_ERR),
80 	NULL, 0, 0,
81 };
82 
83 /*
84  * WUC/RUC will need to be special cased for the target ereports, because you
85  * need to decode the tlp log.
86  */
87 #define	FAB_FIRE_WUCRUC(fb) \
88 	FAB_FIRE_PEC_BIT(fb), 0, 0, (PCI_STAT_R_MAST_AB | PCI_STAT_S_SYSERR)
89 #define	FAB_FIRE_OE(fb, bit) \
90 	FAB_FIRE_PEC_BIT(fb), PCIE_AER_UCE_ ## bit, PCI_STAT_S_SYSERR, 0
91 #define	FAB_OB_OE(fb, bit) \
92 	FAB_FIRE_PEC_BIT(fb), PCIE_AER_UCE_ ## bit, PCI_STAT_S_SYSERR, 0
93 static fab_fire_tbl_t fab_fire_pec_oe_tbl[] = {
94 	FAB_FIRE_WUCRUC(WUC),
95 	FAB_FIRE_WUCRUC(RUC),
96 	FAB_FIRE_OE(ERU, DLP),
97 	FAB_FIRE_OE(ERO, DLP),
98 	FAB_FIRE_OE(EMP, DLP),
99 	FAB_FIRE_OE(EPE, DLP),
100 	NULL, 0, 0,
101 };
102 
103 #define	FAB_FIRE_DMC(fb) \
104 	FAB_FIRE_DMC_BIT(fb), PCIE_AER_UCE_CA, 0, PCI_STAT_S_TARG_AB
105 #define	FAB_N2_DMU(fb) \
106 	FAB_N2_DMU_BIT(fb), PCIE_AER_UCE_CA, 0, PCI_STAT_S_TARG_AB
107 static fab_fire_tbl_t fab_fire_dmc_tbl[] = {
108 	FAB_FIRE_DMC(BYP_ERR),
109 	FAB_FIRE_DMC(BYP_OOR),
110 	FAB_FIRE_DMC(TRN_OOR),
111 	FAB_FIRE_DMC(TTE_INV),
112 	FAB_FIRE_DMC(TTE_PRT),
113 	FAB_N2_DMU("iotsbdesc_inv"),
114 	FAB_N2_DMU("sun4v_adj_va_uf"),
115 	FAB_N2_DMU("sun4v_inv_pg_sz"),
116 	FAB_N2_DMU("sun4v_key_err"),
117 	FAB_N2_DMU("sun4v_va_oor"),
118 	NULL, 0, 0
119 };
120 
121 /* ARGSUSED */
122 static void
fab_fire_to_data(fmd_hdl_t * hdl,nvlist_t * nvl,fab_data_t * data)123 fab_fire_to_data(fmd_hdl_t *hdl, nvlist_t *nvl, fab_data_t *data)
124 {
125 	data->nvl = nvl;
126 
127 	/* Always Root Complex */
128 	data->dev_type = PCIE_PCIECAP_DEV_TYPE_ROOT;
129 
130 	data->pcie_ue_sev = (PCIE_AER_UCE_DLP | PCIE_AER_UCE_SD |
131 	    PCIE_AER_UCE_FCP | PCIE_AER_UCE_RO | PCIE_AER_UCE_MTLP);
132 }
133 
134 static int
fab_xlate_fire_ce(fmd_hdl_t * hdl,fab_data_t * data,nvlist_t * erpt,const char * class)135 fab_xlate_fire_ce(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
136     const char *class)
137 {
138 	fab_fire_tbl_t	*entry;
139 	uint64_t	reg;
140 
141 	for (entry = fab_fire_pec_ce_tbl; entry->err_class; entry++) {
142 		if (STRCMP(class, entry->err_class))
143 			goto send;
144 	}
145 
146 	return (0);
147 
148 send:
149 	fmd_hdl_debug(hdl, "Translate Fire CE %s\n", class);
150 
151 	/* Fill in the device status register */
152 	data->pcie_err_status = PCIE_DEVSTS_CE_DETECTED;
153 
154 	/* Fill in the AER CE register */
155 	if (nvlist_lookup_uint64(erpt, "tlu-cess", &reg) == 0) {
156 		data->pcie_ce_status = (uint32_t)reg | (uint32_t)(reg >> 32);
157 	}
158 
159 	return (1);
160 }
161 
162 static int
fab_xlate_fire_ue(fmd_hdl_t * hdl,fab_data_t * data,nvlist_t * erpt,const char * class)163 fab_xlate_fire_ue(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
164     const char *class)
165 {
166 	fab_fire_tbl_t	*entry;
167 	uint64_t	reg;
168 	uint32_t	temp;
169 	pcie_tlp_hdr_t	*hdr;
170 
171 	for (entry = fab_fire_pec_ue_tbl; entry->err_class; entry++) {
172 		if (STRCMP(class, entry->err_class))
173 			goto send;
174 	}
175 
176 	return (0);
177 
178 send:
179 	fmd_hdl_debug(hdl, "Translate Fire UE %s\n", class);
180 
181 	/* Fill in PCI Status Register */
182 	data->pci_err_status = entry->pci_err_sts;
183 	data->pci_bdg_sec_stat = entry->pci_bdg_sts;
184 
185 	/* Fill in the device status register */
186 	if (entry->fire_bit & data->pcie_ue_sev)
187 		data->pcie_err_status = PCIE_DEVSTS_FE_DETECTED;
188 	else
189 		data->pcie_err_status = PCIE_DEVSTS_NFE_DETECTED;
190 
191 	if (entry->fire_bit == PCIE_AER_UCE_UR)
192 		data->pcie_err_status |= PCIE_DEVSTS_UR_DETECTED;
193 
194 	/* Fill in the AER UE register */
195 	if (nvlist_lookup_uint64(erpt, "tlu-uess", &reg) == 0) {
196 		data->pcie_ue_status = (uint32_t)reg | (uint32_t)(reg >> 32);
197 	}
198 
199 	/* Fill in the AER Control register */
200 	if ((reg & (uint64_t)entry->fire_bit) &&
201 	    nvlist_lookup_boolean(erpt, "primary")) {
202 		temp = entry->fire_bit;
203 		for (data->pcie_adv_ctl = (uint32_t)-1; temp;
204 		    data->pcie_adv_ctl++)
205 			temp = temp >> 1;
206 	}
207 
208 	/* If CTO create target information */
209 	if (entry->fire_bit == PCIE_AER_UCE_TO &&
210 	    nvlist_lookup_boolean(erpt, "primary")) {
211 		if (nvlist_lookup_uint64(erpt, "tlu-tueh1l", &reg) == 0) {
212 			data->pcie_ue_hdr[0] = (uint32_t)(reg >> 32);
213 			data->pcie_ue_hdr[1] = (uint32_t)(reg);
214 		}
215 		if (nvlist_lookup_uint64(erpt, "tlu-tueh2l", &reg) == 0) {
216 			data->pcie_ue_hdr[2] = (uint32_t)(reg >> 32);
217 			data->pcie_ue_hdr[3] = (uint32_t)(reg);
218 		}
219 
220 		hdr = (pcie_tlp_hdr_t *)(&data->pcie_ue_hdr[0]);
221 		switch (hdr->type) {
222 		case PCIE_TLP_TYPE_IO:
223 		case PCIE_TLP_TYPE_MEM:
224 		case PCIE_TLP_TYPE_MEMLK:
225 			data->pcie_ue_tgt_trans = PF_ADDR_PIO;
226 			if (hdr->fmt & 0x1) {
227 				data->pcie_ue_tgt_addr = reg;
228 			} else {
229 				data->pcie_ue_tgt_addr = data->pcie_ue_hdr[2];
230 			}
231 			break;
232 		case PCIE_TLP_TYPE_CFG0:
233 		case PCIE_TLP_TYPE_CFG1:
234 			data->pcie_ue_tgt_trans = PF_ADDR_CFG;
235 			data->pcie_ue_tgt_bdf = data->pcie_ue_hdr[2] >> 16;
236 			break;
237 		}
238 	}
239 
240 	/* Fill in the AER Header registers */
241 	if (nvlist_lookup_uint64(erpt, "tlu-rueh1l", &reg) == 0) {
242 		data->pcie_ue_hdr[0] = (uint32_t)(reg >> 32);
243 		data->pcie_ue_hdr[1] = (uint32_t)(reg);
244 	}
245 	if (nvlist_lookup_uint64(erpt, "tlu-rueh2l", &reg) == 0) {
246 		data->pcie_ue_hdr[2] = (uint32_t)(reg >> 32);
247 		data->pcie_ue_hdr[3] = (uint32_t)(reg);
248 	}
249 
250 	return (1);
251 }
252 
253 static int
fab_xlate_fire_oe(fmd_hdl_t * hdl,fab_data_t * data,nvlist_t * erpt,const char * class)254 fab_xlate_fire_oe(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
255     const char *class)
256 {
257 	fab_fire_tbl_t	*entry;
258 	uint64_t	reg;
259 
260 	for (entry = fab_fire_pec_oe_tbl; entry->err_class; entry++) {
261 		if (STRCMP(class, entry->err_class))
262 			goto send;
263 	}
264 
265 	return (0);
266 
267 send:
268 	fmd_hdl_debug(hdl, "Translate Fire OE %s\n", class);
269 
270 	/* Fill in PCI Status Register */
271 	if (entry->fire_bit) {
272 		data->pci_err_status = entry->pci_err_sts;
273 		data->pci_bdg_sec_stat = entry->pci_bdg_sts;
274 	} else {
275 		if (nvlist_lookup_uint64(erpt, "tlu-roeeh1l", &reg) == 0) {
276 			data->pcie_ue_hdr[0] = (uint32_t)(reg >> 32);
277 			data->pcie_ue_hdr[1] = (uint32_t)(reg);
278 		}
279 		if (nvlist_lookup_uint64(erpt, "tlu-roeeh2l", &reg) == 0) {
280 			data->pcie_ue_hdr[2] = (uint32_t)(reg >> 32);
281 			data->pcie_ue_hdr[3] = (uint32_t)(reg);
282 		}
283 
284 		if (((pcie_tlp_hdr_t *)(&data->pcie_ue_hdr[0]))->type ==
285 		    PCIE_TLP_TYPE_CPL) {
286 			pcie_cpl_t *cpl = (pcie_cpl_t *)&data->pcie_ue_hdr[1];
287 			switch (cpl->status) {
288 			case PCIE_CPL_STS_UR:
289 				data->pci_err_status = 0;
290 				data->pci_bdg_sec_stat = PCI_STAT_R_MAST_AB |
291 				    PCI_STAT_S_SYSERR;
292 				break;
293 			case PCIE_CPL_STS_CA:
294 				data->pci_err_status = 0;
295 				data->pci_bdg_sec_stat = PCI_STAT_R_TARG_AB |
296 				    PCI_STAT_S_SYSERR;
297 				break;
298 			}
299 		}
300 	}
301 
302 	/* Fill in the device status register */
303 	if (entry->fire_bit & data->pcie_ue_sev)
304 		data->pcie_err_status = PCIE_DEVSTS_FE_DETECTED;
305 	else
306 		data->pcie_err_status = PCIE_DEVSTS_NFE_DETECTED;
307 
308 	/* Fill in the AER UE register */
309 	data->pcie_ue_status = entry->fire_bit;
310 
311 	return (1);
312 }
313 
314 static int
fab_xlate_fire_dmc(fmd_hdl_t * hdl,fab_data_t * data,nvlist_t * erpt,const char * class)315 fab_xlate_fire_dmc(fmd_hdl_t *hdl, fab_data_t *data, nvlist_t *erpt,
316     const char *class)
317 {
318 	fab_fire_tbl_t	*entry;
319 	uint64_t	reg;
320 	uint32_t	temp;
321 
322 	for (entry = fab_fire_dmc_tbl; entry->err_class; entry++) {
323 		fmd_hdl_debug(hdl, "Matching %s\n", entry->err_class);
324 		if (STRCMP(class, entry->err_class) &&
325 		    nvlist_lookup_boolean(erpt, "primary"))
326 			goto send;
327 	}
328 
329 	return (0);
330 
331 send:
332 	fmd_hdl_debug(hdl, "Translate Fire DMC %s\n", class);
333 
334 	/* Fill in PCI Status Register */
335 	data->pci_err_status = entry->pci_err_sts;
336 	data->pci_bdg_sec_stat = entry->pci_bdg_sts;
337 
338 	/* Fill in the device status register */
339 	data->pcie_err_status = PCIE_DEVSTS_NFE_DETECTED;
340 
341 	/* Fill in the AER UE register */
342 	data->pcie_ue_status = entry->fire_bit;
343 
344 	/* Fill in the AER Control register */
345 	temp = entry->fire_bit;
346 	for (data->pcie_adv_ctl = (uint32_t)-1; temp; data->pcie_adv_ctl++)
347 		temp = temp >> 1;
348 
349 	/* Fill in the AER Header registers */
350 	if (nvlist_lookup_uint64(erpt, "mmu-tfsr", &reg) == 0) {
351 		fmd_hdl_debug(hdl, "tfsr 0x%llx\n", reg);
352 		/* Get the trans type */
353 		temp = (reg & 0x3F0000) >> 16;
354 		data->pcie_ue_hdr[0] = (uint32_t)(temp << 24);
355 		data->pcie_ue_tgt_trans = PF_ADDR_DMA;
356 		/* Get the req id */
357 		temp = (reg & 0xFFFF);
358 		data->pcie_ue_hdr[1] = (uint32_t)(temp << 16);
359 		data->pcie_ue_tgt_bdf = temp;
360 	}
361 
362 	if (nvlist_lookup_uint64(erpt, "mmu-tfar", &reg) == 0) {
363 		fmd_hdl_debug(hdl, "tfar 0x%llx\n", reg);
364 		/* Get the address */
365 		data->pcie_ue_hdr[2] = reg;
366 		data->pcie_ue_hdr[3] = 0;
367 		data->pcie_ue_tgt_addr = reg;
368 	}
369 
370 	fmd_hdl_debug(hdl, "HEADER 0 0x%x\n", data->pcie_ue_hdr[0]);
371 	fmd_hdl_debug(hdl, "HEADER 1 0x%x\n", data->pcie_ue_hdr[1]);
372 	fmd_hdl_debug(hdl, "HEADER 2 0x%x\n", data->pcie_ue_hdr[2]);
373 	fmd_hdl_debug(hdl, "HEADER 3 0x%x\n", data->pcie_ue_hdr[3]);
374 
375 	return (1);
376 }
377 
378 void
fab_xlate_fire_erpts(fmd_hdl_t * hdl,nvlist_t * nvl,const char * class)379 fab_xlate_fire_erpts(fmd_hdl_t *hdl, nvlist_t *nvl, const char *class)
380 {
381 	fab_data_t data = {0};
382 
383 	fmd_hdl_debug(hdl, "Fire RC ereport received: %s\n", class);
384 
385 	fab_fire_to_data(hdl, nvl, &data);
386 
387 	if (fmd_nvl_class_match(hdl, nvl, "ereport.io.fire.pec.*")) {
388 		if (! fab_xlate_fire_ce(hdl, &data, nvl, class) &&
389 		    ! fab_xlate_fire_ue(hdl, &data, nvl, class))
390 			(void) fab_xlate_fire_oe(hdl, &data, nvl, class);
391 	} else if (fmd_nvl_class_match(hdl, nvl, "ereport.io.fire.dmc.*") ||
392 	    fmd_nvl_class_match(hdl, nvl, "ereport.io.n2.dmu.*"))
393 		(void) fab_xlate_fire_dmc(hdl, &data, nvl, class);
394 
395 	fab_xlate_pcie_erpts(hdl, &data);
396 }
397