xref: /onnv-gate/usr/src/uts/common/io/ntxn/unm_nic_main.c (revision 11878:ac93462db6d7)
17956Sxiuyan.wang@Sun.COM /*
27956Sxiuyan.wang@Sun.COM  * CDDL HEADER START
37956Sxiuyan.wang@Sun.COM  *
47956Sxiuyan.wang@Sun.COM  * The contents of this file are subject to the terms of the
57956Sxiuyan.wang@Sun.COM  * Common Development and Distribution License (the "License").
67956Sxiuyan.wang@Sun.COM  * You may not use this file except in compliance with the License.
77956Sxiuyan.wang@Sun.COM  *
87956Sxiuyan.wang@Sun.COM  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97956Sxiuyan.wang@Sun.COM  * or http://www.opensolaris.org/os/licensing.
107956Sxiuyan.wang@Sun.COM  * See the License for the specific language governing permissions
117956Sxiuyan.wang@Sun.COM  * and limitations under the License.
127956Sxiuyan.wang@Sun.COM  *
137956Sxiuyan.wang@Sun.COM  * When distributing Covered Code, include this CDDL HEADER in each
147956Sxiuyan.wang@Sun.COM  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157956Sxiuyan.wang@Sun.COM  * If applicable, add the following below this CDDL HEADER, with the
167956Sxiuyan.wang@Sun.COM  * fields enclosed by brackets "[]" replaced with your own identifying
177956Sxiuyan.wang@Sun.COM  * information: Portions Copyright [yyyy] [name of copyright owner]
187956Sxiuyan.wang@Sun.COM  *
197956Sxiuyan.wang@Sun.COM  * CDDL HEADER END
207956Sxiuyan.wang@Sun.COM  */
217956Sxiuyan.wang@Sun.COM /*
227956Sxiuyan.wang@Sun.COM  * Copyright 2008 NetXen, Inc.  All rights reserved.
237956Sxiuyan.wang@Sun.COM  * Use is subject to license terms.
247956Sxiuyan.wang@Sun.COM  */
257956Sxiuyan.wang@Sun.COM /*
26*11878SVenu.Iyer@Sun.COM  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
277956Sxiuyan.wang@Sun.COM  * Use is subject to license terms.
287956Sxiuyan.wang@Sun.COM  */
297956Sxiuyan.wang@Sun.COM #include <sys/types.h>
307956Sxiuyan.wang@Sun.COM #include <sys/conf.h>
317956Sxiuyan.wang@Sun.COM #include <sys/debug.h>
327956Sxiuyan.wang@Sun.COM #include <sys/stropts.h>
337956Sxiuyan.wang@Sun.COM #include <sys/stream.h>
347956Sxiuyan.wang@Sun.COM #include <sys/strlog.h>
357956Sxiuyan.wang@Sun.COM #include <sys/kmem.h>
367956Sxiuyan.wang@Sun.COM #include <sys/stat.h>
377956Sxiuyan.wang@Sun.COM #include <sys/kstat.h>
387956Sxiuyan.wang@Sun.COM #include <sys/vtrace.h>
397956Sxiuyan.wang@Sun.COM #include <sys/dlpi.h>
407956Sxiuyan.wang@Sun.COM #include <sys/strsun.h>
417956Sxiuyan.wang@Sun.COM #include <sys/ethernet.h>
427956Sxiuyan.wang@Sun.COM #include <sys/modctl.h>
437956Sxiuyan.wang@Sun.COM #include <sys/errno.h>
447956Sxiuyan.wang@Sun.COM #include <sys/dditypes.h>
457956Sxiuyan.wang@Sun.COM #include <sys/ddi.h>
467956Sxiuyan.wang@Sun.COM #include <sys/sunddi.h>
477956Sxiuyan.wang@Sun.COM #include <sys/sysmacros.h>
487956Sxiuyan.wang@Sun.COM #include <sys/pci.h>
497956Sxiuyan.wang@Sun.COM 
507956Sxiuyan.wang@Sun.COM #include <sys/gld.h>
517956Sxiuyan.wang@Sun.COM #include <netinet/in.h>
527956Sxiuyan.wang@Sun.COM #include <inet/ip.h>
537956Sxiuyan.wang@Sun.COM #include <inet/tcp.h>
547956Sxiuyan.wang@Sun.COM 
557956Sxiuyan.wang@Sun.COM #include <sys/rwlock.h>
567956Sxiuyan.wang@Sun.COM #include <sys/mutex.h>
577956Sxiuyan.wang@Sun.COM #include <sys/pattr.h>
587956Sxiuyan.wang@Sun.COM #include <sys/strsubr.h>
597956Sxiuyan.wang@Sun.COM #include <sys/ddi_impldefs.h>
607956Sxiuyan.wang@Sun.COM #include<sys/task.h>
617956Sxiuyan.wang@Sun.COM 
627956Sxiuyan.wang@Sun.COM #include "unm_nic_hw.h"
637956Sxiuyan.wang@Sun.COM #include "unm_nic.h"
647956Sxiuyan.wang@Sun.COM 
657956Sxiuyan.wang@Sun.COM #include "nic_phan_reg.h"
667956Sxiuyan.wang@Sun.COM #include "unm_nic_ioctl.h"
677956Sxiuyan.wang@Sun.COM #include "nic_cmn.h"
687956Sxiuyan.wang@Sun.COM #include "unm_version.h"
697956Sxiuyan.wang@Sun.COM #include "unm_brdcfg.h"
707956Sxiuyan.wang@Sun.COM 
717956Sxiuyan.wang@Sun.COM #if defined(lint)
727956Sxiuyan.wang@Sun.COM #undef MBLKL
737956Sxiuyan.wang@Sun.COM #define	MBLKL(_mp_)	((uintptr_t)(_mp_)->b_wptr - (uintptr_t)(_mp_)->b_rptr)
747956Sxiuyan.wang@Sun.COM #endif /* lint */
757956Sxiuyan.wang@Sun.COM 
767956Sxiuyan.wang@Sun.COM #undef UNM_LOOPBACK
777956Sxiuyan.wang@Sun.COM #undef SINGLE_DMA_BUF
787956Sxiuyan.wang@Sun.COM 
797956Sxiuyan.wang@Sun.COM #define	UNM_ADAPTER_UP_MAGIC	777
807956Sxiuyan.wang@Sun.COM #define	VLAN_TAGSZ		0x4
817956Sxiuyan.wang@Sun.COM 
827956Sxiuyan.wang@Sun.COM #define	index2rxbuf(_rdp_, _idx_)	((_rdp_)->rx_buf_pool + (_idx_))
837956Sxiuyan.wang@Sun.COM #define	rxbuf2index(_rdp_, _bufp_)	((_bufp_) - (_rdp_)->rx_buf_pool)
847956Sxiuyan.wang@Sun.COM 
857956Sxiuyan.wang@Sun.COM /*
867956Sxiuyan.wang@Sun.COM  * Receive ISR processes NX_RX_MAXBUFS incoming packets at most, then posts
877956Sxiuyan.wang@Sun.COM  * as many buffers as packets processed. This loop repeats as required to
887956Sxiuyan.wang@Sun.COM  * process all incoming packets delivered in a single interrupt. Higher
897956Sxiuyan.wang@Sun.COM  * value of NX_RX_MAXBUFS improves performance by posting rx buffers less
907956Sxiuyan.wang@Sun.COM  * frequently, but at the cost of not posting quickly enough when card is
917956Sxiuyan.wang@Sun.COM  * running out of rx buffers.
927956Sxiuyan.wang@Sun.COM  */
937956Sxiuyan.wang@Sun.COM #define	NX_RX_THRESHOLD		32
947956Sxiuyan.wang@Sun.COM #define	NX_RX_MAXBUFS		128
957956Sxiuyan.wang@Sun.COM #define	NX_MAX_TXCOMPS		256
967956Sxiuyan.wang@Sun.COM 
979436SJing.Xiong@Sun.COM extern int create_rxtx_rings(unm_adapter *adapter);
989436SJing.Xiong@Sun.COM extern void destroy_rxtx_rings(unm_adapter *adapter);
997956Sxiuyan.wang@Sun.COM 
1007956Sxiuyan.wang@Sun.COM static void unm_post_rx_buffers_nodb(struct unm_adapter_s *adapter,
1017956Sxiuyan.wang@Sun.COM     uint32_t ringid);
1027956Sxiuyan.wang@Sun.COM static mblk_t *unm_process_rcv(unm_adapter *adapter, statusDesc_t *desc);
1037956Sxiuyan.wang@Sun.COM static int unm_process_rcv_ring(unm_adapter *, int);
1047956Sxiuyan.wang@Sun.COM static int unm_process_cmd_ring(struct unm_adapter_s *adapter);
1057956Sxiuyan.wang@Sun.COM 
1067956Sxiuyan.wang@Sun.COM static int unm_nic_do_ioctl(unm_adapter *adapter, queue_t *q, mblk_t *mp);
1077956Sxiuyan.wang@Sun.COM static void unm_nic_ioctl(struct unm_adapter_s *adapter, int cmd, queue_t *q,
1087956Sxiuyan.wang@Sun.COM     mblk_t *mp);
1097956Sxiuyan.wang@Sun.COM 
1107956Sxiuyan.wang@Sun.COM /* GLDv3 interface functions */
1117956Sxiuyan.wang@Sun.COM static int ntxn_m_start(void *);
1127956Sxiuyan.wang@Sun.COM static void ntxn_m_stop(void *);
1137956Sxiuyan.wang@Sun.COM static int ntxn_m_multicst(void *, boolean_t, const uint8_t *);
1147956Sxiuyan.wang@Sun.COM static int ntxn_m_promisc(void *, boolean_t);
1157956Sxiuyan.wang@Sun.COM static int ntxn_m_stat(void *arg, uint_t stat, uint64_t *val);
1167956Sxiuyan.wang@Sun.COM static mblk_t *ntxn_m_tx(void *, mblk_t *);
1177956Sxiuyan.wang@Sun.COM static void ntxn_m_ioctl(void *arg, queue_t *wq, mblk_t *mp);
1187956Sxiuyan.wang@Sun.COM static boolean_t ntxn_m_getcapab(void *arg, mac_capab_t cap, void *cap_data);
1197956Sxiuyan.wang@Sun.COM 
1207956Sxiuyan.wang@Sun.COM /*
1217956Sxiuyan.wang@Sun.COM  * Allocates DMA handle, virtual memory and binds them
1227956Sxiuyan.wang@Sun.COM  * returns size of actual memory binded and the physical address.
1237956Sxiuyan.wang@Sun.COM  */
1247956Sxiuyan.wang@Sun.COM int
unm_pci_alloc_consistent(unm_adapter * adapter,int size,caddr_t * address,ddi_dma_cookie_t * cookie,ddi_dma_handle_t * dma_handle,ddi_acc_handle_t * handlep)1257956Sxiuyan.wang@Sun.COM unm_pci_alloc_consistent(unm_adapter *adapter,
1267956Sxiuyan.wang@Sun.COM 		int size, caddr_t *address, ddi_dma_cookie_t *cookie,
1277956Sxiuyan.wang@Sun.COM 		ddi_dma_handle_t *dma_handle, ddi_acc_handle_t *handlep)
1287956Sxiuyan.wang@Sun.COM {
1297956Sxiuyan.wang@Sun.COM 	int			err;
1307956Sxiuyan.wang@Sun.COM 	uint32_t		ncookies;
1317956Sxiuyan.wang@Sun.COM 	size_t			ring_len;
1327956Sxiuyan.wang@Sun.COM 	uint_t			dma_flags = DDI_DMA_RDWR | DDI_DMA_CONSISTENT;
1337956Sxiuyan.wang@Sun.COM 
1347956Sxiuyan.wang@Sun.COM 	*dma_handle = NULL;
1357956Sxiuyan.wang@Sun.COM 
1367956Sxiuyan.wang@Sun.COM 	if (size <= 0)
1377956Sxiuyan.wang@Sun.COM 		return (DDI_ENOMEM);
1387956Sxiuyan.wang@Sun.COM 
1397956Sxiuyan.wang@Sun.COM 	err = ddi_dma_alloc_handle(adapter->dip,
1407956Sxiuyan.wang@Sun.COM 	    &adapter->gc_dma_attr_desc,
1417956Sxiuyan.wang@Sun.COM 	    DDI_DMA_DONTWAIT, NULL, dma_handle);
1427956Sxiuyan.wang@Sun.COM 	if (err != DDI_SUCCESS) {
1437956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "!%s: %s: ddi_dma_alloc_handle FAILED:"
1447956Sxiuyan.wang@Sun.COM 		    " %d", unm_nic_driver_name, __func__, err);
1457956Sxiuyan.wang@Sun.COM 		return (DDI_ENOMEM);
1467956Sxiuyan.wang@Sun.COM 	}
1477956Sxiuyan.wang@Sun.COM 
1487956Sxiuyan.wang@Sun.COM 	err = ddi_dma_mem_alloc(*dma_handle,
1497956Sxiuyan.wang@Sun.COM 	    size, &adapter->gc_attr_desc,
1507956Sxiuyan.wang@Sun.COM 	    dma_flags & (DDI_DMA_STREAMING | DDI_DMA_CONSISTENT),
1517956Sxiuyan.wang@Sun.COM 	    DDI_DMA_DONTWAIT, NULL, address, &ring_len,
1527956Sxiuyan.wang@Sun.COM 	    handlep);
1537956Sxiuyan.wang@Sun.COM 	if (err != DDI_SUCCESS) {
1547956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "!%s: %s: ddi_dma_mem_alloc failed:"
1557956Sxiuyan.wang@Sun.COM 		    "ret %d, request size: %d",
1567956Sxiuyan.wang@Sun.COM 		    unm_nic_driver_name, __func__, err, size);
1577956Sxiuyan.wang@Sun.COM 		ddi_dma_free_handle(dma_handle);
1587956Sxiuyan.wang@Sun.COM 		return (DDI_ENOMEM);
1597956Sxiuyan.wang@Sun.COM 	}
1607956Sxiuyan.wang@Sun.COM 
1617956Sxiuyan.wang@Sun.COM 	if (ring_len < size) {
1627956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "%s: %s: could not allocate required "
1637956Sxiuyan.wang@Sun.COM 		    "memory :%d\n", unm_nic_driver_name,
1647956Sxiuyan.wang@Sun.COM 		    __func__, err);
1657956Sxiuyan.wang@Sun.COM 		ddi_dma_mem_free(handlep);
1667956Sxiuyan.wang@Sun.COM 		ddi_dma_free_handle(dma_handle);
1677956Sxiuyan.wang@Sun.COM 		return (DDI_FAILURE);
1687956Sxiuyan.wang@Sun.COM 	}
1697956Sxiuyan.wang@Sun.COM 
1707956Sxiuyan.wang@Sun.COM 	(void) memset(*address, 0, size);
1717956Sxiuyan.wang@Sun.COM 
1727956Sxiuyan.wang@Sun.COM 	if (((err = ddi_dma_addr_bind_handle(*dma_handle,
1737956Sxiuyan.wang@Sun.COM 	    NULL, *address, ring_len,
1747956Sxiuyan.wang@Sun.COM 	    dma_flags,
1757956Sxiuyan.wang@Sun.COM 	    DDI_DMA_DONTWAIT, NULL,
1767956Sxiuyan.wang@Sun.COM 	    cookie, &ncookies)) != DDI_DMA_MAPPED) ||
1777956Sxiuyan.wang@Sun.COM 	    (ncookies != 1)) {
1787956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN,
1797956Sxiuyan.wang@Sun.COM 		    "!%s: %s: ddi_dma_addr_bind_handle FAILED: %d",
1807956Sxiuyan.wang@Sun.COM 		    unm_nic_driver_name, __func__, err);
1817956Sxiuyan.wang@Sun.COM 		ddi_dma_mem_free(handlep);
1827956Sxiuyan.wang@Sun.COM 		ddi_dma_free_handle(dma_handle);
1837956Sxiuyan.wang@Sun.COM 		return (DDI_FAILURE);
1847956Sxiuyan.wang@Sun.COM 	}
1857956Sxiuyan.wang@Sun.COM 
1867956Sxiuyan.wang@Sun.COM 	return (DDI_SUCCESS);
1877956Sxiuyan.wang@Sun.COM }
1887956Sxiuyan.wang@Sun.COM 
1897956Sxiuyan.wang@Sun.COM /*
1907956Sxiuyan.wang@Sun.COM  * Unbinds the memory, frees the DMA handle and at the end, frees the memory
1917956Sxiuyan.wang@Sun.COM  */
1927956Sxiuyan.wang@Sun.COM void
unm_pci_free_consistent(ddi_dma_handle_t * dma_handle,ddi_acc_handle_t * acc_handle)1937956Sxiuyan.wang@Sun.COM unm_pci_free_consistent(ddi_dma_handle_t *dma_handle,
1947956Sxiuyan.wang@Sun.COM     ddi_acc_handle_t *acc_handle)
1957956Sxiuyan.wang@Sun.COM {
1967956Sxiuyan.wang@Sun.COM 	int err;
1977956Sxiuyan.wang@Sun.COM 
1987956Sxiuyan.wang@Sun.COM 	err = ddi_dma_unbind_handle(*dma_handle);
1997956Sxiuyan.wang@Sun.COM 	if (err != DDI_SUCCESS) {
2007956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "%s: Error unbinding memory\n", __func__);
2017956Sxiuyan.wang@Sun.COM 		return;
2027956Sxiuyan.wang@Sun.COM 	}
2037956Sxiuyan.wang@Sun.COM 
2047956Sxiuyan.wang@Sun.COM 	ddi_dma_mem_free(acc_handle);
2057956Sxiuyan.wang@Sun.COM 	ddi_dma_free_handle(dma_handle);
2067956Sxiuyan.wang@Sun.COM }
2077956Sxiuyan.wang@Sun.COM 
2087956Sxiuyan.wang@Sun.COM static uint32_t msi_tgt_status[] = {
2097956Sxiuyan.wang@Sun.COM     ISR_INT_TARGET_STATUS, ISR_INT_TARGET_STATUS_F1,
2107956Sxiuyan.wang@Sun.COM     ISR_INT_TARGET_STATUS_F2, ISR_INT_TARGET_STATUS_F3,
2117956Sxiuyan.wang@Sun.COM     ISR_INT_TARGET_STATUS_F4, ISR_INT_TARGET_STATUS_F5,
2127956Sxiuyan.wang@Sun.COM     ISR_INT_TARGET_STATUS_F6, ISR_INT_TARGET_STATUS_F7
2137956Sxiuyan.wang@Sun.COM };
2147956Sxiuyan.wang@Sun.COM 
2157956Sxiuyan.wang@Sun.COM static void
unm_nic_disable_int(unm_adapter * adapter)2167956Sxiuyan.wang@Sun.COM unm_nic_disable_int(unm_adapter *adapter)
2177956Sxiuyan.wang@Sun.COM {
2187956Sxiuyan.wang@Sun.COM 	__uint32_t	temp = 0;
2197956Sxiuyan.wang@Sun.COM 
2207956Sxiuyan.wang@Sun.COM 	adapter->unm_nic_hw_write_wx(adapter, adapter->interrupt_crb,
2217956Sxiuyan.wang@Sun.COM 	    &temp, 4);
2227956Sxiuyan.wang@Sun.COM }
2237956Sxiuyan.wang@Sun.COM 
2249436SJing.Xiong@Sun.COM static inline int
unm_nic_clear_int(unm_adapter * adapter)2257956Sxiuyan.wang@Sun.COM unm_nic_clear_int(unm_adapter *adapter)
2267956Sxiuyan.wang@Sun.COM {
2277956Sxiuyan.wang@Sun.COM 	uint32_t	mask, temp, our_int, status;
2287956Sxiuyan.wang@Sun.COM 
2297956Sxiuyan.wang@Sun.COM 	UNM_READ_LOCK(&adapter->adapter_lock);
2307956Sxiuyan.wang@Sun.COM 
2317956Sxiuyan.wang@Sun.COM 	/* check whether it's our interrupt */
2327956Sxiuyan.wang@Sun.COM 	if (!UNM_IS_MSI_FAMILY(adapter)) {
2337956Sxiuyan.wang@Sun.COM 
2347956Sxiuyan.wang@Sun.COM 		/* Legacy Interrupt case */
2357956Sxiuyan.wang@Sun.COM 		adapter->unm_nic_pci_read_immediate(adapter, ISR_INT_VECTOR,
2367956Sxiuyan.wang@Sun.COM 		    &status);
2377956Sxiuyan.wang@Sun.COM 
2387956Sxiuyan.wang@Sun.COM 		if (!(status & adapter->legacy_intr.int_vec_bit)) {
2397956Sxiuyan.wang@Sun.COM 			UNM_READ_UNLOCK(&adapter->adapter_lock);
2407956Sxiuyan.wang@Sun.COM 			return (-1);
2417956Sxiuyan.wang@Sun.COM 		}
2427956Sxiuyan.wang@Sun.COM 
2437956Sxiuyan.wang@Sun.COM 		if (adapter->ahw.revision_id >= NX_P3_B1) {
2447956Sxiuyan.wang@Sun.COM 			adapter->unm_nic_pci_read_immediate(adapter,
2457956Sxiuyan.wang@Sun.COM 			    ISR_INT_STATE_REG, &temp);
2467956Sxiuyan.wang@Sun.COM 			if (!ISR_IS_LEGACY_INTR_TRIGGERED(temp)) {
2477956Sxiuyan.wang@Sun.COM 				UNM_READ_UNLOCK(&adapter->adapter_lock);
2487956Sxiuyan.wang@Sun.COM 				return (-1);
2497956Sxiuyan.wang@Sun.COM 			}
2507956Sxiuyan.wang@Sun.COM 		} else if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
2517956Sxiuyan.wang@Sun.COM 			our_int = adapter->unm_nic_pci_read_normalize(adapter,
2527956Sxiuyan.wang@Sun.COM 			    CRB_INT_VECTOR);
2537956Sxiuyan.wang@Sun.COM 
2547956Sxiuyan.wang@Sun.COM 			/* FIXME: Assumes pci_func is same as ctx */
2557956Sxiuyan.wang@Sun.COM 			if ((our_int & (0x80 << adapter->portnum)) == 0) {
2567956Sxiuyan.wang@Sun.COM 				if (our_int != 0) {
2577956Sxiuyan.wang@Sun.COM 					/* not our interrupt */
2587956Sxiuyan.wang@Sun.COM 					UNM_READ_UNLOCK(&adapter->adapter_lock);
2597956Sxiuyan.wang@Sun.COM 					return (-1);
2607956Sxiuyan.wang@Sun.COM 				}
2617956Sxiuyan.wang@Sun.COM 			}
2627956Sxiuyan.wang@Sun.COM 			temp = our_int & ~((u32)(0x80 << adapter->portnum));
2637956Sxiuyan.wang@Sun.COM 			adapter->unm_nic_pci_write_normalize(adapter,
2647956Sxiuyan.wang@Sun.COM 			    CRB_INT_VECTOR, temp);
2657956Sxiuyan.wang@Sun.COM 		}
2667956Sxiuyan.wang@Sun.COM 
2677956Sxiuyan.wang@Sun.COM 		if (adapter->fw_major < 4)
2687956Sxiuyan.wang@Sun.COM 			unm_nic_disable_int(adapter);
2697956Sxiuyan.wang@Sun.COM 
2707956Sxiuyan.wang@Sun.COM 		/* claim interrupt */
2717956Sxiuyan.wang@Sun.COM 		temp = 0xffffffff;
2727956Sxiuyan.wang@Sun.COM 		adapter->unm_nic_pci_write_immediate(adapter,
2737956Sxiuyan.wang@Sun.COM 		    adapter->legacy_intr.tgt_status_reg, &temp);
2747956Sxiuyan.wang@Sun.COM 
2757956Sxiuyan.wang@Sun.COM 		adapter->unm_nic_pci_read_immediate(adapter, ISR_INT_VECTOR,
2767956Sxiuyan.wang@Sun.COM 		    &mask);
2777956Sxiuyan.wang@Sun.COM 
2787956Sxiuyan.wang@Sun.COM 		/*
2797956Sxiuyan.wang@Sun.COM 		 * Read again to make sure the legacy interrupt message got
2807956Sxiuyan.wang@Sun.COM 		 * flushed out
2817956Sxiuyan.wang@Sun.COM 		 */
2827956Sxiuyan.wang@Sun.COM 		adapter->unm_nic_pci_read_immediate(adapter, ISR_INT_VECTOR,
2837956Sxiuyan.wang@Sun.COM 		    &mask);
2847956Sxiuyan.wang@Sun.COM 	} else if (adapter->flags & UNM_NIC_MSI_ENABLED) {
2857956Sxiuyan.wang@Sun.COM 		/* clear interrupt */
2867956Sxiuyan.wang@Sun.COM 		temp = 0xffffffff;
2877956Sxiuyan.wang@Sun.COM 		adapter->unm_nic_pci_write_immediate(adapter,
2887956Sxiuyan.wang@Sun.COM 		    msi_tgt_status[adapter->ahw.pci_func], &temp);
2897956Sxiuyan.wang@Sun.COM 	}
2907956Sxiuyan.wang@Sun.COM 
2917956Sxiuyan.wang@Sun.COM 	UNM_READ_UNLOCK(&adapter->adapter_lock);
2927956Sxiuyan.wang@Sun.COM 
2937956Sxiuyan.wang@Sun.COM 	return (0);
2947956Sxiuyan.wang@Sun.COM }
2957956Sxiuyan.wang@Sun.COM 
2967956Sxiuyan.wang@Sun.COM static void
unm_nic_enable_int(unm_adapter * adapter)2977956Sxiuyan.wang@Sun.COM unm_nic_enable_int(unm_adapter *adapter)
2987956Sxiuyan.wang@Sun.COM {
2997956Sxiuyan.wang@Sun.COM 	u32	temp = 1;
3007956Sxiuyan.wang@Sun.COM 
3017956Sxiuyan.wang@Sun.COM 	adapter->unm_nic_hw_write_wx(adapter, adapter->interrupt_crb,
3027956Sxiuyan.wang@Sun.COM 	    &temp, 4);
3037956Sxiuyan.wang@Sun.COM 
3047956Sxiuyan.wang@Sun.COM 	if (!UNM_IS_MSI_FAMILY(adapter)) {
3057956Sxiuyan.wang@Sun.COM 		u32	mask = 0xfbff;
3067956Sxiuyan.wang@Sun.COM 
3077956Sxiuyan.wang@Sun.COM 		adapter->unm_nic_pci_write_immediate(adapter,
3087956Sxiuyan.wang@Sun.COM 		    adapter->legacy_intr.tgt_mask_reg, &mask);
3097956Sxiuyan.wang@Sun.COM 	}
3107956Sxiuyan.wang@Sun.COM }
3117956Sxiuyan.wang@Sun.COM 
3127956Sxiuyan.wang@Sun.COM static void
unm_free_hw_resources(unm_adapter * adapter)3137956Sxiuyan.wang@Sun.COM unm_free_hw_resources(unm_adapter *adapter)
3147956Sxiuyan.wang@Sun.COM {
3157956Sxiuyan.wang@Sun.COM 	unm_recv_context_t *recv_ctx;
3167956Sxiuyan.wang@Sun.COM 	unm_rcv_desc_ctx_t *rcv_desc;
3177956Sxiuyan.wang@Sun.COM 	int ctx, ring;
3187956Sxiuyan.wang@Sun.COM 
3197956Sxiuyan.wang@Sun.COM 	if (adapter->context_alloced == 1) {
3207956Sxiuyan.wang@Sun.COM 		netxen_destroy_rxtx(adapter);
3217956Sxiuyan.wang@Sun.COM 		adapter->context_alloced = 0;
3227956Sxiuyan.wang@Sun.COM 	}
3237956Sxiuyan.wang@Sun.COM 
3247956Sxiuyan.wang@Sun.COM 	if (adapter->ctxDesc != NULL) {
3257956Sxiuyan.wang@Sun.COM 		unm_pci_free_consistent(&adapter->ctxDesc_dma_handle,
3267956Sxiuyan.wang@Sun.COM 		    &adapter->ctxDesc_acc_handle);
3277956Sxiuyan.wang@Sun.COM 		adapter->ctxDesc = NULL;
3287956Sxiuyan.wang@Sun.COM 	}
3297956Sxiuyan.wang@Sun.COM 
3307956Sxiuyan.wang@Sun.COM 	if (adapter->ahw.cmdDescHead != NULL) {
3317956Sxiuyan.wang@Sun.COM 		unm_pci_free_consistent(&adapter->ahw.cmd_desc_dma_handle,
3327956Sxiuyan.wang@Sun.COM 		    &adapter->ahw.cmd_desc_acc_handle);
3337956Sxiuyan.wang@Sun.COM 		adapter->ahw.cmdDesc_physAddr = NULL;
3347956Sxiuyan.wang@Sun.COM 		adapter->ahw.cmdDescHead = NULL;
3357956Sxiuyan.wang@Sun.COM 	}
3367956Sxiuyan.wang@Sun.COM 
3377956Sxiuyan.wang@Sun.COM 	for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
3387956Sxiuyan.wang@Sun.COM 		recv_ctx = &adapter->recv_ctx[ctx];
3397956Sxiuyan.wang@Sun.COM 		for (ring = 0; ring < adapter->max_rds_rings; ring++) {
3407956Sxiuyan.wang@Sun.COM 			rcv_desc = &recv_ctx->rcv_desc[ring];
3417956Sxiuyan.wang@Sun.COM 
3427956Sxiuyan.wang@Sun.COM 			if (rcv_desc->desc_head != NULL) {
3437956Sxiuyan.wang@Sun.COM 				unm_pci_free_consistent(
3447956Sxiuyan.wang@Sun.COM 				    &rcv_desc->rx_desc_dma_handle,
3457956Sxiuyan.wang@Sun.COM 				    &rcv_desc->rx_desc_acc_handle);
3467956Sxiuyan.wang@Sun.COM 				rcv_desc->desc_head = NULL;
3477956Sxiuyan.wang@Sun.COM 				rcv_desc->phys_addr = NULL;
3487956Sxiuyan.wang@Sun.COM 			}
3497956Sxiuyan.wang@Sun.COM 		}
3507956Sxiuyan.wang@Sun.COM 
3517956Sxiuyan.wang@Sun.COM 		if (recv_ctx->rcvStatusDescHead != NULL) {
3527956Sxiuyan.wang@Sun.COM 			unm_pci_free_consistent(
3537956Sxiuyan.wang@Sun.COM 			    &recv_ctx->status_desc_dma_handle,
3547956Sxiuyan.wang@Sun.COM 			    &recv_ctx->status_desc_acc_handle);
3557956Sxiuyan.wang@Sun.COM 			recv_ctx->rcvStatusDesc_physAddr = NULL;
3567956Sxiuyan.wang@Sun.COM 			recv_ctx->rcvStatusDescHead = NULL;
3577956Sxiuyan.wang@Sun.COM 		}
3587956Sxiuyan.wang@Sun.COM 	}
3597956Sxiuyan.wang@Sun.COM }
3607956Sxiuyan.wang@Sun.COM 
3617956Sxiuyan.wang@Sun.COM static void
cleanup_adapter(struct unm_adapter_s * adapter)3627956Sxiuyan.wang@Sun.COM cleanup_adapter(struct unm_adapter_s *adapter)
3637956Sxiuyan.wang@Sun.COM {
3647956Sxiuyan.wang@Sun.COM 	ddi_regs_map_free(&(adapter->regs_handle));
3657956Sxiuyan.wang@Sun.COM 	ddi_regs_map_free(&(adapter->db_handle));
3667956Sxiuyan.wang@Sun.COM 	kmem_free(adapter, sizeof (unm_adapter));
3677956Sxiuyan.wang@Sun.COM }
3687956Sxiuyan.wang@Sun.COM 
3697956Sxiuyan.wang@Sun.COM void
unm_nic_remove(unm_adapter * adapter)3707956Sxiuyan.wang@Sun.COM unm_nic_remove(unm_adapter *adapter)
3717956Sxiuyan.wang@Sun.COM {
3727956Sxiuyan.wang@Sun.COM 	mac_link_update(adapter->mach, LINK_STATE_DOWN);
3737956Sxiuyan.wang@Sun.COM 	unm_nic_stop_port(adapter);
3747956Sxiuyan.wang@Sun.COM 
3757956Sxiuyan.wang@Sun.COM 	if (adapter->interrupt_crb) {
3767956Sxiuyan.wang@Sun.COM 		UNM_READ_LOCK(&adapter->adapter_lock);
3777956Sxiuyan.wang@Sun.COM 		unm_nic_disable_int(adapter);
3787956Sxiuyan.wang@Sun.COM 		UNM_READ_UNLOCK(&adapter->adapter_lock);
3797956Sxiuyan.wang@Sun.COM 	}
3807956Sxiuyan.wang@Sun.COM 	(void) untimeout(adapter->watchdog_timer);
3817956Sxiuyan.wang@Sun.COM 
3827956Sxiuyan.wang@Sun.COM 	unm_free_hw_resources(adapter);
3839436SJing.Xiong@Sun.COM 
3849436SJing.Xiong@Sun.COM 	if (adapter->is_up == UNM_ADAPTER_UP_MAGIC)
3859436SJing.Xiong@Sun.COM 		destroy_rxtx_rings(adapter);
3867956Sxiuyan.wang@Sun.COM 
3877956Sxiuyan.wang@Sun.COM 	if (adapter->portnum == 0)
3887956Sxiuyan.wang@Sun.COM 		unm_free_dummy_dma(adapter);
3897956Sxiuyan.wang@Sun.COM 
3907956Sxiuyan.wang@Sun.COM 	unm_destroy_intr(adapter);
3917956Sxiuyan.wang@Sun.COM 
3927956Sxiuyan.wang@Sun.COM 	ddi_set_driver_private(adapter->dip, NULL);
3937956Sxiuyan.wang@Sun.COM 	cleanup_adapter(adapter);
3947956Sxiuyan.wang@Sun.COM }
3957956Sxiuyan.wang@Sun.COM 
3967956Sxiuyan.wang@Sun.COM static int
init_firmware(unm_adapter * adapter)3977956Sxiuyan.wang@Sun.COM init_firmware(unm_adapter *adapter)
3987956Sxiuyan.wang@Sun.COM {
3997956Sxiuyan.wang@Sun.COM 	uint32_t state = 0, loops = 0, tempout;
4007956Sxiuyan.wang@Sun.COM 
4017956Sxiuyan.wang@Sun.COM 	/* Window 1 call */
4027956Sxiuyan.wang@Sun.COM 	UNM_READ_LOCK(&adapter->adapter_lock);
4037956Sxiuyan.wang@Sun.COM 	state = adapter->unm_nic_pci_read_normalize(adapter, CRB_CMDPEG_STATE);
4047956Sxiuyan.wang@Sun.COM 	UNM_READ_UNLOCK(&adapter->adapter_lock);
4057956Sxiuyan.wang@Sun.COM 
4067956Sxiuyan.wang@Sun.COM 	if (state == PHAN_INITIALIZE_ACK)
4077956Sxiuyan.wang@Sun.COM 		return (0);
4087956Sxiuyan.wang@Sun.COM 
4097956Sxiuyan.wang@Sun.COM 	while (state != PHAN_INITIALIZE_COMPLETE && loops < 200000) {
4107956Sxiuyan.wang@Sun.COM 		drv_usecwait(100);
4117956Sxiuyan.wang@Sun.COM 		/* Window 1 call */
4127956Sxiuyan.wang@Sun.COM 		UNM_READ_LOCK(&adapter->adapter_lock);
4137956Sxiuyan.wang@Sun.COM 		state = adapter->unm_nic_pci_read_normalize(adapter,
4147956Sxiuyan.wang@Sun.COM 		    CRB_CMDPEG_STATE);
4157956Sxiuyan.wang@Sun.COM 		UNM_READ_UNLOCK(&adapter->adapter_lock);
4167956Sxiuyan.wang@Sun.COM 		loops++;
4177956Sxiuyan.wang@Sun.COM 	}
4187956Sxiuyan.wang@Sun.COM 
4197956Sxiuyan.wang@Sun.COM 	if (loops >= 200000) {
4207956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "%s%d: CmdPeg init incomplete:%x\n",
4217956Sxiuyan.wang@Sun.COM 		    adapter->name, adapter->instance, state);
4227956Sxiuyan.wang@Sun.COM 		return (-EIO);
4237956Sxiuyan.wang@Sun.COM 	}
4247956Sxiuyan.wang@Sun.COM 
4257956Sxiuyan.wang@Sun.COM 	/* Window 1 call */
4267956Sxiuyan.wang@Sun.COM 	UNM_READ_LOCK(&adapter->adapter_lock);
4277956Sxiuyan.wang@Sun.COM 	tempout = INTR_SCHEME_PERPORT;
4287956Sxiuyan.wang@Sun.COM 	adapter->unm_nic_hw_write_wx(adapter, CRB_NIC_CAPABILITIES_HOST,
4297956Sxiuyan.wang@Sun.COM 	    &tempout, 4);
4307956Sxiuyan.wang@Sun.COM 	tempout = MSI_MODE_MULTIFUNC;
4317956Sxiuyan.wang@Sun.COM 	adapter->unm_nic_hw_write_wx(adapter, CRB_NIC_MSI_MODE_HOST,
4327956Sxiuyan.wang@Sun.COM 	    &tempout, 4);
4337956Sxiuyan.wang@Sun.COM 	tempout = MPORT_MULTI_FUNCTION_MODE;
4347956Sxiuyan.wang@Sun.COM 	adapter->unm_nic_hw_write_wx(adapter, CRB_MPORT_MODE, &tempout, 4);
4357956Sxiuyan.wang@Sun.COM 	tempout = PHAN_INITIALIZE_ACK;
4367956Sxiuyan.wang@Sun.COM 	adapter->unm_nic_hw_write_wx(adapter, CRB_CMDPEG_STATE, &tempout, 4);
4377956Sxiuyan.wang@Sun.COM 	UNM_READ_UNLOCK(&adapter->adapter_lock);
4387956Sxiuyan.wang@Sun.COM 
4397956Sxiuyan.wang@Sun.COM 	return (0);
4407956Sxiuyan.wang@Sun.COM }
4417956Sxiuyan.wang@Sun.COM 
4427956Sxiuyan.wang@Sun.COM /*
4437956Sxiuyan.wang@Sun.COM  * Utility to synchronize with receive peg.
4447956Sxiuyan.wang@Sun.COM  *  Returns   0 on sucess
4457956Sxiuyan.wang@Sun.COM  *         -EIO on error
4467956Sxiuyan.wang@Sun.COM  */
4477956Sxiuyan.wang@Sun.COM int
receive_peg_ready(struct unm_adapter_s * adapter)4487956Sxiuyan.wang@Sun.COM receive_peg_ready(struct unm_adapter_s *adapter)
4497956Sxiuyan.wang@Sun.COM {
4507956Sxiuyan.wang@Sun.COM 	uint32_t state = 0;
4517956Sxiuyan.wang@Sun.COM 	int loops = 0, err = 0;
4527956Sxiuyan.wang@Sun.COM 
4537956Sxiuyan.wang@Sun.COM 	/* Window 1 call */
4547956Sxiuyan.wang@Sun.COM 	UNM_READ_LOCK(&adapter->adapter_lock);
4557956Sxiuyan.wang@Sun.COM 	state = adapter->unm_nic_pci_read_normalize(adapter, CRB_RCVPEG_STATE);
4567956Sxiuyan.wang@Sun.COM 	UNM_READ_UNLOCK(&adapter->adapter_lock);
4577956Sxiuyan.wang@Sun.COM 
4587956Sxiuyan.wang@Sun.COM 	while ((state != PHAN_PEG_RCV_INITIALIZED) && (loops < 20000)) {
4597956Sxiuyan.wang@Sun.COM 		drv_usecwait(100);
4607956Sxiuyan.wang@Sun.COM 		/* Window 1 call */
4617956Sxiuyan.wang@Sun.COM 
4627956Sxiuyan.wang@Sun.COM 		UNM_READ_LOCK(&adapter->adapter_lock);
4637956Sxiuyan.wang@Sun.COM 		state = adapter->unm_nic_pci_read_normalize(adapter,
4647956Sxiuyan.wang@Sun.COM 		    CRB_RCVPEG_STATE);
4657956Sxiuyan.wang@Sun.COM 		UNM_READ_UNLOCK(&adapter->adapter_lock);
4667956Sxiuyan.wang@Sun.COM 
4677956Sxiuyan.wang@Sun.COM 		loops++;
4687956Sxiuyan.wang@Sun.COM 	}
4697956Sxiuyan.wang@Sun.COM 
4707956Sxiuyan.wang@Sun.COM 	if (loops >= 20000) {
4717956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "Receive Peg initialization incomplete 0x%x\n",
4727956Sxiuyan.wang@Sun.COM 		    state);
4737956Sxiuyan.wang@Sun.COM 		err = -EIO;
4747956Sxiuyan.wang@Sun.COM 	}
4757956Sxiuyan.wang@Sun.COM 
4767956Sxiuyan.wang@Sun.COM 	return (err);
4777956Sxiuyan.wang@Sun.COM }
4787956Sxiuyan.wang@Sun.COM 
4797956Sxiuyan.wang@Sun.COM /*
4807956Sxiuyan.wang@Sun.COM  * check if the firmware has been downloaded and ready to run  and
4817956Sxiuyan.wang@Sun.COM  * setup the address for the descriptors in the adapter
4827956Sxiuyan.wang@Sun.COM  */
4837956Sxiuyan.wang@Sun.COM static int
unm_nic_hw_resources(unm_adapter * adapter)4847956Sxiuyan.wang@Sun.COM unm_nic_hw_resources(unm_adapter *adapter)
4857956Sxiuyan.wang@Sun.COM {
4867956Sxiuyan.wang@Sun.COM 	hardware_context	*hw = &adapter->ahw;
4877956Sxiuyan.wang@Sun.COM 	void			*addr;
4887956Sxiuyan.wang@Sun.COM 	int			err;
4897956Sxiuyan.wang@Sun.COM 	int			ctx, ring;
4907956Sxiuyan.wang@Sun.COM 	unm_recv_context_t	*recv_ctx;
4917956Sxiuyan.wang@Sun.COM 	unm_rcv_desc_ctx_t	*rcv_desc;
4927956Sxiuyan.wang@Sun.COM 	ddi_dma_cookie_t	cookie;
4937956Sxiuyan.wang@Sun.COM 	int			size;
4947956Sxiuyan.wang@Sun.COM 
4957956Sxiuyan.wang@Sun.COM 	if (err = receive_peg_ready(adapter))
4967956Sxiuyan.wang@Sun.COM 		return (err);
4977956Sxiuyan.wang@Sun.COM 
4987956Sxiuyan.wang@Sun.COM 	size = (sizeof (RingContext) + sizeof (uint32_t));
4997956Sxiuyan.wang@Sun.COM 
5007956Sxiuyan.wang@Sun.COM 	err = unm_pci_alloc_consistent(adapter,
5017956Sxiuyan.wang@Sun.COM 	    size, (caddr_t *)&addr, &cookie,
5027956Sxiuyan.wang@Sun.COM 	    &adapter->ctxDesc_dma_handle,
5037956Sxiuyan.wang@Sun.COM 	    &adapter->ctxDesc_acc_handle);
5047956Sxiuyan.wang@Sun.COM 	if (err != DDI_SUCCESS) {
5057956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "Failed to allocate HW context\n");
5067956Sxiuyan.wang@Sun.COM 		return (err);
5077956Sxiuyan.wang@Sun.COM 	}
5087956Sxiuyan.wang@Sun.COM 
5097956Sxiuyan.wang@Sun.COM 	adapter->ctxDesc_physAddr = cookie.dmac_laddress;
5107956Sxiuyan.wang@Sun.COM 
5117956Sxiuyan.wang@Sun.COM 	(void) memset(addr, 0, sizeof (RingContext));
5127956Sxiuyan.wang@Sun.COM 
5137956Sxiuyan.wang@Sun.COM 	adapter->ctxDesc = (RingContext *) addr;
5147956Sxiuyan.wang@Sun.COM 	adapter->ctxDesc->CtxId = adapter->portnum;
5157956Sxiuyan.wang@Sun.COM 	adapter->ctxDesc->CMD_CONSUMER_OFFSET =
5167956Sxiuyan.wang@Sun.COM 	    adapter->ctxDesc_physAddr + sizeof (RingContext);
5177956Sxiuyan.wang@Sun.COM 	adapter->cmdConsumer =
5187956Sxiuyan.wang@Sun.COM 	    (uint32_t *)(uintptr_t)(((char *)addr) + sizeof (RingContext));
5197956Sxiuyan.wang@Sun.COM 
5207956Sxiuyan.wang@Sun.COM 	ASSERT(!((unsigned long)adapter->ctxDesc_physAddr & 0x3f));
5217956Sxiuyan.wang@Sun.COM 
5227956Sxiuyan.wang@Sun.COM 	/*
5237956Sxiuyan.wang@Sun.COM 	 * Allocate command descriptor ring.
5247956Sxiuyan.wang@Sun.COM 	 */
5257956Sxiuyan.wang@Sun.COM 	size = (sizeof (cmdDescType0_t) * adapter->MaxTxDescCount);
5267956Sxiuyan.wang@Sun.COM 	err = unm_pci_alloc_consistent(adapter,
5277956Sxiuyan.wang@Sun.COM 	    size, (caddr_t *)&addr, &cookie,
5287956Sxiuyan.wang@Sun.COM 	    &hw->cmd_desc_dma_handle,
5297956Sxiuyan.wang@Sun.COM 	    &hw->cmd_desc_acc_handle);
5307956Sxiuyan.wang@Sun.COM 	if (err != DDI_SUCCESS) {
5317956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "Failed to allocate cmd desc ring\n");
5327956Sxiuyan.wang@Sun.COM 		return (err);
5337956Sxiuyan.wang@Sun.COM 	}
5347956Sxiuyan.wang@Sun.COM 
5357956Sxiuyan.wang@Sun.COM 	hw->cmdDesc_physAddr = cookie.dmac_laddress;
5367956Sxiuyan.wang@Sun.COM 	hw->cmdDescHead = (cmdDescType0_t *)addr;
5377956Sxiuyan.wang@Sun.COM 
5387956Sxiuyan.wang@Sun.COM 	for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
5397956Sxiuyan.wang@Sun.COM 		recv_ctx = &adapter->recv_ctx[ctx];
5407956Sxiuyan.wang@Sun.COM 
5417956Sxiuyan.wang@Sun.COM 		size = (sizeof (statusDesc_t)* adapter->MaxRxDescCount);
5427956Sxiuyan.wang@Sun.COM 		err = unm_pci_alloc_consistent(adapter,
5437956Sxiuyan.wang@Sun.COM 		    size, (caddr_t *)&addr,
5447956Sxiuyan.wang@Sun.COM 		    &recv_ctx->status_desc_dma_cookie,
5457956Sxiuyan.wang@Sun.COM 		    &recv_ctx->status_desc_dma_handle,
5467956Sxiuyan.wang@Sun.COM 		    &recv_ctx->status_desc_acc_handle);
5477956Sxiuyan.wang@Sun.COM 		if (err != DDI_SUCCESS) {
5487956Sxiuyan.wang@Sun.COM 			cmn_err(CE_WARN, "Failed to allocate sts desc ring\n");
5497956Sxiuyan.wang@Sun.COM 			goto free_cmd_desc;
5507956Sxiuyan.wang@Sun.COM 		}
5517956Sxiuyan.wang@Sun.COM 
5527956Sxiuyan.wang@Sun.COM 		(void) memset(addr, 0, size);
5537956Sxiuyan.wang@Sun.COM 		recv_ctx->rcvStatusDesc_physAddr =
5547956Sxiuyan.wang@Sun.COM 		    recv_ctx->status_desc_dma_cookie.dmac_laddress;
5557956Sxiuyan.wang@Sun.COM 		recv_ctx->rcvStatusDescHead = (statusDesc_t *)addr;
5567956Sxiuyan.wang@Sun.COM 
5577956Sxiuyan.wang@Sun.COM 		/* rds rings */
5587956Sxiuyan.wang@Sun.COM 		for (ring = 0; ring < adapter->max_rds_rings; ring++) {
5597956Sxiuyan.wang@Sun.COM 			rcv_desc = &recv_ctx->rcv_desc[ring];
5607956Sxiuyan.wang@Sun.COM 
5617956Sxiuyan.wang@Sun.COM 			size = (sizeof (rcvDesc_t) * adapter->MaxRxDescCount);
5627956Sxiuyan.wang@Sun.COM 			err = unm_pci_alloc_consistent(adapter,
5637956Sxiuyan.wang@Sun.COM 			    size, (caddr_t *)&addr,
5647956Sxiuyan.wang@Sun.COM 			    &rcv_desc->rx_desc_dma_cookie,
5657956Sxiuyan.wang@Sun.COM 			    &rcv_desc->rx_desc_dma_handle,
5667956Sxiuyan.wang@Sun.COM 			    &rcv_desc->rx_desc_acc_handle);
5677956Sxiuyan.wang@Sun.COM 			if (err != DDI_SUCCESS) {
5687956Sxiuyan.wang@Sun.COM 				cmn_err(CE_WARN, "Failed to allocate "
5697956Sxiuyan.wang@Sun.COM 				    "rx desc ring %d\n", ring);
5707956Sxiuyan.wang@Sun.COM 				goto free_status_desc;
5717956Sxiuyan.wang@Sun.COM 			}
5727956Sxiuyan.wang@Sun.COM 
5737956Sxiuyan.wang@Sun.COM 			rcv_desc->phys_addr =
5747956Sxiuyan.wang@Sun.COM 			    rcv_desc->rx_desc_dma_cookie.dmac_laddress;
5757956Sxiuyan.wang@Sun.COM 			rcv_desc->desc_head = (rcvDesc_t *)addr;
5767956Sxiuyan.wang@Sun.COM 		}
5777956Sxiuyan.wang@Sun.COM 	}
5787956Sxiuyan.wang@Sun.COM 
5797956Sxiuyan.wang@Sun.COM 	if (err = netxen_create_rxtx(adapter))
5807956Sxiuyan.wang@Sun.COM 		goto free_statusrx_desc;
5817956Sxiuyan.wang@Sun.COM 	adapter->context_alloced = 1;
5827956Sxiuyan.wang@Sun.COM 
5837956Sxiuyan.wang@Sun.COM 	return (DDI_SUCCESS);
5847956Sxiuyan.wang@Sun.COM 
5857956Sxiuyan.wang@Sun.COM free_statusrx_desc:
5867956Sxiuyan.wang@Sun.COM free_status_desc:
5877956Sxiuyan.wang@Sun.COM free_cmd_desc:
5887956Sxiuyan.wang@Sun.COM 	unm_free_hw_resources(adapter);
5897956Sxiuyan.wang@Sun.COM 
5907956Sxiuyan.wang@Sun.COM 	return (err);
5917956Sxiuyan.wang@Sun.COM }
5927956Sxiuyan.wang@Sun.COM 
unm_desc_dma_sync(ddi_dma_handle_t handle,uint_t start,uint_t count,uint_t range,uint_t unit_size,uint_t direction)5937956Sxiuyan.wang@Sun.COM void unm_desc_dma_sync(ddi_dma_handle_t handle, uint_t start, uint_t count,
5947956Sxiuyan.wang@Sun.COM     uint_t range, uint_t unit_size, uint_t direction)
5957956Sxiuyan.wang@Sun.COM {
5967956Sxiuyan.wang@Sun.COM 	if ((start + count) < range) {
5977956Sxiuyan.wang@Sun.COM 		(void) ddi_dma_sync(handle, start * unit_size,
5987956Sxiuyan.wang@Sun.COM 		    count * unit_size, direction);
5997956Sxiuyan.wang@Sun.COM 	} else {
6007956Sxiuyan.wang@Sun.COM 		(void) ddi_dma_sync(handle, start * unit_size, 0, direction);
6017956Sxiuyan.wang@Sun.COM 		(void) ddi_dma_sync(handle, 0,
6027956Sxiuyan.wang@Sun.COM 		    (start + count - range) * unit_size, DDI_DMA_SYNC_FORCPU);
6037956Sxiuyan.wang@Sun.COM 	}
6047956Sxiuyan.wang@Sun.COM }
6057956Sxiuyan.wang@Sun.COM 
6067956Sxiuyan.wang@Sun.COM static uint32_t crb_cmd_producer[4] = { CRB_CMD_PRODUCER_OFFSET,
6077956Sxiuyan.wang@Sun.COM     CRB_CMD_PRODUCER_OFFSET_1, CRB_CMD_PRODUCER_OFFSET_2,
6087956Sxiuyan.wang@Sun.COM     CRB_CMD_PRODUCER_OFFSET_3 };
6097956Sxiuyan.wang@Sun.COM 
6107956Sxiuyan.wang@Sun.COM static uint32_t crb_cmd_consumer[4] = { CRB_CMD_CONSUMER_OFFSET,
6117956Sxiuyan.wang@Sun.COM     CRB_CMD_CONSUMER_OFFSET_1, CRB_CMD_CONSUMER_OFFSET_2,
6127956Sxiuyan.wang@Sun.COM     CRB_CMD_CONSUMER_OFFSET_3 };
6137956Sxiuyan.wang@Sun.COM 
6147956Sxiuyan.wang@Sun.COM void
unm_nic_update_cmd_producer(struct unm_adapter_s * adapter,uint32_t crb_producer)6157956Sxiuyan.wang@Sun.COM unm_nic_update_cmd_producer(struct unm_adapter_s *adapter,
6167956Sxiuyan.wang@Sun.COM     uint32_t crb_producer)
6177956Sxiuyan.wang@Sun.COM {
6187956Sxiuyan.wang@Sun.COM 	int data = crb_producer;
6197956Sxiuyan.wang@Sun.COM 
6207956Sxiuyan.wang@Sun.COM 	if (adapter->crb_addr_cmd_producer) {
6217956Sxiuyan.wang@Sun.COM 		UNM_READ_LOCK(&adapter->adapter_lock);
6227956Sxiuyan.wang@Sun.COM 		adapter->unm_nic_hw_write_wx(adapter,
6237956Sxiuyan.wang@Sun.COM 		    adapter->crb_addr_cmd_producer, &data, 4);
6247956Sxiuyan.wang@Sun.COM 		UNM_READ_UNLOCK(&adapter->adapter_lock);
6257956Sxiuyan.wang@Sun.COM 	}
6267956Sxiuyan.wang@Sun.COM }
6277956Sxiuyan.wang@Sun.COM 
6287956Sxiuyan.wang@Sun.COM static void
unm_nic_update_cmd_consumer(struct unm_adapter_s * adapter,uint32_t crb_producer)6297956Sxiuyan.wang@Sun.COM unm_nic_update_cmd_consumer(struct unm_adapter_s *adapter,
6307956Sxiuyan.wang@Sun.COM     uint32_t crb_producer)
6317956Sxiuyan.wang@Sun.COM {
6327956Sxiuyan.wang@Sun.COM 	int data = crb_producer;
6337956Sxiuyan.wang@Sun.COM 
6347956Sxiuyan.wang@Sun.COM 	if (adapter->crb_addr_cmd_consumer)
6357956Sxiuyan.wang@Sun.COM 		adapter->unm_nic_hw_write_wx(adapter,
6367956Sxiuyan.wang@Sun.COM 		    adapter->crb_addr_cmd_consumer, &data, 4);
6377956Sxiuyan.wang@Sun.COM }
6387956Sxiuyan.wang@Sun.COM 
6397956Sxiuyan.wang@Sun.COM /*
6407956Sxiuyan.wang@Sun.COM  * Looks for type of packet and sets opcode accordingly
6417956Sxiuyan.wang@Sun.COM  * so that checksum offload can be used.
6427956Sxiuyan.wang@Sun.COM  */
6437956Sxiuyan.wang@Sun.COM static void
unm_tx_csum(cmdDescType0_t * desc,mblk_t * mp,pktinfo_t * pktinfo)6447956Sxiuyan.wang@Sun.COM unm_tx_csum(cmdDescType0_t *desc, mblk_t *mp, pktinfo_t *pktinfo)
6457956Sxiuyan.wang@Sun.COM {
6467956Sxiuyan.wang@Sun.COM 	if (pktinfo->mac_hlen == sizeof (struct ether_vlan_header))
6477956Sxiuyan.wang@Sun.COM 		desc->u1.s1.flags = FLAGS_VLAN_TAGGED;
6487956Sxiuyan.wang@Sun.COM 
6497956Sxiuyan.wang@Sun.COM 	if (pktinfo->etype == htons(ETHERTYPE_IP)) {
6507956Sxiuyan.wang@Sun.COM 		uint32_t	start, flags;
6517956Sxiuyan.wang@Sun.COM 
652*11878SVenu.Iyer@Sun.COM 		mac_hcksum_get(mp, &start, NULL, NULL, NULL, &flags);
6537956Sxiuyan.wang@Sun.COM 		if ((flags & (HCK_FULLCKSUM | HCK_IPV4_HDRCKSUM)) == 0)
6547956Sxiuyan.wang@Sun.COM 			return;
6557956Sxiuyan.wang@Sun.COM 
6567956Sxiuyan.wang@Sun.COM 		/*
6577956Sxiuyan.wang@Sun.COM 		 * For TCP/UDP, ask hardware to do both IP header and
6587956Sxiuyan.wang@Sun.COM 		 * full checksum, even if stack has already done one or
6597956Sxiuyan.wang@Sun.COM 		 * the other. Hardware will always get it correct even
6607956Sxiuyan.wang@Sun.COM 		 * if stack has already done it.
6617956Sxiuyan.wang@Sun.COM 		 */
6627956Sxiuyan.wang@Sun.COM 		switch (pktinfo->l4_proto) {
6637956Sxiuyan.wang@Sun.COM 			case IPPROTO_TCP:
6647956Sxiuyan.wang@Sun.COM 				desc->u1.s1.opcode = TX_TCP_PKT;
6657956Sxiuyan.wang@Sun.COM 				break;
6667956Sxiuyan.wang@Sun.COM 			case IPPROTO_UDP:
6677956Sxiuyan.wang@Sun.COM 				desc->u1.s1.opcode = TX_UDP_PKT;
6687956Sxiuyan.wang@Sun.COM 				break;
6697956Sxiuyan.wang@Sun.COM 			default:
6707956Sxiuyan.wang@Sun.COM 				/* Must be here with HCK_IPV4_HDRCKSUM */
6717956Sxiuyan.wang@Sun.COM 				desc->u1.s1.opcode = TX_IP_PKT;
6727956Sxiuyan.wang@Sun.COM 				return;
6737956Sxiuyan.wang@Sun.COM 		}
6747956Sxiuyan.wang@Sun.COM 
6757956Sxiuyan.wang@Sun.COM 		desc->u1.s1.ipHdrOffset = pktinfo->mac_hlen;
6767956Sxiuyan.wang@Sun.COM 		desc->u1.s1.tcpHdrOffset = pktinfo->mac_hlen + pktinfo->ip_hlen;
6777956Sxiuyan.wang@Sun.COM 	}
6787956Sxiuyan.wang@Sun.COM }
6797956Sxiuyan.wang@Sun.COM 
6807956Sxiuyan.wang@Sun.COM /*
6817956Sxiuyan.wang@Sun.COM  * For IP/UDP/TCP checksum offload, this checks for MAC+IP header in one
6827956Sxiuyan.wang@Sun.COM  * contiguous block ending at 8 byte aligned address as required by hardware.
6837956Sxiuyan.wang@Sun.COM  * Caller assumes pktinfo->total_len will be updated by this function and
6847956Sxiuyan.wang@Sun.COM  * if pktinfo->etype is set to 0, it will need to linearize the mblk and
6857956Sxiuyan.wang@Sun.COM  * invoke unm_update_pkt_info() to determine ethertype, IP header len and
6867956Sxiuyan.wang@Sun.COM  * protocol.
6877956Sxiuyan.wang@Sun.COM  */
6887956Sxiuyan.wang@Sun.COM static boolean_t
unm_get_pkt_info(mblk_t * mp,pktinfo_t * pktinfo)6897956Sxiuyan.wang@Sun.COM unm_get_pkt_info(mblk_t *mp, pktinfo_t *pktinfo)
6907956Sxiuyan.wang@Sun.COM {
6917956Sxiuyan.wang@Sun.COM 	mblk_t		*bp;
6927956Sxiuyan.wang@Sun.COM 	ushort_t	type;
6937956Sxiuyan.wang@Sun.COM 
6947956Sxiuyan.wang@Sun.COM 	(void) memset(pktinfo, 0, sizeof (pktinfo_t));
6957956Sxiuyan.wang@Sun.COM 
6967956Sxiuyan.wang@Sun.COM 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
6977956Sxiuyan.wang@Sun.COM 		if (MBLKL(bp) == 0)
6987956Sxiuyan.wang@Sun.COM 			continue;
6997956Sxiuyan.wang@Sun.COM 		pktinfo->mblk_no++;
7007956Sxiuyan.wang@Sun.COM 		pktinfo->total_len += MBLKL(bp);
7017956Sxiuyan.wang@Sun.COM 	}
7027956Sxiuyan.wang@Sun.COM 
7037956Sxiuyan.wang@Sun.COM 	if (MBLKL(mp) < (sizeof (struct ether_header) + sizeof (ipha_t)))
7047956Sxiuyan.wang@Sun.COM 		return (B_FALSE);
7057956Sxiuyan.wang@Sun.COM 
7067956Sxiuyan.wang@Sun.COM 	/*
7077956Sxiuyan.wang@Sun.COM 	 * We just need non 1 byte aligned address, since ether_type is
7087956Sxiuyan.wang@Sun.COM 	 * ushort.
7097956Sxiuyan.wang@Sun.COM 	 */
7107956Sxiuyan.wang@Sun.COM 	if ((uintptr_t)mp->b_rptr & 1)
7117956Sxiuyan.wang@Sun.COM 		return (B_FALSE);
7127956Sxiuyan.wang@Sun.COM 
7137956Sxiuyan.wang@Sun.COM 	type = ((struct ether_header *)(uintptr_t)mp->b_rptr)->ether_type;
7147956Sxiuyan.wang@Sun.COM 	if (type == htons(ETHERTYPE_VLAN)) {
7157956Sxiuyan.wang@Sun.COM 		if (MBLKL(mp) < (sizeof (struct ether_vlan_header) +
7167956Sxiuyan.wang@Sun.COM 		    sizeof (ipha_t)))
7177956Sxiuyan.wang@Sun.COM 			return (B_FALSE);
7187956Sxiuyan.wang@Sun.COM 		type = ((struct ether_vlan_header *) \
7197956Sxiuyan.wang@Sun.COM 		    (uintptr_t)mp->b_rptr)->ether_type;
7207956Sxiuyan.wang@Sun.COM 		pktinfo->mac_hlen = sizeof (struct ether_vlan_header);
7217956Sxiuyan.wang@Sun.COM 	} else {
7227956Sxiuyan.wang@Sun.COM 		pktinfo->mac_hlen = sizeof (struct ether_header);
7237956Sxiuyan.wang@Sun.COM 	}
7247956Sxiuyan.wang@Sun.COM 	pktinfo->etype = type;
7257956Sxiuyan.wang@Sun.COM 
7267956Sxiuyan.wang@Sun.COM 	if (pktinfo->etype == htons(ETHERTYPE_IP)) {
7277956Sxiuyan.wang@Sun.COM 		uchar_t *ip_off = mp->b_rptr + pktinfo->mac_hlen;
7287956Sxiuyan.wang@Sun.COM 
7297956Sxiuyan.wang@Sun.COM 		pktinfo->ip_hlen = IPH_HDR_LENGTH((uintptr_t)ip_off);
7307956Sxiuyan.wang@Sun.COM 		pktinfo->l4_proto =
7317956Sxiuyan.wang@Sun.COM 		    ((ipha_t *)(uintptr_t)ip_off)->ipha_protocol;
7327956Sxiuyan.wang@Sun.COM 
7337956Sxiuyan.wang@Sun.COM 		/* IP header not aligned to quadward boundary? */
7347956Sxiuyan.wang@Sun.COM 		if ((unsigned long)(ip_off + pktinfo->ip_hlen) % 8 != 0)
7357956Sxiuyan.wang@Sun.COM 			return (B_FALSE);
7367956Sxiuyan.wang@Sun.COM 	}
7377956Sxiuyan.wang@Sun.COM 
7387956Sxiuyan.wang@Sun.COM 	return (B_TRUE);
7397956Sxiuyan.wang@Sun.COM }
7407956Sxiuyan.wang@Sun.COM 
7417956Sxiuyan.wang@Sun.COM static void
unm_update_pkt_info(char * ptr,pktinfo_t * pktinfo)7427956Sxiuyan.wang@Sun.COM unm_update_pkt_info(char *ptr, pktinfo_t *pktinfo)
7437956Sxiuyan.wang@Sun.COM {
7447956Sxiuyan.wang@Sun.COM 	ushort_t	type;
7457956Sxiuyan.wang@Sun.COM 
7467956Sxiuyan.wang@Sun.COM 	type = ((struct ether_header *)(uintptr_t)ptr)->ether_type;
7477956Sxiuyan.wang@Sun.COM 	if (type == htons(ETHERTYPE_VLAN)) {
7487956Sxiuyan.wang@Sun.COM 		type = ((struct ether_vlan_header *)(uintptr_t)ptr)->ether_type;
7497956Sxiuyan.wang@Sun.COM 		pktinfo->mac_hlen = sizeof (struct ether_vlan_header);
7507956Sxiuyan.wang@Sun.COM 	} else {
7517956Sxiuyan.wang@Sun.COM 		pktinfo->mac_hlen = sizeof (struct ether_header);
7527956Sxiuyan.wang@Sun.COM 	}
7537956Sxiuyan.wang@Sun.COM 	pktinfo->etype = type;
7547956Sxiuyan.wang@Sun.COM 
7557956Sxiuyan.wang@Sun.COM 	if (pktinfo->etype == htons(ETHERTYPE_IP)) {
7567956Sxiuyan.wang@Sun.COM 		char *ipp = ptr + pktinfo->mac_hlen;
7577956Sxiuyan.wang@Sun.COM 
7587956Sxiuyan.wang@Sun.COM 		pktinfo->ip_hlen = IPH_HDR_LENGTH((uintptr_t)ipp);
7597956Sxiuyan.wang@Sun.COM 		pktinfo->l4_proto = ((ipha_t *)(uintptr_t)ipp)->ipha_protocol;
7607956Sxiuyan.wang@Sun.COM 	}
7617956Sxiuyan.wang@Sun.COM }
7627956Sxiuyan.wang@Sun.COM 
7637956Sxiuyan.wang@Sun.COM static boolean_t
unm_send_copy(struct unm_adapter_s * adapter,mblk_t * mp,pktinfo_t * pktinfo)7647956Sxiuyan.wang@Sun.COM unm_send_copy(struct unm_adapter_s *adapter, mblk_t *mp, pktinfo_t *pktinfo)
7657956Sxiuyan.wang@Sun.COM {
7667956Sxiuyan.wang@Sun.COM 	hardware_context *hw;
7677956Sxiuyan.wang@Sun.COM 	u32				producer = 0;
7687956Sxiuyan.wang@Sun.COM 	cmdDescType0_t			*hwdesc;
7697956Sxiuyan.wang@Sun.COM 	struct unm_cmd_buffer		*pbuf = NULL;
7707956Sxiuyan.wang@Sun.COM 	u32				mblen;
7717956Sxiuyan.wang@Sun.COM 	int				no_of_desc = 1;
7727956Sxiuyan.wang@Sun.COM 	int				MaxTxDescCount;
7737956Sxiuyan.wang@Sun.COM 	mblk_t				*bp;
7747956Sxiuyan.wang@Sun.COM 	char				*txb;
7757956Sxiuyan.wang@Sun.COM 
7767956Sxiuyan.wang@Sun.COM 	hw = &adapter->ahw;
7777956Sxiuyan.wang@Sun.COM 	MaxTxDescCount = adapter->MaxTxDescCount;
7787956Sxiuyan.wang@Sun.COM 
7797956Sxiuyan.wang@Sun.COM 	UNM_SPIN_LOCK(&adapter->tx_lock);
7807956Sxiuyan.wang@Sun.COM 	membar_enter();
7817956Sxiuyan.wang@Sun.COM 
7827956Sxiuyan.wang@Sun.COM 	if (find_diff_among(adapter->cmdProducer, adapter->lastCmdConsumer,
7837956Sxiuyan.wang@Sun.COM 	    MaxTxDescCount) <= 2) {
7847956Sxiuyan.wang@Sun.COM 		adapter->stats.outofcmddesc++;
7857956Sxiuyan.wang@Sun.COM 		adapter->resched_needed = 1;
7867956Sxiuyan.wang@Sun.COM 		membar_exit();
7877956Sxiuyan.wang@Sun.COM 		UNM_SPIN_UNLOCK(&adapter->tx_lock);
7887956Sxiuyan.wang@Sun.COM 		return (B_FALSE);
7897956Sxiuyan.wang@Sun.COM 	}
7907956Sxiuyan.wang@Sun.COM 	adapter->freecmds -= no_of_desc;
7917956Sxiuyan.wang@Sun.COM 
7927956Sxiuyan.wang@Sun.COM 	producer = adapter->cmdProducer;
7937956Sxiuyan.wang@Sun.COM 
7947956Sxiuyan.wang@Sun.COM 	adapter->cmdProducer = get_index_range(adapter->cmdProducer,
7957956Sxiuyan.wang@Sun.COM 	    MaxTxDescCount, no_of_desc);
7967956Sxiuyan.wang@Sun.COM 
7977956Sxiuyan.wang@Sun.COM 	hwdesc = &hw->cmdDescHead[producer];
7987956Sxiuyan.wang@Sun.COM 	(void) memset(hwdesc, 0, sizeof (cmdDescType0_t));
7997956Sxiuyan.wang@Sun.COM 	pbuf = &adapter->cmd_buf_arr[producer];
8007956Sxiuyan.wang@Sun.COM 
8017956Sxiuyan.wang@Sun.COM 	pbuf->msg = NULL;
8027956Sxiuyan.wang@Sun.COM 	pbuf->head = NULL;
8037956Sxiuyan.wang@Sun.COM 	pbuf->tail = NULL;
8047956Sxiuyan.wang@Sun.COM 
8057956Sxiuyan.wang@Sun.COM 	txb = pbuf->dma_area.vaddr;
8067956Sxiuyan.wang@Sun.COM 
8077956Sxiuyan.wang@Sun.COM 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
8087956Sxiuyan.wang@Sun.COM 		if ((mblen = MBLKL(bp)) == 0)
8097956Sxiuyan.wang@Sun.COM 			continue;
8107956Sxiuyan.wang@Sun.COM 		bcopy(bp->b_rptr, txb, mblen);
8117956Sxiuyan.wang@Sun.COM 		txb += mblen;
8127956Sxiuyan.wang@Sun.COM 	}
8137956Sxiuyan.wang@Sun.COM 
8147956Sxiuyan.wang@Sun.COM 	/*
8157956Sxiuyan.wang@Sun.COM 	 * Determine metadata if not previously done due to fragmented mblk.
8167956Sxiuyan.wang@Sun.COM 	 */
8177956Sxiuyan.wang@Sun.COM 	if (pktinfo->etype == 0)
8187956Sxiuyan.wang@Sun.COM 		unm_update_pkt_info(pbuf->dma_area.vaddr, pktinfo);
8197956Sxiuyan.wang@Sun.COM 
8207956Sxiuyan.wang@Sun.COM 	(void) ddi_dma_sync(pbuf->dma_area.dma_hdl,
8217956Sxiuyan.wang@Sun.COM 	    0, pktinfo->total_len, DDI_DMA_SYNC_FORDEV);
8227956Sxiuyan.wang@Sun.COM 
8237956Sxiuyan.wang@Sun.COM 	/* hwdesc->u1.s1.tcpHdrOffset = 0; */
8247956Sxiuyan.wang@Sun.COM 	/* hwdesc->mss = 0; */
8257956Sxiuyan.wang@Sun.COM 	hwdesc->u1.s1.opcode = TX_ETHER_PKT;
8267956Sxiuyan.wang@Sun.COM 	hwdesc->u3.s1.port = adapter->portnum;
8277956Sxiuyan.wang@Sun.COM 	hwdesc->u3.s1.ctx_id = adapter->portnum;
8287956Sxiuyan.wang@Sun.COM 
8297956Sxiuyan.wang@Sun.COM 	hwdesc->u6.s1.buffer1Length = pktinfo->total_len;
8307956Sxiuyan.wang@Sun.COM 	hwdesc->u5.AddrBuffer1 = pbuf->dma_area.dma_addr;
8317956Sxiuyan.wang@Sun.COM 	hwdesc->u1.s1.numOfBuffers = 1;
8327956Sxiuyan.wang@Sun.COM 	hwdesc->u1.s1.totalLength = pktinfo->total_len;
8337956Sxiuyan.wang@Sun.COM 
8347956Sxiuyan.wang@Sun.COM 	unm_tx_csum(hwdesc, mp, pktinfo);
8357956Sxiuyan.wang@Sun.COM 
8367956Sxiuyan.wang@Sun.COM 	unm_desc_dma_sync(hw->cmd_desc_dma_handle,
8377956Sxiuyan.wang@Sun.COM 	    producer,
8387956Sxiuyan.wang@Sun.COM 	    no_of_desc,
8397956Sxiuyan.wang@Sun.COM 	    MaxTxDescCount,
8407956Sxiuyan.wang@Sun.COM 	    sizeof (cmdDescType0_t),
8417956Sxiuyan.wang@Sun.COM 	    DDI_DMA_SYNC_FORDEV);
8427956Sxiuyan.wang@Sun.COM 
8437956Sxiuyan.wang@Sun.COM 	hw->cmdProducer = adapter->cmdProducer;
8447956Sxiuyan.wang@Sun.COM 	unm_nic_update_cmd_producer(adapter, adapter->cmdProducer);
8457956Sxiuyan.wang@Sun.COM 
8467956Sxiuyan.wang@Sun.COM 	adapter->stats.txbytes += pktinfo->total_len;
8477956Sxiuyan.wang@Sun.COM 	adapter->stats.xmitfinished++;
8487956Sxiuyan.wang@Sun.COM 	adapter->stats.txcopyed++;
8497956Sxiuyan.wang@Sun.COM 	UNM_SPIN_UNLOCK(&adapter->tx_lock);
8507956Sxiuyan.wang@Sun.COM 
8517956Sxiuyan.wang@Sun.COM 	freemsg(mp);
8527956Sxiuyan.wang@Sun.COM 	return (B_TRUE);
8537956Sxiuyan.wang@Sun.COM }
8547956Sxiuyan.wang@Sun.COM 
8557956Sxiuyan.wang@Sun.COM /* Should be called with adapter->tx_lock held. */
8567956Sxiuyan.wang@Sun.COM static void
unm_return_dma_handle(unm_adapter * adapter,unm_dmah_node_t * head,unm_dmah_node_t * tail,uint32_t num)8577956Sxiuyan.wang@Sun.COM unm_return_dma_handle(unm_adapter *adapter, unm_dmah_node_t *head,
8587956Sxiuyan.wang@Sun.COM     unm_dmah_node_t *tail, uint32_t num)
8597956Sxiuyan.wang@Sun.COM {
8607956Sxiuyan.wang@Sun.COM 	ASSERT(tail != NULL);
8617956Sxiuyan.wang@Sun.COM 	tail->next = adapter->dmahdl_pool;
8627956Sxiuyan.wang@Sun.COM 	adapter->dmahdl_pool = head;
8637956Sxiuyan.wang@Sun.COM 	adapter->freehdls += num;
8647956Sxiuyan.wang@Sun.COM }
8657956Sxiuyan.wang@Sun.COM 
8667956Sxiuyan.wang@Sun.COM static unm_dmah_node_t *
unm_reserve_dma_handle(unm_adapter * adapter)8677956Sxiuyan.wang@Sun.COM unm_reserve_dma_handle(unm_adapter* adapter)
8687956Sxiuyan.wang@Sun.COM {
8697956Sxiuyan.wang@Sun.COM 	unm_dmah_node_t *dmah = NULL;
8707956Sxiuyan.wang@Sun.COM 
8717956Sxiuyan.wang@Sun.COM 	dmah = adapter->dmahdl_pool;
8727956Sxiuyan.wang@Sun.COM 	if (dmah != NULL) {
8737956Sxiuyan.wang@Sun.COM 		adapter->dmahdl_pool = dmah->next;
8747956Sxiuyan.wang@Sun.COM 		dmah->next = NULL;
8757956Sxiuyan.wang@Sun.COM 		adapter->freehdls--;
8767956Sxiuyan.wang@Sun.COM 		membar_exit();
8777956Sxiuyan.wang@Sun.COM 	}
8787956Sxiuyan.wang@Sun.COM 
8797956Sxiuyan.wang@Sun.COM 	return (dmah);
8807956Sxiuyan.wang@Sun.COM }
8817956Sxiuyan.wang@Sun.COM 
8827956Sxiuyan.wang@Sun.COM static boolean_t
unm_send_mapped(struct unm_adapter_s * adapter,mblk_t * mp,pktinfo_t * pktinfo)8837956Sxiuyan.wang@Sun.COM unm_send_mapped(struct unm_adapter_s *adapter, mblk_t *mp, pktinfo_t *pktinfo)
8847956Sxiuyan.wang@Sun.COM {
8857956Sxiuyan.wang@Sun.COM 	hardware_context		*hw;
8867956Sxiuyan.wang@Sun.COM 	u32				producer = 0;
8877956Sxiuyan.wang@Sun.COM 	u32				saved_producer = 0;
8887956Sxiuyan.wang@Sun.COM 	cmdDescType0_t			*hwdesc;
8897956Sxiuyan.wang@Sun.COM 	struct unm_cmd_buffer		*pbuf = NULL;
8907956Sxiuyan.wang@Sun.COM 	int				no_of_desc;
8917956Sxiuyan.wang@Sun.COM 	int				k;
8927956Sxiuyan.wang@Sun.COM 	int				MaxTxDescCount;
8937956Sxiuyan.wang@Sun.COM 	mblk_t				*bp;
8947956Sxiuyan.wang@Sun.COM 
8957956Sxiuyan.wang@Sun.COM 	unm_dmah_node_t *dmah, *head = NULL, *tail = NULL, *hdlp;
8967956Sxiuyan.wang@Sun.COM 	ddi_dma_cookie_t cookie[MAX_COOKIES_PER_CMD + 1];
8977956Sxiuyan.wang@Sun.COM 	int ret, i;
8987956Sxiuyan.wang@Sun.COM 	uint32_t hdl_reserved = 0;
8997956Sxiuyan.wang@Sun.COM 	uint32_t mblen;
9007956Sxiuyan.wang@Sun.COM 	uint32_t ncookies, index = 0, total_cookies = 0;
9017956Sxiuyan.wang@Sun.COM 
9027956Sxiuyan.wang@Sun.COM 	MaxTxDescCount = adapter->MaxTxDescCount;
9037956Sxiuyan.wang@Sun.COM 
9047956Sxiuyan.wang@Sun.COM 	UNM_SPIN_LOCK(&adapter->tx_lock);
9057956Sxiuyan.wang@Sun.COM 
9067956Sxiuyan.wang@Sun.COM 	/* bind all the mblks of the packet first */
9077956Sxiuyan.wang@Sun.COM 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
9087956Sxiuyan.wang@Sun.COM 		mblen = MBLKL(bp);
9097956Sxiuyan.wang@Sun.COM 		if (mblen == 0)
9107956Sxiuyan.wang@Sun.COM 			continue;
9117956Sxiuyan.wang@Sun.COM 
9127956Sxiuyan.wang@Sun.COM 		dmah = unm_reserve_dma_handle(adapter);
9137956Sxiuyan.wang@Sun.COM 		if (dmah == NULL) {
9147956Sxiuyan.wang@Sun.COM 			adapter->stats.outoftxdmahdl++;
9157956Sxiuyan.wang@Sun.COM 			goto err_map;
9167956Sxiuyan.wang@Sun.COM 		}
9177956Sxiuyan.wang@Sun.COM 
9187956Sxiuyan.wang@Sun.COM 		ret = ddi_dma_addr_bind_handle(dmah->dmahdl,
9197956Sxiuyan.wang@Sun.COM 		    NULL, (caddr_t)bp->b_rptr, mblen,
9207956Sxiuyan.wang@Sun.COM 		    DDI_DMA_STREAMING | DDI_DMA_WRITE,
9217956Sxiuyan.wang@Sun.COM 		    DDI_DMA_DONTWAIT, NULL, &cookie[index], &ncookies);
9227956Sxiuyan.wang@Sun.COM 
9237956Sxiuyan.wang@Sun.COM 		if (ret != DDI_DMA_MAPPED)
9247956Sxiuyan.wang@Sun.COM 			goto err_map;
9257956Sxiuyan.wang@Sun.COM 
9267956Sxiuyan.wang@Sun.COM 		if (tail == NULL) {
9277956Sxiuyan.wang@Sun.COM 			head = tail = dmah;
9287956Sxiuyan.wang@Sun.COM 		} else {
9297956Sxiuyan.wang@Sun.COM 			tail->next = dmah;
9307956Sxiuyan.wang@Sun.COM 			tail = dmah;
9317956Sxiuyan.wang@Sun.COM 		}
9327956Sxiuyan.wang@Sun.COM 		hdl_reserved++;
9337956Sxiuyan.wang@Sun.COM 
9347956Sxiuyan.wang@Sun.COM 		total_cookies += ncookies;
9357956Sxiuyan.wang@Sun.COM 		if (total_cookies > MAX_COOKIES_PER_CMD) {
9367956Sxiuyan.wang@Sun.COM 			dmah = NULL;
9377956Sxiuyan.wang@Sun.COM 			goto err_map;
9387956Sxiuyan.wang@Sun.COM 		}
9397956Sxiuyan.wang@Sun.COM 
9407956Sxiuyan.wang@Sun.COM 		if (index == 0) {
9417956Sxiuyan.wang@Sun.COM 			size_t	hsize = cookie[0].dmac_size;
9427956Sxiuyan.wang@Sun.COM 
9437956Sxiuyan.wang@Sun.COM 			/*
9447956Sxiuyan.wang@Sun.COM 			 * For TCP/UDP packets with checksum offload,
9457956Sxiuyan.wang@Sun.COM 			 * MAC/IP headers need to be contiguous. Otherwise,
9467956Sxiuyan.wang@Sun.COM 			 * there must be at least 16 bytes in the first
9477956Sxiuyan.wang@Sun.COM 			 * descriptor.
9487956Sxiuyan.wang@Sun.COM 			 */
9497956Sxiuyan.wang@Sun.COM 			if ((pktinfo->l4_proto == IPPROTO_TCP) ||
9507956Sxiuyan.wang@Sun.COM 			    (pktinfo->l4_proto == IPPROTO_UDP)) {
9517956Sxiuyan.wang@Sun.COM 				if (hsize < (pktinfo->mac_hlen +
9527956Sxiuyan.wang@Sun.COM 				    pktinfo->ip_hlen)) {
9537956Sxiuyan.wang@Sun.COM 					dmah = NULL;
9547956Sxiuyan.wang@Sun.COM 					goto err_map;
9557956Sxiuyan.wang@Sun.COM 				}
9567956Sxiuyan.wang@Sun.COM 			} else {
9577956Sxiuyan.wang@Sun.COM 				if (hsize < 16) {
9587956Sxiuyan.wang@Sun.COM 					dmah = NULL;
9597956Sxiuyan.wang@Sun.COM 					goto err_map;
9607956Sxiuyan.wang@Sun.COM 				}
9617956Sxiuyan.wang@Sun.COM 			}
9627956Sxiuyan.wang@Sun.COM 		}
9637956Sxiuyan.wang@Sun.COM 
9647956Sxiuyan.wang@Sun.COM 		index++;
9657956Sxiuyan.wang@Sun.COM 		ncookies--;
9667956Sxiuyan.wang@Sun.COM 		for (i = 0; i < ncookies; i++, index++)
9677956Sxiuyan.wang@Sun.COM 			ddi_dma_nextcookie(dmah->dmahdl, &cookie[index]);
9687956Sxiuyan.wang@Sun.COM 	}
9697956Sxiuyan.wang@Sun.COM 
9707956Sxiuyan.wang@Sun.COM 	dmah = NULL;
9717956Sxiuyan.wang@Sun.COM 	hw = &adapter->ahw;
9727956Sxiuyan.wang@Sun.COM 	no_of_desc = (total_cookies + 3) >> 2;
9737956Sxiuyan.wang@Sun.COM 
9747956Sxiuyan.wang@Sun.COM 	membar_enter();
9757956Sxiuyan.wang@Sun.COM 	if (find_diff_among(adapter->cmdProducer, adapter->lastCmdConsumer,
9767956Sxiuyan.wang@Sun.COM 	    MaxTxDescCount) < no_of_desc+2) {
9777956Sxiuyan.wang@Sun.COM 		/*
9787956Sxiuyan.wang@Sun.COM 		 * If we are going to be trying the copy path, no point
9797956Sxiuyan.wang@Sun.COM 		 * scheduling an upcall when Tx resources are freed.
9807956Sxiuyan.wang@Sun.COM 		 */
9817956Sxiuyan.wang@Sun.COM 		if (pktinfo->total_len > adapter->maxmtu) {
9827956Sxiuyan.wang@Sun.COM 			adapter->stats.outofcmddesc++;
9837956Sxiuyan.wang@Sun.COM 			adapter->resched_needed = 1;
9847956Sxiuyan.wang@Sun.COM 		}
9857956Sxiuyan.wang@Sun.COM 		membar_exit();
9867956Sxiuyan.wang@Sun.COM 		goto err_alloc_desc;
9877956Sxiuyan.wang@Sun.COM 	}
9887956Sxiuyan.wang@Sun.COM 	adapter->freecmds -= no_of_desc;
9897956Sxiuyan.wang@Sun.COM 
9907956Sxiuyan.wang@Sun.COM 	/* Copy the descriptors into the hardware    */
9917956Sxiuyan.wang@Sun.COM 	producer = adapter->cmdProducer;
9927956Sxiuyan.wang@Sun.COM 	saved_producer = producer;
9937956Sxiuyan.wang@Sun.COM 	hwdesc = &hw->cmdDescHead[producer];
9947956Sxiuyan.wang@Sun.COM 	(void) memset(hwdesc, 0, sizeof (cmdDescType0_t));
9957956Sxiuyan.wang@Sun.COM 	pbuf = &adapter->cmd_buf_arr[producer];
9967956Sxiuyan.wang@Sun.COM 
9977956Sxiuyan.wang@Sun.COM 	pbuf->msg = mp;
9987956Sxiuyan.wang@Sun.COM 	pbuf->head = head;
9997956Sxiuyan.wang@Sun.COM 	pbuf->tail = tail;
10007956Sxiuyan.wang@Sun.COM 
10017956Sxiuyan.wang@Sun.COM 	hwdesc->u1.s1.numOfBuffers = total_cookies;
10027956Sxiuyan.wang@Sun.COM 	hwdesc->u1.s1.opcode = TX_ETHER_PKT;
10037956Sxiuyan.wang@Sun.COM 	hwdesc->u3.s1.port = adapter->portnum;
10047956Sxiuyan.wang@Sun.COM 	/* hwdesc->u1.s1.tcpHdrOffset = 0; */
10057956Sxiuyan.wang@Sun.COM 	/* hwdesc->mss = 0; */
10067956Sxiuyan.wang@Sun.COM 	hwdesc->u3.s1.ctx_id = adapter->portnum;
10077956Sxiuyan.wang@Sun.COM 	hwdesc->u1.s1.totalLength = pktinfo->total_len;
10087956Sxiuyan.wang@Sun.COM 	unm_tx_csum(hwdesc, mp, pktinfo);
10097956Sxiuyan.wang@Sun.COM 
10107956Sxiuyan.wang@Sun.COM 	for (i = k = 0; i < total_cookies; i++) {
10117956Sxiuyan.wang@Sun.COM 		if (k == 4) {
10127956Sxiuyan.wang@Sun.COM 			/* Move to the next descriptor */
10137956Sxiuyan.wang@Sun.COM 			k = 0;
10147956Sxiuyan.wang@Sun.COM 			producer = get_next_index(producer, MaxTxDescCount);
10157956Sxiuyan.wang@Sun.COM 			hwdesc = &hw->cmdDescHead[producer];
10167956Sxiuyan.wang@Sun.COM 			(void) memset(hwdesc, 0, sizeof (cmdDescType0_t));
10177956Sxiuyan.wang@Sun.COM 		}
10187956Sxiuyan.wang@Sun.COM 
10197956Sxiuyan.wang@Sun.COM 		switch (k) {
10207956Sxiuyan.wang@Sun.COM 		case 0:
10217956Sxiuyan.wang@Sun.COM 			hwdesc->u6.s1.buffer1Length = cookie[i].dmac_size;
10227956Sxiuyan.wang@Sun.COM 			hwdesc->u5.AddrBuffer1 = cookie[i].dmac_laddress;
10237956Sxiuyan.wang@Sun.COM 			break;
10247956Sxiuyan.wang@Sun.COM 		case 1:
10257956Sxiuyan.wang@Sun.COM 			hwdesc->u6.s1.buffer2Length = cookie[i].dmac_size;
10267956Sxiuyan.wang@Sun.COM 			hwdesc->u2.AddrBuffer2 = cookie[i].dmac_laddress;
10277956Sxiuyan.wang@Sun.COM 			break;
10287956Sxiuyan.wang@Sun.COM 		case 2:
10297956Sxiuyan.wang@Sun.COM 			hwdesc->u6.s1.buffer3Length = cookie[i].dmac_size;
10307956Sxiuyan.wang@Sun.COM 			hwdesc->u4.AddrBuffer3 = cookie[i].dmac_laddress;
10317956Sxiuyan.wang@Sun.COM 			break;
10327956Sxiuyan.wang@Sun.COM 		case 3:
10337956Sxiuyan.wang@Sun.COM 			hwdesc->u6.s1.buffer4Length = cookie[i].dmac_size;
10347956Sxiuyan.wang@Sun.COM 			hwdesc->u7.AddrBuffer4 = cookie[i].dmac_laddress;
10357956Sxiuyan.wang@Sun.COM 			break;
10367956Sxiuyan.wang@Sun.COM 		}
10377956Sxiuyan.wang@Sun.COM 		k++;
10387956Sxiuyan.wang@Sun.COM 	}
10397956Sxiuyan.wang@Sun.COM 
10407956Sxiuyan.wang@Sun.COM 	unm_desc_dma_sync(hw->cmd_desc_dma_handle, saved_producer, no_of_desc,
10417956Sxiuyan.wang@Sun.COM 	    MaxTxDescCount, sizeof (cmdDescType0_t), DDI_DMA_SYNC_FORDEV);
10427956Sxiuyan.wang@Sun.COM 
10437956Sxiuyan.wang@Sun.COM 	adapter->cmdProducer = get_next_index(producer, MaxTxDescCount);
10447956Sxiuyan.wang@Sun.COM 	hw->cmdProducer = adapter->cmdProducer;
10457956Sxiuyan.wang@Sun.COM 	unm_nic_update_cmd_producer(adapter, adapter->cmdProducer);
10467956Sxiuyan.wang@Sun.COM 
10477956Sxiuyan.wang@Sun.COM 	adapter->stats.txbytes += pktinfo->total_len;
10487956Sxiuyan.wang@Sun.COM 	adapter->stats.xmitfinished++;
10497956Sxiuyan.wang@Sun.COM 	adapter->stats.txmapped++;
10507956Sxiuyan.wang@Sun.COM 	UNM_SPIN_UNLOCK(&adapter->tx_lock);
10517956Sxiuyan.wang@Sun.COM 	return (B_TRUE);
10527956Sxiuyan.wang@Sun.COM 
10537956Sxiuyan.wang@Sun.COM err_alloc_desc:
10547956Sxiuyan.wang@Sun.COM err_map:
10557956Sxiuyan.wang@Sun.COM 
10567956Sxiuyan.wang@Sun.COM 	hdlp = head;
10577956Sxiuyan.wang@Sun.COM 	while (hdlp != NULL) {
10587956Sxiuyan.wang@Sun.COM 		(void) ddi_dma_unbind_handle(hdlp->dmahdl);
10597956Sxiuyan.wang@Sun.COM 		hdlp = hdlp->next;
10607956Sxiuyan.wang@Sun.COM 	}
10617956Sxiuyan.wang@Sun.COM 
10627956Sxiuyan.wang@Sun.COM 	/*
10637956Sxiuyan.wang@Sun.COM 	 * add the reserved but bind failed one to the list to be returned
10647956Sxiuyan.wang@Sun.COM 	 */
10657956Sxiuyan.wang@Sun.COM 	if (dmah != NULL) {
10667956Sxiuyan.wang@Sun.COM 		if (tail == NULL)
10677956Sxiuyan.wang@Sun.COM 			head = tail = dmah;
10687956Sxiuyan.wang@Sun.COM 		else {
10697956Sxiuyan.wang@Sun.COM 			tail->next = dmah;
10707956Sxiuyan.wang@Sun.COM 			tail = dmah;
10717956Sxiuyan.wang@Sun.COM 		}
10727956Sxiuyan.wang@Sun.COM 		hdl_reserved++;
10737956Sxiuyan.wang@Sun.COM 	}
10747956Sxiuyan.wang@Sun.COM 
10757956Sxiuyan.wang@Sun.COM 	if (head != NULL)
10767956Sxiuyan.wang@Sun.COM 		unm_return_dma_handle(adapter, head, tail, hdl_reserved);
10777956Sxiuyan.wang@Sun.COM 
10787956Sxiuyan.wang@Sun.COM 	UNM_SPIN_UNLOCK(&adapter->tx_lock);
10797956Sxiuyan.wang@Sun.COM 	return (B_FALSE);
10807956Sxiuyan.wang@Sun.COM }
10817956Sxiuyan.wang@Sun.COM 
10827956Sxiuyan.wang@Sun.COM static boolean_t
unm_nic_xmit_frame(unm_adapter * adapter,mblk_t * mp)10837956Sxiuyan.wang@Sun.COM unm_nic_xmit_frame(unm_adapter *adapter, mblk_t *mp)
10847956Sxiuyan.wang@Sun.COM {
10857956Sxiuyan.wang@Sun.COM 	pktinfo_t	pktinfo;
10867956Sxiuyan.wang@Sun.COM 	boolean_t	status = B_FALSE, send_mapped;
10877956Sxiuyan.wang@Sun.COM 
10887956Sxiuyan.wang@Sun.COM 	adapter->stats.xmitcalled++;
10897956Sxiuyan.wang@Sun.COM 
10907956Sxiuyan.wang@Sun.COM 	send_mapped = unm_get_pkt_info(mp, &pktinfo);
10917956Sxiuyan.wang@Sun.COM 
10927956Sxiuyan.wang@Sun.COM 	if (pktinfo.total_len <= adapter->tx_bcopy_threshold ||
10939436SJing.Xiong@Sun.COM 	    pktinfo.mblk_no >= MAX_COOKIES_PER_CMD)
10947956Sxiuyan.wang@Sun.COM 		send_mapped = B_FALSE;
10957956Sxiuyan.wang@Sun.COM 
10967956Sxiuyan.wang@Sun.COM 	if (send_mapped == B_TRUE)
10977956Sxiuyan.wang@Sun.COM 		status = unm_send_mapped(adapter, mp, &pktinfo);
10987956Sxiuyan.wang@Sun.COM 
10997956Sxiuyan.wang@Sun.COM 	if (status != B_TRUE) {
11007956Sxiuyan.wang@Sun.COM 		if (pktinfo.total_len <= adapter->maxmtu)
11017956Sxiuyan.wang@Sun.COM 			return (unm_send_copy(adapter, mp, &pktinfo));
11027956Sxiuyan.wang@Sun.COM 
11037956Sxiuyan.wang@Sun.COM 		/* message too large */
11047956Sxiuyan.wang@Sun.COM 		freemsg(mp);
11057956Sxiuyan.wang@Sun.COM 		adapter->stats.txdropped++;
11067956Sxiuyan.wang@Sun.COM 		status = B_TRUE;
11077956Sxiuyan.wang@Sun.COM 	}
11087956Sxiuyan.wang@Sun.COM 
11097956Sxiuyan.wang@Sun.COM 	return (status);
11107956Sxiuyan.wang@Sun.COM }
11117956Sxiuyan.wang@Sun.COM 
11127956Sxiuyan.wang@Sun.COM static int
unm_nic_check_temp(struct unm_adapter_s * adapter)11137956Sxiuyan.wang@Sun.COM unm_nic_check_temp(struct unm_adapter_s *adapter)
11147956Sxiuyan.wang@Sun.COM {
11157956Sxiuyan.wang@Sun.COM 	uint32_t temp, temp_state, temp_val;
11167956Sxiuyan.wang@Sun.COM 	int rv = 0;
11177956Sxiuyan.wang@Sun.COM 
11187956Sxiuyan.wang@Sun.COM 	if ((adapter->ahw.revision_id == NX_P3_A2) ||
11197956Sxiuyan.wang@Sun.COM 	    (adapter->ahw.revision_id == NX_P3_A0))
11207956Sxiuyan.wang@Sun.COM 		return (0);
11217956Sxiuyan.wang@Sun.COM 
11227956Sxiuyan.wang@Sun.COM 	temp = adapter->unm_nic_pci_read_normalize(adapter, CRB_TEMP_STATE);
11237956Sxiuyan.wang@Sun.COM 
11247956Sxiuyan.wang@Sun.COM 	temp_state = nx_get_temp_state(temp);
11257956Sxiuyan.wang@Sun.COM 	temp_val = nx_get_temp_val(temp);
11267956Sxiuyan.wang@Sun.COM 
11277956Sxiuyan.wang@Sun.COM 	if (temp_state == NX_TEMP_PANIC) {
11287956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "%s: Device temperature %d C exceeds "
11297956Sxiuyan.wang@Sun.COM 		    "maximum allowed, device has been shut down\n",
11307956Sxiuyan.wang@Sun.COM 		    unm_nic_driver_name, temp_val);
11317956Sxiuyan.wang@Sun.COM 		rv = 1;
11327956Sxiuyan.wang@Sun.COM 	} else if (temp_state == NX_TEMP_WARN) {
11337956Sxiuyan.wang@Sun.COM 		if (adapter->temp == NX_TEMP_NORMAL) {
11347956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "%s: Device temperature %d C exceeds"
11357956Sxiuyan.wang@Sun.COM 		    "operating range. Immediate action needed.\n",
11367956Sxiuyan.wang@Sun.COM 		    unm_nic_driver_name, temp_val);
11377956Sxiuyan.wang@Sun.COM 		}
11387956Sxiuyan.wang@Sun.COM 	} else {
11397956Sxiuyan.wang@Sun.COM 		if (adapter->temp == NX_TEMP_WARN) {
11407956Sxiuyan.wang@Sun.COM 			cmn_err(CE_WARN, "%s: Device temperature is now %d "
11417956Sxiuyan.wang@Sun.COM 			    "degrees C in normal range.\n",
11427956Sxiuyan.wang@Sun.COM 			    unm_nic_driver_name, temp_val);
11437956Sxiuyan.wang@Sun.COM 		}
11447956Sxiuyan.wang@Sun.COM 	}
11457956Sxiuyan.wang@Sun.COM 
11467956Sxiuyan.wang@Sun.COM 	adapter->temp = temp_state;
11477956Sxiuyan.wang@Sun.COM 	return (rv);
11487956Sxiuyan.wang@Sun.COM }
11497956Sxiuyan.wang@Sun.COM 
11507956Sxiuyan.wang@Sun.COM static void
unm_watchdog(unsigned long v)11517956Sxiuyan.wang@Sun.COM unm_watchdog(unsigned long v)
11527956Sxiuyan.wang@Sun.COM {
11537956Sxiuyan.wang@Sun.COM 	unm_adapter *adapter = (unm_adapter *)v;
11547956Sxiuyan.wang@Sun.COM 
11557956Sxiuyan.wang@Sun.COM 	if ((adapter->portnum == 0) && unm_nic_check_temp(adapter)) {
11567956Sxiuyan.wang@Sun.COM 		/*
11577956Sxiuyan.wang@Sun.COM 		 * We return without turning on the netdev queue as there
11587956Sxiuyan.wang@Sun.COM 		 * was an overheated device
11597956Sxiuyan.wang@Sun.COM 		 */
11607956Sxiuyan.wang@Sun.COM 		return;
11617956Sxiuyan.wang@Sun.COM 	}
11627956Sxiuyan.wang@Sun.COM 
11637956Sxiuyan.wang@Sun.COM 	unm_nic_handle_phy_intr(adapter);
11647956Sxiuyan.wang@Sun.COM 
11657956Sxiuyan.wang@Sun.COM 	/*
11667956Sxiuyan.wang@Sun.COM 	 * This function schedules a call for itself.
11677956Sxiuyan.wang@Sun.COM 	 */
11687956Sxiuyan.wang@Sun.COM 	adapter->watchdog_timer = timeout((void (*)(void *))&unm_watchdog,
11697956Sxiuyan.wang@Sun.COM 	    (void *)adapter, 2 * drv_usectohz(1000000));
11707956Sxiuyan.wang@Sun.COM 
11717956Sxiuyan.wang@Sun.COM }
11727956Sxiuyan.wang@Sun.COM 
unm_nic_clear_stats(unm_adapter * adapter)11737956Sxiuyan.wang@Sun.COM static void unm_nic_clear_stats(unm_adapter *adapter)
11747956Sxiuyan.wang@Sun.COM {
11757956Sxiuyan.wang@Sun.COM 	(void) memset(&adapter->stats, 0, sizeof (adapter->stats));
11767956Sxiuyan.wang@Sun.COM }
11777956Sxiuyan.wang@Sun.COM 
11787956Sxiuyan.wang@Sun.COM static void
unm_nic_poll(unm_adapter * adapter)11797956Sxiuyan.wang@Sun.COM unm_nic_poll(unm_adapter *adapter)
11807956Sxiuyan.wang@Sun.COM {
11817956Sxiuyan.wang@Sun.COM 	int	work_done, tx_complete;
11827956Sxiuyan.wang@Sun.COM 
11837956Sxiuyan.wang@Sun.COM 	adapter->stats.polled++;
11847956Sxiuyan.wang@Sun.COM 
11857956Sxiuyan.wang@Sun.COM loop:
11867956Sxiuyan.wang@Sun.COM 	tx_complete = unm_process_cmd_ring(adapter);
11877956Sxiuyan.wang@Sun.COM 	work_done = unm_process_rcv_ring(adapter, NX_RX_MAXBUFS);
11887956Sxiuyan.wang@Sun.COM 	if ((!tx_complete) || (!(work_done < NX_RX_MAXBUFS)))
11897956Sxiuyan.wang@Sun.COM 		goto loop;
11907956Sxiuyan.wang@Sun.COM 
11917956Sxiuyan.wang@Sun.COM 	UNM_READ_LOCK(&adapter->adapter_lock);
11927956Sxiuyan.wang@Sun.COM 	unm_nic_enable_int(adapter);
11937956Sxiuyan.wang@Sun.COM 	UNM_READ_UNLOCK(&adapter->adapter_lock);
11947956Sxiuyan.wang@Sun.COM }
11957956Sxiuyan.wang@Sun.COM 
11967956Sxiuyan.wang@Sun.COM /* ARGSUSED */
11977956Sxiuyan.wang@Sun.COM uint_t
unm_intr(caddr_t data,caddr_t arg)11987956Sxiuyan.wang@Sun.COM unm_intr(caddr_t data, caddr_t arg)
11997956Sxiuyan.wang@Sun.COM {
12007956Sxiuyan.wang@Sun.COM 	unm_adapter	*adapter = (unm_adapter *)(uintptr_t)data;
12017956Sxiuyan.wang@Sun.COM 
12027956Sxiuyan.wang@Sun.COM 	if (unm_nic_clear_int(adapter))
12037956Sxiuyan.wang@Sun.COM 		return (DDI_INTR_UNCLAIMED);
12047956Sxiuyan.wang@Sun.COM 
12057956Sxiuyan.wang@Sun.COM 	unm_nic_poll(adapter);
12067956Sxiuyan.wang@Sun.COM 	return (DDI_INTR_CLAIMED);
12077956Sxiuyan.wang@Sun.COM }
12087956Sxiuyan.wang@Sun.COM 
12097956Sxiuyan.wang@Sun.COM /*
12107956Sxiuyan.wang@Sun.COM  * This is invoked from receive isr. Due to the single threaded nature
12117956Sxiuyan.wang@Sun.COM  * of the invocation, pool_lock acquisition is not neccesary to protect
12127956Sxiuyan.wang@Sun.COM  * pool_list.
12137956Sxiuyan.wang@Sun.COM  */
12147956Sxiuyan.wang@Sun.COM static void
unm_free_rx_buffer(unm_rcv_desc_ctx_t * rcv_desc,unm_rx_buffer_t * rx_buffer)12157956Sxiuyan.wang@Sun.COM unm_free_rx_buffer(unm_rcv_desc_ctx_t *rcv_desc, unm_rx_buffer_t *rx_buffer)
12167956Sxiuyan.wang@Sun.COM {
12177956Sxiuyan.wang@Sun.COM 	/* mutex_enter(rcv_desc->pool_lock); */
12187956Sxiuyan.wang@Sun.COM 	rx_buffer->next = rcv_desc->pool_list;
12197956Sxiuyan.wang@Sun.COM 	rcv_desc->pool_list = rx_buffer;
12207956Sxiuyan.wang@Sun.COM 	rcv_desc->rx_buf_free++;
12217956Sxiuyan.wang@Sun.COM 	/* mutex_exit(rcv_desc->pool_lock); */
12227956Sxiuyan.wang@Sun.COM }
12237956Sxiuyan.wang@Sun.COM 
12247956Sxiuyan.wang@Sun.COM /*
12257956Sxiuyan.wang@Sun.COM  * unm_process_rcv() send the received packet to the protocol stack.
12267956Sxiuyan.wang@Sun.COM  */
12277956Sxiuyan.wang@Sun.COM static mblk_t *
unm_process_rcv(unm_adapter * adapter,statusDesc_t * desc)12287956Sxiuyan.wang@Sun.COM unm_process_rcv(unm_adapter *adapter, statusDesc_t *desc)
12297956Sxiuyan.wang@Sun.COM {
12307956Sxiuyan.wang@Sun.COM 	unm_recv_context_t	*recv_ctx = &(adapter->recv_ctx[0]);
12317956Sxiuyan.wang@Sun.COM 	unm_rx_buffer_t		*rx_buffer;
12327956Sxiuyan.wang@Sun.COM 	mblk_t *mp;
12337956Sxiuyan.wang@Sun.COM 	u32			desc_ctx = desc->u1.s1.type;
12347956Sxiuyan.wang@Sun.COM 	unm_rcv_desc_ctx_t	*rcv_desc = &recv_ctx->rcv_desc[desc_ctx];
12357956Sxiuyan.wang@Sun.COM 	u32			pkt_length = desc->u1.s1.totalLength;
12367956Sxiuyan.wang@Sun.COM 	int			poff = desc->u1.s1.pkt_offset;
12377956Sxiuyan.wang@Sun.COM 	int			index, cksum_flags, docopy;
12387956Sxiuyan.wang@Sun.COM 	int			index_lo = desc->u1.s1.referenceHandle_lo;
12397956Sxiuyan.wang@Sun.COM 	char			*vaddr;
12407956Sxiuyan.wang@Sun.COM 
12417956Sxiuyan.wang@Sun.COM 	index = ((desc->u1.s1.referenceHandle_hi << 4) | index_lo);
12427956Sxiuyan.wang@Sun.COM 
12437956Sxiuyan.wang@Sun.COM 	rx_buffer = index2rxbuf(rcv_desc, index);
12447956Sxiuyan.wang@Sun.COM 
12457956Sxiuyan.wang@Sun.COM 	if (rx_buffer == NULL) {
12467956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "\r\nNULL rx_buffer idx=%d", index);
12477956Sxiuyan.wang@Sun.COM 		return (NULL);
12487956Sxiuyan.wang@Sun.COM 	}
12497956Sxiuyan.wang@Sun.COM 	vaddr = (char *)rx_buffer->dma_info.vaddr;
12507956Sxiuyan.wang@Sun.COM 	if (vaddr == NULL) {
12517956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "\r\nNULL vaddr");
12527956Sxiuyan.wang@Sun.COM 		return (NULL);
12537956Sxiuyan.wang@Sun.COM 	}
12547956Sxiuyan.wang@Sun.COM 	rcv_desc->rx_desc_handled++;
12557956Sxiuyan.wang@Sun.COM 	rcv_desc->rx_buf_card--;
12567956Sxiuyan.wang@Sun.COM 
12577956Sxiuyan.wang@Sun.COM 	(void) ddi_dma_sync(rx_buffer->dma_info.dma_hdl, 0,
12587956Sxiuyan.wang@Sun.COM 	    pkt_length + poff + (adapter->ahw.cut_through ? 0 :
12597956Sxiuyan.wang@Sun.COM 	    IP_ALIGNMENT_BYTES), DDI_DMA_SYNC_FORCPU);
12607956Sxiuyan.wang@Sun.COM 
12617956Sxiuyan.wang@Sun.COM 	/*
12627956Sxiuyan.wang@Sun.COM 	 * Copy packet into new allocated message buffer, if pkt_length
12637956Sxiuyan.wang@Sun.COM 	 * is below copy threshold.
12647956Sxiuyan.wang@Sun.COM 	 */
12657956Sxiuyan.wang@Sun.COM 	docopy = (pkt_length <= adapter->rx_bcopy_threshold) ? 1 : 0;
12667956Sxiuyan.wang@Sun.COM 
12677956Sxiuyan.wang@Sun.COM 	/*
12687956Sxiuyan.wang@Sun.COM 	 * If card is running out of rx buffers, then attempt to allocate
12697956Sxiuyan.wang@Sun.COM 	 * new mblk so we can feed this rx buffer back to card (we
12707956Sxiuyan.wang@Sun.COM 	 * _could_ look at what's pending on free and recycle lists).
12717956Sxiuyan.wang@Sun.COM 	 */
12727956Sxiuyan.wang@Sun.COM 	if (rcv_desc->rx_buf_card < NX_RX_THRESHOLD) {
12737956Sxiuyan.wang@Sun.COM 		docopy = 1;
12747956Sxiuyan.wang@Sun.COM 		adapter->stats.rxbufshort++;
12757956Sxiuyan.wang@Sun.COM 	}
12767956Sxiuyan.wang@Sun.COM 
12777956Sxiuyan.wang@Sun.COM 	if (docopy == 1) {
12787956Sxiuyan.wang@Sun.COM 		if ((mp = allocb(pkt_length + IP_ALIGNMENT_BYTES, 0)) == NULL) {
12797956Sxiuyan.wang@Sun.COM 			adapter->stats.allocbfailed++;
12807956Sxiuyan.wang@Sun.COM 			goto freebuf;
12817956Sxiuyan.wang@Sun.COM 		}
12827956Sxiuyan.wang@Sun.COM 
12837956Sxiuyan.wang@Sun.COM 		mp->b_rptr += IP_ALIGNMENT_BYTES;
12847956Sxiuyan.wang@Sun.COM 		vaddr += poff;
12857956Sxiuyan.wang@Sun.COM 		bcopy(vaddr, mp->b_rptr, pkt_length);
12867956Sxiuyan.wang@Sun.COM 		adapter->stats.rxcopyed++;
12877956Sxiuyan.wang@Sun.COM 		unm_free_rx_buffer(rcv_desc, rx_buffer);
12887956Sxiuyan.wang@Sun.COM 	} else {
12897956Sxiuyan.wang@Sun.COM 		mp = (mblk_t *)rx_buffer->mp;
12907956Sxiuyan.wang@Sun.COM 		if (mp == NULL) {
12917956Sxiuyan.wang@Sun.COM 			mp = desballoc(rx_buffer->dma_info.vaddr,
12927956Sxiuyan.wang@Sun.COM 			    rcv_desc->dma_size, 0, &rx_buffer->rx_recycle);
12937956Sxiuyan.wang@Sun.COM 			if (mp == NULL) {
12947956Sxiuyan.wang@Sun.COM 				adapter->stats.desballocfailed++;
12957956Sxiuyan.wang@Sun.COM 				goto freebuf;
12967956Sxiuyan.wang@Sun.COM 			}
12977956Sxiuyan.wang@Sun.COM 			rx_buffer->mp = mp;
12987956Sxiuyan.wang@Sun.COM 		}
12997956Sxiuyan.wang@Sun.COM 		mp->b_rptr += poff;
13007956Sxiuyan.wang@Sun.COM 		adapter->stats.rxmapped++;
13017956Sxiuyan.wang@Sun.COM 	}
13027956Sxiuyan.wang@Sun.COM 
13037956Sxiuyan.wang@Sun.COM 	mp->b_wptr = (uchar_t *)((unsigned long)mp->b_rptr + pkt_length);
13047956Sxiuyan.wang@Sun.COM 
13057956Sxiuyan.wang@Sun.COM 	if (desc->u1.s1.status == STATUS_CKSUM_OK) {
13067956Sxiuyan.wang@Sun.COM 		adapter->stats.csummed++;
13077956Sxiuyan.wang@Sun.COM 		cksum_flags =
1308*11878SVenu.Iyer@Sun.COM 		    HCK_FULLCKSUM_OK | HCK_IPV4_HDRCKSUM_OK;
13097956Sxiuyan.wang@Sun.COM 	} else {
13107956Sxiuyan.wang@Sun.COM 		cksum_flags = 0;
13117956Sxiuyan.wang@Sun.COM 	}
1312*11878SVenu.Iyer@Sun.COM 	mac_hcksum_set(mp, 0, 0, 0, 0, cksum_flags);
13137956Sxiuyan.wang@Sun.COM 
13147956Sxiuyan.wang@Sun.COM 	adapter->stats.no_rcv++;
13157956Sxiuyan.wang@Sun.COM 	adapter->stats.rxbytes += pkt_length;
13167956Sxiuyan.wang@Sun.COM 	adapter->stats.uphappy++;
13177956Sxiuyan.wang@Sun.COM 
13187956Sxiuyan.wang@Sun.COM 	return (mp);
13197956Sxiuyan.wang@Sun.COM 
13207956Sxiuyan.wang@Sun.COM freebuf:
13217956Sxiuyan.wang@Sun.COM 	unm_free_rx_buffer(rcv_desc, rx_buffer);
13227956Sxiuyan.wang@Sun.COM 	return (NULL);
13237956Sxiuyan.wang@Sun.COM }
13247956Sxiuyan.wang@Sun.COM 
13257956Sxiuyan.wang@Sun.COM /* Process Receive status ring */
13267956Sxiuyan.wang@Sun.COM static int
unm_process_rcv_ring(unm_adapter * adapter,int max)13277956Sxiuyan.wang@Sun.COM unm_process_rcv_ring(unm_adapter *adapter, int max)
13287956Sxiuyan.wang@Sun.COM {
13297956Sxiuyan.wang@Sun.COM 	unm_recv_context_t	*recv_ctx = &(adapter->recv_ctx[0]);
13307956Sxiuyan.wang@Sun.COM 	statusDesc_t		*desc_head = recv_ctx->rcvStatusDescHead;
13317956Sxiuyan.wang@Sun.COM 	statusDesc_t		*desc = NULL;
13327956Sxiuyan.wang@Sun.COM 	uint32_t		consumer, start;
13337956Sxiuyan.wang@Sun.COM 	int			count = 0, ring;
13347956Sxiuyan.wang@Sun.COM 	mblk_t *mp;
13357956Sxiuyan.wang@Sun.COM 
13367956Sxiuyan.wang@Sun.COM 	start = consumer = recv_ctx->statusRxConsumer;
13377956Sxiuyan.wang@Sun.COM 
13387956Sxiuyan.wang@Sun.COM 	unm_desc_dma_sync(recv_ctx->status_desc_dma_handle, start, max,
13397956Sxiuyan.wang@Sun.COM 	    adapter->MaxRxDescCount, sizeof (statusDesc_t),
13407956Sxiuyan.wang@Sun.COM 	    DDI_DMA_SYNC_FORCPU);
13417956Sxiuyan.wang@Sun.COM 
13427956Sxiuyan.wang@Sun.COM 	while (count < max) {
13437956Sxiuyan.wang@Sun.COM 		desc = &desc_head[consumer];
13447956Sxiuyan.wang@Sun.COM 		if (!(desc->u1.s1.owner & STATUS_OWNER_HOST))
13457956Sxiuyan.wang@Sun.COM 			break;
13467956Sxiuyan.wang@Sun.COM 
13477956Sxiuyan.wang@Sun.COM 		mp = unm_process_rcv(adapter, desc);
13487956Sxiuyan.wang@Sun.COM 		desc->u1.s1.owner = STATUS_OWNER_PHANTOM;
13497956Sxiuyan.wang@Sun.COM 
13507956Sxiuyan.wang@Sun.COM 		consumer = (consumer + 1) % adapter->MaxRxDescCount;
13517956Sxiuyan.wang@Sun.COM 		count++;
13527956Sxiuyan.wang@Sun.COM 		if (mp != NULL)
13537956Sxiuyan.wang@Sun.COM 			mac_rx(adapter->mach, NULL, mp);
13547956Sxiuyan.wang@Sun.COM 	}
13557956Sxiuyan.wang@Sun.COM 
13567956Sxiuyan.wang@Sun.COM 	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
13577956Sxiuyan.wang@Sun.COM 		if (recv_ctx->rcv_desc[ring].rx_desc_handled > 0)
13587956Sxiuyan.wang@Sun.COM 			unm_post_rx_buffers_nodb(adapter, ring);
13597956Sxiuyan.wang@Sun.COM 	}
13607956Sxiuyan.wang@Sun.COM 
13617956Sxiuyan.wang@Sun.COM 	if (count) {
13627956Sxiuyan.wang@Sun.COM 		unm_desc_dma_sync(recv_ctx->status_desc_dma_handle, start,
13637956Sxiuyan.wang@Sun.COM 		    count, adapter->MaxRxDescCount, sizeof (statusDesc_t),
13647956Sxiuyan.wang@Sun.COM 		    DDI_DMA_SYNC_FORDEV);
13657956Sxiuyan.wang@Sun.COM 
13667956Sxiuyan.wang@Sun.COM 		/* update the consumer index in phantom */
13677956Sxiuyan.wang@Sun.COM 		recv_ctx->statusRxConsumer = consumer;
13687956Sxiuyan.wang@Sun.COM 
13697956Sxiuyan.wang@Sun.COM 		UNM_READ_LOCK(&adapter->adapter_lock);
13707956Sxiuyan.wang@Sun.COM 		adapter->unm_nic_hw_write_wx(adapter,
13717956Sxiuyan.wang@Sun.COM 		    recv_ctx->host_sds_consumer, &consumer, 4);
13727956Sxiuyan.wang@Sun.COM 		UNM_READ_UNLOCK(&adapter->adapter_lock);
13737956Sxiuyan.wang@Sun.COM 	}
13747956Sxiuyan.wang@Sun.COM 
13757956Sxiuyan.wang@Sun.COM 	return (count);
13767956Sxiuyan.wang@Sun.COM }
13777956Sxiuyan.wang@Sun.COM 
13787956Sxiuyan.wang@Sun.COM /* Process Command status ring */
13797956Sxiuyan.wang@Sun.COM static int
unm_process_cmd_ring(struct unm_adapter_s * adapter)13807956Sxiuyan.wang@Sun.COM unm_process_cmd_ring(struct unm_adapter_s *adapter)
13817956Sxiuyan.wang@Sun.COM {
13827956Sxiuyan.wang@Sun.COM 	u32			last_consumer;
13837956Sxiuyan.wang@Sun.COM 	u32			consumer;
13847956Sxiuyan.wang@Sun.COM 	int			count = 0;
13857956Sxiuyan.wang@Sun.COM 	struct unm_cmd_buffer	*buffer;
13867956Sxiuyan.wang@Sun.COM 	int			done;
13877956Sxiuyan.wang@Sun.COM 	unm_dmah_node_t *dmah, *head = NULL, *tail = NULL;
13887956Sxiuyan.wang@Sun.COM 	uint32_t	free_hdls = 0;
13897956Sxiuyan.wang@Sun.COM 
13907956Sxiuyan.wang@Sun.COM 	(void) ddi_dma_sync(adapter->ctxDesc_dma_handle, sizeof (RingContext),
13917956Sxiuyan.wang@Sun.COM 	    sizeof (uint32_t), DDI_DMA_SYNC_FORCPU);
13927956Sxiuyan.wang@Sun.COM 
13937956Sxiuyan.wang@Sun.COM 	last_consumer = adapter->lastCmdConsumer;
13947956Sxiuyan.wang@Sun.COM 	consumer = *(adapter->cmdConsumer);
13957956Sxiuyan.wang@Sun.COM 
13967956Sxiuyan.wang@Sun.COM 	while (last_consumer != consumer) {
13977956Sxiuyan.wang@Sun.COM 		buffer = &adapter->cmd_buf_arr[last_consumer];
13987956Sxiuyan.wang@Sun.COM 		if (buffer->head != NULL) {
13997956Sxiuyan.wang@Sun.COM 			dmah = buffer->head;
14007956Sxiuyan.wang@Sun.COM 			while (dmah != NULL) {
14017956Sxiuyan.wang@Sun.COM 				(void) ddi_dma_unbind_handle(dmah->dmahdl);
14027956Sxiuyan.wang@Sun.COM 				dmah = dmah->next;
14037956Sxiuyan.wang@Sun.COM 				free_hdls++;
14047956Sxiuyan.wang@Sun.COM 			}
14057956Sxiuyan.wang@Sun.COM 
14067956Sxiuyan.wang@Sun.COM 			if (head == NULL) {
14077956Sxiuyan.wang@Sun.COM 				head = buffer->head;
14087956Sxiuyan.wang@Sun.COM 				tail = buffer->tail;
14097956Sxiuyan.wang@Sun.COM 			} else {
14107956Sxiuyan.wang@Sun.COM 				tail->next = buffer->head;
14117956Sxiuyan.wang@Sun.COM 				tail = buffer->tail;
14127956Sxiuyan.wang@Sun.COM 			}
14137956Sxiuyan.wang@Sun.COM 
14147956Sxiuyan.wang@Sun.COM 			buffer->head = NULL;
14157956Sxiuyan.wang@Sun.COM 			buffer->tail = NULL;
14167956Sxiuyan.wang@Sun.COM 
14177956Sxiuyan.wang@Sun.COM 			if (buffer->msg != NULL) {
14187956Sxiuyan.wang@Sun.COM 				freemsg(buffer->msg);
14197956Sxiuyan.wang@Sun.COM 				buffer->msg = NULL;
14207956Sxiuyan.wang@Sun.COM 			}
14217956Sxiuyan.wang@Sun.COM 		}
14227956Sxiuyan.wang@Sun.COM 
14237956Sxiuyan.wang@Sun.COM 		last_consumer = get_next_index(last_consumer,
14247956Sxiuyan.wang@Sun.COM 		    adapter->MaxTxDescCount);
14257956Sxiuyan.wang@Sun.COM 		if (++count > NX_MAX_TXCOMPS)
14267956Sxiuyan.wang@Sun.COM 			break;
14277956Sxiuyan.wang@Sun.COM 	}
14287956Sxiuyan.wang@Sun.COM 
14297956Sxiuyan.wang@Sun.COM 	if (count) {
14307956Sxiuyan.wang@Sun.COM 		int	doresched;
14317956Sxiuyan.wang@Sun.COM 
14327956Sxiuyan.wang@Sun.COM 		UNM_SPIN_LOCK(&adapter->tx_lock);
14337956Sxiuyan.wang@Sun.COM 		adapter->lastCmdConsumer = last_consumer;
14347956Sxiuyan.wang@Sun.COM 		adapter->freecmds += count;
14357956Sxiuyan.wang@Sun.COM 		membar_exit();
14367956Sxiuyan.wang@Sun.COM 
14377956Sxiuyan.wang@Sun.COM 		doresched = adapter->resched_needed;
14387956Sxiuyan.wang@Sun.COM 		if (doresched)
14397956Sxiuyan.wang@Sun.COM 			adapter->resched_needed = 0;
14407956Sxiuyan.wang@Sun.COM 
14417956Sxiuyan.wang@Sun.COM 		if (head != NULL)
14427956Sxiuyan.wang@Sun.COM 			unm_return_dma_handle(adapter, head, tail, free_hdls);
14437956Sxiuyan.wang@Sun.COM 
14447956Sxiuyan.wang@Sun.COM 		UNM_SPIN_UNLOCK(&adapter->tx_lock);
14457956Sxiuyan.wang@Sun.COM 
14467956Sxiuyan.wang@Sun.COM 		if (doresched)
14477956Sxiuyan.wang@Sun.COM 			mac_tx_update(adapter->mach);
14487956Sxiuyan.wang@Sun.COM 	}
14497956Sxiuyan.wang@Sun.COM 
14507956Sxiuyan.wang@Sun.COM 	(void) ddi_dma_sync(adapter->ctxDesc_dma_handle, sizeof (RingContext),
14517956Sxiuyan.wang@Sun.COM 	    sizeof (uint32_t), DDI_DMA_SYNC_FORCPU);
14527956Sxiuyan.wang@Sun.COM 
14537956Sxiuyan.wang@Sun.COM 	consumer = *(adapter->cmdConsumer);
14547956Sxiuyan.wang@Sun.COM 	done = (adapter->lastCmdConsumer == consumer);
14557956Sxiuyan.wang@Sun.COM 
14567956Sxiuyan.wang@Sun.COM 	return (done);
14577956Sxiuyan.wang@Sun.COM }
14587956Sxiuyan.wang@Sun.COM 
14597956Sxiuyan.wang@Sun.COM /*
14607956Sxiuyan.wang@Sun.COM  * This is invoked from receive isr, and at initialization time when no
14617956Sxiuyan.wang@Sun.COM  * rx buffers have been posted to card. Due to the single threaded nature
14627956Sxiuyan.wang@Sun.COM  * of the invocation, pool_lock acquisition is not neccesary to protect
14637956Sxiuyan.wang@Sun.COM  * pool_list.
14647956Sxiuyan.wang@Sun.COM  */
14657956Sxiuyan.wang@Sun.COM static unm_rx_buffer_t *
unm_reserve_rx_buffer(unm_rcv_desc_ctx_t * rcv_desc)14667956Sxiuyan.wang@Sun.COM unm_reserve_rx_buffer(unm_rcv_desc_ctx_t *rcv_desc)
14677956Sxiuyan.wang@Sun.COM {
14687956Sxiuyan.wang@Sun.COM 	unm_rx_buffer_t *rx_buffer = NULL;
14697956Sxiuyan.wang@Sun.COM 
14707956Sxiuyan.wang@Sun.COM 	/* mutex_enter(rcv_desc->pool_lock); */
14717956Sxiuyan.wang@Sun.COM 	if (rcv_desc->rx_buf_free) {
14727956Sxiuyan.wang@Sun.COM 		rx_buffer = rcv_desc->pool_list;
14737956Sxiuyan.wang@Sun.COM 		rcv_desc->pool_list = rx_buffer->next;
14747956Sxiuyan.wang@Sun.COM 		rx_buffer->next = NULL;
14757956Sxiuyan.wang@Sun.COM 		rcv_desc->rx_buf_free--;
14767956Sxiuyan.wang@Sun.COM 	} else {
14777956Sxiuyan.wang@Sun.COM 		mutex_enter(rcv_desc->recycle_lock);
14787956Sxiuyan.wang@Sun.COM 
14797956Sxiuyan.wang@Sun.COM 		if (rcv_desc->rx_buf_recycle) {
14807956Sxiuyan.wang@Sun.COM 			rcv_desc->pool_list = rcv_desc->recycle_list;
14817956Sxiuyan.wang@Sun.COM 			rcv_desc->recycle_list = NULL;
14827956Sxiuyan.wang@Sun.COM 			rcv_desc->rx_buf_free += rcv_desc->rx_buf_recycle;
14837956Sxiuyan.wang@Sun.COM 			rcv_desc->rx_buf_recycle = 0;
14847956Sxiuyan.wang@Sun.COM 
14857956Sxiuyan.wang@Sun.COM 			rx_buffer = rcv_desc->pool_list;
14867956Sxiuyan.wang@Sun.COM 			rcv_desc->pool_list = rx_buffer->next;
14877956Sxiuyan.wang@Sun.COM 			rx_buffer->next = NULL;
14887956Sxiuyan.wang@Sun.COM 			rcv_desc->rx_buf_free--;
14897956Sxiuyan.wang@Sun.COM 		}
14907956Sxiuyan.wang@Sun.COM 
14917956Sxiuyan.wang@Sun.COM 		mutex_exit(rcv_desc->recycle_lock);
14927956Sxiuyan.wang@Sun.COM 	}
14937956Sxiuyan.wang@Sun.COM 
14947956Sxiuyan.wang@Sun.COM 	/* mutex_exit(rcv_desc->pool_lock); */
14957956Sxiuyan.wang@Sun.COM 	return (rx_buffer);
14967956Sxiuyan.wang@Sun.COM }
14977956Sxiuyan.wang@Sun.COM 
14987956Sxiuyan.wang@Sun.COM static void
post_rx_doorbell(struct unm_adapter_s * adapter,uint32_t ringid,int count)14997956Sxiuyan.wang@Sun.COM post_rx_doorbell(struct unm_adapter_s *adapter, uint32_t ringid, int count)
15007956Sxiuyan.wang@Sun.COM {
15017956Sxiuyan.wang@Sun.COM #define	UNM_RCV_PEG_DB_ID	2
15027956Sxiuyan.wang@Sun.COM #define	UNM_RCV_PRODUCER_OFFSET	0
15037956Sxiuyan.wang@Sun.COM 	ctx_msg msg = {0};
15047956Sxiuyan.wang@Sun.COM 
15057956Sxiuyan.wang@Sun.COM 	/*
15067956Sxiuyan.wang@Sun.COM 	 * Write a doorbell msg to tell phanmon of change in
15077956Sxiuyan.wang@Sun.COM 	 * receive ring producer
15087956Sxiuyan.wang@Sun.COM 	 */
15097956Sxiuyan.wang@Sun.COM 	msg.PegId = UNM_RCV_PEG_DB_ID;
15107956Sxiuyan.wang@Sun.COM 	msg.privId = 1;
15117956Sxiuyan.wang@Sun.COM 	msg.Count = count;
15127956Sxiuyan.wang@Sun.COM 	msg.CtxId = adapter->portnum;
15137956Sxiuyan.wang@Sun.COM 	msg.Opcode = UNM_RCV_PRODUCER(ringid);
15147956Sxiuyan.wang@Sun.COM 	dbwritel(*((__uint32_t *)&msg),
15157956Sxiuyan.wang@Sun.COM 	    (void *)(DB_NORMALIZE(adapter, UNM_RCV_PRODUCER_OFFSET)));
15167956Sxiuyan.wang@Sun.COM }
15177956Sxiuyan.wang@Sun.COM 
15187956Sxiuyan.wang@Sun.COM static int
unm_post_rx_buffers(struct unm_adapter_s * adapter,uint32_t ringid)15197956Sxiuyan.wang@Sun.COM unm_post_rx_buffers(struct unm_adapter_s *adapter, uint32_t ringid)
15207956Sxiuyan.wang@Sun.COM {
15217956Sxiuyan.wang@Sun.COM 	unm_recv_context_t	*recv_ctx = &(adapter->recv_ctx[0]);
15227956Sxiuyan.wang@Sun.COM 	unm_rcv_desc_ctx_t	*rcv_desc = &recv_ctx->rcv_desc[ringid];
15237956Sxiuyan.wang@Sun.COM 	unm_rx_buffer_t		*rx_buffer;
15247956Sxiuyan.wang@Sun.COM 	rcvDesc_t		*pdesc;
15257956Sxiuyan.wang@Sun.COM 	int			count;
15267956Sxiuyan.wang@Sun.COM 
15277956Sxiuyan.wang@Sun.COM 	for (count = 0; count < rcv_desc->MaxRxDescCount; count++) {
15287956Sxiuyan.wang@Sun.COM 		rx_buffer = unm_reserve_rx_buffer(rcv_desc);
15297956Sxiuyan.wang@Sun.COM 		if (rx_buffer != NULL) {
15307956Sxiuyan.wang@Sun.COM 			pdesc = &rcv_desc->desc_head[count];
15317956Sxiuyan.wang@Sun.COM 			pdesc->referenceHandle = rxbuf2index(rcv_desc,
15327956Sxiuyan.wang@Sun.COM 			    rx_buffer);
15337956Sxiuyan.wang@Sun.COM 			pdesc->flags = ringid;
15347956Sxiuyan.wang@Sun.COM 			pdesc->bufferLength = rcv_desc->dma_size;
15357956Sxiuyan.wang@Sun.COM 			pdesc->AddrBuffer = rx_buffer->dma_info.dma_addr;
15367956Sxiuyan.wang@Sun.COM 		}
15377956Sxiuyan.wang@Sun.COM 		else
15387956Sxiuyan.wang@Sun.COM 			return (DDI_FAILURE);
15397956Sxiuyan.wang@Sun.COM 	}
15407956Sxiuyan.wang@Sun.COM 
15417956Sxiuyan.wang@Sun.COM 	rcv_desc->producer = count % rcv_desc->MaxRxDescCount;
15427956Sxiuyan.wang@Sun.COM 	count--;
15437956Sxiuyan.wang@Sun.COM 	unm_desc_dma_sync(rcv_desc->rx_desc_dma_handle,
15447956Sxiuyan.wang@Sun.COM 	    0,		/* start */
15457956Sxiuyan.wang@Sun.COM 	    count,	/* count */
15467956Sxiuyan.wang@Sun.COM 	    count,	/* range */
15477956Sxiuyan.wang@Sun.COM 	    sizeof (rcvDesc_t),	/* unit_size */
15487956Sxiuyan.wang@Sun.COM 	    DDI_DMA_SYNC_FORDEV);	/* direction */
15497956Sxiuyan.wang@Sun.COM 
15507956Sxiuyan.wang@Sun.COM 	rcv_desc->rx_buf_card = rcv_desc->MaxRxDescCount;
15517956Sxiuyan.wang@Sun.COM 	UNM_READ_LOCK(&adapter->adapter_lock);
15527956Sxiuyan.wang@Sun.COM 	adapter->unm_nic_hw_write_wx(adapter, rcv_desc->host_rx_producer,
15537956Sxiuyan.wang@Sun.COM 	    &count, 4);
15547956Sxiuyan.wang@Sun.COM 	if (adapter->fw_major < 4)
15557956Sxiuyan.wang@Sun.COM 		post_rx_doorbell(adapter, ringid, count);
15567956Sxiuyan.wang@Sun.COM 	UNM_READ_UNLOCK(&adapter->adapter_lock);
15577956Sxiuyan.wang@Sun.COM 
15587956Sxiuyan.wang@Sun.COM 	return (DDI_SUCCESS);
15597956Sxiuyan.wang@Sun.COM }
15607956Sxiuyan.wang@Sun.COM 
15617956Sxiuyan.wang@Sun.COM static void
unm_post_rx_buffers_nodb(struct unm_adapter_s * adapter,uint32_t ringid)15627956Sxiuyan.wang@Sun.COM unm_post_rx_buffers_nodb(struct unm_adapter_s *adapter,
15637956Sxiuyan.wang@Sun.COM     uint32_t ringid)
15647956Sxiuyan.wang@Sun.COM {
15657956Sxiuyan.wang@Sun.COM 	unm_recv_context_t	*recv_ctx = &(adapter->recv_ctx[0]);
15667956Sxiuyan.wang@Sun.COM 	unm_rcv_desc_ctx_t	*rcv_desc = &recv_ctx->rcv_desc[ringid];
15677956Sxiuyan.wang@Sun.COM 	struct unm_rx_buffer	*rx_buffer;
15687956Sxiuyan.wang@Sun.COM 	rcvDesc_t		*pdesc;
15697956Sxiuyan.wang@Sun.COM 	int 			count, producer = rcv_desc->producer;
15707956Sxiuyan.wang@Sun.COM 	int 			last_producer = producer;
15717956Sxiuyan.wang@Sun.COM 
15727956Sxiuyan.wang@Sun.COM 	for (count = 0; count < rcv_desc->rx_desc_handled; count++) {
15737956Sxiuyan.wang@Sun.COM 		rx_buffer = unm_reserve_rx_buffer(rcv_desc);
15747956Sxiuyan.wang@Sun.COM 		if (rx_buffer != NULL) {
15757956Sxiuyan.wang@Sun.COM 			pdesc = &rcv_desc->desc_head[producer];
15767956Sxiuyan.wang@Sun.COM 			pdesc->referenceHandle = rxbuf2index(rcv_desc,
15777956Sxiuyan.wang@Sun.COM 			    rx_buffer);
15787956Sxiuyan.wang@Sun.COM 			pdesc->flags = ringid;
15797956Sxiuyan.wang@Sun.COM 			pdesc->bufferLength = rcv_desc->dma_size;
15807956Sxiuyan.wang@Sun.COM 			pdesc->AddrBuffer = rx_buffer->dma_info.dma_addr;
15817956Sxiuyan.wang@Sun.COM 		} else {
15827956Sxiuyan.wang@Sun.COM 			adapter->stats.outofrxbuf++;
15837956Sxiuyan.wang@Sun.COM 			break;
15847956Sxiuyan.wang@Sun.COM 		}
15857956Sxiuyan.wang@Sun.COM 		producer = get_next_index(producer, rcv_desc->MaxRxDescCount);
15867956Sxiuyan.wang@Sun.COM 	}
15877956Sxiuyan.wang@Sun.COM 
15887956Sxiuyan.wang@Sun.COM 	/* if we did allocate buffers, then write the count to Phantom */
15897956Sxiuyan.wang@Sun.COM 	if (count) {
15907956Sxiuyan.wang@Sun.COM 		/* Sync rx ring, considering case for wrap around */
15917956Sxiuyan.wang@Sun.COM 		unm_desc_dma_sync(rcv_desc->rx_desc_dma_handle, last_producer,
15927956Sxiuyan.wang@Sun.COM 		    count, rcv_desc->MaxRxDescCount, sizeof (rcvDesc_t),
15937956Sxiuyan.wang@Sun.COM 		    DDI_DMA_SYNC_FORDEV);
15947956Sxiuyan.wang@Sun.COM 
15957956Sxiuyan.wang@Sun.COM 		rcv_desc->producer = producer;
15967956Sxiuyan.wang@Sun.COM 		rcv_desc->rx_desc_handled -= count;
15977956Sxiuyan.wang@Sun.COM 		rcv_desc->rx_buf_card += count;
15987956Sxiuyan.wang@Sun.COM 
15997956Sxiuyan.wang@Sun.COM 		producer = (producer - 1) % rcv_desc->MaxRxDescCount;
16007956Sxiuyan.wang@Sun.COM 		UNM_READ_LOCK(&adapter->adapter_lock);
16017956Sxiuyan.wang@Sun.COM 		adapter->unm_nic_hw_write_wx(adapter,
16027956Sxiuyan.wang@Sun.COM 		    rcv_desc->host_rx_producer, &producer, 4);
16037956Sxiuyan.wang@Sun.COM 		UNM_READ_UNLOCK(&adapter->adapter_lock);
16047956Sxiuyan.wang@Sun.COM 	}
16057956Sxiuyan.wang@Sun.COM }
16067956Sxiuyan.wang@Sun.COM 
16077956Sxiuyan.wang@Sun.COM int
unm_nic_fill_statistics_128M(struct unm_adapter_s * adapter,struct unm_statistics * unm_stats)16087956Sxiuyan.wang@Sun.COM unm_nic_fill_statistics_128M(struct unm_adapter_s *adapter,
16097956Sxiuyan.wang@Sun.COM 			    struct unm_statistics *unm_stats)
16107956Sxiuyan.wang@Sun.COM {
16117956Sxiuyan.wang@Sun.COM 	void *addr;
16127956Sxiuyan.wang@Sun.COM 	if (adapter->ahw.board_type == UNM_NIC_XGBE) {
16137956Sxiuyan.wang@Sun.COM 		UNM_WRITE_LOCK(&adapter->adapter_lock);
16147956Sxiuyan.wang@Sun.COM 		unm_nic_pci_change_crbwindow_128M(adapter, 0);
16157956Sxiuyan.wang@Sun.COM 
16167956Sxiuyan.wang@Sun.COM 		/* LINTED: E_FALSE_LOGICAL_EXPR */
16177956Sxiuyan.wang@Sun.COM 		UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_TX_BYTE_CNT,
16187956Sxiuyan.wang@Sun.COM 		    &(unm_stats->tx_bytes));
16197956Sxiuyan.wang@Sun.COM 		/* LINTED: E_FALSE_LOGICAL_EXPR */
16207956Sxiuyan.wang@Sun.COM 		UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_TX_FRAME_CNT,
16217956Sxiuyan.wang@Sun.COM 		    &(unm_stats->tx_packets));
16227956Sxiuyan.wang@Sun.COM 		/* LINTED: E_FALSE_LOGICAL_EXPR */
16237956Sxiuyan.wang@Sun.COM 		UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_RX_BYTE_CNT,
16247956Sxiuyan.wang@Sun.COM 		    &(unm_stats->rx_bytes));
16257956Sxiuyan.wang@Sun.COM 		/* LINTED: E_FALSE_LOGICAL_EXPR */
16267956Sxiuyan.wang@Sun.COM 		UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_RX_FRAME_CNT,
16277956Sxiuyan.wang@Sun.COM 		    &(unm_stats->rx_packets));
16287956Sxiuyan.wang@Sun.COM 		/* LINTED: E_FALSE_LOGICAL_EXPR */
16297956Sxiuyan.wang@Sun.COM 		UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_AGGR_ERROR_CNT,
16307956Sxiuyan.wang@Sun.COM 		    &(unm_stats->rx_errors));
16317956Sxiuyan.wang@Sun.COM 		/* LINTED: E_FALSE_LOGICAL_EXPR */
16327956Sxiuyan.wang@Sun.COM 		UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_CRC_ERROR_CNT,
16337956Sxiuyan.wang@Sun.COM 		    &(unm_stats->rx_CRC_errors));
16347956Sxiuyan.wang@Sun.COM 		/* LINTED: E_FALSE_LOGICAL_EXPR */
16357956Sxiuyan.wang@Sun.COM 		UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_OVERSIZE_FRAME_ERR,
16367956Sxiuyan.wang@Sun.COM 		    &(unm_stats->rx_long_length_error));
16377956Sxiuyan.wang@Sun.COM 		/* LINTED: E_FALSE_LOGICAL_EXPR */
16387956Sxiuyan.wang@Sun.COM 		UNM_NIC_LOCKED_READ_REG(UNM_NIU_XGE_UNDERSIZE_FRAME_ERR,
16397956Sxiuyan.wang@Sun.COM 		    &(unm_stats->rx_short_length_error));
16407956Sxiuyan.wang@Sun.COM 
16417956Sxiuyan.wang@Sun.COM 		/*
16427956Sxiuyan.wang@Sun.COM 		 * For reading rx_MAC_error bit different procedure
16437956Sxiuyan.wang@Sun.COM 		 * UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_TEST_MUX_CTL, 0x15);
16447956Sxiuyan.wang@Sun.COM 		 * UNM_NIC_LOCKED_READ_REG((UNM_CRB_NIU + 0xC0), &temp);
16457956Sxiuyan.wang@Sun.COM 		 * unm_stats->rx_MAC_errors = temp & 0xff;
16467956Sxiuyan.wang@Sun.COM 		 */
16477956Sxiuyan.wang@Sun.COM 
16487956Sxiuyan.wang@Sun.COM 		unm_nic_pci_change_crbwindow_128M(adapter, 1);
16497956Sxiuyan.wang@Sun.COM 		UNM_WRITE_UNLOCK(&adapter->adapter_lock);
16507956Sxiuyan.wang@Sun.COM 	} else {
16517956Sxiuyan.wang@Sun.COM 		UNM_SPIN_LOCK_ISR(&adapter->tx_lock);
16527956Sxiuyan.wang@Sun.COM 		unm_stats->tx_bytes = adapter->stats.txbytes;
16537956Sxiuyan.wang@Sun.COM 		unm_stats->tx_packets = adapter->stats.xmitedframes +
16547956Sxiuyan.wang@Sun.COM 		    adapter->stats.xmitfinished;
16557956Sxiuyan.wang@Sun.COM 		unm_stats->rx_bytes = adapter->stats.rxbytes;
16567956Sxiuyan.wang@Sun.COM 		unm_stats->rx_packets = adapter->stats.no_rcv;
16577956Sxiuyan.wang@Sun.COM 		unm_stats->rx_errors = adapter->stats.rcvdbadmsg;
16587956Sxiuyan.wang@Sun.COM 		unm_stats->tx_errors = adapter->stats.nocmddescriptor;
16597956Sxiuyan.wang@Sun.COM 		unm_stats->rx_short_length_error = adapter->stats.uplcong;
16607956Sxiuyan.wang@Sun.COM 		unm_stats->rx_long_length_error = adapter->stats.uphcong;
16617956Sxiuyan.wang@Sun.COM 		unm_stats->rx_CRC_errors = 0;
16627956Sxiuyan.wang@Sun.COM 		unm_stats->rx_MAC_errors = 0;
16637956Sxiuyan.wang@Sun.COM 		UNM_SPIN_UNLOCK_ISR(&adapter->tx_lock);
16647956Sxiuyan.wang@Sun.COM 	}
16657956Sxiuyan.wang@Sun.COM 	return (0);
16667956Sxiuyan.wang@Sun.COM }
16677956Sxiuyan.wang@Sun.COM 
16687956Sxiuyan.wang@Sun.COM int
unm_nic_fill_statistics_2M(struct unm_adapter_s * adapter,struct unm_statistics * unm_stats)16697956Sxiuyan.wang@Sun.COM unm_nic_fill_statistics_2M(struct unm_adapter_s *adapter,
16707956Sxiuyan.wang@Sun.COM     struct unm_statistics *unm_stats)
16717956Sxiuyan.wang@Sun.COM {
16727956Sxiuyan.wang@Sun.COM 	if (adapter->ahw.board_type == UNM_NIC_XGBE) {
16737956Sxiuyan.wang@Sun.COM 		(void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_TX_BYTE_CNT,
16747956Sxiuyan.wang@Sun.COM 		    &(unm_stats->tx_bytes), 4);
16757956Sxiuyan.wang@Sun.COM 		(void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_TX_FRAME_CNT,
16767956Sxiuyan.wang@Sun.COM 		    &(unm_stats->tx_packets), 4);
16777956Sxiuyan.wang@Sun.COM 		(void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_RX_BYTE_CNT,
16787956Sxiuyan.wang@Sun.COM 		    &(unm_stats->rx_bytes), 4);
16797956Sxiuyan.wang@Sun.COM 		(void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_RX_FRAME_CNT,
16807956Sxiuyan.wang@Sun.COM 		    &(unm_stats->rx_packets), 4);
16817956Sxiuyan.wang@Sun.COM 		(void) unm_nic_hw_read_wx_2M(adapter,
16827956Sxiuyan.wang@Sun.COM 		    UNM_NIU_XGE_AGGR_ERROR_CNT, &(unm_stats->rx_errors), 4);
16837956Sxiuyan.wang@Sun.COM 		(void) unm_nic_hw_read_wx_2M(adapter, UNM_NIU_XGE_CRC_ERROR_CNT,
16847956Sxiuyan.wang@Sun.COM 		    &(unm_stats->rx_CRC_errors), 4);
16857956Sxiuyan.wang@Sun.COM 		(void) unm_nic_hw_read_wx_2M(adapter,
16867956Sxiuyan.wang@Sun.COM 		    UNM_NIU_XGE_OVERSIZE_FRAME_ERR,
16877956Sxiuyan.wang@Sun.COM 		    &(unm_stats->rx_long_length_error), 4);
16887956Sxiuyan.wang@Sun.COM 		(void) unm_nic_hw_read_wx_2M(adapter,
16897956Sxiuyan.wang@Sun.COM 		    UNM_NIU_XGE_UNDERSIZE_FRAME_ERR,
16907956Sxiuyan.wang@Sun.COM 		    &(unm_stats->rx_short_length_error), 4);
16917956Sxiuyan.wang@Sun.COM 	} else {
16927956Sxiuyan.wang@Sun.COM 		UNM_SPIN_LOCK_ISR(&adapter->tx_lock);
16937956Sxiuyan.wang@Sun.COM 		unm_stats->tx_bytes = adapter->stats.txbytes;
16947956Sxiuyan.wang@Sun.COM 		unm_stats->tx_packets = adapter->stats.xmitedframes +
16957956Sxiuyan.wang@Sun.COM 		    adapter->stats.xmitfinished;
16967956Sxiuyan.wang@Sun.COM 		unm_stats->rx_bytes = adapter->stats.rxbytes;
16977956Sxiuyan.wang@Sun.COM 		unm_stats->rx_packets = adapter->stats.no_rcv;
16987956Sxiuyan.wang@Sun.COM 		unm_stats->rx_errors = adapter->stats.rcvdbadmsg;
16997956Sxiuyan.wang@Sun.COM 		unm_stats->tx_errors = adapter->stats.nocmddescriptor;
17007956Sxiuyan.wang@Sun.COM 		unm_stats->rx_short_length_error = adapter->stats.uplcong;
17017956Sxiuyan.wang@Sun.COM 		unm_stats->rx_long_length_error = adapter->stats.uphcong;
17027956Sxiuyan.wang@Sun.COM 		unm_stats->rx_CRC_errors = 0;
17037956Sxiuyan.wang@Sun.COM 		unm_stats->rx_MAC_errors = 0;
17047956Sxiuyan.wang@Sun.COM 		UNM_SPIN_UNLOCK_ISR(&adapter->tx_lock);
17057956Sxiuyan.wang@Sun.COM 	}
17067956Sxiuyan.wang@Sun.COM 	return (0);
17077956Sxiuyan.wang@Sun.COM }
17087956Sxiuyan.wang@Sun.COM 
17097956Sxiuyan.wang@Sun.COM int
unm_nic_clear_statistics_128M(struct unm_adapter_s * adapter)17107956Sxiuyan.wang@Sun.COM unm_nic_clear_statistics_128M(struct unm_adapter_s *adapter)
17117956Sxiuyan.wang@Sun.COM {
17127956Sxiuyan.wang@Sun.COM 	void *addr;
17137956Sxiuyan.wang@Sun.COM 	int data = 0;
17147956Sxiuyan.wang@Sun.COM 
17157956Sxiuyan.wang@Sun.COM 	UNM_WRITE_LOCK(&adapter->adapter_lock);
17167956Sxiuyan.wang@Sun.COM 	unm_nic_pci_change_crbwindow_128M(adapter, 0);
17177956Sxiuyan.wang@Sun.COM 
17187956Sxiuyan.wang@Sun.COM 	/* LINTED: E_FALSE_LOGICAL_EXPR */
17197956Sxiuyan.wang@Sun.COM 	UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_TX_BYTE_CNT, &data);
17207956Sxiuyan.wang@Sun.COM 	/* LINTED: E_FALSE_LOGICAL_EXPR */
17217956Sxiuyan.wang@Sun.COM 	UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_TX_FRAME_CNT, &data);
17227956Sxiuyan.wang@Sun.COM 	/* LINTED: E_FALSE_LOGICAL_EXPR */
17237956Sxiuyan.wang@Sun.COM 	UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_RX_BYTE_CNT, &data);
17247956Sxiuyan.wang@Sun.COM 	/* LINTED: E_FALSE_LOGICAL_EXPR */
17257956Sxiuyan.wang@Sun.COM 	UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_RX_FRAME_CNT, &data);
17267956Sxiuyan.wang@Sun.COM 	/* LINTED: E_FALSE_LOGICAL_EXPR */
17277956Sxiuyan.wang@Sun.COM 	UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_AGGR_ERROR_CNT, &data);
17287956Sxiuyan.wang@Sun.COM 	/* LINTED: E_FALSE_LOGICAL_EXPR */
17297956Sxiuyan.wang@Sun.COM 	UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_CRC_ERROR_CNT, &data);
17307956Sxiuyan.wang@Sun.COM 	/* LINTED: E_FALSE_LOGICAL_EXPR */
17317956Sxiuyan.wang@Sun.COM 	UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_OVERSIZE_FRAME_ERR, &data);
17327956Sxiuyan.wang@Sun.COM 	/* LINTED: E_FALSE_LOGICAL_EXPR */
17337956Sxiuyan.wang@Sun.COM 	UNM_NIC_LOCKED_WRITE_REG(UNM_NIU_XGE_UNDERSIZE_FRAME_ERR, &data);
17347956Sxiuyan.wang@Sun.COM 
17357956Sxiuyan.wang@Sun.COM 	unm_nic_pci_change_crbwindow_128M(adapter, 1);
17367956Sxiuyan.wang@Sun.COM 	UNM_WRITE_UNLOCK(&adapter->adapter_lock);
17377956Sxiuyan.wang@Sun.COM 	unm_nic_clear_stats(adapter);
17387956Sxiuyan.wang@Sun.COM 	return (0);
17397956Sxiuyan.wang@Sun.COM }
17407956Sxiuyan.wang@Sun.COM 
17417956Sxiuyan.wang@Sun.COM int
unm_nic_clear_statistics_2M(struct unm_adapter_s * adapter)17427956Sxiuyan.wang@Sun.COM unm_nic_clear_statistics_2M(struct unm_adapter_s *adapter)
17437956Sxiuyan.wang@Sun.COM {
17447956Sxiuyan.wang@Sun.COM 	int data = 0;
17457956Sxiuyan.wang@Sun.COM 
17467956Sxiuyan.wang@Sun.COM 	(void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_TX_BYTE_CNT,
17477956Sxiuyan.wang@Sun.COM 	    &data, 4);
17487956Sxiuyan.wang@Sun.COM 	(void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_TX_FRAME_CNT,
17497956Sxiuyan.wang@Sun.COM 	    &data, 4);
17507956Sxiuyan.wang@Sun.COM 	(void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_RX_BYTE_CNT,
17517956Sxiuyan.wang@Sun.COM 	    &data, 4);
17527956Sxiuyan.wang@Sun.COM 	(void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_RX_FRAME_CNT,
17537956Sxiuyan.wang@Sun.COM 	    &data, 4);
17547956Sxiuyan.wang@Sun.COM 	(void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_AGGR_ERROR_CNT,
17557956Sxiuyan.wang@Sun.COM 	    &data, 4);
17567956Sxiuyan.wang@Sun.COM 	(void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_CRC_ERROR_CNT,
17577956Sxiuyan.wang@Sun.COM 	    &data, 4);
17587956Sxiuyan.wang@Sun.COM 	(void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_OVERSIZE_FRAME_ERR,
17597956Sxiuyan.wang@Sun.COM 	    &data, 4);
17607956Sxiuyan.wang@Sun.COM 	(void) unm_nic_hw_write_wx_2M(adapter, UNM_NIU_XGE_UNDERSIZE_FRAME_ERR,
17617956Sxiuyan.wang@Sun.COM 	    &data, 4);
17627956Sxiuyan.wang@Sun.COM 	unm_nic_clear_stats(adapter);
17637956Sxiuyan.wang@Sun.COM 	return (0);
17647956Sxiuyan.wang@Sun.COM }
17657956Sxiuyan.wang@Sun.COM 
17667956Sxiuyan.wang@Sun.COM /*
17677956Sxiuyan.wang@Sun.COM  * unm_nic_ioctl ()    We provide the tcl/phanmon support
17687956Sxiuyan.wang@Sun.COM  * through these ioctls.
17697956Sxiuyan.wang@Sun.COM  */
17707956Sxiuyan.wang@Sun.COM static void
unm_nic_ioctl(struct unm_adapter_s * adapter,int cmd,queue_t * q,mblk_t * mp)17717956Sxiuyan.wang@Sun.COM unm_nic_ioctl(struct unm_adapter_s *adapter, int cmd, queue_t *q, mblk_t *mp)
17727956Sxiuyan.wang@Sun.COM {
17737956Sxiuyan.wang@Sun.COM 	void *ptr;
17747956Sxiuyan.wang@Sun.COM 
17757956Sxiuyan.wang@Sun.COM 	switch (cmd) {
17767956Sxiuyan.wang@Sun.COM 	case UNM_NIC_CMD:
17777956Sxiuyan.wang@Sun.COM 		(void) unm_nic_do_ioctl(adapter, q, mp);
17787956Sxiuyan.wang@Sun.COM 		break;
17797956Sxiuyan.wang@Sun.COM 
17807956Sxiuyan.wang@Sun.COM 	case UNM_NIC_NAME:
17817956Sxiuyan.wang@Sun.COM 		ptr = (void *) mp->b_cont->b_rptr;
17827956Sxiuyan.wang@Sun.COM 
17837956Sxiuyan.wang@Sun.COM 		/*
17847956Sxiuyan.wang@Sun.COM 		 * Phanmon checks for "UNM-UNM" string
17857956Sxiuyan.wang@Sun.COM 		 * Replace the hardcoded value with appropriate macro
17867956Sxiuyan.wang@Sun.COM 		 */
17877956Sxiuyan.wang@Sun.COM 		DPRINTF(-1, (CE_CONT, "UNM_NIC_NAME ioctl executed %d %d\n",
17887956Sxiuyan.wang@Sun.COM 		    cmd, __LINE__));
17897956Sxiuyan.wang@Sun.COM 		(void) memcpy(ptr, "UNM-UNM", 10);
17907956Sxiuyan.wang@Sun.COM 		miocack(q, mp, 10, 0);
17917956Sxiuyan.wang@Sun.COM 		break;
17927956Sxiuyan.wang@Sun.COM 
17937956Sxiuyan.wang@Sun.COM 	default:
17947956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "Netxen ioctl cmd %x not supported\n", cmd);
17957956Sxiuyan.wang@Sun.COM 
17967956Sxiuyan.wang@Sun.COM 		miocnak(q, mp, 0, EINVAL);
17977956Sxiuyan.wang@Sun.COM 		break;
17987956Sxiuyan.wang@Sun.COM 	}
17997956Sxiuyan.wang@Sun.COM }
18007956Sxiuyan.wang@Sun.COM 
18017956Sxiuyan.wang@Sun.COM int
unm_nic_resume(unm_adapter * adapter)18027956Sxiuyan.wang@Sun.COM unm_nic_resume(unm_adapter *adapter)
18037956Sxiuyan.wang@Sun.COM {
18047956Sxiuyan.wang@Sun.COM 
18057956Sxiuyan.wang@Sun.COM 	adapter->watchdog_timer = timeout((void (*)(void *))&unm_watchdog,
18067956Sxiuyan.wang@Sun.COM 	    (void *) adapter, 50000);
18077956Sxiuyan.wang@Sun.COM 
18087956Sxiuyan.wang@Sun.COM 	if (adapter->intr_type == DDI_INTR_TYPE_MSI)
18097956Sxiuyan.wang@Sun.COM 		(void) ddi_intr_block_enable(&adapter->intr_handle, 1);
18107956Sxiuyan.wang@Sun.COM 	else
18117956Sxiuyan.wang@Sun.COM 		(void) ddi_intr_enable(adapter->intr_handle);
18127956Sxiuyan.wang@Sun.COM 	UNM_READ_LOCK(&adapter->adapter_lock);
18137956Sxiuyan.wang@Sun.COM 	unm_nic_enable_int(adapter);
18147956Sxiuyan.wang@Sun.COM 	UNM_READ_UNLOCK(&adapter->adapter_lock);
18157956Sxiuyan.wang@Sun.COM 
18167956Sxiuyan.wang@Sun.COM 	mac_link_update(adapter->mach, LINK_STATE_UP);
18177956Sxiuyan.wang@Sun.COM 
18187956Sxiuyan.wang@Sun.COM 	return (DDI_SUCCESS);
18197956Sxiuyan.wang@Sun.COM }
18207956Sxiuyan.wang@Sun.COM 
18217956Sxiuyan.wang@Sun.COM int
unm_nic_suspend(unm_adapter * adapter)18227956Sxiuyan.wang@Sun.COM unm_nic_suspend(unm_adapter *adapter)
18237956Sxiuyan.wang@Sun.COM {
18247956Sxiuyan.wang@Sun.COM 	mac_link_update(adapter->mach, LINK_STATE_DOWN);
18257956Sxiuyan.wang@Sun.COM 
18267956Sxiuyan.wang@Sun.COM 	(void) untimeout(adapter->watchdog_timer);
18277956Sxiuyan.wang@Sun.COM 
18287956Sxiuyan.wang@Sun.COM 	UNM_READ_LOCK(&adapter->adapter_lock);
18297956Sxiuyan.wang@Sun.COM 	unm_nic_disable_int(adapter);
18307956Sxiuyan.wang@Sun.COM 	UNM_READ_UNLOCK(&adapter->adapter_lock);
18317956Sxiuyan.wang@Sun.COM 	if (adapter->intr_type == DDI_INTR_TYPE_MSI)
18327956Sxiuyan.wang@Sun.COM 		(void) ddi_intr_block_disable(&adapter->intr_handle, 1);
18337956Sxiuyan.wang@Sun.COM 	else
18347956Sxiuyan.wang@Sun.COM 		(void) ddi_intr_disable(adapter->intr_handle);
18357956Sxiuyan.wang@Sun.COM 
18367956Sxiuyan.wang@Sun.COM 	return (DDI_SUCCESS);
18377956Sxiuyan.wang@Sun.COM }
18387956Sxiuyan.wang@Sun.COM 
18397956Sxiuyan.wang@Sun.COM static int
unm_nic_do_ioctl(unm_adapter * adapter,queue_t * wq,mblk_t * mp)18407956Sxiuyan.wang@Sun.COM unm_nic_do_ioctl(unm_adapter *adapter, queue_t *wq, mblk_t *mp)
18417956Sxiuyan.wang@Sun.COM {
18427956Sxiuyan.wang@Sun.COM 	unm_nic_ioctl_data_t		data;
18437956Sxiuyan.wang@Sun.COM 	struct unm_nic_ioctl_data	*up_data;
18447956Sxiuyan.wang@Sun.COM 	ddi_acc_handle_t		conf_handle;
18457956Sxiuyan.wang@Sun.COM 	int				retval = 0;
18469436SJing.Xiong@Sun.COM 	uint64_t			efuse_chip_id = 0;
18477956Sxiuyan.wang@Sun.COM 	char				*ptr1;
18487956Sxiuyan.wang@Sun.COM 	short				*ptr2;
18497956Sxiuyan.wang@Sun.COM 	int				*ptr4;
18507956Sxiuyan.wang@Sun.COM 
18517956Sxiuyan.wang@Sun.COM 	up_data = (struct unm_nic_ioctl_data *)(mp->b_cont->b_rptr);
18527956Sxiuyan.wang@Sun.COM 	(void) memcpy(&data, (void **)(uintptr_t)(mp->b_cont->b_rptr),
18537956Sxiuyan.wang@Sun.COM 	    sizeof (data));
18547956Sxiuyan.wang@Sun.COM 
18557956Sxiuyan.wang@Sun.COM 	/* Shouldn't access beyond legal limits of  "char u[64];" member */
18567956Sxiuyan.wang@Sun.COM 	if (data.size > sizeof (data.uabc)) {
18577956Sxiuyan.wang@Sun.COM 		/* evil user tried to crash the kernel */
18587956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "bad size: %d\n", data.size);
18597956Sxiuyan.wang@Sun.COM 		retval = GLD_BADARG;
18607956Sxiuyan.wang@Sun.COM 		goto error_out;
18617956Sxiuyan.wang@Sun.COM 	}
18627956Sxiuyan.wang@Sun.COM 
18637956Sxiuyan.wang@Sun.COM 	switch (data.cmd) {
18647956Sxiuyan.wang@Sun.COM 	case unm_nic_cmd_pci_read:
18657956Sxiuyan.wang@Sun.COM 
18667956Sxiuyan.wang@Sun.COM 		if ((retval = adapter->unm_nic_hw_read_ioctl(adapter,
18677956Sxiuyan.wang@Sun.COM 		    data.off, up_data, data.size))) {
18687956Sxiuyan.wang@Sun.COM 			DPRINTF(-1, (CE_WARN, "%s(%d) unm_nic_hw_read_wx "
18697956Sxiuyan.wang@Sun.COM 		    "returned %d\n", __FUNCTION__, __LINE__, retval));
18707956Sxiuyan.wang@Sun.COM 
18717956Sxiuyan.wang@Sun.COM 			retval = data.rv;
18727956Sxiuyan.wang@Sun.COM 			goto error_out;
18737956Sxiuyan.wang@Sun.COM 		}
18747956Sxiuyan.wang@Sun.COM 
18757956Sxiuyan.wang@Sun.COM 		data.rv = 0;
18767956Sxiuyan.wang@Sun.COM 		break;
18777956Sxiuyan.wang@Sun.COM 
18787956Sxiuyan.wang@Sun.COM 	case unm_nic_cmd_pci_write:
18797956Sxiuyan.wang@Sun.COM 		if ((data.rv = adapter->unm_nic_hw_write_ioctl(adapter,
18807956Sxiuyan.wang@Sun.COM 		    data.off, &(data.uabc), data.size))) {
18817956Sxiuyan.wang@Sun.COM 			DPRINTF(-1, (CE_WARN, "%s(%d) unm_nic_hw_write_wx "
18827956Sxiuyan.wang@Sun.COM 			    "returned %d\n", __FUNCTION__,
18837956Sxiuyan.wang@Sun.COM 			    __LINE__, data.rv));
18847956Sxiuyan.wang@Sun.COM 			retval = data.rv;
18857956Sxiuyan.wang@Sun.COM 			goto error_out;
18867956Sxiuyan.wang@Sun.COM 		}
18877956Sxiuyan.wang@Sun.COM 		data.size = 0;
18887956Sxiuyan.wang@Sun.COM 		break;
18897956Sxiuyan.wang@Sun.COM 
18907956Sxiuyan.wang@Sun.COM 	case unm_nic_cmd_pci_mem_read:
18917956Sxiuyan.wang@Sun.COM 		if ((data.rv = adapter->unm_nic_pci_mem_read(adapter,
18927956Sxiuyan.wang@Sun.COM 		    data.off, up_data, data.size))) {
18937956Sxiuyan.wang@Sun.COM 			DPRINTF(-1, (CE_WARN, "%s(%d) unm_nic_pci_mem_read "
18947956Sxiuyan.wang@Sun.COM 			    "returned %d\n", __FUNCTION__,
18957956Sxiuyan.wang@Sun.COM 			    __LINE__, data.rv));
18967956Sxiuyan.wang@Sun.COM 			retval = data.rv;
18977956Sxiuyan.wang@Sun.COM 			goto error_out;
18987956Sxiuyan.wang@Sun.COM 		}
18997956Sxiuyan.wang@Sun.COM 		data.rv = 0;
19007956Sxiuyan.wang@Sun.COM 		break;
19017956Sxiuyan.wang@Sun.COM 
19027956Sxiuyan.wang@Sun.COM 	case unm_nic_cmd_pci_mem_write:
19037956Sxiuyan.wang@Sun.COM 		if ((data.rv = adapter->unm_nic_pci_mem_write(adapter,
19047956Sxiuyan.wang@Sun.COM 		    data.off, &(data.uabc), data.size))) {
19057956Sxiuyan.wang@Sun.COM 			DPRINTF(-1, (CE_WARN,
19067956Sxiuyan.wang@Sun.COM 			    "%s(%d) unm_nic_cmd_pci_mem_write "
19077956Sxiuyan.wang@Sun.COM 			    "returned %d\n",
19087956Sxiuyan.wang@Sun.COM 			    __FUNCTION__, __LINE__, data.rv));
19097956Sxiuyan.wang@Sun.COM 			retval = data.rv;
19107956Sxiuyan.wang@Sun.COM 			goto error_out;
19117956Sxiuyan.wang@Sun.COM 		}
19127956Sxiuyan.wang@Sun.COM 
19137956Sxiuyan.wang@Sun.COM 		data.size = 0;
19147956Sxiuyan.wang@Sun.COM 		data.rv = 0;
19157956Sxiuyan.wang@Sun.COM 		break;
19167956Sxiuyan.wang@Sun.COM 
19177956Sxiuyan.wang@Sun.COM 	case unm_nic_cmd_pci_config_read:
19187956Sxiuyan.wang@Sun.COM 
19197956Sxiuyan.wang@Sun.COM 		if (adapter->pci_cfg_handle != NULL) {
19207956Sxiuyan.wang@Sun.COM 			conf_handle = adapter->pci_cfg_handle;
19217956Sxiuyan.wang@Sun.COM 
19227956Sxiuyan.wang@Sun.COM 		} else if ((retval = pci_config_setup(adapter->dip,
19237956Sxiuyan.wang@Sun.COM 		    &conf_handle)) != DDI_SUCCESS) {
19247956Sxiuyan.wang@Sun.COM 			DPRINTF(-1, (CE_WARN, "!%s: pci_config_setup failed"
19257956Sxiuyan.wang@Sun.COM 			    " error:%d\n", unm_nic_driver_name, retval));
19267956Sxiuyan.wang@Sun.COM 			goto error_out;
19277956Sxiuyan.wang@Sun.COM 
19287956Sxiuyan.wang@Sun.COM 		} else
19297956Sxiuyan.wang@Sun.COM 			adapter->pci_cfg_handle = conf_handle;
19307956Sxiuyan.wang@Sun.COM 
19317956Sxiuyan.wang@Sun.COM 		switch (data.size) {
19327956Sxiuyan.wang@Sun.COM 		case 1:
19337956Sxiuyan.wang@Sun.COM 			ptr1 = (char *)up_data;
19347956Sxiuyan.wang@Sun.COM 			*ptr1 = (char)pci_config_get8(conf_handle, data.off);
19357956Sxiuyan.wang@Sun.COM 			break;
19367956Sxiuyan.wang@Sun.COM 		case 2:
19377956Sxiuyan.wang@Sun.COM 			ptr2 = (short *)up_data;
19387956Sxiuyan.wang@Sun.COM 			*ptr2 = (short)pci_config_get16(conf_handle, data.off);
19397956Sxiuyan.wang@Sun.COM 			break;
19407956Sxiuyan.wang@Sun.COM 		case 4:
19417956Sxiuyan.wang@Sun.COM 			ptr4 = (int *)up_data;
19427956Sxiuyan.wang@Sun.COM 			*ptr4 = (int)pci_config_get32(conf_handle, data.off);
19437956Sxiuyan.wang@Sun.COM 			break;
19447956Sxiuyan.wang@Sun.COM 		}
19457956Sxiuyan.wang@Sun.COM 
19467956Sxiuyan.wang@Sun.COM 		break;
19477956Sxiuyan.wang@Sun.COM 
19487956Sxiuyan.wang@Sun.COM 	case unm_nic_cmd_pci_config_write:
19497956Sxiuyan.wang@Sun.COM 
19507956Sxiuyan.wang@Sun.COM 		if (adapter->pci_cfg_handle != NULL) {
19517956Sxiuyan.wang@Sun.COM 			conf_handle = adapter->pci_cfg_handle;
19527956Sxiuyan.wang@Sun.COM 		} else if ((retval = pci_config_setup(adapter->dip,
19537956Sxiuyan.wang@Sun.COM 		    &conf_handle)) != DDI_SUCCESS) {
19547956Sxiuyan.wang@Sun.COM 			DPRINTF(-1, (CE_WARN, "!%s: pci_config_setup failed"
19557956Sxiuyan.wang@Sun.COM 			    " error:%d\n", unm_nic_driver_name, retval));
19567956Sxiuyan.wang@Sun.COM 			goto error_out;
19577956Sxiuyan.wang@Sun.COM 		} else {
19587956Sxiuyan.wang@Sun.COM 			adapter->pci_cfg_handle = conf_handle;
19597956Sxiuyan.wang@Sun.COM 		}
19607956Sxiuyan.wang@Sun.COM 
19617956Sxiuyan.wang@Sun.COM 		switch (data.size) {
19627956Sxiuyan.wang@Sun.COM 		case 1:
19637956Sxiuyan.wang@Sun.COM 			pci_config_put8(conf_handle,
19647956Sxiuyan.wang@Sun.COM 			    data.off, *(char *)&(data.uabc));
19657956Sxiuyan.wang@Sun.COM 			break;
19667956Sxiuyan.wang@Sun.COM 		case 2:
19677956Sxiuyan.wang@Sun.COM 			pci_config_put16(conf_handle,
19687956Sxiuyan.wang@Sun.COM 			    data.off, *(short *)(uintptr_t)&(data.uabc));
19697956Sxiuyan.wang@Sun.COM 			break;
19707956Sxiuyan.wang@Sun.COM 		case 4:
19717956Sxiuyan.wang@Sun.COM 			pci_config_put32(conf_handle,
19727956Sxiuyan.wang@Sun.COM 			    data.off, *(u32 *)(uintptr_t)&(data.uabc));
19737956Sxiuyan.wang@Sun.COM 			break;
19747956Sxiuyan.wang@Sun.COM 		}
19757956Sxiuyan.wang@Sun.COM 		data.size = 0;
19767956Sxiuyan.wang@Sun.COM 		break;
19777956Sxiuyan.wang@Sun.COM 
19787956Sxiuyan.wang@Sun.COM 	case unm_nic_cmd_get_stats:
19797956Sxiuyan.wang@Sun.COM 		data.rv = adapter->unm_nic_fill_statistics(adapter,
19807956Sxiuyan.wang@Sun.COM 		    (struct unm_statistics *)up_data);
19817956Sxiuyan.wang@Sun.COM 		data.size = sizeof (struct unm_statistics);
19827956Sxiuyan.wang@Sun.COM 
19837956Sxiuyan.wang@Sun.COM 		break;
19847956Sxiuyan.wang@Sun.COM 
19857956Sxiuyan.wang@Sun.COM 	case unm_nic_cmd_clear_stats:
19867956Sxiuyan.wang@Sun.COM 		data.rv = adapter->unm_nic_clear_statistics(adapter);
19877956Sxiuyan.wang@Sun.COM 		break;
19887956Sxiuyan.wang@Sun.COM 
19897956Sxiuyan.wang@Sun.COM 	case unm_nic_cmd_get_version:
19907956Sxiuyan.wang@Sun.COM 		(void) memcpy(up_data, UNM_NIC_VERSIONID,
19917956Sxiuyan.wang@Sun.COM 		    sizeof (UNM_NIC_VERSIONID));
19927956Sxiuyan.wang@Sun.COM 		data.size = sizeof (UNM_NIC_VERSIONID);
19937956Sxiuyan.wang@Sun.COM 
19947956Sxiuyan.wang@Sun.COM 		break;
19957956Sxiuyan.wang@Sun.COM 
19967956Sxiuyan.wang@Sun.COM 	case unm_nic_cmd_get_phy_type:
19977956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "unm_nic_cmd_get_phy_type unimplemented\n");
19987956Sxiuyan.wang@Sun.COM 		break;
19997956Sxiuyan.wang@Sun.COM 
20007956Sxiuyan.wang@Sun.COM 	case unm_nic_cmd_efuse_chip_id:
20017956Sxiuyan.wang@Sun.COM 		efuse_chip_id = adapter->unm_nic_pci_read_normalize(adapter,
20029436SJing.Xiong@Sun.COM 		    UNM_EFUSE_CHIP_ID_HIGH);
20039436SJing.Xiong@Sun.COM 		efuse_chip_id <<= 32;
20049436SJing.Xiong@Sun.COM 		efuse_chip_id |= adapter->unm_nic_pci_read_normalize(adapter,
20059436SJing.Xiong@Sun.COM 		    UNM_EFUSE_CHIP_ID_LOW);
20069436SJing.Xiong@Sun.COM 		(void) memcpy(up_data, &efuse_chip_id, sizeof (uint64_t));
20077956Sxiuyan.wang@Sun.COM 		data.rv = 0;
20087956Sxiuyan.wang@Sun.COM 		break;
20097956Sxiuyan.wang@Sun.COM 
20107956Sxiuyan.wang@Sun.COM 	default:
20117956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "%s%d: bad command %d\n", adapter->name,
20127956Sxiuyan.wang@Sun.COM 		    adapter->instance, data.cmd);
20137956Sxiuyan.wang@Sun.COM 		data.rv = GLD_NOTSUPPORTED;
20147956Sxiuyan.wang@Sun.COM 		data.size = 0;
20157956Sxiuyan.wang@Sun.COM 		goto error_out;
20167956Sxiuyan.wang@Sun.COM 	}
20177956Sxiuyan.wang@Sun.COM 
20187956Sxiuyan.wang@Sun.COM work_done:
20197956Sxiuyan.wang@Sun.COM 	miocack(wq, mp, data.size, data.rv);
20207956Sxiuyan.wang@Sun.COM 	return (DDI_SUCCESS);
20217956Sxiuyan.wang@Sun.COM 
20227956Sxiuyan.wang@Sun.COM error_out:
20237956Sxiuyan.wang@Sun.COM 	cmn_err(CE_WARN, "%s(%d) ioctl error\n", __FUNCTION__, data.cmd);
20247956Sxiuyan.wang@Sun.COM 	miocnak(wq, mp, 0, EINVAL);
20257956Sxiuyan.wang@Sun.COM 	return (retval);
20267956Sxiuyan.wang@Sun.COM }
20277956Sxiuyan.wang@Sun.COM 
20287956Sxiuyan.wang@Sun.COM /*
20297956Sxiuyan.wang@Sun.COM  * Local datatype for defining tables of (Offset, Name) pairs
20307956Sxiuyan.wang@Sun.COM  */
20317956Sxiuyan.wang@Sun.COM typedef struct {
20327956Sxiuyan.wang@Sun.COM 	offset_t	index;
20337956Sxiuyan.wang@Sun.COM 	char		*name;
20347956Sxiuyan.wang@Sun.COM } unm_ksindex_t;
20357956Sxiuyan.wang@Sun.COM 
20367956Sxiuyan.wang@Sun.COM static const unm_ksindex_t unm_kstat[] = {
20377956Sxiuyan.wang@Sun.COM 	{ 0,		"freehdls"		},
20387956Sxiuyan.wang@Sun.COM 	{ 1,		"freecmds"		},
20397956Sxiuyan.wang@Sun.COM 	{ 2,		"tx_bcopy_threshold"	},
20407956Sxiuyan.wang@Sun.COM 	{ 3,		"rx_bcopy_threshold"	},
20417956Sxiuyan.wang@Sun.COM 	{ 4,		"xmitcalled"		},
20427956Sxiuyan.wang@Sun.COM 	{ 5,		"xmitedframes"		},
20437956Sxiuyan.wang@Sun.COM 	{ 6,		"xmitfinished"		},
20447956Sxiuyan.wang@Sun.COM 	{ 7,		"txbytes"		},
20457956Sxiuyan.wang@Sun.COM 	{ 8,		"txcopyed"		},
20467956Sxiuyan.wang@Sun.COM 	{ 9,		"txmapped"		},
20477956Sxiuyan.wang@Sun.COM 	{ 10,		"outoftxdmahdl"		},
20487956Sxiuyan.wang@Sun.COM 	{ 11,		"outofcmddesc"		},
20497956Sxiuyan.wang@Sun.COM 	{ 12,		"txdropped"		},
20507956Sxiuyan.wang@Sun.COM 	{ 13,		"polled"		},
20517956Sxiuyan.wang@Sun.COM 	{ 14,		"uphappy"		},
20527956Sxiuyan.wang@Sun.COM 	{ 15,		"updropped"		},
20537956Sxiuyan.wang@Sun.COM 	{ 16,		"csummed"		},
20547956Sxiuyan.wang@Sun.COM 	{ 17,		"no_rcv"		},
20557956Sxiuyan.wang@Sun.COM 	{ 18,		"rxbytes"		},
20567956Sxiuyan.wang@Sun.COM 	{ 19,		"rxcopyed"		},
20577956Sxiuyan.wang@Sun.COM 	{ 20,		"rxmapped"		},
20587956Sxiuyan.wang@Sun.COM 	{ 21,		"desballocfailed"	},
20597956Sxiuyan.wang@Sun.COM 	{ 22,		"outofrxbuf"		},
20607956Sxiuyan.wang@Sun.COM 	{ 23,		"promiscmode"		},
20617956Sxiuyan.wang@Sun.COM 	{ 24,		"rxbufshort"		},
20627956Sxiuyan.wang@Sun.COM 	{ 25,		"allocbfailed"		},
20637956Sxiuyan.wang@Sun.COM 	{ -1,		NULL			}
20647956Sxiuyan.wang@Sun.COM };
20657956Sxiuyan.wang@Sun.COM 
20667956Sxiuyan.wang@Sun.COM static int
unm_kstat_update(kstat_t * ksp,int flag)20677956Sxiuyan.wang@Sun.COM unm_kstat_update(kstat_t *ksp, int flag)
20687956Sxiuyan.wang@Sun.COM {
20697956Sxiuyan.wang@Sun.COM 	unm_adapter *adapter;
20707956Sxiuyan.wang@Sun.COM 	kstat_named_t *knp;
20717956Sxiuyan.wang@Sun.COM 
20727956Sxiuyan.wang@Sun.COM 	if (flag != KSTAT_READ)
20737956Sxiuyan.wang@Sun.COM 		return (EACCES);
20747956Sxiuyan.wang@Sun.COM 
20757956Sxiuyan.wang@Sun.COM 	adapter = ksp->ks_private;
20767956Sxiuyan.wang@Sun.COM 	knp = ksp->ks_data;
20777956Sxiuyan.wang@Sun.COM 
20787956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui32 = adapter->freehdls;
20797956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->freecmds;
20807956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->tx_bcopy_threshold;
20817956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->rx_bcopy_threshold;
20827956Sxiuyan.wang@Sun.COM 
20837956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.xmitcalled;
20847956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.xmitedframes;
20857956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.xmitfinished;
20867956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.txbytes;
20877956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.txcopyed;
20887956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.txmapped;
20897956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.outoftxdmahdl;
20907956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.outofcmddesc;
20917956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.txdropped;
20927956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.polled;
20937956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.uphappy;
20947956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.updropped;
20957956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.csummed;
20967956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.no_rcv;
20977956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.rxbytes;
20987956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.rxcopyed;
20997956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.rxmapped;
21007956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.desballocfailed;
21017956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.outofrxbuf;
21027956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.promiscmode;
21037956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.rxbufshort;
21047956Sxiuyan.wang@Sun.COM 	(knp++)->value.ui64 = adapter->stats.allocbfailed;
21057956Sxiuyan.wang@Sun.COM 
21067956Sxiuyan.wang@Sun.COM 	return (0);
21077956Sxiuyan.wang@Sun.COM }
21087956Sxiuyan.wang@Sun.COM 
21097956Sxiuyan.wang@Sun.COM static kstat_t *
unm_setup_named_kstat(unm_adapter * adapter,int instance,char * name,const unm_ksindex_t * ksip,size_t size,int (* update)(kstat_t *,int))21107956Sxiuyan.wang@Sun.COM unm_setup_named_kstat(unm_adapter *adapter, int instance, char *name,
21117956Sxiuyan.wang@Sun.COM 	const unm_ksindex_t *ksip, size_t size, int (*update)(kstat_t *, int))
21127956Sxiuyan.wang@Sun.COM {
21137956Sxiuyan.wang@Sun.COM 	kstat_t *ksp;
21147956Sxiuyan.wang@Sun.COM 	kstat_named_t *knp;
21157956Sxiuyan.wang@Sun.COM 	char *np;
21167956Sxiuyan.wang@Sun.COM 	int type;
21177956Sxiuyan.wang@Sun.COM 	int count = 0;
21187956Sxiuyan.wang@Sun.COM 
21197956Sxiuyan.wang@Sun.COM 	size /= sizeof (unm_ksindex_t);
21207956Sxiuyan.wang@Sun.COM 	ksp = kstat_create(unm_nic_driver_name, instance, name, "net",
21217956Sxiuyan.wang@Sun.COM 	    KSTAT_TYPE_NAMED, size-1, KSTAT_FLAG_PERSISTENT);
21227956Sxiuyan.wang@Sun.COM 	if (ksp == NULL)
21237956Sxiuyan.wang@Sun.COM 		return (NULL);
21247956Sxiuyan.wang@Sun.COM 
21257956Sxiuyan.wang@Sun.COM 	ksp->ks_private = adapter;
21267956Sxiuyan.wang@Sun.COM 	ksp->ks_update = update;
21277956Sxiuyan.wang@Sun.COM 	for (knp = ksp->ks_data; (np = ksip->name) != NULL; ++knp, ++ksip) {
21287956Sxiuyan.wang@Sun.COM 		count++;
21297956Sxiuyan.wang@Sun.COM 		switch (*np) {
21307956Sxiuyan.wang@Sun.COM 		default:
21317956Sxiuyan.wang@Sun.COM 			type = KSTAT_DATA_UINT64;
21327956Sxiuyan.wang@Sun.COM 			break;
21337956Sxiuyan.wang@Sun.COM 		case '%':
21347956Sxiuyan.wang@Sun.COM 			np += 1;
21357956Sxiuyan.wang@Sun.COM 			type = KSTAT_DATA_UINT32;
21367956Sxiuyan.wang@Sun.COM 			break;
21377956Sxiuyan.wang@Sun.COM 		case '$':
21387956Sxiuyan.wang@Sun.COM 			np += 1;
21397956Sxiuyan.wang@Sun.COM 			type = KSTAT_DATA_STRING;
21407956Sxiuyan.wang@Sun.COM 			break;
21417956Sxiuyan.wang@Sun.COM 		case '&':
21427956Sxiuyan.wang@Sun.COM 			np += 1;
21437956Sxiuyan.wang@Sun.COM 			type = KSTAT_DATA_CHAR;
21447956Sxiuyan.wang@Sun.COM 			break;
21457956Sxiuyan.wang@Sun.COM 		}
21467956Sxiuyan.wang@Sun.COM 		kstat_named_init(knp, np, type);
21477956Sxiuyan.wang@Sun.COM 	}
21487956Sxiuyan.wang@Sun.COM 	kstat_install(ksp);
21497956Sxiuyan.wang@Sun.COM 
21507956Sxiuyan.wang@Sun.COM 	return (ksp);
21517956Sxiuyan.wang@Sun.COM }
21527956Sxiuyan.wang@Sun.COM 
21537956Sxiuyan.wang@Sun.COM void
unm_init_kstats(unm_adapter * adapter,int instance)21547956Sxiuyan.wang@Sun.COM unm_init_kstats(unm_adapter* adapter, int instance)
21557956Sxiuyan.wang@Sun.COM {
21567956Sxiuyan.wang@Sun.COM 	adapter->kstats[0] = unm_setup_named_kstat(adapter,
21577956Sxiuyan.wang@Sun.COM 	    instance, "kstatinfo", unm_kstat,
21587956Sxiuyan.wang@Sun.COM 	    sizeof (unm_kstat), unm_kstat_update);
21597956Sxiuyan.wang@Sun.COM }
21607956Sxiuyan.wang@Sun.COM 
21617956Sxiuyan.wang@Sun.COM void
unm_fini_kstats(unm_adapter * adapter)21627956Sxiuyan.wang@Sun.COM unm_fini_kstats(unm_adapter* adapter)
21637956Sxiuyan.wang@Sun.COM {
21647956Sxiuyan.wang@Sun.COM 
21657956Sxiuyan.wang@Sun.COM 	if (adapter->kstats[0] != NULL) {
21667956Sxiuyan.wang@Sun.COM 			kstat_delete(adapter->kstats[0]);
21677956Sxiuyan.wang@Sun.COM 			adapter->kstats[0] = NULL;
21687956Sxiuyan.wang@Sun.COM 		}
21697956Sxiuyan.wang@Sun.COM }
21707956Sxiuyan.wang@Sun.COM 
21717956Sxiuyan.wang@Sun.COM static int
unm_nic_set_pauseparam(unm_adapter * adapter,unm_pauseparam_t * pause)21727956Sxiuyan.wang@Sun.COM unm_nic_set_pauseparam(unm_adapter *adapter, unm_pauseparam_t *pause)
21737956Sxiuyan.wang@Sun.COM {
21747956Sxiuyan.wang@Sun.COM 	int ret = 0;
21757956Sxiuyan.wang@Sun.COM 
21767956Sxiuyan.wang@Sun.COM 	if (adapter->ahw.board_type == UNM_NIC_GBE) {
21777956Sxiuyan.wang@Sun.COM 		if (unm_niu_gbe_set_rx_flow_ctl(adapter, pause->rx_pause))
21787956Sxiuyan.wang@Sun.COM 			ret = -EIO;
21797956Sxiuyan.wang@Sun.COM 
21807956Sxiuyan.wang@Sun.COM 		if (unm_niu_gbe_set_tx_flow_ctl(adapter, pause->tx_pause))
21817956Sxiuyan.wang@Sun.COM 			ret = -EIO;
21827956Sxiuyan.wang@Sun.COM 
21837956Sxiuyan.wang@Sun.COM 	} else if (adapter->ahw.board_type == UNM_NIC_XGBE) {
21847956Sxiuyan.wang@Sun.COM 		if (unm_niu_xg_set_tx_flow_ctl(adapter, pause->tx_pause))
21857956Sxiuyan.wang@Sun.COM 			ret =  -EIO;
21867956Sxiuyan.wang@Sun.COM 	} else
21877956Sxiuyan.wang@Sun.COM 		ret = -EIO;
21887956Sxiuyan.wang@Sun.COM 
21897956Sxiuyan.wang@Sun.COM 	return (ret);
21907956Sxiuyan.wang@Sun.COM }
21917956Sxiuyan.wang@Sun.COM 
21927956Sxiuyan.wang@Sun.COM /*
21937956Sxiuyan.wang@Sun.COM  * GLD/MAC interfaces
21947956Sxiuyan.wang@Sun.COM  */
21957956Sxiuyan.wang@Sun.COM static int
ntxn_m_start(void * arg)21967956Sxiuyan.wang@Sun.COM ntxn_m_start(void *arg)
21977956Sxiuyan.wang@Sun.COM {
21987956Sxiuyan.wang@Sun.COM 	unm_adapter	*adapter = arg;
21997956Sxiuyan.wang@Sun.COM 	int		ring;
22007956Sxiuyan.wang@Sun.COM 
22017956Sxiuyan.wang@Sun.COM 	UNM_SPIN_LOCK(&adapter->lock);
22027956Sxiuyan.wang@Sun.COM 	if (adapter->is_up == UNM_ADAPTER_UP_MAGIC) {
22037956Sxiuyan.wang@Sun.COM 		UNM_SPIN_UNLOCK(&adapter->lock);
22047956Sxiuyan.wang@Sun.COM 		return (DDI_SUCCESS);
22057956Sxiuyan.wang@Sun.COM 	}
22067956Sxiuyan.wang@Sun.COM 
22079436SJing.Xiong@Sun.COM 	if (create_rxtx_rings(adapter) != DDI_SUCCESS) {
22089436SJing.Xiong@Sun.COM 		UNM_SPIN_UNLOCK(&adapter->lock);
22099436SJing.Xiong@Sun.COM 		return (DDI_FAILURE);
22109436SJing.Xiong@Sun.COM 	}
22119436SJing.Xiong@Sun.COM 
22127956Sxiuyan.wang@Sun.COM 	if (init_firmware(adapter) != DDI_SUCCESS) {
22137956Sxiuyan.wang@Sun.COM 		UNM_SPIN_UNLOCK(&adapter->lock);
22147956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "%s%d: Failed to init firmware\n",
22157956Sxiuyan.wang@Sun.COM 		    adapter->name, adapter->instance);
22169436SJing.Xiong@Sun.COM 		goto dest_rings;
22177956Sxiuyan.wang@Sun.COM 	}
22187956Sxiuyan.wang@Sun.COM 
22197956Sxiuyan.wang@Sun.COM 	unm_nic_clear_stats(adapter);
22207956Sxiuyan.wang@Sun.COM 
22217956Sxiuyan.wang@Sun.COM 	if (unm_nic_hw_resources(adapter) != 0) {
22227956Sxiuyan.wang@Sun.COM 		UNM_SPIN_UNLOCK(&adapter->lock);
22237956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "%s%d: Error setting hw resources\n",
22247956Sxiuyan.wang@Sun.COM 		    adapter->name, adapter->instance);
22259436SJing.Xiong@Sun.COM 		goto dest_rings;
22267956Sxiuyan.wang@Sun.COM 	}
22277956Sxiuyan.wang@Sun.COM 
22287956Sxiuyan.wang@Sun.COM 	if (adapter->fw_major < 4) {
22297956Sxiuyan.wang@Sun.COM 		adapter->crb_addr_cmd_producer =
22307956Sxiuyan.wang@Sun.COM 		    crb_cmd_producer[adapter->portnum];
22317956Sxiuyan.wang@Sun.COM 		adapter->crb_addr_cmd_consumer =
22327956Sxiuyan.wang@Sun.COM 		    crb_cmd_consumer[adapter->portnum];
22337956Sxiuyan.wang@Sun.COM 		unm_nic_update_cmd_producer(adapter, 0);
22347956Sxiuyan.wang@Sun.COM 		unm_nic_update_cmd_consumer(adapter, 0);
22357956Sxiuyan.wang@Sun.COM 	}
22367956Sxiuyan.wang@Sun.COM 
22377956Sxiuyan.wang@Sun.COM 	for (ring = 0; ring < adapter->max_rds_rings; ring++) {
22387956Sxiuyan.wang@Sun.COM 		if (unm_post_rx_buffers(adapter, ring) != DDI_SUCCESS) {
22397956Sxiuyan.wang@Sun.COM 			UNM_SPIN_UNLOCK(&adapter->lock);
22409436SJing.Xiong@Sun.COM 			goto free_hw_res;
22417956Sxiuyan.wang@Sun.COM 		}
22427956Sxiuyan.wang@Sun.COM 	}
22437956Sxiuyan.wang@Sun.COM 
22447956Sxiuyan.wang@Sun.COM 	if (unm_nic_macaddr_set(adapter, adapter->mac_addr) != 0) {
22457956Sxiuyan.wang@Sun.COM 		UNM_SPIN_UNLOCK(&adapter->lock);
22467956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "%s%d: Could not set mac address\n",
22477956Sxiuyan.wang@Sun.COM 		    adapter->name, adapter->instance);
22489436SJing.Xiong@Sun.COM 		goto free_hw_res;
22497956Sxiuyan.wang@Sun.COM 	}
22507956Sxiuyan.wang@Sun.COM 
22517956Sxiuyan.wang@Sun.COM 	if (unm_nic_init_port(adapter) != 0) {
22527956Sxiuyan.wang@Sun.COM 		UNM_SPIN_UNLOCK(&adapter->lock);
22537956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "%s%d: Could not initialize port\n",
22547956Sxiuyan.wang@Sun.COM 		    adapter->name, adapter->instance);
22559436SJing.Xiong@Sun.COM 		goto free_hw_res;
22567956Sxiuyan.wang@Sun.COM 	}
22577956Sxiuyan.wang@Sun.COM 
22587956Sxiuyan.wang@Sun.COM 	unm_nic_set_link_parameters(adapter);
22597956Sxiuyan.wang@Sun.COM 
22607956Sxiuyan.wang@Sun.COM 	/*
22617956Sxiuyan.wang@Sun.COM 	 * P2 and P3 should be handled similarly.
22627956Sxiuyan.wang@Sun.COM 	 */
22637956Sxiuyan.wang@Sun.COM 	if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
22647956Sxiuyan.wang@Sun.COM 		if (unm_nic_set_promisc_mode(adapter) != 0) {
22657956Sxiuyan.wang@Sun.COM 			UNM_SPIN_UNLOCK(&adapter->lock);
22667956Sxiuyan.wang@Sun.COM 			cmn_err(CE_WARN, "%s%d: Could not set promisc mode\n",
22677956Sxiuyan.wang@Sun.COM 			    adapter->name, adapter->instance);
22689436SJing.Xiong@Sun.COM 			goto stop_and_free;
22697956Sxiuyan.wang@Sun.COM 		}
22707956Sxiuyan.wang@Sun.COM 	} else {
22717956Sxiuyan.wang@Sun.COM 		nx_p3_nic_set_multi(adapter);
22727956Sxiuyan.wang@Sun.COM 	}
22737956Sxiuyan.wang@Sun.COM 	adapter->stats.promiscmode = 1;
22747956Sxiuyan.wang@Sun.COM 
22757956Sxiuyan.wang@Sun.COM 	if (unm_nic_set_mtu(adapter, adapter->mtu) != 0) {
22767956Sxiuyan.wang@Sun.COM 		UNM_SPIN_UNLOCK(&adapter->lock);
22777956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "%s%d: Could not set mtu\n",
22787956Sxiuyan.wang@Sun.COM 		    adapter->name, adapter->instance);
22799436SJing.Xiong@Sun.COM 		goto stop_and_free;
22807956Sxiuyan.wang@Sun.COM 	}
22817956Sxiuyan.wang@Sun.COM 
22827956Sxiuyan.wang@Sun.COM 	adapter->watchdog_timer = timeout((void (*)(void *))&unm_watchdog,
22837956Sxiuyan.wang@Sun.COM 	    (void *)adapter, 0);
22847956Sxiuyan.wang@Sun.COM 
22857956Sxiuyan.wang@Sun.COM 	adapter->is_up = UNM_ADAPTER_UP_MAGIC;
22867956Sxiuyan.wang@Sun.COM 
22877956Sxiuyan.wang@Sun.COM 	if (adapter->intr_type == DDI_INTR_TYPE_MSI)
22887956Sxiuyan.wang@Sun.COM 		(void) ddi_intr_block_enable(&adapter->intr_handle, 1);
22897956Sxiuyan.wang@Sun.COM 	else
22907956Sxiuyan.wang@Sun.COM 		(void) ddi_intr_enable(adapter->intr_handle);
22917956Sxiuyan.wang@Sun.COM 	unm_nic_enable_int(adapter);
22927956Sxiuyan.wang@Sun.COM 
22937956Sxiuyan.wang@Sun.COM 	UNM_SPIN_UNLOCK(&adapter->lock);
22947956Sxiuyan.wang@Sun.COM 	return (GLD_SUCCESS);
22959436SJing.Xiong@Sun.COM 
22969436SJing.Xiong@Sun.COM stop_and_free:
22979436SJing.Xiong@Sun.COM 	unm_nic_stop_port(adapter);
22989436SJing.Xiong@Sun.COM free_hw_res:
22999436SJing.Xiong@Sun.COM 	unm_free_hw_resources(adapter);
23009436SJing.Xiong@Sun.COM dest_rings:
23019436SJing.Xiong@Sun.COM 	destroy_rxtx_rings(adapter);
23029436SJing.Xiong@Sun.COM 	return (DDI_FAILURE);
23037956Sxiuyan.wang@Sun.COM }
23047956Sxiuyan.wang@Sun.COM 
23057956Sxiuyan.wang@Sun.COM 
23067956Sxiuyan.wang@Sun.COM /*
23077956Sxiuyan.wang@Sun.COM  * This code is kept here for reference so as to
23087956Sxiuyan.wang@Sun.COM  * see if something different is required to be done
23097956Sxiuyan.wang@Sun.COM  * in GLDV3. This will be deleted later.
23107956Sxiuyan.wang@Sun.COM  */
23117956Sxiuyan.wang@Sun.COM /* ARGSUSED */
23127956Sxiuyan.wang@Sun.COM static void
ntxn_m_stop(void * arg)23137956Sxiuyan.wang@Sun.COM ntxn_m_stop(void *arg)
23147956Sxiuyan.wang@Sun.COM {
23157956Sxiuyan.wang@Sun.COM }
23167956Sxiuyan.wang@Sun.COM 
23177956Sxiuyan.wang@Sun.COM /*ARGSUSED*/
23187956Sxiuyan.wang@Sun.COM static int
ntxn_m_multicst(void * arg,boolean_t add,const uint8_t * ep)23197956Sxiuyan.wang@Sun.COM ntxn_m_multicst(void *arg, boolean_t add, const uint8_t *ep)
23207956Sxiuyan.wang@Sun.COM {
23217956Sxiuyan.wang@Sun.COM 	/*
23227956Sxiuyan.wang@Sun.COM 	 * When we correctly implement this, invoke nx_p3_nic_set_multi()
23237956Sxiuyan.wang@Sun.COM 	 * or nx_p2_nic_set_multi() here.
23247956Sxiuyan.wang@Sun.COM 	 */
23257956Sxiuyan.wang@Sun.COM 	return (GLD_SUCCESS);
23267956Sxiuyan.wang@Sun.COM }
23277956Sxiuyan.wang@Sun.COM 
23287956Sxiuyan.wang@Sun.COM /*ARGSUSED*/
23297956Sxiuyan.wang@Sun.COM static int
ntxn_m_promisc(void * arg,boolean_t on)23307956Sxiuyan.wang@Sun.COM ntxn_m_promisc(void *arg, boolean_t on)
23317956Sxiuyan.wang@Sun.COM {
23327956Sxiuyan.wang@Sun.COM #if 0
23337956Sxiuyan.wang@Sun.COM 	int err = 0;
23347956Sxiuyan.wang@Sun.COM 	struct unm_adapter_s *adapter = arg;
23357956Sxiuyan.wang@Sun.COM 
23367956Sxiuyan.wang@Sun.COM 	err = on ? unm_nic_set_promisc_mode(adapter) :
23377956Sxiuyan.wang@Sun.COM 	    unm_nic_unset_promisc_mode(adapter);
23387956Sxiuyan.wang@Sun.COM 
23397956Sxiuyan.wang@Sun.COM 	if (err)
23407956Sxiuyan.wang@Sun.COM 		return (GLD_FAILURE);
23417956Sxiuyan.wang@Sun.COM #endif
23427956Sxiuyan.wang@Sun.COM 
23437956Sxiuyan.wang@Sun.COM 	return (GLD_SUCCESS);
23447956Sxiuyan.wang@Sun.COM }
23457956Sxiuyan.wang@Sun.COM 
23467956Sxiuyan.wang@Sun.COM static int
ntxn_m_stat(void * arg,uint_t stat,uint64_t * val)23477956Sxiuyan.wang@Sun.COM ntxn_m_stat(void *arg, uint_t stat, uint64_t *val)
23487956Sxiuyan.wang@Sun.COM {
23497956Sxiuyan.wang@Sun.COM 	struct unm_adapter_s		*adapter = arg;
23507956Sxiuyan.wang@Sun.COM 	struct unm_adapter_stats	*portstat = &adapter->stats;
23517956Sxiuyan.wang@Sun.COM 
23527956Sxiuyan.wang@Sun.COM 	switch (stat) {
23537956Sxiuyan.wang@Sun.COM 	case MAC_STAT_IFSPEED:
23547956Sxiuyan.wang@Sun.COM 		if (adapter->ahw.board_type == UNM_NIC_XGBE) {
23557956Sxiuyan.wang@Sun.COM 			/* 10 Gigs */
23567956Sxiuyan.wang@Sun.COM 			*val = 10000000000ULL;
23577956Sxiuyan.wang@Sun.COM 		} else {
23587956Sxiuyan.wang@Sun.COM 			/* 1 Gig */
23597956Sxiuyan.wang@Sun.COM 			*val = 1000000000;
23607956Sxiuyan.wang@Sun.COM 		}
23617956Sxiuyan.wang@Sun.COM 		break;
23627956Sxiuyan.wang@Sun.COM 
23637956Sxiuyan.wang@Sun.COM 	case MAC_STAT_MULTIRCV:
23647956Sxiuyan.wang@Sun.COM 		*val = 0;
23657956Sxiuyan.wang@Sun.COM 		break;
23667956Sxiuyan.wang@Sun.COM 
23677956Sxiuyan.wang@Sun.COM 	case MAC_STAT_BRDCSTRCV:
23687956Sxiuyan.wang@Sun.COM 	case MAC_STAT_BRDCSTXMT:
23697956Sxiuyan.wang@Sun.COM 		*val = 0;
23707956Sxiuyan.wang@Sun.COM 		break;
23717956Sxiuyan.wang@Sun.COM 
23727956Sxiuyan.wang@Sun.COM 	case MAC_STAT_NORCVBUF:
23737956Sxiuyan.wang@Sun.COM 		*val = portstat->updropped;
23747956Sxiuyan.wang@Sun.COM 		break;
23757956Sxiuyan.wang@Sun.COM 
23767956Sxiuyan.wang@Sun.COM 	case MAC_STAT_NOXMTBUF:
23777956Sxiuyan.wang@Sun.COM 		*val = portstat->txdropped;
23787956Sxiuyan.wang@Sun.COM 		break;
23797956Sxiuyan.wang@Sun.COM 
23807956Sxiuyan.wang@Sun.COM 	case MAC_STAT_RBYTES:
23817956Sxiuyan.wang@Sun.COM 		*val = portstat->rxbytes;
23827956Sxiuyan.wang@Sun.COM 		break;
23837956Sxiuyan.wang@Sun.COM 
23847956Sxiuyan.wang@Sun.COM 	case MAC_STAT_OBYTES:
23857956Sxiuyan.wang@Sun.COM 		*val = portstat->txbytes;
23867956Sxiuyan.wang@Sun.COM 		break;
23877956Sxiuyan.wang@Sun.COM 
23887956Sxiuyan.wang@Sun.COM 	case MAC_STAT_OPACKETS:
23897956Sxiuyan.wang@Sun.COM 		*val = portstat->xmitedframes;
23907956Sxiuyan.wang@Sun.COM 		break;
23917956Sxiuyan.wang@Sun.COM 
23927956Sxiuyan.wang@Sun.COM 	case MAC_STAT_IPACKETS:
23937956Sxiuyan.wang@Sun.COM 		*val = portstat->uphappy;
23947956Sxiuyan.wang@Sun.COM 		break;
23957956Sxiuyan.wang@Sun.COM 
23967956Sxiuyan.wang@Sun.COM 	case MAC_STAT_OERRORS:
23977956Sxiuyan.wang@Sun.COM 		*val = portstat->xmitcalled - portstat->xmitedframes;
23987956Sxiuyan.wang@Sun.COM 		break;
23997956Sxiuyan.wang@Sun.COM 
24007956Sxiuyan.wang@Sun.COM 	case ETHER_STAT_LINK_DUPLEX:
24017956Sxiuyan.wang@Sun.COM 		*val = LINK_DUPLEX_FULL;
24027956Sxiuyan.wang@Sun.COM 		break;
24037956Sxiuyan.wang@Sun.COM 
24047956Sxiuyan.wang@Sun.COM 	default:
24057956Sxiuyan.wang@Sun.COM 		/*
24067956Sxiuyan.wang@Sun.COM 		 * Shouldn't reach here...
24077956Sxiuyan.wang@Sun.COM 		 */
24087956Sxiuyan.wang@Sun.COM 		*val = 0;
24097956Sxiuyan.wang@Sun.COM 		DPRINTF(0, (CE_WARN, ": unrecognized parameter = %d, value "
24107956Sxiuyan.wang@Sun.COM 		    "returned 1\n", stat));
24117956Sxiuyan.wang@Sun.COM 
24127956Sxiuyan.wang@Sun.COM 	}
24137956Sxiuyan.wang@Sun.COM 
24147956Sxiuyan.wang@Sun.COM 	return (0);
24157956Sxiuyan.wang@Sun.COM }
24167956Sxiuyan.wang@Sun.COM 
24177956Sxiuyan.wang@Sun.COM static int
ntxn_m_unicst(void * arg,const uint8_t * mac)24187956Sxiuyan.wang@Sun.COM ntxn_m_unicst(void *arg, const uint8_t *mac)
24197956Sxiuyan.wang@Sun.COM {
24207956Sxiuyan.wang@Sun.COM 	struct unm_adapter_s *adapter = arg;
24217956Sxiuyan.wang@Sun.COM 
24227956Sxiuyan.wang@Sun.COM 	DPRINTF(-1, (CE_CONT, "%s: called\n", __func__));
24237956Sxiuyan.wang@Sun.COM 
24247956Sxiuyan.wang@Sun.COM 	if (unm_nic_macaddr_set(adapter, (uint8_t *)mac))
24257956Sxiuyan.wang@Sun.COM 		return (EAGAIN);
24267956Sxiuyan.wang@Sun.COM 	bcopy(mac, adapter->mac_addr, ETHERADDRL);
24277956Sxiuyan.wang@Sun.COM 
24287956Sxiuyan.wang@Sun.COM 	return (0);
24297956Sxiuyan.wang@Sun.COM }
24307956Sxiuyan.wang@Sun.COM 
24317956Sxiuyan.wang@Sun.COM static mblk_t *
ntxn_m_tx(void * arg,mblk_t * mp)24327956Sxiuyan.wang@Sun.COM ntxn_m_tx(void *arg, mblk_t *mp)
24337956Sxiuyan.wang@Sun.COM {
24347956Sxiuyan.wang@Sun.COM 	unm_adapter *adapter = arg;
24357956Sxiuyan.wang@Sun.COM 	mblk_t *next;
24367956Sxiuyan.wang@Sun.COM 
24377956Sxiuyan.wang@Sun.COM 	while (mp != NULL) {
24387956Sxiuyan.wang@Sun.COM 		next = mp->b_next;
24397956Sxiuyan.wang@Sun.COM 		mp->b_next = NULL;
24407956Sxiuyan.wang@Sun.COM 
24417956Sxiuyan.wang@Sun.COM 		if (unm_nic_xmit_frame(adapter, mp) != B_TRUE) {
24427956Sxiuyan.wang@Sun.COM 			mp->b_next = next;
24437956Sxiuyan.wang@Sun.COM 			break;
24447956Sxiuyan.wang@Sun.COM 		}
24457956Sxiuyan.wang@Sun.COM 		mp = next;
24467956Sxiuyan.wang@Sun.COM 		adapter->stats.xmitedframes++;
24477956Sxiuyan.wang@Sun.COM 	}
24487956Sxiuyan.wang@Sun.COM 
24497956Sxiuyan.wang@Sun.COM 	return (mp);
24507956Sxiuyan.wang@Sun.COM }
24517956Sxiuyan.wang@Sun.COM 
24527956Sxiuyan.wang@Sun.COM static void
ntxn_m_ioctl(void * arg,queue_t * wq,mblk_t * mp)24537956Sxiuyan.wang@Sun.COM ntxn_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
24547956Sxiuyan.wang@Sun.COM {
24557956Sxiuyan.wang@Sun.COM 	int		cmd;
24567956Sxiuyan.wang@Sun.COM 	struct iocblk   *iocp = (struct iocblk *)(uintptr_t)mp->b_rptr;
24577956Sxiuyan.wang@Sun.COM 	struct unm_adapter_s *adapter = (struct unm_adapter_s *)arg;
24587956Sxiuyan.wang@Sun.COM 	enum ioc_reply status = IOC_DONE;
24597956Sxiuyan.wang@Sun.COM 
24607956Sxiuyan.wang@Sun.COM 	iocp->ioc_error = 0;
24617956Sxiuyan.wang@Sun.COM 	cmd = iocp->ioc_cmd;
24627956Sxiuyan.wang@Sun.COM 
24637956Sxiuyan.wang@Sun.COM 	if (cmd == ND_GET || cmd == ND_SET) {
24647956Sxiuyan.wang@Sun.COM 		status = unm_nd_ioctl(adapter, wq, mp, iocp);
24657956Sxiuyan.wang@Sun.COM 		switch (status) {
24667956Sxiuyan.wang@Sun.COM 		default:
24677956Sxiuyan.wang@Sun.COM 		case IOC_INVAL:
24687956Sxiuyan.wang@Sun.COM 			miocnak(wq, mp, 0, iocp->ioc_error == 0 ?
24697956Sxiuyan.wang@Sun.COM 			    EINVAL : iocp->ioc_error);
24707956Sxiuyan.wang@Sun.COM 			break;
24717956Sxiuyan.wang@Sun.COM 
24727956Sxiuyan.wang@Sun.COM 		case IOC_DONE:
24737956Sxiuyan.wang@Sun.COM 			break;
24747956Sxiuyan.wang@Sun.COM 
24757956Sxiuyan.wang@Sun.COM 		case IOC_RESTART_ACK:
24767956Sxiuyan.wang@Sun.COM 		case IOC_ACK:
24777956Sxiuyan.wang@Sun.COM 			miocack(wq, mp, 0, 0);
24787956Sxiuyan.wang@Sun.COM 			break;
24797956Sxiuyan.wang@Sun.COM 
24807956Sxiuyan.wang@Sun.COM 		case IOC_RESTART_REPLY:
24817956Sxiuyan.wang@Sun.COM 		case IOC_REPLY:
24827956Sxiuyan.wang@Sun.COM 			mp->b_datap->db_type = iocp->ioc_error == 0 ?
24837956Sxiuyan.wang@Sun.COM 			    M_IOCACK : M_IOCNAK;
24847956Sxiuyan.wang@Sun.COM 			qreply(wq, mp);
24857956Sxiuyan.wang@Sun.COM 			break;
24867956Sxiuyan.wang@Sun.COM 		}
24877956Sxiuyan.wang@Sun.COM 	} else if (cmd <= UNM_NIC_NAME && cmd >= UNM_CMD_START) {
24887956Sxiuyan.wang@Sun.COM 		unm_nic_ioctl(adapter, cmd, wq, mp);
24897956Sxiuyan.wang@Sun.COM 		return;
24907956Sxiuyan.wang@Sun.COM 	} else {
24917956Sxiuyan.wang@Sun.COM 		miocnak(wq, mp, 0, EINVAL);
24927956Sxiuyan.wang@Sun.COM 		return;
24937956Sxiuyan.wang@Sun.COM 	}
24947956Sxiuyan.wang@Sun.COM }
24957956Sxiuyan.wang@Sun.COM 
24967956Sxiuyan.wang@Sun.COM /* ARGSUSED */
24977956Sxiuyan.wang@Sun.COM static boolean_t
ntxn_m_getcapab(void * arg,mac_capab_t cap,void * cap_data)24987956Sxiuyan.wang@Sun.COM ntxn_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
24997956Sxiuyan.wang@Sun.COM {
25007956Sxiuyan.wang@Sun.COM 	switch (cap) {
25017956Sxiuyan.wang@Sun.COM 	case MAC_CAPAB_HCKSUM:
25027956Sxiuyan.wang@Sun.COM 		{
25037956Sxiuyan.wang@Sun.COM 			uint32_t *txflags = cap_data;
25047956Sxiuyan.wang@Sun.COM 
25057956Sxiuyan.wang@Sun.COM 			*txflags = (HCKSUM_ENABLE |
25067956Sxiuyan.wang@Sun.COM 			    HCKSUM_INET_FULL_V4 | HCKSUM_IPHDRCKSUM);
25077956Sxiuyan.wang@Sun.COM 		}
25087956Sxiuyan.wang@Sun.COM 		break;
25099436SJing.Xiong@Sun.COM 
25109436SJing.Xiong@Sun.COM #ifdef SOLARIS11
25119436SJing.Xiong@Sun.COM 	case MAC_CAPAB_ANCHOR_VNIC:
25129436SJing.Xiong@Sun.COM 	case MAC_CAPAB_MULTIFACTADDR:
25139436SJing.Xiong@Sun.COM #else
25149436SJing.Xiong@Sun.COM 	case MAC_CAPAB_POLL:
25159436SJing.Xiong@Sun.COM 	case MAC_CAPAB_MULTIADDRESS:
25169436SJing.Xiong@Sun.COM #endif
25177956Sxiuyan.wang@Sun.COM 	default:
25187956Sxiuyan.wang@Sun.COM 		return (B_FALSE);
25197956Sxiuyan.wang@Sun.COM 	}
25207956Sxiuyan.wang@Sun.COM 
25217956Sxiuyan.wang@Sun.COM 	return (B_TRUE);
25227956Sxiuyan.wang@Sun.COM }
25237956Sxiuyan.wang@Sun.COM 
25247956Sxiuyan.wang@Sun.COM #define	NETXEN_M_CALLBACK_FLAGS	(MC_IOCTL | MC_GETCAPAB)
25257956Sxiuyan.wang@Sun.COM 
25267956Sxiuyan.wang@Sun.COM static mac_callbacks_t ntxn_m_callbacks = {
25277956Sxiuyan.wang@Sun.COM 	NETXEN_M_CALLBACK_FLAGS,
25287956Sxiuyan.wang@Sun.COM 	ntxn_m_stat,
25297956Sxiuyan.wang@Sun.COM 	ntxn_m_start,
25307956Sxiuyan.wang@Sun.COM 	ntxn_m_stop,
25317956Sxiuyan.wang@Sun.COM 	ntxn_m_promisc,
25327956Sxiuyan.wang@Sun.COM 	ntxn_m_multicst,
25337956Sxiuyan.wang@Sun.COM 	ntxn_m_unicst,
25347956Sxiuyan.wang@Sun.COM 	ntxn_m_tx,
2535*11878SVenu.Iyer@Sun.COM 	NULL,			/* mc_reserved */
25367956Sxiuyan.wang@Sun.COM 	ntxn_m_ioctl,
25377956Sxiuyan.wang@Sun.COM 	ntxn_m_getcapab,
25387956Sxiuyan.wang@Sun.COM 	NULL,			/* mc_open */
25397956Sxiuyan.wang@Sun.COM 	NULL,			/* mc_close */
25407956Sxiuyan.wang@Sun.COM 	NULL,			/* mc_setprop */
25417956Sxiuyan.wang@Sun.COM 	NULL			/* mc_getprop */
25427956Sxiuyan.wang@Sun.COM };
25437956Sxiuyan.wang@Sun.COM 
25447956Sxiuyan.wang@Sun.COM int
unm_register_mac(unm_adapter * adapter)25457956Sxiuyan.wang@Sun.COM unm_register_mac(unm_adapter *adapter)
25467956Sxiuyan.wang@Sun.COM {
25477956Sxiuyan.wang@Sun.COM 	int ret;
25487956Sxiuyan.wang@Sun.COM 	mac_register_t *macp;
25497956Sxiuyan.wang@Sun.COM 	unm_pauseparam_t pause;
25507956Sxiuyan.wang@Sun.COM 
25517956Sxiuyan.wang@Sun.COM 	dev_info_t *dip = adapter->dip;
25527956Sxiuyan.wang@Sun.COM 
25537956Sxiuyan.wang@Sun.COM 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
25547956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "Memory not available\n");
25557956Sxiuyan.wang@Sun.COM 		return (DDI_FAILURE);
25567956Sxiuyan.wang@Sun.COM 	}
25577956Sxiuyan.wang@Sun.COM 
25587956Sxiuyan.wang@Sun.COM 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
25597956Sxiuyan.wang@Sun.COM 	macp->m_driver = adapter;
25607956Sxiuyan.wang@Sun.COM 	macp->m_dip = dip;
25617956Sxiuyan.wang@Sun.COM 	macp->m_instance = adapter->instance;
25627956Sxiuyan.wang@Sun.COM 	macp->m_src_addr = adapter->mac_addr;
25637956Sxiuyan.wang@Sun.COM 	macp->m_callbacks = &ntxn_m_callbacks;
25647956Sxiuyan.wang@Sun.COM 	macp->m_min_sdu = 0;
25657956Sxiuyan.wang@Sun.COM 	macp->m_max_sdu = adapter->mtu;
25667956Sxiuyan.wang@Sun.COM #ifdef SOLARIS11
25677956Sxiuyan.wang@Sun.COM 	macp->m_margin = VLAN_TAGSZ;
25687956Sxiuyan.wang@Sun.COM #endif /* SOLARIS11 */
25697956Sxiuyan.wang@Sun.COM 
25707956Sxiuyan.wang@Sun.COM 	ret = mac_register(macp, &adapter->mach);
25717956Sxiuyan.wang@Sun.COM 	mac_free(macp);
25727956Sxiuyan.wang@Sun.COM 	if (ret != 0) {
25737956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "mac_register failed for port %d\n",
25747956Sxiuyan.wang@Sun.COM 		    adapter->portnum);
25757956Sxiuyan.wang@Sun.COM 		return (DDI_FAILURE);
25767956Sxiuyan.wang@Sun.COM 	}
25777956Sxiuyan.wang@Sun.COM 
25787956Sxiuyan.wang@Sun.COM 	unm_init_kstats(adapter, adapter->instance);
25797956Sxiuyan.wang@Sun.COM 
25807956Sxiuyan.wang@Sun.COM 	/* Register NDD-tweakable parameters */
25817956Sxiuyan.wang@Sun.COM 	if (unm_nd_init(adapter)) {
25827956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "unm_nd_init() failed");
25837956Sxiuyan.wang@Sun.COM 		return (DDI_FAILURE);
25847956Sxiuyan.wang@Sun.COM 	}
25857956Sxiuyan.wang@Sun.COM 
25867956Sxiuyan.wang@Sun.COM 	pause.rx_pause = adapter->nd_params[PARAM_ADV_PAUSE_CAP].ndp_val;
25877956Sxiuyan.wang@Sun.COM 	pause.tx_pause = adapter->nd_params[PARAM_ADV_ASYM_PAUSE_CAP].ndp_val;
25887956Sxiuyan.wang@Sun.COM 
25897956Sxiuyan.wang@Sun.COM 	if (unm_nic_set_pauseparam(adapter, &pause)) {
25907956Sxiuyan.wang@Sun.COM 		cmn_err(CE_WARN, "\nBad Pause settings RX %d, Tx %d",
25917956Sxiuyan.wang@Sun.COM 		    pause.rx_pause, pause.tx_pause);
25927956Sxiuyan.wang@Sun.COM 	}
25937956Sxiuyan.wang@Sun.COM 	adapter->nd_params[PARAM_PAUSE_CAP].ndp_val = pause.rx_pause;
25947956Sxiuyan.wang@Sun.COM 	adapter->nd_params[PARAM_ASYM_PAUSE_CAP].ndp_val = pause.tx_pause;
25957956Sxiuyan.wang@Sun.COM 
25967956Sxiuyan.wang@Sun.COM 	return (DDI_SUCCESS);
25977956Sxiuyan.wang@Sun.COM }
2598