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, NULL, NULL,
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, NULL, NULL,
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, NULL, NULL,
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, NULL, NULL
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", ®) == 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", ®) == 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", ®) == 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", ®) == 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", ®) == 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", ®) == 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", ®) == 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", ®) == 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", ®) == 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", ®) == 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