xref: /illumos-gate/usr/src/cmd/fm/modules/common/fabric-xlate/fx_epkt.c (revision bdf0047c9427cca40961a023475891c898579c37)
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 2010 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 #include <sys/types.h>
27 #include <px_err.h>
28 
29 #include "fabric-xlate.h"
30 
31 #define	EPKT_DESC(b, o, p, c, d) (BLOCK_##b << 16 | OP_##o << 12 | \
32     PH_##p << 8 | CND_##c << 4 | DIR_##d)
33 
34 /* EPKT Table used only for RC/RP errors */
35 typedef struct fab_epkt_tbl {
36 	uint32_t	epkt_desc;
37 	uint32_t	pcie_ue_sts;	/* Equivalent PCIe UE Status */
38 	uint16_t	pci_err_sts;	/* Equivalent PCI Error Status */
39 	uint16_t	pci_bdg_sts;	/* Equivalent PCI Bridge Status */
40 	const char	*tgt_class;	/* Target Ereport Class */
41 } fab_epkt_tbl_t;
42 
43 static fab_epkt_tbl_t fab_epkt_tbl[] = {
44 	EPKT_DESC(MMU, XLAT, DATA, INV, RDWR),
45 	PCIE_AER_UCE_CA, 0, PCI_STAT_S_TARG_AB, 0,
46 	EPKT_DESC(MMU, XLAT, ADDR, UNMAP, RDWR),
47 	PCIE_AER_UCE_CA, 0, PCI_STAT_S_TARG_AB, 0,
48 	EPKT_DESC(MMU, XLAT, DATA, PROT, RDWR),
49 	PCIE_AER_UCE_CA, 0, PCI_STAT_S_TARG_AB, 0,
50 
51 	EPKT_DESC(INTR, MSI32, DATA, ILL, IRR),
52 	PCIE_AER_UCE_MTLP, PCI_STAT_S_SYSERR, 0, 0,
53 
54 	EPKT_DESC(PORT, PIO, IRR, RCA, WRITE),
55 	0, PCI_STAT_S_SYSERR, PCI_STAT_R_TARG_AB, 0,
56 
57 	EPKT_DESC(PORT, PIO, IRR, RUR, WRITE),
58 	0, PCI_STAT_S_SYSERR, PCI_STAT_R_MAST_AB, 0,
59 
60 	EPKT_DESC(PORT, PIO, IRR, INV, RDWR),
61 	PCIE_AER_UCE_MTLP, PCI_STAT_S_SYSERR, 0, 0,
62 
63 	EPKT_DESC(PORT, PIO, IRR, TO, READ),
64 	PCIE_AER_UCE_TO, PCI_STAT_S_SYSERR, 0, PCI_TARG_MA,
65 	EPKT_DESC(PORT, PIO, IRR, TO, WRITE),
66 	PCIE_AER_UCE_TO, PCI_STAT_S_SYSERR, 0, PCI_TARG_MA,
67 
68 	EPKT_DESC(PORT, PIO, IRR, UC, IRR),
69 	PCIE_AER_UCE_UC, PCI_STAT_S_SYSERR, 0, 0,
70 
71 	EPKT_DESC(PORT, LINK, FC, TO, IRR),
72 	PCIE_AER_UCE_FCP, PCI_STAT_S_SYSERR, 0, 0,
73 
74 	0, 0, 0, 0, 0
75 };
76 
77 /* ARGSUSED */
78 void
79 fab_epkt_to_data(fmd_hdl_t *hdl, nvlist_t *nvl, fab_data_t *data)
80 {
81 	data->nvl = nvl;
82 
83 	/* Always Root Complex */
84 	data->dev_type = PCIE_PCIECAP_DEV_TYPE_ROOT;
85 
86 	data->pcie_ue_sev = (PCIE_AER_UCE_DLP | PCIE_AER_UCE_SD |
87 	    PCIE_AER_UCE_FCP | PCIE_AER_UCE_RO | PCIE_AER_UCE_MTLP);
88 }
89 
90 static int
91 fab_xlate_epkt(fmd_hdl_t *hdl, fab_data_t *data, px_rc_err_t *epktp)
92 {
93 	fab_epkt_tbl_t *entry;
94 	uint32_t temp;
95 
96 	for (entry = fab_epkt_tbl; entry->epkt_desc != 0; entry++) {
97 		temp = *(uint32_t *)&epktp->rc_descr >> 12;
98 		if (entry->epkt_desc == temp)
99 			goto send;
100 	}
101 
102 	return (0);
103 
104 send:
105 	fmd_hdl_debug(hdl, "Translate epkt DESC = %#x\n", temp);
106 
107 	/* Fill in PCI Status Register */
108 	data->pci_err_status = entry->pci_err_sts;
109 	data->pci_bdg_sec_stat = entry->pci_bdg_sts;
110 
111 	/* Fill in the device status register */
112 	if (epktp->rc_descr.STOP)
113 		data->pcie_err_status = PCIE_DEVSTS_FE_DETECTED;
114 	else if (epktp->rc_descr.C)
115 		data->pcie_err_status = PCIE_DEVSTS_CE_DETECTED;
116 	else
117 		data->pcie_err_status = PCIE_DEVSTS_NFE_DETECTED;
118 
119 	/* Fill in the AER UE register */
120 	data->pcie_ue_status = entry->pcie_ue_sts;
121 
122 	/* Fill in the AER Control register */
123 	temp = entry->pcie_ue_sts;
124 	for (data->pcie_adv_ctl = (uint32_t)-1; temp; data->pcie_adv_ctl++)
125 		temp = temp >> 1;
126 
127 	/* Send target ereports */
128 	data->pcie_ue_no_tgt_erpt = B_TRUE;
129 	if (entry->tgt_class && !epktp->rc_descr.STOP) {
130 		if (epktp->rc_descr.D) {
131 			data->pcie_ue_tgt_trans = PF_ADDR_DMA;
132 			data->pcie_ue_tgt_addr = epktp->addr;
133 		} else if (epktp->rc_descr.M) {
134 			data->pcie_ue_tgt_trans = PF_ADDR_PIO;
135 			data->pcie_ue_tgt_addr = epktp->addr;
136 		}
137 
138 		if (data->pcie_ue_tgt_trans)
139 			fab_send_tgt_erpt(hdl, data, entry->tgt_class,
140 			    B_TRUE);
141 	}
142 	return (1);
143 }
144 
145 void
146 fab_xlate_epkt_erpts(fmd_hdl_t *hdl, nvlist_t *nvl, const char *class)
147 {
148 	fab_data_t data = {0};
149 	px_rc_err_t epkt = {0};
150 	pcie_tlp_hdr_t *tlp_hdr;
151 	void *ptr;
152 	uint8_t ver;
153 	int err;
154 	char *rppath = NULL;
155 	nvlist_t *detector;
156 
157 	fmd_hdl_debug(hdl, "epkt ereport received: %s\n", class);
158 	fab_epkt_to_data(hdl, nvl, &data);
159 
160 	err = nvlist_lookup_uint8(nvl, "epkt_ver", &ver);
161 	err |= nvlist_lookup_uint32(nvl, "desc", (uint32_t *)&epkt.rc_descr);
162 	err |= nvlist_lookup_uint32(nvl, "size", &epkt.size);
163 	err |= nvlist_lookup_uint64(nvl, "addr", &epkt.addr);
164 	err |= nvlist_lookup_uint64(nvl, "hdr1", &epkt.hdr[0]);
165 	err |= nvlist_lookup_uint64(nvl, "hdr2", &epkt.hdr[1]);
166 	err |= nvlist_lookup_uint64(nvl, "reserved", &epkt.reserved);
167 
168 	if (err != 0) {
169 		fmd_hdl_debug(hdl, "Failed to retrieve all epkt payloads");
170 		return;
171 	}
172 
173 	fmd_hdl_debug(hdl, "epkt flags: %c%c%c%c%c%c%c%c%c %s",
174 	    epkt.rc_descr.S ? 'S' : '-', epkt.rc_descr.M ? 'M' : '-',
175 	    epkt.rc_descr.S ? 'Q' : '-', epkt.rc_descr.D ? 'D' : '-',
176 	    epkt.rc_descr.R ? 'R' : '-', epkt.rc_descr.H ? 'H' : '-',
177 	    epkt.rc_descr.C ? 'C' : '-', epkt.rc_descr.I ? 'I' : '-',
178 	    epkt.rc_descr.B ? 'B' : '-', epkt.rc_descr.STOP ? "STOP" : "");
179 
180 	/*
181 	 * If the least byte of the 'reserved' is non zero, it is device
182 	 * and function of the port
183 	 */
184 	if (epkt.reserved && 0xff)
185 		rppath = fab_find_rppath_by_df(hdl, nvl, epkt.reserved & 0xff);
186 
187 	if (epkt.rc_descr.H) {
188 		data.pcie_ue_hdr[0] = (uint32_t)(epkt.hdr[0] >> 32);
189 		data.pcie_ue_hdr[1] = (uint32_t)epkt.hdr[0];
190 		data.pcie_ue_hdr[2] = (uint32_t)(epkt.hdr[1] >> 32);
191 		data.pcie_ue_hdr[3] = (uint32_t)(epkt.hdr[1]);
192 
193 		tlp_hdr = (pcie_tlp_hdr_t *)&data.pcie_ue_hdr[0];
194 		ptr = &data.pcie_ue_hdr[1];
195 		switch (tlp_hdr->type) {
196 		case PCIE_TLP_TYPE_IO:
197 		case PCIE_TLP_TYPE_MEM:
198 		case PCIE_TLP_TYPE_MEMLK:
199 		{
200 			pcie_mem64_t *pmp = ptr;
201 			data.pcie_ue_tgt_trans = PF_ADDR_PIO;
202 			data.pcie_ue_tgt_bdf = pmp->rid;
203 			if (tlp_hdr->fmt & 0x1)
204 				data.pcie_ue_tgt_addr =
205 				    ((uint64_t)pmp->addr1 << 32) | pmp->addr0;
206 			else
207 				data.pcie_ue_tgt_addr =
208 				    ((pcie_memio32_t *)ptr)->addr0;
209 
210 			break;
211 		}
212 
213 		case PCIE_TLP_TYPE_CFG0:
214 		case PCIE_TLP_TYPE_CFG1:
215 		{
216 			pcie_cfg_t *pcp = ptr;
217 
218 			data.pcie_ue_tgt_trans = PF_ADDR_CFG;
219 			data.pcie_ue_tgt_bdf =
220 			    (pcp->bus << 8) | (pcp->dev << 3) | pcp->func;
221 			break;
222 		}
223 
224 		case PCIE_TLP_TYPE_CPL:
225 		case PCIE_TLP_TYPE_CPLLK:
226 			data.pcie_ue_tgt_bdf = ((pcie_cpl_t *)ptr)->rid;
227 			break;
228 		}
229 
230 		fmd_hdl_debug(hdl, "HEADER 0 0x%x", data.pcie_ue_hdr[0]);
231 		fmd_hdl_debug(hdl, "HEADER 1 0x%x", data.pcie_ue_hdr[1]);
232 		fmd_hdl_debug(hdl, "HEADER 2 0x%x", data.pcie_ue_hdr[2]);
233 		fmd_hdl_debug(hdl, "HEADER 3 0x%x", data.pcie_ue_hdr[3]);
234 		fmd_hdl_debug(hdl, "In header bdf = %#hx addr = %#llx",
235 		    data.pcie_ue_tgt_bdf,
236 		    (uint64_t)data.pcie_ue_tgt_addr);
237 
238 		/* find the root port to which this error is related */
239 		if (data.pcie_ue_tgt_bdf)
240 			rppath = fab_find_rppath_by_devbdf(hdl, nvl,
241 			    data.pcie_ue_tgt_bdf);
242 	}
243 
244 	/*
245 	 * reset the detector in the original ereport to the root port
246 	 */
247 	if (rppath) {
248 		if (nvlist_alloc(&detector, NV_UNIQUE_NAME, 0) != 0) {
249 			fmd_hdl_error(hdl, "failed to allocate nvlist");
250 			fmd_hdl_strfree(hdl, rppath);
251 			return;
252 		}
253 		(void) nvlist_add_string(detector, FM_VERSION,
254 		    FM_DEV_SCHEME_VERSION);
255 		(void) nvlist_add_string(detector, FM_FMRI_SCHEME,
256 		    FM_FMRI_SCHEME_DEV);
257 		(void) nvlist_add_string(detector, FM_FMRI_DEV_PATH, rppath);
258 		(void) nvlist_remove_all(nvl, FM_EREPORT_DETECTOR);
259 		(void) nvlist_add_nvlist(nvl, FM_EREPORT_DETECTOR, detector);
260 		nvlist_free(detector);
261 		fmd_hdl_strfree(hdl, rppath);
262 	} else {
263 		/*
264 		 * We can not locate the root port the error originated from.
265 		 * Likely this is because the original ereport is malformed or
266 		 * the hw error register has corrupted contents.  In this case,
267 		 * the best we can do is send ereports on all root ports.
268 		 *
269 		 * Set pcie_rp_send_all for fab_send_erpt() to process later.
270 		 */
271 		fmd_hdl_debug(hdl, "RP not fond. Will translate on all RPs.\n");
272 		data.pcie_rp_send_all = B_TRUE;
273 	}
274 
275 	(void) fab_xlate_epkt(hdl, &data, &epkt);
276 	fab_xlate_pcie_erpts(hdl, &data);
277 }
278