xref: /illumos-gate/usr/src/uts/common/io/nxge/nxge_ipp.c (revision f6485eec)
144961713Sgirish /*
244961713Sgirish  * CDDL HEADER START
344961713Sgirish  *
444961713Sgirish  * The contents of this file are subject to the terms of the
544961713Sgirish  * Common Development and Distribution License (the "License").
644961713Sgirish  * You may not use this file except in compliance with the License.
744961713Sgirish  *
844961713Sgirish  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
944961713Sgirish  * or http://www.opensolaris.org/os/licensing.
1044961713Sgirish  * See the License for the specific language governing permissions
1144961713Sgirish  * and limitations under the License.
1244961713Sgirish  *
1344961713Sgirish  * When distributing Covered Code, include this CDDL HEADER in each
1444961713Sgirish  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
1544961713Sgirish  * If applicable, add the following below this CDDL HEADER, with the
1644961713Sgirish  * fields enclosed by brackets "[]" replaced with your own identifying
1744961713Sgirish  * information: Portions Copyright [yyyy] [name of copyright owner]
1844961713Sgirish  *
1944961713Sgirish  * CDDL HEADER END
2044961713Sgirish  */
2144961713Sgirish /*
22a3c5bd6dSspeer  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
2344961713Sgirish  * Use is subject to license terms.
2444961713Sgirish  */
2544961713Sgirish 
2644961713Sgirish #pragma ident	"%Z%%M%	%I%	%E% SMI"
2744961713Sgirish 
2844961713Sgirish #include <nxge_impl.h>
2944961713Sgirish #include <nxge_ipp.h>
3044961713Sgirish 
3114ea4bb7Ssd #define	NXGE_IPP_FIFO_SYNC_TRY_COUNT 100
3214ea4bb7Ssd 
33a3c5bd6dSspeer /* ARGSUSED */
3444961713Sgirish nxge_status_t
3544961713Sgirish nxge_ipp_init(p_nxge_t nxgep)
3644961713Sgirish {
37a3c5bd6dSspeer 	uint8_t portn;
38a3c5bd6dSspeer 	uint32_t config;
39a3c5bd6dSspeer 	npi_handle_t handle;
40a3c5bd6dSspeer 	uint32_t pkt_size;
41a3c5bd6dSspeer 	ipp_status_t istatus;
42a3c5bd6dSspeer 	npi_status_t rs = NPI_SUCCESS;
43a3c5bd6dSspeer 	uint64_t val;
44a3c5bd6dSspeer 	uint32_t d0, d1, d2, d3, d4;
45a3c5bd6dSspeer 	int i;
46a3c5bd6dSspeer 	uint32_t dfifo_entries;
4744961713Sgirish 
4844961713Sgirish 	handle = nxgep->npi_handle;
4944961713Sgirish 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
5044961713Sgirish 
5144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_init: port%d", portn));
5244961713Sgirish 
5344961713Sgirish 	/* 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)) {
5744961713Sgirish 		if (portn < 2)
5844961713Sgirish 			dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES;
5944961713Sgirish 		else
6044961713Sgirish 			dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES;
6159ac0c16Sdavemq 	} else {
6244961713Sgirish 		goto fail;
6359ac0c16Sdavemq 	}
6444961713Sgirish 
6544961713Sgirish 	for (i = 0; i < dfifo_entries; i++) {
66a3c5bd6dSspeer 		if ((rs = npi_ipp_write_dfifo(handle,
67a3c5bd6dSspeer 				portn, i, 0, 0, 0, 0, 0)) != NPI_SUCCESS)
6844961713Sgirish 			goto fail;
69a3c5bd6dSspeer 		if ((rs = npi_ipp_read_dfifo(handle, portn,
70a3c5bd6dSspeer 				i, &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
7144961713Sgirish 			goto fail;
7244961713Sgirish 	}
7344961713Sgirish 
7444961713Sgirish 	/* Clear PFIFO DFIFO status bits */
7544961713Sgirish 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
7644961713Sgirish 		goto fail;
7744961713Sgirish 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
7844961713Sgirish 		goto fail;
7944961713Sgirish 
8044961713Sgirish 	/*
8144961713Sgirish 	 * Soft reset to make sure we bring the FIFO pointers back to the
8244961713Sgirish 	 * original initial position.
8344961713Sgirish 	 */
8444961713Sgirish 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
8544961713Sgirish 		goto fail;
8644961713Sgirish 
8744961713Sgirish 	/* Clean up ECC counter */
8844961713Sgirish 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_ECC_ERR_COUNTER_REG, &val);
89*f6485eecSyc 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_BAD_CKSUM_ERR_CNT_REG, &val);
9044961713Sgirish 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_DISCARD_PKT_CNT_REG, &val);
9144961713Sgirish 
9244961713Sgirish 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
9344961713Sgirish 		goto fail;
9444961713Sgirish 
9544961713Sgirish 	/* Configure IPP port */
9644961713Sgirish 	if ((rs = npi_ipp_iconfig(handle, INIT, portn, ICFG_IPP_ALL))
97a3c5bd6dSspeer 			!= NPI_SUCCESS)
9844961713Sgirish 		goto fail;
9944961713Sgirish 	nxgep->ipp.iconfig = ICFG_IPP_ALL;
10044961713Sgirish 
10144961713Sgirish 	config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC |
102a3c5bd6dSspeer 		CFG_IPP_TCP_UDP_CKSUM;
10344961713Sgirish 	if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS)
10444961713Sgirish 		goto fail;
10544961713Sgirish 	nxgep->ipp.config = config;
10644961713Sgirish 
10744961713Sgirish 	/* Set max packet size */
10844961713Sgirish 	pkt_size = IPP_MAX_PKT_SIZE;
109a3c5bd6dSspeer 	if ((rs = npi_ipp_set_max_pktsize(handle, portn,
110a3c5bd6dSspeer 			IPP_MAX_PKT_SIZE)) != NPI_SUCCESS)
11144961713Sgirish 		goto fail;
11244961713Sgirish 	nxgep->ipp.max_pkt_size = pkt_size;
11344961713Sgirish 
11444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_init: port%d", portn));
11544961713Sgirish 
11644961713Sgirish 	return (NXGE_OK);
11744961713Sgirish fail:
11844961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
11944961713Sgirish 			"nxge_ipp_init: Fail to initialize IPP Port #%d\n",
12044961713Sgirish 			portn));
12144961713Sgirish 	return (NXGE_ERROR | rs);
12244961713Sgirish }
12344961713Sgirish 
124a3c5bd6dSspeer /* ARGSUSED */
12544961713Sgirish nxge_status_t
12644961713Sgirish nxge_ipp_disable(p_nxge_t nxgep)
12744961713Sgirish {
128a3c5bd6dSspeer 	uint8_t portn;
129a3c5bd6dSspeer 	uint32_t config;
130a3c5bd6dSspeer 	npi_handle_t handle;
131a3c5bd6dSspeer 	npi_status_t rs = NPI_SUCCESS;
13214ea4bb7Ssd 	uint16_t wr_ptr, rd_ptr;
13314ea4bb7Ssd 	uint32_t try_count;
13444961713Sgirish 
13544961713Sgirish 	handle = nxgep->npi_handle;
13644961713Sgirish 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
13744961713Sgirish 
13844961713Sgirish 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_disable: port%d", portn));
13914ea4bb7Ssd 	(void) nxge_rx_mac_disable(nxgep);
14014ea4bb7Ssd 
14114ea4bb7Ssd 	/*
142a3c5bd6dSspeer 	 * Wait until ip read and write fifo pointers are equal
14314ea4bb7Ssd 	 */
14414ea4bb7Ssd 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
14514ea4bb7Ssd 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
14614ea4bb7Ssd 	try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT;
14714ea4bb7Ssd 
14814ea4bb7Ssd 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
14914ea4bb7Ssd 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
15014ea4bb7Ssd 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
15114ea4bb7Ssd 		try_count--;
15214ea4bb7Ssd 	}
15314ea4bb7Ssd 
15414ea4bb7Ssd 	if (try_count == 0) {
15514ea4bb7Ssd 		if ((rd_ptr != 0) && (wr_ptr != 1)) {
15614ea4bb7Ssd 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
157a3c5bd6dSspeer 				" nxge_ipp_disable: port%d failed"
158a3c5bd6dSspeer 				" rd_fifo != wr_fifo", portn));
15914ea4bb7Ssd 			goto fail;
16014ea4bb7Ssd 		}
16114ea4bb7Ssd 	}
16244961713Sgirish 	/* disable the IPP */
16344961713Sgirish 	config = nxgep->ipp.config;
164a3c5bd6dSspeer 	if ((rs = npi_ipp_config(handle, DISABLE,
165a3c5bd6dSspeer 			portn, config)) != NPI_SUCCESS)
16644961713Sgirish 		goto fail;
16744961713Sgirish 
16844961713Sgirish 	/* IPP soft reset */
169a3c5bd6dSspeer 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
17044961713Sgirish 		goto fail;
17144961713Sgirish 
17244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_disable: port%d", portn));
17344961713Sgirish 	return (NXGE_OK);
17444961713Sgirish fail:
17544961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
176a3c5bd6dSspeer 		"nxge_ipp_disable: Fail to disable IPP Port #%d\n", portn));
17744961713Sgirish 	return (NXGE_ERROR | rs);
17844961713Sgirish }
17944961713Sgirish 
180a3c5bd6dSspeer /* ARGSUSED */
18144961713Sgirish nxge_status_t
18244961713Sgirish nxge_ipp_reset(p_nxge_t nxgep)
18344961713Sgirish {
184a3c5bd6dSspeer 	uint8_t portn;
185a3c5bd6dSspeer 	uint32_t config;
186a3c5bd6dSspeer 	npi_handle_t handle;
187a3c5bd6dSspeer 	npi_status_t rs = NPI_SUCCESS;
18844961713Sgirish 	uint16_t wr_ptr, rd_ptr;
18944961713Sgirish 	uint32_t try_count;
190a3c5bd6dSspeer 
19144961713Sgirish 	handle = nxgep->npi_handle;
19244961713Sgirish 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
19344961713Sgirish 
19444961713Sgirish 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_reset: port%d", portn));
19544961713Sgirish 
19644961713Sgirish 	/* disable the IPP */
19744961713Sgirish 	config = nxgep->ipp.config;
198a3c5bd6dSspeer 	if ((rs = npi_ipp_config(handle, DISABLE,
199a3c5bd6dSspeer 			portn, config)) != NPI_SUCCESS)
20044961713Sgirish 		goto fail;
20144961713Sgirish 
20244961713Sgirish 	/*
203a3c5bd6dSspeer 	 * Wait until ip read and write fifo pointers are equal
20444961713Sgirish 	 */
20544961713Sgirish 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
20644961713Sgirish 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
20714ea4bb7Ssd 	try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT;
20844961713Sgirish 
20944961713Sgirish 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
21044961713Sgirish 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
21144961713Sgirish 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
21244961713Sgirish 		try_count--;
21344961713Sgirish 	}
21444961713Sgirish 
21544961713Sgirish 	if (try_count == 0) {
21614ea4bb7Ssd 		if ((rd_ptr != 0) && (wr_ptr != 1)) {
21714ea4bb7Ssd 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
218a3c5bd6dSspeer 				" nxge_ipp_disable: port%d failed"
219a3c5bd6dSspeer 				" rd_fifo != wr_fifo", portn));
22014ea4bb7Ssd 			goto fail;
22114ea4bb7Ssd 		}
22244961713Sgirish 	}
22344961713Sgirish 
22444961713Sgirish 	/* IPP soft reset */
22544961713Sgirish 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS) {
22644961713Sgirish 		goto fail;
22744961713Sgirish 	}
22844961713Sgirish 
22944961713Sgirish 	/* to reset control FIFO */
230a3c5bd6dSspeer 	if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS)
23144961713Sgirish 		goto fail;
23244961713Sgirish 
23344961713Sgirish 	/*
234a3c5bd6dSspeer 	 * Making sure that error source is cleared if this is an injected
235a3c5bd6dSspeer 	 * error.
23644961713Sgirish 	 */
23744961713Sgirish 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
23844961713Sgirish 
23944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_reset: port%d", portn));
24044961713Sgirish 	return (NXGE_OK);
24144961713Sgirish fail:
24244961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
24344961713Sgirish 			"nxge_ipp_init: Fail to Reset IPP Port #%d\n",
24444961713Sgirish 			portn));
24544961713Sgirish 	return (NXGE_ERROR | rs);
24644961713Sgirish }
24744961713Sgirish 
248a3c5bd6dSspeer /* ARGSUSED */
24944961713Sgirish nxge_status_t
25044961713Sgirish nxge_ipp_enable(p_nxge_t nxgep)
25144961713Sgirish {
252a3c5bd6dSspeer 	uint8_t portn;
253a3c5bd6dSspeer 	uint32_t config;
254a3c5bd6dSspeer 	npi_handle_t handle;
255a3c5bd6dSspeer 	uint32_t pkt_size;
256a3c5bd6dSspeer 	npi_status_t rs = NPI_SUCCESS;
25744961713Sgirish 
25844961713Sgirish 	handle = nxgep->npi_handle;
25944961713Sgirish 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
26044961713Sgirish 
26144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_enable: port%d", portn));
26244961713Sgirish 
26344961713Sgirish 	config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC |
264a3c5bd6dSspeer 		CFG_IPP_TCP_UDP_CKSUM;
26544961713Sgirish 	if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS)
26644961713Sgirish 		goto fail;
26744961713Sgirish 	nxgep->ipp.config = config;
26844961713Sgirish 
26944961713Sgirish 	/* Set max packet size */
27044961713Sgirish 	pkt_size = IPP_MAX_PKT_SIZE;
271a3c5bd6dSspeer 	if ((rs = npi_ipp_set_max_pktsize(handle, portn,
272a3c5bd6dSspeer 			IPP_MAX_PKT_SIZE)) != NPI_SUCCESS)
27344961713Sgirish 		goto fail;
27444961713Sgirish 	nxgep->ipp.max_pkt_size = pkt_size;
27544961713Sgirish 
27644961713Sgirish 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_enable: port%d", portn));
27744961713Sgirish 	return (NXGE_OK);
27844961713Sgirish fail:
27944961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
280a3c5bd6dSspeer 		"nxge_ipp_init: Fail to Enable IPP Port #%d\n", portn));
28144961713Sgirish 	return (NXGE_ERROR | rs);
28244961713Sgirish }
28344961713Sgirish 
284a3c5bd6dSspeer /* ARGSUSED */
28544961713Sgirish nxge_status_t
28644961713Sgirish nxge_ipp_handle_sys_errors(p_nxge_t nxgep)
28744961713Sgirish {
288a3c5bd6dSspeer 	npi_handle_t handle;
289a3c5bd6dSspeer 	npi_status_t rs = NPI_SUCCESS;
290a3c5bd6dSspeer 	p_nxge_ipp_stats_t statsp;
291a3c5bd6dSspeer 	ipp_status_t istatus;
292a3c5bd6dSspeer 	uint8_t portn;
293a3c5bd6dSspeer 	p_ipp_errlog_t errlogp;
294a3c5bd6dSspeer 	boolean_t rxport_fatal = B_FALSE;
295a3c5bd6dSspeer 	nxge_status_t status = NXGE_OK;
29653f3d8ecSyc 	uint8_t cnt8;
29753f3d8ecSyc 	uint16_t cnt16;
29844961713Sgirish 
29944961713Sgirish 	handle = nxgep->npi_handle;
30044961713Sgirish 	statsp = (p_nxge_ipp_stats_t)&nxgep->statsp->ipp_stats;
30144961713Sgirish 	portn = nxgep->mac.portnum;
30244961713Sgirish 
30344961713Sgirish 	errlogp = (p_ipp_errlog_t)&statsp->errlog;
30444961713Sgirish 
30544961713Sgirish 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
30644961713Sgirish 		return (NXGE_ERROR | rs);
30744961713Sgirish 
308a3c5bd6dSspeer 	if (istatus.value == 0) {
30944961713Sgirish 		/*
31044961713Sgirish 		 * The error is not initiated from this port, so just exit.
31144961713Sgirish 		 */
31244961713Sgirish 		return (NXGE_OK);
313a3c5bd6dSspeer 	}
31444961713Sgirish 
31544961713Sgirish 	if (istatus.bits.w0.dfifo_missed_sop) {
31644961713Sgirish 		statsp->sop_miss++;
31744961713Sgirish 		if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn,
31844961713Sgirish 					&errlogp->dfifo_rd_ptr)) != NPI_SUCCESS)
31944961713Sgirish 			return (NXGE_ERROR | rs);
32044961713Sgirish 		if ((rs = npi_ipp_get_state_mach(handle, portn,
321a3c5bd6dSspeer 				&errlogp->state_mach)) != NPI_SUCCESS)
32244961713Sgirish 			return (NXGE_ERROR | rs);
32344961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
324a3c5bd6dSspeer 			NXGE_FM_EREPORT_IPP_SOP_MISS);
32544961713Sgirish 		if (statsp->sop_miss < IPP_MAX_ERR_SHOW)
32644961713Sgirish 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
32744961713Sgirish 				"nxge_ipp_err_evnts: fatal error: sop_miss\n"));
32844961713Sgirish 		rxport_fatal = B_TRUE;
32944961713Sgirish 	}
33044961713Sgirish 	if (istatus.bits.w0.dfifo_missed_eop) {
33144961713Sgirish 		statsp->eop_miss++;
33244961713Sgirish 		if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn,
333a3c5bd6dSspeer 				&errlogp->dfifo_rd_ptr)) != NPI_SUCCESS)
33444961713Sgirish 			return (NXGE_ERROR | rs);
33544961713Sgirish 		if ((rs = npi_ipp_get_state_mach(handle, portn,
336a3c5bd6dSspeer 				&errlogp->state_mach)) != NPI_SUCCESS)
33744961713Sgirish 			return (NXGE_ERROR | rs);
33844961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
339a3c5bd6dSspeer 			NXGE_FM_EREPORT_IPP_EOP_MISS);
34044961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
341a3c5bd6dSspeer 			"nxge_ipp_err_evnts: fatal error: eop_miss\n"));
34244961713Sgirish 		rxport_fatal = B_TRUE;
34344961713Sgirish 	}
34444961713Sgirish 	if (istatus.bits.w0.dfifo_uncorr_ecc_err) {
34514ea4bb7Ssd 		boolean_t ue_ecc_valid;
34614ea4bb7Ssd 
347a3c5bd6dSspeer 		if ((status = nxge_ipp_eccue_valid_check(nxgep,
348a3c5bd6dSspeer 				&ue_ecc_valid)) != NXGE_OK)
34914ea4bb7Ssd 			return (status);
35014ea4bb7Ssd 
35114ea4bb7Ssd 		if (ue_ecc_valid) {
35214ea4bb7Ssd 			statsp->dfifo_ue++;
35314ea4bb7Ssd 			if ((rs = npi_ipp_get_ecc_syndrome(handle, portn,
35444961713Sgirish 					&errlogp->ecc_syndrome)) != NPI_SUCCESS)
35514ea4bb7Ssd 				return (NXGE_ERROR | rs);
35614ea4bb7Ssd 			NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
357a3c5bd6dSspeer 				NXGE_FM_EREPORT_IPP_DFIFO_UE);
35814ea4bb7Ssd 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
35944961713Sgirish 				"nxge_ipp_err_evnts: fatal error: dfifo_ue\n"));
36014ea4bb7Ssd 			rxport_fatal = B_TRUE;
36114ea4bb7Ssd 		}
36244961713Sgirish 	}
36344961713Sgirish 	if (istatus.bits.w0.pre_fifo_perr) {
36444961713Sgirish 		statsp->pfifo_perr++;
36544961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
366a3c5bd6dSspeer 			NXGE_FM_EREPORT_IPP_PFIFO_PERR);
36744961713Sgirish 		if (statsp->pfifo_perr < IPP_MAX_ERR_SHOW)
36844961713Sgirish 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
369a3c5bd6dSspeer 				"nxge_ipp_err_evnts: "
370a3c5bd6dSspeer 				"fatal error: pre_pifo_perr\n"));
37144961713Sgirish 		rxport_fatal = B_TRUE;
37244961713Sgirish 	}
37344961713Sgirish 	if (istatus.bits.w0.pre_fifo_overrun) {
37444961713Sgirish 		statsp->pfifo_over++;
37544961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
376a3c5bd6dSspeer 			NXGE_FM_EREPORT_IPP_PFIFO_OVER);
37744961713Sgirish 		if (statsp->pfifo_over < IPP_MAX_ERR_SHOW)
37844961713Sgirish 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
379a3c5bd6dSspeer 				"nxge_ipp_err_evnts: "
380a3c5bd6dSspeer 				"fatal error: pfifo_over\n"));
38144961713Sgirish 		rxport_fatal = B_TRUE;
38244961713Sgirish 	}
38344961713Sgirish 	if (istatus.bits.w0.pre_fifo_underrun) {
38444961713Sgirish 		statsp->pfifo_und++;
38544961713Sgirish 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
386a3c5bd6dSspeer 			NXGE_FM_EREPORT_IPP_PFIFO_UND);
38744961713Sgirish 		if (statsp->pfifo_und < IPP_MAX_ERR_SHOW)
38844961713Sgirish 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
389a3c5bd6dSspeer 				"nxge_ipp_err_evnts: "
390a3c5bd6dSspeer 				"fatal error: pfifo_und\n"));
39144961713Sgirish 		rxport_fatal = B_TRUE;
39244961713Sgirish 	}
39344961713Sgirish 	if (istatus.bits.w0.bad_cksum_cnt_ovfl) {
394d710877aSyc 		/*
395d710877aSyc 		 * Clear bit BAD_CS_MX of register IPP_INT_STAT
396d710877aSyc 		 * by reading register IPP_BAD_CS_CNT
397d710877aSyc 		 */
39853f3d8ecSyc 		(void) npi_ipp_get_cs_err_count(handle, portn, &cnt16);
39944961713Sgirish 		statsp->bad_cs_cnt += IPP_BAD_CS_CNT_MASK;
400*f6485eecSyc 		/*
401*f6485eecSyc 		 * Do not send FMA ereport because this error does not
402*f6485eecSyc 		 * indicate a HW failure
403*f6485eecSyc 		 */
404a3c5bd6dSspeer 		if (statsp->bad_cs_cnt < (IPP_MAX_ERR_SHOW *
405a3c5bd6dSspeer 				IPP_BAD_CS_CNT_MASK))
40644961713Sgirish 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
40744961713Sgirish 				"nxge_ipp_err_evnts: bad_cs_max\n"));
40844961713Sgirish 	}
40944961713Sgirish 	if (istatus.bits.w0.pkt_discard_cnt_ovfl) {
410d710877aSyc 		/*
411d710877aSyc 		 * Clear bit PKT_DIS_MX of register IPP_INT_STAT
412d710877aSyc 		 * by reading register IPP_PKT_DIS
413d710877aSyc 		 */
41453f3d8ecSyc 		(void) npi_ipp_get_pkt_dis_count(handle, portn, &cnt16);
41544961713Sgirish 		statsp->pkt_dis_cnt += IPP_PKT_DIS_CNT_MASK;
416*f6485eecSyc 		/*
417*f6485eecSyc 		 * Do not send FMA ereport because this error does not
418*f6485eecSyc 		 * indicate a HW failure
419*f6485eecSyc 		 */
420a3c5bd6dSspeer 		if (statsp->pkt_dis_cnt < (IPP_MAX_ERR_SHOW *
421a3c5bd6dSspeer 				IPP_PKT_DIS_CNT_MASK))
42244961713Sgirish 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
42344961713Sgirish 				"nxge_ipp_err_evnts: pkt_dis_max\n"));
42444961713Sgirish 	}
42553f3d8ecSyc 	if (istatus.bits.w0.ecc_err_cnt_ovfl) {
426d710877aSyc 		/*
427d710877aSyc 		 * Clear bit ECC_ERR_MAX of register IPP_INI_STAT
428d710877aSyc 		 * by reading register IPP_ECC
429d710877aSyc 		 */
43053f3d8ecSyc 		(void) npi_ipp_get_ecc_err_count(handle, portn, &cnt8);
43153f3d8ecSyc 		statsp->ecc_err_cnt += IPP_ECC_CNT_MASK;
432*f6485eecSyc 		/*
433*f6485eecSyc 		 * A defect in Neptune port2's IPP module could generate
434*f6485eecSyc 		 * many fake but harmless ECC errors under stress and cause
435*f6485eecSyc 		 * the ecc-error-counter register IPP_ECC to reach its
436*f6485eecSyc 		 * maximum value in a few seconds. To avoid false alarm, do
437*f6485eecSyc 		 * not report the error if it is port2.
438*f6485eecSyc 		 */
439*f6485eecSyc 		if (portn != 2) {
440*f6485eecSyc 			NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
441*f6485eecSyc 			    NXGE_FM_EREPORT_IPP_ECC_ERR_MAX);
442*f6485eecSyc 			if (statsp->ecc_err_cnt < (IPP_MAX_ERR_SHOW *
443*f6485eecSyc 			    IPP_ECC_CNT_MASK)) {
444*f6485eecSyc 				NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
445*f6485eecSyc 				    "nxge_ipp_err_evnts: pkt_ecc_err_max\n"));
446*f6485eecSyc 			}
447*f6485eecSyc 		}
44853f3d8ecSyc 	}
44944961713Sgirish 	/*
450a3c5bd6dSspeer 	 * Making sure that error source is cleared if this is an injected
451a3c5bd6dSspeer 	 * error.
45244961713Sgirish 	 */
45344961713Sgirish 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
45444961713Sgirish 
45544961713Sgirish 	if (rxport_fatal) {
45644961713Sgirish 		NXGE_DEBUG_MSG((nxgep, IPP_CTL,
457a3c5bd6dSspeer 			" nxge_ipp_handle_sys_errors:"
458a3c5bd6dSspeer 			" fatal Error on  Port #%d\n", portn));
45944961713Sgirish 		status = nxge_ipp_fatal_err_recover(nxgep);
46044961713Sgirish 		if (status == NXGE_OK) {
46144961713Sgirish 			FM_SERVICE_RESTORED(nxgep);
46244961713Sgirish 		}
46344961713Sgirish 	}
46444961713Sgirish 	return (status);
46544961713Sgirish }
46644961713Sgirish 
467a3c5bd6dSspeer /* ARGSUSED */
46844961713Sgirish void
46944961713Sgirish nxge_ipp_inject_err(p_nxge_t nxgep, uint32_t err_id)
47044961713Sgirish {
471a3c5bd6dSspeer 	ipp_status_t ipps;
472a3c5bd6dSspeer 	ipp_ecc_ctrl_t ecc_ctrl;
473a3c5bd6dSspeer 	uint8_t portn = nxgep->mac.portnum;
47444961713Sgirish 
47544961713Sgirish 	switch (err_id) {
47644961713Sgirish 	case NXGE_FM_EREPORT_IPP_DFIFO_UE:
47744961713Sgirish 		ecc_ctrl.value = 0;
47844961713Sgirish 		ecc_ctrl.bits.w0.cor_dbl = 1;
47944961713Sgirish 		ecc_ctrl.bits.w0.cor_1 = 1;
48044961713Sgirish 		ecc_ctrl.bits.w0.cor_lst = 1;
48144961713Sgirish 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n",
482a3c5bd6dSspeer 			(unsigned long long) ecc_ctrl.value);
48344961713Sgirish 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG,
484a3c5bd6dSspeer 			ecc_ctrl.value);
48544961713Sgirish 		break;
486a3c5bd6dSspeer 
48744961713Sgirish 	case NXGE_FM_EREPORT_IPP_DFIFO_CE:
48844961713Sgirish 		ecc_ctrl.value = 0;
48944961713Sgirish 		ecc_ctrl.bits.w0.cor_sng = 1;
49044961713Sgirish 		ecc_ctrl.bits.w0.cor_1 = 1;
49144961713Sgirish 		ecc_ctrl.bits.w0.cor_snd = 1;
49244961713Sgirish 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n",
493a3c5bd6dSspeer 			(unsigned long long) ecc_ctrl.value);
49444961713Sgirish 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG,
495a3c5bd6dSspeer 			ecc_ctrl.value);
49644961713Sgirish 		break;
497a3c5bd6dSspeer 
49844961713Sgirish 	case NXGE_FM_EREPORT_IPP_EOP_MISS:
49944961713Sgirish 	case NXGE_FM_EREPORT_IPP_SOP_MISS:
50044961713Sgirish 	case NXGE_FM_EREPORT_IPP_PFIFO_PERR:
50144961713Sgirish 	case NXGE_FM_EREPORT_IPP_ECC_ERR_MAX:
50244961713Sgirish 	case NXGE_FM_EREPORT_IPP_PFIFO_OVER:
50344961713Sgirish 	case NXGE_FM_EREPORT_IPP_PFIFO_UND:
50444961713Sgirish 	case NXGE_FM_EREPORT_IPP_BAD_CS_MX:
50544961713Sgirish 	case NXGE_FM_EREPORT_IPP_PKT_DIS_MX:
50644961713Sgirish 	case NXGE_FM_EREPORT_IPP_RESET_FAIL:
50744961713Sgirish 		IPP_REG_RD(nxgep->npi_handle, portn, IPP_INT_STATUS_REG,
50844961713Sgirish 			&ipps.value);
50944961713Sgirish 		if (err_id == NXGE_FM_EREPORT_IPP_EOP_MISS)
51044961713Sgirish 			ipps.bits.w0.dfifo_missed_eop = 1;
51144961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_IPP_SOP_MISS)
51244961713Sgirish 			ipps.bits.w0.dfifo_missed_sop = 1;
51344961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_UE)
51444961713Sgirish 			ipps.bits.w0.dfifo_uncorr_ecc_err = 1;
51544961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_CE)
51644961713Sgirish 			ipps.bits.w0.dfifo_corr_ecc_err = 1;
51744961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_PERR)
51844961713Sgirish 			ipps.bits.w0.pre_fifo_perr = 1;
519d710877aSyc 		else if (err_id == NXGE_FM_EREPORT_IPP_ECC_ERR_MAX) {
520d710877aSyc 			/*
521d710877aSyc 			 * Fill register IPP_ECC with max ECC-error-
522d710877aSyc 			 * counter value (0xff) to set the ECC_ERR_MAX bit
523d710877aSyc 			 * of the IPP_INT_STAT register and trigger an
524d710877aSyc 			 * FMA ereport.
525d710877aSyc 			 */
526d710877aSyc 			IPP_REG_WR(nxgep->npi_handle, portn,
527d710877aSyc 			    IPP_ECC_ERR_COUNTER_REG, IPP_ECC_CNT_MASK);
528d710877aSyc 		} else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_OVER)
52944961713Sgirish 			ipps.bits.w0.pre_fifo_overrun = 1;
53044961713Sgirish 		else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_UND)
53144961713Sgirish 			ipps.bits.w0.pre_fifo_underrun = 1;
532d710877aSyc 		else if (err_id == NXGE_FM_EREPORT_IPP_BAD_CS_MX) {
533d710877aSyc 			/*
534d710877aSyc 			 * Fill IPP_BAD_CS_CNT with max bad-checksum-counter
535d710877aSyc 			 * value (0x3fff) to set the BAD_CS_MX bit of
536d710877aSyc 			 * IPP_INT_STAT and trigger an FMA ereport.
537d710877aSyc 			 */
538d710877aSyc 			IPP_REG_WR(nxgep->npi_handle, portn,
539*f6485eecSyc 			    IPP_BAD_CKSUM_ERR_CNT_REG, IPP_BAD_CS_CNT_MASK);
540d710877aSyc 		} else if (err_id == NXGE_FM_EREPORT_IPP_PKT_DIS_MX) {
541d710877aSyc 			/*
542d710877aSyc 			 * Fill IPP_PKT_DIS with max packet-discard-counter
543d710877aSyc 			 * value (0x3fff) to set the PKT_DIS_MX bit of
544d710877aSyc 			 * IPP_INT_STAT and trigger an FMA ereport.
545d710877aSyc 			 */
546d710877aSyc 			IPP_REG_WR(nxgep->npi_handle, portn,
547d710877aSyc 			    IPP_DISCARD_PKT_CNT_REG, IPP_PKT_DIS_CNT_MASK);
548d710877aSyc 		}
54944961713Sgirish 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_INT_STATUS_REG\n",
550a3c5bd6dSspeer 			(unsigned long long) ipps.value);
55144961713Sgirish 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_INT_STATUS_REG,
552a3c5bd6dSspeer 			ipps.value);
55344961713Sgirish 		break;
55444961713Sgirish 	}
55544961713Sgirish }
55644961713Sgirish 
557a3c5bd6dSspeer /* ARGSUSED */
55844961713Sgirish nxge_status_t
55944961713Sgirish nxge_ipp_fatal_err_recover(p_nxge_t nxgep)
56044961713Sgirish {
561a3c5bd6dSspeer 	npi_handle_t handle;
562a3c5bd6dSspeer 	npi_status_t rs = NPI_SUCCESS;
563a3c5bd6dSspeer 	nxge_status_t status = NXGE_OK;
564a3c5bd6dSspeer 	uint8_t portn;
565a3c5bd6dSspeer 	uint16_t wr_ptr;
566a3c5bd6dSspeer 	uint16_t rd_ptr;
567a3c5bd6dSspeer 	uint32_t try_count;
568a3c5bd6dSspeer 	uint32_t dfifo_entries;
569a3c5bd6dSspeer 	ipp_status_t istatus;
570a3c5bd6dSspeer 	uint32_t d0, d1, d2, d3, d4;
571a3c5bd6dSspeer 	int i;
57244961713Sgirish 
57344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, RX_CTL, "<== nxge_ipp_fatal_err_recover"));
57444961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
575a3c5bd6dSspeer 		"Recovering from RxPort error..."));
57644961713Sgirish 
57744961713Sgirish 	handle = nxgep->npi_handle;
57844961713Sgirish 	portn = nxgep->mac.portnum;
57944961713Sgirish 
58044961713Sgirish 	/*
581a3c5bd6dSspeer 	 * Making sure that error source is cleared if this is an injected
582a3c5bd6dSspeer 	 * error.
58344961713Sgirish 	 */
58444961713Sgirish 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
58544961713Sgirish 
58644961713Sgirish 	/* Disable RxMAC */
58744961713Sgirish 	if (nxge_rx_mac_disable(nxgep) != NXGE_OK)
58844961713Sgirish 		goto fail;
58944961713Sgirish 
59044961713Sgirish 	/* When recovering from IPP, RxDMA channel resets are not necessary */
59144961713Sgirish 	/* Reset ZCP CFIFO */
59244961713Sgirish 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset ZCP CFIFO...", portn));
59344961713Sgirish 	if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS)
59444961713Sgirish 		goto fail;
59544961713Sgirish 
59644961713Sgirish 	/*
597a3c5bd6dSspeer 	 * Wait until ip read and write fifo pointers are equal
59844961713Sgirish 	 */
59944961713Sgirish 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
60044961713Sgirish 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
60144961713Sgirish 	try_count = 512;
60244961713Sgirish 
60344961713Sgirish 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
60444961713Sgirish 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
60544961713Sgirish 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
60644961713Sgirish 		try_count--;
60744961713Sgirish 	}
60844961713Sgirish 
60944961713Sgirish 	if (try_count == 0) {
61044961713Sgirish 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
611a3c5bd6dSspeer 			" nxge_ipp_reset: port%d IPP stalled..."
612a3c5bd6dSspeer 			" rd_fifo_ptr = 0x%x wr_fifo_ptr = 0x%x",
613a3c5bd6dSspeer 			portn, rd_ptr, wr_ptr));
61444961713Sgirish 		/*
615a3c5bd6dSspeer 		 * This means the fatal error occurred on the first line of the
616a3c5bd6dSspeer 		 * fifo. In this case, just reset the IPP without draining the
617a3c5bd6dSspeer 		 * PFIFO.
61844961713Sgirish 		 */
61944961713Sgirish 	}
62044961713Sgirish 
62159ac0c16Sdavemq 	if (nxgep->niu_type == N2_NIU) {
62259ac0c16Sdavemq 		dfifo_entries = IPP_NIU_DFIFO_ENTRIES;
6232e59129aSraghus 	} else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
62444961713Sgirish 		if (portn < 2)
62544961713Sgirish 			dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES;
62644961713Sgirish 		else
62744961713Sgirish 			dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES;
62859ac0c16Sdavemq 	} else {
62944961713Sgirish 		goto fail;
63059ac0c16Sdavemq 	}
63144961713Sgirish 
63244961713Sgirish 	/* Clean up DFIFO SRAM entries */
63344961713Sgirish 	for (i = 0; i < dfifo_entries; i++) {
634a3c5bd6dSspeer 		if ((rs = npi_ipp_write_dfifo(handle, portn,
635a3c5bd6dSspeer 				i, 0, 0, 0, 0, 0)) != NPI_SUCCESS)
63644961713Sgirish 			goto fail;
637a3c5bd6dSspeer 		if ((rs = npi_ipp_read_dfifo(handle, portn, i,
638a3c5bd6dSspeer 				&d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
63944961713Sgirish 			goto fail;
64044961713Sgirish 	}
64144961713Sgirish 
64244961713Sgirish 	/* Clear PFIFO DFIFO status bits */
64344961713Sgirish 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
64444961713Sgirish 		goto fail;
64544961713Sgirish 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
64644961713Sgirish 		goto fail;
64744961713Sgirish 
64844961713Sgirish 	/* Reset IPP */
64944961713Sgirish 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset IPP...", portn));
65044961713Sgirish 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
65144961713Sgirish 		goto fail;
65244961713Sgirish 
65344961713Sgirish 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset RxMAC...", portn));
65444961713Sgirish 	if (nxge_rx_mac_reset(nxgep) != NXGE_OK)
65544961713Sgirish 		goto fail;
65644961713Sgirish 
65744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Initialize RxMAC...", portn));
65844961713Sgirish 	if ((status = nxge_rx_mac_init(nxgep)) != NXGE_OK)
65944961713Sgirish 		goto fail;
66044961713Sgirish 
66144961713Sgirish 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Enable RxMAC...", portn));
66244961713Sgirish 	if (nxge_rx_mac_enable(nxgep) != NXGE_OK)
66344961713Sgirish 		goto fail;
66444961713Sgirish 
66544961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
666d710877aSyc 		"Recovery successful, RxPort restored"));
66744961713Sgirish 	NXGE_DEBUG_MSG((nxgep, RX_CTL, "==> nxge_ipp_fatal_err_recover"));
66844961713Sgirish 
66944961713Sgirish 	return (NXGE_OK);
67044961713Sgirish fail:
67144961713Sgirish 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
67244961713Sgirish 	return (status | rs);
67344961713Sgirish }
67414ea4bb7Ssd 
675a3c5bd6dSspeer /* ARGSUSED */
6761a4557b6Syc /*
67753f3d8ecSyc  *    A hardware bug may cause fake ECCUEs (ECC Uncorrectable Error).
6781a4557b6Syc  * This function checks if a ECCUE is real(valid) or not.  It is not
6791a4557b6Syc  * real if rd_ptr == wr_ptr.
6801a4557b6Syc  *    The hardware module that has the bug is used not only by the IPP
6811a4557b6Syc  * FIFO but also by the ZCP FIFO, therefore this function is also
6821a4557b6Syc  * called by nxge_zcp_handle_sys_errors for validating the ZCP FIFO
6831a4557b6Syc  * error.
6841a4557b6Syc  */
68514ea4bb7Ssd nxge_status_t
68614ea4bb7Ssd nxge_ipp_eccue_valid_check(p_nxge_t nxgep, boolean_t *valid)
68714ea4bb7Ssd {
68814ea4bb7Ssd 	npi_handle_t handle;
68914ea4bb7Ssd 	npi_status_t rs = NPI_SUCCESS;
69014ea4bb7Ssd 	uint8_t portn;
69114ea4bb7Ssd 	uint16_t rd_ptr;
69214ea4bb7Ssd 	uint16_t wr_ptr;
69314ea4bb7Ssd 	uint16_t curr_rd_ptr;
69414ea4bb7Ssd 	uint16_t curr_wr_ptr;
69514ea4bb7Ssd 	uint32_t stall_cnt;
69614ea4bb7Ssd 	uint32_t d0, d1, d2, d3, d4;
69714ea4bb7Ssd 
69814ea4bb7Ssd 	handle = nxgep->npi_handle;
69914ea4bb7Ssd 	portn = nxgep->mac.portnum;
70014ea4bb7Ssd 	*valid = B_TRUE;
70114ea4bb7Ssd 
70214ea4bb7Ssd 	if ((rs = npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr))
703a3c5bd6dSspeer 		!= NPI_SUCCESS)
70414ea4bb7Ssd 		goto fail;
7051a4557b6Syc 	if ((rs = npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr))
706a3c5bd6dSspeer 		!= NPI_SUCCESS)
70714ea4bb7Ssd 		goto fail;
70814ea4bb7Ssd 
70914ea4bb7Ssd 	if (rd_ptr == wr_ptr) {
7101a4557b6Syc 		*valid = B_FALSE; /* FIFO not stuck, so it's not a real ECCUE */
71114ea4bb7Ssd 	} else {
71214ea4bb7Ssd 		stall_cnt = 0;
713ee5416c9Syc 		/*
714ee5416c9Syc 		 * Check if the two pointers are moving, the ECCUE is invali
715ee5416c9Syc 		 * if either pointer is moving, which indicates that the FIFO
716ee5416c9Syc 		 * is functional.
717ee5416c9Syc 		 */
71814ea4bb7Ssd 		while (stall_cnt < 16) {
719a3c5bd6dSspeer 			if ((rs = npi_ipp_get_dfifo_rd_ptr(handle,
720a3c5bd6dSspeer 					portn, &curr_rd_ptr)) != NPI_SUCCESS)
72114ea4bb7Ssd 				goto fail;
722a3c5bd6dSspeer 			if ((rs = npi_ipp_get_dfifo_wr_ptr(handle,
723a3c5bd6dSspeer 					portn, &curr_wr_ptr)) != NPI_SUCCESS)
72414ea4bb7Ssd 				goto fail;
72514ea4bb7Ssd 
726ee5416c9Syc 			if (rd_ptr == curr_rd_ptr && wr_ptr == curr_wr_ptr) {
72714ea4bb7Ssd 				stall_cnt++;
728ee5416c9Syc 			} else {
72914ea4bb7Ssd 				*valid = B_FALSE;
73014ea4bb7Ssd 				break;
73114ea4bb7Ssd 			}
73214ea4bb7Ssd 		}
73314ea4bb7Ssd 
734a3c5bd6dSspeer 		if (valid) {
735ee5416c9Syc 			/*
736d710877aSyc 			 * Further check to see if the ECCUE is valid. The
737ee5416c9Syc 			 * error is real if the LSB of d4 is 1, which
738ee5416c9Syc 			 * indicates that the data that has set the ECC
739ee5416c9Syc 			 * error flag is the 16-byte internal control word.
740ee5416c9Syc 			 */
741ee5416c9Syc 			if ((rs = npi_ipp_read_dfifo(handle, portn, rd_ptr,
742ee5416c9Syc 			    &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
74314ea4bb7Ssd 				goto fail;
74414ea4bb7Ssd 			if ((d4 & 0x1) == 0)	/* Not the 1st line */
74514ea4bb7Ssd 				*valid = B_FALSE;
74614ea4bb7Ssd 		}
74714ea4bb7Ssd 	}
74814ea4bb7Ssd 	return (NXGE_OK);
74914ea4bb7Ssd fail:
75014ea4bb7Ssd 	return (NXGE_ERROR | rs);
75114ea4bb7Ssd }
752