Merge commit '7e934d3acc051b7ee3ef0d11571fd1225800a607'
[unleashed.git] / kernel / os / pcifm.c
blob2acc856c8efca7502afc3329840e67aa178f32e1
1 /*
2 * CDDL HEADER START
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]
19 * CDDL HEADER END
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>
34 #include <sys/pci.h>
35 #include <sys/pci_cap.h>
36 #include <sys/pci_impl.h>
37 #include <sys/epm.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, 0, NULL, 0,
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,
59 PCI_REC_TA, PCI_STAT_R_TARG_AB, PCI_TARG_REC_TA, DDI_FM_UNKNOWN,
60 PCI_SIG_TA, PCI_STAT_S_TARG_AB, NULL, DDI_FM_UNKNOWN,
61 NULL, 0, NULL, 0,
64 static pci_fm_err_t pcix_err_tbl[] = {
65 PCIX_SPL_DIS, PCI_PCIX_SPL_DSCD, NULL, DDI_FM_UNKNOWN,
66 PCIX_UNEX_SPL, PCI_PCIX_UNEX_SPL, NULL, DDI_FM_UNKNOWN,
67 PCIX_RX_SPL_MSG, PCI_PCIX_RX_SPL_MSG, NULL, DDI_FM_UNKNOWN,
68 NULL, 0, NULL, 0,
71 static pci_fm_err_t pcix_sec_err_tbl[] = {
72 PCIX_SPL_DIS, PCI_PCIX_BSS_SPL_DSCD, NULL, DDI_FM_UNKNOWN,
73 PCIX_UNEX_SPL, PCI_PCIX_BSS_UNEX_SPL, NULL, DDI_FM_UNKNOWN,
74 PCIX_BSS_SPL_OR, PCI_PCIX_BSS_SPL_OR, NULL, DDI_FM_OK,
75 PCIX_BSS_SPL_DLY, PCI_PCIX_BSS_SPL_DLY, NULL, DDI_FM_OK,
76 NULL, 0, NULL, 0,
79 static int
80 pci_config_check(ddi_acc_handle_t handle, int fme_flag)
82 ddi_acc_hdl_t *hp = impl_acc_hdl_get(handle);
83 ddi_fm_error_t de;
85 if (!(DDI_FM_ACC_ERR_CAP(ddi_fm_capable(hp->ah_dip))))
86 return (DDI_FM_OK);
88 de.fme_version = DDI_FME_VERSION;
90 ddi_fm_acc_err_get(handle, &de, de.fme_version);
91 if (de.fme_status != DDI_FM_OK) {
92 if (fme_flag == DDI_FM_ERR_UNEXPECTED) {
93 char buf[FM_MAX_CLASS];
95 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
96 PCI_ERROR_SUBCLASS, PCI_NR);
97 ddi_fm_ereport_post(hp->ah_dip, buf, de.fme_ena,
98 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, NULL);
100 ddi_fm_acc_err_clear(handle, de.fme_version);
102 return (de.fme_status);
105 static void
106 pcix_ecc_regs_gather(pci_erpt_t *erpt_p, pcix_ecc_regs_t *pcix_ecc_regs,
107 uint8_t pcix_cap_ptr, int fme_flag)
109 int bdg = erpt_p->pe_dflags & PCI_BRIDGE_DEV;
111 pcix_ecc_regs->pcix_ecc_ctlstat = pci_config_get32(erpt_p->pe_hdl,
112 (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_STATUS :
113 PCI_PCIX_ECC_STATUS)));
114 if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
115 pcix_ecc_regs->pcix_ecc_vflags |= PCIX_ERR_ECC_STS_VALID;
116 else
117 return;
118 pcix_ecc_regs->pcix_ecc_fstaddr = pci_config_get32(erpt_p->pe_hdl,
119 (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_FST_AD :
120 PCI_PCIX_ECC_FST_AD)));
121 pcix_ecc_regs->pcix_ecc_secaddr = pci_config_get32(erpt_p->pe_hdl,
122 (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_SEC_AD :
123 PCI_PCIX_ECC_SEC_AD)));
124 pcix_ecc_regs->pcix_ecc_attr = pci_config_get32((
125 ddi_acc_handle_t)erpt_p->pe_hdl,
126 (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_ATTR : PCI_PCIX_ECC_ATTR)));
129 static void
130 pcix_regs_gather(pci_erpt_t *erpt_p, void *pe_regs, int fme_flag)
132 if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
133 pcix_bdg_error_regs_t *pcix_bdg_regs =
134 (pcix_bdg_error_regs_t *)pe_regs;
135 uint8_t pcix_bdg_cap_ptr;
136 int i;
138 pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr;
139 pcix_bdg_regs->pcix_bdg_sec_stat = pci_config_get16(
140 erpt_p->pe_hdl, (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS));
141 if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
142 pcix_bdg_regs->pcix_bdg_vflags |=
143 PCIX_BDG_SEC_STATUS_VALID;
144 else
145 return;
146 pcix_bdg_regs->pcix_bdg_stat = pci_config_get32(erpt_p->pe_hdl,
147 (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS));
148 if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
149 pcix_bdg_regs->pcix_bdg_vflags |= PCIX_BDG_STATUS_VALID;
150 else
151 return;
152 if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
153 pcix_ecc_regs_t *pcix_bdg_ecc_regs;
155 for (i = 0; i < 2; i++) {
156 pcix_bdg_ecc_regs =
157 pcix_bdg_regs->pcix_bdg_ecc_regs[i];
158 pci_config_put32(erpt_p->pe_hdl,
159 (pcix_bdg_cap_ptr +
160 PCI_PCIX_BDG_ECC_STATUS), i);
161 pcix_ecc_regs_gather(erpt_p,
162 pcix_bdg_ecc_regs,
163 pcix_bdg_cap_ptr, fme_flag);
166 } else {
167 pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs;
168 uint8_t pcix_cap_ptr;
170 pcix_cap_ptr = pcix_regs->pcix_cap_ptr;
172 pcix_regs->pcix_command = pci_config_get16(erpt_p->pe_hdl,
173 (pcix_cap_ptr + PCI_PCIX_COMMAND));
174 pcix_regs->pcix_status = pci_config_get32(erpt_p->pe_hdl,
175 (pcix_cap_ptr + PCI_PCIX_STATUS));
176 if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
177 pcix_regs->pcix_vflags |= PCIX_ERR_STATUS_VALID;
178 else
179 return;
180 if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
181 pcix_ecc_regs_t *pcix_ecc_regs =
182 pcix_regs->pcix_ecc_regs;
184 pcix_ecc_regs_gather(erpt_p, pcix_ecc_regs,
185 pcix_cap_ptr, fme_flag);
190 /*ARGSUSED*/
191 static void
192 pci_regs_gather(dev_info_t *dip, pci_erpt_t *erpt_p, int fme_flag)
194 pci_error_regs_t *pci_regs = erpt_p->pe_pci_regs;
197 * Start by reading all the error registers that are available for
198 * pci and pci express and for leaf devices and bridges/switches
200 pci_regs->pci_err_status = pci_config_get16(erpt_p->pe_hdl,
201 PCI_CONF_STAT);
202 if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK)
203 return;
204 pci_regs->pci_vflags |= PCI_ERR_STATUS_VALID;
205 pci_regs->pci_cfg_comm = pci_config_get16(erpt_p->pe_hdl,
206 PCI_CONF_COMM);
207 if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK)
208 return;
211 * If pci-pci bridge grab PCI bridge specific error registers.
213 if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
214 pci_regs->pci_bdg_regs->pci_bdg_sec_stat =
215 pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS);
216 if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
217 pci_regs->pci_bdg_regs->pci_bdg_vflags |=
218 PCI_BDG_SEC_STAT_VALID;
219 pci_regs->pci_bdg_regs->pci_bdg_ctrl =
220 pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL);
221 if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
222 pci_regs->pci_bdg_regs->pci_bdg_vflags |=
223 PCI_BDG_CTRL_VALID;
226 /* If pci-x device grab error registers */
227 if (erpt_p->pe_dflags & PCIX_DEV)
228 pcix_regs_gather(erpt_p, erpt_p->pe_regs, fme_flag);
232 static void
233 pcix_regs_clear(pci_erpt_t *erpt_p, void *pe_regs)
235 if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
236 pcix_bdg_error_regs_t *pcix_bdg_regs =
237 (pcix_bdg_error_regs_t *)pe_regs;
238 uint8_t pcix_bdg_cap_ptr;
239 int i;
241 pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr;
243 if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID)
244 pci_config_put16(erpt_p->pe_hdl,
245 (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS),
246 pcix_bdg_regs->pcix_bdg_sec_stat);
248 if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID)
249 pci_config_put32(erpt_p->pe_hdl,
250 (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS),
251 pcix_bdg_regs->pcix_bdg_stat);
253 pcix_bdg_regs->pcix_bdg_vflags = 0x0;
255 if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
256 pcix_ecc_regs_t *pcix_bdg_ecc_regs;
257 for (i = 0; i < 2; i++) {
258 pcix_bdg_ecc_regs =
259 pcix_bdg_regs->pcix_bdg_ecc_regs[i];
261 if (pcix_bdg_ecc_regs->pcix_ecc_vflags &
262 PCIX_ERR_ECC_STS_VALID) {
263 pci_config_put32(erpt_p->pe_hdl,
264 (pcix_bdg_cap_ptr +
265 PCI_PCIX_BDG_ECC_STATUS),
268 pci_config_put32(erpt_p->pe_hdl,
269 (pcix_bdg_cap_ptr +
270 PCI_PCIX_BDG_ECC_STATUS),
271 pcix_bdg_ecc_regs->
272 pcix_ecc_ctlstat);
274 pcix_bdg_ecc_regs->pcix_ecc_vflags =
275 0x0;
278 } else {
279 pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs;
280 uint8_t pcix_cap_ptr;
282 pcix_cap_ptr = pcix_regs->pcix_cap_ptr;
284 if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID)
285 pci_config_put32(erpt_p->pe_hdl,
286 (pcix_cap_ptr + PCI_PCIX_STATUS),
287 pcix_regs->pcix_status);
289 pcix_regs->pcix_vflags = 0x0;
291 if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
292 pcix_ecc_regs_t *pcix_ecc_regs =
293 pcix_regs->pcix_ecc_regs;
295 if (pcix_ecc_regs->pcix_ecc_vflags &
296 PCIX_ERR_ECC_STS_VALID)
297 pci_config_put32(erpt_p->pe_hdl,
298 (pcix_cap_ptr + PCI_PCIX_ECC_STATUS),
299 pcix_ecc_regs->pcix_ecc_ctlstat);
301 pcix_ecc_regs->pcix_ecc_vflags = 0x0;
306 static void
307 pci_regs_clear(pci_erpt_t *erpt_p)
310 * Finally clear the error bits
312 if (erpt_p->pe_dflags & PCIX_DEV)
313 pcix_regs_clear(erpt_p, erpt_p->pe_regs);
315 if (erpt_p->pe_pci_regs->pci_vflags & PCI_ERR_STATUS_VALID)
316 pci_config_put16(erpt_p->pe_hdl, PCI_CONF_STAT,
317 erpt_p->pe_pci_regs->pci_err_status);
319 erpt_p->pe_pci_regs->pci_vflags = 0x0;
321 if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
322 if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags &
323 PCI_BDG_SEC_STAT_VALID)
324 pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS,
325 erpt_p->pe_pci_regs->pci_bdg_regs->
326 pci_bdg_sec_stat);
327 if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags &
328 PCI_BDG_CTRL_VALID)
329 pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL,
330 erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_ctrl);
332 erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags = 0x0;
337 * pcix_ereport_setup: Allocate structures for PCI-X error handling and ereport
338 * generation.
340 /* ARGSUSED */
341 static void
342 pcix_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p)
344 uint16_t pcix_cap_ptr = PCI_CAP_NEXT_PTR_NULL;
345 ddi_acc_handle_t eh;
346 int i;
348 if (pci_config_setup(dip, &eh) == DDI_SUCCESS) {
349 (void) PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCIX, &pcix_cap_ptr);
350 pci_config_teardown(&eh);
353 if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL)
354 erpt_p->pe_dflags |= PCIX_DEV;
355 else
356 return;
358 if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
359 pcix_bdg_error_regs_t *pcix_bdg_regs;
361 erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_bdg_error_regs_t),
362 KM_SLEEP);
363 pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs;
364 pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr;
365 pcix_bdg_regs->pcix_bdg_ver = pci_config_get16(erpt_p->pe_hdl,
366 pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
367 if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
368 for (i = 0; i < 2; i++) {
369 pcix_bdg_regs->pcix_bdg_ecc_regs[i] =
370 kmem_zalloc(sizeof (pcix_ecc_regs_t),
371 KM_SLEEP);
374 } else {
375 pcix_error_regs_t *pcix_regs;
377 erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_error_regs_t),
378 KM_SLEEP);
379 pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs;
380 pcix_regs->pcix_cap_ptr = pcix_cap_ptr;
381 pcix_regs->pcix_ver = pci_config_get16(erpt_p->pe_hdl,
382 pcix_cap_ptr + PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
383 if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
384 pcix_regs->pcix_ecc_regs = kmem_zalloc(
385 sizeof (pcix_ecc_regs_t), KM_SLEEP);
391 * pci_ereport_setup: Detect PCI device type and initialize structures to be
392 * used to generate ereports based on detected generic device errors.
394 void
395 pci_ereport_setup(dev_info_t *dip)
397 struct dev_info *devi = DEVI(dip);
398 struct i_ddi_fmhdl *fmhdl = devi->devi_fmhdl;
399 pci_erpt_t *erpt_p;
400 uint8_t pci_hdr_type;
401 uint16_t pci_status;
402 pci_regspec_t *pci_rp;
403 int32_t len;
404 uint32_t phys_hi;
407 * If device is not ereport capbable then report an error against the
408 * driver for using this interface,
410 if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) &&
411 !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
412 i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP);
413 return;
417 * ASSERT fmhdl exists and fh_bus_specific is NULL.
419 ASSERT(fmhdl && (fmhdl->fh_bus_specific == NULL));
421 erpt_p = kmem_zalloc(sizeof (pci_erpt_t), KM_SLEEP);
423 if (pci_config_setup(dip, &erpt_p->pe_hdl) != DDI_SUCCESS)
424 goto error;
426 erpt_p->pe_pci_regs = kmem_zalloc(sizeof (pci_error_regs_t), KM_SLEEP);
428 pci_status = pci_config_get16(erpt_p->pe_hdl, PCI_CONF_STAT);
429 if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) !=
430 DDI_FM_OK)
431 goto error;
434 * Get header type and record if device is a bridge.
436 pci_hdr_type = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_HEADER);
437 if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) !=
438 DDI_FM_OK)
439 goto error;
442 * Check to see if PCI device is a bridge, if so allocate pci bridge
443 * error register structure.
445 if ((pci_hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
446 erpt_p->pe_dflags |= PCI_BRIDGE_DEV;
447 erpt_p->pe_pci_regs->pci_bdg_regs = kmem_zalloc(
448 sizeof (pci_bdg_error_regs_t), KM_SLEEP);
451 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
452 (caddr_t)&pci_rp, &len) == DDI_SUCCESS) {
453 phys_hi = pci_rp->pci_phys_hi;
454 kmem_free(pci_rp, len);
456 erpt_p->pe_bdf = (uint16_t)(PCI_REG_BDFR_G(phys_hi) >>
457 PCI_REG_FUNC_SHIFT);
460 if (!(pci_status & PCI_STAT_CAP)) {
461 goto done;
464 /* Initialize structures for PCI-X devices. */
465 pcix_ereport_setup(dip, erpt_p);
467 done:
468 pci_regs_gather(dip, erpt_p, DDI_FM_ERR_UNEXPECTED);
469 pci_regs_clear(erpt_p);
472 * Before returning set fh_bus_specific to completed pci_erpt_t
473 * structure
475 fmhdl->fh_bus_specific = (void *)erpt_p;
477 return;
478 error:
479 if (erpt_p->pe_pci_regs)
480 kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t));
481 kmem_free(erpt_p, sizeof (pci_erpt_t));
482 erpt_p = NULL;
485 static void
486 pcix_ereport_teardown(pci_erpt_t *erpt_p)
488 if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
489 pcix_bdg_error_regs_t *pcix_bdg_regs;
490 uint16_t pcix_ver;
492 pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs;
493 pcix_ver = pcix_bdg_regs->pcix_bdg_ver;
494 if (PCIX_ECC_VER_CHECK(pcix_ver)) {
495 int i;
496 for (i = 0; i < 2; i++)
497 kmem_free(pcix_bdg_regs->pcix_bdg_ecc_regs[i],
498 sizeof (pcix_ecc_regs_t));
500 kmem_free(erpt_p->pe_regs, sizeof (pcix_bdg_error_regs_t));
501 } else {
502 pcix_error_regs_t *pcix_regs;
503 uint16_t pcix_ver;
505 pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs;
506 pcix_ver = pcix_regs->pcix_ver;
507 if (PCIX_ECC_VER_CHECK(pcix_ver)) {
508 kmem_free(pcix_regs->pcix_ecc_regs,
509 sizeof (pcix_ecc_regs_t));
511 kmem_free(erpt_p->pe_regs, sizeof (pcix_error_regs_t));
515 void
516 pci_ereport_teardown(dev_info_t *dip)
518 struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
519 pci_erpt_t *erpt_p;
521 if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) &&
522 !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
523 i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP);
526 ASSERT(fmhdl);
528 erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific;
529 if (erpt_p == NULL)
530 return;
532 if (erpt_p->pe_dflags & PCIX_DEV)
533 pcix_ereport_teardown(erpt_p);
534 pci_config_teardown((ddi_acc_handle_t *)&erpt_p->pe_hdl);
535 if (erpt_p->pe_dflags & PCI_BRIDGE_DEV)
536 kmem_free(erpt_p->pe_pci_regs->pci_bdg_regs,
537 sizeof (pci_bdg_error_regs_t));
538 kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t));
539 kmem_free(erpt_p, sizeof (pci_erpt_t));
540 fmhdl->fh_bus_specific = NULL;
543 * The following sparc specific code should be removed once the pci_cap
544 * interfaces create the necessary properties for us.
548 /*ARGSUSED*/
549 static int
550 pcix_check_addr(dev_info_t *dip, ddi_fm_error_t *derr,
551 pcix_ecc_regs_t *pcix_ecc_regs, int type)
553 int cmd = (pcix_ecc_regs->pcix_ecc_ctlstat >> 16) & 0xf;
554 uint64_t addr;
555 pci_fme_bus_specific_t *pci_fme_bsp =
556 (pci_fme_bus_specific_t *)derr->fme_bus_specific;
558 addr = pcix_ecc_regs->pcix_ecc_secaddr;
559 addr = addr << 32;
560 addr |= pcix_ecc_regs->pcix_ecc_fstaddr;
562 switch (cmd) {
563 case PCI_PCIX_CMD_INTR:
564 case PCI_PCIX_CMD_SPEC:
565 return (DDI_FM_FATAL);
566 case PCI_PCIX_CMD_IORD:
567 case PCI_PCIX_CMD_IOWR:
568 pci_fme_bsp->pci_bs_addr = addr;
569 pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID;
570 pci_fme_bsp->pci_bs_type = type;
571 return (DDI_FM_UNKNOWN);
572 case PCI_PCIX_CMD_DEVID:
573 return (DDI_FM_FATAL);
574 case PCI_PCIX_CMD_MEMRD_DW:
575 case PCI_PCIX_CMD_MEMWR:
576 case PCI_PCIX_CMD_MEMRD_BL:
577 case PCI_PCIX_CMD_MEMWR_BL:
578 pci_fme_bsp->pci_bs_addr = addr;
579 pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID;
580 pci_fme_bsp->pci_bs_type = type;
581 return (DDI_FM_UNKNOWN);
582 case PCI_PCIX_CMD_CFRD:
583 case PCI_PCIX_CMD_CFWR:
585 * for type 1 config transaction we can find bdf from address
587 if ((addr & 3) == 1) {
588 pci_fme_bsp->pci_bs_bdf = (addr >> 8) & 0xffffffff;
589 pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID;
590 pci_fme_bsp->pci_bs_type = type;
592 return (DDI_FM_UNKNOWN);
593 case PCI_PCIX_CMD_SPL:
594 case PCI_PCIX_CMD_DADR:
595 return (DDI_FM_UNKNOWN);
596 case PCI_PCIX_CMD_MEMRDBL:
597 case PCI_PCIX_CMD_MEMWRBL:
598 pci_fme_bsp->pci_bs_addr = addr;
599 pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID;
600 pci_fme_bsp->pci_bs_type = type;
601 return (DDI_FM_UNKNOWN);
602 default:
603 return (DDI_FM_FATAL);
607 /*ARGSUSED*/
608 static int
609 pci_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
611 pci_bdg_error_regs_t *pci_bdg_regs = erpt_p->pe_pci_regs->pci_bdg_regs;
612 int fatal = 0;
613 int nonfatal = 0;
614 int unknown = 0;
615 int ok = 0;
616 int ret = DDI_FM_OK;
617 char buf[FM_MAX_CLASS];
618 int i;
619 pci_fme_bus_specific_t *pci_fme_bsp =
620 (pci_fme_bus_specific_t *)derr->fme_bus_specific;
622 if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED)
623 goto done;
625 if ((pci_bdg_regs->pci_bdg_vflags & PCI_BDG_CTRL_VALID) &&
626 (pci_bdg_regs->pci_bdg_ctrl & PCI_BCNF_BCNTRL_DTO_STAT)) {
627 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
628 PCI_ERROR_SUBCLASS, PCI_DTO);
629 ddi_fm_ereport_post(dip, buf, derr->fme_ena,
630 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
631 PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16,
632 pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL,
633 DATA_TYPE_UINT16, pci_bdg_regs->pci_bdg_ctrl, NULL);
634 unknown++;
637 if (pci_bdg_regs->pci_bdg_vflags & PCI_BDG_SEC_STAT_VALID) {
638 for (i = 0; pci_bdg_err_tbl[i].err_class != NULL; i++) {
639 if (pci_bdg_regs->pci_bdg_sec_stat &
640 pci_bdg_err_tbl[i].reg_bit) {
641 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s",
642 PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS,
643 pci_bdg_err_tbl[i].err_class);
644 ddi_fm_ereport_post(dip, buf, derr->fme_ena,
645 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
646 PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16,
647 pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL,
648 DATA_TYPE_UINT16,
649 pci_bdg_regs->pci_bdg_ctrl, NULL);
650 PCI_FM_SEV_INC(pci_bdg_err_tbl[i].flags);
651 if (pci_fme_bsp && (pci_fme_bsp->pci_bs_flags &
652 PCI_BS_ADDR_VALID) &&
653 pci_fme_bsp->pci_bs_type == ACC_HANDLE &&
654 pci_bdg_err_tbl[i].terr_class)
655 pci_target_enqueue(derr->fme_ena,
656 pci_bdg_err_tbl[i].terr_class,
657 PCI_ERROR_SUBCLASS,
658 pci_fme_bsp->pci_bs_addr);
663 done:
665 * Need to check for poke and cautious put. We already know peek
666 * and cautious get errors occurred (as we got a trap) and we know
667 * they are nonfatal.
669 if (derr->fme_flag == DDI_FM_ERR_EXPECTED) {
671 * for cautious puts we treat all errors as nonfatal. Actually
672 * we set nonfatal for cautious gets as well - doesn't do any
673 * harm
675 if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB |
676 PCI_STAT_R_MAST_AB | PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR))
677 nonfatal++;
679 if (derr->fme_flag == DDI_FM_ERR_POKE) {
681 * special case for pokes - we only consider master abort
682 * and target abort as nonfatal. Sserr with no master abort is
683 * fatal, but master/target abort can come in on separate
684 * instance, so return unknown and parent will determine if
685 * nonfatal (if another child returned nonfatal - ie master
686 * or target abort) or fatal otherwise
688 if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB |
689 PCI_STAT_R_MAST_AB))
690 nonfatal++;
691 if (erpt_p->pe_pci_regs->pci_err_status & PCI_STAT_S_SYSERR)
692 unknown++;
696 * now check children below the bridge
698 ret = ndi_fm_handler_dispatch(dip, NULL, derr);
699 PCI_FM_SEV_INC(ret);
700 return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
701 (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
704 static int
705 pcix_ecc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
706 void *pe_regs)
708 pcix_error_regs_t *pcix_regs;
709 pcix_bdg_error_regs_t *pcix_bdg_regs;
710 pcix_ecc_regs_t *pcix_ecc_regs;
711 int bridge;
712 int i;
713 int ecc_phase;
714 int ecc_corr;
715 int sec_ue;
716 int sec_ce;
717 int fatal = 0;
718 int nonfatal = 0;
719 int unknown = 0;
720 int ok = 0;
721 char buf[FM_MAX_CLASS];
723 if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
724 pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs;
725 bridge = 1;
726 } else {
727 pcix_regs = (pcix_error_regs_t *)pe_regs;
728 bridge = 0;
731 for (i = 0; i < (bridge ? 2 : 1); i++) {
732 int ret = DDI_FM_OK;
733 pcix_ecc_regs = bridge ? pcix_bdg_regs->pcix_bdg_ecc_regs[i] :
734 pcix_regs->pcix_ecc_regs;
735 if (pcix_ecc_regs->pcix_ecc_vflags & PCIX_ERR_ECC_STS_VALID) {
736 ecc_phase = (pcix_ecc_regs->pcix_ecc_ctlstat &
737 PCI_PCIX_ECC_PHASE) >> 0x4;
738 ecc_corr = (pcix_ecc_regs->pcix_ecc_ctlstat &
739 PCI_PCIX_ECC_CORR);
740 sec_ue = (pcix_ecc_regs->pcix_ecc_ctlstat &
741 PCI_PCIX_ECC_S_UE);
742 sec_ce = (pcix_ecc_regs->pcix_ecc_ctlstat &
743 PCI_PCIX_ECC_S_CE);
745 switch (ecc_phase) {
746 case PCI_PCIX_ECC_PHASE_NOERR:
747 break;
748 case PCI_PCIX_ECC_PHASE_FADDR:
749 case PCI_PCIX_ECC_PHASE_SADDR:
750 PCI_FM_SEV_INC(ecc_corr ? DDI_FM_OK :
751 DDI_FM_FATAL);
752 (void) snprintf(buf, FM_MAX_CLASS,
753 "%s.%s%s", PCIX_ERROR_SUBCLASS,
754 i ? PCIX_SEC_ERROR_SUBCLASS : "",
755 ecc_corr ? PCIX_ECC_CE_ADDR :
756 PCIX_ECC_UE_ADDR);
757 break;
758 case PCI_PCIX_ECC_PHASE_ATTR:
759 PCI_FM_SEV_INC(ecc_corr ?
760 DDI_FM_OK : DDI_FM_FATAL);
761 (void) snprintf(buf, FM_MAX_CLASS,
762 "%s.%s%s", PCIX_ERROR_SUBCLASS,
763 i ? PCIX_SEC_ERROR_SUBCLASS : "",
764 ecc_corr ? PCIX_ECC_CE_ATTR :
765 PCIX_ECC_UE_ATTR);
766 break;
767 case PCI_PCIX_ECC_PHASE_DATA32:
768 case PCI_PCIX_ECC_PHASE_DATA64:
769 if (ecc_corr)
770 ret = DDI_FM_OK;
771 else {
772 int type;
773 pci_error_regs_t *pci_regs =
774 erpt_p->pe_pci_regs;
776 if (i) {
777 if (pci_regs->pci_bdg_regs->
778 pci_bdg_sec_stat &
779 PCI_STAT_S_PERROR)
780 type = ACC_HANDLE;
781 else
782 type = DMA_HANDLE;
783 } else {
784 if (pci_regs->pci_err_status &
785 PCI_STAT_S_PERROR)
786 type = DMA_HANDLE;
787 else
788 type = ACC_HANDLE;
790 ret = pcix_check_addr(dip, derr,
791 pcix_ecc_regs, type);
793 PCI_FM_SEV_INC(ret);
795 (void) snprintf(buf, FM_MAX_CLASS,
796 "%s.%s%s", PCIX_ERROR_SUBCLASS,
797 i ? PCIX_SEC_ERROR_SUBCLASS : "",
798 ecc_corr ? PCIX_ECC_CE_DATA :
799 PCIX_ECC_UE_DATA);
800 break;
802 if (ecc_phase)
803 if (bridge)
804 ddi_fm_ereport_post(dip, buf,
805 derr->fme_ena,
806 DDI_NOSLEEP, FM_VERSION,
807 DATA_TYPE_UINT8, 0,
808 PCIX_SEC_STATUS, DATA_TYPE_UINT16,
809 pcix_bdg_regs->pcix_bdg_sec_stat,
810 PCIX_BDG_STAT, DATA_TYPE_UINT32,
811 pcix_bdg_regs->pcix_bdg_stat,
812 PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
813 pcix_ecc_regs->pcix_ecc_ctlstat,
814 PCIX_ECC_ATTR, DATA_TYPE_UINT32,
815 pcix_ecc_regs->pcix_ecc_attr, NULL);
816 else
817 ddi_fm_ereport_post(dip, buf,
818 derr->fme_ena,
819 DDI_NOSLEEP, FM_VERSION,
820 DATA_TYPE_UINT8, 0,
821 PCIX_COMMAND, DATA_TYPE_UINT16,
822 pcix_regs->pcix_command,
823 PCIX_STATUS, DATA_TYPE_UINT32,
824 pcix_regs->pcix_status,
825 PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
826 pcix_ecc_regs->pcix_ecc_ctlstat,
827 PCIX_ECC_ATTR, DATA_TYPE_UINT32,
828 pcix_ecc_regs->pcix_ecc_attr, NULL);
829 if (sec_ce || sec_ue) {
830 (void) snprintf(buf, FM_MAX_CLASS,
831 "%s.%s%s", PCIX_ERROR_SUBCLASS,
832 i ? PCIX_SEC_ERROR_SUBCLASS : "",
833 sec_ce ? PCIX_ECC_S_CE : PCIX_ECC_S_UE);
834 if (bridge)
835 ddi_fm_ereport_post(dip, buf,
836 derr->fme_ena,
837 DDI_NOSLEEP, FM_VERSION,
838 DATA_TYPE_UINT8, 0,
839 PCIX_SEC_STATUS, DATA_TYPE_UINT16,
840 pcix_bdg_regs->pcix_bdg_sec_stat,
841 PCIX_BDG_STAT, DATA_TYPE_UINT32,
842 pcix_bdg_regs->pcix_bdg_stat,
843 PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
844 pcix_ecc_regs->pcix_ecc_ctlstat,
845 PCIX_ECC_ATTR, DATA_TYPE_UINT32,
846 pcix_ecc_regs->pcix_ecc_attr, NULL);
847 else
848 ddi_fm_ereport_post(dip, buf,
849 derr->fme_ena,
850 DDI_NOSLEEP, FM_VERSION,
851 DATA_TYPE_UINT8, 0,
852 PCIX_COMMAND, DATA_TYPE_UINT16,
853 pcix_regs->pcix_command,
854 PCIX_STATUS, DATA_TYPE_UINT32,
855 pcix_regs->pcix_status,
856 PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
857 pcix_ecc_regs->pcix_ecc_ctlstat,
858 PCIX_ECC_ATTR, DATA_TYPE_UINT32,
859 pcix_ecc_regs->pcix_ecc_attr, NULL);
860 PCI_FM_SEV_INC(sec_ue ? DDI_FM_FATAL :
861 DDI_FM_OK);
865 return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
866 (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
869 static int
870 pcix_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
871 void *pe_regs)
873 pcix_bdg_error_regs_t *pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs;
874 int fatal = 0;
875 int nonfatal = 0;
876 int unknown = 0;
877 int ok = 0;
878 char buf[FM_MAX_CLASS];
879 int i;
881 if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) {
882 for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) {
883 if ((pcix_bdg_regs->pcix_bdg_stat &
884 pcix_err_tbl[i].reg_bit)) {
885 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
886 PCIX_ERROR_SUBCLASS,
887 pcix_err_tbl[i].err_class);
888 ddi_fm_ereport_post(dip, buf, derr->fme_ena,
889 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
890 PCIX_SEC_STATUS, DATA_TYPE_UINT16,
891 pcix_bdg_regs->pcix_bdg_sec_stat,
892 PCIX_BDG_STAT, DATA_TYPE_UINT32,
893 pcix_bdg_regs->pcix_bdg_stat, NULL);
894 PCI_FM_SEV_INC(pcix_err_tbl[i].flags);
899 if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) {
900 for (i = 0; pcix_sec_err_tbl[i].err_class != NULL; i++) {
901 if ((pcix_bdg_regs->pcix_bdg_sec_stat &
902 pcix_sec_err_tbl[i].reg_bit)) {
903 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s%s",
904 PCIX_ERROR_SUBCLASS,
905 PCIX_SEC_ERROR_SUBCLASS,
906 pcix_sec_err_tbl[i].err_class);
907 ddi_fm_ereport_post(dip, buf, derr->fme_ena,
908 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
909 PCIX_SEC_STATUS, DATA_TYPE_UINT16,
910 pcix_bdg_regs->pcix_bdg_sec_stat,
911 PCIX_BDG_STAT, DATA_TYPE_UINT32,
912 pcix_bdg_regs->pcix_bdg_stat, NULL);
913 PCI_FM_SEV_INC(pcix_sec_err_tbl[i].flags);
918 /* Log/Handle ECC errors */
919 if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
920 int ret;
922 ret = pcix_ecc_error_report(dip, derr, erpt_p,
923 (void *)pcix_bdg_regs);
924 PCI_FM_SEV_INC(ret);
926 return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
927 (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
930 static int
931 pcix_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
933 pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs;
934 int fatal = 0;
935 int nonfatal = 0;
936 int unknown = 0;
937 int ok = 0;
938 char buf[FM_MAX_CLASS];
939 int i;
941 if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) {
942 for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) {
943 if (!(pcix_regs->pcix_status & pcix_err_tbl[i].reg_bit))
944 continue;
946 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
947 PCIX_ERROR_SUBCLASS, pcix_err_tbl[i].err_class);
948 ddi_fm_ereport_post(dip, buf, derr->fme_ena,
949 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
950 PCIX_COMMAND, DATA_TYPE_UINT16,
951 pcix_regs->pcix_command, PCIX_STATUS,
952 DATA_TYPE_UINT32, pcix_regs->pcix_status,
953 NULL);
954 PCI_FM_SEV_INC(pcix_err_tbl[i].flags);
957 /* Log/Handle ECC errors */
958 if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
959 int ret = pcix_ecc_error_report(dip, derr, erpt_p,
960 (void *)pcix_regs);
961 PCI_FM_SEV_INC(ret);
964 return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
965 (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
968 static void
969 pci_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
971 int fatal = 0;
972 int nonfatal = 0;
973 int unknown = 0;
974 int ok = 0;
975 char buf[FM_MAX_CLASS];
976 int i;
978 if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) {
980 * Log generic PCI errors.
982 for (i = 0; pci_err_tbl[i].err_class != NULL; i++) {
983 if (!(erpt_p->pe_pci_regs->pci_err_status &
984 pci_err_tbl[i].reg_bit) ||
985 !(erpt_p->pe_pci_regs->pci_vflags &
986 PCI_ERR_STATUS_VALID))
987 continue;
989 * Generate an ereport for this error bit.
991 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
992 PCI_ERROR_SUBCLASS, pci_err_tbl[i].err_class);
993 ddi_fm_ereport_post(dip, buf, derr->fme_ena,
994 DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
995 PCI_CONFIG_STATUS, DATA_TYPE_UINT16,
996 erpt_p->pe_pci_regs->pci_err_status,
997 PCI_CONFIG_COMMAND, DATA_TYPE_UINT16,
998 erpt_p->pe_pci_regs->pci_cfg_comm, NULL);
1000 PCI_FM_SEV_INC(pci_err_tbl[i].flags);
1002 if (erpt_p->pe_dflags & PCIX_DEV) {
1003 if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
1004 int ret = pcix_bdg_error_report(dip, derr,
1005 erpt_p, erpt_p->pe_regs);
1006 PCI_FM_SEV_INC(ret);
1007 } else {
1008 int ret = pcix_error_report(dip, derr, erpt_p);
1009 PCI_FM_SEV_INC(ret);
1014 if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV)) {
1015 int ret = pci_bdg_error_report(dip, derr, erpt_p);
1016 PCI_FM_SEV_INC(ret);
1019 if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) {
1020 pci_fme_bus_specific_t *pci_fme_bsp;
1021 int ret = DDI_FM_UNKNOWN;
1023 pci_fme_bsp = (pci_fme_bus_specific_t *)derr->fme_bus_specific;
1024 if (pci_fme_bsp->pci_bs_flags & PCI_BS_ADDR_VALID) {
1025 ret = ndi_fmc_entry_error(dip,
1026 pci_fme_bsp->pci_bs_type, derr,
1027 (void *)&pci_fme_bsp->pci_bs_addr);
1028 PCI_FM_SEV_INC(ret);
1031 * If we didn't find the handle using an addr, try using bdf.
1032 * Note we don't do this where the bdf is for a
1033 * device behind a pciex/pci bridge as the bridge may have
1034 * fabricated the bdf.
1036 if (ret == DDI_FM_UNKNOWN &&
1037 (pci_fme_bsp->pci_bs_flags & PCI_BS_BDF_VALID) &&
1038 pci_fme_bsp->pci_bs_bdf == erpt_p->pe_bdf) {
1039 ret = ndi_fmc_entry_error_all(dip,
1040 pci_fme_bsp->pci_bs_type, derr);
1041 PCI_FM_SEV_INC(ret);
1045 derr->fme_status = (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
1046 (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
1049 void
1050 pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *xx_status)
1052 struct i_ddi_fmhdl *fmhdl;
1053 pci_erpt_t *erpt_p;
1054 ddi_fm_error_t de;
1055 pci_fme_bus_specific_t pci_fme_bs;
1058 * On PCI Express systems, all error handling and ereport are done via
1059 * the PCIe misc module. This function is a no-op for PCIe Systems. In
1060 * order to tell if a system is a PCI or PCIe system, check that the
1061 * bus_private_data exists. If it exists, this is a PCIe system.
1063 if (ndi_get_bus_private(dip, B_TRUE)) {
1064 derr->fme_status = DDI_FM_OK;
1065 if (xx_status != NULL)
1066 *xx_status = 0x0;
1068 return;
1071 fmhdl = DEVI(dip)->devi_fmhdl;
1072 if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) &&
1073 !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
1074 i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP);
1075 return;
1079 * copy in the ddi_fm_error_t structure in case it's VER0
1081 de.fme_version = derr->fme_version;
1082 de.fme_status = derr->fme_status;
1083 de.fme_flag = derr->fme_flag;
1084 de.fme_ena = derr->fme_ena;
1085 de.fme_acc_handle = derr->fme_acc_handle;
1086 de.fme_dma_handle = derr->fme_dma_handle;
1087 de.fme_bus_specific = derr->fme_bus_specific;
1088 if (derr->fme_version >= DDI_FME_VER1)
1089 de.fme_bus_type = derr->fme_bus_type;
1090 else
1091 de.fme_bus_type = DDI_FME_BUS_TYPE_DFLT;
1092 if (de.fme_bus_type == DDI_FME_BUS_TYPE_DFLT) {
1094 * if this is the first pci device we've found convert
1095 * fme_bus_specific to DDI_FME_BUS_TYPE_PCI
1097 bzero(&pci_fme_bs, sizeof (pci_fme_bs));
1098 if (de.fme_bus_specific) {
1100 * the cpu passed us an addr - this can be used to look
1101 * up an access handle
1103 pci_fme_bs.pci_bs_addr = (uintptr_t)de.fme_bus_specific;
1104 pci_fme_bs.pci_bs_type = ACC_HANDLE;
1105 pci_fme_bs.pci_bs_flags |= PCI_BS_ADDR_VALID;
1107 de.fme_bus_specific = (void *)&pci_fme_bs;
1108 de.fme_bus_type = DDI_FME_BUS_TYPE_PCI;
1111 ASSERT(fmhdl);
1113 if (de.fme_ena == 0)
1114 de.fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
1116 erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific;
1117 if (erpt_p == NULL)
1118 return;
1120 pci_regs_gather(dip, erpt_p, de.fme_flag);
1121 pci_error_report(dip, &de, erpt_p);
1122 pci_regs_clear(erpt_p);
1124 derr->fme_status = de.fme_status;
1125 derr->fme_ena = de.fme_ena;
1126 derr->fme_acc_handle = de.fme_acc_handle;
1127 derr->fme_dma_handle = de.fme_dma_handle;
1128 if (xx_status != NULL)
1129 *xx_status = erpt_p->pe_pci_regs->pci_err_status;
1133 * private version of walk_devs() that can be used during panic. No
1134 * sleeping or locking required.
1136 static int
1137 pci_fm_walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg)
1139 while (dip) {
1140 switch ((*f)(dip, arg)) {
1141 case DDI_WALK_TERMINATE:
1142 return (DDI_WALK_TERMINATE);
1143 case DDI_WALK_CONTINUE:
1144 if (pci_fm_walk_devs(ddi_get_child(dip), f,
1145 arg) == DDI_WALK_TERMINATE)
1146 return (DDI_WALK_TERMINATE);
1147 break;
1148 case DDI_WALK_PRUNECHILD:
1149 break;
1151 dip = ddi_get_next_sibling(dip);
1153 return (DDI_WALK_CONTINUE);
1157 * need special version of ddi_fm_ereport_post() as the leaf driver may
1158 * not be hardened.
1160 static void
1161 pci_fm_ereport_post(dev_info_t *dip, const char *error_class, uint64_t ena,
1162 uint8_t version, ...)
1164 char *name;
1165 char device_path[MAXPATHLEN];
1166 char ddi_error_class[FM_MAX_CLASS];
1167 nvlist_t *ereport, *detector;
1168 nv_alloc_t *nva;
1169 errorq_elem_t *eqep;
1170 va_list ap;
1172 if (panicstr) {
1173 eqep = errorq_reserve(ereport_errorq);
1174 if (eqep == NULL)
1175 return;
1176 ereport = errorq_elem_nvl(ereport_errorq, eqep);
1177 nva = errorq_elem_nva(ereport_errorq, eqep);
1178 detector = fm_nvlist_create(nva);
1179 } else {
1180 ereport = fm_nvlist_create(NULL);
1181 detector = fm_nvlist_create(NULL);
1184 (void) ddi_pathname(dip, device_path);
1185 fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL,
1186 device_path, NULL, NULL);
1187 (void) snprintf(ddi_error_class, FM_MAX_CLASS, "%s.%s",
1188 DDI_IO_CLASS, error_class);
1189 fm_ereport_set(ereport, version, ddi_error_class, ena, detector, NULL);
1191 va_start(ap, version);
1192 name = va_arg(ap, char *);
1193 (void) i_fm_payload_set(ereport, name, ap);
1194 va_end(ap);
1196 if (panicstr) {
1197 errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC);
1198 } else {
1199 (void) fm_ereport_post(ereport, EVCH_TRYHARD);
1200 fm_nvlist_destroy(ereport, FM_NVA_FREE);
1201 fm_nvlist_destroy(detector, FM_NVA_FREE);
1205 static int
1206 pci_check_regs(dev_info_t *dip, void *arg)
1208 int reglen;
1209 int rn;
1210 int totreg;
1211 pci_regspec_t *drv_regp;
1212 pci_target_err_t *tgt_err = (pci_target_err_t *)arg;
1214 if (tgt_err->tgt_pci_space == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
1216 * for config space, we need to check if the given address
1217 * is a valid config space address for this device - based
1218 * on pci_phys_hi of the config space entry in reg property.
1220 if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
1221 "reg", (caddr_t)&drv_regp, &reglen) != DDI_SUCCESS)
1222 return (DDI_WALK_CONTINUE);
1224 totreg = reglen / sizeof (pci_regspec_t);
1225 for (rn = 0; rn < totreg; rn++) {
1226 if (tgt_err->tgt_pci_space ==
1227 PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi) &&
1228 (tgt_err->tgt_pci_addr & (PCI_REG_BUS_M |
1229 PCI_REG_DEV_M | PCI_REG_FUNC_M)) ==
1230 (drv_regp[rn].pci_phys_hi & (PCI_REG_BUS_M |
1231 PCI_REG_DEV_M | PCI_REG_FUNC_M))) {
1232 tgt_err->tgt_dip = dip;
1233 kmem_free(drv_regp, reglen);
1234 return (DDI_WALK_TERMINATE);
1237 kmem_free(drv_regp, reglen);
1238 } else {
1240 * for non config space, need to check reg to look
1241 * for any non-relocable mapping, otherwise check
1242 * assigned-addresses.
1244 if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
1245 "reg", (caddr_t)&drv_regp, &reglen) != DDI_SUCCESS)
1246 return (DDI_WALK_CONTINUE);
1248 totreg = reglen / sizeof (pci_regspec_t);
1249 for (rn = 0; rn < totreg; rn++) {
1250 if ((drv_regp[rn].pci_phys_hi & PCI_RELOCAT_B) &&
1251 (tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN ||
1252 tgt_err->tgt_pci_space ==
1253 PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) &&
1254 (tgt_err->tgt_pci_addr >=
1255 (uint64_t)drv_regp[rn].pci_phys_low +
1256 ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) &&
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 (uint64_t)drv_regp[rn].pci_size_low +
1261 ((uint64_t)drv_regp[rn].pci_size_hi << 32))) {
1262 tgt_err->tgt_dip = dip;
1263 kmem_free(drv_regp, reglen);
1264 return (DDI_WALK_TERMINATE);
1267 kmem_free(drv_regp, reglen);
1269 if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
1270 "assigned-addresses", (caddr_t)&drv_regp, &reglen) !=
1271 DDI_SUCCESS)
1272 return (DDI_WALK_CONTINUE);
1274 totreg = reglen / sizeof (pci_regspec_t);
1275 for (rn = 0; rn < totreg; rn++) {
1276 if ((tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN ||
1277 tgt_err->tgt_pci_space ==
1278 PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) &&
1279 (tgt_err->tgt_pci_addr >=
1280 (uint64_t)drv_regp[rn].pci_phys_low +
1281 ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) &&
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 (uint64_t)drv_regp[rn].pci_size_low +
1286 ((uint64_t)drv_regp[rn].pci_size_hi << 32))) {
1287 tgt_err->tgt_dip = dip;
1288 kmem_free(drv_regp, reglen);
1289 return (DDI_WALK_TERMINATE);
1292 kmem_free(drv_regp, reglen);
1294 return (DDI_WALK_CONTINUE);
1298 * impl_fix_ranges - fixes the config space entry of the "ranges"
1299 * property on psycho+ platforms. (if changing this function please make sure
1300 * to change the pci_fix_ranges function in pcipsy.c)
1302 /*ARGSUSED*/
1303 static void
1304 pci_fix_ranges(dev_info_t *dip, pci_ranges_t *pci_ranges, int nrange)
1308 static int
1309 pci_check_ranges(dev_info_t *dip, void *arg)
1311 uint64_t range_parent_begin;
1312 uint64_t range_parent_size;
1313 uint64_t range_parent_end;
1314 uint32_t space_type;
1315 uint32_t bus_num;
1316 uint32_t range_offset;
1317 pci_ranges_t *pci_ranges, *rangep;
1318 pci_bus_range_t *pci_bus_rangep;
1319 int pci_ranges_length;
1320 int nrange;
1321 pci_target_err_t *tgt_err = (pci_target_err_t *)arg;
1322 int i, size;
1323 if (strcmp(ddi_node_name(dip), "pci") != 0 &&
1324 strcmp(ddi_node_name(dip), "pciex") != 0)
1325 return (DDI_WALK_CONTINUE);
1328 * Get the ranges property. Note we only look at the top level pci
1329 * node (hostbridge) which has a ranges property of type pci_ranges_t
1330 * not at pci-pci bridges.
1332 if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
1333 (caddr_t)&pci_ranges, &pci_ranges_length) != DDI_SUCCESS) {
1335 * no ranges property - no translation needed
1337 tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr;
1338 tgt_err->tgt_pci_space = TGT_PCI_SPACE_UNKNOWN;
1339 if (panicstr)
1340 (void) pci_fm_walk_devs(ddi_get_child(dip),
1341 pci_check_regs, (void *)tgt_err);
1342 else {
1343 int circ = 0;
1344 ndi_devi_enter(dip, &circ);
1345 ddi_walk_devs(ddi_get_child(dip), pci_check_regs,
1346 (void *)tgt_err);
1347 ndi_devi_exit(dip, circ);
1349 if (tgt_err->tgt_dip != NULL)
1350 return (DDI_WALK_TERMINATE);
1351 return (DDI_WALK_PRUNECHILD);
1353 nrange = pci_ranges_length / sizeof (pci_ranges_t);
1354 rangep = pci_ranges;
1356 /* Need to fix the pci ranges property for psycho based systems */
1357 pci_fix_ranges(dip, pci_ranges, nrange);
1359 for (i = 0; i < nrange; i++, rangep++) {
1360 range_parent_begin = ((uint64_t)rangep->parent_high << 32) +
1361 rangep->parent_low;
1362 range_parent_size = ((uint64_t)rangep->size_high << 32) +
1363 rangep->size_low;
1364 range_parent_end = range_parent_begin + range_parent_size - 1;
1366 if ((tgt_err->tgt_err_addr < range_parent_begin) ||
1367 (tgt_err->tgt_err_addr > range_parent_end)) {
1368 /* Not in range */
1369 continue;
1371 space_type = PCI_REG_ADDR_G(rangep->child_high);
1372 if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
1373 /* Config space address - check bus range */
1374 range_offset = tgt_err->tgt_err_addr -
1375 range_parent_begin;
1376 bus_num = PCI_REG_BUS_G(range_offset);
1377 if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
1378 DDI_PROP_DONTPASS, "bus-range",
1379 (caddr_t)&pci_bus_rangep, &size) != DDI_SUCCESS) {
1380 continue;
1382 if ((bus_num < pci_bus_rangep->lo) ||
1383 (bus_num > pci_bus_rangep->hi)) {
1385 * Bus number not appropriate for this
1386 * pci nexus.
1388 kmem_free(pci_bus_rangep, size);
1389 continue;
1391 kmem_free(pci_bus_rangep, size);
1394 /* We have a match if we get here - compute pci address */
1395 tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr -
1396 range_parent_begin;
1397 tgt_err->tgt_pci_addr += (((uint64_t)rangep->child_mid << 32) +
1398 rangep->child_low);
1399 tgt_err->tgt_pci_space = space_type;
1400 if (panicstr)
1401 (void) pci_fm_walk_devs(ddi_get_child(dip),
1402 pci_check_regs, (void *)tgt_err);
1403 else {
1404 int circ = 0;
1405 ndi_devi_enter(dip, &circ);
1406 ddi_walk_devs(ddi_get_child(dip), pci_check_regs,
1407 (void *)tgt_err);
1408 ndi_devi_exit(dip, circ);
1410 if (tgt_err->tgt_dip != NULL) {
1411 kmem_free(pci_ranges, pci_ranges_length);
1412 return (DDI_WALK_TERMINATE);
1415 kmem_free(pci_ranges, pci_ranges_length);
1416 return (DDI_WALK_PRUNECHILD);
1420 * Function used to drain pci_target_queue, either during panic or after softint
1421 * is generated, to generate target device ereports based on captured physical
1422 * addresses
1424 /*ARGSUSED*/
1425 static void
1426 pci_target_drain(void *private_p, pci_target_err_t *tgt_err)
1428 char buf[FM_MAX_CLASS];
1431 * The following assumes that all pci_pci bridge devices
1432 * are configured as transparant. Find the top-level pci
1433 * nexus which has tgt_err_addr in one of its ranges, converting this
1434 * to a pci address in the process. Then starting at this node do
1435 * another tree walk to find a device with the pci address we've
1436 * found within range of one of it's assigned-addresses properties.
1438 tgt_err->tgt_dip = NULL;
1439 if (panicstr)
1440 (void) pci_fm_walk_devs(ddi_root_node(), pci_check_ranges,
1441 (void *)tgt_err);
1442 else
1443 ddi_walk_devs(ddi_root_node(), pci_check_ranges,
1444 (void *)tgt_err);
1445 if (tgt_err->tgt_dip == NULL)
1446 return;
1448 (void) snprintf(buf, FM_MAX_CLASS, "%s.%s", tgt_err->tgt_bridge_type,
1449 tgt_err->tgt_err_class);
1450 pci_fm_ereport_post(tgt_err->tgt_dip, buf, tgt_err->tgt_err_ena, 0,
1451 PCI_PA, DATA_TYPE_UINT64, tgt_err->tgt_err_addr, NULL);
1454 void
1455 pci_target_enqueue(uint64_t ena, char *class, char *bridge_type, uint64_t addr)
1457 pci_target_err_t tgt_err;
1459 tgt_err.tgt_err_ena = ena;
1460 tgt_err.tgt_err_class = class;
1461 tgt_err.tgt_bridge_type = bridge_type;
1462 tgt_err.tgt_err_addr = addr;
1463 errorq_dispatch(pci_target_queue, (void *)&tgt_err,
1464 sizeof (pci_target_err_t), ERRORQ_ASYNC);
1467 void
1468 pci_targetq_init(void)
1471 * PCI target errorq, to schedule async handling of generation of
1472 * target device ereports based on captured physical address.
1473 * The errorq is created here but destroyed when _fini is called
1474 * for the pci module.
1476 if (pci_target_queue == NULL) {
1477 pci_target_queue = errorq_create("pci_target_queue",
1478 (errorq_func_t)pci_target_drain, NULL,
1479 TARGET_MAX_ERRS, sizeof (pci_target_err_t), FM_ERR_PIL,
1480 ERRORQ_VITAL);
1481 if (pci_target_queue == NULL)
1482 panic("failed to create required system error queue");