xref: /titanic_50/usr/src/uts/common/io/hxge/hxge_fm.c (revision 45405cce0657d01714b3d014a0facf3bdce45736)
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 2009 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #include <hxge_impl.h>
28 #include <sys/ddifm.h>
29 #include <sys/fm/protocol.h>
30 #include <sys/fm/util.h>
31 #include <sys/fm/io/ddi.h>
32 
33 static hxge_fm_ereport_attr_t
34 *hxge_fm_get_ereport_attr(hxge_fm_ereport_id_t ereport_id);
35 
36 static int
37 hxge_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data);
38 
39 hxge_fm_ereport_attr_t hxge_fm_ereport_vmac[] = {
40 	{HXGE_FM_EREPORT_VMAC_LINK_DOWN,	"10g_link_down",
41 						DDI_FM_DEVICE_INTERN_UNCORR,
42 						DDI_SERVICE_LOST}
43 };
44 
45 hxge_fm_ereport_attr_t hxge_fm_ereport_pfc[] = {
46 	/*
47 	 * The following are part of LDF 0, non-fatal
48 	 */
49 	{HXGE_FM_EREPORT_PFC_TCAM_PAR_ERR,	"classifier_tcam_par_err",
50 						DDI_FM_DEVICE_INTERN_UNCORR,
51 						DDI_SERVICE_UNAFFECTED},
52 	{HXGE_FM_EREPORT_PFC_VLAN_PAR_ERR,	"classifier_vlan_par_err",
53 						DDI_FM_DEVICE_INTERN_UNCORR,
54 						DDI_SERVICE_UNAFFECTED},
55 	{HXGE_FM_EREPORT_PFC_PKT_DROP,		"classifier_pkt_drop_err",
56 						DDI_FM_DEVICE_INTERN_UNCORR,
57 						DDI_SERVICE_UNAFFECTED}
58 };
59 
60 hxge_fm_ereport_attr_t hxge_fm_ereport_rdmc[] = {
61 	/*
62 	 * The following are part of LDF1, fatal
63 	 */
64 	{HXGE_FM_EREPORT_RDMC_RBR_CPL_TO,	"rxdma_rbr_cpl_to",
65 						DDI_FM_DEVICE_NO_RESPONSE,
66 						DDI_SERVICE_DEGRADED},
67 	{HXGE_FM_EREPORT_RDMC_PEU_RESP_ERR,	"rxdma_peu_resp_err",
68 						DDI_FM_DEVICE_INVAL_STATE,
69 						DDI_SERVICE_DEGRADED},
70 	{HXGE_FM_EREPORT_RDMC_RCR_SHA_PAR,	"rxdma_rcr_sha_par_err",
71 						DDI_FM_DEVICE_INTERN_UNCORR,
72 						DDI_SERVICE_DEGRADED},
73 	{HXGE_FM_EREPORT_RDMC_RBR_PRE_PAR,	"rxdma_rbr_pre_par_err",
74 						DDI_FM_DEVICE_INTERN_UNCORR,
75 						DDI_SERVICE_DEGRADED},
76 	{HXGE_FM_EREPORT_RDMC_RBR_PRE_EMPTY,	"rxdma_rbr_pre_empty_err",
77 						DDI_FM_DEVICE_INTERN_UNCORR,
78 						DDI_SERVICE_DEGRADED},
79 	{HXGE_FM_EREPORT_RDMC_RCR_SHA_FULL,	"rxdma_rcr_sha_full",
80 						DDI_FM_DEVICE_INVAL_STATE,
81 						DDI_SERVICE_DEGRADED},
82 	{HXGE_FM_EREPORT_RDMC_RCRFULL,		"rxdma_rcr_full",
83 						DDI_FM_DEVICE_INVAL_STATE,
84 						DDI_SERVICE_DEGRADED},
85 	{HXGE_FM_EREPORT_RDMC_RBR_EMPTY,	"rxdma_rbr_empty",
86 						DDI_FM_DEVICE_INVAL_STATE,
87 						DDI_SERVICE_DEGRADED},
88 	{HXGE_FM_EREPORT_RDMC_RBRFULL,		"rxdma_rbr_full",
89 						DDI_FM_DEVICE_INVAL_STATE,
90 						DDI_SERVICE_DEGRADED},
91 	{HXGE_FM_EREPORT_RDMC_RCR_ERR,		"rxdma_completion_err",
92 						DDI_FM_DEVICE_INTERN_UNCORR,
93 						DDI_SERVICE_DEGRADED},
94 	/*
95 	 * Control/Data ram received a ecc double bit error.
96 	 * Fatal error. Part of Device Error 1
97 	 */
98 	{HXGE_FM_EREPORT_RDMC_CTRL_FIFO_DED,	"rxdma_ctrl_fifo_ded",
99 						DDI_FM_DEVICE_INTERN_UNCORR,
100 						DDI_SERVICE_DEGRADED},
101 	{HXGE_FM_EREPORT_RDMC_DATA_FIFO_DED,	"rxdma_data_fifo_ded",
102 						DDI_FM_DEVICE_INTERN_UNCORR,
103 						DDI_SERVICE_DEGRADED},
104 	/*
105 	 * Control/Data ram received a ecc single bit error.
106 	 * Non-Fatal error. Part of Device Error 0
107 	 */
108 	{HXGE_FM_EREPORT_RDMC_CTRL_FIFO_SEC,	"rxdma_ctrl_fifo_sec",
109 						DDI_FM_DEVICE_INTERN_CORR,
110 						DDI_SERVICE_UNAFFECTED},
111 	{HXGE_FM_EREPORT_RDMC_DATA_FIFO_SEC,	"rxdma_data_fifo_sec",
112 						DDI_FM_DEVICE_INTERN_CORR,
113 						DDI_SERVICE_UNAFFECTED}
114 };
115 
116 hxge_fm_ereport_attr_t hxge_fm_ereport_tdmc[] = {
117 	{HXGE_FM_EREPORT_TDMC_PEU_RESP_ERR,	"txdma_peu_resp_err",
118 						DDI_FM_DEVICE_INVAL_STATE,
119 						DDI_SERVICE_DEGRADED},
120 	{HXGE_FM_EREPORT_TDMC_PKT_SIZE_HDR_ERR,	"txdma_pkt_size_hdr_err",
121 						DDI_FM_DEVICE_INVAL_STATE,
122 						DDI_SERVICE_DEGRADED},
123 	{HXGE_FM_EREPORT_TDMC_RUNT_PKT_DROP_ERR, "txdma_runt_pkt_drop_err",
124 						DDI_FM_DEVICE_INVAL_STATE,
125 						DDI_SERVICE_DEGRADED},
126 	{HXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR,	"txdma_pkt_size_err",
127 						DDI_FM_DEVICE_INVAL_STATE,
128 						DDI_SERVICE_DEGRADED},
129 	{HXGE_FM_EREPORT_TDMC_TX_RNG_OFLOW,	"txdma_tx_rng_oflow",
130 						DDI_FM_DEVICE_INVAL_STATE,
131 						DDI_SERVICE_DEGRADED},
132 	{HXGE_FM_EREPORT_TDMC_PREF_PAR_ERR,	"txdma_pref_par_err",
133 						DDI_FM_DEVICE_INTERN_UNCORR,
134 						DDI_SERVICE_DEGRADED},
135 	{HXGE_FM_EREPORT_TDMC_TDR_PREF_CPL_TO,	"txdma_tdr_pref_cpl_to",
136 						DDI_FM_DEVICE_NO_RESPONSE,
137 						DDI_SERVICE_DEGRADED},
138 	{HXGE_FM_EREPORT_TDMC_PKT_CPL_TO,	"txdma_pkt_cpl_to",
139 						DDI_FM_DEVICE_NO_RESPONSE,
140 						DDI_SERVICE_DEGRADED},
141 	{HXGE_FM_EREPORT_TDMC_INVALID_SOP,	"txdma_invalid_sop",
142 						DDI_FM_DEVICE_INVAL_STATE,
143 						DDI_SERVICE_DEGRADED},
144 	{HXGE_FM_EREPORT_TDMC_UNEXPECTED_SOP,	"txdma_unexpected_sop",
145 						DDI_FM_DEVICE_INVAL_STATE,
146 						DDI_SERVICE_DEGRADED},
147 	{HXGE_FM_EREPORT_TDMC_REORD_TBL_PAR,	"txdma_reord_tbl_par_err",
148 						DDI_FM_DEVICE_INTERN_UNCORR,
149 						DDI_SERVICE_DEGRADED},
150 	{HXGE_FM_EREPORT_TDMC_REORD_BUF_DED,	"txdma_reord_buf_ded_err",
151 						DDI_FM_DEVICE_INTERN_UNCORR,
152 						DDI_SERVICE_DEGRADED}
153 };
154 
155 hxge_fm_ereport_attr_t hxge_fm_ereport_peu[] = {
156 	{HXGE_FM_EREPORT_PEU_ERR,		"peu_peu_err",
157 						DDI_FM_DEVICE_INTERN_UNCORR,
158 						DDI_SERVICE_LOST},
159 	{HXGE_FM_EREPORT_PEU_VNM_PIO_ERR,	"peu_vnm_pio_err",
160 						DDI_FM_DEVICE_INTERN_UNCORR,
161 						DDI_SERVICE_LOST}
162 };
163 
164 hxge_fm_ereport_attr_t hxge_fm_ereport_sw[] = {
165 	{HXGE_FM_EREPORT_SW_INVALID_CHAN_NUM,	"invalid_chan_num",
166 						DDI_FM_DEVICE_INVAL_STATE,
167 						DDI_SERVICE_LOST},
168 	{HXGE_FM_EREPORT_SW_INVALID_PARAM,	"invalid_param",
169 						DDI_FM_DEVICE_INVAL_STATE,
170 						DDI_SERVICE_LOST}
171 };
172 
173 void
174 hxge_fm_init(p_hxge_t hxgep, ddi_device_acc_attr_t *reg_attr,
175 	ddi_device_acc_attr_t *desc_attr, ddi_dma_attr_t *dma_attr)
176 {
177 	ddi_iblock_cookie_t iblk;
178 
179 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "==> hxge_fm_init"));
180 
181 	/* fm-capable in hxge.conf can be used to set fm_capabilities. */
182 	hxgep->fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY, hxgep->dip,
183 	    DDI_PROP_DONTPASS, "fm-capable",
184 	    DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE);
185 
186 	HXGE_DEBUG_MSG((hxgep, DDI_CTL,
187 	    "FM capable = %d\n", hxgep->fm_capabilities));
188 
189 	/*
190 	 * Register capabilities with IO Fault Services. The capabilities
191 	 * set above may not be supported by the parent nexus, in that case
192 	 * some capability bits may be cleared.
193 	 */
194 	if (hxgep->fm_capabilities)
195 		ddi_fm_init(hxgep->dip, &hxgep->fm_capabilities, &iblk);
196 
197 	/*
198 	 * Initialize pci ereport capabilities if ereport capable
199 	 */
200 	if (DDI_FM_EREPORT_CAP(hxgep->fm_capabilities) ||
201 	    DDI_FM_ERRCB_CAP(hxgep->fm_capabilities)) {
202 		pci_ereport_setup(hxgep->dip);
203 	}
204 
205 	/* Register error callback if error callback capable */
206 	if (DDI_FM_ERRCB_CAP(hxgep->fm_capabilities)) {
207 		ddi_fm_handler_register(hxgep->dip,
208 		    hxge_fm_error_cb, (void *) hxgep);
209 	}
210 
211 	/*
212 	 * DDI_FLGERR_ACC indicates:
213 	 * o Driver will check its access handle(s) for faults on
214 	 *   a regular basis by calling ddi_fm_acc_err_get
215 	 * o Driver is able to cope with incorrect results of I/O
216 	 *   operations resulted from an I/O fault
217 	 */
218 	if (DDI_FM_ACC_ERR_CAP(hxgep->fm_capabilities)) {
219 		reg_attr->devacc_attr_access  = DDI_FLAGERR_ACC;
220 		desc_attr->devacc_attr_access = DDI_FLAGERR_ACC;
221 	} else {
222 		reg_attr->devacc_attr_access  = DDI_DEFAULT_ACC;
223 		desc_attr->devacc_attr_access = DDI_DEFAULT_ACC;
224 	}
225 
226 	/*
227 	 * DDI_DMA_FLAGERR indicates:
228 	 * o Driver will check its DMA handle(s) for faults on a
229 	 *   regular basis using ddi_fm_dma_err_get
230 	 * o Driver is able to cope with incorrect results of DMA
231 	 *   operations resulted from an I/O fault
232 	 */
233 	if (DDI_FM_DMA_ERR_CAP(hxgep->fm_capabilities))
234 		dma_attr->dma_attr_flags |= DDI_DMA_FLAGERR;
235 	else
236 		dma_attr->dma_attr_flags &= ~DDI_DMA_FLAGERR;
237 
238 	HXGE_DEBUG_MSG((hxgep, DDI_CTL, "<== hxge_fm_init"));
239 }
240 
241 void
242 hxge_fm_fini(p_hxge_t hxgep)
243 {
244 	/* Only unregister FMA capabilities if we registered some */
245 	if (hxgep->fm_capabilities) {
246 		/*
247 		 * Release any resources allocated by pci_ereport_setup()
248 		 */
249 		if (DDI_FM_EREPORT_CAP(hxgep->fm_capabilities) ||
250 		    DDI_FM_ERRCB_CAP(hxgep->fm_capabilities))
251 			pci_ereport_teardown(hxgep->dip);
252 
253 		/*
254 		 * Un-register error callback if error callback capable
255 		 */
256 		if (DDI_FM_ERRCB_CAP(hxgep->fm_capabilities))
257 			ddi_fm_handler_unregister(hxgep->dip);
258 
259 		/* Unregister from IO Fault Services */
260 		ddi_fm_fini(hxgep->dip);
261 	}
262 }
263 
264 
265 /*
266  * Simply call pci_ereport_post which generates ereports for errors
267  * that occur in the PCI local bus configuration status registers.
268  */
269 /*ARGSUSED*/
270 static int
271 hxge_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err,
272 	const void *impl_data)
273 {
274 	pci_ereport_post(dip, err, NULL);
275 	return (err->fme_status);
276 }
277 
278 
279 static hxge_fm_ereport_attr_t *
280 hxge_fm_get_ereport_attr(hxge_fm_ereport_id_t ereport_id)
281 {
282 	hxge_fm_ereport_attr_t	*attr;
283 	uint8_t			blk_id;
284 	uint8_t			index;
285 
286 	/* Extract the block id and the index within the block */
287 	blk_id = ((ereport_id >> EREPORT_FM_ID_SHIFT) & EREPORT_FM_ID_MASK);
288 	index = (ereport_id & EREPORT_INDEX_MASK);
289 
290 	/* Return the appropriate structure of type hxge_fm_ereport_attr_t */
291 	switch (blk_id) {
292 	case FM_SW_ID:
293 		attr = &hxge_fm_ereport_sw[index];
294 		break;
295 	case FM_VMAC_ID:
296 		attr = &hxge_fm_ereport_vmac[index];
297 		break;
298 	case FM_PFC_ID:
299 		attr = &hxge_fm_ereport_pfc[index];
300 		break;
301 	case FM_RXDMA_ID:
302 		attr = &hxge_fm_ereport_rdmc[index];
303 		break;
304 	case FM_TXDMA_ID:
305 		attr = &hxge_fm_ereport_tdmc[index];
306 		break;
307 	case FM_PEU_ID:
308 		attr = &hxge_fm_ereport_peu[index];
309 		break;
310 	default:
311 		attr = NULL;
312 	}
313 
314 	return (attr);
315 }
316 
317 static void
318 hxge_fm_ereport(p_hxge_t hxgep, uint8_t err_chan,
319 	hxge_fm_ereport_attr_t *ereport)
320 {
321 	uint64_t		ena;
322 	char			eclass[FM_MAX_CLASS];
323 	char			*err_str;
324 	p_hxge_stats_t		statsp;
325 
326 	(void) snprintf(eclass, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE,
327 	    ereport->eclass);
328 
329 	err_str = ereport->str;
330 	ena = fm_ena_generate(0, FM_ENA_FMT1);
331 	statsp = hxgep->statsp;
332 
333 	switch (ereport->index) {
334 	case HXGE_FM_EREPORT_VMAC_LINK_DOWN:
335 		ddi_fm_ereport_post(hxgep->dip, eclass, ena, DDI_NOSLEEP,
336 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
337 		    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
338 		    NULL);
339 		break;
340 	case HXGE_FM_EREPORT_PFC_TCAM_PAR_ERR:
341 		ddi_fm_ereport_post(hxgep->dip, eclass, ena, DDI_NOSLEEP,
342 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
343 		    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
344 		    ERNAME_PFC_TCAM_ERR, DATA_TYPE_UINT32,
345 		    statsp->pfc_stats.tcam_parity_err,
346 		    NULL);
347 		break;
348 	case HXGE_FM_EREPORT_PFC_VLAN_PAR_ERR:
349 		ddi_fm_ereport_post(hxgep->dip, eclass, ena, DDI_NOSLEEP,
350 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
351 		    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
352 		    ERNAME_PFC_VLAN_ERR, DATA_TYPE_UINT32,
353 		    statsp->pfc_stats.vlan_parity_err,
354 		    NULL);
355 		break;
356 	case HXGE_FM_EREPORT_PFC_PKT_DROP:
357 		ddi_fm_ereport_post(hxgep->dip, eclass, ena, DDI_NOSLEEP,
358 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
359 		    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
360 		    ERNAME_PFC_PKT_DROP, DATA_TYPE_UINT32,
361 		    statsp->pfc_stats.pkt_drop,
362 		    NULL);
363 		break;
364 	case HXGE_FM_EREPORT_RDMC_RBR_CPL_TO:
365 	case HXGE_FM_EREPORT_RDMC_PEU_RESP_ERR:
366 	case HXGE_FM_EREPORT_RDMC_RCRFULL:
367 	case HXGE_FM_EREPORT_RDMC_RBR_EMPTY:
368 	case HXGE_FM_EREPORT_RDMC_RBRFULL:
369 	case HXGE_FM_EREPORT_RDMC_RBR_PRE_EMPTY:
370 	case HXGE_FM_EREPORT_RDMC_RCR_SHA_FULL:
371 		ddi_fm_ereport_post(hxgep->dip, eclass, ena, DDI_NOSLEEP,
372 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
373 		    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
374 		    ERNAME_ERR_DCHAN, DATA_TYPE_UINT8, err_chan,
375 		    NULL);
376 		break;
377 	case HXGE_FM_EREPORT_RDMC_RBR_PRE_PAR:
378 	case HXGE_FM_EREPORT_RDMC_RCR_SHA_PAR: {
379 		uint32_t err_log;
380 		hxge_rx_ring_stats_t *rdc_statsp;
381 
382 		rdc_statsp = &statsp->rdc_stats[err_chan];
383 		if (ereport->index == HXGE_FM_EREPORT_RDMC_RBR_PRE_PAR)
384 			err_log = (uint32_t)
385 			    rdc_statsp->errlog.pre_par.value;
386 		else
387 			err_log = (uint32_t)
388 			    rdc_statsp->errlog.sha_par.value;
389 		ddi_fm_ereport_post(hxgep->dip, eclass, ena, DDI_NOSLEEP,
390 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
391 		    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
392 		    ERNAME_ERR_DCHAN, DATA_TYPE_UINT8, err_chan,
393 		    ERNAME_RDMC_PAR_ERR_LOG, DATA_TYPE_UINT8, err_log,
394 		    NULL);
395 		}
396 		break;
397 	case HXGE_FM_EREPORT_RDMC_RCR_ERR: {
398 		uint8_t err_type;
399 		err_type = statsp->rdc_stats[err_chan].errlog.compl_err_type;
400 		ddi_fm_ereport_post(hxgep->dip, eclass, ena, DDI_NOSLEEP,
401 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
402 		    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
403 		    ERNAME_ERR_DCHAN, DATA_TYPE_UINT8, err_chan,
404 		    ERNAME_RDC_ERR_TYPE, DATA_TYPE_UINT8, err_type,
405 		    NULL);
406 		}
407 		break;
408 	case HXGE_FM_EREPORT_RDMC_CTRL_FIFO_SEC:
409 	case HXGE_FM_EREPORT_RDMC_CTRL_FIFO_DED:
410 	case HXGE_FM_EREPORT_RDMC_DATA_FIFO_SEC:
411 	case HXGE_FM_EREPORT_RDMC_DATA_FIFO_DED:
412 		ddi_fm_ereport_post(hxgep->dip, eclass, ena, DDI_NOSLEEP,
413 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
414 		    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
415 		    NULL);
416 		break;
417 
418 	case HXGE_FM_EREPORT_TDMC_PEU_RESP_ERR:
419 	case HXGE_FM_EREPORT_TDMC_TX_RNG_OFLOW:
420 	case HXGE_FM_EREPORT_TDMC_PKT_SIZE_HDR_ERR:
421 	case HXGE_FM_EREPORT_TDMC_RUNT_PKT_DROP_ERR:
422 	case HXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR:
423 	case HXGE_FM_EREPORT_TDMC_TDR_PREF_CPL_TO:
424 	case HXGE_FM_EREPORT_TDMC_PKT_CPL_TO:
425 	case HXGE_FM_EREPORT_TDMC_INVALID_SOP:
426 	case HXGE_FM_EREPORT_TDMC_UNEXPECTED_SOP:
427 		ddi_fm_ereport_post(hxgep->dip, eclass, ena, DDI_NOSLEEP,
428 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
429 		    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
430 		    ERNAME_ERR_DCHAN, DATA_TYPE_UINT8, err_chan,
431 		    NULL);
432 		break;
433 
434 	case HXGE_FM_EREPORT_TDMC_PREF_PAR_ERR:
435 		ddi_fm_ereport_post(hxgep->dip, eclass, ena, DDI_NOSLEEP,
436 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
437 		    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
438 		    ERNAME_ERR_DCHAN, DATA_TYPE_UINT8, err_chan,
439 		    ERNAME_TDC_PREF_PAR_LOG, DATA_TYPE_UINT32,
440 		    statsp->tdc_stats[err_chan].errlog.value, NULL);
441 		break;
442 	case HXGE_FM_EREPORT_TDMC_REORD_TBL_PAR:
443 	case HXGE_FM_EREPORT_TDMC_REORD_BUF_DED:
444 		ddi_fm_ereport_post(hxgep->dip, eclass, ena, DDI_NOSLEEP,
445 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
446 		    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
447 		    NULL);
448 		break;
449 
450 	case HXGE_FM_EREPORT_PEU_ERR:
451 	case HXGE_FM_EREPORT_PEU_VNM_PIO_ERR:
452 		ddi_fm_ereport_post(hxgep->dip, eclass, ena, DDI_NOSLEEP,
453 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
454 		    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
455 		    NULL);
456 		break;
457 
458 	case HXGE_FM_EREPORT_SW_INVALID_CHAN_NUM:
459 	case HXGE_FM_EREPORT_SW_INVALID_PARAM:
460 		ddi_fm_ereport_post(hxgep->dip, eclass, ena, DDI_NOSLEEP,
461 		    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
462 		    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
463 		    NULL);
464 		break;
465 	}
466 }
467 
468 void
469 hxge_fm_report_error(p_hxge_t hxgep, uint8_t err_chan,
470 	hxge_fm_ereport_id_t fm_ereport_id)
471 {
472 	hxge_fm_ereport_attr_t	*fm_ereport_attr;
473 
474 	fm_ereport_attr = hxge_fm_get_ereport_attr(fm_ereport_id);
475 
476 	if (fm_ereport_attr != NULL &&
477 	    (DDI_FM_EREPORT_CAP(hxgep->fm_capabilities))) {
478 		hxge_fm_ereport(hxgep, err_chan, fm_ereport_attr);
479 		ddi_fm_service_impact(hxgep->dip, fm_ereport_attr->impact);
480 	}
481 }
482 
483 int
484 fm_check_acc_handle(ddi_acc_handle_t handle)
485 {
486 	ddi_fm_error_t err;
487 
488 	ddi_fm_acc_err_get(handle, &err, DDI_FME_VERSION);
489 	ddi_fm_acc_err_clear(handle, DDI_FME_VERSION);
490 
491 	return (err.fme_status);
492 }
493 
494 int
495 fm_check_dma_handle(ddi_dma_handle_t handle)
496 {
497 	ddi_fm_error_t err;
498 
499 	ddi_fm_dma_err_get(handle, &err, DDI_FME_VERSION);
500 	return (err.fme_status);
501 }
502