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