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 * Copyright (c) 2010, Oracle and/or its affiliates. All rights reserved.
23 */
24
25#pragma dictionary "PCIEX"
26
27#include <px_err.h>
28
29/*
30 * generic root complex/root port diagnosis rules
31 */
32
33#define	PCIEXFN		pciexbus/pciexdev/pciexfn
34#define	PCIEXFNHZ	pciexbus<>/pciexdev<>/pciexfn<>
35
36#define RC_N    5
37#define RC_T    72h
38
39#define SW_FIT    5000
40#define FW_FIT    5000
41#define HB_FIT    400
42
43#define EPKT_DESC       (payloadprop("desc") >> 12)
44#define EPKT_B_BIT      (payloadprop("desc") & (1 << 7))
45#define EPKT_C_BIT      (payloadprop("desc") & (1 << 5))
46#define EPKT_H_BIT      (payloadprop("desc") & (1 << 4))
47
48#define MATCHES_DESC(b, o, p, c, d) \
49    (EPKT_DESC == (b << 16 | o << 12 | p << 8 | c << 4 | d))
50
51#define IS_CE (EPKT_C_BIT != 0 && setserdsuffix(EPKT_DESC))
52#define IS_UE (EPKT_C_BIT == 0)
53
54/*
55 * BLOCK bit set means the error may cause a pipe stall and thus a CTO
56 * in the fabric
57 */
58#define IS_BLOCKED (EPKT_B_BIT != 0)
59
60#define EPKT(b, o, p, c, d) \
61    ereport.io.pciex.rc.epkt@hostbridge { MATCHES_DESC(b, o, p, c, d) }
62
63/* Errors that will be diagnosed by the fabric DE (pciex.esc) */
64#define	DIAG_BY_FAB \
65	(MATCHES_DESC(BLOCK_INTR,OP_MSI32,PH_DATA,CND_ILL,DIR_IRR) ||	\
66	MATCHES_DESC(BLOCK_PORT,OP_LINK,PH_FC,CND_TO,DIR_IRR) ||	\
67	MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_IRR,CND_INV,DIR_RDWR) ||	\
68	MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_IRR,CND_RCA,DIR_WRITE) ||	\
69	MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_IRR,CND_RUR,DIR_WRITE) ||	\
70	MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_IRR,CND_TO,DIR_READ) ||	\
71	MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_IRR,CND_TO,DIR_WRITE) ||	\
72	MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_IRR,CND_UC,DIR_IRR))
73
74/* Ereport Events */
75event ereport.io.pciex.rc.epkt@hostbridge {within(5s)};
76
77/* Internal Events */
78event error.io.pciex.rc.stall@hostbridge;
79event error.io.pciex.rc.poiscomp@hostbridge;
80event error.io.pciex.nr-d@hostbridge/pciexrc/PCIEXFN;
81event error.io.pciex.badreq-u@hostbridge/pciexrc/PCIEXFN;
82event error.io.pciex.poiscomp-d@hostbridge/pciexrc/PCIEXFN;
83event error.io.pciex.noimpact-d@hostbridge/pciexrc/PCIEXFN;
84event error.io.pciex.lost-d@hostbridge/pciexrc/PCIEXFN;
85event error.io.pciex.degraded-d@hostbridge/pciexrc/PCIEXFN;
86
87/* Upset event */
88event upset.io.pciex.rc.stall@hostbridge;
89event upset.io.pciex.rc.discard@hostbridge;
90
91/*
92 * Fault Events
93 * Do no retire and FRUs for SW/FW faults
94 */
95event fault.io.pciex.rc.generic-ue@hostbridge,
96    FITrate=HB_FIT, retire=0, response=0;
97event fault.io.pciex.rc.generic-sw@hostbridge,
98    FITrate=SW_FIT, retire=0, response=0;
99event fault.io.pciex.rc.generic-fw@hostbridge,
100    FITrate=FW_FIT, retire=0, response=0;
101
102/* Serd engine for CE errors */
103engine serd.io.pciex.rc.generic-ce@hostbridge, N=RC_N, T=RC_T;
104event fault.io.pciex.rc.generic-ce@hostbridge, FITrate=HB_FIT,
105    engine=serd.io.pciex.rc.generic-ce@hostbridge;
106
107/* Fire faults */
108event fault.io.fire.pciex.device@PCIEXFN, FITrate=1000;
109event fault.io.fire.pci.device@pcibus/pcidev/pcifn, FITrate=1000;
110
111/* Generic Root Complex Software faults */
112prop fault.io.pciex.rc.generic-sw@hostbridge ->
113    ereport.io.pciex.rc.epkt@hostbridge {
114	MATCHES_DESC(BLOCK_INTR,OP_FIXED,PH_UNKNOWN,CND_ILL,DIR_INGRESS)  ||
115	MATCHES_DESC(BLOCK_INTR,OP_MSI32,PH_UNKNOWN,CND_ILL,DIR_IRR)  ||
116	MATCHES_DESC(BLOCK_INTR,OP_PCIEMSG,PH_UNKNOWN,CND_ILL,DIR_INGRESS)
117    };
118
119/* Generic Root Complex Firmware faults */
120prop fault.io.pciex.rc.generic-fw@hostbridge ->
121    ereport.io.pciex.rc.epkt@hostbridge {
122	MATCHES_DESC(BLOCK_HOSTBUS,OP_PIO,PH_ADDR,CND_UNMAP,DIR_WRITE)
123    };
124
125/* Generic Root Complex CE faults */
126prop fault.io.pciex.rc.generic-ce@hostbridge { IS_CE } ->
127    ereport.io.pciex.rc.epkt@hostbridge;
128
129/* Generic Root Complex UE faults from propagations */
130event error.io.pciex.rc.generic-ue1@hostbridge;
131event error.io.pciex.rc.generic-ue2@hostbridge;
132
133prop fault.io.pciex.rc.generic-ue@hostbridge ->
134    error.io.pciex.rc.generic-ue1@hostbridge,
135    error.io.pciex.rc.generic-ue2@hostbridge,
136    error.io.pciex.rc.stall@hostbridge,
137    error.io.pciex.rc.poiscomp@hostbridge;
138
139/* Generic Root Complex UE propagations */
140prop error.io.pciex.rc.generic-ue1@hostbridge { IS_UE && !IS_BLOCKED } ->
141    ereport.io.pciex.rc.epkt@hostbridge {
142	MATCHES_DESC(BLOCK_HOSTBUS,OP_DMA,PH_DATA,CND_INT,DIR_READ) ||
143	MATCHES_DESC(BLOCK_HOSTBUS,OP_DMA,PH_DATA,CND_INT,DIR_UNKNOWN) ||
144	MATCHES_DESC(BLOCK_HOSTBUS,OP_DMA,PH_DATA,CND_INT,DIR_WRITE) ||
145	MATCHES_DESC(BLOCK_HOSTBUS,OP_DMA,PH_DATA,CND_TO,DIR_READ) ||
146	MATCHES_DESC(BLOCK_HOSTBUS,OP_DMA,PH_DATA,CND_TO,DIR_WRITE) ||
147	MATCHES_DESC(BLOCK_HOSTBUS,OP_PIO,PH_DATA,CND_INT,DIR_UNKNOWN) ||
148	MATCHES_DESC(BLOCK_HOSTBUS,OP_UNKNOWN,PH_DATA,CND_INT,DIR_UNKNOWN) ||
149	MATCHES_DESC(BLOCK_HOSTBUS,OP_UNKNOWN,PH_DATA,CND_INT,DIR_UNKNOWN) ||
150	MATCHES_DESC(BLOCK_INTR,OP_MSI32,PH_DATA,CND_INT,DIR_UNKNOWN) ||
151	MATCHES_DESC(BLOCK_INTR,OP_MSIQ,PH_DATA,CND_INT,DIR_UNKNOWN)
152    };
153
154prop error.io.pciex.rc.generic-ue2@hostbridge { IS_UE && !IS_BLOCKED } ->
155    ereport.io.pciex.rc.epkt@hostbridge {
156	MATCHES_DESC(BLOCK_MMU,OP_TBW,PH_ADDR,CND_UNKNOWN,DIR_UNKNOWN) ||
157	MATCHES_DESC(BLOCK_MMU,OP_TBW,PH_ADDR,CND_UNMAP,DIR_UNKNOWN) ||
158	MATCHES_DESC(BLOCK_MMU,OP_TBW,PH_DATA,CND_INT,DIR_IRR) ||
159	MATCHES_DESC(BLOCK_MMU,OP_TBW,PH_UNKNOWN,CND_UNKNOWN,DIR_UNKNOWN) ||
160	MATCHES_DESC(BLOCK_MMU,OP_XLAT,PH_DATA,CND_INT,DIR_UNKNOWN) ||
161	MATCHES_DESC(BLOCK_PORT,OP_DMA,PH_DATA,CND_INT,DIR_READ) ||
162	MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_DATA,CND_INT,DIR_READ) ||
163	MATCHES_DESC(BLOCK_PORT,OP_PIO,PH_DATA,CND_INT,DIR_UNKNOWN) ||
164	MATCHES_DESC(BLOCK_PORT,OP_UNKNOWN,PH_DATA,CND_INT,DIR_UNKNOWN) ||
165	MATCHES_DESC(BLOCK_PORT,OP_UNKNOWN,PH_DATA,CND_INT,DIR_UNKNOWN)
166    };
167
168/* Errors that will cause a pipe stall and thus a CTO in the fabric */
169prop error.io.pciex.rc.stall@hostbridge (0) ->
170    error.io.pciex.nr-d@hostbridge/pciexrc<>/PCIEXFNHZ;
171prop error.io.pciex.rc.stall@hostbridge { IS_UE && IS_BLOCKED } ->
172    ereport.io.pciex.rc.epkt@hostbridge { !DIAG_BY_FAB };
173
174/*
175 * Errors that will send a poisoned data to the fabric
176 * Also the poiscomp-d could represent a fault that a hardened driver
177 * handled and reported a service impact.
178 */
179prop error.io.pciex.rc.poiscomp@hostbridge (0) ->
180    error.io.pciex.poiscomp-d@hostbridge/pciexrc<>/PCIEXFNHZ,
181    error.io.pciex.noimpact-d@hostbridge/pciexrc<>/PCIEXFNHZ,
182    error.io.pciex.lost-d@hostbridge/pciexrc<>/PCIEXFNHZ,
183    error.io.pciex.degraded-d@hostbridge/pciexrc<>/PCIEXFNHZ;
184
185prop error.io.pciex.rc.poiscomp@hostbridge { IS_UE && !IS_BLOCKED } ->
186    ereport.io.pciex.rc.epkt@hostbridge {
187	MATCHES_DESC(BLOCK_HOSTBUS,OP_DMA,PH_DATA,CND_INT,DIR_READ)
188    };
189
190prop error.io.pciex.badreq-u@hostbridge/pciexrc/PCIEXFN { IS_UE && !IS_BLOCKED } (0) ->
191    ereport.io.pciex.rc.epkt@hostbridge {
192	MATCHES_DESC(BLOCK_MMU,OP_XLAT,PH_ADDR,CND_UNMAP,DIR_RDWR) ||
193	MATCHES_DESC(BLOCK_MMU,OP_XLAT,PH_DATA,CND_INV,DIR_RDWR) ||
194	MATCHES_DESC(BLOCK_MMU,OP_XLAT,PH_DATA,CND_PROT,DIR_RDWR)
195    };
196
197/*
198 * The errors will be diagnosed by pciex.esc but may also cause a CTO
199 * in the fabric.
200 */
201prop upset.io.pciex.rc.stall@hostbridge ->
202    ereport.io.pciex.rc.epkt@hostbridge { IS_BLOCKED && DIAG_BY_FAB };
203prop upset.io.pciex.rc.stall@hostbridge (0) ->
204    error.io.pciex.nr-d@hostbridge/pciexrc<>/PCIEXFNHZ;
205
206/* The errors will be discarded here and diagnosed by pciex.esc. */
207prop upset.io.pciex.rc.discard@hostbridge ->
208    ereport.io.pciex.rc.epkt@hostbridge { !IS_BLOCKED && DIAG_BY_FAB };
209
210/* Event queue overflow */
211#define PROP_PLAT_FRU "FRU"
212#define GET_HB_FRU (confprop(asru(hostbridge), PROP_PLAT_FRU))
213#define GET_PCIE_FRU (confprop(asru(pciexbus[b]/pciexdev[d]/pciexfn[0]), PROP_PLAT_FRU))
214#define GET_PCI_FRU (confprop(asru(pcibus[b]/pcidev[d]/pcifn[0]), PROP_PLAT_FRU))
215
216prop fault.io.fire.pciex.device@pciexbus[b]/pciexdev[d]/pciexfn[0]
217    {
218        /*
219         * Indict PCI-E FRU(s) under this root complex excluding the
220         * one that the Fire ASIC resides on.
221         */
222        is_under(hostbridge, pciexbus[b]/pciexdev[d]/pciexfn[0]) &&
223	(GET_HB_FRU != GET_PCIE_FRU)
224    } (0) -> EPKT(BLOCK_INTR,OP_MSIQ,PH_UNKNOWN,CND_OV,DIR_IRR);
225
226prop fault.io.fire.pci.device@pcibus[b]/pcidev[d]/pcifn[0]
227    {
228        /*
229         * Indict PCI FRU(s) under this root complex excluding the
230         * one that the Fire ASIC resides on.
231         */
232        is_under(hostbridge, pcibus[b]/pcidev[d]/pcifn[0]) &&
233	    (GET_HB_FRU != GET_PCI_FRU)
234    } (0) -> EPKT(BLOCK_INTR,OP_MSIQ,PH_UNKNOWN,CND_OV,DIR_IRR);
235