/*
 * CDDL HEADER START
 *
 * The contents of this file are subject to the terms of the
 * Common Development and Distribution License (the "License").
 * You may not use this file except in compliance with the License.
 *
 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
 * or http://www.opensolaris.org/os/licensing.
 * See the License for the specific language governing permissions
 * and limitations under the License.
 *
 * When distributing Covered Code, include this CDDL HEADER in each
 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
 * If applicable, add the following below this CDDL HEADER, with the
 * fields enclosed by brackets "[]" replaced with your own identifying
 * information: Portions Copyright [yyyy] [name of copyright owner]
 *
 * CDDL HEADER END
 */
/*
 * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
 * Use is subject to license terms.
 */

#pragma ident	"%Z%%M%	%I%	%E% SMI"

#include <sys/nxge/nxge_impl.h>
#include <sys/nxge/nxge_hio.h>
#include <sys/ddifm.h>
#include <sys/fm/protocol.h>
#include <sys/fm/util.h>
#include <sys/fm/io/ddi.h>

static nxge_fm_ereport_attr_t
*nxge_fm_get_ereport_attr(nxge_fm_ereport_id_t);

static int
nxge_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err, const void *impl_data);

nxge_fm_ereport_attr_t	nxge_fm_ereport_pcs[] = {
	{NXGE_FM_EREPORT_XPCS_LINK_DOWN,	"10g_link_down",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_XPCS_TX_LINK_FAULT,	"10g_tx_link_fault",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_XPCS_RX_LINK_FAULT,	"10g_rx_link_fault",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_PCS_LINK_DOWN,		"1g_link_down",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_PCS_REMOTE_FAULT,	"1g_remote_fault",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED},
};

nxge_fm_ereport_attr_t	nxge_fm_ereport_mif[] = {
	{NXGE_FM_EREPORT_MIF_ACCESS_FAIL,	"transceiver_access_fail"}
};

nxge_fm_ereport_attr_t nxge_fm_ereport_fflp[] = {
	{NXGE_FM_EREPORT_FFLP_TCAM_ERR,		"classifier_tcam_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_FFLP_VLAN_PAR_ERR,	"classifier_vlan_par_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_FFLP_HASHT_DATA_ERR,	"classifier_hasht_data_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_FFLP_HASHT_LOOKUP_ERR,	"classifier_hasht_lookup_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_FFLP_ACCESS_FAIL,	"classifier_access_fail",
						DDI_FM_DEVICE_NO_RESPONSE,
						DDI_SERVICE_DEGRADED}
};

nxge_fm_ereport_attr_t nxge_fm_ereport_ipp[] = {
	{NXGE_FM_EREPORT_IPP_EOP_MISS,		"rx_eop_miss",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_IPP_SOP_MISS,		"rx_sop_miss",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_IPP_DFIFO_UE,		"rx_dfifo_ucorr_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_IPP_DFIFO_CE,		"rx_dfifo_corr_err",
						DDI_FM_DEVICE_INTERN_CORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_IPP_PFIFO_PERR,	"rx_dfifo_parity_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_IPP_ECC_ERR_MAX,	"rx_ecc_err_max",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_IPP_PFIFO_OVER,	"rx_pfifo_overflow",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_IPP_PFIFO_UND,		"rx_pfifo_underrun",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_IPP_BAD_CS_MX,		"rx_bad_cksum_max",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_IPP_PKT_DIS_MX,	"rx_pkt_discard_max",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_IPP_RESET_FAIL,	"rx_reset_fail",
						DDI_FM_DEVICE_NO_RESPONSE,
						DDI_SERVICE_LOST}
};

nxge_fm_ereport_attr_t nxge_fm_ereport_rdmc[] = {
	{NXGE_FM_EREPORT_RDMC_DCF_ERR,		"rxdma_dcf_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_RDMC_RCR_ACK_ERR,	"rxdma_rcr_ack_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_RDMC_DC_FIFO_ERR,	"rxdma_dc_fifo_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_RDMC_RCR_SHA_PAR,	"rxdma_rcr_sha_par_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_RDMC_RBR_PRE_PAR,	"rxdma_rbr_pre_par_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_RDMC_RBR_TMOUT,	"rxdma_rbr_tmout",
						DDI_FM_DEVICE_NO_RESPONSE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_RDMC_RSP_CNT_ERR,	"rxdma_rsp_cnt_err",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_RDMC_BYTE_EN_BUS,	"rxdma_byte_en_bus",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_RDMC_RSP_DAT_ERR,	"rxdma_rsp_dat_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_RDMC_ID_MISMATCH,	"rxdma_id_mismatch",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_RDMC_ZCP_EOP_ERR,	"rxdma_zcp_eop_err",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_RDMC_IPP_EOP_ERR,	"rxdma_ipp_eop_err",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_RDMC_RCR_ERR,		"rxdma_completion_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_RDMC_CONFIG_ERR,	"rxdma_config_err",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_RDMC_RCRINCON,		"rxdma_rcrincon",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_RDMC_RCRFULL,		"rxdma_rcrfull",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_RDMC_RBRFULL,		"rxdma_rbrfull",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_RDMC_RBRLOGPAGE,	"rxdma_rbrlogpage",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_RDMC_CFIGLOGPAGE,	"rxdma_cfiglogpage",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED}
};

nxge_fm_ereport_attr_t nxge_fm_ereport_zcp[] = {
	{NXGE_FM_EREPORT_ZCP_RRFIFO_UNDERRUN,	"rxzcopy_rrfifo_underrun",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_ZCP_RSPFIFO_UNCORR_ERR,
						"rxzcopy_rspfifo_uncorr_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_ZCP_STAT_TBL_PERR,	"rxzcopy_stat_tbl_perr",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_ZCP_DYN_TBL_PERR,	"rxzcopy_dyn_tbl_perr",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_ZCP_BUF_TBL_PERR,	"rxzcopy_buf_tbl_perr",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_ZCP_CFIFO_ECC,		"rxzcopy_cfifo_ecc",
						DDI_FM_DEVICE_INTERN_CORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_ZCP_RRFIFO_OVERRUN,	"rxzcopy_rrfifo_overrun",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_ZCP_BUFFER_OVERFLOW,	"rxzcopy_buffer_overflow",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_ZCP_TT_PROGRAM_ERR,	"rxzcopy_tt_program_err",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_ZCP_RSP_TT_INDEX_ERR,	"rxzcopy_rsp_tt_index_err",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_ZCP_SLV_TT_INDEX_ERR,	"rxzcopy_slv_tt_index_err",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_ZCP_TT_INDEX_ERR,	"rxzcopy_tt_index_err",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_ZCP_ACCESS_FAIL,	"rxzcopy_access_fail",
						DDI_FM_DEVICE_NO_RESPONSE,
						DDI_SERVICE_LOST},
};

nxge_fm_ereport_attr_t nxge_fm_ereport_rxmac[] = {
	{NXGE_FM_EREPORT_RXMAC_UNDERFLOW,	"rxmac_underflow",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_RXMAC_CRC_ERRCNT_EXP,	"rxmac_crc_errcnt_exp",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_RXMAC_LENGTH_ERRCNT_EXP,
						"rxmac_length_errcnt_exp",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_RXMAC_VIOL_ERRCNT_EXP,	"rxmac_viol_errcnt_exp",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_RXMAC_RXFRAG_CNT_EXP,	"rxmac_rxfrag_cnt_exp",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_RXMAC_ALIGN_ECNT_EXP,	"rxmac_align_ecnt_exp",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_RXMAC_LINKFAULT_CNT_EXP,
						"rxmac_linkfault_cnt_exp",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_RXMAC_RESET_FAIL,	"rxmac_reset_fail",
						DDI_FM_DEVICE_NO_RESPONSE,
						DDI_SERVICE_UNAFFECTED},
};

nxge_fm_ereport_attr_t nxge_fm_ereport_tdmc[] = {
	{NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR,	"txdma_pref_buf_par_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_TDMC_MBOX_ERR,		"txdma_mbox_err",
						DDI_FM_DEVICE_NO_RESPONSE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_TDMC_NACK_PREF,	"txdma_nack_pref",
						DDI_FM_DEVICE_NO_RESPONSE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_TDMC_NACK_PKT_RD,	"txdma_nack_pkt_rd",
						DDI_FM_DEVICE_NO_RESPONSE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR,	"txdma_pkt_size_err",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW,	"txdma_tx_ring_oflow",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_TDMC_CONF_PART_ERR,	"txdma_conf_part_err",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR,	"txdma_pkt_prt_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_DEGRADED},
	{NXGE_FM_EREPORT_TDMC_RESET_FAIL,	"txdma_reset_fail",
						DDI_FM_DEVICE_NO_RESPONSE,
						DDI_SERVICE_LOST},
};

nxge_fm_ereport_attr_t nxge_fm_ereport_txc[] = {
	{NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR,	"tx_ro_correct_err",
						DDI_FM_DEVICE_INTERN_CORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_TXC_RO_UNCORRECT_ERR,	"tx_ro_uncorrect_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR,	"tx_sf_correct_err",
						DDI_FM_DEVICE_INTERN_CORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_TXC_SF_UNCORRECT_ERR,	"tx_sf_uncorrect_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_TXC_ASSY_DEAD,		"tx_assembly_uncorrect_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_TXC_REORDER_ERR,	"tx_reorder_err",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
};

nxge_fm_ereport_attr_t nxge_fm_ereport_txmac[] = {
	{NXGE_FM_EREPORT_TXMAC_UNDERFLOW,	"txmac_underflow",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_TXMAC_OVERFLOW,	"txmac_overflow",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_TXMAC_TXFIFO_XFR_ERR,	"txmac_txfifo_xfr_err",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_TXMAC_MAX_PKT_ERR,	"txmac_max_pkt_err",
						DDI_FM_DEVICE_INTERN_UNCORR,
						DDI_SERVICE_UNAFFECTED},
	{NXGE_FM_EREPORT_TXMAC_RESET_FAIL,	"txmac_reset_fail",
						DDI_FM_DEVICE_NO_RESPONSE,
						DDI_SERVICE_UNAFFECTED},
};

nxge_fm_ereport_attr_t nxge_fm_ereport_espc[] = {
	{NXGE_FM_EREPORT_ESPC_ACCESS_FAIL,	"eprom_access_fail",
						DDI_FM_DEVICE_NO_RESPONSE,
						DDI_SERVICE_LOST},
};

nxge_fm_ereport_attr_t nxge_fm_ereport_xaui[] = {
	{NXGE_FM_EREPORT_XAUI_ERR,		"xaui_bad_or_missing",
						NXGE_FM_DEVICE_XAUI_ERR,
						DDI_SERVICE_LOST},
};

nxge_fm_ereport_attr_t nxge_fm_ereport_xfp[] = {
	{NXGE_FM_EREPORT_XFP_ERR,		"xfp_bad_or_missing",
						NXGE_FM_DEVICE_XFP_ERR,
						DDI_SERVICE_LOST},
};

nxge_fm_ereport_attr_t nxge_fm_ereport_sw[] = {
	{NXGE_FM_EREPORT_SW_INVALID_PORT_NUM,	"invalid_port_num",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_SW_INVALID_CHAN_NUM,	"invalid_chan_num",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
	{NXGE_FM_EREPORT_SW_INVALID_PARAM,	"invalid_param",
						DDI_FM_DEVICE_INVAL_STATE,
						DDI_SERVICE_LOST},
};

void
nxge_fm_init(p_nxge_t nxgep, ddi_device_acc_attr_t *reg_attr,
	ddi_device_acc_attr_t *desc_attr, ddi_dma_attr_t *dma_attr)
{
	ddi_iblock_cookie_t iblk;

	/*
	 * fm-capable in nxge.conf can be used to set fm_capabilities.
	 * If fm-capable is not defined, then the last argument passed to
	 * ddi_prop_get_int will be returned as the capabilities.
	 */
	nxgep->fm_capabilities = ddi_prop_get_int(DDI_DEV_T_ANY, nxgep->dip,
	    DDI_PROP_DONTPASS | DDI_PROP_NOTPROM, "fm-capable",
	    DDI_FM_EREPORT_CAPABLE | DDI_FM_ERRCB_CAPABLE);

	NXGE_ERROR_MSG((nxgep, DDI_CTL,
	    "FM capable = %d\n", nxgep->fm_capabilities));

	if (isLDOMguest(nxgep)) {
		nxgep->fm_capabilities = DDI_FM_NOT_CAPABLE;
		return;
	}

	/*
	 * Register capabilities with IO Fault Services. The capabilities
	 * set above may not be supported by the parent nexus, in that case
	 * some capability bits may be cleared.
	 */
	if (nxgep->fm_capabilities)
		ddi_fm_init(nxgep->dip, &nxgep->fm_capabilities, &iblk);

	/*
	 * Initialize pci ereport capabilities if ereport capable
	 */
	if (DDI_FM_EREPORT_CAP(nxgep->fm_capabilities) ||
	    DDI_FM_ERRCB_CAP(nxgep->fm_capabilities)) {
		pci_ereport_setup(nxgep->dip);
	}

	/* Register error callback if error callback capable */
	if (DDI_FM_ERRCB_CAP(nxgep->fm_capabilities)) {
		ddi_fm_handler_register(nxgep->dip,
		    nxge_fm_error_cb, (void*) nxgep);
	}

	/*
	 * DDI_FLGERR_ACC indicates:
	 * o Driver will check its access handle(s) for faults on
	 *   a regular basis by calling ddi_fm_acc_err_get
	 * o Driver is able to cope with incorrect results of I/O
	 *   operations resulted from an I/O fault
	 */
	if (DDI_FM_ACC_ERR_CAP(nxgep->fm_capabilities)) {
		reg_attr->devacc_attr_access  = DDI_FLAGERR_ACC;
		desc_attr->devacc_attr_access = DDI_FLAGERR_ACC;
	} else {
		reg_attr->devacc_attr_access  = DDI_DEFAULT_ACC;
		desc_attr->devacc_attr_access = DDI_DEFAULT_ACC;
	}

	/*
	 * DDI_DMA_FLAGERR indicates:
	 * o Driver will check its DMA handle(s) for faults on a
	 *   regular basis using ddi_fm_dma_err_get
	 * o Driver is able to cope with incorrect results of DMA
	 *   operations resulted from an I/O fault
	 */
	if (DDI_FM_DMA_ERR_CAP(nxgep->fm_capabilities))
		dma_attr->dma_attr_flags |= DDI_DMA_FLAGERR;
	else
		dma_attr->dma_attr_flags &= ~DDI_DMA_FLAGERR;

}

void
nxge_fm_fini(p_nxge_t nxgep)
{
	/* Only unregister FMA capabilities if we registered some */
	if (nxgep->fm_capabilities) {

		/*
		 * Release any resources allocated by pci_ereport_setup()
		 */
		if (DDI_FM_EREPORT_CAP(nxgep->fm_capabilities) ||
		    DDI_FM_ERRCB_CAP(nxgep->fm_capabilities))
			pci_ereport_teardown(nxgep->dip);

		/*
		 * Un-register error callback if error callback capable
		 */
		if (DDI_FM_ERRCB_CAP(nxgep->fm_capabilities))
			ddi_fm_handler_unregister(nxgep->dip);

		/* Unregister from IO Fault Services */
		ddi_fm_fini(nxgep->dip);
	}
}

/*ARGSUSED*/
/*
 * Simply call pci_ereport_post which generates ereports for errors
 * that occur in the PCI local bus configuration status registers.
 */
static int
nxge_fm_error_cb(dev_info_t *dip, ddi_fm_error_t *err,
	const void *impl_data)
{
	pci_ereport_post(dip, err, NULL);
	return (err->fme_status);
}


static nxge_fm_ereport_attr_t *
nxge_fm_get_ereport_attr(nxge_fm_ereport_id_t ereport_id)
{
	nxge_fm_ereport_attr_t *attr;
	uint8_t	blk_id = (ereport_id >> EREPORT_FM_ID_SHIFT) &
	    EREPORT_FM_ID_MASK;
	uint8_t index = ereport_id & EREPORT_INDEX_MASK;

	switch (blk_id) {
	case FM_SW_ID:
		attr = &nxge_fm_ereport_sw[index];
		break;
	case FM_PCS_ID:
		attr = &nxge_fm_ereport_pcs[index];
		break;
	case FM_TXMAC_ID:
		attr = &nxge_fm_ereport_txmac[index];
		break;
	case FM_RXMAC_ID:
		attr = &nxge_fm_ereport_rxmac[index];
		break;
	case FM_MIF_ID:
		attr = &nxge_fm_ereport_mif[index];
		break;
	case FM_FFLP_ID:
		attr = &nxge_fm_ereport_fflp[index];
		break;
	case FM_ZCP_ID:
		attr = &nxge_fm_ereport_zcp[index];
		break;
	case FM_RXDMA_ID:
		attr = &nxge_fm_ereport_rdmc[index];
		break;
	case FM_TXDMA_ID:
		attr = &nxge_fm_ereport_tdmc[index];
		break;
	case FM_IPP_ID:
		attr = &nxge_fm_ereport_ipp[index];
		break;
	case FM_TXC_ID:
		attr = &nxge_fm_ereport_txc[index];
		break;
	case FM_ESPC_ID:
		attr = &nxge_fm_ereport_espc[index];
		break;
	case FM_XAUI_ID:
		attr = &nxge_fm_ereport_xaui[index];
		break;
	case FM_XFP_ID:
		attr = &nxge_fm_ereport_xfp[index];
		break;
	default:
		attr = NULL;
	}

	return (attr);
}

static void
nxge_fm_ereport(p_nxge_t nxgep, uint8_t err_portn, uint8_t err_chan,
					nxge_fm_ereport_attr_t *ereport)
{
	uint64_t		ena;
	char			eclass[FM_MAX_CLASS];
	char			*err_str;
	p_nxge_stats_t		statsp;

	(void) snprintf(eclass, FM_MAX_CLASS, "%s.%s", DDI_FM_DEVICE,
	    ereport->eclass);
	err_str = ereport->str;
	ena = fm_ena_generate(0, FM_ENA_FMT1);
	statsp = nxgep->statsp;

	switch (ereport->index) {
		case NXGE_FM_EREPORT_XPCS_LINK_DOWN:
		case NXGE_FM_EREPORT_XPCS_TX_LINK_FAULT:
		case NXGE_FM_EREPORT_XPCS_RX_LINK_FAULT:
		case NXGE_FM_EREPORT_PCS_LINK_DOWN:
		case NXGE_FM_EREPORT_PCS_REMOTE_FAULT:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    NULL);
			break;
		case NXGE_FM_EREPORT_IPP_EOP_MISS:
		case NXGE_FM_EREPORT_IPP_SOP_MISS:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    ERNAME_DFIFO_RD_PTR, DATA_TYPE_UINT16,
			    statsp->ipp_stats.errlog.dfifo_rd_ptr,
			    ERNAME_IPP_STATE_MACH, DATA_TYPE_UINT32,
			    statsp->ipp_stats.errlog.state_mach,
			    NULL);
			break;
		case NXGE_FM_EREPORT_IPP_DFIFO_UE:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    ERNAME_DFIFO_ENTRY, DATA_TYPE_UINT16,
			    nxgep->ipp.status.bits.w0.dfifo_ecc_err_idx,
			    ERNAME_DFIFO_SYNDROME, DATA_TYPE_UINT16,
			    statsp->ipp_stats.errlog.ecc_syndrome,
			    NULL);
			break;
		case NXGE_FM_EREPORT_IPP_PFIFO_PERR:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    ERNAME_PFIFO_ENTRY, DATA_TYPE_UINT8,
			    nxgep->ipp.status.bits.w0.pre_fifo_perr_idx,
			    NULL);
			break;
		case NXGE_FM_EREPORT_IPP_DFIFO_CE:
		case NXGE_FM_EREPORT_IPP_ECC_ERR_MAX:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    NULL);
			break;
		case NXGE_FM_EREPORT_IPP_PFIFO_OVER:
		case NXGE_FM_EREPORT_IPP_PFIFO_UND:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    ERNAME_IPP_STATE_MACH, DATA_TYPE_UINT32,
			    statsp->ipp_stats.errlog.state_mach,
			    NULL);
			break;
		case NXGE_FM_EREPORT_IPP_BAD_CS_MX:
		case NXGE_FM_EREPORT_IPP_PKT_DIS_MX:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    NULL);
			break;
		case NXGE_FM_EREPORT_FFLP_TCAM_ERR:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_TCAM_ERR_LOG, DATA_TYPE_UINT32,
			    statsp->fflp_stats.errlog.tcam,
			    NULL);
			break;
		case NXGE_FM_EREPORT_FFLP_VLAN_PAR_ERR:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_VLANTAB_ERR_LOG, DATA_TYPE_UINT32,
			    statsp->fflp_stats.errlog.vlan,
			    NULL);
			break;
		case NXGE_FM_EREPORT_FFLP_HASHT_DATA_ERR:
		{
			int rdc_grp;
			hash_tbl_data_log_t hash_log;

			for (rdc_grp = 0; rdc_grp < MAX_PARTITION; rdc_grp++) {
				hash_log.value = nxgep->classifier.fflp_stats->
				    errlog.hash_pio[rdc_grp];
				if (hash_log.bits.ldw.pio_err) {
					ddi_fm_ereport_post(nxgep->dip, eclass,
					    ena, DDI_NOSLEEP,
					    FM_VERSION, DATA_TYPE_UINT8,
					    FM_EREPORT_VERS0,
					    ERNAME_DETAILED_ERR_TYPE,
					    DATA_TYPE_STRING, err_str,
					    ERNAME_HASHTAB_ERR_LOG,
					    DATA_TYPE_UINT32,
					    nxgep->classifier.fflp_stats->
					    errlog.hash_pio[rdc_grp], NULL);
				}
			}
		}
			break;
		case NXGE_FM_EREPORT_FFLP_HASHT_LOOKUP_ERR:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_HASHT_LOOKUP_ERR_LOG0, DATA_TYPE_UINT32,
			    statsp->fflp_stats.errlog. hash_lookup1,
			    ERNAME_HASHT_LOOKUP_ERR_LOG1, DATA_TYPE_UINT32,
			    statsp->fflp_stats.errlog.hash_lookup2,
			    NULL);
			break;
		case NXGE_FM_EREPORT_RDMC_DCF_ERR:
		case NXGE_FM_EREPORT_RDMC_RBR_TMOUT:
		case NXGE_FM_EREPORT_RDMC_RSP_CNT_ERR:
		case NXGE_FM_EREPORT_RDMC_BYTE_EN_BUS:
		case NXGE_FM_EREPORT_RDMC_RSP_DAT_ERR:
		case NXGE_FM_EREPORT_RDMC_RCR_ACK_ERR:
		case NXGE_FM_EREPORT_RDMC_DC_FIFO_ERR:
		case NXGE_FM_EREPORT_RDMC_CONFIG_ERR:
		case NXGE_FM_EREPORT_RDMC_RCRINCON:
		case NXGE_FM_EREPORT_RDMC_RCRFULL:
		case NXGE_FM_EREPORT_RDMC_RBRFULL:
		case NXGE_FM_EREPORT_RDMC_RBRLOGPAGE:
		case NXGE_FM_EREPORT_RDMC_CFIGLOGPAGE:
		case NXGE_FM_EREPORT_RDMC_ID_MISMATCH:
		case NXGE_FM_EREPORT_RDMC_ZCP_EOP_ERR:
		case NXGE_FM_EREPORT_RDMC_IPP_EOP_ERR:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    ERNAME_ERR_DCHAN, DATA_TYPE_UINT8, err_chan,
			    NULL);
			break;
		case NXGE_FM_EREPORT_RDMC_RBR_PRE_PAR:
		case NXGE_FM_EREPORT_RDMC_RCR_SHA_PAR:
			{
			uint32_t err_log;
			if (ereport->index == NXGE_FM_EREPORT_RDMC_RBR_PRE_PAR)
				err_log = (uint32_t)statsp->
				    rdc_stats[err_chan].errlog.pre_par.value;
			else
				err_log = (uint32_t)statsp->
				    rdc_stats[err_chan].errlog.sha_par.value;
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    ERNAME_ERR_DCHAN, DATA_TYPE_UINT8, err_chan,
			    ERNAME_RDMC_PAR_ERR_LOG, DATA_TYPE_UINT8, err_log,
			    NULL);
			}
			break;
		case NXGE_FM_EREPORT_RDMC_RCR_ERR:
			{
			uint8_t err_type;
			err_type = statsp->
			    rdc_stats[err_chan].errlog.compl_err_type;
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    ERNAME_ERR_DCHAN, DATA_TYPE_UINT8, err_chan,
			    ERNAME_RDC_ERR_TYPE, DATA_TYPE_UINT8, err_type,
			    NULL);
			}
			break;

		case NXGE_FM_EREPORT_ZCP_RRFIFO_UNDERRUN:
		case NXGE_FM_EREPORT_ZCP_RRFIFO_OVERRUN:
		case NXGE_FM_EREPORT_ZCP_BUFFER_OVERFLOW:
			{
			uint32_t sm;
			sm = statsp->
			    zcp_stats.errlog.state_mach.bits.ldw.state;
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    sm, DATA_TYPE_UINT32,
			    NULL);
			break;
			}
		case NXGE_FM_EREPORT_ZCP_CFIFO_ECC:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    NULL);
			break;
		case NXGE_FM_EREPORT_ZCP_RSPFIFO_UNCORR_ERR:
		case NXGE_FM_EREPORT_ZCP_STAT_TBL_PERR:
		case NXGE_FM_EREPORT_ZCP_DYN_TBL_PERR:
		case NXGE_FM_EREPORT_ZCP_BUF_TBL_PERR:
		case NXGE_FM_EREPORT_ZCP_TT_PROGRAM_ERR:
		case NXGE_FM_EREPORT_ZCP_RSP_TT_INDEX_ERR:
		case NXGE_FM_EREPORT_ZCP_SLV_TT_INDEX_ERR:
		case NXGE_FM_EREPORT_ZCP_TT_INDEX_ERR:
		case NXGE_FM_EREPORT_RXMAC_UNDERFLOW:
		case NXGE_FM_EREPORT_RXMAC_CRC_ERRCNT_EXP:
		case NXGE_FM_EREPORT_RXMAC_LENGTH_ERRCNT_EXP:
		case NXGE_FM_EREPORT_RXMAC_VIOL_ERRCNT_EXP:
		case NXGE_FM_EREPORT_RXMAC_RXFRAG_CNT_EXP:
		case NXGE_FM_EREPORT_RXMAC_LINKFAULT_CNT_EXP:
		case NXGE_FM_EREPORT_RXMAC_ALIGN_ECNT_EXP:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    NULL);
			break;
		case NXGE_FM_EREPORT_TDMC_MBOX_ERR:
		case NXGE_FM_EREPORT_TDMC_TX_RING_OFLOW:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    ERNAME_ERR_DCHAN, DATA_TYPE_UINT8, err_chan,
			    NULL);
			break;
		case NXGE_FM_EREPORT_TDMC_PREF_BUF_PAR_ERR:
		case NXGE_FM_EREPORT_TDMC_NACK_PREF:
		case NXGE_FM_EREPORT_TDMC_NACK_PKT_RD:
		case NXGE_FM_EREPORT_TDMC_PKT_SIZE_ERR:
		case NXGE_FM_EREPORT_TDMC_CONF_PART_ERR:
		case NXGE_FM_EREPORT_TDMC_PKT_PRT_ERR:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    ERNAME_ERR_DCHAN, DATA_TYPE_UINT8, err_chan,
			    ERNAME_TDMC_ERR_LOG1, DATA_TYPE_UINT32,
			    statsp->tdc_stats[err_chan].errlog.logl.value,
			    ERNAME_TDMC_ERR_LOG1, DATA_TYPE_UINT32,
			    statsp->tdc_stats[err_chan].errlog.logh.value,
			    DATA_TYPE_UINT32,
			    NULL);
			break;
		case NXGE_FM_EREPORT_TXC_RO_CORRECT_ERR:
		case NXGE_FM_EREPORT_TXC_RO_UNCORRECT_ERR:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    ERNAME_TXC_ROECC_ADDR, DATA_TYPE_UINT16,
			    statsp->txc_stats.errlog.ro_st.roecc.
			    bits.ldw.ecc_address,
			    ERNAME_TXC_ROECC_DATA0, DATA_TYPE_UINT32,
			    statsp->txc_stats.errlog.ro_st.d0.
			    bits.ldw.ro_ecc_data0,
			    ERNAME_TXC_ROECC_DATA1, DATA_TYPE_UINT32,
			    statsp->txc_stats.errlog.ro_st.d1.
			    bits.ldw.ro_ecc_data1,
			    ERNAME_TXC_ROECC_DATA2, DATA_TYPE_UINT32,
			    statsp->txc_stats.errlog.ro_st.d2.
			    bits.ldw.ro_ecc_data2,
			    ERNAME_TXC_ROECC_DATA3, DATA_TYPE_UINT32,
			    statsp->txc_stats.errlog.ro_st.d3.
			    bits.ldw.ro_ecc_data3,
			    ERNAME_TXC_ROECC_DATA4, DATA_TYPE_UINT32,
			    statsp->txc_stats.errlog.ro_st.d4.
			    bits.ldw.ro_ecc_data4,
			    NULL);
			break;
		case NXGE_FM_EREPORT_TXC_REORDER_ERR:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    ERNAME_TXC_RO_STATE0, DATA_TYPE_UINT32,
			    (uint32_t)statsp->txc_stats.errlog.ro_st.st0.value,
			    ERNAME_TXC_RO_STATE1, DATA_TYPE_UINT32,
			    (uint32_t)statsp->txc_stats.errlog.ro_st.st1.value,
			    ERNAME_TXC_RO_STATE2, DATA_TYPE_UINT32,
			    (uint32_t)statsp->txc_stats.errlog.ro_st.st2.value,
			    ERNAME_TXC_RO_STATE3, DATA_TYPE_UINT32,
			    (uint32_t)statsp->txc_stats.errlog.ro_st.st3.value,
			    ERNAME_TXC_RO_STATE_CTL, DATA_TYPE_UINT32,
			    (uint32_t)statsp->txc_stats.errlog.ro_st.ctl.value,
			    ERNAME_TXC_RO_TIDS, DATA_TYPE_UINT32,
			    (uint32_t)statsp->txc_stats.errlog.ro_st.tids.value,
			    NULL);
			break;
		case NXGE_FM_EREPORT_TXC_SF_CORRECT_ERR:
		case NXGE_FM_EREPORT_TXC_SF_UNCORRECT_ERR:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    ERNAME_TXC_SFECC_ADDR, DATA_TYPE_UINT32,
			    statsp->txc_stats.errlog.sf_st.sfecc.
			    bits.ldw.ecc_address,
			    ERNAME_TXC_SFECC_DATA0, DATA_TYPE_UINT32,
			    statsp->txc_stats.errlog.sf_st.d0.
			    bits.ldw.sf_ecc_data0,
			    ERNAME_TXC_SFECC_DATA0, DATA_TYPE_UINT32,
			    statsp->txc_stats.errlog.sf_st.d1.
			    bits.ldw.sf_ecc_data1,
			    ERNAME_TXC_SFECC_DATA0, DATA_TYPE_UINT32,
			    statsp->txc_stats.errlog.sf_st.d2.
			    bits.ldw.sf_ecc_data2,
			    ERNAME_TXC_SFECC_DATA0, DATA_TYPE_UINT32,
			    statsp->txc_stats.errlog.sf_st.d3.
			    bits.ldw.sf_ecc_data3,
			    ERNAME_TXC_SFECC_DATA0, DATA_TYPE_UINT32,
			    statsp->txc_stats.errlog.sf_st.d4.
			    bits.ldw.sf_ecc_data4,
			    NULL);
			break;
		case NXGE_FM_EREPORT_TXMAC_UNDERFLOW:
		case NXGE_FM_EREPORT_TXMAC_OVERFLOW:
		case NXGE_FM_EREPORT_TXMAC_TXFIFO_XFR_ERR:
		case NXGE_FM_EREPORT_TXMAC_MAX_PKT_ERR:
		case NXGE_FM_EREPORT_XAUI_ERR:
		case NXGE_FM_EREPORT_XFP_ERR:
		case NXGE_FM_EREPORT_SW_INVALID_PORT_NUM:
		case NXGE_FM_EREPORT_SW_INVALID_CHAN_NUM:
		case NXGE_FM_EREPORT_SW_INVALID_PARAM:
			ddi_fm_ereport_post(nxgep->dip, eclass, ena,
			    DDI_NOSLEEP,
			    FM_VERSION, DATA_TYPE_UINT8, FM_EREPORT_VERS0,
			    ERNAME_DETAILED_ERR_TYPE, DATA_TYPE_STRING, err_str,
			    ERNAME_ERR_PORTN, DATA_TYPE_UINT8, err_portn,
			    NULL);
			break;
	}
}

void
nxge_fm_report_error(p_nxge_t nxgep, uint8_t err_portn, uint8_t err_chan,
					nxge_fm_ereport_id_t fm_ereport_id)
{
	nxge_fm_ereport_attr_t		*fm_ereport_attr;

	fm_ereport_attr = nxge_fm_get_ereport_attr(fm_ereport_id);
	if (fm_ereport_attr != NULL &&
	    (DDI_FM_EREPORT_CAP(nxgep->fm_capabilities))) {
		nxge_fm_ereport(nxgep, err_portn, err_chan, fm_ereport_attr);
		ddi_fm_service_impact(nxgep->dip, fm_ereport_attr->impact);
	}
}

int
fm_check_acc_handle(ddi_acc_handle_t handle)
{
	ddi_fm_error_t err;

	ddi_fm_acc_err_get(handle, &err, DDI_FME_VERSION);
#ifndef	NXGE_FM_S10
	ddi_fm_acc_err_clear(handle, DDI_FME_VERSION);
#endif
	return (err.fme_status);
}

int
fm_check_dma_handle(ddi_dma_handle_t handle)
{
	ddi_fm_error_t err;

	ddi_fm_dma_err_get(handle, &err, DDI_FME_VERSION);
	return (err.fme_status);
}