xref: /titanic_50/usr/src/uts/common/io/nxge/nxge_ipp.c (revision 52ccf843e173e2a4a657360b0a22853fd413905f)
16f45ec7bSml29623 /*
26f45ec7bSml29623  * CDDL HEADER START
36f45ec7bSml29623  *
46f45ec7bSml29623  * The contents of this file are subject to the terms of the
56f45ec7bSml29623  * Common Development and Distribution License (the "License").
66f45ec7bSml29623  * You may not use this file except in compliance with the License.
76f45ec7bSml29623  *
86f45ec7bSml29623  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
96f45ec7bSml29623  * or http://www.opensolaris.org/os/licensing.
106f45ec7bSml29623  * See the License for the specific language governing permissions
116f45ec7bSml29623  * and limitations under the License.
126f45ec7bSml29623  *
136f45ec7bSml29623  * When distributing Covered Code, include this CDDL HEADER in each
146f45ec7bSml29623  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
156f45ec7bSml29623  * If applicable, add the following below this CDDL HEADER, with the
166f45ec7bSml29623  * fields enclosed by brackets "[]" replaced with your own identifying
176f45ec7bSml29623  * information: Portions Copyright [yyyy] [name of copyright owner]
186f45ec7bSml29623  *
196f45ec7bSml29623  * CDDL HEADER END
206f45ec7bSml29623  */
216f45ec7bSml29623 /*
2263e23a19Syc148097  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
236f45ec7bSml29623  * Use is subject to license terms.
246f45ec7bSml29623  */
256f45ec7bSml29623 
266f45ec7bSml29623 #pragma ident	"%Z%%M%	%I%	%E% SMI"
276f45ec7bSml29623 
286f45ec7bSml29623 #include <nxge_impl.h>
296f45ec7bSml29623 #include <nxge_ipp.h>
306f45ec7bSml29623 
316f45ec7bSml29623 #define	NXGE_IPP_FIFO_SYNC_TRY_COUNT 100
326f45ec7bSml29623 
336f45ec7bSml29623 /* ARGSUSED */
346f45ec7bSml29623 nxge_status_t
nxge_ipp_init(p_nxge_t nxgep)356f45ec7bSml29623 nxge_ipp_init(p_nxge_t nxgep)
366f45ec7bSml29623 {
376f45ec7bSml29623 	uint8_t portn;
386f45ec7bSml29623 	uint32_t config;
396f45ec7bSml29623 	npi_handle_t handle;
406f45ec7bSml29623 	uint32_t pkt_size;
416f45ec7bSml29623 	ipp_status_t istatus;
426f45ec7bSml29623 	npi_status_t rs = NPI_SUCCESS;
436f45ec7bSml29623 	uint64_t val;
446f45ec7bSml29623 	uint32_t d0, d1, d2, d3, d4;
456f45ec7bSml29623 	int i;
466f45ec7bSml29623 	uint32_t dfifo_entries;
476f45ec7bSml29623 
486f45ec7bSml29623 	handle = nxgep->npi_handle;
496f45ec7bSml29623 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
506f45ec7bSml29623 
516f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_init: port%d", portn));
526f45ec7bSml29623 
536f45ec7bSml29623 	/* Initialize ECC and parity in SRAM of DFIFO and PFIFO */
5459ac0c16Sdavemq 	if (nxgep->niu_type == N2_NIU) {
5559ac0c16Sdavemq 		dfifo_entries = IPP_NIU_DFIFO_ENTRIES;
562e59129aSraghus 	} else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
576f45ec7bSml29623 		if (portn < 2)
586f45ec7bSml29623 			dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES;
596f45ec7bSml29623 		else
606f45ec7bSml29623 			dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES;
6159ac0c16Sdavemq 	} else {
626f45ec7bSml29623 		goto fail;
6359ac0c16Sdavemq 	}
646f45ec7bSml29623 
656f45ec7bSml29623 	for (i = 0; i < dfifo_entries; i++) {
666f45ec7bSml29623 		if ((rs = npi_ipp_write_dfifo(handle,
676f45ec7bSml29623 		    portn, i, 0, 0, 0, 0, 0)) != NPI_SUCCESS)
686f45ec7bSml29623 			goto fail;
696f45ec7bSml29623 		if ((rs = npi_ipp_read_dfifo(handle, portn,
706f45ec7bSml29623 		    i, &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
716f45ec7bSml29623 			goto fail;
726f45ec7bSml29623 	}
736f45ec7bSml29623 
746f45ec7bSml29623 	/* Clear PFIFO DFIFO status bits */
756f45ec7bSml29623 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
766f45ec7bSml29623 		goto fail;
776f45ec7bSml29623 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
786f45ec7bSml29623 		goto fail;
796f45ec7bSml29623 
806f45ec7bSml29623 	/*
816f45ec7bSml29623 	 * Soft reset to make sure we bring the FIFO pointers back to the
826f45ec7bSml29623 	 * original initial position.
836f45ec7bSml29623 	 */
846f45ec7bSml29623 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
856f45ec7bSml29623 		goto fail;
866f45ec7bSml29623 
876f45ec7bSml29623 	/* Clean up ECC counter */
886f45ec7bSml29623 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_ECC_ERR_COUNTER_REG, &val);
89f6485eecSyc148097 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_BAD_CKSUM_ERR_CNT_REG, &val);
906f45ec7bSml29623 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_DISCARD_PKT_CNT_REG, &val);
916f45ec7bSml29623 
926f45ec7bSml29623 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
936f45ec7bSml29623 		goto fail;
946f45ec7bSml29623 
956f45ec7bSml29623 	/* Configure IPP port */
966f45ec7bSml29623 	if ((rs = npi_ipp_iconfig(handle, INIT, portn, ICFG_IPP_ALL))
976f45ec7bSml29623 	    != NPI_SUCCESS)
986f45ec7bSml29623 		goto fail;
996f45ec7bSml29623 	nxgep->ipp.iconfig = ICFG_IPP_ALL;
1006f45ec7bSml29623 
1016f45ec7bSml29623 	config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC |
1026f45ec7bSml29623 	    CFG_IPP_TCP_UDP_CKSUM;
1036f45ec7bSml29623 	if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS)
1046f45ec7bSml29623 		goto fail;
1056f45ec7bSml29623 	nxgep->ipp.config = config;
1066f45ec7bSml29623 
1076f45ec7bSml29623 	/* Set max packet size */
1086f45ec7bSml29623 	pkt_size = IPP_MAX_PKT_SIZE;
1096f45ec7bSml29623 	if ((rs = npi_ipp_set_max_pktsize(handle, portn,
1106f45ec7bSml29623 	    IPP_MAX_PKT_SIZE)) != NPI_SUCCESS)
1116f45ec7bSml29623 		goto fail;
1126f45ec7bSml29623 	nxgep->ipp.max_pkt_size = pkt_size;
1136f45ec7bSml29623 
1146f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_init: port%d", portn));
1156f45ec7bSml29623 
1166f45ec7bSml29623 	return (NXGE_OK);
1176f45ec7bSml29623 fail:
1186f45ec7bSml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
1196f45ec7bSml29623 	    "nxge_ipp_init: Fail to initialize IPP Port #%d\n",
1206f45ec7bSml29623 	    portn));
1216f45ec7bSml29623 	return (NXGE_ERROR | rs);
1226f45ec7bSml29623 }
1236f45ec7bSml29623 
1246f45ec7bSml29623 /* ARGSUSED */
1256f45ec7bSml29623 nxge_status_t
nxge_ipp_disable(p_nxge_t nxgep)1266f45ec7bSml29623 nxge_ipp_disable(p_nxge_t nxgep)
1276f45ec7bSml29623 {
1286f45ec7bSml29623 	uint8_t portn;
1296f45ec7bSml29623 	uint32_t config;
1306f45ec7bSml29623 	npi_handle_t handle;
1316f45ec7bSml29623 	npi_status_t rs = NPI_SUCCESS;
1326f45ec7bSml29623 	uint16_t wr_ptr, rd_ptr;
1336f45ec7bSml29623 	uint32_t try_count;
1346f45ec7bSml29623 
1356f45ec7bSml29623 	handle = nxgep->npi_handle;
1366f45ec7bSml29623 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
1376f45ec7bSml29623 
1386f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_disable: port%d", portn));
1396f45ec7bSml29623 	(void) nxge_rx_mac_disable(nxgep);
1406f45ec7bSml29623 
1416f45ec7bSml29623 	/*
1426f45ec7bSml29623 	 * Wait until ip read and write fifo pointers are equal
1436f45ec7bSml29623 	 */
1446f45ec7bSml29623 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
1456f45ec7bSml29623 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
1466f45ec7bSml29623 	try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT;
1476f45ec7bSml29623 
1486f45ec7bSml29623 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
1496f45ec7bSml29623 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
1506f45ec7bSml29623 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
1516f45ec7bSml29623 		try_count--;
1526f45ec7bSml29623 	}
1536f45ec7bSml29623 
1546f45ec7bSml29623 	if (try_count == 0) {
1556f45ec7bSml29623 		if ((rd_ptr != 0) && (wr_ptr != 1)) {
1566f45ec7bSml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
1576f45ec7bSml29623 			    " nxge_ipp_disable: port%d failed"
1586f45ec7bSml29623 			    " rd_fifo != wr_fifo", portn));
1596f45ec7bSml29623 			goto fail;
1606f45ec7bSml29623 		}
1616f45ec7bSml29623 	}
1626f45ec7bSml29623 	/* disable the IPP */
1636f45ec7bSml29623 	config = nxgep->ipp.config;
1646f45ec7bSml29623 	if ((rs = npi_ipp_config(handle, DISABLE,
1656f45ec7bSml29623 	    portn, config)) != NPI_SUCCESS)
1666f45ec7bSml29623 		goto fail;
1676f45ec7bSml29623 
1686f45ec7bSml29623 	/* IPP soft reset */
1696f45ec7bSml29623 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
1706f45ec7bSml29623 		goto fail;
1716f45ec7bSml29623 
1726f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_disable: port%d", portn));
1736f45ec7bSml29623 	return (NXGE_OK);
1746f45ec7bSml29623 fail:
1756f45ec7bSml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
1766f45ec7bSml29623 	    "nxge_ipp_disable: Fail to disable IPP Port #%d\n", portn));
1776f45ec7bSml29623 	return (NXGE_ERROR | rs);
1786f45ec7bSml29623 }
1796f45ec7bSml29623 
1806f45ec7bSml29623 /* ARGSUSED */
1816f45ec7bSml29623 nxge_status_t
nxge_ipp_reset(p_nxge_t nxgep)1826f45ec7bSml29623 nxge_ipp_reset(p_nxge_t nxgep)
1836f45ec7bSml29623 {
1846f45ec7bSml29623 	uint8_t portn;
1856f45ec7bSml29623 	uint32_t config;
1866f45ec7bSml29623 	npi_handle_t handle;
1876f45ec7bSml29623 	npi_status_t rs = NPI_SUCCESS;
1886f45ec7bSml29623 	uint16_t wr_ptr, rd_ptr;
1896f45ec7bSml29623 	uint32_t try_count;
1906f45ec7bSml29623 
1916f45ec7bSml29623 	handle = nxgep->npi_handle;
1926f45ec7bSml29623 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
1936f45ec7bSml29623 
1946f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_reset: port%d", portn));
1956f45ec7bSml29623 
1966f45ec7bSml29623 	/* disable the IPP */
1976f45ec7bSml29623 	config = nxgep->ipp.config;
1986f45ec7bSml29623 	if ((rs = npi_ipp_config(handle, DISABLE,
1996f45ec7bSml29623 	    portn, config)) != NPI_SUCCESS)
2006f45ec7bSml29623 		goto fail;
2016f45ec7bSml29623 
2026f45ec7bSml29623 	/*
2036f45ec7bSml29623 	 * Wait until ip read and write fifo pointers are equal
2046f45ec7bSml29623 	 */
2056f45ec7bSml29623 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
2066f45ec7bSml29623 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
2076f45ec7bSml29623 	try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT;
2086f45ec7bSml29623 
2096f45ec7bSml29623 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
2106f45ec7bSml29623 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
2116f45ec7bSml29623 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
2126f45ec7bSml29623 		try_count--;
2136f45ec7bSml29623 	}
2146f45ec7bSml29623 
2156f45ec7bSml29623 	if (try_count == 0) {
2166f45ec7bSml29623 		if ((rd_ptr != 0) && (wr_ptr != 1)) {
2176f45ec7bSml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2186f45ec7bSml29623 			    " nxge_ipp_disable: port%d failed"
2196f45ec7bSml29623 			    " rd_fifo != wr_fifo", portn));
2206f45ec7bSml29623 			goto fail;
2216f45ec7bSml29623 		}
2226f45ec7bSml29623 	}
2236f45ec7bSml29623 
2246f45ec7bSml29623 	/* IPP soft reset */
2256f45ec7bSml29623 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS) {
2266f45ec7bSml29623 		goto fail;
2276f45ec7bSml29623 	}
2286f45ec7bSml29623 
2296f45ec7bSml29623 	/* to reset control FIFO */
2306f45ec7bSml29623 	if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS)
2316f45ec7bSml29623 		goto fail;
2326f45ec7bSml29623 
2336f45ec7bSml29623 	/*
2346f45ec7bSml29623 	 * Making sure that error source is cleared if this is an injected
2356f45ec7bSml29623 	 * error.
2366f45ec7bSml29623 	 */
2376f45ec7bSml29623 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
2386f45ec7bSml29623 
2396f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_reset: port%d", portn));
2406f45ec7bSml29623 	return (NXGE_OK);
2416f45ec7bSml29623 fail:
2426f45ec7bSml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2436f45ec7bSml29623 	    "nxge_ipp_init: Fail to Reset IPP Port #%d\n",
2446f45ec7bSml29623 	    portn));
2456f45ec7bSml29623 	return (NXGE_ERROR | rs);
2466f45ec7bSml29623 }
2476f45ec7bSml29623 
2486f45ec7bSml29623 /* ARGSUSED */
2496f45ec7bSml29623 nxge_status_t
nxge_ipp_enable(p_nxge_t nxgep)2506f45ec7bSml29623 nxge_ipp_enable(p_nxge_t nxgep)
2516f45ec7bSml29623 {
2526f45ec7bSml29623 	uint8_t portn;
2536f45ec7bSml29623 	uint32_t config;
2546f45ec7bSml29623 	npi_handle_t handle;
2556f45ec7bSml29623 	uint32_t pkt_size;
2566f45ec7bSml29623 	npi_status_t rs = NPI_SUCCESS;
2576f45ec7bSml29623 
2586f45ec7bSml29623 	handle = nxgep->npi_handle;
2596f45ec7bSml29623 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
2606f45ec7bSml29623 
2616f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_enable: port%d", portn));
2626f45ec7bSml29623 
2636f45ec7bSml29623 	config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC |
2646f45ec7bSml29623 	    CFG_IPP_TCP_UDP_CKSUM;
2656f45ec7bSml29623 	if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS)
2666f45ec7bSml29623 		goto fail;
2676f45ec7bSml29623 	nxgep->ipp.config = config;
2686f45ec7bSml29623 
2696f45ec7bSml29623 	/* Set max packet size */
2706f45ec7bSml29623 	pkt_size = IPP_MAX_PKT_SIZE;
2716f45ec7bSml29623 	if ((rs = npi_ipp_set_max_pktsize(handle, portn,
2726f45ec7bSml29623 	    IPP_MAX_PKT_SIZE)) != NPI_SUCCESS)
2736f45ec7bSml29623 		goto fail;
2746f45ec7bSml29623 	nxgep->ipp.max_pkt_size = pkt_size;
2756f45ec7bSml29623 
2766f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_enable: port%d", portn));
2776f45ec7bSml29623 	return (NXGE_OK);
2786f45ec7bSml29623 fail:
2796f45ec7bSml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
2806f45ec7bSml29623 	    "nxge_ipp_init: Fail to Enable IPP Port #%d\n", portn));
2816f45ec7bSml29623 	return (NXGE_ERROR | rs);
2826f45ec7bSml29623 }
2836f45ec7bSml29623 
2846f45ec7bSml29623 /* ARGSUSED */
2856f45ec7bSml29623 nxge_status_t
nxge_ipp_drain(p_nxge_t nxgep)286*678453a8Sspeer nxge_ipp_drain(p_nxge_t nxgep)
287*678453a8Sspeer {
288*678453a8Sspeer 	uint8_t portn;
289*678453a8Sspeer 	npi_handle_t handle;
290*678453a8Sspeer 	npi_status_t rs = NPI_SUCCESS;
291*678453a8Sspeer 	uint16_t wr_ptr, rd_ptr;
292*678453a8Sspeer 	uint32_t try_count;
293*678453a8Sspeer 
294*678453a8Sspeer 	handle = nxgep->npi_handle;
295*678453a8Sspeer 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
296*678453a8Sspeer 
297*678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_drain: port%d", portn));
298*678453a8Sspeer 
299*678453a8Sspeer 	/*
300*678453a8Sspeer 	 * Wait until ip read and write fifo pointers are equal
301*678453a8Sspeer 	 */
302*678453a8Sspeer 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
303*678453a8Sspeer 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
304*678453a8Sspeer 	try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT;
305*678453a8Sspeer 
306*678453a8Sspeer 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
307*678453a8Sspeer 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
308*678453a8Sspeer 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
309*678453a8Sspeer 		try_count--;
310*678453a8Sspeer 	}
311*678453a8Sspeer 
312*678453a8Sspeer 	if (try_count == 0) {
313*678453a8Sspeer 		if ((rd_ptr != 0) && (wr_ptr != 1)) {
314*678453a8Sspeer 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
315*678453a8Sspeer 			    " nxge_ipp_drain: port%d failed"
316*678453a8Sspeer 			    " rd_fifo != wr_fifo", portn));
317*678453a8Sspeer 			goto fail;
318*678453a8Sspeer 		}
319*678453a8Sspeer 	}
320*678453a8Sspeer 
321*678453a8Sspeer 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_drain: port%d", portn));
322*678453a8Sspeer 	return (NXGE_OK);
323*678453a8Sspeer fail:
324*678453a8Sspeer 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_ipp_init: "
325*678453a8Sspeer 	    "Fail to Reset IPP Port #%d\n", portn));
326*678453a8Sspeer 	return (NXGE_ERROR | rs);
327*678453a8Sspeer }
328*678453a8Sspeer 
329*678453a8Sspeer /* ARGSUSED */
330*678453a8Sspeer nxge_status_t
nxge_ipp_handle_sys_errors(p_nxge_t nxgep)3316f45ec7bSml29623 nxge_ipp_handle_sys_errors(p_nxge_t nxgep)
3326f45ec7bSml29623 {
3336f45ec7bSml29623 	npi_handle_t handle;
3346f45ec7bSml29623 	npi_status_t rs = NPI_SUCCESS;
3356f45ec7bSml29623 	p_nxge_ipp_stats_t statsp;
3366f45ec7bSml29623 	ipp_status_t istatus;
3376f45ec7bSml29623 	uint8_t portn;
3386f45ec7bSml29623 	p_ipp_errlog_t errlogp;
3396f45ec7bSml29623 	boolean_t rxport_fatal = B_FALSE;
3406f45ec7bSml29623 	nxge_status_t status = NXGE_OK;
34153f3d8ecSyc148097 	uint8_t cnt8;
34253f3d8ecSyc148097 	uint16_t cnt16;
3436f45ec7bSml29623 
3446f45ec7bSml29623 	handle = nxgep->npi_handle;
3456f45ec7bSml29623 	statsp = (p_nxge_ipp_stats_t)&nxgep->statsp->ipp_stats;
3466f45ec7bSml29623 	portn = nxgep->mac.portnum;
3476f45ec7bSml29623 
3486f45ec7bSml29623 	errlogp = (p_ipp_errlog_t)&statsp->errlog;
3496f45ec7bSml29623 
3506f45ec7bSml29623 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
3516f45ec7bSml29623 		return (NXGE_ERROR | rs);
3526f45ec7bSml29623 
3536f45ec7bSml29623 	if (istatus.value == 0) {
3546f45ec7bSml29623 		/*
3556f45ec7bSml29623 		 * The error is not initiated from this port, so just exit.
3566f45ec7bSml29623 		 */
3576f45ec7bSml29623 		return (NXGE_OK);
3586f45ec7bSml29623 	}
3596f45ec7bSml29623 
3606f45ec7bSml29623 	if (istatus.bits.w0.dfifo_missed_sop) {
3616f45ec7bSml29623 		statsp->sop_miss++;
3626f45ec7bSml29623 		if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn,
3636f45ec7bSml29623 		    &errlogp->dfifo_rd_ptr)) != NPI_SUCCESS)
3646f45ec7bSml29623 			return (NXGE_ERROR | rs);
3656f45ec7bSml29623 		if ((rs = npi_ipp_get_state_mach(handle, portn,
3666f45ec7bSml29623 		    &errlogp->state_mach)) != NPI_SUCCESS)
3676f45ec7bSml29623 			return (NXGE_ERROR | rs);
3686f45ec7bSml29623 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
3696f45ec7bSml29623 		    NXGE_FM_EREPORT_IPP_SOP_MISS);
3706f45ec7bSml29623 		if (statsp->sop_miss < IPP_MAX_ERR_SHOW)
3716f45ec7bSml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3726f45ec7bSml29623 			    "nxge_ipp_err_evnts: fatal error: sop_miss\n"));
3736f45ec7bSml29623 		rxport_fatal = B_TRUE;
3746f45ec7bSml29623 	}
3756f45ec7bSml29623 	if (istatus.bits.w0.dfifo_missed_eop) {
3766f45ec7bSml29623 		statsp->eop_miss++;
3776f45ec7bSml29623 		if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn,
3786f45ec7bSml29623 		    &errlogp->dfifo_rd_ptr)) != NPI_SUCCESS)
3796f45ec7bSml29623 			return (NXGE_ERROR | rs);
3806f45ec7bSml29623 		if ((rs = npi_ipp_get_state_mach(handle, portn,
3816f45ec7bSml29623 		    &errlogp->state_mach)) != NPI_SUCCESS)
3826f45ec7bSml29623 			return (NXGE_ERROR | rs);
3836f45ec7bSml29623 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
3846f45ec7bSml29623 		    NXGE_FM_EREPORT_IPP_EOP_MISS);
3856f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
3866f45ec7bSml29623 		    "nxge_ipp_err_evnts: fatal error: eop_miss\n"));
3876f45ec7bSml29623 		rxport_fatal = B_TRUE;
3886f45ec7bSml29623 	}
3896f45ec7bSml29623 	if (istatus.bits.w0.dfifo_uncorr_ecc_err) {
3906f45ec7bSml29623 		boolean_t ue_ecc_valid;
3916f45ec7bSml29623 
3926f45ec7bSml29623 		if ((status = nxge_ipp_eccue_valid_check(nxgep,
3936f45ec7bSml29623 		    &ue_ecc_valid)) != NXGE_OK)
3946f45ec7bSml29623 			return (status);
3956f45ec7bSml29623 
3966f45ec7bSml29623 		if (ue_ecc_valid) {
3976f45ec7bSml29623 			statsp->dfifo_ue++;
3986f45ec7bSml29623 			if ((rs = npi_ipp_get_ecc_syndrome(handle, portn,
3996f45ec7bSml29623 			    &errlogp->ecc_syndrome)) != NPI_SUCCESS)
4006f45ec7bSml29623 				return (NXGE_ERROR | rs);
4016f45ec7bSml29623 			NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
4026f45ec7bSml29623 			    NXGE_FM_EREPORT_IPP_DFIFO_UE);
4036f45ec7bSml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4046f45ec7bSml29623 			    "nxge_ipp_err_evnts: fatal error: dfifo_ue\n"));
4056f45ec7bSml29623 			rxport_fatal = B_TRUE;
4066f45ec7bSml29623 		}
4076f45ec7bSml29623 	}
4086f45ec7bSml29623 	if (istatus.bits.w0.pre_fifo_perr) {
4096f45ec7bSml29623 		statsp->pfifo_perr++;
4106f45ec7bSml29623 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
4116f45ec7bSml29623 		    NXGE_FM_EREPORT_IPP_PFIFO_PERR);
4126f45ec7bSml29623 		if (statsp->pfifo_perr < IPP_MAX_ERR_SHOW)
4136f45ec7bSml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4146f45ec7bSml29623 			    "nxge_ipp_err_evnts: "
4156f45ec7bSml29623 			    "fatal error: pre_pifo_perr\n"));
4166f45ec7bSml29623 		rxport_fatal = B_TRUE;
4176f45ec7bSml29623 	}
4186f45ec7bSml29623 	if (istatus.bits.w0.pre_fifo_overrun) {
4196f45ec7bSml29623 		statsp->pfifo_over++;
4206f45ec7bSml29623 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
4216f45ec7bSml29623 		    NXGE_FM_EREPORT_IPP_PFIFO_OVER);
4226f45ec7bSml29623 		if (statsp->pfifo_over < IPP_MAX_ERR_SHOW)
4236f45ec7bSml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4246f45ec7bSml29623 			    "nxge_ipp_err_evnts: "
4256f45ec7bSml29623 			    "fatal error: pfifo_over\n"));
4266f45ec7bSml29623 		rxport_fatal = B_TRUE;
4276f45ec7bSml29623 	}
4286f45ec7bSml29623 	if (istatus.bits.w0.pre_fifo_underrun) {
4296f45ec7bSml29623 		statsp->pfifo_und++;
4306f45ec7bSml29623 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
4316f45ec7bSml29623 		    NXGE_FM_EREPORT_IPP_PFIFO_UND);
4326f45ec7bSml29623 		if (statsp->pfifo_und < IPP_MAX_ERR_SHOW)
4336f45ec7bSml29623 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4346f45ec7bSml29623 			    "nxge_ipp_err_evnts: "
4356f45ec7bSml29623 			    "fatal error: pfifo_und\n"));
4366f45ec7bSml29623 		rxport_fatal = B_TRUE;
4376f45ec7bSml29623 	}
4386f45ec7bSml29623 	if (istatus.bits.w0.bad_cksum_cnt_ovfl) {
439d710877aSyc148097 		/*
44063e23a19Syc148097 		 * Do not send FMA ereport or log error message
44163e23a19Syc148097 		 * in /var/adm/messages because this error does not
44263e23a19Syc148097 		 * indicate a HW failure.
44363e23a19Syc148097 		 *
444d710877aSyc148097 		 * Clear bit BAD_CS_MX of register IPP_INT_STAT
445d710877aSyc148097 		 * by reading register IPP_BAD_CS_CNT
446d710877aSyc148097 		 */
44753f3d8ecSyc148097 		(void) npi_ipp_get_cs_err_count(handle, portn, &cnt16);
4486f45ec7bSml29623 		statsp->bad_cs_cnt += IPP_BAD_CS_CNT_MASK;
4496f45ec7bSml29623 	}
4506f45ec7bSml29623 	if (istatus.bits.w0.pkt_discard_cnt_ovfl) {
451d710877aSyc148097 		/*
45263e23a19Syc148097 		 * Do not send FMA ereport or log error message
45363e23a19Syc148097 		 * in /var/adm/messages because this error does not
45463e23a19Syc148097 		 * indicate a HW failure.
45563e23a19Syc148097 		 *
456d710877aSyc148097 		 * Clear bit PKT_DIS_MX of register IPP_INT_STAT
457d710877aSyc148097 		 * by reading register IPP_PKT_DIS
458d710877aSyc148097 		 */
45953f3d8ecSyc148097 		(void) npi_ipp_get_pkt_dis_count(handle, portn, &cnt16);
4606f45ec7bSml29623 		statsp->pkt_dis_cnt += IPP_PKT_DIS_CNT_MASK;
4616f45ec7bSml29623 	}
46253f3d8ecSyc148097 	if (istatus.bits.w0.ecc_err_cnt_ovfl) {
463d710877aSyc148097 		/*
464d710877aSyc148097 		 * Clear bit ECC_ERR_MAX of register IPP_INI_STAT
465d710877aSyc148097 		 * by reading register IPP_ECC
466d710877aSyc148097 		 */
46753f3d8ecSyc148097 		(void) npi_ipp_get_ecc_err_count(handle, portn, &cnt8);
46853f3d8ecSyc148097 		statsp->ecc_err_cnt += IPP_ECC_CNT_MASK;
469f6485eecSyc148097 		/*
470f6485eecSyc148097 		 * A defect in Neptune port2's IPP module could generate
471f6485eecSyc148097 		 * many fake but harmless ECC errors under stress and cause
472f6485eecSyc148097 		 * the ecc-error-counter register IPP_ECC to reach its
473f6485eecSyc148097 		 * maximum value in a few seconds. To avoid false alarm, do
474f6485eecSyc148097 		 * not report the error if it is port2.
475f6485eecSyc148097 		 */
476f6485eecSyc148097 		if (portn != 2) {
47753f3d8ecSyc148097 			NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
47853f3d8ecSyc148097 			    NXGE_FM_EREPORT_IPP_ECC_ERR_MAX);
47953f3d8ecSyc148097 			if (statsp->ecc_err_cnt < (IPP_MAX_ERR_SHOW *
480f6485eecSyc148097 			    IPP_ECC_CNT_MASK)) {
48153f3d8ecSyc148097 				NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
48253f3d8ecSyc148097 				    "nxge_ipp_err_evnts: pkt_ecc_err_max\n"));
48353f3d8ecSyc148097 			}
484f6485eecSyc148097 		}
485f6485eecSyc148097 	}
4866f45ec7bSml29623 	/*
4876f45ec7bSml29623 	 * Making sure that error source is cleared if this is an injected
4886f45ec7bSml29623 	 * error.
4896f45ec7bSml29623 	 */
4906f45ec7bSml29623 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
4916f45ec7bSml29623 
4926f45ec7bSml29623 	if (rxport_fatal) {
4936f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, IPP_CTL,
4946f45ec7bSml29623 		    " nxge_ipp_handle_sys_errors:"
4956f45ec7bSml29623 		    " fatal Error on  Port #%d\n", portn));
4966f45ec7bSml29623 		status = nxge_ipp_fatal_err_recover(nxgep);
4976f45ec7bSml29623 		if (status == NXGE_OK) {
4986f45ec7bSml29623 			FM_SERVICE_RESTORED(nxgep);
4996f45ec7bSml29623 		}
5006f45ec7bSml29623 	}
5016f45ec7bSml29623 	return (status);
5026f45ec7bSml29623 }
5036f45ec7bSml29623 
5046f45ec7bSml29623 /* ARGSUSED */
5056f45ec7bSml29623 void
nxge_ipp_inject_err(p_nxge_t nxgep,uint32_t err_id)5066f45ec7bSml29623 nxge_ipp_inject_err(p_nxge_t nxgep, uint32_t err_id)
5076f45ec7bSml29623 {
5086f45ec7bSml29623 	ipp_status_t ipps;
5096f45ec7bSml29623 	ipp_ecc_ctrl_t ecc_ctrl;
5106f45ec7bSml29623 	uint8_t portn = nxgep->mac.portnum;
5116f45ec7bSml29623 
5126f45ec7bSml29623 	switch (err_id) {
5136f45ec7bSml29623 	case NXGE_FM_EREPORT_IPP_DFIFO_UE:
5146f45ec7bSml29623 		ecc_ctrl.value = 0;
5156f45ec7bSml29623 		ecc_ctrl.bits.w0.cor_dbl = 1;
5166f45ec7bSml29623 		ecc_ctrl.bits.w0.cor_1 = 1;
5176f45ec7bSml29623 		ecc_ctrl.bits.w0.cor_lst = 1;
5186f45ec7bSml29623 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n",
5196f45ec7bSml29623 		    (unsigned long long) ecc_ctrl.value);
5206f45ec7bSml29623 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG,
5216f45ec7bSml29623 		    ecc_ctrl.value);
5226f45ec7bSml29623 		break;
5236f45ec7bSml29623 
5246f45ec7bSml29623 	case NXGE_FM_EREPORT_IPP_DFIFO_CE:
5256f45ec7bSml29623 		ecc_ctrl.value = 0;
5266f45ec7bSml29623 		ecc_ctrl.bits.w0.cor_sng = 1;
5276f45ec7bSml29623 		ecc_ctrl.bits.w0.cor_1 = 1;
5286f45ec7bSml29623 		ecc_ctrl.bits.w0.cor_snd = 1;
5296f45ec7bSml29623 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n",
5306f45ec7bSml29623 		    (unsigned long long) ecc_ctrl.value);
5316f45ec7bSml29623 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG,
5326f45ec7bSml29623 		    ecc_ctrl.value);
5336f45ec7bSml29623 		break;
5346f45ec7bSml29623 
5356f45ec7bSml29623 	case NXGE_FM_EREPORT_IPP_EOP_MISS:
5366f45ec7bSml29623 	case NXGE_FM_EREPORT_IPP_SOP_MISS:
5376f45ec7bSml29623 	case NXGE_FM_EREPORT_IPP_PFIFO_PERR:
5386f45ec7bSml29623 	case NXGE_FM_EREPORT_IPP_ECC_ERR_MAX:
5396f45ec7bSml29623 	case NXGE_FM_EREPORT_IPP_PFIFO_OVER:
5406f45ec7bSml29623 	case NXGE_FM_EREPORT_IPP_PFIFO_UND:
5416f45ec7bSml29623 	case NXGE_FM_EREPORT_IPP_BAD_CS_MX:
5426f45ec7bSml29623 	case NXGE_FM_EREPORT_IPP_PKT_DIS_MX:
5436f45ec7bSml29623 	case NXGE_FM_EREPORT_IPP_RESET_FAIL:
5446f45ec7bSml29623 		IPP_REG_RD(nxgep->npi_handle, portn, IPP_INT_STATUS_REG,
5456f45ec7bSml29623 		    &ipps.value);
5466f45ec7bSml29623 		if (err_id == NXGE_FM_EREPORT_IPP_EOP_MISS)
5476f45ec7bSml29623 			ipps.bits.w0.dfifo_missed_eop = 1;
5486f45ec7bSml29623 		else if (err_id == NXGE_FM_EREPORT_IPP_SOP_MISS)
5496f45ec7bSml29623 			ipps.bits.w0.dfifo_missed_sop = 1;
5506f45ec7bSml29623 		else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_UE)
5516f45ec7bSml29623 			ipps.bits.w0.dfifo_uncorr_ecc_err = 1;
5526f45ec7bSml29623 		else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_CE)
5536f45ec7bSml29623 			ipps.bits.w0.dfifo_corr_ecc_err = 1;
5546f45ec7bSml29623 		else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_PERR)
5556f45ec7bSml29623 			ipps.bits.w0.pre_fifo_perr = 1;
556d710877aSyc148097 		else if (err_id == NXGE_FM_EREPORT_IPP_ECC_ERR_MAX) {
557d710877aSyc148097 			/*
558d710877aSyc148097 			 * Fill register IPP_ECC with max ECC-error-
559d710877aSyc148097 			 * counter value (0xff) to set the ECC_ERR_MAX bit
560d710877aSyc148097 			 * of the IPP_INT_STAT register and trigger an
561d710877aSyc148097 			 * FMA ereport.
562d710877aSyc148097 			 */
563d710877aSyc148097 			IPP_REG_WR(nxgep->npi_handle, portn,
564d710877aSyc148097 			    IPP_ECC_ERR_COUNTER_REG, IPP_ECC_CNT_MASK);
565d710877aSyc148097 		} else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_OVER)
5666f45ec7bSml29623 			ipps.bits.w0.pre_fifo_overrun = 1;
5676f45ec7bSml29623 		else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_UND)
5686f45ec7bSml29623 			ipps.bits.w0.pre_fifo_underrun = 1;
569d710877aSyc148097 		else if (err_id == NXGE_FM_EREPORT_IPP_BAD_CS_MX) {
570d710877aSyc148097 			/*
571d710877aSyc148097 			 * Fill IPP_BAD_CS_CNT with max bad-checksum-counter
572d710877aSyc148097 			 * value (0x3fff) to set the BAD_CS_MX bit of
573d710877aSyc148097 			 * IPP_INT_STAT and trigger an FMA ereport.
574d710877aSyc148097 			 */
575d710877aSyc148097 			IPP_REG_WR(nxgep->npi_handle, portn,
576f6485eecSyc148097 			    IPP_BAD_CKSUM_ERR_CNT_REG, IPP_BAD_CS_CNT_MASK);
577d710877aSyc148097 		} else if (err_id == NXGE_FM_EREPORT_IPP_PKT_DIS_MX) {
578d710877aSyc148097 			/*
579d710877aSyc148097 			 * Fill IPP_PKT_DIS with max packet-discard-counter
580d710877aSyc148097 			 * value (0x3fff) to set the PKT_DIS_MX bit of
581d710877aSyc148097 			 * IPP_INT_STAT and trigger an FMA ereport.
582d710877aSyc148097 			 */
583d710877aSyc148097 			IPP_REG_WR(nxgep->npi_handle, portn,
584d710877aSyc148097 			    IPP_DISCARD_PKT_CNT_REG, IPP_PKT_DIS_CNT_MASK);
585d710877aSyc148097 		}
5866f45ec7bSml29623 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_INT_STATUS_REG\n",
5876f45ec7bSml29623 		    (unsigned long long) ipps.value);
5886f45ec7bSml29623 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_INT_STATUS_REG,
5896f45ec7bSml29623 		    ipps.value);
5906f45ec7bSml29623 		break;
5916f45ec7bSml29623 	}
5926f45ec7bSml29623 }
5936f45ec7bSml29623 
5946f45ec7bSml29623 /* ARGSUSED */
5956f45ec7bSml29623 nxge_status_t
nxge_ipp_fatal_err_recover(p_nxge_t nxgep)5966f45ec7bSml29623 nxge_ipp_fatal_err_recover(p_nxge_t nxgep)
5976f45ec7bSml29623 {
5986f45ec7bSml29623 	npi_handle_t handle;
5996f45ec7bSml29623 	npi_status_t rs = NPI_SUCCESS;
6006f45ec7bSml29623 	nxge_status_t status = NXGE_OK;
6016f45ec7bSml29623 	uint8_t portn;
6026f45ec7bSml29623 	uint16_t wr_ptr;
6036f45ec7bSml29623 	uint16_t rd_ptr;
6046f45ec7bSml29623 	uint32_t try_count;
6056f45ec7bSml29623 	uint32_t dfifo_entries;
6066f45ec7bSml29623 	ipp_status_t istatus;
6076f45ec7bSml29623 	uint32_t d0, d1, d2, d3, d4;
6086f45ec7bSml29623 	int i;
6096f45ec7bSml29623 
6106f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, RX_CTL, "<== nxge_ipp_fatal_err_recover"));
6116f45ec7bSml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
6126f45ec7bSml29623 	    "Recovering from RxPort error..."));
6136f45ec7bSml29623 
6146f45ec7bSml29623 	handle = nxgep->npi_handle;
6156f45ec7bSml29623 	portn = nxgep->mac.portnum;
6166f45ec7bSml29623 
6176f45ec7bSml29623 	/*
6186f45ec7bSml29623 	 * Making sure that error source is cleared if this is an injected
6196f45ec7bSml29623 	 * error.
6206f45ec7bSml29623 	 */
6216f45ec7bSml29623 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
6226f45ec7bSml29623 
6236f45ec7bSml29623 	/* Disable RxMAC */
6246f45ec7bSml29623 	if (nxge_rx_mac_disable(nxgep) != NXGE_OK)
6256f45ec7bSml29623 		goto fail;
6266f45ec7bSml29623 
6276f45ec7bSml29623 	/* When recovering from IPP, RxDMA channel resets are not necessary */
6286f45ec7bSml29623 	/* Reset ZCP CFIFO */
6296f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset ZCP CFIFO...", portn));
6306f45ec7bSml29623 	if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS)
6316f45ec7bSml29623 		goto fail;
6326f45ec7bSml29623 
6336f45ec7bSml29623 	/*
6346f45ec7bSml29623 	 * Wait until ip read and write fifo pointers are equal
6356f45ec7bSml29623 	 */
6366f45ec7bSml29623 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
6376f45ec7bSml29623 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
6386f45ec7bSml29623 	try_count = 512;
6396f45ec7bSml29623 
6406f45ec7bSml29623 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
6416f45ec7bSml29623 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
6426f45ec7bSml29623 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
6436f45ec7bSml29623 		try_count--;
6446f45ec7bSml29623 	}
6456f45ec7bSml29623 
6466f45ec7bSml29623 	if (try_count == 0) {
6476f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
6486f45ec7bSml29623 		    " nxge_ipp_reset: port%d IPP stalled..."
6496f45ec7bSml29623 		    " rd_fifo_ptr = 0x%x wr_fifo_ptr = 0x%x",
6506f45ec7bSml29623 		    portn, rd_ptr, wr_ptr));
6516f45ec7bSml29623 		/*
6526f45ec7bSml29623 		 * This means the fatal error occurred on the first line of the
6536f45ec7bSml29623 		 * fifo. In this case, just reset the IPP without draining the
6546f45ec7bSml29623 		 * PFIFO.
6556f45ec7bSml29623 		 */
6566f45ec7bSml29623 	}
6576f45ec7bSml29623 
65859ac0c16Sdavemq 	if (nxgep->niu_type == N2_NIU) {
65959ac0c16Sdavemq 		dfifo_entries = IPP_NIU_DFIFO_ENTRIES;
6602e59129aSraghus 	} else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
6616f45ec7bSml29623 		if (portn < 2)
6626f45ec7bSml29623 			dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES;
6636f45ec7bSml29623 		else
6646f45ec7bSml29623 			dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES;
66559ac0c16Sdavemq 	} else {
6666f45ec7bSml29623 		goto fail;
66759ac0c16Sdavemq 	}
6686f45ec7bSml29623 
6696f45ec7bSml29623 	/* Clean up DFIFO SRAM entries */
6706f45ec7bSml29623 	for (i = 0; i < dfifo_entries; i++) {
6716f45ec7bSml29623 		if ((rs = npi_ipp_write_dfifo(handle, portn,
6726f45ec7bSml29623 		    i, 0, 0, 0, 0, 0)) != NPI_SUCCESS)
6736f45ec7bSml29623 			goto fail;
6746f45ec7bSml29623 		if ((rs = npi_ipp_read_dfifo(handle, portn, i,
6756f45ec7bSml29623 		    &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
6766f45ec7bSml29623 			goto fail;
6776f45ec7bSml29623 	}
6786f45ec7bSml29623 
6796f45ec7bSml29623 	/* Clear PFIFO DFIFO status bits */
6806f45ec7bSml29623 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
6816f45ec7bSml29623 		goto fail;
6826f45ec7bSml29623 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
6836f45ec7bSml29623 		goto fail;
6846f45ec7bSml29623 
6856f45ec7bSml29623 	/* Reset IPP */
6866f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset IPP...", portn));
6876f45ec7bSml29623 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
6886f45ec7bSml29623 		goto fail;
6896f45ec7bSml29623 
6906f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset RxMAC...", portn));
6916f45ec7bSml29623 	if (nxge_rx_mac_reset(nxgep) != NXGE_OK)
6926f45ec7bSml29623 		goto fail;
6936f45ec7bSml29623 
6946f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Initialize RxMAC...", portn));
6956f45ec7bSml29623 	if ((status = nxge_rx_mac_init(nxgep)) != NXGE_OK)
6966f45ec7bSml29623 		goto fail;
6976f45ec7bSml29623 
6986f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Enable RxMAC...", portn));
6996f45ec7bSml29623 	if (nxge_rx_mac_enable(nxgep) != NXGE_OK)
7006f45ec7bSml29623 		goto fail;
7016f45ec7bSml29623 
7026f45ec7bSml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
703d710877aSyc148097 	    "Recovery successful, RxPort restored"));
7046f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, RX_CTL, "==> nxge_ipp_fatal_err_recover"));
7056f45ec7bSml29623 
7066f45ec7bSml29623 	return (NXGE_OK);
7076f45ec7bSml29623 fail:
7086f45ec7bSml29623 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
7096f45ec7bSml29623 	return (status | rs);
7106f45ec7bSml29623 }
7116f45ec7bSml29623 
7126f45ec7bSml29623 /* ARGSUSED */
7131a4557b6Syc148097 /*
71453f3d8ecSyc148097  *    A hardware bug may cause fake ECCUEs (ECC Uncorrectable Error).
7151a4557b6Syc148097  * This function checks if a ECCUE is real(valid) or not.  It is not
7161a4557b6Syc148097  * real if rd_ptr == wr_ptr.
7171a4557b6Syc148097  *    The hardware module that has the bug is used not only by the IPP
7181a4557b6Syc148097  * FIFO but also by the ZCP FIFO, therefore this function is also
7191a4557b6Syc148097  * called by nxge_zcp_handle_sys_errors for validating the ZCP FIFO
7201a4557b6Syc148097  * error.
7211a4557b6Syc148097  */
7226f45ec7bSml29623 nxge_status_t
nxge_ipp_eccue_valid_check(p_nxge_t nxgep,boolean_t * valid)7236f45ec7bSml29623 nxge_ipp_eccue_valid_check(p_nxge_t nxgep, boolean_t *valid)
7246f45ec7bSml29623 {
7256f45ec7bSml29623 	npi_handle_t handle;
7266f45ec7bSml29623 	npi_status_t rs = NPI_SUCCESS;
7276f45ec7bSml29623 	uint8_t portn;
7286f45ec7bSml29623 	uint16_t rd_ptr;
7296f45ec7bSml29623 	uint16_t wr_ptr;
7306f45ec7bSml29623 	uint16_t curr_rd_ptr;
7316f45ec7bSml29623 	uint16_t curr_wr_ptr;
7326f45ec7bSml29623 	uint32_t stall_cnt;
7336f45ec7bSml29623 	uint32_t d0, d1, d2, d3, d4;
7346f45ec7bSml29623 
7356f45ec7bSml29623 	handle = nxgep->npi_handle;
7366f45ec7bSml29623 	portn = nxgep->mac.portnum;
7376f45ec7bSml29623 	*valid = B_TRUE;
7386f45ec7bSml29623 
7396f45ec7bSml29623 	if ((rs = npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr))
7406f45ec7bSml29623 	    != NPI_SUCCESS)
7416f45ec7bSml29623 		goto fail;
7421a4557b6Syc148097 	if ((rs = npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr))
7436f45ec7bSml29623 	    != NPI_SUCCESS)
7446f45ec7bSml29623 		goto fail;
7456f45ec7bSml29623 
7466f45ec7bSml29623 	if (rd_ptr == wr_ptr) {
7471a4557b6Syc148097 		*valid = B_FALSE; /* FIFO not stuck, so it's not a real ECCUE */
7486f45ec7bSml29623 	} else {
7496f45ec7bSml29623 		stall_cnt = 0;
750ee5416c9Syc148097 		/*
751ee5416c9Syc148097 		 * Check if the two pointers are moving, the ECCUE is invali
752ee5416c9Syc148097 		 * if either pointer is moving, which indicates that the FIFO
753ee5416c9Syc148097 		 * is functional.
754ee5416c9Syc148097 		 */
7556f45ec7bSml29623 		while (stall_cnt < 16) {
7566f45ec7bSml29623 			if ((rs = npi_ipp_get_dfifo_rd_ptr(handle,
7576f45ec7bSml29623 			    portn, &curr_rd_ptr)) != NPI_SUCCESS)
7586f45ec7bSml29623 				goto fail;
7596f45ec7bSml29623 			if ((rs = npi_ipp_get_dfifo_wr_ptr(handle,
7606f45ec7bSml29623 			    portn, &curr_wr_ptr)) != NPI_SUCCESS)
7616f45ec7bSml29623 				goto fail;
7626f45ec7bSml29623 
763ee5416c9Syc148097 			if (rd_ptr == curr_rd_ptr && wr_ptr == curr_wr_ptr) {
7646f45ec7bSml29623 				stall_cnt++;
765ee5416c9Syc148097 			} else {
7666f45ec7bSml29623 				*valid = B_FALSE;
7676f45ec7bSml29623 				break;
7686f45ec7bSml29623 			}
7696f45ec7bSml29623 		}
7706f45ec7bSml29623 
7716f45ec7bSml29623 		if (valid) {
772ee5416c9Syc148097 			/*
773d710877aSyc148097 			 * Further check to see if the ECCUE is valid. The
774ee5416c9Syc148097 			 * error is real if the LSB of d4 is 1, which
775ee5416c9Syc148097 			 * indicates that the data that has set the ECC
776ee5416c9Syc148097 			 * error flag is the 16-byte internal control word.
777ee5416c9Syc148097 			 */
778ee5416c9Syc148097 			if ((rs = npi_ipp_read_dfifo(handle, portn, rd_ptr,
779ee5416c9Syc148097 			    &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
7806f45ec7bSml29623 				goto fail;
7816f45ec7bSml29623 			if ((d4 & 0x1) == 0)	/* Not the 1st line */
7826f45ec7bSml29623 				*valid = B_FALSE;
7836f45ec7bSml29623 		}
7846f45ec7bSml29623 	}
7856f45ec7bSml29623 	return (NXGE_OK);
7866f45ec7bSml29623 fail:
7876f45ec7bSml29623 	return (NXGE_ERROR | rs);
7886f45ec7bSml29623 }
789