xref: /onnv-gate/usr/src/uts/common/io/nxge/nxge_ipp.c (revision 5523:04f3e2f192d3)
13859Sml29623 /*
23859Sml29623  * CDDL HEADER START
33859Sml29623  *
43859Sml29623  * The contents of this file are subject to the terms of the
53859Sml29623  * Common Development and Distribution License (the "License").
63859Sml29623  * You may not use this file except in compliance with the License.
73859Sml29623  *
83859Sml29623  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
93859Sml29623  * or http://www.opensolaris.org/os/licensing.
103859Sml29623  * See the License for the specific language governing permissions
113859Sml29623  * and limitations under the License.
123859Sml29623  *
133859Sml29623  * When distributing Covered Code, include this CDDL HEADER in each
143859Sml29623  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
153859Sml29623  * If applicable, add the following below this CDDL HEADER, with the
163859Sml29623  * fields enclosed by brackets "[]" replaced with your own identifying
173859Sml29623  * information: Portions Copyright [yyyy] [name of copyright owner]
183859Sml29623  *
193859Sml29623  * CDDL HEADER END
203859Sml29623  */
213859Sml29623 /*
223859Sml29623  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
233859Sml29623  * Use is subject to license terms.
243859Sml29623  */
253859Sml29623 
263859Sml29623 #pragma ident	"%Z%%M%	%I%	%E% SMI"
273859Sml29623 
283859Sml29623 #include <nxge_impl.h>
293859Sml29623 #include <nxge_ipp.h>
303859Sml29623 
313859Sml29623 #define	NXGE_IPP_FIFO_SYNC_TRY_COUNT 100
323859Sml29623 
333859Sml29623 /* ARGSUSED */
343859Sml29623 nxge_status_t
353859Sml29623 nxge_ipp_init(p_nxge_t nxgep)
363859Sml29623 {
373859Sml29623 	uint8_t portn;
383859Sml29623 	uint32_t config;
393859Sml29623 	npi_handle_t handle;
403859Sml29623 	uint32_t pkt_size;
413859Sml29623 	ipp_status_t istatus;
423859Sml29623 	npi_status_t rs = NPI_SUCCESS;
433859Sml29623 	uint64_t val;
443859Sml29623 	uint32_t d0, d1, d2, d3, d4;
453859Sml29623 	int i;
463859Sml29623 	uint32_t dfifo_entries;
473859Sml29623 
483859Sml29623 	handle = nxgep->npi_handle;
493859Sml29623 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
503859Sml29623 
513859Sml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_init: port%d", portn));
523859Sml29623 
533859Sml29623 	/* Initialize ECC and parity in SRAM of DFIFO and PFIFO */
544732Sdavemq 	if (nxgep->niu_type == N2_NIU) {
554732Sdavemq 		dfifo_entries = IPP_NIU_DFIFO_ENTRIES;
564977Sraghus 	} else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
573859Sml29623 		if (portn < 2)
583859Sml29623 			dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES;
593859Sml29623 		else
603859Sml29623 			dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES;
614732Sdavemq 	} else {
623859Sml29623 		goto fail;
634732Sdavemq 	}
643859Sml29623 
653859Sml29623 	for (i = 0; i < dfifo_entries; i++) {
663859Sml29623 		if ((rs = npi_ipp_write_dfifo(handle,
673859Sml29623 				portn, i, 0, 0, 0, 0, 0)) != NPI_SUCCESS)
683859Sml29623 			goto fail;
693859Sml29623 		if ((rs = npi_ipp_read_dfifo(handle, portn,
703859Sml29623 				i, &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
713859Sml29623 			goto fail;
723859Sml29623 	}
733859Sml29623 
743859Sml29623 	/* Clear PFIFO DFIFO status bits */
753859Sml29623 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
763859Sml29623 		goto fail;
773859Sml29623 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
783859Sml29623 		goto fail;
793859Sml29623 
803859Sml29623 	/*
813859Sml29623 	 * Soft reset to make sure we bring the FIFO pointers back to the
823859Sml29623 	 * original initial position.
833859Sml29623 	 */
843859Sml29623 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
853859Sml29623 		goto fail;
863859Sml29623 
873859Sml29623 	/* Clean up ECC counter */
883859Sml29623 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_ECC_ERR_COUNTER_REG, &val);
89*5523Syc148097 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_BAD_CKSUM_ERR_CNT_REG, &val);
903859Sml29623 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_DISCARD_PKT_CNT_REG, &val);
913859Sml29623 
923859Sml29623 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
933859Sml29623 		goto fail;
943859Sml29623 
953859Sml29623 	/* Configure IPP port */
963859Sml29623 	if ((rs = npi_ipp_iconfig(handle, INIT, portn, ICFG_IPP_ALL))
973859Sml29623 			!= NPI_SUCCESS)
983859Sml29623 		goto fail;
993859Sml29623 	nxgep->ipp.iconfig = ICFG_IPP_ALL;
1003859Sml29623 
1013859Sml29623 	config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC |
1023859Sml29623 		CFG_IPP_TCP_UDP_CKSUM;
1033859Sml29623 	if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS)
1043859Sml29623 		goto fail;
1053859Sml29623 	nxgep->ipp.config = config;
1063859Sml29623 
1073859Sml29623 	/* Set max packet size */
1083859Sml29623 	pkt_size = IPP_MAX_PKT_SIZE;
1093859Sml29623 	if ((rs = npi_ipp_set_max_pktsize(handle, portn,
1103859Sml29623 			IPP_MAX_PKT_SIZE)) != NPI_SUCCESS)
1113859Sml29623 		goto fail;
1123859Sml29623 	nxgep->ipp.max_pkt_size = pkt_size;
1133859Sml29623 
1143859Sml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_init: port%d", portn));
1153859Sml29623 
1163859Sml29623 	return (NXGE_OK);
1173859Sml29623 fail:
1183859Sml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
1193859Sml29623 			"nxge_ipp_init: Fail to initialize IPP Port #%d\n",
1203859Sml29623 			portn));
1213859Sml29623 	return (NXGE_ERROR | rs);
1223859Sml29623 }
1233859Sml29623 
1243859Sml29623 /* ARGSUSED */
1253859Sml29623 nxge_status_t
1263859Sml29623 nxge_ipp_disable(p_nxge_t nxgep)
1273859Sml29623 {
1283859Sml29623 	uint8_t portn;
1293859Sml29623 	uint32_t config;
1303859Sml29623 	npi_handle_t handle;
1313859Sml29623 	npi_status_t rs = NPI_SUCCESS;
1323859Sml29623 	uint16_t wr_ptr, rd_ptr;
1333859Sml29623 	uint32_t try_count;
1343859Sml29623 
1353859Sml29623 	handle = nxgep->npi_handle;
1363859Sml29623 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
1373859Sml29623 
1383859Sml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_disable: port%d", portn));
1393859Sml29623 	(void) nxge_rx_mac_disable(nxgep);
1403859Sml29623 
1413859Sml29623 	/*
1423859Sml29623 	 * Wait until ip read and write fifo pointers are equal
1433859Sml29623 	 */
1443859Sml29623 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
1453859Sml29623 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
1463859Sml29623 	try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT;
1473859Sml29623 
1483859Sml29623 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
1493859Sml29623 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
1503859Sml29623 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
1513859Sml29623 		try_count--;
1523859Sml29623 	}
1533859Sml29623 
1543859Sml29623 	if (try_count == 0) {
1553859Sml29623 		if ((rd_ptr != 0) && (wr_ptr != 1)) {
1563859Sml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
1573859Sml29623 				" nxge_ipp_disable: port%d failed"
1583859Sml29623 				" rd_fifo != wr_fifo", portn));
1593859Sml29623 			goto fail;
1603859Sml29623 		}
1613859Sml29623 	}
1623859Sml29623 	/* disable the IPP */
1633859Sml29623 	config = nxgep->ipp.config;
1643859Sml29623 	if ((rs = npi_ipp_config(handle, DISABLE,
1653859Sml29623 			portn, config)) != NPI_SUCCESS)
1663859Sml29623 		goto fail;
1673859Sml29623 
1683859Sml29623 	/* IPP soft reset */
1693859Sml29623 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
1703859Sml29623 		goto fail;
1713859Sml29623 
1723859Sml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_disable: port%d", portn));
1733859Sml29623 	return (NXGE_OK);
1743859Sml29623 fail:
1753859Sml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
1763859Sml29623 		"nxge_ipp_disable: Fail to disable IPP Port #%d\n", portn));
1773859Sml29623 	return (NXGE_ERROR | rs);
1783859Sml29623 }
1793859Sml29623 
1803859Sml29623 /* ARGSUSED */
1813859Sml29623 nxge_status_t
1823859Sml29623 nxge_ipp_reset(p_nxge_t nxgep)
1833859Sml29623 {
1843859Sml29623 	uint8_t portn;
1853859Sml29623 	uint32_t config;
1863859Sml29623 	npi_handle_t handle;
1873859Sml29623 	npi_status_t rs = NPI_SUCCESS;
1883859Sml29623 	uint16_t wr_ptr, rd_ptr;
1893859Sml29623 	uint32_t try_count;
1903859Sml29623 
1913859Sml29623 	handle = nxgep->npi_handle;
1923859Sml29623 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
1933859Sml29623 
1943859Sml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_reset: port%d", portn));
1953859Sml29623 
1963859Sml29623 	/* disable the IPP */
1973859Sml29623 	config = nxgep->ipp.config;
1983859Sml29623 	if ((rs = npi_ipp_config(handle, DISABLE,
1993859Sml29623 			portn, config)) != NPI_SUCCESS)
2003859Sml29623 		goto fail;
2013859Sml29623 
2023859Sml29623 	/*
2033859Sml29623 	 * Wait until ip read and write fifo pointers are equal
2043859Sml29623 	 */
2053859Sml29623 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
2063859Sml29623 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
2073859Sml29623 	try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT;
2083859Sml29623 
2093859Sml29623 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
2103859Sml29623 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
2113859Sml29623 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
2123859Sml29623 		try_count--;
2133859Sml29623 	}
2143859Sml29623 
2153859Sml29623 	if (try_count == 0) {
2163859Sml29623 		if ((rd_ptr != 0) && (wr_ptr != 1)) {
2173859Sml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2183859Sml29623 				" nxge_ipp_disable: port%d failed"
2193859Sml29623 				" rd_fifo != wr_fifo", portn));
2203859Sml29623 			goto fail;
2213859Sml29623 		}
2223859Sml29623 	}
2233859Sml29623 
2243859Sml29623 	/* IPP soft reset */
2253859Sml29623 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS) {
2263859Sml29623 		goto fail;
2273859Sml29623 	}
2283859Sml29623 
2293859Sml29623 	/* to reset control FIFO */
2303859Sml29623 	if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS)
2313859Sml29623 		goto fail;
2323859Sml29623 
2333859Sml29623 	/*
2343859Sml29623 	 * Making sure that error source is cleared if this is an injected
2353859Sml29623 	 * error.
2363859Sml29623 	 */
2373859Sml29623 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
2383859Sml29623 
2393859Sml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_reset: port%d", portn));
2403859Sml29623 	return (NXGE_OK);
2413859Sml29623 fail:
2423859Sml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2433859Sml29623 			"nxge_ipp_init: Fail to Reset IPP Port #%d\n",
2443859Sml29623 			portn));
2453859Sml29623 	return (NXGE_ERROR | rs);
2463859Sml29623 }
2473859Sml29623 
2483859Sml29623 /* ARGSUSED */
2493859Sml29623 nxge_status_t
2503859Sml29623 nxge_ipp_enable(p_nxge_t nxgep)
2513859Sml29623 {
2523859Sml29623 	uint8_t portn;
2533859Sml29623 	uint32_t config;
2543859Sml29623 	npi_handle_t handle;
2553859Sml29623 	uint32_t pkt_size;
2563859Sml29623 	npi_status_t rs = NPI_SUCCESS;
2573859Sml29623 
2583859Sml29623 	handle = nxgep->npi_handle;
2593859Sml29623 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
2603859Sml29623 
2613859Sml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_enable: port%d", portn));
2623859Sml29623 
2633859Sml29623 	config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC |
2643859Sml29623 		CFG_IPP_TCP_UDP_CKSUM;
2653859Sml29623 	if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS)
2663859Sml29623 		goto fail;
2673859Sml29623 	nxgep->ipp.config = config;
2683859Sml29623 
2693859Sml29623 	/* Set max packet size */
2703859Sml29623 	pkt_size = IPP_MAX_PKT_SIZE;
2713859Sml29623 	if ((rs = npi_ipp_set_max_pktsize(handle, portn,
2723859Sml29623 			IPP_MAX_PKT_SIZE)) != NPI_SUCCESS)
2733859Sml29623 		goto fail;
2743859Sml29623 	nxgep->ipp.max_pkt_size = pkt_size;
2753859Sml29623 
2763859Sml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_enable: port%d", portn));
2773859Sml29623 	return (NXGE_OK);
2783859Sml29623 fail:
2793859Sml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2803859Sml29623 		"nxge_ipp_init: Fail to Enable IPP Port #%d\n", portn));
2813859Sml29623 	return (NXGE_ERROR | rs);
2823859Sml29623 }
2833859Sml29623 
2843859Sml29623 /* ARGSUSED */
2853859Sml29623 nxge_status_t
2863859Sml29623 nxge_ipp_handle_sys_errors(p_nxge_t nxgep)
2873859Sml29623 {
2883859Sml29623 	npi_handle_t handle;
2893859Sml29623 	npi_status_t rs = NPI_SUCCESS;
2903859Sml29623 	p_nxge_ipp_stats_t statsp;
2913859Sml29623 	ipp_status_t istatus;
2923859Sml29623 	uint8_t portn;
2933859Sml29623 	p_ipp_errlog_t errlogp;
2943859Sml29623 	boolean_t rxport_fatal = B_FALSE;
2953859Sml29623 	nxge_status_t status = NXGE_OK;
2965165Syc148097 	uint8_t cnt8;
2975165Syc148097 	uint16_t cnt16;
2983859Sml29623 
2993859Sml29623 	handle = nxgep->npi_handle;
3003859Sml29623 	statsp = (p_nxge_ipp_stats_t)&nxgep->statsp->ipp_stats;
3013859Sml29623 	portn = nxgep->mac.portnum;
3023859Sml29623 
3033859Sml29623 	errlogp = (p_ipp_errlog_t)&statsp->errlog;
3043859Sml29623 
3053859Sml29623 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
3063859Sml29623 		return (NXGE_ERROR | rs);
3073859Sml29623 
3083859Sml29623 	if (istatus.value == 0) {
3093859Sml29623 		/*
3103859Sml29623 		 * The error is not initiated from this port, so just exit.
3113859Sml29623 		 */
3123859Sml29623 		return (NXGE_OK);
3133859Sml29623 	}
3143859Sml29623 
3153859Sml29623 	if (istatus.bits.w0.dfifo_missed_sop) {
3163859Sml29623 		statsp->sop_miss++;
3173859Sml29623 		if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn,
3183859Sml29623 					&errlogp->dfifo_rd_ptr)) != NPI_SUCCESS)
3193859Sml29623 			return (NXGE_ERROR | rs);
3203859Sml29623 		if ((rs = npi_ipp_get_state_mach(handle, portn,
3213859Sml29623 				&errlogp->state_mach)) != NPI_SUCCESS)
3223859Sml29623 			return (NXGE_ERROR | rs);
3233859Sml29623 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
3243859Sml29623 			NXGE_FM_EREPORT_IPP_SOP_MISS);
3253859Sml29623 		if (statsp->sop_miss < IPP_MAX_ERR_SHOW)
3263859Sml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3273859Sml29623 				"nxge_ipp_err_evnts: fatal error: sop_miss\n"));
3283859Sml29623 		rxport_fatal = B_TRUE;
3293859Sml29623 	}
3303859Sml29623 	if (istatus.bits.w0.dfifo_missed_eop) {
3313859Sml29623 		statsp->eop_miss++;
3323859Sml29623 		if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn,
3333859Sml29623 				&errlogp->dfifo_rd_ptr)) != NPI_SUCCESS)
3343859Sml29623 			return (NXGE_ERROR | rs);
3353859Sml29623 		if ((rs = npi_ipp_get_state_mach(handle, portn,
3363859Sml29623 				&errlogp->state_mach)) != NPI_SUCCESS)
3373859Sml29623 			return (NXGE_ERROR | rs);
3383859Sml29623 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
3393859Sml29623 			NXGE_FM_EREPORT_IPP_EOP_MISS);
3403859Sml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3413859Sml29623 			"nxge_ipp_err_evnts: fatal error: eop_miss\n"));
3423859Sml29623 		rxport_fatal = B_TRUE;
3433859Sml29623 	}
3443859Sml29623 	if (istatus.bits.w0.dfifo_uncorr_ecc_err) {
3453859Sml29623 		boolean_t ue_ecc_valid;
3463859Sml29623 
3473859Sml29623 		if ((status = nxge_ipp_eccue_valid_check(nxgep,
3483859Sml29623 				&ue_ecc_valid)) != NXGE_OK)
3493859Sml29623 			return (status);
3503859Sml29623 
3513859Sml29623 		if (ue_ecc_valid) {
3523859Sml29623 			statsp->dfifo_ue++;
3533859Sml29623 			if ((rs = npi_ipp_get_ecc_syndrome(handle, portn,
3543859Sml29623 					&errlogp->ecc_syndrome)) != NPI_SUCCESS)
3553859Sml29623 				return (NXGE_ERROR | rs);
3563859Sml29623 			NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
3573859Sml29623 				NXGE_FM_EREPORT_IPP_DFIFO_UE);
3583859Sml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3593859Sml29623 				"nxge_ipp_err_evnts: fatal error: dfifo_ue\n"));
3603859Sml29623 			rxport_fatal = B_TRUE;
3613859Sml29623 		}
3623859Sml29623 	}
3633859Sml29623 	if (istatus.bits.w0.pre_fifo_perr) {
3643859Sml29623 		statsp->pfifo_perr++;
3653859Sml29623 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
3663859Sml29623 			NXGE_FM_EREPORT_IPP_PFIFO_PERR);
3673859Sml29623 		if (statsp->pfifo_perr < IPP_MAX_ERR_SHOW)
3683859Sml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3693859Sml29623 				"nxge_ipp_err_evnts: "
3703859Sml29623 				"fatal error: pre_pifo_perr\n"));
3713859Sml29623 		rxport_fatal = B_TRUE;
3723859Sml29623 	}
3733859Sml29623 	if (istatus.bits.w0.pre_fifo_overrun) {
3743859Sml29623 		statsp->pfifo_over++;
3753859Sml29623 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
3763859Sml29623 			NXGE_FM_EREPORT_IPP_PFIFO_OVER);
3773859Sml29623 		if (statsp->pfifo_over < IPP_MAX_ERR_SHOW)
3783859Sml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3793859Sml29623 				"nxge_ipp_err_evnts: "
3803859Sml29623 				"fatal error: pfifo_over\n"));
3813859Sml29623 		rxport_fatal = B_TRUE;
3823859Sml29623 	}
3833859Sml29623 	if (istatus.bits.w0.pre_fifo_underrun) {
3843859Sml29623 		statsp->pfifo_und++;
3853859Sml29623 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
3863859Sml29623 			NXGE_FM_EREPORT_IPP_PFIFO_UND);
3873859Sml29623 		if (statsp->pfifo_und < IPP_MAX_ERR_SHOW)
3883859Sml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3893859Sml29623 				"nxge_ipp_err_evnts: "
3903859Sml29623 				"fatal error: pfifo_und\n"));
3913859Sml29623 		rxport_fatal = B_TRUE;
3923859Sml29623 	}
3933859Sml29623 	if (istatus.bits.w0.bad_cksum_cnt_ovfl) {
3945222Syc148097 		/*
3955222Syc148097 		 * Clear bit BAD_CS_MX of register IPP_INT_STAT
3965222Syc148097 		 * by reading register IPP_BAD_CS_CNT
3975222Syc148097 		 */
3985165Syc148097 		(void) npi_ipp_get_cs_err_count(handle, portn, &cnt16);
3993859Sml29623 		statsp->bad_cs_cnt += IPP_BAD_CS_CNT_MASK;
400*5523Syc148097 		/*
401*5523Syc148097 		 * Do not send FMA ereport because this error does not
402*5523Syc148097 		 * indicate a HW failure
403*5523Syc148097 		 */
4043859Sml29623 		if (statsp->bad_cs_cnt < (IPP_MAX_ERR_SHOW *
4053859Sml29623 				IPP_BAD_CS_CNT_MASK))
4063859Sml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4073859Sml29623 				"nxge_ipp_err_evnts: bad_cs_max\n"));
4083859Sml29623 	}
4093859Sml29623 	if (istatus.bits.w0.pkt_discard_cnt_ovfl) {
4105222Syc148097 		/*
4115222Syc148097 		 * Clear bit PKT_DIS_MX of register IPP_INT_STAT
4125222Syc148097 		 * by reading register IPP_PKT_DIS
4135222Syc148097 		 */
4145165Syc148097 		(void) npi_ipp_get_pkt_dis_count(handle, portn, &cnt16);
4153859Sml29623 		statsp->pkt_dis_cnt += IPP_PKT_DIS_CNT_MASK;
416*5523Syc148097 		/*
417*5523Syc148097 		 * Do not send FMA ereport because this error does not
418*5523Syc148097 		 * indicate a HW failure
419*5523Syc148097 		 */
4203859Sml29623 		if (statsp->pkt_dis_cnt < (IPP_MAX_ERR_SHOW *
4213859Sml29623 				IPP_PKT_DIS_CNT_MASK))
4223859Sml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4233859Sml29623 				"nxge_ipp_err_evnts: pkt_dis_max\n"));
4243859Sml29623 	}
4255165Syc148097 	if (istatus.bits.w0.ecc_err_cnt_ovfl) {
4265222Syc148097 		/*
4275222Syc148097 		 * Clear bit ECC_ERR_MAX of register IPP_INI_STAT
4285222Syc148097 		 * by reading register IPP_ECC
4295222Syc148097 		 */
4305165Syc148097 		(void) npi_ipp_get_ecc_err_count(handle, portn, &cnt8);
4315165Syc148097 		statsp->ecc_err_cnt += IPP_ECC_CNT_MASK;
432*5523Syc148097 		/*
433*5523Syc148097 		 * A defect in Neptune port2's IPP module could generate
434*5523Syc148097 		 * many fake but harmless ECC errors under stress and cause
435*5523Syc148097 		 * the ecc-error-counter register IPP_ECC to reach its
436*5523Syc148097 		 * maximum value in a few seconds. To avoid false alarm, do
437*5523Syc148097 		 * not report the error if it is port2.
438*5523Syc148097 		 */
439*5523Syc148097 		if (portn != 2) {
440*5523Syc148097 			NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
441*5523Syc148097 			    NXGE_FM_EREPORT_IPP_ECC_ERR_MAX);
442*5523Syc148097 			if (statsp->ecc_err_cnt < (IPP_MAX_ERR_SHOW *
443*5523Syc148097 			    IPP_ECC_CNT_MASK)) {
444*5523Syc148097 				NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
445*5523Syc148097 				    "nxge_ipp_err_evnts: pkt_ecc_err_max\n"));
446*5523Syc148097 			}
447*5523Syc148097 		}
4485165Syc148097 	}
4493859Sml29623 	/*
4503859Sml29623 	 * Making sure that error source is cleared if this is an injected
4513859Sml29623 	 * error.
4523859Sml29623 	 */
4533859Sml29623 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
4543859Sml29623 
4553859Sml29623 	if (rxport_fatal) {
4563859Sml29623 		NXGE_DEBUG_MSG((nxgep, IPP_CTL,
4573859Sml29623 			" nxge_ipp_handle_sys_errors:"
4583859Sml29623 			" fatal Error on  Port #%d\n", portn));
4593859Sml29623 		status = nxge_ipp_fatal_err_recover(nxgep);
4603859Sml29623 		if (status == NXGE_OK) {
4613859Sml29623 			FM_SERVICE_RESTORED(nxgep);
4623859Sml29623 		}
4633859Sml29623 	}
4643859Sml29623 	return (status);
4653859Sml29623 }
4663859Sml29623 
4673859Sml29623 /* ARGSUSED */
4683859Sml29623 void
4693859Sml29623 nxge_ipp_inject_err(p_nxge_t nxgep, uint32_t err_id)
4703859Sml29623 {
4713859Sml29623 	ipp_status_t ipps;
4723859Sml29623 	ipp_ecc_ctrl_t ecc_ctrl;
4733859Sml29623 	uint8_t portn = nxgep->mac.portnum;
4743859Sml29623 
4753859Sml29623 	switch (err_id) {
4763859Sml29623 	case NXGE_FM_EREPORT_IPP_DFIFO_UE:
4773859Sml29623 		ecc_ctrl.value = 0;
4783859Sml29623 		ecc_ctrl.bits.w0.cor_dbl = 1;
4793859Sml29623 		ecc_ctrl.bits.w0.cor_1 = 1;
4803859Sml29623 		ecc_ctrl.bits.w0.cor_lst = 1;
4813859Sml29623 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n",
4823859Sml29623 			(unsigned long long) ecc_ctrl.value);
4833859Sml29623 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG,
4843859Sml29623 			ecc_ctrl.value);
4853859Sml29623 		break;
4863859Sml29623 
4873859Sml29623 	case NXGE_FM_EREPORT_IPP_DFIFO_CE:
4883859Sml29623 		ecc_ctrl.value = 0;
4893859Sml29623 		ecc_ctrl.bits.w0.cor_sng = 1;
4903859Sml29623 		ecc_ctrl.bits.w0.cor_1 = 1;
4913859Sml29623 		ecc_ctrl.bits.w0.cor_snd = 1;
4923859Sml29623 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n",
4933859Sml29623 			(unsigned long long) ecc_ctrl.value);
4943859Sml29623 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG,
4953859Sml29623 			ecc_ctrl.value);
4963859Sml29623 		break;
4973859Sml29623 
4983859Sml29623 	case NXGE_FM_EREPORT_IPP_EOP_MISS:
4993859Sml29623 	case NXGE_FM_EREPORT_IPP_SOP_MISS:
5003859Sml29623 	case NXGE_FM_EREPORT_IPP_PFIFO_PERR:
5013859Sml29623 	case NXGE_FM_EREPORT_IPP_ECC_ERR_MAX:
5023859Sml29623 	case NXGE_FM_EREPORT_IPP_PFIFO_OVER:
5033859Sml29623 	case NXGE_FM_EREPORT_IPP_PFIFO_UND:
5043859Sml29623 	case NXGE_FM_EREPORT_IPP_BAD_CS_MX:
5053859Sml29623 	case NXGE_FM_EREPORT_IPP_PKT_DIS_MX:
5063859Sml29623 	case NXGE_FM_EREPORT_IPP_RESET_FAIL:
5073859Sml29623 		IPP_REG_RD(nxgep->npi_handle, portn, IPP_INT_STATUS_REG,
5083859Sml29623 			&ipps.value);
5093859Sml29623 		if (err_id == NXGE_FM_EREPORT_IPP_EOP_MISS)
5103859Sml29623 			ipps.bits.w0.dfifo_missed_eop = 1;
5113859Sml29623 		else if (err_id == NXGE_FM_EREPORT_IPP_SOP_MISS)
5123859Sml29623 			ipps.bits.w0.dfifo_missed_sop = 1;
5133859Sml29623 		else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_UE)
5143859Sml29623 			ipps.bits.w0.dfifo_uncorr_ecc_err = 1;
5153859Sml29623 		else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_CE)
5163859Sml29623 			ipps.bits.w0.dfifo_corr_ecc_err = 1;
5173859Sml29623 		else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_PERR)
5183859Sml29623 			ipps.bits.w0.pre_fifo_perr = 1;
5195222Syc148097 		else if (err_id == NXGE_FM_EREPORT_IPP_ECC_ERR_MAX) {
5205222Syc148097 			/*
5215222Syc148097 			 * Fill register IPP_ECC with max ECC-error-
5225222Syc148097 			 * counter value (0xff) to set the ECC_ERR_MAX bit
5235222Syc148097 			 * of the IPP_INT_STAT register and trigger an
5245222Syc148097 			 * FMA ereport.
5255222Syc148097 			 */
5265222Syc148097 			IPP_REG_WR(nxgep->npi_handle, portn,
5275222Syc148097 			    IPP_ECC_ERR_COUNTER_REG, IPP_ECC_CNT_MASK);
5285222Syc148097 		} else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_OVER)
5293859Sml29623 			ipps.bits.w0.pre_fifo_overrun = 1;
5303859Sml29623 		else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_UND)
5313859Sml29623 			ipps.bits.w0.pre_fifo_underrun = 1;
5325222Syc148097 		else if (err_id == NXGE_FM_EREPORT_IPP_BAD_CS_MX) {
5335222Syc148097 			/*
5345222Syc148097 			 * Fill IPP_BAD_CS_CNT with max bad-checksum-counter
5355222Syc148097 			 * value (0x3fff) to set the BAD_CS_MX bit of
5365222Syc148097 			 * IPP_INT_STAT and trigger an FMA ereport.
5375222Syc148097 			 */
5385222Syc148097 			IPP_REG_WR(nxgep->npi_handle, portn,
539*5523Syc148097 			    IPP_BAD_CKSUM_ERR_CNT_REG, IPP_BAD_CS_CNT_MASK);
5405222Syc148097 		} else if (err_id == NXGE_FM_EREPORT_IPP_PKT_DIS_MX) {
5415222Syc148097 			/*
5425222Syc148097 			 * Fill IPP_PKT_DIS with max packet-discard-counter
5435222Syc148097 			 * value (0x3fff) to set the PKT_DIS_MX bit of
5445222Syc148097 			 * IPP_INT_STAT and trigger an FMA ereport.
5455222Syc148097 			 */
5465222Syc148097 			IPP_REG_WR(nxgep->npi_handle, portn,
5475222Syc148097 			    IPP_DISCARD_PKT_CNT_REG, IPP_PKT_DIS_CNT_MASK);
5485222Syc148097 		}
5493859Sml29623 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_INT_STATUS_REG\n",
5503859Sml29623 			(unsigned long long) ipps.value);
5513859Sml29623 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_INT_STATUS_REG,
5523859Sml29623 			ipps.value);
5533859Sml29623 		break;
5543859Sml29623 	}
5553859Sml29623 }
5563859Sml29623 
5573859Sml29623 /* ARGSUSED */
5583859Sml29623 nxge_status_t
5593859Sml29623 nxge_ipp_fatal_err_recover(p_nxge_t nxgep)
5603859Sml29623 {
5613859Sml29623 	npi_handle_t handle;
5623859Sml29623 	npi_status_t rs = NPI_SUCCESS;
5633859Sml29623 	nxge_status_t status = NXGE_OK;
5643859Sml29623 	uint8_t portn;
5653859Sml29623 	uint16_t wr_ptr;
5663859Sml29623 	uint16_t rd_ptr;
5673859Sml29623 	uint32_t try_count;
5683859Sml29623 	uint32_t dfifo_entries;
5693859Sml29623 	ipp_status_t istatus;
5703859Sml29623 	uint32_t d0, d1, d2, d3, d4;
5713859Sml29623 	int i;
5723859Sml29623 
5733859Sml29623 	NXGE_DEBUG_MSG((nxgep, RX_CTL, "<== nxge_ipp_fatal_err_recover"));
5743859Sml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
5753859Sml29623 		"Recovering from RxPort error..."));
5763859Sml29623 
5773859Sml29623 	handle = nxgep->npi_handle;
5783859Sml29623 	portn = nxgep->mac.portnum;
5793859Sml29623 
5803859Sml29623 	/*
5813859Sml29623 	 * Making sure that error source is cleared if this is an injected
5823859Sml29623 	 * error.
5833859Sml29623 	 */
5843859Sml29623 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
5853859Sml29623 
5863859Sml29623 	/* Disable RxMAC */
5873859Sml29623 	if (nxge_rx_mac_disable(nxgep) != NXGE_OK)
5883859Sml29623 		goto fail;
5893859Sml29623 
5903859Sml29623 	/* When recovering from IPP, RxDMA channel resets are not necessary */
5913859Sml29623 	/* Reset ZCP CFIFO */
5923859Sml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset ZCP CFIFO...", portn));
5933859Sml29623 	if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS)
5943859Sml29623 		goto fail;
5953859Sml29623 
5963859Sml29623 	/*
5973859Sml29623 	 * Wait until ip read and write fifo pointers are equal
5983859Sml29623 	 */
5993859Sml29623 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
6003859Sml29623 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
6013859Sml29623 	try_count = 512;
6023859Sml29623 
6033859Sml29623 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
6043859Sml29623 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
6053859Sml29623 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
6063859Sml29623 		try_count--;
6073859Sml29623 	}
6083859Sml29623 
6093859Sml29623 	if (try_count == 0) {
6103859Sml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
6113859Sml29623 			" nxge_ipp_reset: port%d IPP stalled..."
6123859Sml29623 			" rd_fifo_ptr = 0x%x wr_fifo_ptr = 0x%x",
6133859Sml29623 			portn, rd_ptr, wr_ptr));
6143859Sml29623 		/*
6153859Sml29623 		 * This means the fatal error occurred on the first line of the
6163859Sml29623 		 * fifo. In this case, just reset the IPP without draining the
6173859Sml29623 		 * PFIFO.
6183859Sml29623 		 */
6193859Sml29623 	}
6203859Sml29623 
6214732Sdavemq 	if (nxgep->niu_type == N2_NIU) {
6224732Sdavemq 		dfifo_entries = IPP_NIU_DFIFO_ENTRIES;
6234977Sraghus 	} else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
6243859Sml29623 		if (portn < 2)
6253859Sml29623 			dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES;
6263859Sml29623 		else
6273859Sml29623 			dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES;
6284732Sdavemq 	} else {
6293859Sml29623 		goto fail;
6304732Sdavemq 	}
6313859Sml29623 
6323859Sml29623 	/* Clean up DFIFO SRAM entries */
6333859Sml29623 	for (i = 0; i < dfifo_entries; i++) {
6343859Sml29623 		if ((rs = npi_ipp_write_dfifo(handle, portn,
6353859Sml29623 				i, 0, 0, 0, 0, 0)) != NPI_SUCCESS)
6363859Sml29623 			goto fail;
6373859Sml29623 		if ((rs = npi_ipp_read_dfifo(handle, portn, i,
6383859Sml29623 				&d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
6393859Sml29623 			goto fail;
6403859Sml29623 	}
6413859Sml29623 
6423859Sml29623 	/* Clear PFIFO DFIFO status bits */
6433859Sml29623 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
6443859Sml29623 		goto fail;
6453859Sml29623 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
6463859Sml29623 		goto fail;
6473859Sml29623 
6483859Sml29623 	/* Reset IPP */
6493859Sml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset IPP...", portn));
6503859Sml29623 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
6513859Sml29623 		goto fail;
6523859Sml29623 
6533859Sml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset RxMAC...", portn));
6543859Sml29623 	if (nxge_rx_mac_reset(nxgep) != NXGE_OK)
6553859Sml29623 		goto fail;
6563859Sml29623 
6573859Sml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Initialize RxMAC...", portn));
6583859Sml29623 	if ((status = nxge_rx_mac_init(nxgep)) != NXGE_OK)
6593859Sml29623 		goto fail;
6603859Sml29623 
6613859Sml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Enable RxMAC...", portn));
6623859Sml29623 	if (nxge_rx_mac_enable(nxgep) != NXGE_OK)
6633859Sml29623 		goto fail;
6643859Sml29623 
6653859Sml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
6665222Syc148097 		"Recovery successful, RxPort restored"));
6673859Sml29623 	NXGE_DEBUG_MSG((nxgep, RX_CTL, "==> nxge_ipp_fatal_err_recover"));
6683859Sml29623 
6693859Sml29623 	return (NXGE_OK);
6703859Sml29623 fail:
6713859Sml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
6723859Sml29623 	return (status | rs);
6733859Sml29623 }
6743859Sml29623 
6753859Sml29623 /* ARGSUSED */
6764638Syc148097 /*
6775165Syc148097  *    A hardware bug may cause fake ECCUEs (ECC Uncorrectable Error).
6784638Syc148097  * This function checks if a ECCUE is real(valid) or not.  It is not
6794638Syc148097  * real if rd_ptr == wr_ptr.
6804638Syc148097  *    The hardware module that has the bug is used not only by the IPP
6814638Syc148097  * FIFO but also by the ZCP FIFO, therefore this function is also
6824638Syc148097  * called by nxge_zcp_handle_sys_errors for validating the ZCP FIFO
6834638Syc148097  * error.
6844638Syc148097  */
6853859Sml29623 nxge_status_t
6863859Sml29623 nxge_ipp_eccue_valid_check(p_nxge_t nxgep, boolean_t *valid)
6873859Sml29623 {
6883859Sml29623 	npi_handle_t handle;
6893859Sml29623 	npi_status_t rs = NPI_SUCCESS;
6903859Sml29623 	uint8_t portn;
6913859Sml29623 	uint16_t rd_ptr;
6923859Sml29623 	uint16_t wr_ptr;
6933859Sml29623 	uint16_t curr_rd_ptr;
6943859Sml29623 	uint16_t curr_wr_ptr;
6953859Sml29623 	uint32_t stall_cnt;
6963859Sml29623 	uint32_t d0, d1, d2, d3, d4;
6973859Sml29623 
6983859Sml29623 	handle = nxgep->npi_handle;
6993859Sml29623 	portn = nxgep->mac.portnum;
7003859Sml29623 	*valid = B_TRUE;
7013859Sml29623 
7023859Sml29623 	if ((rs = npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr))
7033859Sml29623 		!= NPI_SUCCESS)
7043859Sml29623 		goto fail;
7054638Syc148097 	if ((rs = npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr))
7063859Sml29623 		!= NPI_SUCCESS)
7073859Sml29623 		goto fail;
7083859Sml29623 
7093859Sml29623 	if (rd_ptr == wr_ptr) {
7104638Syc148097 		*valid = B_FALSE; /* FIFO not stuck, so it's not a real ECCUE */
7113859Sml29623 	} else {
7123859Sml29623 		stall_cnt = 0;
7135060Syc148097 		/*
7145060Syc148097 		 * Check if the two pointers are moving, the ECCUE is invali
7155060Syc148097 		 * if either pointer is moving, which indicates that the FIFO
7165060Syc148097 		 * is functional.
7175060Syc148097 		 */
7183859Sml29623 		while (stall_cnt < 16) {
7193859Sml29623 			if ((rs = npi_ipp_get_dfifo_rd_ptr(handle,
7203859Sml29623 					portn, &curr_rd_ptr)) != NPI_SUCCESS)
7213859Sml29623 				goto fail;
7223859Sml29623 			if ((rs = npi_ipp_get_dfifo_wr_ptr(handle,
7233859Sml29623 					portn, &curr_wr_ptr)) != NPI_SUCCESS)
7243859Sml29623 				goto fail;
7253859Sml29623 
7265060Syc148097 			if (rd_ptr == curr_rd_ptr && wr_ptr == curr_wr_ptr) {
7273859Sml29623 				stall_cnt++;
7285060Syc148097 			} else {
7293859Sml29623 				*valid = B_FALSE;
7303859Sml29623 				break;
7313859Sml29623 			}
7323859Sml29623 		}
7333859Sml29623 
7343859Sml29623 		if (valid) {
7355060Syc148097 			/*
7365222Syc148097 			 * Further check to see if the ECCUE is valid. The
7375060Syc148097 			 * error is real if the LSB of d4 is 1, which
7385060Syc148097 			 * indicates that the data that has set the ECC
7395060Syc148097 			 * error flag is the 16-byte internal control word.
7405060Syc148097 			 */
7415060Syc148097 			if ((rs = npi_ipp_read_dfifo(handle, portn, rd_ptr,
7425060Syc148097 			    &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
7433859Sml29623 				goto fail;
7443859Sml29623 			if ((d4 & 0x1) == 0)	/* Not the 1st line */
7453859Sml29623 				*valid = B_FALSE;
7463859Sml29623 		}
7473859Sml29623 	}
7483859Sml29623 	return (NXGE_OK);
7493859Sml29623 fail:
7503859Sml29623 	return (NXGE_ERROR | rs);
7513859Sml29623 }
752