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