xref: /illumos-gate/usr/src/uts/common/io/nxge/nxge_ipp.c (revision 44961713)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 /*
22  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
23  * Use is subject to license terms.
24  */
25 
26 #pragma ident	"%Z%%M%	%I%	%E% SMI"
27 
28 #include <nxge_impl.h>
29 #include <nxge_ipp.h>
30 
31 nxge_status_t
32 nxge_ipp_init(p_nxge_t nxgep)
33 {
34 	uint8_t		portn;
35 	uint32_t	config;
36 	npi_handle_t	handle;
37 	uint32_t	pkt_size;
38 	ipp_status_t	istatus;
39 	npi_status_t	rs = NPI_SUCCESS;
40 	uint64_t	val;
41 	uint32_t	d0, d1, d2, d3, d4;
42 	int		i;
43 	uint32_t	dfifo_entries;
44 
45 	handle = nxgep->npi_handle;
46 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
47 
48 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_init: port%d", portn));
49 
50 	/* Initialize ECC and parity in SRAM of DFIFO and PFIFO */
51 
52 	if ((nxgep->niu_type == NEPTUNE) || (nxgep->niu_type == NEPTUNE_2)) {
53 		if (portn < 2)
54 			dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES;
55 		else
56 			dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES;
57 	} else if (nxgep->niu_type == N2_NIU) {
58 			dfifo_entries = IPP_NIU_DFIFO_ENTRIES;
59 	} else
60 		goto fail;
61 
62 	for (i = 0; i < dfifo_entries; i++) {
63 		if ((rs = npi_ipp_write_dfifo(handle, portn, i, 0, 0, 0, 0, 0))
64 								!= NPI_SUCCESS)
65 			goto fail;
66 		if ((rs = npi_ipp_read_dfifo(handle, portn, i, &d0, &d1, &d2,
67 						&d3, &d4)) != NPI_SUCCESS)
68 			goto fail;
69 	}
70 
71 	/* Clear PFIFO DFIFO status bits */
72 
73 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
74 		goto fail;
75 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
76 		goto fail;
77 
78 	/*
79 	 * Soft reset to make sure we bring the FIFO pointers back to the
80 	 * original initial position.
81 	 */
82 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
83 		goto fail;
84 
85 	/* Clean up ECC counter */
86 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_ECC_ERR_COUNTER_REG, &val);
87 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_TCP_CKSUM_ERR_CNT_REG, &val);
88 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_DISCARD_PKT_CNT_REG, &val);
89 
90 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
91 		goto fail;
92 
93 	/* Configure IPP port */
94 	if ((rs = npi_ipp_iconfig(handle, INIT, portn, ICFG_IPP_ALL))
95 							!= NPI_SUCCESS)
96 		goto fail;
97 	nxgep->ipp.iconfig = ICFG_IPP_ALL;
98 
99 	config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC |
100 			CFG_IPP_TCP_UDP_CKSUM;
101 	if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS)
102 		goto fail;
103 	nxgep->ipp.config = config;
104 
105 	/* Set max packet size */
106 	pkt_size = IPP_MAX_PKT_SIZE;
107 	if ((rs = npi_ipp_set_max_pktsize(handle, portn, IPP_MAX_PKT_SIZE)) !=
108 						NPI_SUCCESS)
109 		goto fail;
110 	nxgep->ipp.max_pkt_size = pkt_size;
111 
112 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_init: port%d", portn));
113 
114 	return (NXGE_OK);
115 fail:
116 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
117 			"nxge_ipp_init: Fail to initialize IPP Port #%d\n",
118 			portn));
119 	return (NXGE_ERROR | rs);
120 }
121 
122 
123 nxge_status_t
124 nxge_ipp_disable(p_nxge_t nxgep)
125 {
126 	uint8_t		portn;
127 	uint32_t	config;
128 	npi_handle_t	handle;
129 	npi_status_t	rs = NPI_SUCCESS;
130 
131 	handle = nxgep->npi_handle;
132 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
133 
134 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_disable: port%d", portn));
135 
136 	/* disable the IPP */
137 	config = nxgep->ipp.config;
138 	if ((rs = npi_ipp_config(handle, DISABLE, portn, config))
139 							!= NPI_SUCCESS) {
140 		goto fail;
141 	}
142 
143 /* add code to reset control FIFO */
144 	/* IPP soft reset */
145 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS) {
146 		goto fail;
147 	}
148 
149 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_disable: port%d", portn));
150 
151 	return (NXGE_OK);
152 fail:
153 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
154 		"nxge_ipp_disable: Fail to disable IPP Port #%d\n",
155 		portn));
156 	return (NXGE_ERROR | rs);
157 }
158 
159 nxge_status_t
160 nxge_ipp_reset(p_nxge_t nxgep)
161 {
162 	uint8_t		portn;
163 	uint32_t	config;
164 	npi_handle_t	handle;
165 	npi_status_t	rs = NPI_SUCCESS;
166 	uint16_t wr_ptr, rd_ptr;
167 	uint32_t try_count;
168 	handle = nxgep->npi_handle;
169 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
170 
171 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_reset: port%d", portn));
172 
173 	/* disable the IPP */
174 	config = nxgep->ipp.config;
175 	if ((rs = npi_ipp_config(handle, DISABLE, portn, config))
176 							!= NPI_SUCCESS) {
177 		goto fail;
178 	}
179 
180 	/*
181 	 * Wait until ip read and write fifo pointers
182 	 * are equal
183 	 */
184 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
185 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
186 	try_count = 10;
187 
188 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
189 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
190 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
191 		try_count--;
192 	}
193 
194 	if (try_count == 0) {
195 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
196 				    " nxge_ipp_reset: port%d failed"
197 				    " rd_fifo != wr_fifo", portn));
198 		goto fail;
199 	}
200 
201 	/* IPP soft reset */
202 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS) {
203 		goto fail;
204 	}
205 
206 	/* to reset control FIFO */
207 	if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS) {
208 		goto fail;
209 	}
210 
211 	/*
212 	 * Making sure that error source is cleared if this is an
213 	 * injected error.
214 	 */
215 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
216 
217 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_reset: port%d", portn));
218 
219 	return (NXGE_OK);
220 fail:
221 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
222 			"nxge_ipp_init: Fail to Reset IPP Port #%d\n",
223 			portn));
224 	return (NXGE_ERROR | rs);
225 }
226 
227 
228 
229 nxge_status_t
230 nxge_ipp_enable(p_nxge_t nxgep)
231 {
232 	uint8_t		portn;
233 	uint32_t	config;
234 	npi_handle_t	handle;
235 	uint32_t	pkt_size;
236 	npi_status_t	rs = NPI_SUCCESS;
237 
238 	handle = nxgep->npi_handle;
239 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
240 
241 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_enable: port%d", portn));
242 
243 	config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC |
244 			CFG_IPP_TCP_UDP_CKSUM;
245 	if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS)
246 		goto fail;
247 	nxgep->ipp.config = config;
248 
249 	/* Set max packet size */
250 	pkt_size = IPP_MAX_PKT_SIZE;
251 	if ((rs = npi_ipp_set_max_pktsize(handle, portn, IPP_MAX_PKT_SIZE)) !=
252 						NPI_SUCCESS)
253 		goto fail;
254 	nxgep->ipp.max_pkt_size = pkt_size;
255 
256 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_enable: port%d", portn));
257 
258 	return (NXGE_OK);
259 fail:
260 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
261 			"nxge_ipp_init: Fail to Enable IPP Port #%d\n",
262 			portn));
263 	return (NXGE_ERROR | rs);
264 }
265 
266 
267 nxge_status_t
268 nxge_ipp_handle_sys_errors(p_nxge_t nxgep)
269 {
270 	npi_handle_t		handle;
271 	npi_status_t		rs = NPI_SUCCESS;
272 	p_nxge_ipp_stats_t	statsp;
273 	ipp_status_t		istatus;
274 	uint8_t			portn;
275 	p_ipp_errlog_t		errlogp;
276 	boolean_t		rxport_fatal = B_FALSE;
277 	nxge_status_t		status = NXGE_OK;
278 
279 	handle = nxgep->npi_handle;
280 	statsp = (p_nxge_ipp_stats_t)&nxgep->statsp->ipp_stats;
281 	portn = nxgep->mac.portnum;
282 
283 	errlogp = (p_ipp_errlog_t)&statsp->errlog;
284 
285 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
286 		return (NXGE_ERROR | rs);
287 
288 	if (istatus.value == 0)
289 		/*
290 		 * The error is not initiated from this port, so just exit.
291 		 */
292 		return (NXGE_OK);
293 
294 	if (istatus.bits.w0.dfifo_missed_sop) {
295 		statsp->sop_miss++;
296 		if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn,
297 					&errlogp->dfifo_rd_ptr)) != NPI_SUCCESS)
298 			return (NXGE_ERROR | rs);
299 		if ((rs = npi_ipp_get_state_mach(handle, portn,
300 					&errlogp->state_mach)) != NPI_SUCCESS)
301 			return (NXGE_ERROR | rs);
302 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
303 					NXGE_FM_EREPORT_IPP_SOP_MISS);
304 		if (statsp->sop_miss < IPP_MAX_ERR_SHOW)
305 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
306 				"nxge_ipp_err_evnts: fatal error: sop_miss\n"));
307 		rxport_fatal = B_TRUE;
308 	}
309 	if (istatus.bits.w0.dfifo_missed_eop) {
310 		statsp->eop_miss++;
311 		if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn,
312 					&errlogp->dfifo_rd_ptr)) != NPI_SUCCESS)
313 			return (NXGE_ERROR | rs);
314 		if ((rs = npi_ipp_get_state_mach(handle, portn,
315 					&errlogp->state_mach)) != NPI_SUCCESS)
316 			return (NXGE_ERROR | rs);
317 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
318 					NXGE_FM_EREPORT_IPP_EOP_MISS);
319 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
320 				"nxge_ipp_err_evnts: fatal error: eop_miss\n"));
321 		rxport_fatal = B_TRUE;
322 	}
323 	if (istatus.bits.w0.dfifo_uncorr_ecc_err) {
324 		statsp->dfifo_ue++;
325 		if ((rs = npi_ipp_get_ecc_syndrome(handle, portn,
326 					&errlogp->ecc_syndrome)) != NPI_SUCCESS)
327 			return (NXGE_ERROR | rs);
328 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
329 					NXGE_FM_EREPORT_IPP_DFIFO_UE);
330 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
331 				"nxge_ipp_err_evnts: fatal error: dfifo_ue\n"));
332 		rxport_fatal = B_TRUE;
333 	}
334 #ifdef IPP_ECC_CORR_ERR
335 	if (istatus.bits.w0.dfifo_corr_ecc_err) {
336 		/*
337 		 * Do nothing here. ECC errors are collected from the
338 		 * ECC counter.
339 		 */
340 		;
341 	}
342 #endif
343 	if (istatus.bits.w0.pre_fifo_perr) {
344 		statsp->pfifo_perr++;
345 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
346 					NXGE_FM_EREPORT_IPP_PFIFO_PERR);
347 		if (statsp->pfifo_perr < IPP_MAX_ERR_SHOW)
348 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
349 			"nxge_ipp_err_evnts: fatal error: pre_pifo_perr\n"));
350 		rxport_fatal = B_TRUE;
351 	}
352 	if (istatus.bits.w0.ecc_err_cnt_ovfl) {
353 		statsp->ecc_err_cnt += IPP_ECC_CNT_MASK;
354 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
355 					NXGE_FM_EREPORT_IPP_ECC_ERR_MAX);
356 		if (statsp->ecc_err_cnt < (IPP_MAX_ERR_SHOW * IPP_ECC_CNT_MASK))
357 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
358 				"nxge_ipp_err_evnts: ecc_err_max\n"));
359 	}
360 	if (istatus.bits.w0.pre_fifo_overrun) {
361 		statsp->pfifo_over++;
362 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
363 					NXGE_FM_EREPORT_IPP_PFIFO_OVER);
364 		if (statsp->pfifo_over < IPP_MAX_ERR_SHOW)
365 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
366 			"nxge_ipp_err_evnts: fatal error: pfifo_over\n"));
367 		rxport_fatal = B_TRUE;
368 	}
369 	if (istatus.bits.w0.pre_fifo_underrun) {
370 		statsp->pfifo_und++;
371 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
372 					NXGE_FM_EREPORT_IPP_PFIFO_UND);
373 		if (statsp->pfifo_und < IPP_MAX_ERR_SHOW)
374 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
375 			"nxge_ipp_err_evnts: fatal error: pfifo_und\n"));
376 		rxport_fatal = B_TRUE;
377 	}
378 	if (istatus.bits.w0.bad_cksum_cnt_ovfl) {
379 		statsp->bad_cs_cnt += IPP_BAD_CS_CNT_MASK;
380 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
381 					NXGE_FM_EREPORT_IPP_BAD_CS_MX);
382 		if (statsp->bad_cs_cnt <
383 				(IPP_MAX_ERR_SHOW * IPP_BAD_CS_CNT_MASK))
384 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
385 				"nxge_ipp_err_evnts: bad_cs_max\n"));
386 	}
387 	if (istatus.bits.w0.pkt_discard_cnt_ovfl) {
388 		statsp->pkt_dis_cnt += IPP_PKT_DIS_CNT_MASK;
389 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
390 					NXGE_FM_EREPORT_IPP_PKT_DIS_MX);
391 		if (statsp->pkt_dis_cnt <
392 				(IPP_MAX_ERR_SHOW * IPP_PKT_DIS_CNT_MASK))
393 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
394 				"nxge_ipp_err_evnts: pkt_dis_max\n"));
395 	}
396 
397 	/*
398 	 * Making sure that error source is cleared if this is an
399 	 * injected error.
400 	 */
401 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
402 
403 	if (rxport_fatal) {
404 		NXGE_DEBUG_MSG((nxgep, IPP_CTL,
405 			    " nxge_ipp_handle_sys_errors:"
406 			    " fatal Error on  Port #%d\n",
407 			    portn));
408 		status = nxge_ipp_fatal_err_recover(nxgep);
409 #ifdef	NXGE_FM
410 		if (status == NXGE_OK) {
411 			FM_SERVICE_RESTORED(nxgep);
412 		}
413 #endif
414 	}
415 
416 	return (status);
417 }
418 
419 void
420 nxge_ipp_inject_err(p_nxge_t nxgep, uint32_t err_id)
421 {
422 	ipp_status_t	ipps;
423 	ipp_ecc_ctrl_t	ecc_ctrl;
424 	uint8_t		portn = nxgep->mac.portnum;
425 
426 	switch (err_id) {
427 	case NXGE_FM_EREPORT_IPP_DFIFO_UE:
428 		ecc_ctrl.value = 0;
429 		ecc_ctrl.bits.w0.cor_dbl = 1;
430 		ecc_ctrl.bits.w0.cor_1 = 1;
431 		ecc_ctrl.bits.w0.cor_lst = 1;
432 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n",
433 				(unsigned long long)ecc_ctrl.value);
434 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG,
435 				ecc_ctrl.value);
436 		break;
437 	case NXGE_FM_EREPORT_IPP_DFIFO_CE:
438 		ecc_ctrl.value = 0;
439 		ecc_ctrl.bits.w0.cor_sng = 1;
440 		ecc_ctrl.bits.w0.cor_1 = 1;
441 		ecc_ctrl.bits.w0.cor_snd = 1;
442 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n",
443 				(unsigned long long)ecc_ctrl.value);
444 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG,
445 				ecc_ctrl.value);
446 		break;
447 	case NXGE_FM_EREPORT_IPP_EOP_MISS:
448 	case NXGE_FM_EREPORT_IPP_SOP_MISS:
449 	case NXGE_FM_EREPORT_IPP_PFIFO_PERR:
450 	case NXGE_FM_EREPORT_IPP_ECC_ERR_MAX:
451 	case NXGE_FM_EREPORT_IPP_PFIFO_OVER:
452 	case NXGE_FM_EREPORT_IPP_PFIFO_UND:
453 	case NXGE_FM_EREPORT_IPP_BAD_CS_MX:
454 	case NXGE_FM_EREPORT_IPP_PKT_DIS_MX:
455 	case NXGE_FM_EREPORT_IPP_RESET_FAIL:
456 		IPP_REG_RD(nxgep->npi_handle, portn, IPP_INT_STATUS_REG,
457 			&ipps.value);
458 		if (err_id == NXGE_FM_EREPORT_IPP_EOP_MISS)
459 			ipps.bits.w0.dfifo_missed_eop = 1;
460 		else if (err_id == NXGE_FM_EREPORT_IPP_SOP_MISS)
461 			ipps.bits.w0.dfifo_missed_sop = 1;
462 		else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_UE)
463 			ipps.bits.w0.dfifo_uncorr_ecc_err = 1;
464 		else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_CE)
465 			ipps.bits.w0.dfifo_corr_ecc_err = 1;
466 		else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_PERR)
467 			ipps.bits.w0.pre_fifo_perr = 1;
468 		else if (err_id == NXGE_FM_EREPORT_IPP_ECC_ERR_MAX)
469 			ipps.bits.w0.ecc_err_cnt_ovfl = 1;
470 		else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_OVER)
471 			ipps.bits.w0.pre_fifo_overrun = 1;
472 		else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_UND)
473 			ipps.bits.w0.pre_fifo_underrun = 1;
474 		else if (err_id == NXGE_FM_EREPORT_IPP_BAD_CS_MX)
475 			ipps.bits.w0.bad_cksum_cnt_ovfl = 1;
476 		else if (err_id == NXGE_FM_EREPORT_IPP_PKT_DIS_MX)
477 			ipps.bits.w0.pkt_discard_cnt_ovfl = 1;
478 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_INT_STATUS_REG\n",
479 				(unsigned long long)ipps.value);
480 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_INT_STATUS_REG,
481 				ipps.value);
482 		break;
483 	}
484 }
485 
486 nxge_status_t
487 nxge_ipp_fatal_err_recover(p_nxge_t nxgep)
488 {
489 	npi_handle_t		handle;
490 	npi_status_t		rs = NPI_SUCCESS;
491 	nxge_status_t		status = NXGE_OK;
492 	uint8_t			portn;
493 	uint16_t		wr_ptr;
494 	uint16_t		rd_ptr;
495 	uint32_t		try_count;
496 	uint32_t		dfifo_entries;
497 	ipp_status_t		istatus;
498 	uint32_t		d0, d1, d2, d3, d4;
499 	int			i;
500 
501 	NXGE_DEBUG_MSG((nxgep, RX_CTL, "<== nxge_ipp_fatal_err_recover"));
502 
503 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
504 			"Recovering from RxPort error..."));
505 
506 	handle = nxgep->npi_handle;
507 	portn = nxgep->mac.portnum;
508 
509 	/*
510 	 * Making sure that error source is cleared if this is an
511 	 * injected error.
512 	 */
513 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
514 
515 	/* Disable RxMAC */
516 
517 	if (nxge_rx_mac_disable(nxgep) != NXGE_OK)
518 		goto fail;
519 
520 	/* When recovering from IPP, RxDMA channel resets are not necessary */
521 	/* Reset ZCP CFIFO */
522 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset ZCP CFIFO...", portn));
523 	if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS)
524 		goto fail;
525 
526 	/*
527 	 * Wait until ip read and write fifo pointers
528 	 * are equal
529 	 */
530 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
531 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
532 	try_count = 512;
533 
534 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
535 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
536 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
537 		try_count--;
538 	}
539 
540 	if (try_count == 0) {
541 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
542 				    " nxge_ipp_reset: port%d IPP stalled..."
543 				    " rd_fifo_ptr = 0x%x wr_fifo_ptr = 0x%x",
544 				    portn, rd_ptr, wr_ptr));
545 		/*
546 		 * This means the fatal error occurred on the first line
547 		 * of the fifo. In this case, just reset the IPP without
548 		 * draining the PFIFO.
549 		 */
550 	}
551 
552 	if ((nxgep->niu_type == NEPTUNE) || (nxgep->niu_type == NEPTUNE_2)) {
553 		if (portn < 2)
554 			dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES;
555 		else
556 			dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES;
557 	} else if (nxgep->niu_type == N2_NIU) {
558 			dfifo_entries = IPP_NIU_DFIFO_ENTRIES;
559 	} else
560 		goto fail;
561 
562 	/* Clean up DFIFO SRAM entries */
563 	for (i = 0; i < dfifo_entries; i++) {
564 		if ((rs = npi_ipp_write_dfifo(handle, portn, i, 0, 0, 0, 0, 0))
565 								!= NPI_SUCCESS)
566 			goto fail;
567 		if ((rs = npi_ipp_read_dfifo(handle, portn, i, &d0, &d1, &d2,
568 						&d3, &d4)) != NPI_SUCCESS)
569 			goto fail;
570 	}
571 
572 	/* Clear PFIFO DFIFO status bits */
573 
574 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
575 		goto fail;
576 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
577 		goto fail;
578 
579 	/* Reset IPP */
580 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset IPP...", portn));
581 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
582 		goto fail;
583 
584 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset RxMAC...", portn));
585 	if (nxge_rx_mac_reset(nxgep) != NXGE_OK)
586 		goto fail;
587 
588 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Initialize RxMAC...", portn));
589 
590 	if ((status = nxge_rx_mac_init(nxgep)) != NXGE_OK)
591 		goto fail;
592 
593 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Enable RxMAC...", portn));
594 
595 	if (nxge_rx_mac_enable(nxgep) != NXGE_OK)
596 		goto fail;
597 
598 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
599 				"Recovery Sucessful, RxPort Restored"));
600 	NXGE_DEBUG_MSG((nxgep, RX_CTL, "==> nxge_ipp_fatal_err_recover"));
601 
602 	return (NXGE_OK);
603 fail:
604 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
605 	return (status | rs);
606 }
607