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
33static hxge_fm_ereport_attr_t
34*hxge_fm_get_ereport_attr(hxge_fm_ereport_id_t ereport_id);
35
36static int
37hxge_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data);
38
39hxge_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
45hxge_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
60hxge_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
116hxge_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
155hxge_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
164hxge_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
173void
174hxge_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
241void
242hxge_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*/
270static int
271hxge_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
279static hxge_fm_ereport_attr_t *
280hxge_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
317static void
318hxge_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
468void
469hxge_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
483int
484fm_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
494int
495fm_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