xref: /illumos-gate/usr/src/uts/common/io/nxge/nxge_hw.c (revision e3d11eee533a61e848d8b250c8db63f7cb855904)
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 /*
2289282175SSantwona Behera  * Copyright (c) 2006, 2010, Oracle and/or its affiliates. All rights reserved.
236f45ec7bSml29623  */
246f45ec7bSml29623 
256f45ec7bSml29623 #include <sys/nxge/nxge_impl.h>
266f45ec7bSml29623 
276f45ec7bSml29623 /*
286f45ec7bSml29623  * Tunable Receive Completion Ring Configuration B parameters.
296f45ec7bSml29623  */
306f45ec7bSml29623 uint16_t nxge_rx_pkt_thres;	/* 16 bits */
316f45ec7bSml29623 uint8_t nxge_rx_pkt_timeout;	/* 6 bits based on DMA clock divider */
326f45ec7bSml29623 
336f45ec7bSml29623 lb_property_t lb_normal = {normal, "normal", nxge_lb_normal};
346f45ec7bSml29623 lb_property_t lb_external10g = {external, "external10g", nxge_lb_ext10g};
356f45ec7bSml29623 lb_property_t lb_external1000 = {external, "external1000", nxge_lb_ext1000};
366f45ec7bSml29623 lb_property_t lb_external100 = {external, "external100", nxge_lb_ext100};
376f45ec7bSml29623 lb_property_t lb_external10 = {external, "external10", nxge_lb_ext10};
386f45ec7bSml29623 lb_property_t lb_phy10g = {internal, "phy10g", nxge_lb_phy10g};
396f45ec7bSml29623 lb_property_t lb_phy1000 = {internal, "phy1000", nxge_lb_phy1000};
406f45ec7bSml29623 lb_property_t lb_phy = {internal, "phy", nxge_lb_phy};
416f45ec7bSml29623 lb_property_t lb_serdes10g = {internal, "serdes10g", nxge_lb_serdes10g};
426f45ec7bSml29623 lb_property_t lb_serdes1000 = {internal, "serdes", nxge_lb_serdes1000};
436f45ec7bSml29623 lb_property_t lb_mac10g = {internal, "mac10g", nxge_lb_mac10g};
446f45ec7bSml29623 lb_property_t lb_mac1000 = {internal, "mac1000", nxge_lb_mac1000};
456f45ec7bSml29623 lb_property_t lb_mac = {internal, "mac10/100", nxge_lb_mac};
466f45ec7bSml29623 
476f45ec7bSml29623 uint32_t nxge_lb_dbg = 1;
486f45ec7bSml29623 void nxge_get_mii(p_nxge_t nxgep, p_mblk_t mp);
496f45ec7bSml29623 void nxge_put_mii(p_nxge_t nxgep, p_mblk_t mp);
50ee5416c9Syc148097 static nxge_status_t nxge_check_xaui_xfp(p_nxge_t nxgep);
516f45ec7bSml29623 
526f45ec7bSml29623 extern uint32_t nxge_rx_mode;
536f45ec7bSml29623 extern uint32_t nxge_jumbo_mtu;
544df55fdeSJanie Lu extern uint16_t	nxge_rdc_buf_offset;
556f45ec7bSml29623 
566f45ec7bSml29623 static void
576f45ec7bSml29623 nxge_rtrace_ioctl(p_nxge_t, queue_t *, mblk_t *, struct iocblk *);
586f45ec7bSml29623 
596f45ec7bSml29623 /* ARGSUSED */
60321febdeSsbehera nxge_status_t
nxge_global_reset(p_nxge_t nxgep)616f45ec7bSml29623 nxge_global_reset(p_nxge_t nxgep)
626f45ec7bSml29623 {
63321febdeSsbehera 	nxge_status_t	status = NXGE_OK;
64321febdeSsbehera 
656f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "==> nxge_global_reset"));
666f45ec7bSml29623 
67321febdeSsbehera 	if ((status = nxge_link_monitor(nxgep, LINK_MONITOR_STOP)) != NXGE_OK)
68321febdeSsbehera 		return (status);
696f45ec7bSml29623 	(void) nxge_intr_hw_disable(nxgep);
706f45ec7bSml29623 
716f45ec7bSml29623 	if ((nxgep->suspended) ||
726f45ec7bSml29623 	    ((nxgep->statsp->port_stats.lb_mode ==
736f45ec7bSml29623 	    nxge_lb_phy1000) ||
746f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode ==
756f45ec7bSml29623 	    nxge_lb_phy10g) ||
766f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode ==
776f45ec7bSml29623 	    nxge_lb_serdes1000) ||
786f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode ==
796f45ec7bSml29623 	    nxge_lb_serdes10g))) {
80321febdeSsbehera 		if ((status = nxge_link_init(nxgep)) != NXGE_OK)
81321febdeSsbehera 			return (status);
826f45ec7bSml29623 	}
83321febdeSsbehera 
84321febdeSsbehera 	if ((status = nxge_link_monitor(nxgep, LINK_MONITOR_START)) != NXGE_OK)
85321febdeSsbehera 		return (status);
86321febdeSsbehera 	if ((status = nxge_mac_init(nxgep)) != NXGE_OK)
87321febdeSsbehera 		return (status);
886f45ec7bSml29623 	(void) nxge_intr_hw_enable(nxgep);
896f45ec7bSml29623 
906f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "<== nxge_global_reset"));
91321febdeSsbehera 	return (status);
926f45ec7bSml29623 }
936f45ec7bSml29623 
946f45ec7bSml29623 /* ARGSUSED */
956f45ec7bSml29623 void
nxge_hw_id_init(p_nxge_t nxgep)966f45ec7bSml29623 nxge_hw_id_init(p_nxge_t nxgep)
976f45ec7bSml29623 {
986f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "==> nxge_hw_id_init"));
9948056c53SMichael Speer 
1006f45ec7bSml29623 	/*
1016f45ec7bSml29623 	 * Set up initial hardware parameters required such as mac mtu size.
1026f45ec7bSml29623 	 */
1036f45ec7bSml29623 	nxgep->mac.is_jumbo = B_FALSE;
10448056c53SMichael Speer 
1051bd6825cSml29623 	/*
1061bd6825cSml29623 	 * Set the maxframe size to 1522 (1518 + 4) to account for
1071bd6825cSml29623 	 * VLAN tagged packets.
1081bd6825cSml29623 	 */
1091bd6825cSml29623 	nxgep->mac.minframesize = NXGE_MIN_MAC_FRAMESIZE;	/* 64 */
1101bd6825cSml29623 	nxgep->mac.maxframesize = NXGE_MAX_MAC_FRAMESIZE;	/* 1522 */
1116f45ec7bSml29623 
11248056c53SMichael Speer 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "<== nxge_hw_id_init: maxframesize %d",
11348056c53SMichael Speer 	    nxgep->mac.maxframesize));
1146f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "<== nxge_hw_id_init"));
1156f45ec7bSml29623 }
1166f45ec7bSml29623 
1176f45ec7bSml29623 /* ARGSUSED */
1186f45ec7bSml29623 void
nxge_hw_init_niu_common(p_nxge_t nxgep)1196f45ec7bSml29623 nxge_hw_init_niu_common(p_nxge_t nxgep)
1206f45ec7bSml29623 {
1216f45ec7bSml29623 	p_nxge_hw_list_t hw_p;
1226f45ec7bSml29623 
1236f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "==> nxge_hw_init_niu_common"));
1246f45ec7bSml29623 
1256f45ec7bSml29623 	if ((hw_p = nxgep->nxge_hw_p) == NULL) {
1266f45ec7bSml29623 		return;
1276f45ec7bSml29623 	}
1286f45ec7bSml29623 	MUTEX_ENTER(&hw_p->nxge_cfg_lock);
1296f45ec7bSml29623 	if (hw_p->flags & COMMON_INIT_DONE) {
1306f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, MOD_CTL,
1316f45ec7bSml29623 		    "nxge_hw_init_niu_common"
1326f45ec7bSml29623 		    " already done for dip $%p function %d exiting",
1336f45ec7bSml29623 		    hw_p->parent_devp, nxgep->function_num));
1346f45ec7bSml29623 		MUTEX_EXIT(&hw_p->nxge_cfg_lock);
1356f45ec7bSml29623 		return;
1366f45ec7bSml29623 	}
1376f45ec7bSml29623 
1386f45ec7bSml29623 	hw_p->flags = COMMON_INIT_START;
1396f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MOD_CTL, "nxge_hw_init_niu_common"
1406f45ec7bSml29623 	    " Started for device id %x with function %d",
1416f45ec7bSml29623 	    hw_p->parent_devp, nxgep->function_num));
1426f45ec7bSml29623 
1436f45ec7bSml29623 	/* per neptune common block init */
1446f45ec7bSml29623 	(void) nxge_fflp_hw_reset(nxgep);
1456f45ec7bSml29623 
1464df55fdeSJanie Lu 	if (nxgep->niu_hw_type != NIU_HW_TYPE_RF) {
1474df55fdeSJanie Lu 		switch (nxge_rdc_buf_offset) {
1484df55fdeSJanie Lu 		case SW_OFFSET_NO_OFFSET:
1494df55fdeSJanie Lu 		case SW_OFFSET_64:
1504df55fdeSJanie Lu 		case SW_OFFSET_128:
1514df55fdeSJanie Lu 			break;
1524df55fdeSJanie Lu 		default:
1534df55fdeSJanie Lu 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
1544df55fdeSJanie Lu 			    "nxge_hw_init_niu_common: Unsupported RDC buffer"
1554df55fdeSJanie Lu 			    " offset code %d, setting to %d",
1564df55fdeSJanie Lu 			    nxge_rdc_buf_offset, SW_OFFSET_NO_OFFSET));
1574df55fdeSJanie Lu 			nxge_rdc_buf_offset = SW_OFFSET_NO_OFFSET;
1584df55fdeSJanie Lu 			break;
1594df55fdeSJanie Lu 		}
1604df55fdeSJanie Lu 	} else {
1614df55fdeSJanie Lu 		switch (nxge_rdc_buf_offset) {
1624df55fdeSJanie Lu 		case SW_OFFSET_NO_OFFSET:
1634df55fdeSJanie Lu 		case SW_OFFSET_64:
1644df55fdeSJanie Lu 		case SW_OFFSET_128:
1654df55fdeSJanie Lu 		case SW_OFFSET_192:
1664df55fdeSJanie Lu 		case SW_OFFSET_256:
1674df55fdeSJanie Lu 		case SW_OFFSET_320:
1684df55fdeSJanie Lu 		case SW_OFFSET_384:
1694df55fdeSJanie Lu 		case SW_OFFSET_448:
1704df55fdeSJanie Lu 			break;
1714df55fdeSJanie Lu 		default:
1724df55fdeSJanie Lu 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
1734df55fdeSJanie Lu 			    "nxge_hw_init_niu_common: Unsupported RDC buffer"
1744df55fdeSJanie Lu 			    " offset code %d, setting to %d",
1754df55fdeSJanie Lu 			    nxge_rdc_buf_offset, SW_OFFSET_NO_OFFSET));
1764df55fdeSJanie Lu 			nxge_rdc_buf_offset = SW_OFFSET_NO_OFFSET;
1774df55fdeSJanie Lu 			break;
1784df55fdeSJanie Lu 		}
1794df55fdeSJanie Lu 	}
1804df55fdeSJanie Lu 
1816f45ec7bSml29623 	hw_p->flags = COMMON_INIT_DONE;
1826f45ec7bSml29623 	MUTEX_EXIT(&hw_p->nxge_cfg_lock);
1836f45ec7bSml29623 
1846f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, MOD_CTL, "nxge_hw_init_niu_common"
1856f45ec7bSml29623 	    " Done for device id %x with function %d",
1866f45ec7bSml29623 	    hw_p->parent_devp, nxgep->function_num));
1876f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "<== nxge_hw_init_niu_common"));
1886f45ec7bSml29623 }
1896f45ec7bSml29623 
1906f45ec7bSml29623 uint_t
nxge_intr(char * arg1,char * arg2)191*e3d11eeeSToomas Soome nxge_intr(char *arg1, char *arg2)
1926f45ec7bSml29623 {
1936f45ec7bSml29623 	p_nxge_ldv_t ldvp = (p_nxge_ldv_t)arg1;
1946f45ec7bSml29623 	p_nxge_t nxgep = (p_nxge_t)arg2;
1956f45ec7bSml29623 	uint_t serviced = DDI_INTR_UNCLAIMED;
1966f45ec7bSml29623 	uint8_t ldv;
1976f45ec7bSml29623 	npi_handle_t handle;
1986f45ec7bSml29623 	p_nxge_ldgv_t ldgvp;
1996f45ec7bSml29623 	p_nxge_ldg_t ldgp, t_ldgp;
2006f45ec7bSml29623 	p_nxge_ldv_t t_ldvp;
2016f45ec7bSml29623 	uint64_t vector0 = 0, vector1 = 0, vector2 = 0;
2026f45ec7bSml29623 	int i, j, nldvs, nintrs = 1;
2036f45ec7bSml29623 	npi_status_t rs = NPI_SUCCESS;
2046f45ec7bSml29623 
2054df3b64dSToomas Soome 	VERIFY(ldvp != NULL);
2064df3b64dSToomas Soome 
2076f45ec7bSml29623 	/* DDI interface returns second arg as NULL (n2 niumx driver) !!! */
2086f45ec7bSml29623 	if (arg2 == NULL || (void *) ldvp->nxgep != arg2) {
2096f45ec7bSml29623 		nxgep = ldvp->nxgep;
2106f45ec7bSml29623 	}
2116f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "==> nxge_intr"));
2126f45ec7bSml29623 
2136f45ec7bSml29623 	if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
2146f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, INT_CTL,
2156f45ec7bSml29623 		    "<== nxge_intr: not initialized 0x%x", serviced));
2166f45ec7bSml29623 		return (serviced);
2176f45ec7bSml29623 	}
2186f45ec7bSml29623 
2196f45ec7bSml29623 	ldgvp = nxgep->ldgvp;
2206f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "==> nxge_intr: ldgvp $%p", ldgvp));
2216f45ec7bSml29623 	if (ldvp == NULL && ldgvp) {
2226f45ec7bSml29623 		t_ldvp = ldvp = ldgvp->ldvp;
2236f45ec7bSml29623 	}
2246f45ec7bSml29623 	if (ldvp) {
2256f45ec7bSml29623 		ldgp = t_ldgp = ldvp->ldgp;
2266f45ec7bSml29623 	}
2276f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "==> nxge_intr: "
2286f45ec7bSml29623 	    "ldgvp $%p ldvp $%p ldgp $%p", ldgvp, ldvp, ldgp));
2296f45ec7bSml29623 	if (ldgvp == NULL || ldvp == NULL || ldgp == NULL) {
2306f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, INT_CTL, "==> nxge_intr: "
2316f45ec7bSml29623 		    "ldgvp $%p ldvp $%p ldgp $%p", ldgvp, ldvp, ldgp));
2326f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, INT_CTL, "<== nxge_intr: not ready"));
2336f45ec7bSml29623 		return (DDI_INTR_UNCLAIMED);
2346f45ec7bSml29623 	}
2356f45ec7bSml29623 	/*
2366f45ec7bSml29623 	 * This interrupt handler will have to go through all the logical
2376f45ec7bSml29623 	 * devices to find out which logical device interrupts us and then call
2386f45ec7bSml29623 	 * its handler to process the events.
2396f45ec7bSml29623 	 */
2406f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
2416f45ec7bSml29623 	t_ldgp = ldgp;
2426f45ec7bSml29623 	t_ldvp = ldgp->ldvp;
2436f45ec7bSml29623 
2446f45ec7bSml29623 	nldvs = ldgp->nldvs;
2456f45ec7bSml29623 
2466f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "==> nxge_intr: #ldvs %d #intrs %d",
2476f45ec7bSml29623 	    nldvs, ldgvp->ldg_intrs));
2486f45ec7bSml29623 
2496f45ec7bSml29623 	serviced = DDI_INTR_CLAIMED;
2506f45ec7bSml29623 	for (i = 0; i < nintrs; i++, t_ldgp++) {
2516f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, INT_CTL, "==> nxge_intr(%d): #ldvs %d "
2526f45ec7bSml29623 		    " #intrs %d", i, nldvs, nintrs));
2536f45ec7bSml29623 		/* Get this group's flag bits.  */
2546f45ec7bSml29623 		rs = npi_ldsv_ldfs_get(handle, t_ldgp->ldg,
2556f45ec7bSml29623 		    &vector0, &vector1, &vector2);
2566f45ec7bSml29623 		if (rs) {
2576f45ec7bSml29623 			continue;
2586f45ec7bSml29623 		}
2596f45ec7bSml29623 		if (!vector0 && !vector1 && !vector2) {
2606f45ec7bSml29623 			NXGE_DEBUG_MSG((nxgep, INT_CTL, "==> nxge_intr: "
2616f45ec7bSml29623 			    "no interrupts on group %d", t_ldgp->ldg));
2626f45ec7bSml29623 			continue;
2636f45ec7bSml29623 		}
2646f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, INT_CTL, "==> nxge_intr: "
2656f45ec7bSml29623 		    "vector0 0x%llx vector1 0x%llx vector2 0x%llx",
2666f45ec7bSml29623 		    vector0, vector1, vector2));
2676f45ec7bSml29623 		nldvs = t_ldgp->nldvs;
2686f45ec7bSml29623 		for (j = 0; j < nldvs; j++, t_ldvp++) {
2696f45ec7bSml29623 			/*
2706f45ec7bSml29623 			 * Call device's handler if flag bits are on.
2716f45ec7bSml29623 			 */
2726f45ec7bSml29623 			ldv = t_ldvp->ldv;
2736f45ec7bSml29623 			if (((ldv < NXGE_MAC_LD_START) &&
2746f45ec7bSml29623 			    (LDV_ON(ldv, vector0) |
2756f45ec7bSml29623 			    (LDV_ON(ldv, vector1)))) ||
2766f45ec7bSml29623 			    (ldv >= NXGE_MAC_LD_START &&
2776f45ec7bSml29623 			    ((LDV2_ON_1(ldv, vector2)) ||
2786f45ec7bSml29623 			    (LDV2_ON_2(ldv, vector2))))) {
2796f45ec7bSml29623 				(void) (t_ldvp->ldv_intr_handler)(
2806f45ec7bSml29623 				    (caddr_t)t_ldvp, arg2);
2816f45ec7bSml29623 				NXGE_DEBUG_MSG((nxgep, INT_CTL,
2826f45ec7bSml29623 				    "==> nxge_intr: "
2836f45ec7bSml29623 				    "calling device %d #ldvs %d #intrs %d",
2846f45ec7bSml29623 				    j, nldvs, nintrs));
2856f45ec7bSml29623 			}
2866f45ec7bSml29623 		}
2876f45ec7bSml29623 	}
2886f45ec7bSml29623 
2896f45ec7bSml29623 	t_ldgp = ldgp;
2906f45ec7bSml29623 	for (i = 0; i < nintrs; i++, t_ldgp++) {
2916f45ec7bSml29623 		/* rearm group interrupts */
2926f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, INT_CTL, "==> nxge_intr: arm "
2936f45ec7bSml29623 		    "group %d", t_ldgp->ldg));
2946f45ec7bSml29623 		(void) npi_intr_ldg_mgmt_set(handle, t_ldgp->ldg,
2956f45ec7bSml29623 		    t_ldgp->arm, t_ldgp->ldg_timer);
2966f45ec7bSml29623 	}
2976f45ec7bSml29623 
2986f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_intr: serviced 0x%x",
2996f45ec7bSml29623 	    serviced));
3006f45ec7bSml29623 	return (serviced);
3016f45ec7bSml29623 }
3026f45ec7bSml29623 
30300161856Syc148097 
30400161856Syc148097 /*
30500161856Syc148097  * XFP Related Status Register Values Under 3 Different Conditions
30600161856Syc148097  *
30700161856Syc148097  * -------------+-------------------------+-------------------------
3080cad6a5fSyc148097  * 		|   Intel XFP and Avago   |	 Picolight XFP
30900161856Syc148097  * -------------+---------+---------------+---------+---------------
31000161856Syc148097  *		| STATUS0 | TX_ALARM_STAT | STATUS0 | TX_ALARM_STAT
31100161856Syc148097  * -------------+---------+---------------+---------+---------------
31200161856Syc148097  *	No XFP  | 0x639C  |      0x40     | 0x639C  |      0x40
31300161856Syc148097  * -------------+---------+---------------+---------+---------------
31400161856Syc148097  * XFP,linkdown | 0x43BC  |      0x40     | 0x639C  |      0x40
31500161856Syc148097  * -------------+---------+---------------+---------+---------------
31600161856Syc148097  * XFP,linkup   | 0x03FC  |      0x0      | 0x03FC  |      0x0
31700161856Syc148097  * -------------+---------+---------------+---------+---------------
31800161856Syc148097  * Note:
31900161856Syc148097  *      STATUS0         = BCM8704_USER_ANALOG_STATUS0_REG
32000161856Syc148097  *      TX_ALARM_STAT   = BCM8704_USER_TX_ALARM_STATUS_REG
32100161856Syc148097  */
3226f45ec7bSml29623 /* ARGSUSED */
323ee5416c9Syc148097 static nxge_status_t
nxge_check_xaui_xfp(p_nxge_t nxgep)324ee5416c9Syc148097 nxge_check_xaui_xfp(p_nxge_t nxgep)
325ee5416c9Syc148097 {
326ee5416c9Syc148097 	nxge_status_t	status = NXGE_OK;
327ee5416c9Syc148097 	uint8_t		phy_port_addr;
328ee5416c9Syc148097 	uint16_t	val;
329ee5416c9Syc148097 	uint16_t	val1;
330ee5416c9Syc148097 	uint8_t		portn;
331ee5416c9Syc148097 
332ee5416c9Syc148097 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "==> nxge_check_xaui_xfp"));
333ee5416c9Syc148097 
334ee5416c9Syc148097 	portn = nxgep->mac.portnum;
335ee5416c9Syc148097 	phy_port_addr = nxgep->statsp->mac_stats.xcvr_portn;
336ee5416c9Syc148097 
33700161856Syc148097 	/*
33800161856Syc148097 	 * Keep the val1 code even though it is not used. Could be
33900161856Syc148097 	 * used to differenciate the "No XFP" case and "XFP,linkdown"
34000161856Syc148097 	 * case when a Intel XFP is used.
34100161856Syc148097 	 */
342ee5416c9Syc148097 	if ((status = nxge_mdio_read(nxgep, phy_port_addr,
343ee5416c9Syc148097 	    BCM8704_USER_DEV3_ADDR,
344ee5416c9Syc148097 	    BCM8704_USER_ANALOG_STATUS0_REG, &val)) == NXGE_OK) {
345ee5416c9Syc148097 		status = nxge_mdio_read(nxgep, phy_port_addr,
346ee5416c9Syc148097 		    BCM8704_USER_DEV3_ADDR,
347ee5416c9Syc148097 		    BCM8704_USER_TX_ALARM_STATUS_REG, &val1);
348ee5416c9Syc148097 	}
34900161856Syc148097 
350ee5416c9Syc148097 	if (status != NXGE_OK) {
351b37cc459SToomas Soome 		NXGE_FM_REPORT_ERROR(nxgep, portn, 0,
352ee5416c9Syc148097 		    NXGE_FM_EREPORT_XAUI_ERR);
35300161856Syc148097 		if (DDI_FM_EREPORT_CAP(nxgep->fm_capabilities)) {
354ee5416c9Syc148097 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
355ee5416c9Syc148097 			    "XAUI is bad or absent on port<%d>\n", portn));
35600161856Syc148097 		}
3570cad6a5fSyc148097 #ifdef NXGE_DEBUG
3580cad6a5fSyc148097 	/*
3590cad6a5fSyc148097 	 * As a workaround for CR6693529, do not execute this block of
3600cad6a5fSyc148097 	 * code for non-debug driver. When a Picolight XFP transceiver
3610cad6a5fSyc148097 	 * is used, register BCM8704_USER_ANALOG_STATUS0_REG returns
3620cad6a5fSyc148097 	 * the same 0x639C value in normal link down case, which causes
3630cad6a5fSyc148097 	 * false FMA messages and link reconnection problem.
3640cad6a5fSyc148097 	 */
365ee5416c9Syc148097 	} else if (nxgep->mac.portmode == PORT_10G_FIBER) {
366ee5416c9Syc148097 		/*
367f6485eecSyc148097 		 * 0x03FC = 0000 0011 1111 1100 (XFP is normal)
368f6485eecSyc148097 		 * 0x639C = 0110 0011 1001 1100 (XFP has problem)
369ee5416c9Syc148097 		 * bit14 = 1: PDM loss-of-light indicator
370ee5416c9Syc148097 		 * bit13 = 1: PDM Rx loss-of-signal
371ee5416c9Syc148097 		 * bit6  = 0: Light is NOT ok
372ee5416c9Syc148097 		 * bit5  = 0: PMD Rx signal is NOT ok
373ee5416c9Syc148097 		 */
374f6485eecSyc148097 		if (val == 0x639C) {
375ee5416c9Syc148097 			NXGE_FM_REPORT_ERROR(nxgep, portn, NULL,
376ee5416c9Syc148097 			    NXGE_FM_EREPORT_XFP_ERR);
37700161856Syc148097 			if (DDI_FM_EREPORT_CAP(nxgep->fm_capabilities)) {
378ee5416c9Syc148097 				NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
37900161856Syc148097 				    "XFP is bad or absent on port<%d>\n",
38000161856Syc148097 				    portn));
38100161856Syc148097 			}
382ee5416c9Syc148097 			status = NXGE_ERROR;
383ee5416c9Syc148097 		}
3840cad6a5fSyc148097 #endif
385ee5416c9Syc148097 	}
386ee5416c9Syc148097 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_check_xaui_xfp"));
387ee5416c9Syc148097 	return (status);
388ee5416c9Syc148097 }
389ee5416c9Syc148097 
390ee5416c9Syc148097 
391ee5416c9Syc148097 /* ARGSUSED */
3926f45ec7bSml29623 uint_t
nxge_syserr_intr(void * arg1,void * arg2)3936f45ec7bSml29623 nxge_syserr_intr(void *arg1, void *arg2)
3946f45ec7bSml29623 {
3956f45ec7bSml29623 	p_nxge_ldv_t ldvp = (p_nxge_ldv_t)arg1;
3966f45ec7bSml29623 	p_nxge_t nxgep = (p_nxge_t)arg2;
3976f45ec7bSml29623 	p_nxge_ldg_t ldgp = NULL;
3986f45ec7bSml29623 	npi_handle_t handle;
3996f45ec7bSml29623 	sys_err_stat_t estat;
4006f45ec7bSml29623 	uint_t serviced = DDI_INTR_UNCLAIMED;
4016f45ec7bSml29623 
4026f45ec7bSml29623 	if (arg1 == NULL && arg2 == NULL) {
4036f45ec7bSml29623 		return (serviced);
4046f45ec7bSml29623 	}
4056f45ec7bSml29623 	if (arg2 == NULL || ((ldvp != NULL && (void *) ldvp->nxgep != arg2))) {
4066f45ec7bSml29623 		if (ldvp != NULL) {
4076f45ec7bSml29623 			nxgep = ldvp->nxgep;
4086f45ec7bSml29623 		}
4096f45ec7bSml29623 	}
4106f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, SYSERR_CTL,
4116f45ec7bSml29623 	    "==> nxge_syserr_intr: arg2 $%p arg1 $%p", nxgep, ldvp));
4126f45ec7bSml29623 	if (ldvp != NULL && ldvp->use_timer == B_FALSE) {
4136f45ec7bSml29623 		ldgp = ldvp->ldgp;
4146f45ec7bSml29623 		if (ldgp == NULL) {
4156f45ec7bSml29623 			NXGE_ERROR_MSG((nxgep, SYSERR_CTL,
4166f45ec7bSml29623 			    "<== nxge_syserrintr(no logical group): "
4176f45ec7bSml29623 			    "arg2 $%p arg1 $%p", nxgep, ldvp));
4186f45ec7bSml29623 			return (DDI_INTR_UNCLAIMED);
4196f45ec7bSml29623 		}
4206f45ec7bSml29623 		/*
4216f45ec7bSml29623 		 * Get the logical device state if the function uses interrupt.
4226f45ec7bSml29623 		 */
4236f45ec7bSml29623 	}
4246f45ec7bSml29623 
4256f45ec7bSml29623 	/* This interrupt handler is for system error interrupts.  */
4266f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
4276f45ec7bSml29623 	estat.value = 0;
4286f45ec7bSml29623 	(void) npi_fzc_sys_err_stat_get(handle, &estat);
4296f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, SYSERR_CTL,
4306f45ec7bSml29623 	    "==> nxge_syserr_intr: device error 0x%016llx", estat.value));
4316f45ec7bSml29623 
4326f45ec7bSml29623 	if (estat.bits.ldw.smx) {
4336f45ec7bSml29623 		/* SMX */
4346f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4356f45ec7bSml29623 		    "==> nxge_syserr_intr: device error - SMX"));
4366f45ec7bSml29623 	} else if (estat.bits.ldw.mac) {
4376f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4386f45ec7bSml29623 		    "==> nxge_syserr_intr: device error - MAC"));
4396f45ec7bSml29623 		/*
4406f45ec7bSml29623 		 * There is nothing to be done here. All MAC errors go to per
4416f45ec7bSml29623 		 * MAC port interrupt. MIF interrupt is the only MAC sub-block
4426f45ec7bSml29623 		 * that can generate status here. MIF status reported will be
4436f45ec7bSml29623 		 * ignored here. It is checked by per port timer instead.
4446f45ec7bSml29623 		 */
4456f45ec7bSml29623 	} else if (estat.bits.ldw.ipp) {
4466f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, NXGE_ERR_CTL,
4476f45ec7bSml29623 		    "==> nxge_syserr_intr: device error - IPP"));
4486f45ec7bSml29623 		(void) nxge_ipp_handle_sys_errors(nxgep);
4496f45ec7bSml29623 	} else if (estat.bits.ldw.zcp) {
4506f45ec7bSml29623 		/* ZCP */
451f6485eecSyc148097 		NXGE_DEBUG_MSG((nxgep, NXGE_ERR_CTL,
4526f45ec7bSml29623 		    "==> nxge_syserr_intr: device error - ZCP"));
4536f45ec7bSml29623 		(void) nxge_zcp_handle_sys_errors(nxgep);
4546f45ec7bSml29623 	} else if (estat.bits.ldw.tdmc) {
4556f45ec7bSml29623 		/* TDMC */
4566f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4576f45ec7bSml29623 		    "==> nxge_syserr_intr: device error - TDMC"));
4586f45ec7bSml29623 		/*
4596f45ec7bSml29623 		 * There is no TDMC system errors defined in the PRM. All TDMC
4606f45ec7bSml29623 		 * channel specific errors are reported on a per channel basis.
4616f45ec7bSml29623 		 */
4626f45ec7bSml29623 	} else if (estat.bits.ldw.rdmc) {
4636f45ec7bSml29623 		/* RDMC */
4646f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4656f45ec7bSml29623 		    "==> nxge_syserr_intr: device error - RDMC"));
4666f45ec7bSml29623 		(void) nxge_rxdma_handle_sys_errors(nxgep);
4676f45ec7bSml29623 	} else if (estat.bits.ldw.txc) {
4686f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4696f45ec7bSml29623 		    "==> nxge_syserr_intr: device error - TXC"));
4706f45ec7bSml29623 		(void) nxge_txc_handle_sys_errors(nxgep);
4716f45ec7bSml29623 	} else if ((nxgep->niu_type != N2_NIU) && estat.bits.ldw.peu) {
4726f45ec7bSml29623 		/* PCI-E */
4736f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4746f45ec7bSml29623 		    "==> nxge_syserr_intr: device error - PCI-E"));
4756f45ec7bSml29623 	} else if (estat.bits.ldw.meta1) {
4766f45ec7bSml29623 		/* META1 */
4776f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4786f45ec7bSml29623 		    "==> nxge_syserr_intr: device error - META1"));
4796f45ec7bSml29623 	} else if (estat.bits.ldw.meta2) {
4806f45ec7bSml29623 		/* META2 */
4816f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4826f45ec7bSml29623 		    "==> nxge_syserr_intr: device error - META2"));
4836f45ec7bSml29623 	} else if (estat.bits.ldw.fflp) {
4846f45ec7bSml29623 		/* FFLP */
4856f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
4866f45ec7bSml29623 		    "==> nxge_syserr_intr: device error - FFLP"));
4876f45ec7bSml29623 		(void) nxge_fflp_handle_sys_errors(nxgep);
4886f45ec7bSml29623 	}
489ee5416c9Syc148097 
49000161856Syc148097 	/*
49100161856Syc148097 	 * nxge_check_xaui_xfg checks XAUI for all of the following
49200161856Syc148097 	 * portmodes, but checks XFP only if portmode == PORT_10G_FIBER.
49300161856Syc148097 	 */
494ee5416c9Syc148097 	if (nxgep->mac.portmode == PORT_10G_FIBER ||
49500161856Syc148097 	    nxgep->mac.portmode == PORT_10G_COPPER ||
49600161856Syc148097 	    nxgep->mac.portmode == PORT_10G_TN1010 ||
49700161856Syc148097 	    nxgep->mac.portmode == PORT_1G_TN1010) {
498ee5416c9Syc148097 		if (nxge_check_xaui_xfp(nxgep) != NXGE_OK) {
499ee5416c9Syc148097 			NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
500ee5416c9Syc148097 			    "==> nxge_syserr_intr: device error - XAUI"));
501ee5416c9Syc148097 		}
502ee5416c9Syc148097 	}
503ee5416c9Syc148097 
5046f45ec7bSml29623 	serviced = DDI_INTR_CLAIMED;
5056f45ec7bSml29623 
5066f45ec7bSml29623 	if (ldgp != NULL && ldvp != NULL && ldgp->nldvs == 1 &&
5076f45ec7bSml29623 	    !ldvp->use_timer) {
5086f45ec7bSml29623 		(void) npi_intr_ldg_mgmt_set(handle, ldgp->ldg,
5096f45ec7bSml29623 		    B_TRUE, ldgp->ldg_timer);
5106f45ec7bSml29623 	}
5116f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, SYSERR_CTL, "<== nxge_syserr_intr"));
5126f45ec7bSml29623 	return (serviced);
5136f45ec7bSml29623 }
5146f45ec7bSml29623 
5156f45ec7bSml29623 /* ARGSUSED */
5166f45ec7bSml29623 void
nxge_intr_hw_enable(p_nxge_t nxgep)5176f45ec7bSml29623 nxge_intr_hw_enable(p_nxge_t nxgep)
5186f45ec7bSml29623 {
5196f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "==> nxge_intr_hw_enable"));
5206f45ec7bSml29623 	(void) nxge_intr_mask_mgmt_set(nxgep, B_TRUE);
5216f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_intr_hw_enable"));
5226f45ec7bSml29623 }
5236f45ec7bSml29623 
5246f45ec7bSml29623 /* ARGSUSED */
5256f45ec7bSml29623 void
nxge_intr_hw_disable(p_nxge_t nxgep)5266f45ec7bSml29623 nxge_intr_hw_disable(p_nxge_t nxgep)
5276f45ec7bSml29623 {
5286f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "==> nxge_intr_hw_disable"));
5296f45ec7bSml29623 	(void) nxge_intr_mask_mgmt_set(nxgep, B_FALSE);
5306f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_intr_hw_disable"));
5316f45ec7bSml29623 }
5326f45ec7bSml29623 
5336f45ec7bSml29623 /* ARGSUSED */
5346f45ec7bSml29623 void
nxge_rx_hw_blank(void * arg,time_t ticks,uint_t count)5356f45ec7bSml29623 nxge_rx_hw_blank(void *arg, time_t ticks, uint_t count)
5366f45ec7bSml29623 {
5376f45ec7bSml29623 	p_nxge_t nxgep = (p_nxge_t)arg;
5386f45ec7bSml29623 	uint8_t channel;
5396f45ec7bSml29623 	npi_handle_t handle;
5406f45ec7bSml29623 	p_nxge_ldgv_t ldgvp;
5416f45ec7bSml29623 	p_nxge_ldv_t ldvp;
5426f45ec7bSml29623 	int i;
5436f45ec7bSml29623 
5446f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "==> nxge_rx_hw_blank"));
5456f45ec7bSml29623 	handle = NXGE_DEV_NPI_HANDLE(nxgep);
5466f45ec7bSml29623 
5476f45ec7bSml29623 	if ((ldgvp = nxgep->ldgvp) == NULL) {
5486f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, INT_CTL,
5496f45ec7bSml29623 		    "<== nxge_rx_hw_blank (not enabled)"));
5506f45ec7bSml29623 		return;
5516f45ec7bSml29623 	}
5526f45ec7bSml29623 	ldvp = nxgep->ldgvp->ldvp;
5536f45ec7bSml29623 	if (ldvp == NULL) {
5546f45ec7bSml29623 		return;
5556f45ec7bSml29623 	}
5566f45ec7bSml29623 	for (i = 0; i < ldgvp->nldvs; i++, ldvp++) {
5576f45ec7bSml29623 		if (ldvp->is_rxdma) {
5586f45ec7bSml29623 			channel = ldvp->channel;
5596f45ec7bSml29623 			(void) npi_rxdma_cfg_rdc_rcr_threshold(handle,
5606f45ec7bSml29623 			    channel, count);
5616f45ec7bSml29623 			(void) npi_rxdma_cfg_rdc_rcr_timeout(handle,
5626f45ec7bSml29623 			    channel, ticks);
5636f45ec7bSml29623 		}
5646f45ec7bSml29623 	}
5656f45ec7bSml29623 
5666f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, INT_CTL, "<== nxge_rx_hw_blank"));
5676f45ec7bSml29623 }
5686f45ec7bSml29623 
5696f45ec7bSml29623 /* ARGSUSED */
5706f45ec7bSml29623 void
nxge_hw_stop(p_nxge_t nxgep)5716f45ec7bSml29623 nxge_hw_stop(p_nxge_t nxgep)
5726f45ec7bSml29623 {
5736f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "==> nxge_hw_stop"));
5746f45ec7bSml29623 
5756f45ec7bSml29623 	(void) nxge_tx_mac_disable(nxgep);
5766f45ec7bSml29623 	(void) nxge_rx_mac_disable(nxgep);
5776f45ec7bSml29623 	(void) nxge_txdma_hw_mode(nxgep, NXGE_DMA_STOP);
5786f45ec7bSml29623 	(void) nxge_rxdma_hw_mode(nxgep, NXGE_DMA_STOP);
5796f45ec7bSml29623 
5806f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "<== nxge_hw_stop"));
5816f45ec7bSml29623 }
5826f45ec7bSml29623 
5836f45ec7bSml29623 /* ARGSUSED */
5846f45ec7bSml29623 void
nxge_hw_ioctl(p_nxge_t nxgep,queue_t * wq,mblk_t * mp,struct iocblk * iocp)5856f45ec7bSml29623 nxge_hw_ioctl(p_nxge_t nxgep, queue_t *wq, mblk_t *mp, struct iocblk *iocp)
5866f45ec7bSml29623 {
5876f45ec7bSml29623 	int cmd;
5886f45ec7bSml29623 
5896f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL, "==> nxge_hw_ioctl"));
5906f45ec7bSml29623 
5916f45ec7bSml29623 	if (nxgep == NULL) {
5926f45ec7bSml29623 		miocnak(wq, mp, 0, EINVAL);
5936f45ec7bSml29623 		return;
5946f45ec7bSml29623 	}
5956f45ec7bSml29623 	iocp->ioc_error = 0;
5966f45ec7bSml29623 	cmd = iocp->ioc_cmd;
5976f45ec7bSml29623 
5986f45ec7bSml29623 	switch (cmd) {
5996f45ec7bSml29623 	default:
6006f45ec7bSml29623 		miocnak(wq, mp, 0, EINVAL);
6016f45ec7bSml29623 		return;
6026f45ec7bSml29623 
6036f45ec7bSml29623 	case NXGE_GET_MII:
6046f45ec7bSml29623 		nxge_get_mii(nxgep, mp->b_cont);
6056f45ec7bSml29623 		miocack(wq, mp, sizeof (uint16_t), 0);
6066f45ec7bSml29623 		break;
6076f45ec7bSml29623 
6086f45ec7bSml29623 	case NXGE_PUT_MII:
6096f45ec7bSml29623 		nxge_put_mii(nxgep, mp->b_cont);
6106f45ec7bSml29623 		miocack(wq, mp, 0, 0);
6116f45ec7bSml29623 		break;
6126f45ec7bSml29623 
6136f45ec7bSml29623 	case NXGE_GET64:
6146f45ec7bSml29623 		nxge_get64(nxgep, mp->b_cont);
6156f45ec7bSml29623 		miocack(wq, mp, sizeof (uint32_t), 0);
6166f45ec7bSml29623 		break;
6176f45ec7bSml29623 
6186f45ec7bSml29623 	case NXGE_PUT64:
6196f45ec7bSml29623 		nxge_put64(nxgep, mp->b_cont);
6206f45ec7bSml29623 		miocack(wq, mp, 0, 0);
6216f45ec7bSml29623 		break;
6226f45ec7bSml29623 
6236f45ec7bSml29623 	case NXGE_PUT_TCAM:
6246f45ec7bSml29623 		nxge_put_tcam(nxgep, mp->b_cont);
6256f45ec7bSml29623 		miocack(wq, mp, 0, 0);
6266f45ec7bSml29623 		break;
6276f45ec7bSml29623 
6286f45ec7bSml29623 	case NXGE_GET_TCAM:
6296f45ec7bSml29623 		nxge_get_tcam(nxgep, mp->b_cont);
6306f45ec7bSml29623 		miocack(wq, mp, 0, 0);
6316f45ec7bSml29623 		break;
6326f45ec7bSml29623 
6336f45ec7bSml29623 	case NXGE_TX_REGS_DUMP:
6346f45ec7bSml29623 		nxge_txdma_regs_dump_channels(nxgep);
6356f45ec7bSml29623 		miocack(wq, mp, 0, 0);
6366f45ec7bSml29623 		break;
6376f45ec7bSml29623 	case NXGE_RX_REGS_DUMP:
6386f45ec7bSml29623 		nxge_rxdma_regs_dump_channels(nxgep);
6396f45ec7bSml29623 		miocack(wq, mp, 0, 0);
6406f45ec7bSml29623 		break;
6416f45ec7bSml29623 	case NXGE_VIR_INT_REGS_DUMP:
6426f45ec7bSml29623 	case NXGE_INT_REGS_DUMP:
6436f45ec7bSml29623 		nxge_virint_regs_dump(nxgep);
6446f45ec7bSml29623 		miocack(wq, mp, 0, 0);
6456f45ec7bSml29623 		break;
6466f45ec7bSml29623 	case NXGE_RTRACE:
6476f45ec7bSml29623 		nxge_rtrace_ioctl(nxgep, wq, mp, iocp);
6486f45ec7bSml29623 		break;
6496f45ec7bSml29623 	}
6506f45ec7bSml29623 }
6516f45ec7bSml29623 
6526f45ec7bSml29623 /* ARGSUSED */
6536f45ec7bSml29623 void
nxge_loopback_ioctl(p_nxge_t nxgep,queue_t * wq,mblk_t * mp,struct iocblk * iocp)6546f45ec7bSml29623 nxge_loopback_ioctl(p_nxge_t nxgep, queue_t *wq, mblk_t *mp,
6556f45ec7bSml29623 	struct iocblk *iocp)
6566f45ec7bSml29623 {
6576f45ec7bSml29623 	p_lb_property_t lb_props;
6586f45ec7bSml29623 
6596f45ec7bSml29623 	size_t size;
6606f45ec7bSml29623 	int i;
6616f45ec7bSml29623 
6626f45ec7bSml29623 	if (mp->b_cont == NULL) {
6636f45ec7bSml29623 		miocnak(wq, mp, 0, EINVAL);
6646f45ec7bSml29623 	}
6656f45ec7bSml29623 	switch (iocp->ioc_cmd) {
6666f45ec7bSml29623 	case LB_GET_MODE:
6676f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, IOC_CTL, "NXGE_GET_LB_MODE command"));
6686f45ec7bSml29623 		if (nxgep != NULL) {
6696f45ec7bSml29623 			*(lb_info_sz_t *)mp->b_cont->b_rptr =
6706f45ec7bSml29623 			    nxgep->statsp->port_stats.lb_mode;
6716f45ec7bSml29623 			miocack(wq, mp, sizeof (nxge_lb_t), 0);
672ee5416c9Syc148097 		} else {
6736f45ec7bSml29623 			miocnak(wq, mp, 0, EINVAL);
674ee5416c9Syc148097 		}
6756f45ec7bSml29623 		break;
6766f45ec7bSml29623 	case LB_SET_MODE:
6776f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, IOC_CTL, "NXGE_SET_LB_MODE command"));
6786f45ec7bSml29623 		if (iocp->ioc_count != sizeof (uint32_t)) {
6796f45ec7bSml29623 			miocack(wq, mp, 0, 0);
6806f45ec7bSml29623 			break;
6816f45ec7bSml29623 		}
6826f45ec7bSml29623 		if ((nxgep != NULL) && nxge_set_lb(nxgep, wq, mp->b_cont)) {
6836f45ec7bSml29623 			miocack(wq, mp, 0, 0);
6846f45ec7bSml29623 		} else {
6856f45ec7bSml29623 			miocnak(wq, mp, 0, EPROTO);
6866f45ec7bSml29623 		}
6876f45ec7bSml29623 		break;
6886f45ec7bSml29623 	case LB_GET_INFO_SIZE:
6896f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, IOC_CTL, "LB_GET_INFO_SIZE command"));
6906f45ec7bSml29623 		if (nxgep != NULL) {
6916f45ec7bSml29623 			size = sizeof (lb_normal);
6926f45ec7bSml29623 			if (nxgep->statsp->mac_stats.cap_10gfdx) {
69300161856Syc148097 				/* TN1010 does not support external loopback */
69400161856Syc148097 				if (nxgep->mac.portmode != PORT_1G_TN1010 &&
69500161856Syc148097 				    nxgep->mac.portmode != PORT_10G_TN1010) {
6966f45ec7bSml29623 					size += sizeof (lb_external10g);
69700161856Syc148097 				}
6986f45ec7bSml29623 				size += sizeof (lb_mac10g);
699936117e2Ssbehera 				/* Publish PHY loopback if PHY is present */
700936117e2Ssbehera 				if (nxgep->mac.portmode == PORT_10G_COPPER ||
70100161856Syc148097 				    nxgep->mac.portmode == PORT_10G_TN1010 ||
702936117e2Ssbehera 				    nxgep->mac.portmode == PORT_10G_FIBER)
703936117e2Ssbehera 					size += sizeof (lb_phy10g);
7046f45ec7bSml29623 			}
70500161856Syc148097 
70600161856Syc148097 			/*
70700161856Syc148097 			 * Even if cap_10gfdx is false, we still do 10G
70800161856Syc148097 			 * serdes loopback as a part of SunVTS xnetlbtest
70900161856Syc148097 			 * internal loopback test.
71000161856Syc148097 			 */
711936117e2Ssbehera 			if (nxgep->mac.portmode == PORT_10G_FIBER ||
71289282175SSantwona Behera 			    nxgep->mac.portmode == PORT_10G_COPPER ||
71300161856Syc148097 			    nxgep->mac.portmode == PORT_10G_TN1010 ||
714936117e2Ssbehera 			    nxgep->mac.portmode == PORT_10G_SERDES)
715936117e2Ssbehera 				size += sizeof (lb_serdes10g);
716936117e2Ssbehera 
7176f45ec7bSml29623 			if (nxgep->statsp->mac_stats.cap_1000fdx) {
71800161856Syc148097 				/* TN1010 does not support external loopback */
71900161856Syc148097 				if (nxgep->mac.portmode != PORT_1G_TN1010 &&
72000161856Syc148097 				    nxgep->mac.portmode != PORT_10G_TN1010) {
7216f45ec7bSml29623 					size += sizeof (lb_external1000);
72200161856Syc148097 				}
7236f45ec7bSml29623 				size += sizeof (lb_mac1000);
7240cad6a5fSyc148097 				if (nxgep->mac.portmode == PORT_1G_COPPER ||
72500161856Syc148097 				    nxgep->mac.portmode == PORT_1G_TN1010 ||
7260cad6a5fSyc148097 				    nxgep->mac.portmode ==
7270cad6a5fSyc148097 				    PORT_1G_RGMII_FIBER)
7286f45ec7bSml29623 					size += sizeof (lb_phy1000);
7296f45ec7bSml29623 			}
7306f45ec7bSml29623 			if (nxgep->statsp->mac_stats.cap_100fdx)
7316f45ec7bSml29623 				size += sizeof (lb_external100);
7326f45ec7bSml29623 			if (nxgep->statsp->mac_stats.cap_10fdx)
7336f45ec7bSml29623 				size += sizeof (lb_external10);
734936117e2Ssbehera 			if (nxgep->mac.portmode == PORT_1G_FIBER ||
73500161856Syc148097 			    nxgep->mac.portmode == PORT_1G_TN1010 ||
736936117e2Ssbehera 			    nxgep->mac.portmode == PORT_1G_SERDES)
7376f45ec7bSml29623 				size += sizeof (lb_serdes1000);
7382e59129aSraghus 
7396f45ec7bSml29623 			*(lb_info_sz_t *)mp->b_cont->b_rptr = size;
7406f45ec7bSml29623 
7416f45ec7bSml29623 			NXGE_DEBUG_MSG((nxgep, IOC_CTL,
7426f45ec7bSml29623 			    "NXGE_GET_LB_INFO command: size %d", size));
7436f45ec7bSml29623 			miocack(wq, mp, sizeof (lb_info_sz_t), 0);
7446f45ec7bSml29623 		} else
7456f45ec7bSml29623 			miocnak(wq, mp, 0, EINVAL);
7466f45ec7bSml29623 		break;
7476f45ec7bSml29623 
7486f45ec7bSml29623 	case LB_GET_INFO:
7496f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, IOC_CTL, "NXGE_GET_LB_INFO command"));
7506f45ec7bSml29623 		if (nxgep != NULL) {
7516f45ec7bSml29623 			size = sizeof (lb_normal);
7526f45ec7bSml29623 			if (nxgep->statsp->mac_stats.cap_10gfdx) {
75300161856Syc148097 				/* TN1010 does not support external loopback */
75400161856Syc148097 				if (nxgep->mac.portmode != PORT_1G_TN1010 &&
75500161856Syc148097 				    nxgep->mac.portmode != PORT_10G_TN1010) {
7566f45ec7bSml29623 					size += sizeof (lb_external10g);
75700161856Syc148097 				}
7586f45ec7bSml29623 				size += sizeof (lb_mac10g);
759936117e2Ssbehera 				/* Publish PHY loopback if PHY is present */
760936117e2Ssbehera 				if (nxgep->mac.portmode == PORT_10G_COPPER ||
76100161856Syc148097 				    nxgep->mac.portmode == PORT_10G_TN1010 ||
762936117e2Ssbehera 				    nxgep->mac.portmode == PORT_10G_FIBER)
763936117e2Ssbehera 					size += sizeof (lb_phy10g);
7646f45ec7bSml29623 			}
765936117e2Ssbehera 			if (nxgep->mac.portmode == PORT_10G_FIBER ||
76689282175SSantwona Behera 			    nxgep->mac.portmode == PORT_10G_COPPER ||
76700161856Syc148097 			    nxgep->mac.portmode == PORT_10G_TN1010 ||
768936117e2Ssbehera 			    nxgep->mac.portmode == PORT_10G_SERDES)
769936117e2Ssbehera 				size += sizeof (lb_serdes10g);
770936117e2Ssbehera 
7716f45ec7bSml29623 			if (nxgep->statsp->mac_stats.cap_1000fdx) {
77200161856Syc148097 				/* TN1010 does not support external loopback */
77300161856Syc148097 				if (nxgep->mac.portmode != PORT_1G_TN1010 &&
77400161856Syc148097 				    nxgep->mac.portmode != PORT_10G_TN1010) {
7756f45ec7bSml29623 					size += sizeof (lb_external1000);
77600161856Syc148097 				}
7776f45ec7bSml29623 				size += sizeof (lb_mac1000);
7780cad6a5fSyc148097 				if (nxgep->mac.portmode == PORT_1G_COPPER ||
77900161856Syc148097 				    nxgep->mac.portmode == PORT_1G_TN1010 ||
7800cad6a5fSyc148097 				    nxgep->mac.portmode ==
7810cad6a5fSyc148097 				    PORT_1G_RGMII_FIBER)
7826f45ec7bSml29623 					size += sizeof (lb_phy1000);
7836f45ec7bSml29623 			}
7846f45ec7bSml29623 			if (nxgep->statsp->mac_stats.cap_100fdx)
7856f45ec7bSml29623 				size += sizeof (lb_external100);
78600161856Syc148097 
7876f45ec7bSml29623 			if (nxgep->statsp->mac_stats.cap_10fdx)
7886f45ec7bSml29623 				size += sizeof (lb_external10);
78900161856Syc148097 
790936117e2Ssbehera 			if (nxgep->mac.portmode == PORT_1G_FIBER ||
79100161856Syc148097 			    nxgep->mac.portmode == PORT_1G_TN1010 ||
792936117e2Ssbehera 			    nxgep->mac.portmode == PORT_1G_SERDES)
7936f45ec7bSml29623 				size += sizeof (lb_serdes1000);
7946f45ec7bSml29623 
7956f45ec7bSml29623 			NXGE_DEBUG_MSG((nxgep, IOC_CTL,
7966f45ec7bSml29623 			    "NXGE_GET_LB_INFO command: size %d", size));
7976f45ec7bSml29623 			if (size == iocp->ioc_count) {
7986f45ec7bSml29623 				i = 0;
7996f45ec7bSml29623 				lb_props = (p_lb_property_t)mp->b_cont->b_rptr;
8006f45ec7bSml29623 				lb_props[i++] = lb_normal;
80100161856Syc148097 
8026f45ec7bSml29623 				if (nxgep->statsp->mac_stats.cap_10gfdx) {
8036f45ec7bSml29623 					lb_props[i++] = lb_mac10g;
804936117e2Ssbehera 					if (nxgep->mac.portmode ==
805936117e2Ssbehera 					    PORT_10G_COPPER ||
806936117e2Ssbehera 					    nxgep->mac.portmode ==
80700161856Syc148097 					    PORT_10G_TN1010 ||
80800161856Syc148097 					    nxgep->mac.portmode ==
80900161856Syc148097 					    PORT_10G_FIBER) {
8106f45ec7bSml29623 						lb_props[i++] = lb_phy10g;
81100161856Syc148097 					}
81200161856Syc148097 					/* TN1010 does not support ext lb */
81300161856Syc148097 					if (nxgep->mac.portmode !=
81400161856Syc148097 					    PORT_10G_TN1010 &&
81500161856Syc148097 					    nxgep->mac.portmode !=
81600161856Syc148097 					    PORT_1G_TN1010) {
8176f45ec7bSml29623 						lb_props[i++] = lb_external10g;
8186f45ec7bSml29623 					}
81900161856Syc148097 				}
82000161856Syc148097 
821936117e2Ssbehera 				if (nxgep->mac.portmode == PORT_10G_FIBER ||
82289282175SSantwona Behera 				    nxgep->mac.portmode == PORT_10G_COPPER ||
82300161856Syc148097 				    nxgep->mac.portmode == PORT_10G_TN1010 ||
824936117e2Ssbehera 				    nxgep->mac.portmode == PORT_10G_SERDES)
825936117e2Ssbehera 					lb_props[i++] = lb_serdes10g;
826936117e2Ssbehera 
82700161856Syc148097 				if (nxgep->statsp->mac_stats.cap_1000fdx) {
82800161856Syc148097 					/* TN1010 does not support ext lb */
82900161856Syc148097 					if (nxgep->mac.portmode !=
83000161856Syc148097 					    PORT_10G_TN1010 &&
83100161856Syc148097 					    nxgep->mac.portmode !=
83200161856Syc148097 					    PORT_1G_TN1010) {
8336f45ec7bSml29623 						lb_props[i++] = lb_external1000;
83400161856Syc148097 					}
83500161856Syc148097 				}
83600161856Syc148097 
8376f45ec7bSml29623 				if (nxgep->statsp->mac_stats.cap_100fdx)
8386f45ec7bSml29623 					lb_props[i++] = lb_external100;
83900161856Syc148097 
8406f45ec7bSml29623 				if (nxgep->statsp->mac_stats.cap_10fdx)
8416f45ec7bSml29623 					lb_props[i++] = lb_external10;
84200161856Syc148097 
8436f45ec7bSml29623 				if (nxgep->statsp->mac_stats.cap_1000fdx)
8446f45ec7bSml29623 					lb_props[i++] = lb_mac1000;
84500161856Syc148097 
8460cad6a5fSyc148097 				if (nxgep->mac.portmode == PORT_1G_COPPER ||
84700161856Syc148097 				    nxgep->mac.portmode == PORT_1G_TN1010 ||
8480cad6a5fSyc148097 				    nxgep->mac.portmode ==
8490cad6a5fSyc148097 				    PORT_1G_RGMII_FIBER) {
8506f45ec7bSml29623 					if (nxgep->statsp->mac_stats.
8516f45ec7bSml29623 					    cap_1000fdx)
8526f45ec7bSml29623 						lb_props[i++] = lb_phy1000;
8530cad6a5fSyc148097 				} else if (nxgep->mac.portmode ==
8540cad6a5fSyc148097 				    PORT_1G_FIBER ||
8550cad6a5fSyc148097 				    nxgep->mac.portmode == PORT_1G_TN1010 ||
8560cad6a5fSyc148097 				    nxgep->mac.portmode == PORT_1G_SERDES) {
8576f45ec7bSml29623 					lb_props[i++] = lb_serdes1000;
8582e59129aSraghus 				}
8596f45ec7bSml29623 				miocack(wq, mp, size, 0);
8606f45ec7bSml29623 			} else
8616f45ec7bSml29623 				miocnak(wq, mp, 0, EINVAL);
8626f45ec7bSml29623 		} else {
8636f45ec7bSml29623 			miocnak(wq, mp, 0, EINVAL);
8646f45ec7bSml29623 			cmn_err(CE_NOTE, "!nxge_hw_ioctl: invalid command 0x%x",
8656f45ec7bSml29623 			    iocp->ioc_cmd);
8666f45ec7bSml29623 		}
8676f45ec7bSml29623 		break;
8686f45ec7bSml29623 	}
8696f45ec7bSml29623 }
8706f45ec7bSml29623 
8716f45ec7bSml29623 /*
8726f45ec7bSml29623  * DMA channel interfaces to access various channel specific
8736f45ec7bSml29623  * hardware functions.
8746f45ec7bSml29623  */
8756f45ec7bSml29623 /* ARGSUSED */
8766f45ec7bSml29623 void
nxge_rxdma_channel_put64(nxge_os_acc_handle_t handle,void * reg_addrp,uint32_t reg_base,uint16_t channel,uint64_t reg_data)8776f45ec7bSml29623 nxge_rxdma_channel_put64(nxge_os_acc_handle_t handle, void *reg_addrp,
8786f45ec7bSml29623 	uint32_t reg_base, uint16_t channel, uint64_t reg_data)
8796f45ec7bSml29623 {
8806f45ec7bSml29623 	uint64_t reg_offset;
8816f45ec7bSml29623 
8826f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, DMA_CTL, "<== nxge_rxdma_channel_put64"));
8836f45ec7bSml29623 
8846f45ec7bSml29623 	/*
8856f45ec7bSml29623 	 * Channel is assumed to be from 0 to the maximum DMA channel #. If we
8866f45ec7bSml29623 	 * use the virtual DMA CSR address space from the config space (in PCI
8876f45ec7bSml29623 	 * case), then the following code need to be use different offset
8886f45ec7bSml29623 	 * computation macro.
8896f45ec7bSml29623 	 */
8906f45ec7bSml29623 	reg_offset = reg_base + DMC_OFFSET(channel);
8916f45ec7bSml29623 	NXGE_PIO_WRITE64(handle, reg_addrp, reg_offset, reg_data);
8926f45ec7bSml29623 
8936f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, DMA_CTL, "<== nxge_rxdma_channel_put64"));
8946f45ec7bSml29623 }
8956f45ec7bSml29623 
8966f45ec7bSml29623 /* ARGSUSED */
8976f45ec7bSml29623 uint64_t
nxge_rxdma_channel_get64(nxge_os_acc_handle_t handle,void * reg_addrp,uint32_t reg_base,uint16_t channel)8986f45ec7bSml29623 nxge_rxdma_channel_get64(nxge_os_acc_handle_t handle, void *reg_addrp,
8996f45ec7bSml29623 	uint32_t reg_base, uint16_t channel)
9006f45ec7bSml29623 {
9016f45ec7bSml29623 	uint64_t reg_offset;
9026f45ec7bSml29623 
9036f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, DMA_CTL, "<== nxge_rxdma_channel_get64"));
9046f45ec7bSml29623 
9056f45ec7bSml29623 	/*
9066f45ec7bSml29623 	 * Channel is assumed to be from 0 to the maximum DMA channel #. If we
9076f45ec7bSml29623 	 * use the virtual DMA CSR address space from the config space (in PCI
9086f45ec7bSml29623 	 * case), then the following code need to be use different offset
9096f45ec7bSml29623 	 * computation macro.
9106f45ec7bSml29623 	 */
9116f45ec7bSml29623 	reg_offset = reg_base + DMC_OFFSET(channel);
9126f45ec7bSml29623 
9136f45ec7bSml29623 	NXGE_DEBUG_MSG((NULL, DMA_CTL, "<== nxge_rxdma_channel_get64"));
9146f45ec7bSml29623 
9156f45ec7bSml29623 	return (NXGE_PIO_READ64(handle, reg_addrp, reg_offset));
9166f45ec7bSml29623 }
9176f45ec7bSml29623 
9186f45ec7bSml29623 /* ARGSUSED */
9196f45ec7bSml29623 void
nxge_get32(p_nxge_t nxgep,p_mblk_t mp)9206f45ec7bSml29623 nxge_get32(p_nxge_t nxgep, p_mblk_t mp)
9216f45ec7bSml29623 {
9226f45ec7bSml29623 	nxge_os_acc_handle_t nxge_regh;
9236f45ec7bSml29623 
9246f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL, "nxge_get32"));
9256f45ec7bSml29623 	nxge_regh = nxgep->dev_regs->nxge_regh;
9266f45ec7bSml29623 
9276f45ec7bSml29623 	*(uint32_t *)mp->b_rptr = NXGE_PIO_READ32(nxge_regh,
9286f45ec7bSml29623 	    nxgep->dev_regs->nxge_regp, *(uint32_t *)mp->b_rptr);
9296f45ec7bSml29623 
9306f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL, "value = 0x%08X",
9316f45ec7bSml29623 	    *(uint32_t *)mp->b_rptr));
9326f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL, "nxge_get32"));
9336f45ec7bSml29623 }
9346f45ec7bSml29623 
9356f45ec7bSml29623 /* ARGSUSED */
9366f45ec7bSml29623 void
nxge_put32(p_nxge_t nxgep,p_mblk_t mp)9376f45ec7bSml29623 nxge_put32(p_nxge_t nxgep, p_mblk_t mp)
9386f45ec7bSml29623 {
9396f45ec7bSml29623 	nxge_os_acc_handle_t nxge_regh;
9406f45ec7bSml29623 	uint32_t *buf;
9416f45ec7bSml29623 	uint8_t *reg;
9426f45ec7bSml29623 
9436f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL, "nxge_put32"));
9446f45ec7bSml29623 	nxge_regh = nxgep->dev_regs->nxge_regh;
9456f45ec7bSml29623 
9466f45ec7bSml29623 	buf = (uint32_t *)mp->b_rptr;
9476f45ec7bSml29623 	reg = (uint8_t *)(nxgep->dev_regs->nxge_regp) + buf[0];
9486f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL,
9496f45ec7bSml29623 	    "reg = 0x%016llX index = 0x%08X value = 0x%08X",
9506f45ec7bSml29623 	    reg, buf[0], buf[1]));
9516f45ec7bSml29623 	NXGE_PIO_WRITE32(nxge_regh, (uint32_t *)reg, 0, buf[1]);
9526f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL, "nxge_put32"));
9536f45ec7bSml29623 }
9546f45ec7bSml29623 
9556f45ec7bSml29623 /*ARGSUSED*/
9566f45ec7bSml29623 boolean_t
nxge_set_lb(p_nxge_t nxgep,queue_t * wq,p_mblk_t mp)9576f45ec7bSml29623 nxge_set_lb(p_nxge_t nxgep, queue_t *wq, p_mblk_t mp)
9586f45ec7bSml29623 {
9596f45ec7bSml29623 	boolean_t status = B_TRUE;
9606f45ec7bSml29623 	uint32_t lb_mode;
9616f45ec7bSml29623 	lb_property_t *lb_info;
9626f45ec7bSml29623 
9636f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL, "<== nxge_set_lb"));
9646f45ec7bSml29623 	lb_mode = nxgep->statsp->port_stats.lb_mode;
9656f45ec7bSml29623 	if (lb_mode == *(uint32_t *)mp->b_rptr) {
9666f45ec7bSml29623 		cmn_err(CE_NOTE,
9676f45ec7bSml29623 		    "!nxge%d: Loopback mode already set (lb_mode %d).\n",
9686f45ec7bSml29623 		    nxgep->instance, lb_mode);
9696f45ec7bSml29623 		status = B_FALSE;
9706f45ec7bSml29623 		goto nxge_set_lb_exit;
9716f45ec7bSml29623 	}
9726f45ec7bSml29623 	lb_mode = *(uint32_t *)mp->b_rptr;
9736f45ec7bSml29623 	lb_info = NULL;
9746f45ec7bSml29623 	if (lb_mode == lb_normal.value)
9756f45ec7bSml29623 		lb_info = &lb_normal;
9766f45ec7bSml29623 	else if ((lb_mode == lb_external10g.value) &&
9776f45ec7bSml29623 	    (nxgep->statsp->mac_stats.cap_10gfdx))
9786f45ec7bSml29623 		lb_info = &lb_external10g;
9796f45ec7bSml29623 	else if ((lb_mode == lb_external1000.value) &&
9806f45ec7bSml29623 	    (nxgep->statsp->mac_stats.cap_1000fdx))
9816f45ec7bSml29623 		lb_info = &lb_external1000;
9826f45ec7bSml29623 	else if ((lb_mode == lb_external100.value) &&
9836f45ec7bSml29623 	    (nxgep->statsp->mac_stats.cap_100fdx))
9846f45ec7bSml29623 		lb_info = &lb_external100;
9856f45ec7bSml29623 	else if ((lb_mode == lb_external10.value) &&
9866f45ec7bSml29623 	    (nxgep->statsp->mac_stats.cap_10fdx))
9876f45ec7bSml29623 		lb_info = &lb_external10;
9886f45ec7bSml29623 	else if ((lb_mode == lb_phy10g.value) &&
9890cad6a5fSyc148097 	    (nxgep->mac.portmode == PORT_10G_COPPER ||
9900cad6a5fSyc148097 	    nxgep->mac.portmode == PORT_10G_TN1010 ||
9910cad6a5fSyc148097 	    nxgep->mac.portmode == PORT_10G_FIBER))
9926f45ec7bSml29623 		lb_info = &lb_phy10g;
9936f45ec7bSml29623 	else if ((lb_mode == lb_phy1000.value) &&
9940cad6a5fSyc148097 	    (nxgep->mac.portmode == PORT_1G_COPPER ||
9950cad6a5fSyc148097 	    nxgep->mac.portmode == PORT_1G_TN1010 ||
9960cad6a5fSyc148097 	    nxgep->mac.portmode == PORT_1G_RGMII_FIBER))
9976f45ec7bSml29623 		lb_info = &lb_phy1000;
9986f45ec7bSml29623 	else if ((lb_mode == lb_phy.value) &&
9996f45ec7bSml29623 	    (nxgep->mac.portmode == PORT_1G_COPPER))
10006f45ec7bSml29623 		lb_info = &lb_phy;
10016f45ec7bSml29623 	else if ((lb_mode == lb_serdes10g.value) &&
10020cad6a5fSyc148097 	    (nxgep->mac.portmode == PORT_10G_FIBER ||
10030cad6a5fSyc148097 	    nxgep->mac.portmode == PORT_10G_COPPER ||
10040cad6a5fSyc148097 	    nxgep->mac.portmode == PORT_10G_TN1010 ||
10050cad6a5fSyc148097 	    nxgep->mac.portmode == PORT_10G_SERDES))
10066f45ec7bSml29623 		lb_info = &lb_serdes10g;
10076f45ec7bSml29623 	else if ((lb_mode == lb_serdes1000.value) &&
10080cad6a5fSyc148097 	    (nxgep->mac.portmode == PORT_1G_FIBER ||
10090cad6a5fSyc148097 	    nxgep->mac.portmode == PORT_1G_TN1010 ||
10100cad6a5fSyc148097 	    nxgep->mac.portmode == PORT_1G_SERDES))
10116f45ec7bSml29623 		lb_info = &lb_serdes1000;
10126f45ec7bSml29623 	else if (lb_mode == lb_mac10g.value)
10136f45ec7bSml29623 		lb_info = &lb_mac10g;
10146f45ec7bSml29623 	else if (lb_mode == lb_mac1000.value)
10156f45ec7bSml29623 		lb_info = &lb_mac1000;
10166f45ec7bSml29623 	else if (lb_mode == lb_mac.value)
10176f45ec7bSml29623 		lb_info = &lb_mac;
10186f45ec7bSml29623 	else {
10196f45ec7bSml29623 		cmn_err(CE_NOTE,
10206f45ec7bSml29623 		    "!nxge%d: Loopback mode not supported(mode %d).\n",
10216f45ec7bSml29623 		    nxgep->instance, lb_mode);
10226f45ec7bSml29623 		status = B_FALSE;
10236f45ec7bSml29623 		goto nxge_set_lb_exit;
10246f45ec7bSml29623 	}
10256f45ec7bSml29623 
10266f45ec7bSml29623 	if (lb_mode == nxge_lb_normal) {
10276f45ec7bSml29623 		if (nxge_lb_dbg) {
10286f45ec7bSml29623 			cmn_err(CE_NOTE,
10296f45ec7bSml29623 			    "!nxge%d: Returning to normal operation",
10306f45ec7bSml29623 			    nxgep->instance);
10316f45ec7bSml29623 		}
1032321febdeSsbehera 		if (nxge_set_lb_normal(nxgep) != NXGE_OK) {
1033321febdeSsbehera 			status = B_FALSE;
1034321febdeSsbehera 			cmn_err(CE_NOTE,
1035321febdeSsbehera 			    "!nxge%d: Failed to return to normal operation",
1036321febdeSsbehera 			    nxgep->instance);
1037321febdeSsbehera 		}
10386f45ec7bSml29623 		goto nxge_set_lb_exit;
10396f45ec7bSml29623 	}
10406f45ec7bSml29623 	nxgep->statsp->port_stats.lb_mode = lb_mode;
10416f45ec7bSml29623 
10426f45ec7bSml29623 	if (nxge_lb_dbg)
10436f45ec7bSml29623 		cmn_err(CE_NOTE,
10446f45ec7bSml29623 		    "!nxge%d: Adapter now in %s loopback mode",
10456f45ec7bSml29623 		    nxgep->instance, lb_info->key);
10466f45ec7bSml29623 	nxgep->param_arr[param_autoneg].value = 0;
10476f45ec7bSml29623 	nxgep->param_arr[param_anar_10gfdx].value =
10486f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_ext10g) ||
10496f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_mac10g) ||
10506f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_phy10g) ||
10516f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_serdes10g);
10526f45ec7bSml29623 	nxgep->param_arr[param_anar_10ghdx].value = 0;
10536f45ec7bSml29623 	nxgep->param_arr[param_anar_1000fdx].value =
10546f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_ext1000) ||
10556f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_mac1000) ||
10566f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_phy1000) ||
10576f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_serdes1000);
10586f45ec7bSml29623 	nxgep->param_arr[param_anar_1000hdx].value = 0;
10596f45ec7bSml29623 	nxgep->param_arr[param_anar_100fdx].value =
10606f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_phy) ||
10616f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_mac) ||
10626f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_ext100);
10636f45ec7bSml29623 	nxgep->param_arr[param_anar_100hdx].value = 0;
10646f45ec7bSml29623 	nxgep->param_arr[param_anar_10fdx].value =
10656f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_mac) ||
10666f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_ext10);
10676f45ec7bSml29623 	if (nxgep->statsp->port_stats.lb_mode == nxge_lb_ext1000) {
10686f45ec7bSml29623 		nxgep->param_arr[param_master_cfg_enable].value = 1;
10696f45ec7bSml29623 		nxgep->param_arr[param_master_cfg_value].value = 1;
10706f45ec7bSml29623 	}
10716f45ec7bSml29623 	if ((nxgep->statsp->port_stats.lb_mode == nxge_lb_ext10g) ||
10726f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_ext1000) ||
10736f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_ext100) ||
10746f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_ext10) ||
10756f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_phy10g) ||
10766f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_phy1000) ||
10776f45ec7bSml29623 	    (nxgep->statsp->port_stats.lb_mode == nxge_lb_phy)) {
10786f45ec7bSml29623 
1079321febdeSsbehera 		if (nxge_link_monitor(nxgep, LINK_MONITOR_STOP) != NXGE_OK)
1080321febdeSsbehera 			goto nxge_set_lb_err;
1081321febdeSsbehera 		if (nxge_xcvr_find(nxgep) != NXGE_OK)
1082321febdeSsbehera 			goto nxge_set_lb_err;
1083321febdeSsbehera 		if (nxge_link_init(nxgep) != NXGE_OK)
1084321febdeSsbehera 			goto nxge_set_lb_err;
1085321febdeSsbehera 		if (nxge_link_monitor(nxgep, LINK_MONITOR_START) != NXGE_OK)
1086321febdeSsbehera 			goto nxge_set_lb_err;
10876f45ec7bSml29623 	}
10886f45ec7bSml29623 	if (lb_info->lb_type == internal) {
10896f45ec7bSml29623 		if ((nxgep->statsp->port_stats.lb_mode == nxge_lb_mac10g) ||
10906f45ec7bSml29623 		    (nxgep->statsp->port_stats.lb_mode ==
10916f45ec7bSml29623 		    nxge_lb_phy10g) ||
10926f45ec7bSml29623 		    (nxgep->statsp->port_stats.lb_mode ==
10936f45ec7bSml29623 		    nxge_lb_serdes10g)) {
10946f45ec7bSml29623 			nxgep->statsp->mac_stats.link_speed = 10000;
10956f45ec7bSml29623 		} else if ((nxgep->statsp->port_stats.lb_mode
10966f45ec7bSml29623 		    == nxge_lb_mac1000) ||
10976f45ec7bSml29623 		    (nxgep->statsp->port_stats.lb_mode ==
10986f45ec7bSml29623 		    nxge_lb_phy1000) ||
10996f45ec7bSml29623 		    (nxgep->statsp->port_stats.lb_mode ==
11006f45ec7bSml29623 		    nxge_lb_serdes1000)) {
11016f45ec7bSml29623 			nxgep->statsp->mac_stats.link_speed = 1000;
11026f45ec7bSml29623 		} else {
11036f45ec7bSml29623 			nxgep->statsp->mac_stats.link_speed = 100;
11046f45ec7bSml29623 		}
11056f45ec7bSml29623 		nxgep->statsp->mac_stats.link_duplex = 2;
11066f45ec7bSml29623 		nxgep->statsp->mac_stats.link_up = 1;
11076f45ec7bSml29623 	}
1108321febdeSsbehera 	if (nxge_global_reset(nxgep) != NXGE_OK)
1109321febdeSsbehera 		goto nxge_set_lb_err;
11106f45ec7bSml29623 
11116f45ec7bSml29623 nxge_set_lb_exit:
11126f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DDI_CTL,
11136f45ec7bSml29623 	    "<== nxge_set_lb status = 0x%08x", status));
11146f45ec7bSml29623 	return (status);
1115321febdeSsbehera nxge_set_lb_err:
1116321febdeSsbehera 	status = B_FALSE;
1117321febdeSsbehera 	cmn_err(CE_NOTE,
1118321febdeSsbehera 	    "!nxge%d: Failed to put adapter in %s loopback mode",
1119321febdeSsbehera 	    nxgep->instance, lb_info->key);
1120321febdeSsbehera 	return (status);
11216f45ec7bSml29623 }
11226f45ec7bSml29623 
112300161856Syc148097 /* Return to normal (no loopback) mode */
11246f45ec7bSml29623 /* ARGSUSED */
1125321febdeSsbehera nxge_status_t
nxge_set_lb_normal(p_nxge_t nxgep)11266f45ec7bSml29623 nxge_set_lb_normal(p_nxge_t nxgep)
11276f45ec7bSml29623 {
1128321febdeSsbehera 	nxge_status_t	status = NXGE_OK;
1129321febdeSsbehera 
11306f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "==> nxge_set_lb_normal"));
1131321febdeSsbehera 
11326f45ec7bSml29623 	nxgep->statsp->port_stats.lb_mode = nxge_lb_normal;
11336f45ec7bSml29623 	nxgep->param_arr[param_autoneg].value =
11346f45ec7bSml29623 	    nxgep->param_arr[param_autoneg].old_value;
11356f45ec7bSml29623 	nxgep->param_arr[param_anar_1000fdx].value =
11366f45ec7bSml29623 	    nxgep->param_arr[param_anar_1000fdx].old_value;
11376f45ec7bSml29623 	nxgep->param_arr[param_anar_1000hdx].value =
11386f45ec7bSml29623 	    nxgep->param_arr[param_anar_1000hdx].old_value;
11396f45ec7bSml29623 	nxgep->param_arr[param_anar_100fdx].value =
11406f45ec7bSml29623 	    nxgep->param_arr[param_anar_100fdx].old_value;
11416f45ec7bSml29623 	nxgep->param_arr[param_anar_100hdx].value =
11426f45ec7bSml29623 	    nxgep->param_arr[param_anar_100hdx].old_value;
11436f45ec7bSml29623 	nxgep->param_arr[param_anar_10fdx].value =
11446f45ec7bSml29623 	    nxgep->param_arr[param_anar_10fdx].old_value;
11456f45ec7bSml29623 	nxgep->param_arr[param_master_cfg_enable].value =
11466f45ec7bSml29623 	    nxgep->param_arr[param_master_cfg_enable].old_value;
11476f45ec7bSml29623 	nxgep->param_arr[param_master_cfg_value].value =
11486f45ec7bSml29623 	    nxgep->param_arr[param_master_cfg_value].old_value;
11496f45ec7bSml29623 
1150321febdeSsbehera 	if ((status = nxge_global_reset(nxgep)) != NXGE_OK)
1151321febdeSsbehera 		return (status);
11526f45ec7bSml29623 
1153321febdeSsbehera 	if ((status = nxge_link_monitor(nxgep, LINK_MONITOR_STOP)) != NXGE_OK)
1154321febdeSsbehera 		return (status);
1155321febdeSsbehera 	if ((status = nxge_xcvr_find(nxgep)) != NXGE_OK)
1156321febdeSsbehera 		return (status);
1157321febdeSsbehera 	if ((status = nxge_link_init(nxgep)) != NXGE_OK)
1158321febdeSsbehera 		return (status);
1159321febdeSsbehera 	status = nxge_link_monitor(nxgep, LINK_MONITOR_START);
11606f45ec7bSml29623 
11616f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, DDI_CTL, "<== nxge_set_lb_normal"));
1162321febdeSsbehera 
1163321febdeSsbehera 	return (status);
11646f45ec7bSml29623 }
11656f45ec7bSml29623 
11666f45ec7bSml29623 /* ARGSUSED */
11676f45ec7bSml29623 void
nxge_get_mii(p_nxge_t nxgep,p_mblk_t mp)11686f45ec7bSml29623 nxge_get_mii(p_nxge_t nxgep, p_mblk_t mp)
11696f45ec7bSml29623 {
11706f45ec7bSml29623 	uint16_t reg;
11716f45ec7bSml29623 
11726f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL, "==> nxge_get_mii"));
11736f45ec7bSml29623 
11746f45ec7bSml29623 	reg = *(uint16_t *)mp->b_rptr;
11756f45ec7bSml29623 	(void) nxge_mii_read(nxgep, nxgep->statsp->mac_stats.xcvr_portn, reg,
11766f45ec7bSml29623 	    (uint16_t *)mp->b_rptr);
11776f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL, "reg = 0x%08X value = 0x%04X",
11786f45ec7bSml29623 	    reg, *(uint16_t *)mp->b_rptr));
11796f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL, "<== nxge_get_mii"));
11806f45ec7bSml29623 }
11816f45ec7bSml29623 
11826f45ec7bSml29623 /* ARGSUSED */
11836f45ec7bSml29623 void
nxge_put_mii(p_nxge_t nxgep,p_mblk_t mp)11846f45ec7bSml29623 nxge_put_mii(p_nxge_t nxgep, p_mblk_t mp)
11856f45ec7bSml29623 {
11866f45ec7bSml29623 	uint16_t *buf;
11876f45ec7bSml29623 	uint8_t reg;
11886f45ec7bSml29623 
11896f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL, "==> nxge_put_mii"));
11906f45ec7bSml29623 	buf = (uint16_t *)mp->b_rptr;
11916f45ec7bSml29623 	reg = (uint8_t)buf[0];
11926f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL,
11936f45ec7bSml29623 	    "reg = 0x%08X index = 0x%08X value = 0x%08X",
11946f45ec7bSml29623 	    reg, buf[0], buf[1]));
11956f45ec7bSml29623 	(void) nxge_mii_write(nxgep, nxgep->statsp->mac_stats.xcvr_portn,
11966f45ec7bSml29623 	    reg, buf[1]);
11976f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, IOC_CTL, "<== nxge_put_mii"));
11986f45ec7bSml29623 }
11996f45ec7bSml29623 
12006f45ec7bSml29623 /* ARGSUSED */
12016f45ec7bSml29623 void
nxge_check_hw_state(p_nxge_t nxgep)12026f45ec7bSml29623 nxge_check_hw_state(p_nxge_t nxgep)
12036f45ec7bSml29623 {
12046f45ec7bSml29623 	p_nxge_ldgv_t ldgvp;
12056f45ec7bSml29623 	p_nxge_ldv_t t_ldvp;
12066f45ec7bSml29623 
12076f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, SYSERR_CTL, "==> nxge_check_hw_state"));
12086f45ec7bSml29623 
12096f45ec7bSml29623 	MUTEX_ENTER(nxgep->genlock);
12106f45ec7bSml29623 	nxgep->nxge_timerid = 0;
12116f45ec7bSml29623 	if (!(nxgep->drv_state & STATE_HW_INITIALIZED)) {
12126f45ec7bSml29623 		goto nxge_check_hw_state_exit;
12136f45ec7bSml29623 	}
12146f45ec7bSml29623 	nxge_check_tx_hang(nxgep);
12156f45ec7bSml29623 
12166f45ec7bSml29623 	ldgvp = nxgep->ldgvp;
12176f45ec7bSml29623 	if (ldgvp == NULL || (ldgvp->ldvp_syserr == NULL)) {
12186f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, SYSERR_CTL, "<== nxge_check_hw_state: "
12196f45ec7bSml29623 		    "NULL ldgvp (interrupt not ready)."));
12206f45ec7bSml29623 		goto nxge_check_hw_state_exit;
12216f45ec7bSml29623 	}
12226f45ec7bSml29623 	t_ldvp = ldgvp->ldvp_syserr;
12236f45ec7bSml29623 	if (!t_ldvp->use_timer) {
12246f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, SYSERR_CTL, "<== nxge_check_hw_state: "
12256f45ec7bSml29623 		    "ldgvp $%p t_ldvp $%p use_timer flag %d",
12266f45ec7bSml29623 		    ldgvp, t_ldvp, t_ldvp->use_timer));
12276f45ec7bSml29623 		goto nxge_check_hw_state_exit;
12286f45ec7bSml29623 	}
12296f45ec7bSml29623 	if (fm_check_acc_handle(nxgep->dev_regs->nxge_regh) != DDI_FM_OK) {
12306f45ec7bSml29623 		NXGE_ERROR_MSG((nxgep, NXGE_ERR_CTL,
12316f45ec7bSml29623 		    "port%d Bad register acc handle", nxgep->mac.portnum));
12326f45ec7bSml29623 	}
12336f45ec7bSml29623 	(void) nxge_syserr_intr((void *) t_ldvp, (void *) nxgep);
12346f45ec7bSml29623 
12356f45ec7bSml29623 	nxgep->nxge_timerid = nxge_start_timer(nxgep, nxge_check_hw_state,
12366f45ec7bSml29623 	    NXGE_CHECK_TIMER);
12376f45ec7bSml29623 
12386f45ec7bSml29623 nxge_check_hw_state_exit:
12396f45ec7bSml29623 	MUTEX_EXIT(nxgep->genlock);
12406f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, SYSERR_CTL, "<== nxge_check_hw_state"));
12416f45ec7bSml29623 }
12426f45ec7bSml29623 
12436f45ec7bSml29623 /*ARGSUSED*/
12446f45ec7bSml29623 static void
nxge_rtrace_ioctl(p_nxge_t nxgep,queue_t * wq,mblk_t * mp,struct iocblk * iocp)12456f45ec7bSml29623 nxge_rtrace_ioctl(p_nxge_t nxgep, queue_t *wq, mblk_t *mp,
12466f45ec7bSml29623 	struct iocblk *iocp)
12476f45ec7bSml29623 {
12486f45ec7bSml29623 	ssize_t size;
12496f45ec7bSml29623 	rtrace_t *rtp;
12506f45ec7bSml29623 	mblk_t *nmp;
12516f45ec7bSml29623 	uint32_t i, j;
12526f45ec7bSml29623 	uint32_t start_blk;
12536f45ec7bSml29623 	uint32_t base_entry;
12546f45ec7bSml29623 	uint32_t num_entries;
12556f45ec7bSml29623 
12566f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, STR_CTL, "==> nxge_rtrace_ioctl"));
12576f45ec7bSml29623 
12586f45ec7bSml29623 	size = 1024;
12596f45ec7bSml29623 	if (mp->b_cont == NULL || MBLKL(mp->b_cont) < size) {
12606f45ec7bSml29623 		NXGE_DEBUG_MSG((nxgep, STR_CTL,
12616f45ec7bSml29623 		    "malformed M_IOCTL MBLKL = %d size = %d",
12626f45ec7bSml29623 		    MBLKL(mp->b_cont), size));
12636f45ec7bSml29623 		miocnak(wq, mp, 0, EINVAL);
12646f45ec7bSml29623 		return;
12656f45ec7bSml29623 	}
12666f45ec7bSml29623 	nmp = mp->b_cont;
12676f45ec7bSml29623 	rtp = (rtrace_t *)nmp->b_rptr;
12686f45ec7bSml29623 	start_blk = rtp->next_idx;
12696f45ec7bSml29623 	num_entries = rtp->last_idx;
12706f45ec7bSml29623 	base_entry = start_blk * MAX_RTRACE_IOC_ENTRIES;
12716f45ec7bSml29623 
12726f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, STR_CTL, "start_blk = %d\n", start_blk));
12736f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, STR_CTL, "num_entries = %d\n", num_entries));
12746f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, STR_CTL, "base_entry = %d\n", base_entry));
12756f45ec7bSml29623 
12766f45ec7bSml29623 	rtp->next_idx = npi_rtracebuf.next_idx;
12776f45ec7bSml29623 	rtp->last_idx = npi_rtracebuf.last_idx;
12786f45ec7bSml29623 	rtp->wrapped = npi_rtracebuf.wrapped;
12796f45ec7bSml29623 	for (i = 0, j = base_entry; i < num_entries; i++, j++) {
12806f45ec7bSml29623 		rtp->buf[i].ctl_addr = npi_rtracebuf.buf[j].ctl_addr;
12816f45ec7bSml29623 		rtp->buf[i].val_l32 = npi_rtracebuf.buf[j].val_l32;
12826f45ec7bSml29623 		rtp->buf[i].val_h32 = npi_rtracebuf.buf[j].val_h32;
12836f45ec7bSml29623 	}
12846f45ec7bSml29623 
12856f45ec7bSml29623 	nmp->b_wptr = nmp->b_rptr + size;
12866f45ec7bSml29623 	NXGE_DEBUG_MSG((nxgep, STR_CTL, "<== nxge_rtrace_ioctl"));
12876f45ec7bSml29623 	miocack(wq, mp, (int)size, 0);
12886f45ec7bSml29623 }
1289