xref: /illumos-gate/usr/src/uts/common/os/pcifm.c (revision 257873cfc1dd3337766407f80397db60a56f2f5a)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <sys/types.h>
28 #include <sys/sunndi.h>
29 #include <sys/sysmacros.h>
30 #include <sys/ddifm_impl.h>
31 #include <sys/fm/util.h>
32 #include <sys/fm/protocol.h>
33 #include <sys/fm/io/pci.h>
34 #include <sys/fm/io/ddi.h>
35 #include <sys/pci.h>
36 #include <sys/pci_cap.h>
37 #include <sys/pci_impl.h>
38 #include <sys/epm.h>
39 #include <sys/pcifm.h>
40 
41 #define	PCIX_ECC_VER_CHECK(x)	(((x) == PCI_PCIX_VER_1) ||\
42 				((x) == PCI_PCIX_VER_2))
43 
44 errorq_t *pci_target_queue = NULL;
45 
46 pci_fm_err_t pci_err_tbl[] = {
47 	PCI_DET_PERR,	PCI_STAT_PERROR,	NULL,		DDI_FM_UNKNOWN,
48 	PCI_MDPE,	PCI_STAT_S_PERROR,	PCI_TARG_MDPE,	DDI_FM_UNKNOWN,
49 	PCI_SIG_SERR,	PCI_STAT_S_SYSERR,	NULL,		DDI_FM_FATAL,
50 	PCI_MA,		PCI_STAT_R_MAST_AB,	PCI_TARG_MA,	DDI_FM_UNKNOWN,
51 	PCI_REC_TA,	PCI_STAT_R_TARG_AB,	PCI_TARG_REC_TA, DDI_FM_UNKNOWN,
52 	PCI_SIG_TA,	PCI_STAT_S_TARG_AB,	NULL,		DDI_FM_UNKNOWN,
53 	NULL, NULL, NULL, NULL,
54 };
55 
56 pci_fm_err_t pci_bdg_err_tbl[] = {
57 	PCI_DET_PERR,	PCI_STAT_PERROR,	NULL,		DDI_FM_UNKNOWN,
58 	PCI_MDPE,	PCI_STAT_S_PERROR,	PCI_TARG_MDPE,	DDI_FM_UNKNOWN,
59 	PCI_REC_SERR,	PCI_STAT_S_SYSERR,	NULL,		DDI_FM_UNKNOWN,
60 #if defined(__sparc)
61 	PCI_MA,		PCI_STAT_R_MAST_AB,	PCI_TARG_MA,	DDI_FM_UNKNOWN,
62 #endif
63 	PCI_REC_TA,	PCI_STAT_R_TARG_AB,	PCI_TARG_REC_TA, DDI_FM_UNKNOWN,
64 	PCI_SIG_TA,	PCI_STAT_S_TARG_AB,	NULL,		DDI_FM_UNKNOWN,
65 	NULL, NULL, NULL, NULL,
66 };
67 
68 static pci_fm_err_t pcix_err_tbl[] = {
69 	PCIX_SPL_DIS,		PCI_PCIX_SPL_DSCD,	NULL,	DDI_FM_UNKNOWN,
70 	PCIX_UNEX_SPL,		PCI_PCIX_UNEX_SPL,	NULL,	DDI_FM_UNKNOWN,
71 	PCIX_RX_SPL_MSG,	PCI_PCIX_RX_SPL_MSG,	NULL,   DDI_FM_UNKNOWN,
72 	NULL, NULL, NULL, NULL,
73 };
74 
75 static pci_fm_err_t pcix_sec_err_tbl[] = {
76 	PCIX_SPL_DIS,		PCI_PCIX_BSS_SPL_DSCD,	NULL,	DDI_FM_UNKNOWN,
77 	PCIX_UNEX_SPL,		PCI_PCIX_BSS_UNEX_SPL,	NULL,	DDI_FM_UNKNOWN,
78 	PCIX_BSS_SPL_OR,	PCI_PCIX_BSS_SPL_OR,	NULL,	DDI_FM_OK,
79 	PCIX_BSS_SPL_DLY,	PCI_PCIX_BSS_SPL_DLY,	NULL,	DDI_FM_OK,
80 	NULL, NULL, NULL, NULL,
81 };
82 
83 static int
84 pci_config_check(ddi_acc_handle_t handle, int fme_flag)
85 {
86 	ddi_acc_hdl_t *hp = impl_acc_hdl_get(handle);
87 	ddi_fm_error_t de;
88 
89 	if (!(DDI_FM_ACC_ERR_CAP(ddi_fm_capable(hp->ah_dip))))
90 		return (DDI_FM_OK);
91 
92 	de.fme_version = DDI_FME_VERSION;
93 
94 	ddi_fm_acc_err_get(handle, &de, de.fme_version);
95 	if (de.fme_status != DDI_FM_OK) {
96 		if (fme_flag == DDI_FM_ERR_UNEXPECTED) {
97 			char buf[FM_MAX_CLASS];
98 
99 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
100 			    PCI_ERROR_SUBCLASS, PCI_NR);
101 			ddi_fm_ereport_post(hp->ah_dip, buf, de.fme_ena,
102 			    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0, NULL);
103 		}
104 		ddi_fm_acc_err_clear(handle, de.fme_version);
105 	}
106 	return (de.fme_status);
107 }
108 
109 static void
110 pcix_ecc_regs_gather(pci_erpt_t *erpt_p, pcix_ecc_regs_t *pcix_ecc_regs,
111     uint8_t pcix_cap_ptr, int fme_flag)
112 {
113 	int bdg = erpt_p->pe_dflags & PCI_BRIDGE_DEV;
114 
115 	pcix_ecc_regs->pcix_ecc_ctlstat = pci_config_get32(erpt_p->pe_hdl,
116 	    (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_STATUS :
117 	    PCI_PCIX_ECC_STATUS)));
118 	if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
119 		pcix_ecc_regs->pcix_ecc_vflags |= PCIX_ERR_ECC_STS_VALID;
120 	else
121 		return;
122 	pcix_ecc_regs->pcix_ecc_fstaddr = pci_config_get32(erpt_p->pe_hdl,
123 	    (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_FST_AD :
124 	    PCI_PCIX_ECC_FST_AD)));
125 	pcix_ecc_regs->pcix_ecc_secaddr = pci_config_get32(erpt_p->pe_hdl,
126 	    (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_SEC_AD :
127 	    PCI_PCIX_ECC_SEC_AD)));
128 	pcix_ecc_regs->pcix_ecc_attr = pci_config_get32((
129 	    ddi_acc_handle_t)erpt_p->pe_hdl,
130 	    (pcix_cap_ptr + (bdg ? PCI_PCIX_BDG_ECC_ATTR : PCI_PCIX_ECC_ATTR)));
131 }
132 
133 static void
134 pcix_regs_gather(pci_erpt_t *erpt_p, void *pe_regs, int fme_flag)
135 {
136 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
137 		pcix_bdg_error_regs_t *pcix_bdg_regs =
138 		    (pcix_bdg_error_regs_t *)pe_regs;
139 		uint8_t pcix_bdg_cap_ptr;
140 		int i;
141 
142 		pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr;
143 		pcix_bdg_regs->pcix_bdg_sec_stat = pci_config_get16(
144 		    erpt_p->pe_hdl, (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS));
145 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
146 			pcix_bdg_regs->pcix_bdg_vflags |=
147 			    PCIX_BDG_SEC_STATUS_VALID;
148 		else
149 			return;
150 		pcix_bdg_regs->pcix_bdg_stat = pci_config_get32(erpt_p->pe_hdl,
151 		    (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS));
152 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
153 			pcix_bdg_regs->pcix_bdg_vflags |= PCIX_BDG_STATUS_VALID;
154 		else
155 			return;
156 		if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
157 			pcix_ecc_regs_t *pcix_bdg_ecc_regs;
158 
159 			for (i = 0; i < 2; i++) {
160 				pcix_bdg_ecc_regs =
161 				    pcix_bdg_regs->pcix_bdg_ecc_regs[i];
162 				pci_config_put32(erpt_p->pe_hdl,
163 				    (pcix_bdg_cap_ptr +
164 				    PCI_PCIX_BDG_ECC_STATUS), i);
165 				pcix_ecc_regs_gather(erpt_p,
166 				    pcix_bdg_ecc_regs,
167 				    pcix_bdg_cap_ptr, fme_flag);
168 			}
169 		}
170 	} else {
171 		pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs;
172 		uint8_t pcix_cap_ptr;
173 
174 		pcix_cap_ptr = pcix_regs->pcix_cap_ptr;
175 
176 		pcix_regs->pcix_command = pci_config_get16(erpt_p->pe_hdl,
177 		    (pcix_cap_ptr + PCI_PCIX_COMMAND));
178 		pcix_regs->pcix_status = pci_config_get32(erpt_p->pe_hdl,
179 		    (pcix_cap_ptr + PCI_PCIX_STATUS));
180 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
181 			pcix_regs->pcix_vflags |= PCIX_ERR_STATUS_VALID;
182 		else
183 			return;
184 		if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
185 			pcix_ecc_regs_t *pcix_ecc_regs =
186 			    pcix_regs->pcix_ecc_regs;
187 
188 			pcix_ecc_regs_gather(erpt_p, pcix_ecc_regs,
189 			    pcix_cap_ptr, fme_flag);
190 		}
191 	}
192 }
193 
194 /*ARGSUSED*/
195 static void
196 pci_regs_gather(dev_info_t *dip, pci_erpt_t *erpt_p, int fme_flag)
197 {
198 	pci_error_regs_t *pci_regs = erpt_p->pe_pci_regs;
199 
200 	/*
201 	 * Start by reading all the error registers that are available for
202 	 * pci and pci express and for leaf devices and bridges/switches
203 	 */
204 	pci_regs->pci_err_status = pci_config_get16(erpt_p->pe_hdl,
205 	    PCI_CONF_STAT);
206 	if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK)
207 		return;
208 	pci_regs->pci_vflags |= PCI_ERR_STATUS_VALID;
209 	pci_regs->pci_cfg_comm = pci_config_get16(erpt_p->pe_hdl,
210 	    PCI_CONF_COMM);
211 	if (pci_config_check(erpt_p->pe_hdl, fme_flag) != DDI_FM_OK)
212 		return;
213 
214 	/*
215 	 * If pci-pci bridge grab PCI bridge specific error registers.
216 	 */
217 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
218 		pci_regs->pci_bdg_regs->pci_bdg_sec_stat =
219 		    pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS);
220 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
221 			pci_regs->pci_bdg_regs->pci_bdg_vflags |=
222 			    PCI_BDG_SEC_STAT_VALID;
223 		pci_regs->pci_bdg_regs->pci_bdg_ctrl =
224 		    pci_config_get16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL);
225 		if (pci_config_check(erpt_p->pe_hdl, fme_flag) == DDI_FM_OK)
226 			pci_regs->pci_bdg_regs->pci_bdg_vflags |=
227 			    PCI_BDG_CTRL_VALID;
228 	}
229 
230 	/* If pci-x device grab error registers */
231 	if (erpt_p->pe_dflags & PCIX_DEV)
232 		pcix_regs_gather(erpt_p, erpt_p->pe_regs, fme_flag);
233 
234 }
235 
236 static void
237 pcix_regs_clear(pci_erpt_t *erpt_p, void *pe_regs)
238 {
239 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
240 		pcix_bdg_error_regs_t *pcix_bdg_regs =
241 		    (pcix_bdg_error_regs_t *)pe_regs;
242 		uint8_t pcix_bdg_cap_ptr;
243 		int i;
244 
245 		pcix_bdg_cap_ptr = pcix_bdg_regs->pcix_bdg_cap_ptr;
246 
247 		if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID)
248 			pci_config_put16(erpt_p->pe_hdl,
249 			    (pcix_bdg_cap_ptr + PCI_PCIX_SEC_STATUS),
250 			    pcix_bdg_regs->pcix_bdg_sec_stat);
251 
252 		if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID)
253 			pci_config_put32(erpt_p->pe_hdl,
254 			    (pcix_bdg_cap_ptr + PCI_PCIX_BDG_STATUS),
255 			    pcix_bdg_regs->pcix_bdg_stat);
256 
257 		pcix_bdg_regs->pcix_bdg_vflags = 0x0;
258 
259 		if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
260 			pcix_ecc_regs_t *pcix_bdg_ecc_regs;
261 			for (i = 0; i < 2; i++) {
262 				pcix_bdg_ecc_regs =
263 				    pcix_bdg_regs->pcix_bdg_ecc_regs[i];
264 
265 				if (pcix_bdg_ecc_regs->pcix_ecc_vflags &
266 				    PCIX_ERR_ECC_STS_VALID) {
267 					pci_config_put32(erpt_p->pe_hdl,
268 					    (pcix_bdg_cap_ptr +
269 					    PCI_PCIX_BDG_ECC_STATUS),
270 					    i);
271 
272 					pci_config_put32(erpt_p->pe_hdl,
273 					    (pcix_bdg_cap_ptr +
274 					    PCI_PCIX_BDG_ECC_STATUS),
275 					    pcix_bdg_ecc_regs->
276 					    pcix_ecc_ctlstat);
277 				}
278 				pcix_bdg_ecc_regs->pcix_ecc_vflags =
279 				    0x0;
280 			}
281 		}
282 	} else {
283 		pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)pe_regs;
284 		uint8_t pcix_cap_ptr;
285 
286 		pcix_cap_ptr = pcix_regs->pcix_cap_ptr;
287 
288 		if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID)
289 			pci_config_put32(erpt_p->pe_hdl,
290 			    (pcix_cap_ptr + PCI_PCIX_STATUS),
291 			    pcix_regs->pcix_status);
292 
293 		pcix_regs->pcix_vflags = 0x0;
294 
295 		if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
296 			pcix_ecc_regs_t *pcix_ecc_regs =
297 			    pcix_regs->pcix_ecc_regs;
298 
299 			if (pcix_ecc_regs->pcix_ecc_vflags &
300 			    PCIX_ERR_ECC_STS_VALID)
301 				pci_config_put32(erpt_p->pe_hdl,
302 				    (pcix_cap_ptr + PCI_PCIX_ECC_STATUS),
303 				    pcix_ecc_regs->pcix_ecc_ctlstat);
304 
305 			pcix_ecc_regs->pcix_ecc_vflags = 0x0;
306 		}
307 	}
308 }
309 
310 static void
311 pci_regs_clear(pci_erpt_t *erpt_p)
312 {
313 	/*
314 	 * Finally clear the error bits
315 	 */
316 	if (erpt_p->pe_dflags & PCIX_DEV)
317 		pcix_regs_clear(erpt_p, erpt_p->pe_regs);
318 
319 	if (erpt_p->pe_pci_regs->pci_vflags & PCI_ERR_STATUS_VALID)
320 		pci_config_put16(erpt_p->pe_hdl, PCI_CONF_STAT,
321 		    erpt_p->pe_pci_regs->pci_err_status);
322 
323 	erpt_p->pe_pci_regs->pci_vflags = 0x0;
324 
325 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
326 		if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags &
327 		    PCI_BDG_SEC_STAT_VALID)
328 			pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_SEC_STATUS,
329 			    erpt_p->pe_pci_regs->pci_bdg_regs->
330 			    pci_bdg_sec_stat);
331 		if (erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags &
332 		    PCI_BDG_CTRL_VALID)
333 			pci_config_put16(erpt_p->pe_hdl, PCI_BCNF_BCNTRL,
334 			    erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_ctrl);
335 
336 		erpt_p->pe_pci_regs->pci_bdg_regs->pci_bdg_vflags = 0x0;
337 	}
338 }
339 
340 /*
341  * pcix_ereport_setup: Allocate structures for PCI-X error handling and ereport
342  * generation.
343  */
344 /* ARGSUSED */
345 static void
346 pcix_ereport_setup(dev_info_t *dip, pci_erpt_t *erpt_p)
347 {
348 	uint16_t pcix_cap_ptr = PCI_CAP_NEXT_PTR_NULL;
349 	ddi_acc_handle_t eh;
350 	int i;
351 
352 	if (pci_config_setup(dip, &eh) == DDI_SUCCESS) {
353 		(void) PCI_CAP_LOCATE(eh, PCI_CAP_ID_PCIX, &pcix_cap_ptr);
354 		pci_config_teardown(&eh);
355 	}
356 
357 	if (pcix_cap_ptr != PCI_CAP_NEXT_PTR_NULL)
358 		erpt_p->pe_dflags |= PCIX_DEV;
359 	else
360 		return;
361 
362 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
363 		pcix_bdg_error_regs_t *pcix_bdg_regs;
364 
365 		erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_bdg_error_regs_t),
366 		    KM_SLEEP);
367 		pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs;
368 		pcix_bdg_regs->pcix_bdg_cap_ptr = pcix_cap_ptr;
369 		pcix_bdg_regs->pcix_bdg_ver = pci_config_get16(erpt_p->pe_hdl,
370 		    pcix_cap_ptr + PCI_PCIX_SEC_STATUS) & PCI_PCIX_VER_MASK;
371 		if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
372 			for (i = 0; i < 2; i++) {
373 				pcix_bdg_regs->pcix_bdg_ecc_regs[i] =
374 				    kmem_zalloc(sizeof (pcix_ecc_regs_t),
375 				    KM_SLEEP);
376 			}
377 		}
378 	} else {
379 		pcix_error_regs_t *pcix_regs;
380 
381 		erpt_p->pe_regs = kmem_zalloc(sizeof (pcix_error_regs_t),
382 		    KM_SLEEP);
383 		pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs;
384 		pcix_regs->pcix_cap_ptr = pcix_cap_ptr;
385 		pcix_regs->pcix_ver = pci_config_get16(erpt_p->pe_hdl,
386 		    pcix_cap_ptr + PCI_PCIX_COMMAND) & PCI_PCIX_VER_MASK;
387 		if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
388 			pcix_regs->pcix_ecc_regs = kmem_zalloc(
389 			    sizeof (pcix_ecc_regs_t), KM_SLEEP);
390 		}
391 	}
392 }
393 
394 /*
395  * pci_ereport_setup: Detect PCI device type and initialize structures to be
396  * used to generate ereports based on detected generic device errors.
397  */
398 void
399 pci_ereport_setup(dev_info_t *dip)
400 {
401 	struct dev_info *devi = DEVI(dip);
402 	struct i_ddi_fmhdl *fmhdl = devi->devi_fmhdl;
403 	pci_erpt_t *erpt_p;
404 	uint8_t pci_hdr_type;
405 	uint16_t pci_status;
406 	pci_regspec_t *pci_rp;
407 	int32_t len;
408 	uint32_t phys_hi;
409 
410 	/*
411 	 * If device is not ereport capbable then report an error against the
412 	 * driver for using this interface,
413 	 */
414 	if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) &&
415 	    !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
416 		i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP);
417 		return;
418 	}
419 
420 	/*
421 	 * ASSERT fmhdl exists and fh_bus_specific is NULL.
422 	 */
423 	ASSERT(fmhdl && (fmhdl->fh_bus_specific == NULL));
424 
425 	erpt_p = kmem_zalloc(sizeof (pci_erpt_t), KM_SLEEP);
426 
427 	if (pci_config_setup(dip, &erpt_p->pe_hdl) != DDI_SUCCESS)
428 		goto error;
429 
430 	erpt_p->pe_pci_regs = kmem_zalloc(sizeof (pci_error_regs_t), KM_SLEEP);
431 
432 	pci_status = pci_config_get16(erpt_p->pe_hdl, PCI_CONF_STAT);
433 	if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) !=
434 	    DDI_FM_OK)
435 		goto error;
436 
437 	/*
438 	 * Get header type and record if device is a bridge.
439 	 */
440 	pci_hdr_type = pci_config_get8(erpt_p->pe_hdl, PCI_CONF_HEADER);
441 	if (pci_config_check(erpt_p->pe_hdl, DDI_FM_ERR_UNEXPECTED) !=
442 	    DDI_FM_OK)
443 		goto error;
444 
445 	/*
446 	 * Check to see if PCI device is a bridge, if so allocate pci bridge
447 	 * error register structure.
448 	 */
449 	if ((pci_hdr_type & PCI_HEADER_TYPE_M) == PCI_HEADER_PPB) {
450 		erpt_p->pe_dflags |= PCI_BRIDGE_DEV;
451 		erpt_p->pe_pci_regs->pci_bdg_regs = kmem_zalloc(
452 		    sizeof (pci_bdg_error_regs_t), KM_SLEEP);
453 	}
454 
455 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "reg",
456 	    (caddr_t)&pci_rp, &len) == DDI_SUCCESS) {
457 		phys_hi = pci_rp->pci_phys_hi;
458 		kmem_free(pci_rp, len);
459 
460 		erpt_p->pe_bdf = (uint16_t)(PCI_REG_BDFR_G(phys_hi) >>
461 		    PCI_REG_FUNC_SHIFT);
462 	}
463 
464 	if (!(pci_status & PCI_STAT_CAP)) {
465 		goto done;
466 	}
467 
468 	/* Initialize structures for PCI-X devices. */
469 	pcix_ereport_setup(dip, erpt_p);
470 
471 done:
472 	pci_regs_gather(dip, erpt_p, DDI_FM_ERR_UNEXPECTED);
473 	pci_regs_clear(erpt_p);
474 
475 	/*
476 	 * Before returning set fh_bus_specific to completed pci_erpt_t
477 	 * structure
478 	 */
479 	fmhdl->fh_bus_specific = (void *)erpt_p;
480 
481 	return;
482 error:
483 	if (erpt_p->pe_pci_regs)
484 		kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t));
485 	kmem_free(erpt_p, sizeof (pci_erpt_t));
486 	erpt_p = NULL;
487 }
488 
489 static void
490 pcix_ereport_teardown(pci_erpt_t *erpt_p)
491 {
492 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
493 		pcix_bdg_error_regs_t *pcix_bdg_regs;
494 		uint16_t pcix_ver;
495 
496 		pcix_bdg_regs = (pcix_bdg_error_regs_t *)erpt_p->pe_regs;
497 		pcix_ver = pcix_bdg_regs->pcix_bdg_ver;
498 		if (PCIX_ECC_VER_CHECK(pcix_ver)) {
499 			int i;
500 			for (i = 0; i < 2; i++)
501 				kmem_free(pcix_bdg_regs->pcix_bdg_ecc_regs[i],
502 				    sizeof (pcix_ecc_regs_t));
503 		}
504 		kmem_free(erpt_p->pe_regs, sizeof (pcix_bdg_error_regs_t));
505 	} else {
506 		pcix_error_regs_t *pcix_regs;
507 		uint16_t pcix_ver;
508 
509 		pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs;
510 		pcix_ver = pcix_regs->pcix_ver;
511 		if (PCIX_ECC_VER_CHECK(pcix_ver)) {
512 			kmem_free(pcix_regs->pcix_ecc_regs,
513 			    sizeof (pcix_ecc_regs_t));
514 		}
515 		kmem_free(erpt_p->pe_regs, sizeof (pcix_error_regs_t));
516 	}
517 }
518 
519 void
520 pci_ereport_teardown(dev_info_t *dip)
521 {
522 	struct i_ddi_fmhdl *fmhdl = DEVI(dip)->devi_fmhdl;
523 	pci_erpt_t *erpt_p;
524 
525 	if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) &&
526 	    !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
527 		i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_SLEEP);
528 	}
529 
530 	ASSERT(fmhdl);
531 
532 	erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific;
533 	if (erpt_p == NULL)
534 		return;
535 
536 	if (erpt_p->pe_dflags & PCIX_DEV)
537 		pcix_ereport_teardown(erpt_p);
538 	pci_config_teardown((ddi_acc_handle_t *)&erpt_p->pe_hdl);
539 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV)
540 		kmem_free(erpt_p->pe_pci_regs->pci_bdg_regs,
541 		    sizeof (pci_bdg_error_regs_t));
542 	kmem_free(erpt_p->pe_pci_regs, sizeof (pci_error_regs_t));
543 	kmem_free(erpt_p, sizeof (pci_erpt_t));
544 	fmhdl->fh_bus_specific = NULL;
545 
546 	/*
547 	 * The following sparc specific code should be removed once the pci_cap
548 	 * interfaces create the necessary properties for us.
549 	 */
550 }
551 
552 /*ARGSUSED*/
553 static int
554 pcix_check_addr(dev_info_t *dip, ddi_fm_error_t *derr,
555     pcix_ecc_regs_t *pcix_ecc_regs, int type)
556 {
557 	int cmd = (pcix_ecc_regs->pcix_ecc_ctlstat >> 16) & 0xf;
558 	uint64_t addr;
559 	pci_fme_bus_specific_t *pci_fme_bsp =
560 	    (pci_fme_bus_specific_t *)derr->fme_bus_specific;
561 
562 	addr = pcix_ecc_regs->pcix_ecc_secaddr;
563 	addr = addr << 32;
564 	addr |= pcix_ecc_regs->pcix_ecc_fstaddr;
565 
566 	switch (cmd) {
567 	case PCI_PCIX_CMD_INTR:
568 	case PCI_PCIX_CMD_SPEC:
569 		return (DDI_FM_FATAL);
570 	case PCI_PCIX_CMD_IORD:
571 	case PCI_PCIX_CMD_IOWR:
572 		pci_fme_bsp->pci_bs_addr = addr;
573 		pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID;
574 		pci_fme_bsp->pci_bs_type = type;
575 		return (DDI_FM_UNKNOWN);
576 	case PCI_PCIX_CMD_DEVID:
577 		return (DDI_FM_FATAL);
578 	case PCI_PCIX_CMD_MEMRD_DW:
579 	case PCI_PCIX_CMD_MEMWR:
580 	case PCI_PCIX_CMD_MEMRD_BL:
581 	case PCI_PCIX_CMD_MEMWR_BL:
582 		pci_fme_bsp->pci_bs_addr = addr;
583 		pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID;
584 		pci_fme_bsp->pci_bs_type = type;
585 		return (DDI_FM_UNKNOWN);
586 	case PCI_PCIX_CMD_CFRD:
587 	case PCI_PCIX_CMD_CFWR:
588 		/*
589 		 * for type 1 config transaction we can find bdf from address
590 		 */
591 		if ((addr & 3) == 1) {
592 			pci_fme_bsp->pci_bs_bdf = (addr >> 8) & 0xffffffff;
593 			pci_fme_bsp->pci_bs_flags |= PCI_BS_BDF_VALID;
594 			pci_fme_bsp->pci_bs_type = type;
595 		}
596 		return (DDI_FM_UNKNOWN);
597 	case PCI_PCIX_CMD_SPL:
598 	case PCI_PCIX_CMD_DADR:
599 		return (DDI_FM_UNKNOWN);
600 	case PCI_PCIX_CMD_MEMRDBL:
601 	case PCI_PCIX_CMD_MEMWRBL:
602 		pci_fme_bsp->pci_bs_addr = addr;
603 		pci_fme_bsp->pci_bs_flags |= PCI_BS_ADDR_VALID;
604 		pci_fme_bsp->pci_bs_type = type;
605 		return (DDI_FM_UNKNOWN);
606 	default:
607 		return (DDI_FM_FATAL);
608 	}
609 }
610 
611 /*ARGSUSED*/
612 static int
613 pci_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
614 {
615 	pci_bdg_error_regs_t *pci_bdg_regs = erpt_p->pe_pci_regs->pci_bdg_regs;
616 	int fatal = 0;
617 	int nonfatal = 0;
618 	int unknown = 0;
619 	int ok = 0;
620 	int ret = DDI_FM_OK;
621 	char buf[FM_MAX_CLASS];
622 	int i;
623 	pci_fme_bus_specific_t *pci_fme_bsp =
624 	    (pci_fme_bus_specific_t *)derr->fme_bus_specific;
625 
626 	if (derr->fme_flag != DDI_FM_ERR_UNEXPECTED)
627 		goto done;
628 
629 	if ((pci_bdg_regs->pci_bdg_vflags & PCI_BDG_CTRL_VALID) &&
630 	    (pci_bdg_regs->pci_bdg_ctrl & PCI_BCNF_BCNTRL_DTO_STAT)) {
631 		(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
632 		    PCI_ERROR_SUBCLASS, PCI_DTO);
633 		ddi_fm_ereport_post(dip, buf, derr->fme_ena,
634 		    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
635 		    PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16,
636 		    pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL,
637 		    DATA_TYPE_UINT16, pci_bdg_regs->pci_bdg_ctrl, NULL);
638 		unknown++;
639 	}
640 
641 	if (pci_bdg_regs->pci_bdg_vflags & PCI_BDG_SEC_STAT_VALID) {
642 		for (i = 0; pci_bdg_err_tbl[i].err_class != NULL; i++) {
643 			if (pci_bdg_regs->pci_bdg_sec_stat &
644 			    pci_bdg_err_tbl[i].reg_bit) {
645 				(void) snprintf(buf, FM_MAX_CLASS, "%s.%s-%s",
646 				    PCI_ERROR_SUBCLASS, PCI_SEC_ERROR_SUBCLASS,
647 				    pci_bdg_err_tbl[i].err_class);
648 				ddi_fm_ereport_post(dip, buf, derr->fme_ena,
649 				    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
650 				    PCI_SEC_CONFIG_STATUS, DATA_TYPE_UINT16,
651 				    pci_bdg_regs->pci_bdg_sec_stat, PCI_BCNTRL,
652 				    DATA_TYPE_UINT16,
653 				    pci_bdg_regs->pci_bdg_ctrl, NULL);
654 				PCI_FM_SEV_INC(pci_bdg_err_tbl[i].flags);
655 				if (pci_fme_bsp && (pci_fme_bsp->pci_bs_flags &
656 				    PCI_BS_ADDR_VALID) &&
657 				    pci_fme_bsp->pci_bs_type == ACC_HANDLE &&
658 				    pci_bdg_err_tbl[i].terr_class)
659 					pci_target_enqueue(derr->fme_ena,
660 					    pci_bdg_err_tbl[i].terr_class,
661 					    PCI_ERROR_SUBCLASS,
662 					    pci_fme_bsp->pci_bs_addr);
663 			}
664 		}
665 	}
666 
667 done:
668 	/*
669 	 * Need to check for poke and cautious put. We already know peek
670 	 * and cautious get errors occurred (as we got a trap) and we know
671 	 * they are nonfatal.
672 	 */
673 	if (derr->fme_flag == DDI_FM_ERR_EXPECTED) {
674 		/*
675 		 * for cautious puts we treat all errors as nonfatal. Actually
676 		 * we set nonfatal for cautious gets as well - doesn't do any
677 		 * harm
678 		 */
679 		if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB |
680 		    PCI_STAT_R_MAST_AB | PCI_STAT_S_PERROR | PCI_STAT_S_SYSERR))
681 			nonfatal++;
682 	}
683 	if (derr->fme_flag == DDI_FM_ERR_POKE) {
684 		/*
685 		 * special case for pokes - we only consider master abort
686 		 * and target abort as nonfatal. Sserr with no master abort is
687 		 * fatal, but master/target abort can come in on separate
688 		 * instance, so return unknown and parent will determine if
689 		 * nonfatal (if another child returned nonfatal - ie master
690 		 * or target abort) or fatal otherwise
691 		 */
692 		if (pci_bdg_regs->pci_bdg_sec_stat & (PCI_STAT_R_TARG_AB |
693 		    PCI_STAT_R_MAST_AB))
694 			nonfatal++;
695 		if (erpt_p->pe_pci_regs->pci_err_status & PCI_STAT_S_SYSERR)
696 			unknown++;
697 	}
698 
699 	/*
700 	 * now check children below the bridge
701 	 */
702 	ret = ndi_fm_handler_dispatch(dip, NULL, derr);
703 	PCI_FM_SEV_INC(ret);
704 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
705 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
706 }
707 
708 static int
709 pcix_ecc_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
710     void *pe_regs)
711 {
712 	pcix_error_regs_t *pcix_regs;
713 	pcix_bdg_error_regs_t *pcix_bdg_regs;
714 	pcix_ecc_regs_t *pcix_ecc_regs;
715 	int bridge;
716 	int i;
717 	int ecc_phase;
718 	int ecc_corr;
719 	int sec_ue;
720 	int sec_ce;
721 	int fatal = 0;
722 	int nonfatal = 0;
723 	int unknown = 0;
724 	int ok = 0;
725 	char buf[FM_MAX_CLASS];
726 
727 	if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
728 		pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs;
729 		bridge = 1;
730 	} else {
731 		pcix_regs = (pcix_error_regs_t *)pe_regs;
732 		bridge = 0;
733 	}
734 
735 	for (i = 0; i < (bridge ? 2 : 1); i++) {
736 		int ret = DDI_FM_OK;
737 		pcix_ecc_regs = bridge ? pcix_bdg_regs->pcix_bdg_ecc_regs[i] :
738 		    pcix_regs->pcix_ecc_regs;
739 		if (pcix_ecc_regs->pcix_ecc_vflags & PCIX_ERR_ECC_STS_VALID) {
740 			ecc_phase = (pcix_ecc_regs->pcix_ecc_ctlstat &
741 			    PCI_PCIX_ECC_PHASE) >> 0x4;
742 			ecc_corr = (pcix_ecc_regs->pcix_ecc_ctlstat &
743 			    PCI_PCIX_ECC_CORR);
744 			sec_ue = (pcix_ecc_regs->pcix_ecc_ctlstat &
745 			    PCI_PCIX_ECC_S_UE);
746 			sec_ce = (pcix_ecc_regs->pcix_ecc_ctlstat &
747 			    PCI_PCIX_ECC_S_CE);
748 
749 			switch (ecc_phase) {
750 			case PCI_PCIX_ECC_PHASE_NOERR:
751 				break;
752 			case PCI_PCIX_ECC_PHASE_FADDR:
753 			case PCI_PCIX_ECC_PHASE_SADDR:
754 				PCI_FM_SEV_INC(ecc_corr ?  DDI_FM_OK :
755 				    DDI_FM_FATAL);
756 				(void) snprintf(buf, FM_MAX_CLASS,
757 				    "%s.%s%s", PCIX_ERROR_SUBCLASS,
758 				    i ? PCIX_SEC_ERROR_SUBCLASS : "",
759 				    ecc_corr ? PCIX_ECC_CE_ADDR :
760 				    PCIX_ECC_UE_ADDR);
761 				break;
762 			case PCI_PCIX_ECC_PHASE_ATTR:
763 				PCI_FM_SEV_INC(ecc_corr ?
764 				    DDI_FM_OK : DDI_FM_FATAL);
765 				(void) snprintf(buf, FM_MAX_CLASS,
766 				    "%s.%s%s", PCIX_ERROR_SUBCLASS,
767 				    i ? PCIX_SEC_ERROR_SUBCLASS : "",
768 				    ecc_corr ? PCIX_ECC_CE_ATTR :
769 				    PCIX_ECC_UE_ATTR);
770 				break;
771 			case PCI_PCIX_ECC_PHASE_DATA32:
772 			case PCI_PCIX_ECC_PHASE_DATA64:
773 				if (ecc_corr)
774 					ret = DDI_FM_OK;
775 				else {
776 					int type;
777 					pci_error_regs_t *pci_regs =
778 					    erpt_p->pe_pci_regs;
779 
780 					if (i) {
781 						if (pci_regs->pci_bdg_regs->
782 						    pci_bdg_sec_stat &
783 						    PCI_STAT_S_PERROR)
784 							type = ACC_HANDLE;
785 						else
786 							type = DMA_HANDLE;
787 					} else {
788 						if (pci_regs->pci_err_status &
789 						    PCI_STAT_S_PERROR)
790 							type = DMA_HANDLE;
791 						else
792 							type = ACC_HANDLE;
793 					}
794 					ret = pcix_check_addr(dip, derr,
795 					    pcix_ecc_regs, type);
796 				}
797 				PCI_FM_SEV_INC(ret);
798 
799 				(void) snprintf(buf, FM_MAX_CLASS,
800 				    "%s.%s%s", PCIX_ERROR_SUBCLASS,
801 				    i ? PCIX_SEC_ERROR_SUBCLASS : "",
802 				    ecc_corr ? PCIX_ECC_CE_DATA :
803 				    PCIX_ECC_UE_DATA);
804 				break;
805 			}
806 			if (ecc_phase)
807 				if (bridge)
808 					ddi_fm_ereport_post(dip, buf,
809 					    derr->fme_ena,
810 					    DDI_NOSLEEP, FM_VERSION,
811 					    DATA_TYPE_UINT8, 0,
812 					    PCIX_SEC_STATUS, DATA_TYPE_UINT16,
813 					    pcix_bdg_regs->pcix_bdg_sec_stat,
814 					    PCIX_BDG_STAT, DATA_TYPE_UINT32,
815 					    pcix_bdg_regs->pcix_bdg_stat,
816 					    PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
817 					    pcix_ecc_regs->pcix_ecc_ctlstat,
818 					    PCIX_ECC_ATTR, DATA_TYPE_UINT32,
819 					    pcix_ecc_regs->pcix_ecc_attr, NULL);
820 				else
821 					ddi_fm_ereport_post(dip, buf,
822 					    derr->fme_ena,
823 					    DDI_NOSLEEP, FM_VERSION,
824 					    DATA_TYPE_UINT8, 0,
825 					    PCIX_COMMAND, DATA_TYPE_UINT16,
826 					    pcix_regs->pcix_command,
827 					    PCIX_STATUS, DATA_TYPE_UINT32,
828 					    pcix_regs->pcix_status,
829 					    PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
830 					    pcix_ecc_regs->pcix_ecc_ctlstat,
831 					    PCIX_ECC_ATTR, DATA_TYPE_UINT32,
832 					    pcix_ecc_regs->pcix_ecc_attr, NULL);
833 			if (sec_ce || sec_ue) {
834 				(void) snprintf(buf, FM_MAX_CLASS,
835 				    "%s.%s%s", PCIX_ERROR_SUBCLASS,
836 				    i ? PCIX_SEC_ERROR_SUBCLASS : "",
837 				    sec_ce ? PCIX_ECC_S_CE : PCIX_ECC_S_UE);
838 				if (bridge)
839 					ddi_fm_ereport_post(dip, buf,
840 					    derr->fme_ena,
841 					    DDI_NOSLEEP, FM_VERSION,
842 					    DATA_TYPE_UINT8, 0,
843 					    PCIX_SEC_STATUS, DATA_TYPE_UINT16,
844 					    pcix_bdg_regs->pcix_bdg_sec_stat,
845 					    PCIX_BDG_STAT, DATA_TYPE_UINT32,
846 					    pcix_bdg_regs->pcix_bdg_stat,
847 					    PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
848 					    pcix_ecc_regs->pcix_ecc_ctlstat,
849 					    PCIX_ECC_ATTR, DATA_TYPE_UINT32,
850 					    pcix_ecc_regs->pcix_ecc_attr, NULL);
851 				else
852 					ddi_fm_ereport_post(dip, buf,
853 					    derr->fme_ena,
854 					    DDI_NOSLEEP, FM_VERSION,
855 					    DATA_TYPE_UINT8, 0,
856 					    PCIX_COMMAND, DATA_TYPE_UINT16,
857 					    pcix_regs->pcix_command,
858 					    PCIX_STATUS, DATA_TYPE_UINT32,
859 					    pcix_regs->pcix_status,
860 					    PCIX_ECC_CTLSTAT, DATA_TYPE_UINT32,
861 					    pcix_ecc_regs->pcix_ecc_ctlstat,
862 					    PCIX_ECC_ATTR, DATA_TYPE_UINT32,
863 					    pcix_ecc_regs->pcix_ecc_attr, NULL);
864 				PCI_FM_SEV_INC(sec_ue ? DDI_FM_FATAL :
865 				    DDI_FM_OK);
866 			}
867 		}
868 	}
869 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
870 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
871 }
872 
873 static int
874 pcix_bdg_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p,
875     void *pe_regs)
876 {
877 	pcix_bdg_error_regs_t *pcix_bdg_regs = (pcix_bdg_error_regs_t *)pe_regs;
878 	int fatal = 0;
879 	int nonfatal = 0;
880 	int unknown = 0;
881 	int ok = 0;
882 	char buf[FM_MAX_CLASS];
883 	int i;
884 
885 	if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_STATUS_VALID) {
886 		for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) {
887 			if ((pcix_bdg_regs->pcix_bdg_stat &
888 			    pcix_err_tbl[i].reg_bit)) {
889 				(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
890 				    PCIX_ERROR_SUBCLASS,
891 				    pcix_err_tbl[i].err_class);
892 				ddi_fm_ereport_post(dip, buf, derr->fme_ena,
893 				    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
894 				    PCIX_SEC_STATUS, DATA_TYPE_UINT16,
895 				    pcix_bdg_regs->pcix_bdg_sec_stat,
896 				    PCIX_BDG_STAT, DATA_TYPE_UINT32,
897 				    pcix_bdg_regs->pcix_bdg_stat, NULL);
898 				PCI_FM_SEV_INC(pcix_err_tbl[i].flags);
899 			}
900 		}
901 	}
902 
903 	if (pcix_bdg_regs->pcix_bdg_vflags & PCIX_BDG_SEC_STATUS_VALID) {
904 		for (i = 0; pcix_sec_err_tbl[i].err_class != NULL; i++) {
905 			if ((pcix_bdg_regs->pcix_bdg_sec_stat &
906 			    pcix_sec_err_tbl[i].reg_bit)) {
907 				(void) snprintf(buf, FM_MAX_CLASS, "%s.%s%s",
908 				    PCIX_ERROR_SUBCLASS,
909 				    PCIX_SEC_ERROR_SUBCLASS,
910 				    pcix_sec_err_tbl[i].err_class);
911 				ddi_fm_ereport_post(dip, buf, derr->fme_ena,
912 				    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
913 				    PCIX_SEC_STATUS, DATA_TYPE_UINT16,
914 				    pcix_bdg_regs->pcix_bdg_sec_stat,
915 				    PCIX_BDG_STAT, DATA_TYPE_UINT32,
916 				    pcix_bdg_regs->pcix_bdg_stat, NULL);
917 				PCI_FM_SEV_INC(pcix_sec_err_tbl[i].flags);
918 			}
919 		}
920 	}
921 
922 	/* Log/Handle ECC errors */
923 	if (PCIX_ECC_VER_CHECK(pcix_bdg_regs->pcix_bdg_ver)) {
924 		int ret;
925 
926 		ret = pcix_ecc_error_report(dip, derr, erpt_p,
927 		    (void *)pcix_bdg_regs);
928 		PCI_FM_SEV_INC(ret);
929 	}
930 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
931 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
932 }
933 
934 static int
935 pcix_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
936 {
937 	pcix_error_regs_t *pcix_regs = (pcix_error_regs_t *)erpt_p->pe_regs;
938 	int fatal = 0;
939 	int nonfatal = 0;
940 	int unknown = 0;
941 	int ok = 0;
942 	char buf[FM_MAX_CLASS];
943 	int i;
944 
945 	if (pcix_regs->pcix_vflags & PCIX_ERR_STATUS_VALID) {
946 		for (i = 0; pcix_err_tbl[i].err_class != NULL; i++) {
947 			if (!(pcix_regs->pcix_status & pcix_err_tbl[i].reg_bit))
948 				continue;
949 
950 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
951 			    PCIX_ERROR_SUBCLASS, pcix_err_tbl[i].err_class);
952 			ddi_fm_ereport_post(dip, buf, derr->fme_ena,
953 			    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
954 			    PCIX_COMMAND, DATA_TYPE_UINT16,
955 			    pcix_regs->pcix_command, PCIX_STATUS,
956 			    DATA_TYPE_UINT32, pcix_regs->pcix_status,
957 			    NULL);
958 			PCI_FM_SEV_INC(pcix_err_tbl[i].flags);
959 		}
960 	}
961 	/* Log/Handle ECC errors */
962 	if (PCIX_ECC_VER_CHECK(pcix_regs->pcix_ver)) {
963 		int ret = pcix_ecc_error_report(dip, derr, erpt_p,
964 		    (void *)pcix_regs);
965 		PCI_FM_SEV_INC(ret);
966 	}
967 
968 	return (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
969 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
970 }
971 
972 static void
973 pci_error_report(dev_info_t *dip, ddi_fm_error_t *derr, pci_erpt_t *erpt_p)
974 {
975 	int fatal = 0;
976 	int nonfatal = 0;
977 	int unknown = 0;
978 	int ok = 0;
979 	char buf[FM_MAX_CLASS];
980 	int i;
981 
982 	if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) {
983 		/*
984 		 * Log generic PCI errors.
985 		 */
986 		for (i = 0; pci_err_tbl[i].err_class != NULL; i++) {
987 			if (!(erpt_p->pe_pci_regs->pci_err_status &
988 			    pci_err_tbl[i].reg_bit) ||
989 			    !(erpt_p->pe_pci_regs->pci_vflags &
990 			    PCI_ERR_STATUS_VALID))
991 				continue;
992 			/*
993 			 * Generate an ereport for this error bit.
994 			 */
995 			(void) snprintf(buf, FM_MAX_CLASS, "%s.%s",
996 			    PCI_ERROR_SUBCLASS, pci_err_tbl[i].err_class);
997 			ddi_fm_ereport_post(dip, buf, derr->fme_ena,
998 			    DDI_NOSLEEP, FM_VERSION, DATA_TYPE_UINT8, 0,
999 			    PCI_CONFIG_STATUS, DATA_TYPE_UINT16,
1000 			    erpt_p->pe_pci_regs->pci_err_status,
1001 			    PCI_CONFIG_COMMAND, DATA_TYPE_UINT16,
1002 			    erpt_p->pe_pci_regs->pci_cfg_comm, NULL);
1003 
1004 			PCI_FM_SEV_INC(pci_err_tbl[i].flags);
1005 		}
1006 		if (erpt_p->pe_dflags & PCIX_DEV) {
1007 			if (erpt_p->pe_dflags & PCI_BRIDGE_DEV) {
1008 				int ret = pcix_bdg_error_report(dip, derr,
1009 				    erpt_p, erpt_p->pe_regs);
1010 				PCI_FM_SEV_INC(ret);
1011 			} else {
1012 				int ret = pcix_error_report(dip, derr, erpt_p);
1013 				PCI_FM_SEV_INC(ret);
1014 			}
1015 		}
1016 	}
1017 
1018 	if ((erpt_p->pe_dflags & PCI_BRIDGE_DEV)) {
1019 		int ret = pci_bdg_error_report(dip, derr, erpt_p);
1020 		PCI_FM_SEV_INC(ret);
1021 	}
1022 
1023 	if (derr->fme_flag == DDI_FM_ERR_UNEXPECTED) {
1024 		pci_fme_bus_specific_t *pci_fme_bsp;
1025 		int ret = DDI_FM_UNKNOWN;
1026 
1027 		pci_fme_bsp = (pci_fme_bus_specific_t *)derr->fme_bus_specific;
1028 		if (pci_fme_bsp->pci_bs_flags & PCI_BS_ADDR_VALID) {
1029 			ret = ndi_fmc_entry_error(dip,
1030 			    pci_fme_bsp->pci_bs_type, derr,
1031 			    (void *)&pci_fme_bsp->pci_bs_addr);
1032 			PCI_FM_SEV_INC(ret);
1033 		}
1034 		/*
1035 		 * If we didn't find the handle using an addr, try using bdf.
1036 		 * Note we don't do this where the bdf is for a
1037 		 * device behind a pciex/pci bridge as the bridge may have
1038 		 * fabricated the bdf.
1039 		 */
1040 		if (ret == DDI_FM_UNKNOWN &&
1041 		    (pci_fme_bsp->pci_bs_flags & PCI_BS_BDF_VALID) &&
1042 		    pci_fme_bsp->pci_bs_bdf == erpt_p->pe_bdf) {
1043 			ret = ndi_fmc_entry_error_all(dip,
1044 			    pci_fme_bsp->pci_bs_type, derr);
1045 			PCI_FM_SEV_INC(ret);
1046 		}
1047 	}
1048 
1049 	derr->fme_status = (fatal ? DDI_FM_FATAL : (nonfatal ? DDI_FM_NONFATAL :
1050 	    (unknown ? DDI_FM_UNKNOWN : DDI_FM_OK)));
1051 }
1052 
1053 void
1054 pci_ereport_post(dev_info_t *dip, ddi_fm_error_t *derr, uint16_t *xx_status)
1055 {
1056 	struct i_ddi_fmhdl *fmhdl;
1057 	pci_erpt_t *erpt_p;
1058 	ddi_fm_error_t de;
1059 	pci_fme_bus_specific_t pci_fme_bs;
1060 
1061 	/*
1062 	 * On PCI Express systems, all error handling and ereport are done via
1063 	 * the PCIe misc module.  This function is a no-op for PCIe Systems.  In
1064 	 * order to tell if a system is a PCI or PCIe system, check that the
1065 	 * bus_private_data exists.  If it exists, this is a PCIe system.
1066 	 */
1067 	if (ndi_get_bus_private(dip, B_TRUE)) {
1068 		derr->fme_status = DDI_FM_OK;
1069 		if (xx_status != NULL)
1070 			*xx_status = 0x0;
1071 
1072 		return;
1073 	}
1074 
1075 	fmhdl = DEVI(dip)->devi_fmhdl;
1076 	if (!DDI_FM_EREPORT_CAP(ddi_fm_capable(dip)) &&
1077 	    !DDI_FM_ERRCB_CAP(ddi_fm_capable(dip))) {
1078 		i_ddi_drv_ereport_post(dip, DVR_EFMCAP, NULL, DDI_NOSLEEP);
1079 		return;
1080 	}
1081 
1082 	/*
1083 	 * copy in the ddi_fm_error_t structure in case it's VER0
1084 	 */
1085 	de.fme_version = derr->fme_version;
1086 	de.fme_status = derr->fme_status;
1087 	de.fme_flag = derr->fme_flag;
1088 	de.fme_ena = derr->fme_ena;
1089 	de.fme_acc_handle = derr->fme_acc_handle;
1090 	de.fme_dma_handle = derr->fme_dma_handle;
1091 	de.fme_bus_specific = derr->fme_bus_specific;
1092 	if (derr->fme_version >= DDI_FME_VER1)
1093 		de.fme_bus_type = derr->fme_bus_type;
1094 	else
1095 		de.fme_bus_type = DDI_FME_BUS_TYPE_DFLT;
1096 	if (de.fme_bus_type == DDI_FME_BUS_TYPE_DFLT) {
1097 		/*
1098 		 * if this is the first pci device we've found convert
1099 		 * fme_bus_specific to DDI_FME_BUS_TYPE_PCI
1100 		 */
1101 		bzero(&pci_fme_bs, sizeof (pci_fme_bs));
1102 		if (de.fme_bus_specific) {
1103 			/*
1104 			 * the cpu passed us an addr - this can be used to look
1105 			 * up an access handle
1106 			 */
1107 			pci_fme_bs.pci_bs_addr = (uintptr_t)de.fme_bus_specific;
1108 			pci_fme_bs.pci_bs_type = ACC_HANDLE;
1109 			pci_fme_bs.pci_bs_flags |= PCI_BS_ADDR_VALID;
1110 		}
1111 		de.fme_bus_specific = (void *)&pci_fme_bs;
1112 		de.fme_bus_type = DDI_FME_BUS_TYPE_PCI;
1113 	}
1114 
1115 	ASSERT(fmhdl);
1116 
1117 	if (de.fme_ena == NULL)
1118 		de.fme_ena = fm_ena_generate(0, FM_ENA_FMT1);
1119 
1120 	erpt_p = (pci_erpt_t *)fmhdl->fh_bus_specific;
1121 	if (erpt_p == NULL)
1122 		return;
1123 
1124 	pci_regs_gather(dip, erpt_p, de.fme_flag);
1125 	pci_error_report(dip, &de, erpt_p);
1126 	pci_regs_clear(erpt_p);
1127 
1128 	derr->fme_status = de.fme_status;
1129 	derr->fme_ena = de.fme_ena;
1130 	derr->fme_acc_handle = de.fme_acc_handle;
1131 	derr->fme_dma_handle = de.fme_dma_handle;
1132 	if (xx_status != NULL)
1133 		*xx_status = erpt_p->pe_pci_regs->pci_err_status;
1134 }
1135 
1136 /*
1137  * private version of walk_devs() that can be used during panic. No
1138  * sleeping or locking required.
1139  */
1140 static int
1141 pci_fm_walk_devs(dev_info_t *dip, int (*f)(dev_info_t *, void *), void *arg)
1142 {
1143 	while (dip) {
1144 		switch ((*f)(dip, arg)) {
1145 		case DDI_WALK_TERMINATE:
1146 			return (DDI_WALK_TERMINATE);
1147 		case DDI_WALK_CONTINUE:
1148 			if (pci_fm_walk_devs(ddi_get_child(dip), f,
1149 			    arg) == DDI_WALK_TERMINATE)
1150 				return (DDI_WALK_TERMINATE);
1151 			break;
1152 		case DDI_WALK_PRUNECHILD:
1153 			break;
1154 		}
1155 		dip = ddi_get_next_sibling(dip);
1156 	}
1157 	return (DDI_WALK_CONTINUE);
1158 }
1159 
1160 /*
1161  * need special version of ddi_fm_ereport_post() as the leaf driver may
1162  * not be hardened.
1163  */
1164 static void
1165 pci_fm_ereport_post(dev_info_t *dip, const char *error_class, uint64_t ena,
1166     uint8_t version, ...)
1167 {
1168 	char *name;
1169 	char device_path[MAXPATHLEN];
1170 	char ddi_error_class[FM_MAX_CLASS];
1171 	nvlist_t *ereport, *detector;
1172 	nv_alloc_t *nva;
1173 	errorq_elem_t *eqep;
1174 	va_list ap;
1175 
1176 	if (panicstr) {
1177 		eqep = errorq_reserve(ereport_errorq);
1178 		if (eqep == NULL)
1179 			return;
1180 		ereport = errorq_elem_nvl(ereport_errorq, eqep);
1181 		nva = errorq_elem_nva(ereport_errorq, eqep);
1182 		detector = fm_nvlist_create(nva);
1183 	} else {
1184 		ereport = fm_nvlist_create(NULL);
1185 		detector = fm_nvlist_create(NULL);
1186 	}
1187 
1188 	(void) ddi_pathname(dip, device_path);
1189 	fm_fmri_dev_set(detector, FM_DEV_SCHEME_VERSION, NULL,
1190 	    device_path, NULL);
1191 	(void) snprintf(ddi_error_class, FM_MAX_CLASS, "%s.%s",
1192 	    DDI_IO_CLASS, error_class);
1193 	fm_ereport_set(ereport, version, ddi_error_class, ena, detector, NULL);
1194 
1195 	va_start(ap, version);
1196 	name = va_arg(ap, char *);
1197 	(void) i_fm_payload_set(ereport, name, ap);
1198 	va_end(ap);
1199 
1200 	if (panicstr) {
1201 		errorq_commit(ereport_errorq, eqep, ERRORQ_SYNC);
1202 	} else {
1203 		(void) fm_ereport_post(ereport, EVCH_TRYHARD);
1204 		fm_nvlist_destroy(ereport, FM_NVA_FREE);
1205 		fm_nvlist_destroy(detector, FM_NVA_FREE);
1206 	}
1207 }
1208 
1209 static int
1210 pci_check_regs(dev_info_t *dip, void *arg)
1211 {
1212 	int reglen;
1213 	int rn;
1214 	int totreg;
1215 	pci_regspec_t *drv_regp;
1216 	pci_target_err_t *tgt_err = (pci_target_err_t *)arg;
1217 
1218 	if (tgt_err->tgt_pci_space == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
1219 		/*
1220 		 * for config space, we need to check if the given address
1221 		 * is a valid config space address for this device - based
1222 		 * on pci_phys_hi of the config space entry in reg property.
1223 		 */
1224 		if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
1225 		    "reg", (caddr_t)&drv_regp, &reglen) != DDI_SUCCESS)
1226 			return (DDI_WALK_CONTINUE);
1227 
1228 		totreg = reglen / sizeof (pci_regspec_t);
1229 		for (rn = 0; rn < totreg; rn++) {
1230 			if (tgt_err->tgt_pci_space ==
1231 			    PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi) &&
1232 			    (tgt_err->tgt_pci_addr & (PCI_REG_BUS_M |
1233 			    PCI_REG_DEV_M | PCI_REG_FUNC_M)) ==
1234 			    (drv_regp[rn].pci_phys_hi & (PCI_REG_BUS_M |
1235 			    PCI_REG_DEV_M | PCI_REG_FUNC_M))) {
1236 				tgt_err->tgt_dip = dip;
1237 				kmem_free(drv_regp, reglen);
1238 				return (DDI_WALK_TERMINATE);
1239 			}
1240 		}
1241 		kmem_free(drv_regp, reglen);
1242 	} else {
1243 		/*
1244 		 * for non config space, need to check reg to look
1245 		 * for any non-relocable mapping, otherwise check
1246 		 * assigned-addresses.
1247 		 */
1248 		if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
1249 		    "reg", (caddr_t)&drv_regp, &reglen) != DDI_SUCCESS)
1250 			return (DDI_WALK_CONTINUE);
1251 
1252 		totreg = reglen / sizeof (pci_regspec_t);
1253 		for (rn = 0; rn < totreg; rn++) {
1254 			if ((drv_regp[rn].pci_phys_hi & PCI_RELOCAT_B) &&
1255 			    (tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN ||
1256 			    tgt_err->tgt_pci_space ==
1257 			    PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) &&
1258 			    (tgt_err->tgt_pci_addr >=
1259 			    (uint64_t)drv_regp[rn].pci_phys_low +
1260 			    ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) &&
1261 			    (tgt_err->tgt_pci_addr <
1262 			    (uint64_t)drv_regp[rn].pci_phys_low +
1263 			    ((uint64_t)drv_regp[rn].pci_phys_mid << 32) +
1264 			    (uint64_t)drv_regp[rn].pci_size_low +
1265 			    ((uint64_t)drv_regp[rn].pci_size_hi << 32))) {
1266 				tgt_err->tgt_dip = dip;
1267 				kmem_free(drv_regp, reglen);
1268 				return (DDI_WALK_TERMINATE);
1269 			}
1270 		}
1271 		kmem_free(drv_regp, reglen);
1272 
1273 		if (ddi_getlongprop(DDI_DEV_T_NONE, dip, DDI_PROP_DONTPASS,
1274 		    "assigned-addresses", (caddr_t)&drv_regp, &reglen) !=
1275 		    DDI_SUCCESS)
1276 			return (DDI_WALK_CONTINUE);
1277 
1278 		totreg = reglen / sizeof (pci_regspec_t);
1279 		for (rn = 0; rn < totreg; rn++) {
1280 			if ((tgt_err->tgt_pci_space == TGT_PCI_SPACE_UNKNOWN ||
1281 			    tgt_err->tgt_pci_space ==
1282 			    PCI_REG_ADDR_G(drv_regp[rn].pci_phys_hi)) &&
1283 			    (tgt_err->tgt_pci_addr >=
1284 			    (uint64_t)drv_regp[rn].pci_phys_low +
1285 			    ((uint64_t)drv_regp[rn].pci_phys_mid << 32)) &&
1286 			    (tgt_err->tgt_pci_addr <
1287 			    (uint64_t)drv_regp[rn].pci_phys_low +
1288 			    ((uint64_t)drv_regp[rn].pci_phys_mid << 32) +
1289 			    (uint64_t)drv_regp[rn].pci_size_low +
1290 			    ((uint64_t)drv_regp[rn].pci_size_hi << 32))) {
1291 				tgt_err->tgt_dip = dip;
1292 				kmem_free(drv_regp, reglen);
1293 				return (DDI_WALK_TERMINATE);
1294 			}
1295 		}
1296 		kmem_free(drv_regp, reglen);
1297 	}
1298 	return (DDI_WALK_CONTINUE);
1299 }
1300 
1301 /*
1302  * impl_fix_ranges - fixes the config space entry of the "ranges"
1303  * property on psycho+ platforms.  (if changing this function please make sure
1304  * to change the pci_fix_ranges function in pcipsy.c)
1305  */
1306 /*ARGSUSED*/
1307 static void
1308 pci_fix_ranges(dev_info_t *dip, pci_ranges_t *pci_ranges, int nrange)
1309 {
1310 #if defined(__sparc)
1311 	char *name = ddi_binding_name(dip);
1312 
1313 	if ((strcmp(name, "pci108e,8000") == 0) ||
1314 	    (strcmp(name, "pci108e,a000") == 0) ||
1315 	    (strcmp(name, "pci108e,a001") == 0)) {
1316 		int i;
1317 		for (i = 0; i < nrange; i++, pci_ranges++)
1318 			if ((pci_ranges->child_high & PCI_REG_ADDR_M) ==
1319 			    PCI_ADDR_CONFIG)
1320 				pci_ranges->parent_low |=
1321 				    pci_ranges->child_high;
1322 	}
1323 #endif
1324 }
1325 
1326 static int
1327 pci_check_ranges(dev_info_t *dip, void *arg)
1328 {
1329 	uint64_t range_parent_begin;
1330 	uint64_t range_parent_size;
1331 	uint64_t range_parent_end;
1332 	uint32_t space_type;
1333 	uint32_t bus_num;
1334 	uint32_t range_offset;
1335 	pci_ranges_t *pci_ranges, *rangep;
1336 	pci_bus_range_t *pci_bus_rangep;
1337 	int pci_ranges_length;
1338 	int nrange;
1339 	pci_target_err_t *tgt_err = (pci_target_err_t *)arg;
1340 	int i, size;
1341 	if (strcmp(ddi_node_name(dip), "pci") != 0 &&
1342 	    strcmp(ddi_node_name(dip), "pciex") != 0)
1343 		return (DDI_WALK_CONTINUE);
1344 
1345 	/*
1346 	 * Get the ranges property. Note we only look at the top level pci
1347 	 * node (hostbridge) which has a ranges property of type pci_ranges_t
1348 	 * not at pci-pci bridges.
1349 	 */
1350 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS, "ranges",
1351 	    (caddr_t)&pci_ranges, &pci_ranges_length) != DDI_SUCCESS) {
1352 		/*
1353 		 * no ranges property - no translation needed
1354 		 */
1355 		tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr;
1356 		tgt_err->tgt_pci_space = TGT_PCI_SPACE_UNKNOWN;
1357 		if (panicstr)
1358 			(void) pci_fm_walk_devs(ddi_get_child(dip),
1359 			    pci_check_regs, (void *)tgt_err);
1360 		else {
1361 			int circ = 0;
1362 			ndi_devi_enter(dip, &circ);
1363 			ddi_walk_devs(ddi_get_child(dip), pci_check_regs,
1364 			    (void *)tgt_err);
1365 			ndi_devi_exit(dip, circ);
1366 		}
1367 		if (tgt_err->tgt_dip != NULL)
1368 			return (DDI_WALK_TERMINATE);
1369 		return (DDI_WALK_PRUNECHILD);
1370 	}
1371 	nrange = pci_ranges_length / sizeof (pci_ranges_t);
1372 	rangep = pci_ranges;
1373 
1374 	/* Need to fix the pci ranges property for psycho based systems */
1375 	pci_fix_ranges(dip, pci_ranges, nrange);
1376 
1377 	for (i = 0; i < nrange; i++, rangep++) {
1378 		range_parent_begin = ((uint64_t)rangep->parent_high << 32) +
1379 		    rangep->parent_low;
1380 		range_parent_size = ((uint64_t)rangep->size_high << 32) +
1381 		    rangep->size_low;
1382 		range_parent_end = range_parent_begin + range_parent_size - 1;
1383 
1384 		if ((tgt_err->tgt_err_addr < range_parent_begin) ||
1385 		    (tgt_err->tgt_err_addr > range_parent_end)) {
1386 			/* Not in range */
1387 			continue;
1388 		}
1389 		space_type = PCI_REG_ADDR_G(rangep->child_high);
1390 		if (space_type == PCI_REG_ADDR_G(PCI_ADDR_CONFIG)) {
1391 			/* Config space address - check bus range */
1392 			range_offset = tgt_err->tgt_err_addr -
1393 			    range_parent_begin;
1394 			bus_num = PCI_REG_BUS_G(range_offset);
1395 			if (ddi_getlongprop(DDI_DEV_T_ANY, dip,
1396 			    DDI_PROP_DONTPASS, "bus-range",
1397 			    (caddr_t)&pci_bus_rangep, &size) != DDI_SUCCESS) {
1398 				continue;
1399 			}
1400 			if ((bus_num < pci_bus_rangep->lo) ||
1401 			    (bus_num > pci_bus_rangep->hi)) {
1402 				/*
1403 				 * Bus number not appropriate for this
1404 				 * pci nexus.
1405 				 */
1406 				kmem_free(pci_bus_rangep, size);
1407 				continue;
1408 			}
1409 			kmem_free(pci_bus_rangep, size);
1410 		}
1411 
1412 		/* We have a match if we get here - compute pci address */
1413 		tgt_err->tgt_pci_addr = tgt_err->tgt_err_addr -
1414 		    range_parent_begin;
1415 		tgt_err->tgt_pci_addr += (((uint64_t)rangep->child_mid << 32) +
1416 		    rangep->child_low);
1417 		tgt_err->tgt_pci_space = space_type;
1418 		if (panicstr)
1419 			(void) pci_fm_walk_devs(ddi_get_child(dip),
1420 			    pci_check_regs, (void *)tgt_err);
1421 		else {
1422 			int circ = 0;
1423 			ndi_devi_enter(dip, &circ);
1424 			ddi_walk_devs(ddi_get_child(dip), pci_check_regs,
1425 			    (void *)tgt_err);
1426 			ndi_devi_exit(dip, circ);
1427 		}
1428 		if (tgt_err->tgt_dip != NULL) {
1429 			kmem_free(pci_ranges, pci_ranges_length);
1430 			return (DDI_WALK_TERMINATE);
1431 		}
1432 	}
1433 	kmem_free(pci_ranges, pci_ranges_length);
1434 	return (DDI_WALK_PRUNECHILD);
1435 }
1436 
1437 /*
1438  * Function used to drain pci_target_queue, either during panic or after softint
1439  * is generated, to generate target device ereports based on captured physical
1440  * addresses
1441  */
1442 /*ARGSUSED*/
1443 static void
1444 pci_target_drain(void *private_p, pci_target_err_t *tgt_err)
1445 {
1446 	char buf[FM_MAX_CLASS];
1447 
1448 	/*
1449 	 * The following assumes that all pci_pci bridge devices
1450 	 * are configured as transparant. Find the top-level pci
1451 	 * nexus which has tgt_err_addr in one of its ranges, converting this
1452 	 * to a pci address in the process. Then starting at this node do
1453 	 * another tree walk to find a device with the pci address we've
1454 	 * found within range of one of it's assigned-addresses properties.
1455 	 */
1456 	tgt_err->tgt_dip = NULL;
1457 	if (panicstr)
1458 		(void) pci_fm_walk_devs(ddi_root_node(), pci_check_ranges,
1459 		    (void *)tgt_err);
1460 	else
1461 		ddi_walk_devs(ddi_root_node(), pci_check_ranges,
1462 		    (void *)tgt_err);
1463 	if (tgt_err->tgt_dip == NULL)
1464 		return;
1465 
1466 	(void) snprintf(buf, FM_MAX_CLASS, "%s.%s", tgt_err->tgt_bridge_type,
1467 	    tgt_err->tgt_err_class);
1468 	pci_fm_ereport_post(tgt_err->tgt_dip, buf, tgt_err->tgt_err_ena, 0,
1469 	    PCI_PA, DATA_TYPE_UINT64, tgt_err->tgt_err_addr, NULL);
1470 }
1471 
1472 void
1473 pci_target_enqueue(uint64_t ena, char *class, char *bridge_type, uint64_t addr)
1474 {
1475 	pci_target_err_t tgt_err;
1476 
1477 	tgt_err.tgt_err_ena = ena;
1478 	tgt_err.tgt_err_class = class;
1479 	tgt_err.tgt_bridge_type = bridge_type;
1480 	tgt_err.tgt_err_addr = addr;
1481 	errorq_dispatch(pci_target_queue, (void *)&tgt_err,
1482 	    sizeof (pci_target_err_t), ERRORQ_ASYNC);
1483 }
1484 
1485 void
1486 pci_targetq_init(void)
1487 {
1488 	/*
1489 	 * PCI target errorq, to schedule async handling of generation of
1490 	 * target device ereports based on captured physical address.
1491 	 * The errorq is created here but destroyed when _fini is called
1492 	 * for the pci module.
1493 	 */
1494 	if (pci_target_queue == NULL) {
1495 		pci_target_queue = errorq_create("pci_target_queue",
1496 		    (errorq_func_t)pci_target_drain, (void *)NULL,
1497 		    TARGET_MAX_ERRS, sizeof (pci_target_err_t), FM_ERR_PIL,
1498 		    ERRORQ_VITAL);
1499 		if (pci_target_queue == NULL)
1500 			panic("failed to create required system error queue");
1501 	}
1502 }
1503