xref: /illumos-gate/usr/src/uts/common/io/nxge/nxge_ipp.c (revision da14cebe459d3275048785f25bd869cb09b5307f)
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 2008 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 #define	NXGE_IPP_FIFO_SYNC_TRY_COUNT 100
32 
33 /* ARGSUSED */
34 nxge_status_t
35 nxge_ipp_init(p_nxge_t nxgep)
36 {
37 	uint8_t portn;
38 	uint32_t config;
39 	npi_handle_t handle;
40 	uint32_t pkt_size;
41 	ipp_status_t istatus;
42 	npi_status_t rs = NPI_SUCCESS;
43 	uint64_t val;
44 	uint32_t d0, d1, d2, d3, d4;
45 	int i;
46 	uint32_t dfifo_entries;
47 
48 	handle = nxgep->npi_handle;
49 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
50 
51 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_init: port%d", portn));
52 
53 	/* Initialize ECC and parity in SRAM of DFIFO and PFIFO */
54 	if (nxgep->niu_type == N2_NIU) {
55 		dfifo_entries = IPP_NIU_DFIFO_ENTRIES;
56 	} else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
57 		if (portn < 2)
58 			dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES;
59 		else
60 			dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES;
61 	} else {
62 		goto fail;
63 	}
64 
65 	for (i = 0; i < dfifo_entries; i++) {
66 		if ((rs = npi_ipp_write_dfifo(handle,
67 		    portn, i, 0, 0, 0, 0, 0)) != NPI_SUCCESS)
68 			goto fail;
69 		if ((rs = npi_ipp_read_dfifo(handle, portn,
70 		    i, &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
71 			goto fail;
72 	}
73 
74 	/* Clear PFIFO DFIFO status bits */
75 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
76 		goto fail;
77 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
78 		goto fail;
79 
80 	/*
81 	 * Soft reset to make sure we bring the FIFO pointers back to the
82 	 * original initial position.
83 	 */
84 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
85 		goto fail;
86 
87 	/* Clean up ECC counter */
88 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_ECC_ERR_COUNTER_REG, &val);
89 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_BAD_CKSUM_ERR_CNT_REG, &val);
90 	IPP_REG_RD(nxgep->npi_handle, portn, IPP_DISCARD_PKT_CNT_REG, &val);
91 
92 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
93 		goto fail;
94 
95 	/* Configure IPP port */
96 	if ((rs = npi_ipp_iconfig(handle, INIT, portn, ICFG_IPP_ALL))
97 	    != NPI_SUCCESS)
98 		goto fail;
99 	nxgep->ipp.iconfig = ICFG_IPP_ALL;
100 
101 	config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC |
102 	    CFG_IPP_TCP_UDP_CKSUM;
103 	if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS)
104 		goto fail;
105 	nxgep->ipp.config = config;
106 
107 	/* Set max packet size */
108 	pkt_size = IPP_MAX_PKT_SIZE;
109 	if ((rs = npi_ipp_set_max_pktsize(handle, portn,
110 	    IPP_MAX_PKT_SIZE)) != NPI_SUCCESS)
111 		goto fail;
112 	nxgep->ipp.max_pkt_size = pkt_size;
113 
114 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_init: port%d", portn));
115 
116 	return (NXGE_OK);
117 fail:
118 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
119 	    "nxge_ipp_init: Fail to initialize IPP Port #%d\n",
120 	    portn));
121 	return (NXGE_ERROR | rs);
122 }
123 
124 /* ARGSUSED */
125 nxge_status_t
126 nxge_ipp_disable(p_nxge_t nxgep)
127 {
128 	uint8_t portn;
129 	uint32_t config;
130 	npi_handle_t handle;
131 	npi_status_t rs = NPI_SUCCESS;
132 	uint16_t wr_ptr, rd_ptr;
133 	uint32_t try_count;
134 
135 	handle = nxgep->npi_handle;
136 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
137 
138 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_disable: port%d", portn));
139 	(void) nxge_rx_mac_disable(nxgep);
140 
141 	/*
142 	 * Wait until ip read and write fifo pointers are equal
143 	 */
144 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
145 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
146 	try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT;
147 
148 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
149 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
150 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
151 		try_count--;
152 	}
153 
154 	if (try_count == 0) {
155 		if ((rd_ptr != 0) && (wr_ptr != 1)) {
156 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
157 			    " nxge_ipp_disable: port%d failed"
158 			    " rd_fifo != wr_fifo", portn));
159 			goto fail;
160 		}
161 	}
162 	/* disable the IPP */
163 	config = nxgep->ipp.config;
164 	if ((rs = npi_ipp_config(handle, DISABLE,
165 	    portn, config)) != NPI_SUCCESS)
166 		goto fail;
167 
168 	/* IPP soft reset */
169 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
170 		goto fail;
171 
172 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_disable: port%d", portn));
173 	return (NXGE_OK);
174 fail:
175 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
176 	    "nxge_ipp_disable: Fail to disable IPP Port #%d\n", portn));
177 	return (NXGE_ERROR | rs);
178 }
179 
180 /* ARGSUSED */
181 nxge_status_t
182 nxge_ipp_reset(p_nxge_t nxgep)
183 {
184 	uint8_t portn;
185 	uint32_t config;
186 	npi_handle_t handle;
187 	npi_status_t rs = NPI_SUCCESS;
188 	uint16_t wr_ptr, rd_ptr;
189 	uint32_t try_count;
190 
191 	handle = nxgep->npi_handle;
192 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
193 
194 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_reset: port%d", portn));
195 
196 	/* disable the IPP */
197 	config = nxgep->ipp.config;
198 	if ((rs = npi_ipp_config(handle, DISABLE,
199 	    portn, config)) != NPI_SUCCESS)
200 		goto fail;
201 
202 	/*
203 	 * Wait until ip read and write fifo pointers are equal
204 	 */
205 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
206 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
207 	try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT;
208 
209 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
210 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
211 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
212 		try_count--;
213 	}
214 
215 	if (try_count == 0) {
216 		if ((rd_ptr != 0) && (wr_ptr != 1)) {
217 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
218 			    " nxge_ipp_disable: port%d failed"
219 			    " rd_fifo != wr_fifo", portn));
220 			goto fail;
221 		}
222 	}
223 
224 	/* IPP soft reset */
225 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS) {
226 		goto fail;
227 	}
228 
229 	/* to reset control FIFO */
230 	if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS)
231 		goto fail;
232 
233 	/*
234 	 * Making sure that error source is cleared if this is an injected
235 	 * error.
236 	 */
237 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
238 
239 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_reset: port%d", portn));
240 	return (NXGE_OK);
241 fail:
242 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
243 	    "nxge_ipp_init: Fail to Reset IPP Port #%d\n",
244 	    portn));
245 	return (NXGE_ERROR | rs);
246 }
247 
248 /* ARGSUSED */
249 nxge_status_t
250 nxge_ipp_enable(p_nxge_t nxgep)
251 {
252 	uint8_t portn;
253 	uint32_t config;
254 	npi_handle_t handle;
255 	uint32_t pkt_size;
256 	npi_status_t rs = NPI_SUCCESS;
257 
258 	handle = nxgep->npi_handle;
259 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
260 
261 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_enable: port%d", portn));
262 
263 	config = CFG_IPP | CFG_IPP_DFIFO_ECC_CORRECT | CFG_IPP_DROP_BAD_CRC |
264 	    CFG_IPP_TCP_UDP_CKSUM;
265 	if ((rs = npi_ipp_config(handle, INIT, portn, config)) != NPI_SUCCESS)
266 		goto fail;
267 	nxgep->ipp.config = config;
268 
269 	/* Set max packet size */
270 	pkt_size = IPP_MAX_PKT_SIZE;
271 	if ((rs = npi_ipp_set_max_pktsize(handle, portn,
272 	    IPP_MAX_PKT_SIZE)) != NPI_SUCCESS)
273 		goto fail;
274 	nxgep->ipp.max_pkt_size = pkt_size;
275 
276 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_enable: port%d", portn));
277 	return (NXGE_OK);
278 fail:
279 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
280 	    "nxge_ipp_init: Fail to Enable IPP Port #%d\n", portn));
281 	return (NXGE_ERROR | rs);
282 }
283 
284 /* ARGSUSED */
285 nxge_status_t
286 nxge_ipp_drain(p_nxge_t nxgep)
287 {
288 	uint8_t portn;
289 	npi_handle_t handle;
290 	npi_status_t rs = NPI_SUCCESS;
291 	uint16_t wr_ptr, rd_ptr;
292 	uint32_t try_count;
293 
294 	handle = nxgep->npi_handle;
295 	portn = NXGE_GET_PORT_NUM(nxgep->function_num);
296 
297 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "==> nxge_ipp_drain: port%d", portn));
298 
299 	/*
300 	 * Wait until ip read and write fifo pointers are equal
301 	 */
302 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
303 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
304 	try_count = NXGE_IPP_FIFO_SYNC_TRY_COUNT;
305 
306 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
307 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
308 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
309 		try_count--;
310 	}
311 
312 	if (try_count == 0) {
313 		if ((rd_ptr != 0) && (wr_ptr != 1)) {
314 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
315 			    " nxge_ipp_drain: port%d failed"
316 			    " rd_fifo != wr_fifo", portn));
317 			goto fail;
318 		}
319 	}
320 
321 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "<== nxge_ipp_drain: port%d", portn));
322 	return (NXGE_OK);
323 fail:
324 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "nxge_ipp_init: "
325 	    "Fail to Reset IPP Port #%d\n", portn));
326 	return (NXGE_ERROR | rs);
327 }
328 
329 /* ARGSUSED */
330 nxge_status_t
331 nxge_ipp_handle_sys_errors(p_nxge_t nxgep)
332 {
333 	npi_handle_t handle;
334 	npi_status_t rs = NPI_SUCCESS;
335 	p_nxge_ipp_stats_t statsp;
336 	ipp_status_t istatus;
337 	uint8_t portn;
338 	p_ipp_errlog_t errlogp;
339 	boolean_t rxport_fatal = B_FALSE;
340 	nxge_status_t status = NXGE_OK;
341 	uint8_t cnt8;
342 	uint16_t cnt16;
343 
344 	handle = nxgep->npi_handle;
345 	statsp = (p_nxge_ipp_stats_t)&nxgep->statsp->ipp_stats;
346 	portn = nxgep->mac.portnum;
347 
348 	errlogp = (p_ipp_errlog_t)&statsp->errlog;
349 
350 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
351 		return (NXGE_ERROR | rs);
352 
353 	if (istatus.value == 0) {
354 		/*
355 		 * The error is not initiated from this port, so just exit.
356 		 */
357 		return (NXGE_OK);
358 	}
359 
360 	if (istatus.bits.w0.dfifo_missed_sop) {
361 		statsp->sop_miss++;
362 		if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn,
363 		    &errlogp->dfifo_rd_ptr)) != NPI_SUCCESS)
364 			return (NXGE_ERROR | rs);
365 		if ((rs = npi_ipp_get_state_mach(handle, portn,
366 		    &errlogp->state_mach)) != NPI_SUCCESS)
367 			return (NXGE_ERROR | rs);
368 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
369 		    NXGE_FM_EREPORT_IPP_SOP_MISS);
370 		if (statsp->sop_miss < IPP_MAX_ERR_SHOW)
371 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
372 			    "nxge_ipp_err_evnts: fatal error: sop_miss\n"));
373 		rxport_fatal = B_TRUE;
374 	}
375 	if (istatus.bits.w0.dfifo_missed_eop) {
376 		statsp->eop_miss++;
377 		if ((rs = npi_ipp_get_dfifo_eopm_rdptr(handle, portn,
378 		    &errlogp->dfifo_rd_ptr)) != NPI_SUCCESS)
379 			return (NXGE_ERROR | rs);
380 		if ((rs = npi_ipp_get_state_mach(handle, portn,
381 		    &errlogp->state_mach)) != NPI_SUCCESS)
382 			return (NXGE_ERROR | rs);
383 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
384 		    NXGE_FM_EREPORT_IPP_EOP_MISS);
385 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
386 		    "nxge_ipp_err_evnts: fatal error: eop_miss\n"));
387 		rxport_fatal = B_TRUE;
388 	}
389 	if (istatus.bits.w0.dfifo_uncorr_ecc_err) {
390 		boolean_t ue_ecc_valid;
391 
392 		if ((status = nxge_ipp_eccue_valid_check(nxgep,
393 		    &ue_ecc_valid)) != NXGE_OK)
394 			return (status);
395 
396 		if (ue_ecc_valid) {
397 			statsp->dfifo_ue++;
398 			if ((rs = npi_ipp_get_ecc_syndrome(handle, portn,
399 			    &errlogp->ecc_syndrome)) != NPI_SUCCESS)
400 				return (NXGE_ERROR | rs);
401 			NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
402 			    NXGE_FM_EREPORT_IPP_DFIFO_UE);
403 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
404 			    "nxge_ipp_err_evnts: fatal error: dfifo_ue\n"));
405 			rxport_fatal = B_TRUE;
406 		}
407 	}
408 	if (istatus.bits.w0.pre_fifo_perr) {
409 		statsp->pfifo_perr++;
410 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
411 		    NXGE_FM_EREPORT_IPP_PFIFO_PERR);
412 		if (statsp->pfifo_perr < IPP_MAX_ERR_SHOW)
413 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
414 			    "nxge_ipp_err_evnts: "
415 			    "fatal error: pre_pifo_perr\n"));
416 		rxport_fatal = B_TRUE;
417 	}
418 	if (istatus.bits.w0.pre_fifo_overrun) {
419 		statsp->pfifo_over++;
420 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
421 		    NXGE_FM_EREPORT_IPP_PFIFO_OVER);
422 		if (statsp->pfifo_over < IPP_MAX_ERR_SHOW)
423 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
424 			    "nxge_ipp_err_evnts: "
425 			    "fatal error: pfifo_over\n"));
426 		rxport_fatal = B_TRUE;
427 	}
428 	if (istatus.bits.w0.pre_fifo_underrun) {
429 		statsp->pfifo_und++;
430 		NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
431 		    NXGE_FM_EREPORT_IPP_PFIFO_UND);
432 		if (statsp->pfifo_und < IPP_MAX_ERR_SHOW)
433 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
434 			    "nxge_ipp_err_evnts: "
435 			    "fatal error: pfifo_und\n"));
436 		rxport_fatal = B_TRUE;
437 	}
438 	if (istatus.bits.w0.bad_cksum_cnt_ovfl) {
439 		/*
440 		 * Do not send FMA ereport or log error message
441 		 * in /var/adm/messages because this error does not
442 		 * indicate a HW failure.
443 		 *
444 		 * Clear bit BAD_CS_MX of register IPP_INT_STAT
445 		 * by reading register IPP_BAD_CS_CNT
446 		 */
447 		(void) npi_ipp_get_cs_err_count(handle, portn, &cnt16);
448 		statsp->bad_cs_cnt += IPP_BAD_CS_CNT_MASK;
449 	}
450 	if (istatus.bits.w0.pkt_discard_cnt_ovfl) {
451 		/*
452 		 * Do not send FMA ereport or log error message
453 		 * in /var/adm/messages because this error does not
454 		 * indicate a HW failure.
455 		 *
456 		 * Clear bit PKT_DIS_MX of register IPP_INT_STAT
457 		 * by reading register IPP_PKT_DIS
458 		 */
459 		(void) npi_ipp_get_pkt_dis_count(handle, portn, &cnt16);
460 		statsp->pkt_dis_cnt += IPP_PKT_DIS_CNT_MASK;
461 	}
462 	if (istatus.bits.w0.ecc_err_cnt_ovfl) {
463 		/*
464 		 * Clear bit ECC_ERR_MAX of register IPP_INI_STAT
465 		 * by reading register IPP_ECC
466 		 */
467 		(void) npi_ipp_get_ecc_err_count(handle, portn, &cnt8);
468 		statsp->ecc_err_cnt += IPP_ECC_CNT_MASK;
469 		/*
470 		 * A defect in Neptune port2's IPP module could generate
471 		 * many fake but harmless ECC errors under stress and cause
472 		 * the ecc-error-counter register IPP_ECC to reach its
473 		 * maximum value in a few seconds. To avoid false alarm, do
474 		 * not report the error if it is port2.
475 		 */
476 		if (portn != 2) {
477 			NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
478 			    NXGE_FM_EREPORT_IPP_ECC_ERR_MAX);
479 			if (statsp->ecc_err_cnt < (IPP_MAX_ERR_SHOW *
480 			    IPP_ECC_CNT_MASK)) {
481 				NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
482 				    "nxge_ipp_err_evnts: pkt_ecc_err_max\n"));
483 			}
484 		}
485 	}
486 	/*
487 	 * Making sure that error source is cleared if this is an injected
488 	 * error.
489 	 */
490 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
491 
492 	if (rxport_fatal) {
493 		NXGE_DEBUG_MSG((nxgep, IPP_CTL,
494 		    " nxge_ipp_handle_sys_errors:"
495 		    " fatal Error on  Port #%d\n", portn));
496 		status = nxge_ipp_fatal_err_recover(nxgep);
497 		if (status == NXGE_OK) {
498 			FM_SERVICE_RESTORED(nxgep);
499 		}
500 	}
501 	return (status);
502 }
503 
504 /* ARGSUSED */
505 void
506 nxge_ipp_inject_err(p_nxge_t nxgep, uint32_t err_id)
507 {
508 	ipp_status_t ipps;
509 	ipp_ecc_ctrl_t ecc_ctrl;
510 	uint8_t portn = nxgep->mac.portnum;
511 
512 	switch (err_id) {
513 	case NXGE_FM_EREPORT_IPP_DFIFO_UE:
514 		ecc_ctrl.value = 0;
515 		ecc_ctrl.bits.w0.cor_dbl = 1;
516 		ecc_ctrl.bits.w0.cor_1 = 1;
517 		ecc_ctrl.bits.w0.cor_lst = 1;
518 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n",
519 		    (unsigned long long) ecc_ctrl.value);
520 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG,
521 		    ecc_ctrl.value);
522 		break;
523 
524 	case NXGE_FM_EREPORT_IPP_DFIFO_CE:
525 		ecc_ctrl.value = 0;
526 		ecc_ctrl.bits.w0.cor_sng = 1;
527 		ecc_ctrl.bits.w0.cor_1 = 1;
528 		ecc_ctrl.bits.w0.cor_snd = 1;
529 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_ECC_CTRL_REG\n",
530 		    (unsigned long long) ecc_ctrl.value);
531 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_ECC_CTRL_REG,
532 		    ecc_ctrl.value);
533 		break;
534 
535 	case NXGE_FM_EREPORT_IPP_EOP_MISS:
536 	case NXGE_FM_EREPORT_IPP_SOP_MISS:
537 	case NXGE_FM_EREPORT_IPP_PFIFO_PERR:
538 	case NXGE_FM_EREPORT_IPP_ECC_ERR_MAX:
539 	case NXGE_FM_EREPORT_IPP_PFIFO_OVER:
540 	case NXGE_FM_EREPORT_IPP_PFIFO_UND:
541 	case NXGE_FM_EREPORT_IPP_BAD_CS_MX:
542 	case NXGE_FM_EREPORT_IPP_PKT_DIS_MX:
543 	case NXGE_FM_EREPORT_IPP_RESET_FAIL:
544 		IPP_REG_RD(nxgep->npi_handle, portn, IPP_INT_STATUS_REG,
545 		    &ipps.value);
546 		if (err_id == NXGE_FM_EREPORT_IPP_EOP_MISS)
547 			ipps.bits.w0.dfifo_missed_eop = 1;
548 		else if (err_id == NXGE_FM_EREPORT_IPP_SOP_MISS)
549 			ipps.bits.w0.dfifo_missed_sop = 1;
550 		else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_UE)
551 			ipps.bits.w0.dfifo_uncorr_ecc_err = 1;
552 		else if (err_id == NXGE_FM_EREPORT_IPP_DFIFO_CE)
553 			ipps.bits.w0.dfifo_corr_ecc_err = 1;
554 		else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_PERR)
555 			ipps.bits.w0.pre_fifo_perr = 1;
556 		else if (err_id == NXGE_FM_EREPORT_IPP_ECC_ERR_MAX) {
557 			/*
558 			 * Fill register IPP_ECC with max ECC-error-
559 			 * counter value (0xff) to set the ECC_ERR_MAX bit
560 			 * of the IPP_INT_STAT register and trigger an
561 			 * FMA ereport.
562 			 */
563 			IPP_REG_WR(nxgep->npi_handle, portn,
564 			    IPP_ECC_ERR_COUNTER_REG, IPP_ECC_CNT_MASK);
565 		} else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_OVER)
566 			ipps.bits.w0.pre_fifo_overrun = 1;
567 		else if (err_id == NXGE_FM_EREPORT_IPP_PFIFO_UND)
568 			ipps.bits.w0.pre_fifo_underrun = 1;
569 		else if (err_id == NXGE_FM_EREPORT_IPP_BAD_CS_MX) {
570 			/*
571 			 * Fill IPP_BAD_CS_CNT with max bad-checksum-counter
572 			 * value (0x3fff) to set the BAD_CS_MX bit of
573 			 * IPP_INT_STAT and trigger an FMA ereport.
574 			 */
575 			IPP_REG_WR(nxgep->npi_handle, portn,
576 			    IPP_BAD_CKSUM_ERR_CNT_REG, IPP_BAD_CS_CNT_MASK);
577 		} else if (err_id == NXGE_FM_EREPORT_IPP_PKT_DIS_MX) {
578 			/*
579 			 * Fill IPP_PKT_DIS with max packet-discard-counter
580 			 * value (0x3fff) to set the PKT_DIS_MX bit of
581 			 * IPP_INT_STAT and trigger an FMA ereport.
582 			 */
583 			IPP_REG_WR(nxgep->npi_handle, portn,
584 			    IPP_DISCARD_PKT_CNT_REG, IPP_PKT_DIS_CNT_MASK);
585 		}
586 		cmn_err(CE_NOTE, "!Write 0x%llx to IPP_INT_STATUS_REG\n",
587 		    (unsigned long long) ipps.value);
588 		IPP_REG_WR(nxgep->npi_handle, portn, IPP_INT_STATUS_REG,
589 		    ipps.value);
590 		break;
591 	}
592 }
593 
594 /* ARGSUSED */
595 nxge_status_t
596 nxge_ipp_fatal_err_recover(p_nxge_t nxgep)
597 {
598 	npi_handle_t handle;
599 	npi_status_t rs = NPI_SUCCESS;
600 	nxge_status_t status = NXGE_OK;
601 	uint8_t portn;
602 	uint16_t wr_ptr;
603 	uint16_t rd_ptr;
604 	uint32_t try_count;
605 	uint32_t dfifo_entries;
606 	ipp_status_t istatus;
607 	uint32_t d0, d1, d2, d3, d4;
608 	int i;
609 
610 	NXGE_DEBUG_MSG((nxgep, RX_CTL, "<== nxge_ipp_fatal_err_recover"));
611 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
612 	    "Recovering from RxPort error..."));
613 
614 	handle = nxgep->npi_handle;
615 	portn = nxgep->mac.portnum;
616 
617 	/*
618 	 * Making sure that error source is cleared if this is an injected
619 	 * error.
620 	 */
621 	IPP_REG_WR(handle, portn, IPP_ECC_CTRL_REG, 0);
622 
623 	/* Disable RxMAC */
624 	if (nxge_rx_mac_disable(nxgep) != NXGE_OK)
625 		goto fail;
626 
627 	/* When recovering from IPP, RxDMA channel resets are not necessary */
628 	/* Reset ZCP CFIFO */
629 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset ZCP CFIFO...", portn));
630 	if ((rs = npi_zcp_rest_cfifo_port(handle, portn)) != NPI_SUCCESS)
631 		goto fail;
632 
633 	/*
634 	 * Wait until ip read and write fifo pointers are equal
635 	 */
636 	(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
637 	(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
638 	try_count = 512;
639 
640 	while ((try_count > 0) && (rd_ptr != wr_ptr)) {
641 		(void) npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr);
642 		(void) npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr);
643 		try_count--;
644 	}
645 
646 	if (try_count == 0) {
647 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
648 		    " nxge_ipp_reset: port%d IPP stalled..."
649 		    " rd_fifo_ptr = 0x%x wr_fifo_ptr = 0x%x",
650 		    portn, rd_ptr, wr_ptr));
651 		/*
652 		 * This means the fatal error occurred on the first line of the
653 		 * fifo. In this case, just reset the IPP without draining the
654 		 * PFIFO.
655 		 */
656 	}
657 
658 	if (nxgep->niu_type == N2_NIU) {
659 		dfifo_entries = IPP_NIU_DFIFO_ENTRIES;
660 	} else if (NXGE_IS_VALID_NEPTUNE_TYPE(nxgep)) {
661 		if (portn < 2)
662 			dfifo_entries = IPP_P0_P1_DFIFO_ENTRIES;
663 		else
664 			dfifo_entries = IPP_P2_P3_DFIFO_ENTRIES;
665 	} else {
666 		goto fail;
667 	}
668 
669 	/* Clean up DFIFO SRAM entries */
670 	for (i = 0; i < dfifo_entries; i++) {
671 		if ((rs = npi_ipp_write_dfifo(handle, portn,
672 		    i, 0, 0, 0, 0, 0)) != NPI_SUCCESS)
673 			goto fail;
674 		if ((rs = npi_ipp_read_dfifo(handle, portn, i,
675 		    &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
676 			goto fail;
677 	}
678 
679 	/* Clear PFIFO DFIFO status bits */
680 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
681 		goto fail;
682 	if ((rs = npi_ipp_get_status(handle, portn, &istatus)) != NPI_SUCCESS)
683 		goto fail;
684 
685 	/* Reset IPP */
686 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset IPP...", portn));
687 	if ((rs = npi_ipp_reset(handle, portn)) != NPI_SUCCESS)
688 		goto fail;
689 
690 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Reset RxMAC...", portn));
691 	if (nxge_rx_mac_reset(nxgep) != NXGE_OK)
692 		goto fail;
693 
694 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Initialize RxMAC...", portn));
695 	if ((status = nxge_rx_mac_init(nxgep)) != NXGE_OK)
696 		goto fail;
697 
698 	NXGE_DEBUG_MSG((nxgep, IPP_CTL, "port%d Enable RxMAC...", portn));
699 	if (nxge_rx_mac_enable(nxgep) != NXGE_OK)
700 		goto fail;
701 
702 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
703 	    "Recovery successful, RxPort restored"));
704 	NXGE_DEBUG_MSG((nxgep, RX_CTL, "==> nxge_ipp_fatal_err_recover"));
705 
706 	return (NXGE_OK);
707 fail:
708 	NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL, "Recovery failed"));
709 	return (status | rs);
710 }
711 
712 /* ARGSUSED */
713 /*
714  *    A hardware bug may cause fake ECCUEs (ECC Uncorrectable Error).
715  * This function checks if a ECCUE is real(valid) or not.  It is not
716  * real if rd_ptr == wr_ptr.
717  *    The hardware module that has the bug is used not only by the IPP
718  * FIFO but also by the ZCP FIFO, therefore this function is also
719  * called by nxge_zcp_handle_sys_errors for validating the ZCP FIFO
720  * error.
721  */
722 nxge_status_t
723 nxge_ipp_eccue_valid_check(p_nxge_t nxgep, boolean_t *valid)
724 {
725 	npi_handle_t handle;
726 	npi_status_t rs = NPI_SUCCESS;
727 	uint8_t portn;
728 	uint16_t rd_ptr;
729 	uint16_t wr_ptr;
730 	uint16_t curr_rd_ptr;
731 	uint16_t curr_wr_ptr;
732 	uint32_t stall_cnt;
733 	uint32_t d0, d1, d2, d3, d4;
734 
735 	handle = nxgep->npi_handle;
736 	portn = nxgep->mac.portnum;
737 	*valid = B_TRUE;
738 
739 	if ((rs = npi_ipp_get_dfifo_rd_ptr(handle, portn, &rd_ptr))
740 	    != NPI_SUCCESS)
741 		goto fail;
742 	if ((rs = npi_ipp_get_dfifo_wr_ptr(handle, portn, &wr_ptr))
743 	    != NPI_SUCCESS)
744 		goto fail;
745 
746 	if (rd_ptr == wr_ptr) {
747 		*valid = B_FALSE; /* FIFO not stuck, so it's not a real ECCUE */
748 	} else {
749 		stall_cnt = 0;
750 		/*
751 		 * Check if the two pointers are moving, the ECCUE is invali
752 		 * if either pointer is moving, which indicates that the FIFO
753 		 * is functional.
754 		 */
755 		while (stall_cnt < 16) {
756 			if ((rs = npi_ipp_get_dfifo_rd_ptr(handle,
757 			    portn, &curr_rd_ptr)) != NPI_SUCCESS)
758 				goto fail;
759 			if ((rs = npi_ipp_get_dfifo_wr_ptr(handle,
760 			    portn, &curr_wr_ptr)) != NPI_SUCCESS)
761 				goto fail;
762 
763 			if (rd_ptr == curr_rd_ptr && wr_ptr == curr_wr_ptr) {
764 				stall_cnt++;
765 			} else {
766 				*valid = B_FALSE;
767 				break;
768 			}
769 		}
770 
771 		if (valid) {
772 			/*
773 			 * Further check to see if the ECCUE is valid. The
774 			 * error is real if the LSB of d4 is 1, which
775 			 * indicates that the data that has set the ECC
776 			 * error flag is the 16-byte internal control word.
777 			 */
778 			if ((rs = npi_ipp_read_dfifo(handle, portn, rd_ptr,
779 			    &d0, &d1, &d2, &d3, &d4)) != NPI_SUCCESS)
780 				goto fail;
781 			if ((d4 & 0x1) == 0)	/* Not the 1st line */
782 				*valid = B_FALSE;
783 		}
784 	}
785 	return (NXGE_OK);
786 fail:
787 	return (NXGE_ERROR | rs);
788 }
789