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.
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.
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]
23 * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
26 #include <sys/types.h>
27 #include <sys/sunndi.h>
28 #include <sys/sysmacros.h>
29 #include <sys/ddifm_impl.h>
30 #include <sys/fm/util.h>
31 #include <sys/fm/protocol.h>
32 #include <sys/fm/io/pci.h>
33 #include <sys/fm/io/ddi.h>
35 #include <sys/pci_cap.h>
36 #include <sys/pci_impl.h>
38 #include <sys/pcifm.h>
40 #define PCIX_ECC_VER_CHECK(x) (((x) == PCI_PCIX_VER_1) ||\
41 ((x) == PCI_PCIX_VER_2))
43 errorq_t
*pci_target_queue
= NULL
;
45 pci_fm_err_t pci_err_tbl
[] = {
46 PCI_DET_PERR
, PCI_STAT_PERROR
, NULL
, DDI_FM_UNKNOWN
,
47 PCI_MDPE
, PCI_STAT_S_PERROR
, PCI_TARG_MDPE
, DDI_FM_UNKNOWN
,
48 PCI_SIG_SERR
, PCI_STAT_S_SYSERR
, NULL
, DDI_FM_FATAL
,
49 PCI_MA
, PCI_STAT_R_MAST_AB
, PCI_TARG_MA
, DDI_FM_UNKNOWN
,
50 PCI_REC_TA
, PCI_STAT_R_TARG_AB
, PCI_TARG_REC_TA
, DDI_FM_UNKNOWN
,
51 PCI_SIG_TA
, PCI_STAT_S_TARG_AB
, NULL
, DDI_FM_UNKNOWN
,
52 NULL
, NULL
, NULL
, NULL
,
55 pci_fm_err_t pci_bdg_err_tbl
[] = {
56 PCI_DET_PERR
, PCI_STAT_PERROR
, NULL
, DDI_FM_UNKNOWN
,
57 PCI_MDPE
, PCI_STAT_S_PERROR
, PCI_TARG_MDPE
, DDI_FM_UNKNOWN
,
58 PCI_REC_SERR
, PCI_STAT_S_SYSERR
, NULL
, DDI_FM_UNKNOWN
,
60 PCI_MA
, PCI_STAT_R_MAST_AB
, PCI_TARG_MA
, DDI_FM_UNKNOWN
,
62 PCI_REC_TA
, PCI_STAT_R_TARG_AB
, PCI_TARG_REC_TA
, DDI_FM_UNKNOWN
,
63 PCI_SIG_TA
, PCI_STAT_S_TARG_AB
, NULL
, DDI_FM_UNKNOWN
,
64 NULL
, NULL
, NULL
, NULL
,
67 static pci_fm_err_t pcix_err_tbl
[] = {
68 PCIX_SPL_DIS
, PCI_PCIX_SPL_DSCD
, NULL
, DDI_FM_UNKNOWN
,
69 PCIX_UNEX_SPL
, PCI_PCIX_UNEX_SPL
, NULL
, DDI_FM_UNKNOWN
,
70 PCIX_RX_SPL_MSG
, PCI_PCIX_RX_SPL_MSG
, NULL
, DDI_FM_UNKNOWN
,
71 NULL
, NULL
, NULL
, NULL
,
74 static pci_fm_err_t pcix_sec_err_tbl
[] = {
75 PCIX_SPL_DIS
, PCI_PCIX_BSS_SPL_DSCD
, NULL
, DDI_FM_UNKNOWN
,
76 PCIX_UNEX_SPL
, PCI_PCIX_BSS_UNEX_SPL
, NULL
, DDI_FM_UNKNOWN
,
77 PCIX_BSS_SPL_OR
, PCI_PCIX_BSS_SPL_OR
, NULL
, DDI_FM_OK
,
78 PCIX_BSS_SPL_DLY
, PCI_PCIX_BSS_SPL_DLY
, NULL
, DDI_FM_OK
,
79 NULL
, NULL
, NULL
, NULL
,
83 pci_config_check(ddi_acc_handle_t handle
, int fme_flag
)
85 ddi_acc_hdl_t
*hp
= impl_acc_hdl_get(handle
);
88 if (!(DDI_FM_ACC_ERR_CAP(ddi_fm_capable(hp
->ah_dip
))))
91 de
.fme_version
= DDI_FME_VERSION
;
93 ddi_fm_acc_err_get(handle
, &de
, de
.fme_version
);
94 if (de
.fme_status
!= DDI_FM_OK
) {
95 if (fme_flag
== DDI_FM_ERR_UNEXPECTED
) {
96 char buf
[FM_MAX_CLASS
];
98 (void) snprintf(buf
, FM_MAX_CLASS
, "%s.%s",
99 PCI_ERROR_SUBCLASS
, PCI_NR
);
100 ddi_fm_ereport_post(hp
->ah_dip
, buf
, de
.fme_ena
,
101 DDI_NOSLEEP
, FM_VERSION
, DATA_TYPE_UINT8
, 0, NULL
);
103 ddi_fm_acc_err_clear(handle
, de
.fme_version
);
105 return (de
.fme_status
);
109 pcix_ecc_regs_gather(pci_erpt_t
*erpt_p
, pcix_ecc_regs_t
*pcix_ecc_regs
,
110 uint8_t pcix_cap_ptr
, int fme_flag
)
112 int bdg
= erpt_p
->pe_dflags
& PCI_BRIDGE_DEV
;
114 pcix_ecc_regs
->pcix_ecc_ctlstat
= pci_config_get32(erpt_p
->pe_hdl
,
115 (pcix_cap_ptr
+ (bdg
? PCI_PCIX_BDG_ECC_STATUS
:
116 PCI_PCIX_ECC_STATUS
)));
117 if (pci_config_check(erpt_p
->pe_hdl
, fme_flag
) == DDI_FM_OK
)
118 pcix_ecc_regs
->pcix_ecc_vflags
|= PCIX_ERR_ECC_STS_VALID
;
121 pcix_ecc_regs
->pcix_ecc_fstaddr
= pci_config_get32(erpt_p
->pe_hdl
,
122 (pcix_cap_ptr
+ (bdg
? PCI_PCIX_BDG_ECC_FST_AD
:
123 PCI_PCIX_ECC_FST_AD
)));
124 pcix_ecc_regs
->pcix_ecc_secaddr
= pci_config_get32(erpt_p
->pe_hdl
,
125 (pcix_cap_ptr
+ (bdg
? PCI_PCIX_BDG_ECC_SEC_AD
:
126 PCI_PCIX_ECC_SEC_AD
)));
127 pcix_ecc_regs
->pcix_ecc_attr
= pci_config_get32((
128 ddi_acc_handle_t
)erpt_p
->pe_hdl
,
129 (pcix_cap_ptr
+ (bdg
? PCI_PCIX_BDG_ECC_ATTR
: PCI_PCIX_ECC_ATTR
)));
133 pcix_regs_gather(pci_erpt_t
*erpt_p
, void *pe_regs
, int fme_flag
)
135 if (erpt_p
->pe_dflags
& PCI_BRIDGE_DEV
) {
136 pcix_bdg_error_regs_t
*pcix_bdg_regs
=
137 (pcix_bdg_error_regs_t
*)pe_regs
;
138 uint8_t pcix_bdg_cap_ptr
;
141 pcix_bdg_cap_ptr
= pcix_bdg_regs
->pcix_bdg_cap_ptr
;
142 pcix_bdg_regs
->pcix_bdg_sec_stat
= pci_config_get16(
143 erpt_p
->pe_hdl
, (pcix_bdg_cap_ptr
+ PCI_PCIX_SEC_STATUS
));
144 if (pci_config_check(erpt_p
->pe_hdl
, fme_flag
) == DDI_FM_OK
)
145 pcix_bdg_regs
->pcix_bdg_vflags
|=
146 PCIX_BDG_SEC_STATUS_VALID
;
149 pcix_bdg_regs
->pcix_bdg_stat
= pci_config_get32(erpt_p
->pe_hdl
,
150 (pcix_bdg_cap_ptr
+ PCI_PCIX_BDG_STATUS
));
151 if (pci_config_check(erpt_p
->pe_hdl
, fme_flag
) == DDI_FM_OK
)
152 pcix_bdg_regs
->pcix_bdg_vflags
|= PCIX_BDG_STATUS_VALID
;
155 if (PCIX_ECC_VER_CHECK(pcix_bdg_regs
->pcix_bdg_ver
)) {
156 pcix_ecc_regs_t
*pcix_bdg_ecc_regs
;
158 for (i
= 0; i
< 2; i
++) {
160 pcix_bdg_regs
->pcix_bdg_ecc_regs
[i
];
161 pci_config_put32(erpt_p
->pe_hdl
,
163 PCI_PCIX_BDG_ECC_STATUS
), i
);
164 pcix_ecc_regs_gather(erpt_p
,
166 pcix_bdg_cap_ptr
, fme_flag
);
170 pcix_error_regs_t
*pcix_regs
= (pcix_error_regs_t
*)pe_regs
;
171 uint8_t pcix_cap_ptr
;
173 pcix_cap_ptr
= pcix_regs
->pcix_cap_ptr
;
175 pcix_regs
->pcix_command
= pci_config_get16(erpt_p
->pe_hdl
,
176 (pcix_cap_ptr
+ PCI_PCIX_COMMAND
));
177 pcix_regs
->pcix_status
= pci_config_get32(erpt_p
->pe_hdl
,
178 (pcix_cap_ptr
+ PCI_PCIX_STATUS
));
179 if (pci_config_check(erpt_p
->pe_hdl
, fme_flag
) == DDI_FM_OK
)
180 pcix_regs
->pcix_vflags
|= PCIX_ERR_STATUS_VALID
;
183 if (PCIX_ECC_VER_CHECK(pcix_regs
->pcix_ver
)) {
184 pcix_ecc_regs_t
*pcix_ecc_regs
=
185 pcix_regs
->pcix_ecc_regs
;
187 pcix_ecc_regs_gather(erpt_p
, pcix_ecc_regs
,
188 pcix_cap_ptr
, fme_flag
);
195 pci_regs_gather(dev_info_t
*dip
, pci_erpt_t
*erpt_p
, int fme_flag
)
197 pci_error_regs_t
*pci_regs
= erpt_p
->pe_pci_regs
;
200 * Start by reading all the error registers that are available for
201 * pci and pci express and for leaf devices and bridges/switches
203 pci_regs
->pci_err_status
= pci_config_get16(erpt_p
->pe_hdl
,
205 if (pci_config_check(erpt_p
->pe_hdl
, fme_flag
) != DDI_FM_OK
)
207 pci_regs
->pci_vflags
|= PCI_ERR_STATUS_VALID
;
208 pci_regs
->pci_cfg_comm
= pci_config_get16(erpt_p
->pe_hdl
,
210 if (pci_config_check(erpt_p
->pe_hdl
, fme_flag
) != DDI_FM_OK
)
214 * If pci-pci bridge grab PCI bridge specific error registers.
216 if (erpt_p
->pe_dflags
& PCI_BRIDGE_DEV
) {
217 pci_regs
->pci_bdg_regs
->pci_bdg_sec_stat
=
218 pci_config_get16(erpt_p
->pe_hdl
, PCI_BCNF_SEC_STATUS
);
219 if (pci_config_check(erpt_p
->pe_hdl
, fme_flag
) == DDI_FM_OK
)
220 pci_regs
->pci_bdg_regs
->pci_bdg_vflags
|=
221 PCI_BDG_SEC_STAT_VALID
;
222 pci_regs
->pci_bdg_regs
->pci_bdg_ctrl
=
223 pci_config_get16(erpt_p
->pe_hdl
, PCI_BCNF_BCNTRL
);
224 if (pci_config_check(erpt_p
->pe_hdl
, fme_flag
) == DDI_FM_OK
)
225 pci_regs
->pci_bdg_regs
->pci_bdg_vflags
|=
229 /* If pci-x device grab error registers */
230 if (erpt_p
->pe_dflags
& PCIX_DEV
)
231 pcix_regs_gather(erpt_p
, erpt_p
->pe_regs
, fme_flag
);
236 pcix_regs_clear(pci_erpt_t
*erpt_p
, void *pe_regs
)
238 if (erpt_p
->pe_dflags
& PCI_BRIDGE_DEV
) {
239 pcix_bdg_error_regs_t
*pcix_bdg_regs
=
240 (pcix_bdg_error_regs_t
*)pe_regs
;
241 uint8_t pcix_bdg_cap_ptr
;
244 pcix_bdg_cap_ptr
= pcix_bdg_regs
->pcix_bdg_cap_ptr
;
246 if (pcix_bdg_regs
->pcix_bdg_vflags
& PCIX_BDG_SEC_STATUS_VALID
)
247 pci_config_put16(erpt_p
->pe_hdl
,
248 (pcix_bdg_cap_ptr
+ PCI_PCIX_SEC_STATUS
),
249 pcix_bdg_regs
->pcix_bdg_sec_stat
);
251 if (pcix_bdg_regs
->pcix_bdg_vflags
& PCIX_BDG_STATUS_VALID
)
252 pci_config_put32(erpt_p
->pe_hdl
,
253 (pcix_bdg_cap_ptr
+ PCI_PCIX_BDG_STATUS
),
254 pcix_bdg_regs
->pcix_bdg_stat
);
256 pcix_bdg_regs
->pcix_bdg_vflags
= 0x0;
258 if (PCIX_ECC_VER_CHECK(pcix_bdg_regs
->pcix_bdg_ver
)) {
259 pcix_ecc_regs_t
*pcix_bdg_ecc_regs
;
260 for (i
= 0; i
< 2; i
++) {
262 pcix_bdg_regs
->pcix_bdg_ecc_regs
[i
];
264 if (pcix_bdg_ecc_regs
->pcix_ecc_vflags
&
265 PCIX_ERR_ECC_STS_VALID
) {
266 pci_config_put32(erpt_p
->pe_hdl
,
268 PCI_PCIX_BDG_ECC_STATUS
),
271 pci_config_put32(erpt_p
->pe_hdl
,
273 PCI_PCIX_BDG_ECC_STATUS
),
277 pcix_bdg_ecc_regs
->pcix_ecc_vflags
=
282 pcix_error_regs_t
*pcix_regs
= (pcix_error_regs_t
*)pe_regs
;
283 uint8_t pcix_cap_ptr
;
285 pcix_cap_ptr
= pcix_regs
->pcix_cap_ptr
;
287 if (pcix_regs
->pcix_vflags
& PCIX_ERR_STATUS_VALID
)
288 pci_config_put32(erpt_p
->pe_hdl
,
289 (pcix_cap_ptr
+ PCI_PCIX_STATUS
),
290 pcix_regs
->pcix_status
);
292 pcix_regs
->pcix_vflags
= 0x0;
294 if (PCIX_ECC_VER_CHECK(pcix_regs
->pcix_ver
)) {
295 pcix_ecc_regs_t
*pcix_ecc_regs
=
296 pcix_regs
->pcix_ecc_regs
;
298 if (pcix_ecc_regs
->pcix_ecc_vflags
&
299 PCIX_ERR_ECC_STS_VALID
)
300 pci_config_put32(erpt_p
->pe_hdl
,
301 (pcix_cap_ptr
+ PCI_PCIX_ECC_STATUS
),
302 pcix_ecc_regs
->pcix_ecc_ctlstat
);
304 pcix_ecc_regs
->pcix_ecc_vflags
= 0x0;
310 pci_regs_clear(pci_erpt_t
*erpt_p
)
313 * Finally clear the error bits
315 if (erpt_p
->pe_dflags
& PCIX_DEV
)
316 pcix_regs_clear(erpt_p
, erpt_p
->pe_regs
);
318 if (erpt_p
->pe_pci_regs
->pci_vflags
& PCI_ERR_STATUS_VALID
)
319 pci_config_put16(erpt_p
->pe_hdl
, PCI_CONF_STAT
,
320 erpt_p
->pe_pci_regs
->pci_err_status
);
322 erpt_p
->pe_pci_regs
->pci_vflags
= 0x0;
324 if (erpt_p
->pe_dflags
& PCI_BRIDGE_DEV
) {
325 if (erpt_p
->pe_pci_regs
->pci_bdg_regs
->pci_bdg_vflags
&
326 PCI_BDG_SEC_STAT_VALID
)
327 pci_config_put16(erpt_p
->pe_hdl
, PCI_BCNF_SEC_STATUS
,
328 erpt_p
->pe_pci_regs
->pci_bdg_regs
->
330 if (erpt_p
->pe_pci_regs
->pci_bdg_regs
->pci_bdg_vflags
&
332 pci_config_put16(erpt_p
->pe_hdl
, PCI_BCNF_BCNTRL
,
333 erpt_p
->pe_pci_regs
->pci_bdg_regs
->pci_bdg_ctrl
);
335 erpt_p
->pe_pci_regs
->pci_bdg_regs
->pci_bdg_vflags
= 0x0;
340 * pcix_ereport_setup: Allocate structures for PCI-X error handling and ereport
345 pcix_ereport_setup(dev_info_t
*dip
, pci_erpt_t
*erpt_p
)
347 uint16_t pcix_cap_ptr
= PCI_CAP_NEXT_PTR_NULL
;
351 if (pci_config_setup(dip
, &eh
) == DDI_SUCCESS
) {
352 (void) PCI_CAP_LOCATE(eh
, PCI_CAP_ID_PCIX
, &pcix_cap_ptr
);
353 pci_config_teardown(&eh
);
356 if (pcix_cap_ptr
!= PCI_CAP_NEXT_PTR_NULL
)
357 erpt_p
->pe_dflags
|= PCIX_DEV
;
361 if (erpt_p
->pe_dflags
& PCI_BRIDGE_DEV
) {
362 pcix_bdg_error_regs_t
*pcix_bdg_regs
;
364 erpt_p
->pe_regs
= kmem_zalloc(sizeof (pcix_bdg_error_regs_t
),
366 pcix_bdg_regs
= (pcix_bdg_error_regs_t
*)erpt_p
->pe_regs
;
367 pcix_bdg_regs
->pcix_bdg_cap_ptr
= pcix_cap_ptr
;
368 pcix_bdg_regs
->pcix_bdg_ver
= pci_config_get16(erpt_p
->pe_hdl
,
369 pcix_cap_ptr
+ PCI_PCIX_SEC_STATUS
) & PCI_PCIX_VER_MASK
;
370 if (PCIX_ECC_VER_CHECK(pcix_bdg_regs
->pcix_bdg_ver
)) {
371 for (i
= 0; i
< 2; i
++) {
372 pcix_bdg_regs
->pcix_bdg_ecc_regs
[i
] =
373 kmem_zalloc(sizeof (pcix_ecc_regs_t
),
378 pcix_error_regs_t
*pcix_regs
;
380 erpt_p
->pe_regs
= kmem_zalloc(sizeof (pcix_error_regs_t
),
382 pcix_regs
= (pcix_error_regs_t
*)erpt_p
->pe_regs
;
383 pcix_regs
->pcix_cap_ptr
= pcix_cap_ptr
;
384 pcix_regs
->pcix_ver
= pci_config_get16(erpt_p
->pe_hdl
,
385 pcix_cap_ptr
+ PCI_PCIX_COMMAND
) & PCI_PCIX_VER_MASK
;
386 if (PCIX_ECC_VER_CHECK(pcix_regs
->pcix_ver
)) {
387 pcix_regs
->pcix_ecc_regs
= kmem_zalloc(
388 sizeof (pcix_ecc_regs_t
), KM_SLEEP
);
394 * pci_ereport_setup: Detect PCI device type and initialize structures to be
395 * used to generate ereports based on detected generic device errors.
398 pci_ereport_setup(dev_info_t
*dip
)
400 struct dev_info
*devi
= DEVI(dip
);
401 struct i_ddi_fmhdl
*fmhdl
= devi
->devi_fmhdl
;
403 uint8_t pci_hdr_type
;
405 pci_regspec_t
*pci_rp
;
410 * If device is not ereport capbable then report an error against the
411 * driver for using this interface,
413 if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip
)) &&
414 !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip
))) {
415 i_ddi_drv_ereport_post(dip
, DVR_EFMCAP
, NULL
, DDI_SLEEP
);
420 * ASSERT fmhdl exists and fh_bus_specific is NULL.
422 ASSERT(fmhdl
&& (fmhdl
->fh_bus_specific
== NULL
));
424 erpt_p
= kmem_zalloc(sizeof (pci_erpt_t
), KM_SLEEP
);
426 if (pci_config_setup(dip
, &erpt_p
->pe_hdl
) != DDI_SUCCESS
)
429 erpt_p
->pe_pci_regs
= kmem_zalloc(sizeof (pci_error_regs_t
), KM_SLEEP
);
431 pci_status
= pci_config_get16(erpt_p
->pe_hdl
, PCI_CONF_STAT
);
432 if (pci_config_check(erpt_p
->pe_hdl
, DDI_FM_ERR_UNEXPECTED
) !=
437 * Get header type and record if device is a bridge.
439 pci_hdr_type
= pci_config_get8(erpt_p
->pe_hdl
, PCI_CONF_HEADER
);
440 if (pci_config_check(erpt_p
->pe_hdl
, DDI_FM_ERR_UNEXPECTED
) !=
445 * Check to see if PCI device is a bridge, if so allocate pci bridge
446 * error register structure.
448 if ((pci_hdr_type
& PCI_HEADER_TYPE_M
) == PCI_HEADER_PPB
) {
449 erpt_p
->pe_dflags
|= PCI_BRIDGE_DEV
;
450 erpt_p
->pe_pci_regs
->pci_bdg_regs
= kmem_zalloc(
451 sizeof (pci_bdg_error_regs_t
), KM_SLEEP
);
454 if (ddi_getlongprop(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
, "reg",
455 (caddr_t
)&pci_rp
, &len
) == DDI_SUCCESS
) {
456 phys_hi
= pci_rp
->pci_phys_hi
;
457 kmem_free(pci_rp
, len
);
459 erpt_p
->pe_bdf
= (uint16_t)(PCI_REG_BDFR_G(phys_hi
) >>
463 if (!(pci_status
& PCI_STAT_CAP
)) {
467 /* Initialize structures for PCI-X devices. */
468 pcix_ereport_setup(dip
, erpt_p
);
471 pci_regs_gather(dip
, erpt_p
, DDI_FM_ERR_UNEXPECTED
);
472 pci_regs_clear(erpt_p
);
475 * Before returning set fh_bus_specific to completed pci_erpt_t
478 fmhdl
->fh_bus_specific
= (void *)erpt_p
;
482 if (erpt_p
->pe_pci_regs
)
483 kmem_free(erpt_p
->pe_pci_regs
, sizeof (pci_error_regs_t
));
484 kmem_free(erpt_p
, sizeof (pci_erpt_t
));
489 pcix_ereport_teardown(pci_erpt_t
*erpt_p
)
491 if (erpt_p
->pe_dflags
& PCI_BRIDGE_DEV
) {
492 pcix_bdg_error_regs_t
*pcix_bdg_regs
;
495 pcix_bdg_regs
= (pcix_bdg_error_regs_t
*)erpt_p
->pe_regs
;
496 pcix_ver
= pcix_bdg_regs
->pcix_bdg_ver
;
497 if (PCIX_ECC_VER_CHECK(pcix_ver
)) {
499 for (i
= 0; i
< 2; i
++)
500 kmem_free(pcix_bdg_regs
->pcix_bdg_ecc_regs
[i
],
501 sizeof (pcix_ecc_regs_t
));
503 kmem_free(erpt_p
->pe_regs
, sizeof (pcix_bdg_error_regs_t
));
505 pcix_error_regs_t
*pcix_regs
;
508 pcix_regs
= (pcix_error_regs_t
*)erpt_p
->pe_regs
;
509 pcix_ver
= pcix_regs
->pcix_ver
;
510 if (PCIX_ECC_VER_CHECK(pcix_ver
)) {
511 kmem_free(pcix_regs
->pcix_ecc_regs
,
512 sizeof (pcix_ecc_regs_t
));
514 kmem_free(erpt_p
->pe_regs
, sizeof (pcix_error_regs_t
));
519 pci_ereport_teardown(dev_info_t
*dip
)
521 struct i_ddi_fmhdl
*fmhdl
= DEVI(dip
)->devi_fmhdl
;
524 if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip
)) &&
525 !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip
))) {
526 i_ddi_drv_ereport_post(dip
, DVR_EFMCAP
, NULL
, DDI_SLEEP
);
531 erpt_p
= (pci_erpt_t
*)fmhdl
->fh_bus_specific
;
535 if (erpt_p
->pe_dflags
& PCIX_DEV
)
536 pcix_ereport_teardown(erpt_p
);
537 pci_config_teardown((ddi_acc_handle_t
*)&erpt_p
->pe_hdl
);
538 if (erpt_p
->pe_dflags
& PCI_BRIDGE_DEV
)
539 kmem_free(erpt_p
->pe_pci_regs
->pci_bdg_regs
,
540 sizeof (pci_bdg_error_regs_t
));
541 kmem_free(erpt_p
->pe_pci_regs
, sizeof (pci_error_regs_t
));
542 kmem_free(erpt_p
, sizeof (pci_erpt_t
));
543 fmhdl
->fh_bus_specific
= NULL
;
546 * The following sparc specific code should be removed once the pci_cap
547 * interfaces create the necessary properties for us.
553 pcix_check_addr(dev_info_t
*dip
, ddi_fm_error_t
*derr
,
554 pcix_ecc_regs_t
*pcix_ecc_regs
, int type
)
556 int cmd
= (pcix_ecc_regs
->pcix_ecc_ctlstat
>> 16) & 0xf;
558 pci_fme_bus_specific_t
*pci_fme_bsp
=
559 (pci_fme_bus_specific_t
*)derr
->fme_bus_specific
;
561 addr
= pcix_ecc_regs
->pcix_ecc_secaddr
;
563 addr
|= pcix_ecc_regs
->pcix_ecc_fstaddr
;
566 case PCI_PCIX_CMD_INTR
:
567 case PCI_PCIX_CMD_SPEC
:
568 return (DDI_FM_FATAL
);
569 case PCI_PCIX_CMD_IORD
:
570 case PCI_PCIX_CMD_IOWR
:
571 pci_fme_bsp
->pci_bs_addr
= addr
;
572 pci_fme_bsp
->pci_bs_flags
|= PCI_BS_ADDR_VALID
;
573 pci_fme_bsp
->pci_bs_type
= type
;
574 return (DDI_FM_UNKNOWN
);
575 case PCI_PCIX_CMD_DEVID
:
576 return (DDI_FM_FATAL
);
577 case PCI_PCIX_CMD_MEMRD_DW
:
578 case PCI_PCIX_CMD_MEMWR
:
579 case PCI_PCIX_CMD_MEMRD_BL
:
580 case PCI_PCIX_CMD_MEMWR_BL
:
581 pci_fme_bsp
->pci_bs_addr
= addr
;
582 pci_fme_bsp
->pci_bs_flags
|= PCI_BS_ADDR_VALID
;
583 pci_fme_bsp
->pci_bs_type
= type
;
584 return (DDI_FM_UNKNOWN
);
585 case PCI_PCIX_CMD_CFRD
:
586 case PCI_PCIX_CMD_CFWR
:
588 * for type 1 config transaction we can find bdf from address
590 if ((addr
& 3) == 1) {
591 pci_fme_bsp
->pci_bs_bdf
= (addr
>> 8) & 0xffffffff;
592 pci_fme_bsp
->pci_bs_flags
|= PCI_BS_BDF_VALID
;
593 pci_fme_bsp
->pci_bs_type
= type
;
595 return (DDI_FM_UNKNOWN
);
596 case PCI_PCIX_CMD_SPL
:
597 case PCI_PCIX_CMD_DADR
:
598 return (DDI_FM_UNKNOWN
);
599 case PCI_PCIX_CMD_MEMRDBL
:
600 case PCI_PCIX_CMD_MEMWRBL
:
601 pci_fme_bsp
->pci_bs_addr
= addr
;
602 pci_fme_bsp
->pci_bs_flags
|= PCI_BS_ADDR_VALID
;
603 pci_fme_bsp
->pci_bs_type
= type
;
604 return (DDI_FM_UNKNOWN
);
606 return (DDI_FM_FATAL
);
612 pci_bdg_error_report(dev_info_t
*dip
, ddi_fm_error_t
*derr
, pci_erpt_t
*erpt_p
)
614 pci_bdg_error_regs_t
*pci_bdg_regs
= erpt_p
->pe_pci_regs
->pci_bdg_regs
;
620 char buf
[FM_MAX_CLASS
];
622 pci_fme_bus_specific_t
*pci_fme_bsp
=
623 (pci_fme_bus_specific_t
*)derr
->fme_bus_specific
;
625 if (derr
->fme_flag
!= DDI_FM_ERR_UNEXPECTED
)
628 if ((pci_bdg_regs
->pci_bdg_vflags
& PCI_BDG_CTRL_VALID
) &&
629 (pci_bdg_regs
->pci_bdg_ctrl
& PCI_BCNF_BCNTRL_DTO_STAT
)) {
630 (void) snprintf(buf
, FM_MAX_CLASS
, "%s.%s",
631 PCI_ERROR_SUBCLASS
, PCI_DTO
);
632 ddi_fm_ereport_post(dip
, buf
, derr
->fme_ena
,
633 DDI_NOSLEEP
, FM_VERSION
, DATA_TYPE_UINT8
, 0,
634 PCI_SEC_CONFIG_STATUS
, DATA_TYPE_UINT16
,
635 pci_bdg_regs
->pci_bdg_sec_stat
, PCI_BCNTRL
,
636 DATA_TYPE_UINT16
, pci_bdg_regs
->pci_bdg_ctrl
, NULL
);
640 if (pci_bdg_regs
->pci_bdg_vflags
& PCI_BDG_SEC_STAT_VALID
) {
641 for (i
= 0; pci_bdg_err_tbl
[i
].err_class
!= NULL
; i
++) {
642 if (pci_bdg_regs
->pci_bdg_sec_stat
&
643 pci_bdg_err_tbl
[i
].reg_bit
) {
644 (void) snprintf(buf
, FM_MAX_CLASS
, "%s.%s-%s",
645 PCI_ERROR_SUBCLASS
, PCI_SEC_ERROR_SUBCLASS
,
646 pci_bdg_err_tbl
[i
].err_class
);
647 ddi_fm_ereport_post(dip
, buf
, derr
->fme_ena
,
648 DDI_NOSLEEP
, FM_VERSION
, DATA_TYPE_UINT8
, 0,
649 PCI_SEC_CONFIG_STATUS
, DATA_TYPE_UINT16
,
650 pci_bdg_regs
->pci_bdg_sec_stat
, PCI_BCNTRL
,
652 pci_bdg_regs
->pci_bdg_ctrl
, NULL
);
653 PCI_FM_SEV_INC(pci_bdg_err_tbl
[i
].flags
);
654 if (pci_fme_bsp
&& (pci_fme_bsp
->pci_bs_flags
&
655 PCI_BS_ADDR_VALID
) &&
656 pci_fme_bsp
->pci_bs_type
== ACC_HANDLE
&&
657 pci_bdg_err_tbl
[i
].terr_class
)
658 pci_target_enqueue(derr
->fme_ena
,
659 pci_bdg_err_tbl
[i
].terr_class
,
661 pci_fme_bsp
->pci_bs_addr
);
668 * Need to check for poke and cautious put. We already know peek
669 * and cautious get errors occurred (as we got a trap) and we know
672 if (derr
->fme_flag
== DDI_FM_ERR_EXPECTED
) {
674 * for cautious puts we treat all errors as nonfatal. Actually
675 * we set nonfatal for cautious gets as well - doesn't do any
678 if (pci_bdg_regs
->pci_bdg_sec_stat
& (PCI_STAT_R_TARG_AB
|
679 PCI_STAT_R_MAST_AB
| PCI_STAT_S_PERROR
| PCI_STAT_S_SYSERR
))
682 if (derr
->fme_flag
== DDI_FM_ERR_POKE
) {
684 * special case for pokes - we only consider master abort
685 * and target abort as nonfatal. Sserr with no master abort is
686 * fatal, but master/target abort can come in on separate
687 * instance, so return unknown and parent will determine if
688 * nonfatal (if another child returned nonfatal - ie master
689 * or target abort) or fatal otherwise
691 if (pci_bdg_regs
->pci_bdg_sec_stat
& (PCI_STAT_R_TARG_AB
|
694 if (erpt_p
->pe_pci_regs
->pci_err_status
& PCI_STAT_S_SYSERR
)
699 * now check children below the bridge
701 ret
= ndi_fm_handler_dispatch(dip
, NULL
, derr
);
703 return (fatal
? DDI_FM_FATAL
: (nonfatal
? DDI_FM_NONFATAL
:
704 (unknown
? DDI_FM_UNKNOWN
: DDI_FM_OK
)));
708 pcix_ecc_error_report(dev_info_t
*dip
, ddi_fm_error_t
*derr
, pci_erpt_t
*erpt_p
,
711 pcix_error_regs_t
*pcix_regs
;
712 pcix_bdg_error_regs_t
*pcix_bdg_regs
;
713 pcix_ecc_regs_t
*pcix_ecc_regs
;
724 char buf
[FM_MAX_CLASS
];
726 if (erpt_p
->pe_dflags
& PCI_BRIDGE_DEV
) {
727 pcix_bdg_regs
= (pcix_bdg_error_regs_t
*)pe_regs
;
730 pcix_regs
= (pcix_error_regs_t
*)pe_regs
;
734 for (i
= 0; i
< (bridge
? 2 : 1); i
++) {
736 pcix_ecc_regs
= bridge
? pcix_bdg_regs
->pcix_bdg_ecc_regs
[i
] :
737 pcix_regs
->pcix_ecc_regs
;
738 if (pcix_ecc_regs
->pcix_ecc_vflags
& PCIX_ERR_ECC_STS_VALID
) {
739 ecc_phase
= (pcix_ecc_regs
->pcix_ecc_ctlstat
&
740 PCI_PCIX_ECC_PHASE
) >> 0x4;
741 ecc_corr
= (pcix_ecc_regs
->pcix_ecc_ctlstat
&
743 sec_ue
= (pcix_ecc_regs
->pcix_ecc_ctlstat
&
745 sec_ce
= (pcix_ecc_regs
->pcix_ecc_ctlstat
&
749 case PCI_PCIX_ECC_PHASE_NOERR
:
751 case PCI_PCIX_ECC_PHASE_FADDR
:
752 case PCI_PCIX_ECC_PHASE_SADDR
:
753 PCI_FM_SEV_INC(ecc_corr
? DDI_FM_OK
:
755 (void) snprintf(buf
, FM_MAX_CLASS
,
756 "%s.%s%s", PCIX_ERROR_SUBCLASS
,
757 i
? PCIX_SEC_ERROR_SUBCLASS
: "",
758 ecc_corr
? PCIX_ECC_CE_ADDR
:
761 case PCI_PCIX_ECC_PHASE_ATTR
:
762 PCI_FM_SEV_INC(ecc_corr
?
763 DDI_FM_OK
: DDI_FM_FATAL
);
764 (void) snprintf(buf
, FM_MAX_CLASS
,
765 "%s.%s%s", PCIX_ERROR_SUBCLASS
,
766 i
? PCIX_SEC_ERROR_SUBCLASS
: "",
767 ecc_corr
? PCIX_ECC_CE_ATTR
:
770 case PCI_PCIX_ECC_PHASE_DATA32
:
771 case PCI_PCIX_ECC_PHASE_DATA64
:
776 pci_error_regs_t
*pci_regs
=
780 if (pci_regs
->pci_bdg_regs
->
787 if (pci_regs
->pci_err_status
&
793 ret
= pcix_check_addr(dip
, derr
,
794 pcix_ecc_regs
, type
);
798 (void) snprintf(buf
, FM_MAX_CLASS
,
799 "%s.%s%s", PCIX_ERROR_SUBCLASS
,
800 i
? PCIX_SEC_ERROR_SUBCLASS
: "",
801 ecc_corr
? PCIX_ECC_CE_DATA
:
807 ddi_fm_ereport_post(dip
, buf
,
809 DDI_NOSLEEP
, FM_VERSION
,
811 PCIX_SEC_STATUS
, DATA_TYPE_UINT16
,
812 pcix_bdg_regs
->pcix_bdg_sec_stat
,
813 PCIX_BDG_STAT
, DATA_TYPE_UINT32
,
814 pcix_bdg_regs
->pcix_bdg_stat
,
815 PCIX_ECC_CTLSTAT
, DATA_TYPE_UINT32
,
816 pcix_ecc_regs
->pcix_ecc_ctlstat
,
817 PCIX_ECC_ATTR
, DATA_TYPE_UINT32
,
818 pcix_ecc_regs
->pcix_ecc_attr
, NULL
);
820 ddi_fm_ereport_post(dip
, buf
,
822 DDI_NOSLEEP
, FM_VERSION
,
824 PCIX_COMMAND
, DATA_TYPE_UINT16
,
825 pcix_regs
->pcix_command
,
826 PCIX_STATUS
, DATA_TYPE_UINT32
,
827 pcix_regs
->pcix_status
,
828 PCIX_ECC_CTLSTAT
, DATA_TYPE_UINT32
,
829 pcix_ecc_regs
->pcix_ecc_ctlstat
,
830 PCIX_ECC_ATTR
, DATA_TYPE_UINT32
,
831 pcix_ecc_regs
->pcix_ecc_attr
, NULL
);
832 if (sec_ce
|| sec_ue
) {
833 (void) snprintf(buf
, FM_MAX_CLASS
,
834 "%s.%s%s", PCIX_ERROR_SUBCLASS
,
835 i
? PCIX_SEC_ERROR_SUBCLASS
: "",
836 sec_ce
? PCIX_ECC_S_CE
: PCIX_ECC_S_UE
);
838 ddi_fm_ereport_post(dip
, buf
,
840 DDI_NOSLEEP
, FM_VERSION
,
842 PCIX_SEC_STATUS
, DATA_TYPE_UINT16
,
843 pcix_bdg_regs
->pcix_bdg_sec_stat
,
844 PCIX_BDG_STAT
, DATA_TYPE_UINT32
,
845 pcix_bdg_regs
->pcix_bdg_stat
,
846 PCIX_ECC_CTLSTAT
, DATA_TYPE_UINT32
,
847 pcix_ecc_regs
->pcix_ecc_ctlstat
,
848 PCIX_ECC_ATTR
, DATA_TYPE_UINT32
,
849 pcix_ecc_regs
->pcix_ecc_attr
, NULL
);
851 ddi_fm_ereport_post(dip
, buf
,
853 DDI_NOSLEEP
, FM_VERSION
,
855 PCIX_COMMAND
, DATA_TYPE_UINT16
,
856 pcix_regs
->pcix_command
,
857 PCIX_STATUS
, DATA_TYPE_UINT32
,
858 pcix_regs
->pcix_status
,
859 PCIX_ECC_CTLSTAT
, DATA_TYPE_UINT32
,
860 pcix_ecc_regs
->pcix_ecc_ctlstat
,
861 PCIX_ECC_ATTR
, DATA_TYPE_UINT32
,
862 pcix_ecc_regs
->pcix_ecc_attr
, NULL
);
863 PCI_FM_SEV_INC(sec_ue
? DDI_FM_FATAL
:
868 return (fatal
? DDI_FM_FATAL
: (nonfatal
? DDI_FM_NONFATAL
:
869 (unknown
? DDI_FM_UNKNOWN
: DDI_FM_OK
)));
873 pcix_bdg_error_report(dev_info_t
*dip
, ddi_fm_error_t
*derr
, pci_erpt_t
*erpt_p
,
876 pcix_bdg_error_regs_t
*pcix_bdg_regs
= (pcix_bdg_error_regs_t
*)pe_regs
;
881 char buf
[FM_MAX_CLASS
];
884 if (pcix_bdg_regs
->pcix_bdg_vflags
& PCIX_BDG_STATUS_VALID
) {
885 for (i
= 0; pcix_err_tbl
[i
].err_class
!= NULL
; i
++) {
886 if ((pcix_bdg_regs
->pcix_bdg_stat
&
887 pcix_err_tbl
[i
].reg_bit
)) {
888 (void) snprintf(buf
, FM_MAX_CLASS
, "%s.%s",
890 pcix_err_tbl
[i
].err_class
);
891 ddi_fm_ereport_post(dip
, buf
, derr
->fme_ena
,
892 DDI_NOSLEEP
, FM_VERSION
, DATA_TYPE_UINT8
, 0,
893 PCIX_SEC_STATUS
, DATA_TYPE_UINT16
,
894 pcix_bdg_regs
->pcix_bdg_sec_stat
,
895 PCIX_BDG_STAT
, DATA_TYPE_UINT32
,
896 pcix_bdg_regs
->pcix_bdg_stat
, NULL
);
897 PCI_FM_SEV_INC(pcix_err_tbl
[i
].flags
);
902 if (pcix_bdg_regs
->pcix_bdg_vflags
& PCIX_BDG_SEC_STATUS_VALID
) {
903 for (i
= 0; pcix_sec_err_tbl
[i
].err_class
!= NULL
; i
++) {
904 if ((pcix_bdg_regs
->pcix_bdg_sec_stat
&
905 pcix_sec_err_tbl
[i
].reg_bit
)) {
906 (void) snprintf(buf
, FM_MAX_CLASS
, "%s.%s%s",
908 PCIX_SEC_ERROR_SUBCLASS
,
909 pcix_sec_err_tbl
[i
].err_class
);
910 ddi_fm_ereport_post(dip
, buf
, derr
->fme_ena
,
911 DDI_NOSLEEP
, FM_VERSION
, DATA_TYPE_UINT8
, 0,
912 PCIX_SEC_STATUS
, DATA_TYPE_UINT16
,
913 pcix_bdg_regs
->pcix_bdg_sec_stat
,
914 PCIX_BDG_STAT
, DATA_TYPE_UINT32
,
915 pcix_bdg_regs
->pcix_bdg_stat
, NULL
);
916 PCI_FM_SEV_INC(pcix_sec_err_tbl
[i
].flags
);
921 /* Log/Handle ECC errors */
922 if (PCIX_ECC_VER_CHECK(pcix_bdg_regs
->pcix_bdg_ver
)) {
925 ret
= pcix_ecc_error_report(dip
, derr
, erpt_p
,
926 (void *)pcix_bdg_regs
);
929 return (fatal
? DDI_FM_FATAL
: (nonfatal
? DDI_FM_NONFATAL
:
930 (unknown
? DDI_FM_UNKNOWN
: DDI_FM_OK
)));
934 pcix_error_report(dev_info_t
*dip
, ddi_fm_error_t
*derr
, pci_erpt_t
*erpt_p
)
936 pcix_error_regs_t
*pcix_regs
= (pcix_error_regs_t
*)erpt_p
->pe_regs
;
941 char buf
[FM_MAX_CLASS
];
944 if (pcix_regs
->pcix_vflags
& PCIX_ERR_STATUS_VALID
) {
945 for (i
= 0; pcix_err_tbl
[i
].err_class
!= NULL
; i
++) {
946 if (!(pcix_regs
->pcix_status
& pcix_err_tbl
[i
].reg_bit
))
949 (void) snprintf(buf
, FM_MAX_CLASS
, "%s.%s",
950 PCIX_ERROR_SUBCLASS
, pcix_err_tbl
[i
].err_class
);
951 ddi_fm_ereport_post(dip
, buf
, derr
->fme_ena
,
952 DDI_NOSLEEP
, FM_VERSION
, DATA_TYPE_UINT8
, 0,
953 PCIX_COMMAND
, DATA_TYPE_UINT16
,
954 pcix_regs
->pcix_command
, PCIX_STATUS
,
955 DATA_TYPE_UINT32
, pcix_regs
->pcix_status
,
957 PCI_FM_SEV_INC(pcix_err_tbl
[i
].flags
);
960 /* Log/Handle ECC errors */
961 if (PCIX_ECC_VER_CHECK(pcix_regs
->pcix_ver
)) {
962 int ret
= pcix_ecc_error_report(dip
, derr
, erpt_p
,
967 return (fatal
? DDI_FM_FATAL
: (nonfatal
? DDI_FM_NONFATAL
:
968 (unknown
? DDI_FM_UNKNOWN
: DDI_FM_OK
)));
972 pci_error_report(dev_info_t
*dip
, ddi_fm_error_t
*derr
, pci_erpt_t
*erpt_p
)
978 char buf
[FM_MAX_CLASS
];
981 if (derr
->fme_flag
== DDI_FM_ERR_UNEXPECTED
) {
983 * Log generic PCI errors.
985 for (i
= 0; pci_err_tbl
[i
].err_class
!= NULL
; i
++) {
986 if (!(erpt_p
->pe_pci_regs
->pci_err_status
&
987 pci_err_tbl
[i
].reg_bit
) ||
988 !(erpt_p
->pe_pci_regs
->pci_vflags
&
989 PCI_ERR_STATUS_VALID
))
992 * Generate an ereport for this error bit.
994 (void) snprintf(buf
, FM_MAX_CLASS
, "%s.%s",
995 PCI_ERROR_SUBCLASS
, pci_err_tbl
[i
].err_class
);
996 ddi_fm_ereport_post(dip
, buf
, derr
->fme_ena
,
997 DDI_NOSLEEP
, FM_VERSION
, DATA_TYPE_UINT8
, 0,
998 PCI_CONFIG_STATUS
, DATA_TYPE_UINT16
,
999 erpt_p
->pe_pci_regs
->pci_err_status
,
1000 PCI_CONFIG_COMMAND
, DATA_TYPE_UINT16
,
1001 erpt_p
->pe_pci_regs
->pci_cfg_comm
, NULL
);
1003 PCI_FM_SEV_INC(pci_err_tbl
[i
].flags
);
1005 if (erpt_p
->pe_dflags
& PCIX_DEV
) {
1006 if (erpt_p
->pe_dflags
& PCI_BRIDGE_DEV
) {
1007 int ret
= pcix_bdg_error_report(dip
, derr
,
1008 erpt_p
, erpt_p
->pe_regs
);
1009 PCI_FM_SEV_INC(ret
);
1011 int ret
= pcix_error_report(dip
, derr
, erpt_p
);
1012 PCI_FM_SEV_INC(ret
);
1017 if ((erpt_p
->pe_dflags
& PCI_BRIDGE_DEV
)) {
1018 int ret
= pci_bdg_error_report(dip
, derr
, erpt_p
);
1019 PCI_FM_SEV_INC(ret
);
1022 if (derr
->fme_flag
== DDI_FM_ERR_UNEXPECTED
) {
1023 pci_fme_bus_specific_t
*pci_fme_bsp
;
1024 int ret
= DDI_FM_UNKNOWN
;
1026 pci_fme_bsp
= (pci_fme_bus_specific_t
*)derr
->fme_bus_specific
;
1027 if (pci_fme_bsp
->pci_bs_flags
& PCI_BS_ADDR_VALID
) {
1028 ret
= ndi_fmc_entry_error(dip
,
1029 pci_fme_bsp
->pci_bs_type
, derr
,
1030 (void *)&pci_fme_bsp
->pci_bs_addr
);
1031 PCI_FM_SEV_INC(ret
);
1034 * If we didn't find the handle using an addr, try using bdf.
1035 * Note we don't do this where the bdf is for a
1036 * device behind a pciex/pci bridge as the bridge may have
1037 * fabricated the bdf.
1039 if (ret
== DDI_FM_UNKNOWN
&&
1040 (pci_fme_bsp
->pci_bs_flags
& PCI_BS_BDF_VALID
) &&
1041 pci_fme_bsp
->pci_bs_bdf
== erpt_p
->pe_bdf
) {
1042 ret
= ndi_fmc_entry_error_all(dip
,
1043 pci_fme_bsp
->pci_bs_type
, derr
);
1044 PCI_FM_SEV_INC(ret
);
1048 derr
->fme_status
= (fatal
? DDI_FM_FATAL
: (nonfatal
? DDI_FM_NONFATAL
:
1049 (unknown
? DDI_FM_UNKNOWN
: DDI_FM_OK
)));
1053 pci_ereport_post(dev_info_t
*dip
, ddi_fm_error_t
*derr
, uint16_t *xx_status
)
1055 struct i_ddi_fmhdl
*fmhdl
;
1058 pci_fme_bus_specific_t pci_fme_bs
;
1061 * On PCI Express systems, all error handling and ereport are done via
1062 * the PCIe misc module. This function is a no-op for PCIe Systems. In
1063 * order to tell if a system is a PCI or PCIe system, check that the
1064 * bus_private_data exists. If it exists, this is a PCIe system.
1066 if (ndi_get_bus_private(dip
, B_TRUE
)) {
1067 derr
->fme_status
= DDI_FM_OK
;
1068 if (xx_status
!= NULL
)
1074 fmhdl
= DEVI(dip
)->devi_fmhdl
;
1075 if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip
)) &&
1076 !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip
))) {
1077 i_ddi_drv_ereport_post(dip
, DVR_EFMCAP
, NULL
, DDI_NOSLEEP
);
1082 * copy in the ddi_fm_error_t structure in case it's VER0
1084 de
.fme_version
= derr
->fme_version
;
1085 de
.fme_status
= derr
->fme_status
;
1086 de
.fme_flag
= derr
->fme_flag
;
1087 de
.fme_ena
= derr
->fme_ena
;
1088 de
.fme_acc_handle
= derr
->fme_acc_handle
;
1089 de
.fme_dma_handle
= derr
->fme_dma_handle
;
1090 de
.fme_bus_specific
= derr
->fme_bus_specific
;
1091 if (derr
->fme_version
>= DDI_FME_VER1
)
1092 de
.fme_bus_type
= derr
->fme_bus_type
;
1094 de
.fme_bus_type
= DDI_FME_BUS_TYPE_DFLT
;
1095 if (de
.fme_bus_type
== DDI_FME_BUS_TYPE_DFLT
) {
1097 * if this is the first pci device we've found convert
1098 * fme_bus_specific to DDI_FME_BUS_TYPE_PCI
1100 bzero(&pci_fme_bs
, sizeof (pci_fme_bs
));
1101 if (de
.fme_bus_specific
) {
1103 * the cpu passed us an addr - this can be used to look
1104 * up an access handle
1106 pci_fme_bs
.pci_bs_addr
= (uintptr_t)de
.fme_bus_specific
;
1107 pci_fme_bs
.pci_bs_type
= ACC_HANDLE
;
1108 pci_fme_bs
.pci_bs_flags
|= PCI_BS_ADDR_VALID
;
1110 de
.fme_bus_specific
= (void *)&pci_fme_bs
;
1111 de
.fme_bus_type
= DDI_FME_BUS_TYPE_PCI
;
1116 if (de
.fme_ena
== NULL
)
1117 de
.fme_ena
= fm_ena_generate(0, FM_ENA_FMT1
);
1119 erpt_p
= (pci_erpt_t
*)fmhdl
->fh_bus_specific
;
1123 pci_regs_gather(dip
, erpt_p
, de
.fme_flag
);
1124 pci_error_report(dip
, &de
, erpt_p
);
1125 pci_regs_clear(erpt_p
);
1127 derr
->fme_status
= de
.fme_status
;
1128 derr
->fme_ena
= de
.fme_ena
;
1129 derr
->fme_acc_handle
= de
.fme_acc_handle
;
1130 derr
->fme_dma_handle
= de
.fme_dma_handle
;
1131 if (xx_status
!= NULL
)
1132 *xx_status
= erpt_p
->pe_pci_regs
->pci_err_status
;
1136 * private version of walk_devs() that can be used during panic. No
1137 * sleeping or locking required.
1140 pci_fm_walk_devs(dev_info_t
*dip
, int (*f
)(dev_info_t
*, void *), void *arg
)
1143 switch ((*f
)(dip
, arg
)) {
1144 case DDI_WALK_TERMINATE
:
1145 return (DDI_WALK_TERMINATE
);
1146 case DDI_WALK_CONTINUE
:
1147 if (pci_fm_walk_devs(ddi_get_child(dip
), f
,
1148 arg
) == DDI_WALK_TERMINATE
)
1149 return (DDI_WALK_TERMINATE
);
1151 case DDI_WALK_PRUNECHILD
:
1154 dip
= ddi_get_next_sibling(dip
);
1156 return (DDI_WALK_CONTINUE
);
1160 * need special version of ddi_fm_ereport_post() as the leaf driver may
1164 pci_fm_ereport_post(dev_info_t
*dip
, const char *error_class
, uint64_t ena
,
1165 uint8_t version
, ...)
1168 char device_path
[MAXPATHLEN
];
1169 char ddi_error_class
[FM_MAX_CLASS
];
1170 nvlist_t
*ereport
, *detector
;
1172 errorq_elem_t
*eqep
;
1176 eqep
= errorq_reserve(ereport_errorq
);
1179 ereport
= errorq_elem_nvl(ereport_errorq
, eqep
);
1180 nva
= errorq_elem_nva(ereport_errorq
, eqep
);
1181 detector
= fm_nvlist_create(nva
);
1183 ereport
= fm_nvlist_create(NULL
);
1184 detector
= fm_nvlist_create(NULL
);
1187 (void) ddi_pathname(dip
, device_path
);
1188 fm_fmri_dev_set(detector
, FM_DEV_SCHEME_VERSION
, NULL
,
1189 device_path
, NULL
, NULL
);
1190 (void) snprintf(ddi_error_class
, FM_MAX_CLASS
, "%s.%s",
1191 DDI_IO_CLASS
, error_class
);
1192 fm_ereport_set(ereport
, version
, ddi_error_class
, ena
, detector
, NULL
);
1194 va_start(ap
, version
);
1195 name
= va_arg(ap
, char *);
1196 (void) i_fm_payload_set(ereport
, name
, ap
);
1200 errorq_commit(ereport_errorq
, eqep
, ERRORQ_SYNC
);
1202 (void) fm_ereport_post(ereport
, EVCH_TRYHARD
);
1203 fm_nvlist_destroy(ereport
, FM_NVA_FREE
);
1204 fm_nvlist_destroy(detector
, FM_NVA_FREE
);
1209 pci_check_regs(dev_info_t
*dip
, void *arg
)
1214 pci_regspec_t
*drv_regp
;
1215 pci_target_err_t
*tgt_err
= (pci_target_err_t
*)arg
;
1217 if (tgt_err
->tgt_pci_space
== PCI_REG_ADDR_G(PCI_ADDR_CONFIG
)) {
1219 * for config space, we need to check if the given address
1220 * is a valid config space address for this device - based
1221 * on pci_phys_hi of the config space entry in reg property.
1223 if (ddi_getlongprop(DDI_DEV_T_NONE
, dip
, DDI_PROP_DONTPASS
,
1224 "reg", (caddr_t
)&drv_regp
, ®len
) != DDI_SUCCESS
)
1225 return (DDI_WALK_CONTINUE
);
1227 totreg
= reglen
/ sizeof (pci_regspec_t
);
1228 for (rn
= 0; rn
< totreg
; rn
++) {
1229 if (tgt_err
->tgt_pci_space
==
1230 PCI_REG_ADDR_G(drv_regp
[rn
].pci_phys_hi
) &&
1231 (tgt_err
->tgt_pci_addr
& (PCI_REG_BUS_M
|
1232 PCI_REG_DEV_M
| PCI_REG_FUNC_M
)) ==
1233 (drv_regp
[rn
].pci_phys_hi
& (PCI_REG_BUS_M
|
1234 PCI_REG_DEV_M
| PCI_REG_FUNC_M
))) {
1235 tgt_err
->tgt_dip
= dip
;
1236 kmem_free(drv_regp
, reglen
);
1237 return (DDI_WALK_TERMINATE
);
1240 kmem_free(drv_regp
, reglen
);
1243 * for non config space, need to check reg to look
1244 * for any non-relocable mapping, otherwise check
1245 * assigned-addresses.
1247 if (ddi_getlongprop(DDI_DEV_T_NONE
, dip
, DDI_PROP_DONTPASS
,
1248 "reg", (caddr_t
)&drv_regp
, ®len
) != DDI_SUCCESS
)
1249 return (DDI_WALK_CONTINUE
);
1251 totreg
= reglen
/ sizeof (pci_regspec_t
);
1252 for (rn
= 0; rn
< totreg
; rn
++) {
1253 if ((drv_regp
[rn
].pci_phys_hi
& PCI_RELOCAT_B
) &&
1254 (tgt_err
->tgt_pci_space
== TGT_PCI_SPACE_UNKNOWN
||
1255 tgt_err
->tgt_pci_space
==
1256 PCI_REG_ADDR_G(drv_regp
[rn
].pci_phys_hi
)) &&
1257 (tgt_err
->tgt_pci_addr
>=
1258 (uint64_t)drv_regp
[rn
].pci_phys_low
+
1259 ((uint64_t)drv_regp
[rn
].pci_phys_mid
<< 32)) &&
1260 (tgt_err
->tgt_pci_addr
<
1261 (uint64_t)drv_regp
[rn
].pci_phys_low
+
1262 ((uint64_t)drv_regp
[rn
].pci_phys_mid
<< 32) +
1263 (uint64_t)drv_regp
[rn
].pci_size_low
+
1264 ((uint64_t)drv_regp
[rn
].pci_size_hi
<< 32))) {
1265 tgt_err
->tgt_dip
= dip
;
1266 kmem_free(drv_regp
, reglen
);
1267 return (DDI_WALK_TERMINATE
);
1270 kmem_free(drv_regp
, reglen
);
1272 if (ddi_getlongprop(DDI_DEV_T_NONE
, dip
, DDI_PROP_DONTPASS
,
1273 "assigned-addresses", (caddr_t
)&drv_regp
, ®len
) !=
1275 return (DDI_WALK_CONTINUE
);
1277 totreg
= reglen
/ sizeof (pci_regspec_t
);
1278 for (rn
= 0; rn
< totreg
; rn
++) {
1279 if ((tgt_err
->tgt_pci_space
== TGT_PCI_SPACE_UNKNOWN
||
1280 tgt_err
->tgt_pci_space
==
1281 PCI_REG_ADDR_G(drv_regp
[rn
].pci_phys_hi
)) &&
1282 (tgt_err
->tgt_pci_addr
>=
1283 (uint64_t)drv_regp
[rn
].pci_phys_low
+
1284 ((uint64_t)drv_regp
[rn
].pci_phys_mid
<< 32)) &&
1285 (tgt_err
->tgt_pci_addr
<
1286 (uint64_t)drv_regp
[rn
].pci_phys_low
+
1287 ((uint64_t)drv_regp
[rn
].pci_phys_mid
<< 32) +
1288 (uint64_t)drv_regp
[rn
].pci_size_low
+
1289 ((uint64_t)drv_regp
[rn
].pci_size_hi
<< 32))) {
1290 tgt_err
->tgt_dip
= dip
;
1291 kmem_free(drv_regp
, reglen
);
1292 return (DDI_WALK_TERMINATE
);
1295 kmem_free(drv_regp
, reglen
);
1297 return (DDI_WALK_CONTINUE
);
1301 * impl_fix_ranges - fixes the config space entry of the "ranges"
1302 * property on psycho+ platforms. (if changing this function please make sure
1303 * to change the pci_fix_ranges function in pcipsy.c)
1307 pci_fix_ranges(dev_info_t
*dip
, pci_ranges_t
*pci_ranges
, int nrange
)
1309 #if defined(__sparc)
1310 char *name
= ddi_binding_name(dip
);
1312 if ((strcmp(name
, "pci108e,8000") == 0) ||
1313 (strcmp(name
, "pci108e,a000") == 0) ||
1314 (strcmp(name
, "pci108e,a001") == 0)) {
1316 for (i
= 0; i
< nrange
; i
++, pci_ranges
++)
1317 if ((pci_ranges
->child_high
& PCI_REG_ADDR_M
) ==
1319 pci_ranges
->parent_low
|=
1320 pci_ranges
->child_high
;
1326 pci_check_ranges(dev_info_t
*dip
, void *arg
)
1328 uint64_t range_parent_begin
;
1329 uint64_t range_parent_size
;
1330 uint64_t range_parent_end
;
1331 uint32_t space_type
;
1333 uint32_t range_offset
;
1334 pci_ranges_t
*pci_ranges
, *rangep
;
1335 pci_bus_range_t
*pci_bus_rangep
;
1336 int pci_ranges_length
;
1338 pci_target_err_t
*tgt_err
= (pci_target_err_t
*)arg
;
1340 if (strcmp(ddi_node_name(dip
), "pci") != 0 &&
1341 strcmp(ddi_node_name(dip
), "pciex") != 0)
1342 return (DDI_WALK_CONTINUE
);
1345 * Get the ranges property. Note we only look at the top level pci
1346 * node (hostbridge) which has a ranges property of type pci_ranges_t
1347 * not at pci-pci bridges.
1349 if (ddi_getlongprop(DDI_DEV_T_ANY
, dip
, DDI_PROP_DONTPASS
, "ranges",
1350 (caddr_t
)&pci_ranges
, &pci_ranges_length
) != DDI_SUCCESS
) {
1352 * no ranges property - no translation needed
1354 tgt_err
->tgt_pci_addr
= tgt_err
->tgt_err_addr
;
1355 tgt_err
->tgt_pci_space
= TGT_PCI_SPACE_UNKNOWN
;
1357 (void) pci_fm_walk_devs(ddi_get_child(dip
),
1358 pci_check_regs
, (void *)tgt_err
);
1361 ndi_devi_enter(dip
, &circ
);
1362 ddi_walk_devs(ddi_get_child(dip
), pci_check_regs
,
1364 ndi_devi_exit(dip
, circ
);
1366 if (tgt_err
->tgt_dip
!= NULL
)
1367 return (DDI_WALK_TERMINATE
);
1368 return (DDI_WALK_PRUNECHILD
);
1370 nrange
= pci_ranges_length
/ sizeof (pci_ranges_t
);
1371 rangep
= pci_ranges
;
1373 /* Need to fix the pci ranges property for psycho based systems */
1374 pci_fix_ranges(dip
, pci_ranges
, nrange
);
1376 for (i
= 0; i
< nrange
; i
++, rangep
++) {
1377 range_parent_begin
= ((uint64_t)rangep
->parent_high
<< 32) +
1379 range_parent_size
= ((uint64_t)rangep
->size_high
<< 32) +
1381 range_parent_end
= range_parent_begin
+ range_parent_size
- 1;
1383 if ((tgt_err
->tgt_err_addr
< range_parent_begin
) ||
1384 (tgt_err
->tgt_err_addr
> range_parent_end
)) {
1388 space_type
= PCI_REG_ADDR_G(rangep
->child_high
);
1389 if (space_type
== PCI_REG_ADDR_G(PCI_ADDR_CONFIG
)) {
1390 /* Config space address - check bus range */
1391 range_offset
= tgt_err
->tgt_err_addr
-
1393 bus_num
= PCI_REG_BUS_G(range_offset
);
1394 if (ddi_getlongprop(DDI_DEV_T_ANY
, dip
,
1395 DDI_PROP_DONTPASS
, "bus-range",
1396 (caddr_t
)&pci_bus_rangep
, &size
) != DDI_SUCCESS
) {
1399 if ((bus_num
< pci_bus_rangep
->lo
) ||
1400 (bus_num
> pci_bus_rangep
->hi
)) {
1402 * Bus number not appropriate for this
1405 kmem_free(pci_bus_rangep
, size
);
1408 kmem_free(pci_bus_rangep
, size
);
1411 /* We have a match if we get here - compute pci address */
1412 tgt_err
->tgt_pci_addr
= tgt_err
->tgt_err_addr
-
1414 tgt_err
->tgt_pci_addr
+= (((uint64_t)rangep
->child_mid
<< 32) +
1416 tgt_err
->tgt_pci_space
= space_type
;
1418 (void) pci_fm_walk_devs(ddi_get_child(dip
),
1419 pci_check_regs
, (void *)tgt_err
);
1422 ndi_devi_enter(dip
, &circ
);
1423 ddi_walk_devs(ddi_get_child(dip
), pci_check_regs
,
1425 ndi_devi_exit(dip
, circ
);
1427 if (tgt_err
->tgt_dip
!= NULL
) {
1428 kmem_free(pci_ranges
, pci_ranges_length
);
1429 return (DDI_WALK_TERMINATE
);
1432 kmem_free(pci_ranges
, pci_ranges_length
);
1433 return (DDI_WALK_PRUNECHILD
);
1437 * Function used to drain pci_target_queue, either during panic or after softint
1438 * is generated, to generate target device ereports based on captured physical
1443 pci_target_drain(void *private_p
, pci_target_err_t
*tgt_err
)
1445 char buf
[FM_MAX_CLASS
];
1448 * The following assumes that all pci_pci bridge devices
1449 * are configured as transparant. Find the top-level pci
1450 * nexus which has tgt_err_addr in one of its ranges, converting this
1451 * to a pci address in the process. Then starting at this node do
1452 * another tree walk to find a device with the pci address we've
1453 * found within range of one of it's assigned-addresses properties.
1455 tgt_err
->tgt_dip
= NULL
;
1457 (void) pci_fm_walk_devs(ddi_root_node(), pci_check_ranges
,
1460 ddi_walk_devs(ddi_root_node(), pci_check_ranges
,
1462 if (tgt_err
->tgt_dip
== NULL
)
1465 (void) snprintf(buf
, FM_MAX_CLASS
, "%s.%s", tgt_err
->tgt_bridge_type
,
1466 tgt_err
->tgt_err_class
);
1467 pci_fm_ereport_post(tgt_err
->tgt_dip
, buf
, tgt_err
->tgt_err_ena
, 0,
1468 PCI_PA
, DATA_TYPE_UINT64
, tgt_err
->tgt_err_addr
, NULL
);
1472 pci_target_enqueue(uint64_t ena
, char *class, char *bridge_type
, uint64_t addr
)
1474 pci_target_err_t tgt_err
;
1476 tgt_err
.tgt_err_ena
= ena
;
1477 tgt_err
.tgt_err_class
= class;
1478 tgt_err
.tgt_bridge_type
= bridge_type
;
1479 tgt_err
.tgt_err_addr
= addr
;
1480 errorq_dispatch(pci_target_queue
, (void *)&tgt_err
,
1481 sizeof (pci_target_err_t
), ERRORQ_ASYNC
);
1485 pci_targetq_init(void)
1488 * PCI target errorq, to schedule async handling of generation of
1489 * target device ereports based on captured physical address.
1490 * The errorq is created here but destroyed when _fini is called
1491 * for the pci module.
1493 if (pci_target_queue
== NULL
) {
1494 pci_target_queue
= errorq_create("pci_target_queue",
1495 (errorq_func_t
)pci_target_drain
, (void *)NULL
,
1496 TARGET_MAX_ERRS
, sizeof (pci_target_err_t
), FM_ERR_PIL
,
1498 if (pci_target_queue
== NULL
)
1499 panic("failed to create required system error queue");