xref: /onnv-gate/usr/src/uts/common/io/xge/drv/xgell.c (revision 6937:a5e2c8b5c817)
11256Syl150051 /*
21256Syl150051  * CDDL HEADER START
31256Syl150051  *
41256Syl150051  * The contents of this file are subject to the terms of the
51256Syl150051  * Common Development and Distribution License (the "License").
61256Syl150051  * You may not use this file except in compliance with the License.
71256Syl150051  *
81256Syl150051  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
91256Syl150051  * or http://www.opensolaris.org/os/licensing.
101256Syl150051  * See the License for the specific language governing permissions
111256Syl150051  * and limitations under the License.
121256Syl150051  *
131256Syl150051  * When distributing Covered Code, include this CDDL HEADER in each
141256Syl150051  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
151256Syl150051  * If applicable, add the following below this CDDL HEADER, with the
161256Syl150051  * fields enclosed by brackets "[]" replaced with your own identifying
171256Syl150051  * information: Portions Copyright [yyyy] [name of copyright owner]
181256Syl150051  *
191256Syl150051  * CDDL HEADER END
201256Syl150051  */
211256Syl150051 
221256Syl150051 /*
235895Syz147064  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
241256Syl150051  * Use is subject to license terms.
251256Syl150051  */
261256Syl150051 
271256Syl150051 #pragma ident	"%Z%%M%	%I%	%E% SMI"
281256Syl150051 
291256Syl150051 /*
301256Syl150051  *  Copyright (c) 2002-2005 Neterion, Inc.
311256Syl150051  *  All right Reserved.
321256Syl150051  *
331256Syl150051  *  FileName :    xgell.c
341256Syl150051  *
351256Syl150051  *  Description:  Xge Link Layer data path implementation
361256Syl150051  *
371256Syl150051  */
381256Syl150051 
391256Syl150051 #include "xgell.h"
401256Syl150051 
411256Syl150051 #include <netinet/ip.h>
421256Syl150051 #include <netinet/tcp.h>
433115Syl150051 #include <netinet/udp.h>
441256Syl150051 
452311Sseb #define	XGELL_MAX_FRAME_SIZE(hldev)	((hldev)->config.mtu +	\
461256Syl150051     sizeof (struct ether_vlan_header))
471256Syl150051 
481256Syl150051 #define	HEADROOM		2	/* for DIX-only packets */
491256Syl150051 
501256Syl150051 void header_free_func(void *arg) { }
511256Syl150051 frtn_t header_frtn = {header_free_func, NULL};
521256Syl150051 
531256Syl150051 /* DMA attributes used for Tx side */
541256Syl150051 static struct ddi_dma_attr tx_dma_attr = {
551256Syl150051 	DMA_ATTR_V0,			/* dma_attr_version */
561256Syl150051 	0x0ULL,				/* dma_attr_addr_lo */
571256Syl150051 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_addr_hi */
58*6937Sxw161283 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_count_max */
59*6937Sxw161283 #if defined(__sparc)
60*6937Sxw161283 	0x2000,				/* dma_attr_align */
61*6937Sxw161283 #else
62*6937Sxw161283 	0x1000,				/* dma_attr_align */
63*6937Sxw161283 #endif
64*6937Sxw161283 	0xFC00FC,			/* dma_attr_burstsizes */
65*6937Sxw161283 	0x1,				/* dma_attr_minxfer */
66*6937Sxw161283 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_maxxfer */
671256Syl150051 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_seg */
683115Syl150051 	18,				/* dma_attr_sgllen */
69*6937Sxw161283 	(unsigned int)1,		/* dma_attr_granular */
701256Syl150051 	0				/* dma_attr_flags */
711256Syl150051 };
721256Syl150051 
731256Syl150051 /*
741256Syl150051  * DMA attributes used when using ddi_dma_mem_alloc to
751256Syl150051  * allocat HAL descriptors and Rx buffers during replenish
761256Syl150051  */
771256Syl150051 static struct ddi_dma_attr hal_dma_attr = {
781256Syl150051 	DMA_ATTR_V0,			/* dma_attr_version */
791256Syl150051 	0x0ULL,				/* dma_attr_addr_lo */
801256Syl150051 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_addr_hi */
81*6937Sxw161283 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_count_max */
82*6937Sxw161283 #if defined(__sparc)
83*6937Sxw161283 	0x2000,				/* dma_attr_align */
84*6937Sxw161283 #else
85*6937Sxw161283 	0x1000,				/* dma_attr_align */
86*6937Sxw161283 #endif
87*6937Sxw161283 	0xFC00FC,			/* dma_attr_burstsizes */
88*6937Sxw161283 	0x1,				/* dma_attr_minxfer */
89*6937Sxw161283 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_maxxfer */
901256Syl150051 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_seg */
911256Syl150051 	1,				/* dma_attr_sgllen */
92*6937Sxw161283 	(unsigned int)1,		/* dma_attr_sgllen */
93*6937Sxw161283 	DDI_DMA_RELAXED_ORDERING	/* dma_attr_flags */
941256Syl150051 };
951256Syl150051 
961256Syl150051 struct ddi_dma_attr *p_hal_dma_attr = &hal_dma_attr;
971256Syl150051 
982311Sseb static int		xgell_m_stat(void *, uint_t, uint64_t *);
992311Sseb static int		xgell_m_start(void *);
1002311Sseb static void		xgell_m_stop(void *);
1012311Sseb static int		xgell_m_promisc(void *, boolean_t);
1022311Sseb static int		xgell_m_multicst(void *, boolean_t, const uint8_t *);
1032311Sseb static int		xgell_m_unicst(void *, const uint8_t *);
1042311Sseb static void		xgell_m_ioctl(void *, queue_t *, mblk_t *);
1052311Sseb static mblk_t 		*xgell_m_tx(void *, mblk_t *);
1062311Sseb static boolean_t	xgell_m_getcapab(void *, mac_capab_t, void *);
1072311Sseb 
1082311Sseb #define	XGELL_M_CALLBACK_FLAGS	(MC_IOCTL | MC_GETCAPAB)
1092311Sseb 
1102311Sseb static mac_callbacks_t xgell_m_callbacks = {
1112311Sseb 	XGELL_M_CALLBACK_FLAGS,
1122311Sseb 	xgell_m_stat,
1132311Sseb 	xgell_m_start,
1142311Sseb 	xgell_m_stop,
1152311Sseb 	xgell_m_promisc,
1162311Sseb 	xgell_m_multicst,
1172311Sseb 	xgell_m_unicst,
1182311Sseb 	xgell_m_tx,
1192311Sseb 	NULL,
1202311Sseb 	xgell_m_ioctl,
1212311Sseb 	xgell_m_getcapab
1222311Sseb };
1232311Sseb 
1241256Syl150051 /*
1251256Syl150051  * xge_device_poll
1261256Syl150051  *
1271256Syl150051  * Cyclic should call me every 1s. xge_callback_event_queued should call me
1281256Syl150051  * when HAL hope event was rescheduled.
1291256Syl150051  */
1301256Syl150051 /*ARGSUSED*/
1311256Syl150051 void
1321256Syl150051 xge_device_poll(void *data)
1331256Syl150051 {
1341256Syl150051 	xgelldev_t *lldev = xge_hal_device_private(data);
1351256Syl150051 
1361256Syl150051 	mutex_enter(&lldev->genlock);
1371256Syl150051 	if (lldev->is_initialized) {
1381256Syl150051 		xge_hal_device_poll(data);
1391256Syl150051 		lldev->timeout_id = timeout(xge_device_poll, data,
1401256Syl150051 		    XGE_DEV_POLL_TICKS);
1413115Syl150051 	} else if (lldev->in_reset == 1) {
1423115Syl150051 		lldev->timeout_id = timeout(xge_device_poll, data,
1433115Syl150051 		    XGE_DEV_POLL_TICKS);
1443115Syl150051 	} else {
1453115Syl150051 		lldev->timeout_id = 0;
1461256Syl150051 	}
1471256Syl150051 	mutex_exit(&lldev->genlock);
1481256Syl150051 }
1491256Syl150051 
1501256Syl150051 /*
1511256Syl150051  * xge_device_poll_now
1521256Syl150051  *
1531256Syl150051  * Will call xge_device_poll() immediately
1541256Syl150051  */
1551256Syl150051 void
1561256Syl150051 xge_device_poll_now(void *data)
1571256Syl150051 {
1581256Syl150051 	xgelldev_t *lldev = xge_hal_device_private(data);
1591256Syl150051 
1601256Syl150051 	mutex_enter(&lldev->genlock);
1613115Syl150051 	if (lldev->is_initialized) {
1623115Syl150051 		xge_hal_device_poll(data);
1633115Syl150051 	}
1641256Syl150051 	mutex_exit(&lldev->genlock);
1651256Syl150051 }
1661256Syl150051 
1671256Syl150051 /*
1681256Syl150051  * xgell_callback_link_up
1691256Syl150051  *
1701256Syl150051  * This function called by HAL to notify HW link up state change.
1711256Syl150051  */
1721256Syl150051 void
1731256Syl150051 xgell_callback_link_up(void *userdata)
1741256Syl150051 {
1751256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)userdata;
1761256Syl150051 
1772311Sseb 	mac_link_update(lldev->mh, LINK_STATE_UP);
1781256Syl150051 }
1791256Syl150051 
1801256Syl150051 /*
1811256Syl150051  * xgell_callback_link_down
1821256Syl150051  *
1831256Syl150051  * This function called by HAL to notify HW link down state change.
1841256Syl150051  */
1851256Syl150051 void
1861256Syl150051 xgell_callback_link_down(void *userdata)
1871256Syl150051 {
1881256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)userdata;
1891256Syl150051 
1902311Sseb 	mac_link_update(lldev->mh, LINK_STATE_DOWN);
1911256Syl150051 }
1921256Syl150051 
1931256Syl150051 /*
1941256Syl150051  * xgell_rx_buffer_replenish_all
1951256Syl150051  *
1961256Syl150051  * To replenish all freed dtr(s) with buffers in free pool. It's called by
1971256Syl150051  * xgell_rx_buffer_recycle() or xgell_rx_1b_compl().
1981256Syl150051  * Must be called with pool_lock held.
1991256Syl150051  */
2001256Syl150051 static void
201*6937Sxw161283 xgell_rx_buffer_replenish_all(xgell_ring_t *ring)
2021256Syl150051 {
2031256Syl150051 	xge_hal_dtr_h dtr;
2041256Syl150051 	xgell_rx_buffer_t *rx_buffer;
2051256Syl150051 	xgell_rxd_priv_t *rxd_priv;
2061256Syl150051 
207*6937Sxw161283 	xge_assert(mutex_owned(&ring->bf_pool.pool_lock));
2083115Syl150051 
209*6937Sxw161283 	while ((ring->bf_pool.free > 0) &&
210*6937Sxw161283 	    (xge_hal_ring_dtr_reserve(ring->channelh, &dtr) ==
2111256Syl150051 	    XGE_HAL_OK)) {
212*6937Sxw161283 		rx_buffer = ring->bf_pool.head;
213*6937Sxw161283 		ring->bf_pool.head = rx_buffer->next;
214*6937Sxw161283 		ring->bf_pool.free--;
2151256Syl150051 
2161256Syl150051 		xge_assert(rx_buffer);
2171256Syl150051 		xge_assert(rx_buffer->dma_addr);
2181256Syl150051 
2191256Syl150051 		rxd_priv = (xgell_rxd_priv_t *)
220*6937Sxw161283 		    xge_hal_ring_dtr_private(ring->channelh, dtr);
2211256Syl150051 		xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr,
222*6937Sxw161283 		    ring->bf_pool.size);
2231256Syl150051 
2241256Syl150051 		rxd_priv->rx_buffer = rx_buffer;
225*6937Sxw161283 		xge_hal_ring_dtr_post(ring->channelh, dtr);
2261256Syl150051 	}
2271256Syl150051 }
2281256Syl150051 
2291256Syl150051 /*
2301256Syl150051  * xgell_rx_buffer_release
2311256Syl150051  *
2321256Syl150051  * The only thing done here is to put the buffer back to the pool.
2333115Syl150051  * Calling this function need be protected by mutex, bf_pool.pool_lock.
2341256Syl150051  */
2351256Syl150051 static void
2361256Syl150051 xgell_rx_buffer_release(xgell_rx_buffer_t *rx_buffer)
2371256Syl150051 {
238*6937Sxw161283 	xgell_ring_t *ring = rx_buffer->ring;
2391256Syl150051 
240*6937Sxw161283 	xge_assert(mutex_owned(&ring->bf_pool.pool_lock));
2411256Syl150051 
2421256Syl150051 	/* Put the buffer back to pool */
243*6937Sxw161283 	rx_buffer->next = ring->bf_pool.head;
244*6937Sxw161283 	ring->bf_pool.head = rx_buffer;
2451256Syl150051 
246*6937Sxw161283 	ring->bf_pool.free++;
2471256Syl150051 }
2481256Syl150051 
2491256Syl150051 /*
2501256Syl150051  * xgell_rx_buffer_recycle
2511256Syl150051  *
2521256Syl150051  * Called by desballoc() to "free" the resource.
2531256Syl150051  * We will try to replenish all descripters.
2541256Syl150051  */
255*6937Sxw161283 
256*6937Sxw161283 /*
257*6937Sxw161283  * Previously there were much lock contention between xgell_rx_1b_compl() and
258*6937Sxw161283  * xgell_rx_buffer_recycle(), which consumed a lot of CPU resources and had bad
259*6937Sxw161283  * effect on rx performance. A separate recycle list is introduced to overcome
260*6937Sxw161283  * this. The recycle list is used to record the rx buffer that has been recycled
261*6937Sxw161283  * and these buffers will be retuned back to the free list in bulk instead of
262*6937Sxw161283  * one-by-one.
263*6937Sxw161283  */
264*6937Sxw161283 
2651256Syl150051 static void
2661256Syl150051 xgell_rx_buffer_recycle(char *arg)
2671256Syl150051 {
2681256Syl150051 	xgell_rx_buffer_t *rx_buffer = (xgell_rx_buffer_t *)arg;
269*6937Sxw161283 	xgell_ring_t *ring = rx_buffer->ring;
270*6937Sxw161283 	xgelldev_t *lldev = ring->lldev;
271*6937Sxw161283 	xgell_rx_buffer_pool_t *bf_pool = &ring->bf_pool;
272*6937Sxw161283 
273*6937Sxw161283 	mutex_enter(&bf_pool->recycle_lock);
2741256Syl150051 
275*6937Sxw161283 	rx_buffer->next = bf_pool->recycle_head;
276*6937Sxw161283 	bf_pool->recycle_head = rx_buffer;
277*6937Sxw161283 	if (bf_pool->recycle_tail == NULL)
278*6937Sxw161283 		bf_pool->recycle_tail = rx_buffer;
279*6937Sxw161283 	bf_pool->recycle++;
2801256Syl150051 
2811256Syl150051 	/*
2821256Syl150051 	 * Before finding a good way to set this hiwat, just always call to
2831256Syl150051 	 * replenish_all. *TODO*
2841256Syl150051 	 */
285*6937Sxw161283 	if ((lldev->is_initialized != 0) &&
286*6937Sxw161283 	    (bf_pool->recycle >= XGELL_RX_BUFFER_RECYCLE_CACHE)) {
287*6937Sxw161283 		if (mutex_tryenter(&bf_pool->pool_lock)) {
288*6937Sxw161283 			bf_pool->recycle_tail->next = bf_pool->head;
289*6937Sxw161283 			bf_pool->head = bf_pool->recycle_head;
290*6937Sxw161283 			bf_pool->recycle_head = bf_pool->recycle_tail = NULL;
291*6937Sxw161283 			bf_pool->post -= bf_pool->recycle;
292*6937Sxw161283 			bf_pool->free += bf_pool->recycle;
293*6937Sxw161283 			bf_pool->recycle = 0;
294*6937Sxw161283 			xgell_rx_buffer_replenish_all(ring);
295*6937Sxw161283 			mutex_exit(&bf_pool->pool_lock);
296*6937Sxw161283 		}
2971256Syl150051 	}
2981256Syl150051 
299*6937Sxw161283 	mutex_exit(&bf_pool->recycle_lock);
3001256Syl150051 }
3011256Syl150051 
3021256Syl150051 /*
3031256Syl150051  * xgell_rx_buffer_alloc
3041256Syl150051  *
3051256Syl150051  * Allocate one rx buffer and return with the pointer to the buffer.
3061256Syl150051  * Return NULL if failed.
3071256Syl150051  */
3081256Syl150051 static xgell_rx_buffer_t *
309*6937Sxw161283 xgell_rx_buffer_alloc(xgell_ring_t *ring)
3101256Syl150051 {
3111256Syl150051 	xge_hal_device_t *hldev;
3121256Syl150051 	void *vaddr;
3131256Syl150051 	ddi_dma_handle_t dma_handle;
3141256Syl150051 	ddi_acc_handle_t dma_acch;
3151256Syl150051 	dma_addr_t dma_addr;
3161256Syl150051 	uint_t ncookies;
3171256Syl150051 	ddi_dma_cookie_t dma_cookie;
3181256Syl150051 	size_t real_size;
3191256Syl150051 	extern ddi_device_acc_attr_t *p_xge_dev_attr;
3201256Syl150051 	xgell_rx_buffer_t *rx_buffer;
321*6937Sxw161283 	xgelldev_t *lldev = ring->lldev;
3221256Syl150051 
3233115Syl150051 	hldev = (xge_hal_device_t *)lldev->devh;
3241256Syl150051 
3251256Syl150051 	if (ddi_dma_alloc_handle(hldev->pdev, p_hal_dma_attr, DDI_DMA_SLEEP,
3261256Syl150051 	    0, &dma_handle) != DDI_SUCCESS) {
3271256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA handle",
3281256Syl150051 		    XGELL_IFNAME, lldev->instance);
3291256Syl150051 		goto handle_failed;
3301256Syl150051 	}
3311256Syl150051 
3321256Syl150051 	/* reserve some space at the end of the buffer for recycling */
333*6937Sxw161283 	if (ddi_dma_mem_alloc(dma_handle, HEADROOM + ring->bf_pool.size +
3341256Syl150051 	    sizeof (xgell_rx_buffer_t), p_xge_dev_attr, DDI_DMA_STREAMING,
3351256Syl150051 	    DDI_DMA_SLEEP, 0, (caddr_t *)&vaddr, &real_size, &dma_acch) !=
3361256Syl150051 	    DDI_SUCCESS) {
3371256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory",
3381256Syl150051 		    XGELL_IFNAME, lldev->instance);
3391256Syl150051 		goto mem_failed;
3401256Syl150051 	}
3411256Syl150051 
342*6937Sxw161283 	if (HEADROOM + ring->bf_pool.size + sizeof (xgell_rx_buffer_t) >
3431256Syl150051 	    real_size) {
3441256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory",
3451256Syl150051 		    XGELL_IFNAME, lldev->instance);
3461256Syl150051 		goto bind_failed;
3471256Syl150051 	}
3481256Syl150051 
3491256Syl150051 	if (ddi_dma_addr_bind_handle(dma_handle, NULL, (char *)vaddr + HEADROOM,
350*6937Sxw161283 	    ring->bf_pool.size, DDI_DMA_READ | DDI_DMA_STREAMING,
3511256Syl150051 	    DDI_DMA_SLEEP, 0, &dma_cookie, &ncookies) != DDI_SUCCESS) {
3521256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: out of mapping for mblk",
3531256Syl150051 		    XGELL_IFNAME, lldev->instance);
3541256Syl150051 		goto bind_failed;
3551256Syl150051 	}
3561256Syl150051 
357*6937Sxw161283 	if (ncookies != 1 || dma_cookie.dmac_size < ring->bf_pool.size) {
3581256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not handle partial DMA",
3591256Syl150051 		    XGELL_IFNAME, lldev->instance);
3601256Syl150051 		goto check_failed;
3611256Syl150051 	}
3621256Syl150051 
3631256Syl150051 	dma_addr = dma_cookie.dmac_laddress;
3641256Syl150051 
3651256Syl150051 	rx_buffer = (xgell_rx_buffer_t *)((char *)vaddr + real_size -
3661256Syl150051 	    sizeof (xgell_rx_buffer_t));
3671256Syl150051 	rx_buffer->next = NULL;
3681256Syl150051 	rx_buffer->vaddr = vaddr;
3691256Syl150051 	rx_buffer->dma_addr = dma_addr;
3701256Syl150051 	rx_buffer->dma_handle = dma_handle;
3711256Syl150051 	rx_buffer->dma_acch = dma_acch;
372*6937Sxw161283 	rx_buffer->ring = ring;
3731256Syl150051 	rx_buffer->frtn.free_func = xgell_rx_buffer_recycle;
3741256Syl150051 	rx_buffer->frtn.free_arg = (void *)rx_buffer;
3751256Syl150051 
3761256Syl150051 	return (rx_buffer);
3771256Syl150051 
3781256Syl150051 check_failed:
3791256Syl150051 	(void) ddi_dma_unbind_handle(dma_handle);
3801256Syl150051 bind_failed:
3811256Syl150051 	XGE_OS_MEMORY_CHECK_FREE(vaddr, 0);
3821256Syl150051 	ddi_dma_mem_free(&dma_acch);
3831256Syl150051 mem_failed:
3841256Syl150051 	ddi_dma_free_handle(&dma_handle);
3851256Syl150051 handle_failed:
3861256Syl150051 
3871256Syl150051 	return (NULL);
3881256Syl150051 }
3891256Syl150051 
3901256Syl150051 /*
3911256Syl150051  * xgell_rx_destroy_buffer_pool
3921256Syl150051  *
3931256Syl150051  * Destroy buffer pool. If there is still any buffer hold by upper layer,
3941256Syl150051  * recorded by bf_pool.post, return DDI_FAILURE to reject to be unloaded.
3951256Syl150051  */
3961256Syl150051 static int
397*6937Sxw161283 xgell_rx_destroy_buffer_pool(xgell_ring_t *ring)
3981256Syl150051 {
3991256Syl150051 	xgell_rx_buffer_t *rx_buffer;
4001256Syl150051 	ddi_dma_handle_t  dma_handle;
4011256Syl150051 	ddi_acc_handle_t  dma_acch;
402*6937Sxw161283 	xgelldev_t *lldev = ring->lldev;
4031256Syl150051 	int i;
4041256Syl150051 
405*6937Sxw161283 	if (ring->bf_pool.recycle > 0) {
406*6937Sxw161283 		ring->bf_pool.recycle_tail->next = ring->bf_pool.head;
407*6937Sxw161283 		ring->bf_pool.head = ring->bf_pool.recycle_head;
408*6937Sxw161283 		ring->bf_pool.recycle_tail =
409*6937Sxw161283 		    ring->bf_pool.recycle_head = NULL;
410*6937Sxw161283 		ring->bf_pool.post -= ring->bf_pool.recycle;
411*6937Sxw161283 		ring->bf_pool.free += ring->bf_pool.recycle;
412*6937Sxw161283 		ring->bf_pool.recycle = 0;
413*6937Sxw161283 	}
414*6937Sxw161283 
4151256Syl150051 	/*
4161256Syl150051 	 * If there is any posted buffer, the driver should reject to be
4171256Syl150051 	 * detached. Need notice upper layer to release them.
4181256Syl150051 	 */
419*6937Sxw161283 	if (ring->bf_pool.post != 0) {
4201256Syl150051 		xge_debug_ll(XGE_ERR,
4211256Syl150051 		    "%s%d has some buffers not be recycled, try later!",
4221256Syl150051 		    XGELL_IFNAME, lldev->instance);
4231256Syl150051 		return (DDI_FAILURE);
4241256Syl150051 	}
4251256Syl150051 
4261256Syl150051 	/*
4271256Syl150051 	 * Relase buffers one by one.
4281256Syl150051 	 */
429*6937Sxw161283 	for (i = ring->bf_pool.total; i > 0; i--) {
430*6937Sxw161283 		rx_buffer = ring->bf_pool.head;
4311256Syl150051 		xge_assert(rx_buffer != NULL);
4321256Syl150051 
433*6937Sxw161283 		ring->bf_pool.head = rx_buffer->next;
4341256Syl150051 
4351256Syl150051 		dma_handle = rx_buffer->dma_handle;
4361256Syl150051 		dma_acch = rx_buffer->dma_acch;
4371256Syl150051 
4381256Syl150051 		if (ddi_dma_unbind_handle(dma_handle) != DDI_SUCCESS) {
439*6937Sxw161283 			xge_debug_ll(XGE_ERR, "%s",
440*6937Sxw161283 			    "failed to unbind DMA handle!");
441*6937Sxw161283 			ring->bf_pool.head = rx_buffer;
4421256Syl150051 			return (DDI_FAILURE);
4431256Syl150051 		}
4441256Syl150051 		ddi_dma_mem_free(&dma_acch);
4451256Syl150051 		ddi_dma_free_handle(&dma_handle);
4461256Syl150051 
447*6937Sxw161283 		ring->bf_pool.total--;
448*6937Sxw161283 		ring->bf_pool.free--;
4491256Syl150051 	}
4501256Syl150051 
451*6937Sxw161283 	mutex_destroy(&ring->bf_pool.recycle_lock);
452*6937Sxw161283 	mutex_destroy(&ring->bf_pool.pool_lock);
4531256Syl150051 	return (DDI_SUCCESS);
4541256Syl150051 }
4551256Syl150051 
4561256Syl150051 /*
4571256Syl150051  * xgell_rx_create_buffer_pool
4581256Syl150051  *
4591256Syl150051  * Initialize RX buffer pool for all RX rings. Refer to rx_buffer_pool_t.
4601256Syl150051  */
4611256Syl150051 static int
462*6937Sxw161283 xgell_rx_create_buffer_pool(xgell_ring_t *ring)
4631256Syl150051 {
4641256Syl150051 	xge_hal_device_t *hldev;
4651256Syl150051 	xgell_rx_buffer_t *rx_buffer;
466*6937Sxw161283 	xgelldev_t *lldev = ring->lldev;
4671256Syl150051 	int i;
4681256Syl150051 
4692311Sseb 	hldev = (xge_hal_device_t *)lldev->devh;
4701256Syl150051 
471*6937Sxw161283 	ring->bf_pool.total = 0;
472*6937Sxw161283 	ring->bf_pool.size = XGELL_MAX_FRAME_SIZE(hldev);
473*6937Sxw161283 	ring->bf_pool.head = NULL;
474*6937Sxw161283 	ring->bf_pool.free = 0;
475*6937Sxw161283 	ring->bf_pool.post = 0;
476*6937Sxw161283 	ring->bf_pool.post_hiwat = lldev->config.rx_buffer_post_hiwat;
477*6937Sxw161283 	ring->bf_pool.recycle = 0;
478*6937Sxw161283 	ring->bf_pool.recycle_head = NULL;
479*6937Sxw161283 	ring->bf_pool.recycle_tail = NULL;
4801256Syl150051 
481*6937Sxw161283 	mutex_init(&ring->bf_pool.pool_lock, NULL, MUTEX_DRIVER,
482*6937Sxw161283 	    DDI_INTR_PRI(hldev->irqh));
483*6937Sxw161283 	mutex_init(&ring->bf_pool.recycle_lock, NULL, MUTEX_DRIVER,
484*6937Sxw161283 	    DDI_INTR_PRI(hldev->irqh));
4851256Syl150051 
4861256Syl150051 	/*
4871256Syl150051 	 * Allocate buffers one by one. If failed, destroy whole pool by
4881256Syl150051 	 * call to xgell_rx_destroy_buffer_pool().
4891256Syl150051 	 */
490*6937Sxw161283 
4911256Syl150051 	for (i = 0; i < lldev->config.rx_buffer_total; i++) {
492*6937Sxw161283 		if ((rx_buffer = xgell_rx_buffer_alloc(ring)) == NULL) {
493*6937Sxw161283 			(void) xgell_rx_destroy_buffer_pool(ring);
4941256Syl150051 			return (DDI_FAILURE);
4951256Syl150051 		}
4961256Syl150051 
497*6937Sxw161283 		rx_buffer->next = ring->bf_pool.head;
498*6937Sxw161283 		ring->bf_pool.head = rx_buffer;
4991256Syl150051 
500*6937Sxw161283 		ring->bf_pool.total++;
501*6937Sxw161283 		ring->bf_pool.free++;
5021256Syl150051 	}
5031256Syl150051 
5041256Syl150051 	return (DDI_SUCCESS);
5051256Syl150051 }
5061256Syl150051 
5071256Syl150051 /*
5081256Syl150051  * xgell_rx_dtr_replenish
5091256Syl150051  *
5101256Syl150051  * Replenish descriptor with rx_buffer in RX buffer pool.
5111256Syl150051  * The dtr should be post right away.
5121256Syl150051  */
5131256Syl150051 xge_hal_status_e
5141256Syl150051 xgell_rx_dtr_replenish(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, int index,
5151256Syl150051     void *userdata, xge_hal_channel_reopen_e reopen)
5161256Syl150051 {
5171256Syl150051 	xgell_ring_t *ring = userdata;
5181256Syl150051 	xgell_rx_buffer_t *rx_buffer;
5191256Syl150051 	xgell_rxd_priv_t *rxd_priv;
5201256Syl150051 
521*6937Sxw161283 	if (ring->bf_pool.head == NULL) {
522*6937Sxw161283 		xge_debug_ll(XGE_ERR, "%s", "no more available rx DMA buffer!");
5231256Syl150051 		return (XGE_HAL_FAIL);
5241256Syl150051 	}
525*6937Sxw161283 	rx_buffer = ring->bf_pool.head;
526*6937Sxw161283 	ring->bf_pool.head = rx_buffer->next;
527*6937Sxw161283 	ring->bf_pool.free--;
5281256Syl150051 
5291256Syl150051 	xge_assert(rx_buffer);
5301256Syl150051 	xge_assert(rx_buffer->dma_addr);
5311256Syl150051 
532*6937Sxw161283 	rxd_priv = (xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtr);
533*6937Sxw161283 	xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr, ring->bf_pool.size);
5341256Syl150051 
5351256Syl150051 	rxd_priv->rx_buffer = rx_buffer;
5361256Syl150051 
5371256Syl150051 	return (XGE_HAL_OK);
5381256Syl150051 }
5391256Syl150051 
5401256Syl150051 /*
5411256Syl150051  * xgell_get_ip_offset
5421256Syl150051  *
5431256Syl150051  * Calculate the offset to IP header.
5441256Syl150051  */
5451256Syl150051 static inline int
5461256Syl150051 xgell_get_ip_offset(xge_hal_dtr_info_t *ext_info)
5471256Syl150051 {
5481256Syl150051 	int ip_off;
5491256Syl150051 
5501256Syl150051 	/* get IP-header offset */
5511256Syl150051 	switch (ext_info->frame) {
5521256Syl150051 	case XGE_HAL_FRAME_TYPE_DIX:
5531256Syl150051 		ip_off = XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE;
5541256Syl150051 		break;
5551256Syl150051 	case XGE_HAL_FRAME_TYPE_IPX:
5561256Syl150051 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
5571256Syl150051 		    XGE_HAL_HEADER_802_2_SIZE +
5581256Syl150051 		    XGE_HAL_HEADER_SNAP_SIZE);
5591256Syl150051 		break;
5601256Syl150051 	case XGE_HAL_FRAME_TYPE_LLC:
5611256Syl150051 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
5621256Syl150051 		    XGE_HAL_HEADER_802_2_SIZE);
5631256Syl150051 		break;
5641256Syl150051 	case XGE_HAL_FRAME_TYPE_SNAP:
5651256Syl150051 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
5661256Syl150051 		    XGE_HAL_HEADER_SNAP_SIZE);
5671256Syl150051 		break;
5681256Syl150051 	default:
5691256Syl150051 		ip_off = 0;
5701256Syl150051 		break;
5711256Syl150051 	}
5721256Syl150051 
5731256Syl150051 	if ((ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4 ||
5741256Syl150051 	    ext_info->proto & XGE_HAL_FRAME_PROTO_IPV6) &&
5751256Syl150051 	    (ext_info->proto & XGE_HAL_FRAME_PROTO_VLAN_TAGGED)) {
5761256Syl150051 		ip_off += XGE_HAL_HEADER_VLAN_SIZE;
5771256Syl150051 	}
5781256Syl150051 
5791256Syl150051 	return (ip_off);
5801256Syl150051 }
5811256Syl150051 
5821256Syl150051 /*
5831256Syl150051  * xgell_rx_hcksum_assoc
5841256Syl150051  *
5851256Syl150051  * Judge the packet type and then call to hcksum_assoc() to associate
5861256Syl150051  * h/w checksum information.
5871256Syl150051  */
5881256Syl150051 static inline void
5891256Syl150051 xgell_rx_hcksum_assoc(mblk_t *mp, char *vaddr, int pkt_length,
5901256Syl150051     xge_hal_dtr_info_t *ext_info)
5911256Syl150051 {
5921256Syl150051 	int cksum_flags = 0;
5931256Syl150051 
5941256Syl150051 	if (!(ext_info->proto & XGE_HAL_FRAME_PROTO_IP_FRAGMENTED)) {
5951256Syl150051 		if (ext_info->proto & XGE_HAL_FRAME_PROTO_TCP_OR_UDP) {
5961256Syl150051 			if (ext_info->l3_cksum == XGE_HAL_L3_CKSUM_OK) {
5971256Syl150051 				cksum_flags |= HCK_IPV4_HDRCKSUM;
5981256Syl150051 			}
5991256Syl150051 			if (ext_info->l4_cksum == XGE_HAL_L4_CKSUM_OK) {
6001256Syl150051 				cksum_flags |= HCK_FULLCKSUM_OK;
6011256Syl150051 			}
6021256Syl150051 			if (cksum_flags) {
6031256Syl150051 				cksum_flags |= HCK_FULLCKSUM;
6041256Syl150051 				(void) hcksum_assoc(mp, NULL, NULL, 0,
6051256Syl150051 				    0, 0, 0, cksum_flags, 0);
6061256Syl150051 			}
6071256Syl150051 		}
6081256Syl150051 	} else if (ext_info->proto &
6091256Syl150051 	    (XGE_HAL_FRAME_PROTO_IPV4 | XGE_HAL_FRAME_PROTO_IPV6)) {
6101256Syl150051 		/*
6111256Syl150051 		 * Just pass the partial cksum up to IP.
6121256Syl150051 		 */
6133115Syl150051 		int ip_off = xgell_get_ip_offset(ext_info);
6141256Syl150051 		int start, end = pkt_length - ip_off;
6151256Syl150051 
6161256Syl150051 		if (ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4) {
6171256Syl150051 			struct ip *ip =
6181256Syl150051 			    (struct ip *)(vaddr + ip_off);
6191256Syl150051 			start = ip->ip_hl * 4 + ip_off;
6201256Syl150051 		} else {
6211256Syl150051 			start = ip_off + 40;
6221256Syl150051 		}
6231256Syl150051 		cksum_flags |= HCK_PARTIALCKSUM;
6241256Syl150051 		(void) hcksum_assoc(mp, NULL, NULL, start, 0,
6251256Syl150051 		    end, ntohs(ext_info->l4_cksum), cksum_flags,
6261256Syl150051 		    0);
6271256Syl150051 	}
6281256Syl150051 }
6291256Syl150051 
6301256Syl150051 /*
6311256Syl150051  * xgell_rx_1b_msg_alloc
6321256Syl150051  *
6331256Syl150051  * Allocate message header for data buffer, and decide if copy the packet to
6341256Syl150051  * new data buffer to release big rx_buffer to save memory.
6351256Syl150051  *
6363115Syl150051  * If the pkt_length <= XGELL_RX_DMA_LOWAT, call allocb() to allocate
6371256Syl150051  * new message and copy the payload in.
6381256Syl150051  */
6391256Syl150051 static mblk_t *
6403115Syl150051 xgell_rx_1b_msg_alloc(xgelldev_t *lldev, xgell_rx_buffer_t *rx_buffer,
6413115Syl150051     int pkt_length, xge_hal_dtr_info_t *ext_info, boolean_t *copyit)
6421256Syl150051 {
6431256Syl150051 	mblk_t *mp;
6441256Syl150051 	char *vaddr;
6451256Syl150051 
6461256Syl150051 	vaddr = (char *)rx_buffer->vaddr + HEADROOM;
6471256Syl150051 	/*
6481256Syl150051 	 * Copy packet into new allocated message buffer, if pkt_length
6493115Syl150051 	 * is less than XGELL_RX_DMA_LOWAT
6501256Syl150051 	 */
6513115Syl150051 	if (*copyit || pkt_length <= lldev->config.rx_dma_lowat) {
652*6937Sxw161283 		if ((mp = allocb(pkt_length + HEADROOM, 0)) == NULL) {
6531256Syl150051 			return (NULL);
6541256Syl150051 		}
655*6937Sxw161283 		mp->b_rptr += HEADROOM;
6561256Syl150051 		bcopy(vaddr, mp->b_rptr, pkt_length);
6571256Syl150051 		mp->b_wptr = mp->b_rptr + pkt_length;
6581256Syl150051 		*copyit = B_TRUE;
6591256Syl150051 		return (mp);
6601256Syl150051 	}
6611256Syl150051 
6621256Syl150051 	/*
6631256Syl150051 	 * Just allocate mblk for current data buffer
6641256Syl150051 	 */
6653392Syl150051 	if ((mp = (mblk_t *)desballoc((unsigned char *)vaddr, pkt_length, 0,
6661256Syl150051 	    &rx_buffer->frtn)) == NULL) {
6671256Syl150051 		/* Drop it */
6681256Syl150051 		return (NULL);
6691256Syl150051 	}
6701256Syl150051 	/*
6713392Syl150051 	 * Adjust the b_rptr/b_wptr in the mblk_t structure.
6721256Syl150051 	 */
6733392Syl150051 	mp->b_wptr += pkt_length;
6741256Syl150051 
6751256Syl150051 	return (mp);
6761256Syl150051 }
6771256Syl150051 
6781256Syl150051 /*
6791256Syl150051  * xgell_rx_1b_compl
6801256Syl150051  *
6811256Syl150051  * If the interrupt is because of a received frame or if the receive ring
6821256Syl150051  * contains fresh as yet un-processed frames, this function is called.
6831256Syl150051  */
6841256Syl150051 static xge_hal_status_e
6851256Syl150051 xgell_rx_1b_compl(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
6861256Syl150051     void *userdata)
6871256Syl150051 {
688*6937Sxw161283 	xgell_ring_t *ring = (xgell_ring_t *)userdata;
689*6937Sxw161283 	xgelldev_t *lldev = ring->lldev;
6901256Syl150051 	xgell_rx_buffer_t *rx_buffer;
6911256Syl150051 	mblk_t *mp_head = NULL;
6921256Syl150051 	mblk_t *mp_end  = NULL;
6933115Syl150051 	int pkt_burst = 0;
6943115Syl150051 
695*6937Sxw161283 	mutex_enter(&ring->bf_pool.pool_lock);
6961256Syl150051 
6971256Syl150051 	do {
6981256Syl150051 		int pkt_length;
6991256Syl150051 		dma_addr_t dma_data;
7001256Syl150051 		mblk_t *mp;
7011256Syl150051 		boolean_t copyit = B_FALSE;
7021256Syl150051 
7031256Syl150051 		xgell_rxd_priv_t *rxd_priv = ((xgell_rxd_priv_t *)
7041256Syl150051 		    xge_hal_ring_dtr_private(channelh, dtr));
7051256Syl150051 		xge_hal_dtr_info_t ext_info;
7061256Syl150051 
7071256Syl150051 		rx_buffer = rxd_priv->rx_buffer;
7081256Syl150051 
7091256Syl150051 		xge_hal_ring_dtr_1b_get(channelh, dtr, &dma_data, &pkt_length);
7101256Syl150051 		xge_hal_ring_dtr_info_get(channelh, dtr, &ext_info);
7111256Syl150051 
7121256Syl150051 		xge_assert(dma_data == rx_buffer->dma_addr);
7131256Syl150051 
7141256Syl150051 		if (t_code != 0) {
7151256Syl150051 			xge_debug_ll(XGE_ERR, "%s%d: rx: dtr 0x%"PRIx64
7161256Syl150051 			    " completed due to error t_code %01x", XGELL_IFNAME,
7171256Syl150051 			    lldev->instance, (uint64_t)(uintptr_t)dtr, t_code);
7181256Syl150051 
7191256Syl150051 			(void) xge_hal_device_handle_tcode(channelh, dtr,
7201256Syl150051 			    t_code);
7211256Syl150051 			xge_hal_ring_dtr_free(channelh, dtr); /* drop it */
7221256Syl150051 			xgell_rx_buffer_release(rx_buffer);
7231256Syl150051 			continue;
7241256Syl150051 		}
7251256Syl150051 
7261256Syl150051 		/*
7271256Syl150051 		 * Sync the DMA memory
7281256Syl150051 		 */
7293115Syl150051 		if (ddi_dma_sync(rx_buffer->dma_handle, 0, pkt_length,
7303115Syl150051 		    DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) {
7311256Syl150051 			xge_debug_ll(XGE_ERR, "%s%d: rx: can not do DMA sync",
7321256Syl150051 			    XGELL_IFNAME, lldev->instance);
7331256Syl150051 			xge_hal_ring_dtr_free(channelh, dtr); /* drop it */
7341256Syl150051 			xgell_rx_buffer_release(rx_buffer);
7351256Syl150051 			continue;
7361256Syl150051 		}
7371256Syl150051 
7381256Syl150051 		/*
7391256Syl150051 		 * Allocate message for the packet.
7401256Syl150051 		 */
741*6937Sxw161283 		if (ring->bf_pool.post > ring->bf_pool.post_hiwat) {
7421256Syl150051 			copyit = B_TRUE;
7431256Syl150051 		} else {
7441256Syl150051 			copyit = B_FALSE;
7451256Syl150051 		}
7461256Syl150051 
7473115Syl150051 		mp = xgell_rx_1b_msg_alloc(lldev, rx_buffer, pkt_length,
7483115Syl150051 		    &ext_info, &copyit);
7491256Syl150051 
7501256Syl150051 		xge_hal_ring_dtr_free(channelh, dtr);
7511256Syl150051 
7521256Syl150051 		/*
7531256Syl150051 		 * Release the buffer and recycle it later
7541256Syl150051 		 */
7551256Syl150051 		if ((mp == NULL) || copyit) {
7561256Syl150051 			xgell_rx_buffer_release(rx_buffer);
7571256Syl150051 		} else {
7581256Syl150051 			/*
7591256Syl150051 			 * Count it since the buffer should be loaned up.
7601256Syl150051 			 */
761*6937Sxw161283 			ring->bf_pool.post++;
7621256Syl150051 		}
7631256Syl150051 		if (mp == NULL) {
7641256Syl150051 			xge_debug_ll(XGE_ERR,
7653115Syl150051 			    "%s%d: rx: can not allocate mp mblk",
7663115Syl150051 			    XGELL_IFNAME, lldev->instance);
7671256Syl150051 			continue;
7681256Syl150051 		}
7691256Syl150051 
7701256Syl150051 		/*
7713115Syl150051 		 * Associate cksum_flags per packet type and h/w
7723115Syl150051 		 * cksum flags.
7731256Syl150051 		 */
7741256Syl150051 		xgell_rx_hcksum_assoc(mp, (char *)rx_buffer->vaddr +
7751256Syl150051 		    HEADROOM, pkt_length, &ext_info);
7761256Syl150051 
7771256Syl150051 		if (mp_head == NULL) {
7781256Syl150051 			mp_head = mp;
7791256Syl150051 			mp_end = mp;
7801256Syl150051 		} else {
7811256Syl150051 			mp_end->b_next = mp;
7821256Syl150051 			mp_end = mp;
7831256Syl150051 		}
7841256Syl150051 
7853115Syl150051 		if (++pkt_burst < lldev->config.rx_pkt_burst)
7863115Syl150051 			continue;
7873115Syl150051 
788*6937Sxw161283 		if (ring->bf_pool.post > ring->bf_pool.post_hiwat) {
7893115Syl150051 			/* Replenish rx buffers */
790*6937Sxw161283 			xgell_rx_buffer_replenish_all(ring);
7913115Syl150051 		}
792*6937Sxw161283 		mutex_exit(&ring->bf_pool.pool_lock);
7933115Syl150051 		if (mp_head != NULL) {
7943115Syl150051 			mac_rx(lldev->mh, ((xgell_ring_t *)userdata)->handle,
7953115Syl150051 			    mp_head);
7963115Syl150051 		}
7973115Syl150051 		mp_head = mp_end  = NULL;
7983115Syl150051 		pkt_burst = 0;
799*6937Sxw161283 		mutex_enter(&ring->bf_pool.pool_lock);
8003115Syl150051 
8011256Syl150051 	} while (xge_hal_ring_dtr_next_completed(channelh, &dtr, &t_code) ==
8021256Syl150051 	    XGE_HAL_OK);
8031256Syl150051 
8041256Syl150051 	/*
8051256Syl150051 	 * Always call replenish_all to recycle rx_buffers.
8061256Syl150051 	 */
807*6937Sxw161283 	xgell_rx_buffer_replenish_all(ring);
808*6937Sxw161283 	mutex_exit(&ring->bf_pool.pool_lock);
8091256Syl150051 
8103115Syl150051 	if (mp_head != NULL) {
8113115Syl150051 		mac_rx(lldev->mh, ((xgell_ring_t *)userdata)->handle, mp_head);
8123115Syl150051 	}
8133115Syl150051 
8141256Syl150051 	return (XGE_HAL_OK);
8151256Syl150051 }
8161256Syl150051 
8171256Syl150051 /*
8181256Syl150051  * xgell_xmit_compl
8191256Syl150051  *
8201256Syl150051  * If an interrupt was raised to indicate DMA complete of the Tx packet,
8211256Syl150051  * this function is called. It identifies the last TxD whose buffer was
8221256Syl150051  * freed and frees all skbs whose data have already DMA'ed into the NICs
8231256Syl150051  * internal memory.
8241256Syl150051  */
8251256Syl150051 static xge_hal_status_e
8261256Syl150051 xgell_xmit_compl(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
8271256Syl150051     void *userdata)
8281256Syl150051 {
829*6937Sxw161283 	xgell_fifo_t *fifo = (xgell_fifo_t *)userdata;
830*6937Sxw161283 	xgelldev_t *lldev = fifo->lldev;
8311256Syl150051 
8321256Syl150051 	do {
8331256Syl150051 		xgell_txd_priv_t *txd_priv = ((xgell_txd_priv_t *)
8341256Syl150051 		    xge_hal_fifo_dtr_private(dtr));
8351256Syl150051 		int i;
8361256Syl150051 
8371256Syl150051 		if (t_code) {
8381256Syl150051 			xge_debug_ll(XGE_TRACE, "%s%d: tx: dtr 0x%"PRIx64
8391256Syl150051 			    " completed due to error t_code %01x", XGELL_IFNAME,
8401256Syl150051 			    lldev->instance, (uint64_t)(uintptr_t)dtr, t_code);
8411256Syl150051 
8421256Syl150051 			(void) xge_hal_device_handle_tcode(channelh, dtr,
8431256Syl150051 			    t_code);
8441256Syl150051 		}
8451256Syl150051 
8461256Syl150051 		for (i = 0; i < txd_priv->handle_cnt; i++) {
847*6937Sxw161283 			if (txd_priv->dma_handles[i] != NULL) {
848*6937Sxw161283 				xge_assert(txd_priv->dma_handles[i]);
849*6937Sxw161283 				(void) ddi_dma_unbind_handle(
850*6937Sxw161283 				    txd_priv->dma_handles[i]);
851*6937Sxw161283 				ddi_dma_free_handle(&txd_priv->dma_handles[i]);
852*6937Sxw161283 				txd_priv->dma_handles[i] = 0;
853*6937Sxw161283 			}
8541256Syl150051 		}
855*6937Sxw161283 		txd_priv->handle_cnt = 0;
8561256Syl150051 
8571256Syl150051 		xge_hal_fifo_dtr_free(channelh, dtr);
8581256Syl150051 
859*6937Sxw161283 		if (txd_priv->mblk != NULL) {
860*6937Sxw161283 			freemsg(txd_priv->mblk);
861*6937Sxw161283 			txd_priv->mblk = NULL;
862*6937Sxw161283 		}
863*6937Sxw161283 
8641256Syl150051 		lldev->resched_avail++;
8651256Syl150051 
8661256Syl150051 	} while (xge_hal_fifo_dtr_next_completed(channelh, &dtr, &t_code) ==
8671256Syl150051 	    XGE_HAL_OK);
8681256Syl150051 
8691256Syl150051 	if (lldev->resched_retry &&
8701256Syl150051 	    xge_queue_produce_context(xge_hal_device_queue(lldev->devh),
871*6937Sxw161283 	    XGELL_EVENT_RESCHED_NEEDED, fifo) == XGE_QUEUE_OK) {
872*6937Sxw161283 		xge_debug_ll(XGE_TRACE, "%s%d: IRQ produced event for queue %d",
873*6937Sxw161283 		    XGELL_IFNAME, lldev->instance,
874*6937Sxw161283 		    ((xge_hal_channel_t *)channelh)->post_qid);
8751256Syl150051 		lldev->resched_send = lldev->resched_avail;
8761256Syl150051 		lldev->resched_retry = 0;
8771256Syl150051 	}
8781256Syl150051 
8791256Syl150051 	return (XGE_HAL_OK);
8801256Syl150051 }
8811256Syl150051 
8821256Syl150051 /*
8831256Syl150051  * xgell_send
8843115Syl150051  * @hldev: pointer to xge_hal_device_t strucutre
8851256Syl150051  * @mblk: pointer to network buffer, i.e. mblk_t structure
8861256Syl150051  *
8871256Syl150051  * Called by the xgell_m_tx to transmit the packet to the XFRAME firmware.
8881256Syl150051  * A pointer to an M_DATA message that contains the packet is passed to
8891256Syl150051  * this routine.
8901256Syl150051  */
8911256Syl150051 static boolean_t
8923115Syl150051 xgell_send(xgelldev_t *lldev, mblk_t *mp)
8931256Syl150051 {
8941256Syl150051 	mblk_t *bp;
8953115Syl150051 	boolean_t retry;
8963115Syl150051 	xge_hal_device_t *hldev = lldev->devh;
8971256Syl150051 	xge_hal_status_e status;
8981256Syl150051 	xge_hal_dtr_h dtr;
8991256Syl150051 	xgell_txd_priv_t *txd_priv;
9003115Syl150051 	uint32_t hckflags;
9013115Syl150051 	uint32_t mss;
9023115Syl150051 	int handle_cnt, frag_cnt, ret, i, copied;
9033115Syl150051 	boolean_t used_copy;
904*6937Sxw161283 	xgell_fifo_t *fifo;
905*6937Sxw161283 	xge_hal_channel_h fifo_channel;
9061256Syl150051 
9071256Syl150051 _begin:
9083115Syl150051 	retry = B_FALSE;
9091256Syl150051 	handle_cnt = frag_cnt = 0;
9101256Syl150051 
9111256Syl150051 	if (!lldev->is_initialized || lldev->in_reset)
9121256Syl150051 		return (B_FALSE);
9131256Syl150051 
914*6937Sxw161283 	fifo = &lldev->fifos[0];
915*6937Sxw161283 	fifo_channel = fifo->channelh;
916*6937Sxw161283 
9171256Syl150051 	/*
9181256Syl150051 	 * If the free Tx dtrs count reaches the lower threshold,
9191256Syl150051 	 * inform the gld to stop sending more packets till the free
9201256Syl150051 	 * dtrs count exceeds higher threshold. Driver informs the
9211256Syl150051 	 * gld through gld_sched call, when the free dtrs count exceeds
9221256Syl150051 	 * the higher threshold.
9231256Syl150051 	 */
924*6937Sxw161283 	if (xge_hal_channel_dtr_count(fifo_channel)
9251256Syl150051 	    <= XGELL_TX_LEVEL_LOW) {
926*6937Sxw161283 		if (++fifo->level_low > XGELL_TX_LEVEL_CHECK) {
927*6937Sxw161283 			xge_debug_ll(XGE_TRACE, "%s%d: queue %d: err on xmit,"
928*6937Sxw161283 			    "free descriptors count at low threshold %d",
929*6937Sxw161283 			    XGELL_IFNAME, lldev->instance,
930*6937Sxw161283 			    ((xge_hal_channel_t *)fifo_channel)->post_qid,
931*6937Sxw161283 			    XGELL_TX_LEVEL_LOW);
932*6937Sxw161283 			fifo->level_low = 0;
933*6937Sxw161283 			retry = B_TRUE;
934*6937Sxw161283 			goto _exit;
935*6937Sxw161283 		}
936*6937Sxw161283 	} else {
937*6937Sxw161283 		fifo->level_low = 0;
9381256Syl150051 	}
9391256Syl150051 
940*6937Sxw161283 	status = xge_hal_fifo_dtr_reserve(fifo_channel, &dtr);
9411256Syl150051 	if (status != XGE_HAL_OK) {
9421256Syl150051 		switch (status) {
9431256Syl150051 		case XGE_HAL_INF_CHANNEL_IS_NOT_READY:
9441256Syl150051 			xge_debug_ll(XGE_ERR,
9451256Syl150051 			    "%s%d: channel %d is not ready.", XGELL_IFNAME,
9461256Syl150051 			    lldev->instance,
9471256Syl150051 			    ((xge_hal_channel_t *)
948*6937Sxw161283 			    fifo_channel)->post_qid);
9493115Syl150051 			retry = B_TRUE;
9501256Syl150051 			goto _exit;
9511256Syl150051 		case XGE_HAL_INF_OUT_OF_DESCRIPTORS:
9521256Syl150051 			xge_debug_ll(XGE_TRACE, "%s%d: queue %d: error in xmit,"
9531256Syl150051 			    " out of descriptors.", XGELL_IFNAME,
9541256Syl150051 			    lldev->instance,
9551256Syl150051 			    ((xge_hal_channel_t *)
956*6937Sxw161283 			    fifo_channel)->post_qid);
9573115Syl150051 			retry = B_TRUE;
9581256Syl150051 			goto _exit;
9591256Syl150051 		default:
9601256Syl150051 			return (B_FALSE);
9611256Syl150051 		}
9621256Syl150051 	}
9631256Syl150051 
9641256Syl150051 	txd_priv = xge_hal_fifo_dtr_private(dtr);
9651256Syl150051 	txd_priv->mblk = mp;
9661256Syl150051 
9671256Syl150051 	/*
9681256Syl150051 	 * VLAN tag should be passed down along with MAC header, so h/w needn't
9691256Syl150051 	 * do insertion.
9701256Syl150051 	 *
9711256Syl150051 	 * For NIC driver that has to strip and re-insert VLAN tag, the example
9721256Syl150051 	 * is the other implementation for xge. The driver can simple bcopy()
9731256Syl150051 	 * ether_vlan_header to overwrite VLAN tag and let h/w insert the tag
9741256Syl150051 	 * automatically, since it's impossible that GLD sends down mp(s) with
9751256Syl150051 	 * splited ether_vlan_header.
9761256Syl150051 	 *
9771256Syl150051 	 * struct ether_vlan_header *evhp;
9781256Syl150051 	 * uint16_t tci;
9791256Syl150051 	 *
9801256Syl150051 	 * evhp = (struct ether_vlan_header *)mp->b_rptr;
9811256Syl150051 	 * if (evhp->ether_tpid == htons(VLAN_TPID)) {
9823115Syl150051 	 *	tci = ntohs(evhp->ether_tci);
9833115Syl150051 	 *	(void) bcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ,
9841256Syl150051 	 *	    2 * ETHERADDRL);
9853115Syl150051 	 *	mp->b_rptr += VLAN_TAGSZ;
9861256Syl150051 	 *
9873115Syl150051 	 *	xge_hal_fifo_dtr_vlan_set(dtr, tci);
9881256Syl150051 	 * }
9891256Syl150051 	 */
9901256Syl150051 
9913115Syl150051 	copied = 0;
9923115Syl150051 	used_copy = B_FALSE;
9931256Syl150051 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
9941256Syl150051 		int mblen;
9951256Syl150051 		uint_t ncookies;
9961256Syl150051 		ddi_dma_cookie_t dma_cookie;
9971256Syl150051 		ddi_dma_handle_t dma_handle;
9981256Syl150051 
9991256Syl150051 		/* skip zero-length message blocks */
10001256Syl150051 		mblen = MBLKL(bp);
10011256Syl150051 		if (mblen == 0) {
10021256Syl150051 			continue;
10031256Syl150051 		}
10041256Syl150051 
10053115Syl150051 		/*
10063115Syl150051 		 * Check the message length to decide to DMA or bcopy() data
10073115Syl150051 		 * to tx descriptor(s).
10083115Syl150051 		 */
10093115Syl150051 		if (mblen < lldev->config.tx_dma_lowat &&
10103115Syl150051 		    (copied + mblen) < lldev->tx_copied_max) {
10113115Syl150051 			xge_hal_status_e rc;
1012*6937Sxw161283 			rc = xge_hal_fifo_dtr_buffer_append(fifo_channel,
10133115Syl150051 			    dtr, bp->b_rptr, mblen);
10143115Syl150051 			if (rc == XGE_HAL_OK) {
10153115Syl150051 				used_copy = B_TRUE;
10163115Syl150051 				copied += mblen;
10173115Syl150051 				continue;
10183115Syl150051 			} else if (used_copy) {
10193115Syl150051 				xge_hal_fifo_dtr_buffer_finalize(
1020*6937Sxw161283 				    fifo_channel, dtr, frag_cnt++);
10213115Syl150051 				used_copy = B_FALSE;
10223115Syl150051 			}
10233115Syl150051 		} else if (used_copy) {
1024*6937Sxw161283 			xge_hal_fifo_dtr_buffer_finalize(fifo_channel,
10253115Syl150051 			    dtr, frag_cnt++);
10263115Syl150051 			used_copy = B_FALSE;
10273115Syl150051 		}
10283115Syl150051 
10292311Sseb 		ret = ddi_dma_alloc_handle(lldev->dev_info, &tx_dma_attr,
10301256Syl150051 		    DDI_DMA_DONTWAIT, 0, &dma_handle);
10311256Syl150051 		if (ret != DDI_SUCCESS) {
10321256Syl150051 			xge_debug_ll(XGE_ERR,
10333115Syl150051 			    "%s%d: can not allocate dma handle", XGELL_IFNAME,
10343115Syl150051 			    lldev->instance);
10351256Syl150051 			goto _exit_cleanup;
10361256Syl150051 		}
10371256Syl150051 
10381256Syl150051 		ret = ddi_dma_addr_bind_handle(dma_handle, NULL,
10391256Syl150051 		    (caddr_t)bp->b_rptr, mblen,
10401256Syl150051 		    DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
10411256Syl150051 		    &dma_cookie, &ncookies);
10421256Syl150051 
10431256Syl150051 		switch (ret) {
10441256Syl150051 		case DDI_DMA_MAPPED:
10451256Syl150051 			/* everything's fine */
10461256Syl150051 			break;
10471256Syl150051 
10481256Syl150051 		case DDI_DMA_NORESOURCES:
10491256Syl150051 			xge_debug_ll(XGE_ERR,
10501256Syl150051 			    "%s%d: can not bind dma address",
10511256Syl150051 			    XGELL_IFNAME, lldev->instance);
10521256Syl150051 			ddi_dma_free_handle(&dma_handle);
10531256Syl150051 			goto _exit_cleanup;
10541256Syl150051 
10551256Syl150051 		case DDI_DMA_NOMAPPING:
10561256Syl150051 		case DDI_DMA_INUSE:
10571256Syl150051 		case DDI_DMA_TOOBIG:
10581256Syl150051 		default:
10591256Syl150051 			/* drop packet, don't retry */
10601256Syl150051 			xge_debug_ll(XGE_ERR,
10611256Syl150051 			    "%s%d: can not map message buffer",
10621256Syl150051 			    XGELL_IFNAME, lldev->instance);
10631256Syl150051 			ddi_dma_free_handle(&dma_handle);
10641256Syl150051 			goto _exit_cleanup;
10651256Syl150051 		}
10661256Syl150051 
10673115Syl150051 		if (ncookies + frag_cnt > hldev->config.fifo.max_frags) {
10681256Syl150051 			xge_debug_ll(XGE_ERR, "%s%d: too many fragments, "
10691256Syl150051 			    "requested c:%d+f:%d", XGELL_IFNAME,
10701256Syl150051 			    lldev->instance, ncookies, frag_cnt);
10711256Syl150051 			(void) ddi_dma_unbind_handle(dma_handle);
10721256Syl150051 			ddi_dma_free_handle(&dma_handle);
10731256Syl150051 			goto _exit_cleanup;
10741256Syl150051 		}
10751256Syl150051 
10761256Syl150051 		/* setup the descriptors for this data buffer */
10771256Syl150051 		while (ncookies) {
1078*6937Sxw161283 			xge_hal_fifo_dtr_buffer_set(fifo_channel, dtr,
10791256Syl150051 			    frag_cnt++, dma_cookie.dmac_laddress,
10801256Syl150051 			    dma_cookie.dmac_size);
10811256Syl150051 			if (--ncookies) {
10821256Syl150051 				ddi_dma_nextcookie(dma_handle, &dma_cookie);
10831256Syl150051 			}
10841256Syl150051 
10851256Syl150051 		}
10861256Syl150051 
10871256Syl150051 		txd_priv->dma_handles[handle_cnt++] = dma_handle;
10881256Syl150051 
10891256Syl150051 		if (bp->b_cont &&
10901256Syl150051 		    (frag_cnt + XGE_HAL_DEFAULT_FIFO_FRAGS_THRESHOLD >=
1091*6937Sxw161283 		    hldev->config.fifo.max_frags)) {
10921256Syl150051 			mblk_t *nmp;
10931256Syl150051 
10941256Syl150051 			xge_debug_ll(XGE_TRACE,
10951256Syl150051 			    "too many FRAGs [%d], pull up them", frag_cnt);
10961256Syl150051 
10971256Syl150051 			if ((nmp = msgpullup(bp->b_cont, -1)) == NULL) {
10981256Syl150051 				/* Drop packet, don't retry */
10991256Syl150051 				xge_debug_ll(XGE_ERR,
11001256Syl150051 				    "%s%d: can not pullup message buffer",
11011256Syl150051 				    XGELL_IFNAME, lldev->instance);
11021256Syl150051 				goto _exit_cleanup;
11031256Syl150051 			}
11041256Syl150051 			freemsg(bp->b_cont);
11051256Syl150051 			bp->b_cont = nmp;
11061256Syl150051 		}
11071256Syl150051 	}
11081256Syl150051 
11093115Syl150051 	/* finalize unfinished copies */
11103115Syl150051 	if (used_copy) {
1111*6937Sxw161283 		xge_hal_fifo_dtr_buffer_finalize(fifo_channel, dtr,
11123115Syl150051 		    frag_cnt++);
11133115Syl150051 	}
11143115Syl150051 
11151256Syl150051 	txd_priv->handle_cnt = handle_cnt;
11161256Syl150051 
11173115Syl150051 	/*
11183115Syl150051 	 * If LSO is required, just call xge_hal_fifo_dtr_mss_set(dtr, mss) to
11193115Syl150051 	 * do all necessary work.
11203115Syl150051 	 */
11213115Syl150051 	hcksum_retrieve(mp, NULL, NULL, NULL, NULL, NULL, &mss, &hckflags);
11223115Syl150051 	if ((hckflags & HW_LSO) && (mss != 0)) {
11233115Syl150051 		xge_hal_fifo_dtr_mss_set(dtr, mss);
11243115Syl150051 	}
11253115Syl150051 
11263115Syl150051 	if (hckflags & HCK_IPV4_HDRCKSUM) {
11271256Syl150051 		xge_hal_fifo_dtr_cksum_set_bits(dtr,
11281256Syl150051 		    XGE_HAL_TXD_TX_CKO_IPV4_EN);
11291256Syl150051 	}
11303115Syl150051 	if (hckflags & HCK_FULLCKSUM) {
11311256Syl150051 		xge_hal_fifo_dtr_cksum_set_bits(dtr, XGE_HAL_TXD_TX_CKO_TCP_EN |
11321256Syl150051 		    XGE_HAL_TXD_TX_CKO_UDP_EN);
11331256Syl150051 	}
11341256Syl150051 
1135*6937Sxw161283 	xge_hal_fifo_dtr_post(fifo_channel, dtr);
11361256Syl150051 
11371256Syl150051 	return (B_TRUE);
11381256Syl150051 
11391256Syl150051 _exit_cleanup:
11401256Syl150051 
11411256Syl150051 	for (i = 0; i < handle_cnt; i++) {
11421256Syl150051 		(void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]);
11431256Syl150051 		ddi_dma_free_handle(&txd_priv->dma_handles[i]);
11441256Syl150051 		txd_priv->dma_handles[i] = 0;
11451256Syl150051 	}
11461256Syl150051 
1147*6937Sxw161283 	xge_hal_fifo_dtr_free(fifo_channel, dtr);
11481256Syl150051 
11491256Syl150051 _exit:
11501256Syl150051 	if (retry) {
11511256Syl150051 		if (lldev->resched_avail != lldev->resched_send &&
11521256Syl150051 		    xge_queue_produce_context(xge_hal_device_queue(lldev->devh),
1153*6937Sxw161283 		    XGELL_EVENT_RESCHED_NEEDED, fifo) == XGE_QUEUE_OK) {
11541256Syl150051 			lldev->resched_send = lldev->resched_avail;
11551256Syl150051 			return (B_FALSE);
11561256Syl150051 		} else {
11571256Syl150051 			lldev->resched_retry = 1;
11581256Syl150051 		}
11591256Syl150051 	}
11601256Syl150051 
1161*6937Sxw161283 	if (mp)
1162*6937Sxw161283 		freemsg(mp);
11631256Syl150051 	return (B_TRUE);
11641256Syl150051 }
11651256Syl150051 
11661256Syl150051 /*
11671256Syl150051  * xge_m_tx
11683115Syl150051  * @arg: pointer to the xgelldev_t structure
11691256Syl150051  * @resid: resource id
11701256Syl150051  * @mp: pointer to the message buffer
11711256Syl150051  *
11721256Syl150051  * Called by MAC Layer to send a chain of packets
11731256Syl150051  */
11741256Syl150051 static mblk_t *
11751256Syl150051 xgell_m_tx(void *arg, mblk_t *mp)
11761256Syl150051 {
11773115Syl150051 	xgelldev_t *lldev = arg;
11781256Syl150051 	mblk_t *next;
11791256Syl150051 
11801256Syl150051 	while (mp != NULL) {
11811256Syl150051 		next = mp->b_next;
11821256Syl150051 		mp->b_next = NULL;
11831256Syl150051 
11843115Syl150051 		if (!xgell_send(lldev, mp)) {
11851256Syl150051 			mp->b_next = next;
11861256Syl150051 			break;
11871256Syl150051 		}
11881256Syl150051 		mp = next;
11891256Syl150051 	}
11901256Syl150051 
11911256Syl150051 	return (mp);
11921256Syl150051 }
11931256Syl150051 
11941256Syl150051 /*
11951256Syl150051  * xgell_rx_dtr_term
11961256Syl150051  *
11971256Syl150051  * Function will be called by HAL to terminate all DTRs for
11981256Syl150051  * Ring(s) type of channels.
11991256Syl150051  */
12001256Syl150051 static void
12011256Syl150051 xgell_rx_dtr_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
12021256Syl150051     xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen)
12031256Syl150051 {
1204*6937Sxw161283 	xgell_ring_t *ring = (xgell_ring_t *)userdata;
12051256Syl150051 	xgell_rxd_priv_t *rxd_priv =
12061256Syl150051 	    ((xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtrh));
12071256Syl150051 	xgell_rx_buffer_t *rx_buffer = rxd_priv->rx_buffer;
12081256Syl150051 
12091256Syl150051 	if (state == XGE_HAL_DTR_STATE_POSTED) {
1210*6937Sxw161283 		mutex_enter(&ring->bf_pool.pool_lock);
12111256Syl150051 		xge_hal_ring_dtr_free(channelh, dtrh);
12121256Syl150051 		xgell_rx_buffer_release(rx_buffer);
1213*6937Sxw161283 		mutex_exit(&ring->bf_pool.pool_lock);
12141256Syl150051 	}
12151256Syl150051 }
12161256Syl150051 
12171256Syl150051 /*
12181256Syl150051  * xgell_tx_term
12191256Syl150051  *
12201256Syl150051  * Function will be called by HAL to terminate all DTRs for
12211256Syl150051  * Fifo(s) type of channels.
12221256Syl150051  */
12231256Syl150051 static void
12241256Syl150051 xgell_tx_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
12251256Syl150051     xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen)
12261256Syl150051 {
12271256Syl150051 	xgell_txd_priv_t *txd_priv =
12281256Syl150051 	    ((xgell_txd_priv_t *)xge_hal_fifo_dtr_private(dtrh));
12291256Syl150051 	mblk_t *mp = txd_priv->mblk;
12301256Syl150051 	int i;
12313115Syl150051 
12321256Syl150051 	/*
12331256Syl150051 	 * for Tx we must clean up the DTR *only* if it has been
12341256Syl150051 	 * posted!
12351256Syl150051 	 */
12361256Syl150051 	if (state != XGE_HAL_DTR_STATE_POSTED) {
12371256Syl150051 		return;
12381256Syl150051 	}
12391256Syl150051 
12401256Syl150051 	for (i = 0; i < txd_priv->handle_cnt; i++) {
12411256Syl150051 		xge_assert(txd_priv->dma_handles[i]);
12421256Syl150051 		(void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]);
12431256Syl150051 		ddi_dma_free_handle(&txd_priv->dma_handles[i]);
12441256Syl150051 		txd_priv->dma_handles[i] = 0;
12451256Syl150051 	}
12461256Syl150051 
12471256Syl150051 	xge_hal_fifo_dtr_free(channelh, dtrh);
12481256Syl150051 
1249*6937Sxw161283 	if (mp) {
1250*6937Sxw161283 		txd_priv->mblk = NULL;
1251*6937Sxw161283 		freemsg(mp);
1252*6937Sxw161283 	}
1253*6937Sxw161283 }
1254*6937Sxw161283 
1255*6937Sxw161283 /*
1256*6937Sxw161283  * xgell_tx_close
1257*6937Sxw161283  * @lldev: the link layer object
1258*6937Sxw161283  *
1259*6937Sxw161283  * Close all Tx channels
1260*6937Sxw161283  */
1261*6937Sxw161283 static void
1262*6937Sxw161283 xgell_tx_close(xgelldev_t *lldev)
1263*6937Sxw161283 {
1264*6937Sxw161283 	xge_list_t *item, *list;
1265*6937Sxw161283 	xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh;
1266*6937Sxw161283 
1267*6937Sxw161283 	list = &hldev->fifo_channels;
1268*6937Sxw161283 	while (!xge_list_is_empty(list)) {
1269*6937Sxw161283 		item = xge_list_first_get(list);
1270*6937Sxw161283 		xge_hal_channel_t *channel = xge_container_of(item,
1271*6937Sxw161283 		    xge_hal_channel_t, item);
1272*6937Sxw161283 
1273*6937Sxw161283 		xge_hal_channel_close(channel, XGE_HAL_CHANNEL_OC_NORMAL);
1274*6937Sxw161283 	}
12751256Syl150051 }
12761256Syl150051 
12771256Syl150051 /*
12781256Syl150051  * xgell_tx_open
12791256Syl150051  * @lldev: the link layer object
12801256Syl150051  *
12811256Syl150051  * Initialize and open all Tx channels;
12821256Syl150051  */
12831256Syl150051 static boolean_t
12841256Syl150051 xgell_tx_open(xgelldev_t *lldev)
12851256Syl150051 {
12861256Syl150051 	xge_hal_status_e status;
12871256Syl150051 	u64 adapter_status;
12881256Syl150051 	xge_hal_channel_attr_t attr;
1289*6937Sxw161283 	xge_list_t *item;
1290*6937Sxw161283 	xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh;
12911256Syl150051 
12921256Syl150051 	attr.post_qid		= 0;
12931256Syl150051 	attr.compl_qid		= 0;
12941256Syl150051 	attr.callback		= xgell_xmit_compl;
12951256Syl150051 	attr.per_dtr_space	= sizeof (xgell_txd_priv_t);
12961256Syl150051 	attr.flags		= 0;
12971256Syl150051 	attr.type		= XGE_HAL_CHANNEL_TYPE_FIFO;
12981256Syl150051 	attr.userdata		= lldev;
12991256Syl150051 	attr.dtr_init		= NULL;
13001256Syl150051 	attr.dtr_term		= xgell_tx_term;
13011256Syl150051 
13021256Syl150051 	if (xge_hal_device_status(lldev->devh, &adapter_status)) {
13031256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: device is not ready "
13041256Syl150051 		    "adaper status reads 0x%"PRIx64, XGELL_IFNAME,
13051256Syl150051 		    lldev->instance, (uint64_t)adapter_status);
13061256Syl150051 		return (B_FALSE);
13071256Syl150051 	}
13081256Syl150051 
1309*6937Sxw161283 	/*
1310*6937Sxw161283 	 * Open only configured channels. HAL structures are static,
1311*6937Sxw161283 	 * so, no worries here..
1312*6937Sxw161283 	 */
1313*6937Sxw161283 _next_channel:
1314*6937Sxw161283 	xge_list_for_each(item, &hldev->free_channels) {
1315*6937Sxw161283 		xge_hal_channel_t *channel = xge_container_of(item,
1316*6937Sxw161283 		    xge_hal_channel_t, item);
1317*6937Sxw161283 		xgell_fifo_t *fifo;
1318*6937Sxw161283 
1319*6937Sxw161283 		/* filter on FIFO channels */
1320*6937Sxw161283 		if (channel->type != XGE_HAL_CHANNEL_TYPE_FIFO)
1321*6937Sxw161283 			continue;
1322*6937Sxw161283 
1323*6937Sxw161283 		fifo = &lldev->fifos[attr.post_qid];
1324*6937Sxw161283 		fifo->lldev = lldev;
1325*6937Sxw161283 		attr.userdata = fifo;
1326*6937Sxw161283 
1327*6937Sxw161283 		status = xge_hal_channel_open(lldev->devh, &attr,
1328*6937Sxw161283 		    &fifo->channelh, XGE_HAL_CHANNEL_OC_NORMAL);
1329*6937Sxw161283 		if (status != XGE_HAL_OK) {
1330*6937Sxw161283 			xge_debug_ll(XGE_ERR, "%s%d: cannot open Tx channel "
1331*6937Sxw161283 			    "got status  code %d", XGELL_IFNAME,
1332*6937Sxw161283 			    lldev->instance, status);
1333*6937Sxw161283 			/* unwind */
1334*6937Sxw161283 			xgell_tx_close(lldev);
1335*6937Sxw161283 			return (B_FALSE);
1336*6937Sxw161283 		}
1337*6937Sxw161283 
1338*6937Sxw161283 		attr.post_qid++;
1339*6937Sxw161283 
1340*6937Sxw161283 		/*
1341*6937Sxw161283 		 * because channel_open() moves xge_list entry
1342*6937Sxw161283 		 * to the fifos_channels
1343*6937Sxw161283 		 */
1344*6937Sxw161283 		goto _next_channel;
13451256Syl150051 	}
13461256Syl150051 
13471256Syl150051 	return (B_TRUE);
13481256Syl150051 }
13491256Syl150051 
13501256Syl150051 /*
1351*6937Sxw161283  * xgell_rx_close
1352*6937Sxw161283  * @lldev: the link layer object
1353*6937Sxw161283  *
1354*6937Sxw161283  * Close all Rx channels
1355*6937Sxw161283  */
1356*6937Sxw161283 static void
1357*6937Sxw161283 xgell_rx_close(xgelldev_t *lldev)
1358*6937Sxw161283 {
1359*6937Sxw161283 	xge_list_t *item, *list;
1360*6937Sxw161283 	xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh;
1361*6937Sxw161283 
1362*6937Sxw161283 	list = &hldev->ring_channels;
1363*6937Sxw161283 	while (!xge_list_is_empty(list)) {
1364*6937Sxw161283 		item = xge_list_first_get(list);
1365*6937Sxw161283 		xge_hal_channel_t *channel = xge_container_of(item,
1366*6937Sxw161283 		    xge_hal_channel_t, item);
1367*6937Sxw161283 		xgell_ring_t *ring = xge_hal_channel_userdata(channel);
1368*6937Sxw161283 
1369*6937Sxw161283 		xge_hal_channel_close(channel, XGE_HAL_CHANNEL_OC_NORMAL);
1370*6937Sxw161283 
1371*6937Sxw161283 		/*
1372*6937Sxw161283 		 * destroy Ring's buffer pool
1373*6937Sxw161283 		 */
1374*6937Sxw161283 		if (xgell_rx_destroy_buffer_pool(ring) != DDI_SUCCESS) {
1375*6937Sxw161283 			xge_debug_ll(XGE_ERR, "unable to destroy Ring%d "
1376*6937Sxw161283 			    "buffer pool", channel->post_qid);
1377*6937Sxw161283 		}
1378*6937Sxw161283 		list = &hldev->ring_channels;
1379*6937Sxw161283 	}
1380*6937Sxw161283 }
1381*6937Sxw161283 
1382*6937Sxw161283 /*
13831256Syl150051  * xgell_rx_open
13841256Syl150051  * @lldev: the link layer object
13851256Syl150051  *
13861256Syl150051  * Initialize and open all Rx channels;
13871256Syl150051  */
13881256Syl150051 static boolean_t
13891256Syl150051 xgell_rx_open(xgelldev_t *lldev)
13901256Syl150051 {
13911256Syl150051 	xge_hal_status_e status;
13921256Syl150051 	u64 adapter_status;
13931256Syl150051 	xge_hal_channel_attr_t attr;
1394*6937Sxw161283 	xge_list_t *item;
1395*6937Sxw161283 	xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh;
13961256Syl150051 
1397*6937Sxw161283 	attr.post_qid		= 0;
13981256Syl150051 	attr.compl_qid		= 0;
13991256Syl150051 	attr.callback		= xgell_rx_1b_compl;
14001256Syl150051 	attr.per_dtr_space	= sizeof (xgell_rxd_priv_t);
14011256Syl150051 	attr.flags		= 0;
14021256Syl150051 	attr.type		= XGE_HAL_CHANNEL_TYPE_RING;
14031256Syl150051 	attr.dtr_init		= xgell_rx_dtr_replenish;
14041256Syl150051 	attr.dtr_term		= xgell_rx_dtr_term;
14051256Syl150051 
14061256Syl150051 	if (xge_hal_device_status(lldev->devh, &adapter_status)) {
14071256Syl150051 		xge_debug_ll(XGE_ERR,
14081256Syl150051 		    "%s%d: device is not ready adaper status reads 0x%"PRIx64,
14091256Syl150051 		    XGELL_IFNAME, lldev->instance,
14101256Syl150051 		    (uint64_t)adapter_status);
14111256Syl150051 		return (B_FALSE);
14121256Syl150051 	}
14131256Syl150051 
1414*6937Sxw161283 	/*
1415*6937Sxw161283 	 * Open only configured channels. HAL structures are static,
1416*6937Sxw161283 	 * so, no worries here..
1417*6937Sxw161283 	 */
1418*6937Sxw161283 _next_channel:
1419*6937Sxw161283 	xge_list_for_each(item, &hldev->free_channels) {
1420*6937Sxw161283 		xge_hal_channel_t *channel = xge_container_of(item,
1421*6937Sxw161283 		    xge_hal_channel_t, item);
1422*6937Sxw161283 		xgell_ring_t *ring;
1423*6937Sxw161283 
1424*6937Sxw161283 		/* filter on RING channels */
1425*6937Sxw161283 		if (channel->type != XGE_HAL_CHANNEL_TYPE_RING)
1426*6937Sxw161283 			continue;
1427*6937Sxw161283 
1428*6937Sxw161283 		ring = &lldev->rings[attr.post_qid];
1429*6937Sxw161283 		ring->lldev = lldev;
1430*6937Sxw161283 		attr.userdata = ring;
14311256Syl150051 
1432*6937Sxw161283 		if (xgell_rx_create_buffer_pool(ring) != DDI_SUCCESS) {
1433*6937Sxw161283 			xge_debug_ll(XGE_ERR, "unable to create Ring%d "
1434*6937Sxw161283 			    "buffer pool", attr.post_qid);
1435*6937Sxw161283 			/* unwind */
1436*6937Sxw161283 			xgell_rx_close(lldev);
1437*6937Sxw161283 			return (B_FALSE);
1438*6937Sxw161283 		}
1439*6937Sxw161283 
1440*6937Sxw161283 		status = xge_hal_channel_open(lldev->devh, &attr,
1441*6937Sxw161283 		    &ring->channelh, XGE_HAL_CHANNEL_OC_NORMAL);
1442*6937Sxw161283 		if (status != XGE_HAL_OK) {
1443*6937Sxw161283 			xge_debug_ll(XGE_ERR, "%s%d: cannot open Rx channel "
1444*6937Sxw161283 			    "got status got status code %d", XGELL_IFNAME,
1445*6937Sxw161283 			    lldev->instance, status);
1446*6937Sxw161283 			/* unwind */
1447*6937Sxw161283 			(void) xgell_rx_destroy_buffer_pool(ring);
1448*6937Sxw161283 			xgell_rx_close(lldev);
1449*6937Sxw161283 			return (B_FALSE);
1450*6937Sxw161283 		}
1451*6937Sxw161283 
1452*6937Sxw161283 		attr.post_qid++;
1453*6937Sxw161283 
1454*6937Sxw161283 		/*
1455*6937Sxw161283 		 * because chhannel_open() moves xge_list entry
1456*6937Sxw161283 		 * to the rings channels
1457*6937Sxw161283 		 */
1458*6937Sxw161283 		goto _next_channel;
14591256Syl150051 	}
14601256Syl150051 
14611256Syl150051 	return (B_TRUE);
14621256Syl150051 }
14631256Syl150051 
14641256Syl150051 static int
14651256Syl150051 xgell_initiate_start(xgelldev_t *lldev)
14661256Syl150051 {
14671256Syl150051 	xge_hal_status_e status;
14681256Syl150051 	xge_hal_device_t *hldev = lldev->devh;
14692311Sseb 	int maxpkt = hldev->config.mtu;
14701256Syl150051 
14711256Syl150051 	/* check initial mtu before enabling the device */
14721256Syl150051 	status = xge_hal_device_mtu_check(lldev->devh, maxpkt);
14731256Syl150051 	if (status != XGE_HAL_OK) {
14741256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: MTU size %d is invalid",
14751256Syl150051 		    XGELL_IFNAME, lldev->instance, maxpkt);
14761256Syl150051 		return (EINVAL);
14771256Syl150051 	}
14781256Syl150051 
14791256Syl150051 	/* set initial mtu before enabling the device */
14801256Syl150051 	status = xge_hal_device_mtu_set(lldev->devh, maxpkt);
14811256Syl150051 	if (status != XGE_HAL_OK) {
14821256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not set new MTU %d",
14831256Syl150051 		    XGELL_IFNAME, lldev->instance, maxpkt);
14841256Syl150051 		return (EIO);
14851256Syl150051 	}
14861256Syl150051 
14873115Syl150051 	/* tune jumbo/normal frame UFC counters */
14883115Syl150051 	hldev->config.ring.queue[XGELL_RING_MAIN_QID].rti.ufc_b = \
1489*6937Sxw161283 	    maxpkt > XGE_HAL_DEFAULT_MTU ?
1490*6937Sxw161283 	    XGE_HAL_DEFAULT_RX_UFC_B_J :
1491*6937Sxw161283 	    XGE_HAL_DEFAULT_RX_UFC_B_N;
14923115Syl150051 
14933115Syl150051 	hldev->config.ring.queue[XGELL_RING_MAIN_QID].rti.ufc_c = \
1494*6937Sxw161283 	    maxpkt > XGE_HAL_DEFAULT_MTU ?
1495*6937Sxw161283 	    XGE_HAL_DEFAULT_RX_UFC_C_J :
1496*6937Sxw161283 	    XGE_HAL_DEFAULT_RX_UFC_C_N;
14973115Syl150051 
14981256Syl150051 	/* now, enable the device */
14991256Syl150051 	status = xge_hal_device_enable(lldev->devh);
15001256Syl150051 	if (status != XGE_HAL_OK) {
15011256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not enable the device",
15021256Syl150051 		    XGELL_IFNAME, lldev->instance);
15031256Syl150051 		return (EIO);
15041256Syl150051 	}
15051256Syl150051 
15061256Syl150051 	if (!xgell_rx_open(lldev)) {
15071256Syl150051 		status = xge_hal_device_disable(lldev->devh);
15081256Syl150051 		if (status != XGE_HAL_OK) {
15091256Syl150051 			u64 adapter_status;
15101256Syl150051 			(void) xge_hal_device_status(lldev->devh,
15111256Syl150051 			    &adapter_status);
15121256Syl150051 			xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
15131256Syl150051 			    "the device. adaper status 0x%"PRIx64
15141256Syl150051 			    " returned status %d",
15151256Syl150051 			    XGELL_IFNAME, lldev->instance,
15161256Syl150051 			    (uint64_t)adapter_status, status);
15171256Syl150051 		}
15181256Syl150051 		xge_os_mdelay(1500);
15191256Syl150051 		return (ENOMEM);
15201256Syl150051 	}
15211256Syl150051 
15221256Syl150051 	if (!xgell_tx_open(lldev)) {
15231256Syl150051 		status = xge_hal_device_disable(lldev->devh);
15241256Syl150051 		if (status != XGE_HAL_OK) {
15251256Syl150051 			u64 adapter_status;
15261256Syl150051 			(void) xge_hal_device_status(lldev->devh,
15271256Syl150051 			    &adapter_status);
15281256Syl150051 			xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
15291256Syl150051 			    "the device. adaper status 0x%"PRIx64
15301256Syl150051 			    " returned status %d",
15311256Syl150051 			    XGELL_IFNAME, lldev->instance,
15321256Syl150051 			    (uint64_t)adapter_status, status);
15331256Syl150051 		}
15341256Syl150051 		xge_os_mdelay(1500);
1535*6937Sxw161283 		xgell_rx_close(lldev);
1536*6937Sxw161283 
15371256Syl150051 		return (ENOMEM);
15381256Syl150051 	}
15391256Syl150051 
15401256Syl150051 	/* time to enable interrupts */
1541*6937Sxw161283 	(void) xge_enable_intrs(lldev);
15421256Syl150051 	xge_hal_device_intr_enable(lldev->devh);
15431256Syl150051 
15441256Syl150051 	lldev->is_initialized = 1;
15451256Syl150051 
15461256Syl150051 	return (0);
15471256Syl150051 }
15481256Syl150051 
15491256Syl150051 static void
15501256Syl150051 xgell_initiate_stop(xgelldev_t *lldev)
15511256Syl150051 {
15521256Syl150051 	xge_hal_status_e status;
15531256Syl150051 
15541256Syl150051 	lldev->is_initialized = 0;
15551256Syl150051 
15561256Syl150051 	status = xge_hal_device_disable(lldev->devh);
15571256Syl150051 	if (status != XGE_HAL_OK) {
15581256Syl150051 		u64 adapter_status;
15591256Syl150051 		(void) xge_hal_device_status(lldev->devh, &adapter_status);
15601256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
15611256Syl150051 		    "the device. adaper status 0x%"PRIx64" returned status %d",
15621256Syl150051 		    XGELL_IFNAME, lldev->instance,
15631256Syl150051 		    (uint64_t)adapter_status, status);
15641256Syl150051 	}
15651256Syl150051 	xge_hal_device_intr_disable(lldev->devh);
1566*6937Sxw161283 	/* disable OS ISR's */
1567*6937Sxw161283 	xge_disable_intrs(lldev);
15681256Syl150051 
15691256Syl150051 	xge_debug_ll(XGE_TRACE, "%s",
15701256Syl150051 	    "waiting for device irq to become quiescent...");
15711256Syl150051 	xge_os_mdelay(1500);
15721256Syl150051 
15731256Syl150051 	xge_queue_flush(xge_hal_device_queue(lldev->devh));
15741256Syl150051 
1575*6937Sxw161283 	xgell_rx_close(lldev);
1576*6937Sxw161283 	xgell_tx_close(lldev);
15771256Syl150051 }
15781256Syl150051 
15791256Syl150051 /*
15801256Syl150051  * xgell_m_start
15811256Syl150051  * @arg: pointer to device private strucutre(hldev)
15821256Syl150051  *
15831256Syl150051  * This function is called by MAC Layer to enable the XFRAME
15841256Syl150051  * firmware to generate interrupts and also prepare the
15851256Syl150051  * driver to call mac_rx for delivering receive packets
15861256Syl150051  * to MAC Layer.
15871256Syl150051  */
15881256Syl150051 static int
15891256Syl150051 xgell_m_start(void *arg)
15901256Syl150051 {
15913115Syl150051 	xgelldev_t *lldev = arg;
15923115Syl150051 	xge_hal_device_t *hldev = lldev->devh;
15931256Syl150051 	int ret;
15941256Syl150051 
15951256Syl150051 	xge_debug_ll(XGE_TRACE, "%s%d: M_START", XGELL_IFNAME,
15961256Syl150051 	    lldev->instance);
15971256Syl150051 
15981256Syl150051 	mutex_enter(&lldev->genlock);
15991256Syl150051 
16001256Syl150051 	if (lldev->is_initialized) {
16011256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: device is already initialized",
16021256Syl150051 		    XGELL_IFNAME, lldev->instance);
16031256Syl150051 		mutex_exit(&lldev->genlock);
16041256Syl150051 		return (EINVAL);
16051256Syl150051 	}
16061256Syl150051 
16071256Syl150051 	hldev->terminating = 0;
16081256Syl150051 	if (ret = xgell_initiate_start(lldev)) {
16091256Syl150051 		mutex_exit(&lldev->genlock);
16101256Syl150051 		return (ret);
16111256Syl150051 	}
16121256Syl150051 
16131256Syl150051 	lldev->timeout_id = timeout(xge_device_poll, hldev, XGE_DEV_POLL_TICKS);
16141256Syl150051 
16151256Syl150051 	mutex_exit(&lldev->genlock);
16161256Syl150051 
16171256Syl150051 	return (0);
16181256Syl150051 }
16191256Syl150051 
16201256Syl150051 /*
16211256Syl150051  * xgell_m_stop
16221256Syl150051  * @arg: pointer to device private data (hldev)
16231256Syl150051  *
16241256Syl150051  * This function is called by the MAC Layer to disable
16251256Syl150051  * the XFRAME firmware for generating any interrupts and
16261256Syl150051  * also stop the driver from calling mac_rx() for
16271256Syl150051  * delivering data packets to the MAC Layer.
16281256Syl150051  */
16291256Syl150051 static void
16301256Syl150051 xgell_m_stop(void *arg)
16311256Syl150051 {
16323115Syl150051 	xgelldev_t *lldev = arg;
16333115Syl150051 	xge_hal_device_t *hldev = lldev->devh;
16341256Syl150051 
16351256Syl150051 	xge_debug_ll(XGE_TRACE, "%s", "MAC_STOP");
16361256Syl150051 
16371256Syl150051 	mutex_enter(&lldev->genlock);
16381256Syl150051 	if (!lldev->is_initialized) {
16391256Syl150051 		xge_debug_ll(XGE_ERR, "%s", "device is not initialized...");
16401256Syl150051 		mutex_exit(&lldev->genlock);
16411256Syl150051 		return;
16421256Syl150051 	}
16431256Syl150051 
16441256Syl150051 	xge_hal_device_terminating(hldev);
16451256Syl150051 	xgell_initiate_stop(lldev);
16461256Syl150051 
16471256Syl150051 	/* reset device */
16481256Syl150051 	(void) xge_hal_device_reset(lldev->devh);
16491256Syl150051 
16501256Syl150051 	mutex_exit(&lldev->genlock);
16511256Syl150051 
16523115Syl150051 	if (lldev->timeout_id != 0) {
16533115Syl150051 		(void) untimeout(lldev->timeout_id);
16543115Syl150051 	}
16551256Syl150051 
16561256Syl150051 	xge_debug_ll(XGE_TRACE, "%s", "returning back to MAC Layer...");
16571256Syl150051 }
16581256Syl150051 
16591256Syl150051 /*
16601256Syl150051  * xgell_onerr_reset
16611256Syl150051  * @lldev: pointer to xgelldev_t structure
16621256Syl150051  *
16631256Syl150051  * This function is called by HAL Event framework to reset the HW
16641256Syl150051  * This function is must be called with genlock taken.
16651256Syl150051  */
16661256Syl150051 int
16671256Syl150051 xgell_onerr_reset(xgelldev_t *lldev)
16681256Syl150051 {
16691256Syl150051 	int rc = 0;
16701256Syl150051 
16711256Syl150051 	if (!lldev->is_initialized) {
16721256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not reset",
16731256Syl150051 		    XGELL_IFNAME, lldev->instance);
16741256Syl150051 		return (rc);
16751256Syl150051 	}
16761256Syl150051 
16771256Syl150051 	lldev->in_reset = 1;
16781256Syl150051 	xgell_initiate_stop(lldev);
16791256Syl150051 
16801256Syl150051 	/* reset device */
16811256Syl150051 	(void) xge_hal_device_reset(lldev->devh);
16821256Syl150051 
16831256Syl150051 	rc = xgell_initiate_start(lldev);
16841256Syl150051 	lldev->in_reset = 0;
16851256Syl150051 
16861256Syl150051 	return (rc);
16871256Syl150051 }
16881256Syl150051 
16891256Syl150051 
16901256Syl150051 /*
16911256Syl150051  * xgell_m_unicst
16921256Syl150051  * @arg: pointer to device private strucutre(hldev)
16931256Syl150051  * @mac_addr:
16941256Syl150051  *
16951256Syl150051  * This function is called by MAC Layer to set the physical address
16961256Syl150051  * of the XFRAME firmware.
16971256Syl150051  */
16981256Syl150051 static int
16991256Syl150051 xgell_m_unicst(void *arg, const uint8_t *macaddr)
17001256Syl150051 {
17011256Syl150051 	xge_hal_status_e status;
17023115Syl150051 	xgelldev_t *lldev = (xgelldev_t *)arg;
17033115Syl150051 	xge_hal_device_t *hldev = lldev->devh;
17041256Syl150051 	xge_debug_ll(XGE_TRACE, "%s", "MAC_UNICST");
17051256Syl150051 
17061256Syl150051 	xge_debug_ll(XGE_TRACE, "%s", "M_UNICAST");
17071256Syl150051 
17081256Syl150051 	mutex_enter(&lldev->genlock);
17091256Syl150051 
17101256Syl150051 	xge_debug_ll(XGE_TRACE,
17111256Syl150051 	    "setting macaddr: 0x%02x-%02x-%02x-%02x-%02x-%02x",
17121256Syl150051 	    macaddr[0], macaddr[1], macaddr[2],
17131256Syl150051 	    macaddr[3], macaddr[4], macaddr[5]);
17141256Syl150051 
17151256Syl150051 	status = xge_hal_device_macaddr_set(hldev, 0, (uchar_t *)macaddr);
17161256Syl150051 	if (status != XGE_HAL_OK) {
17171256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not set mac address",
17181256Syl150051 		    XGELL_IFNAME, lldev->instance);
17191256Syl150051 		mutex_exit(&lldev->genlock);
17201256Syl150051 		return (EIO);
17211256Syl150051 	}
17221256Syl150051 
17231256Syl150051 	mutex_exit(&lldev->genlock);
17241256Syl150051 
17251256Syl150051 	return (0);
17261256Syl150051 }
17271256Syl150051 
17281256Syl150051 
17291256Syl150051 /*
17301256Syl150051  * xgell_m_multicst
17311256Syl150051  * @arg: pointer to device private strucutre(hldev)
17321256Syl150051  * @add:
17331256Syl150051  * @mc_addr:
17341256Syl150051  *
17351256Syl150051  * This function is called by MAC Layer to enable or
17361256Syl150051  * disable device-level reception of specific multicast addresses.
17371256Syl150051  */
17381256Syl150051 static int
17391256Syl150051 xgell_m_multicst(void *arg, boolean_t add, const uint8_t *mc_addr)
17401256Syl150051 {
17411256Syl150051 	xge_hal_status_e status;
17423115Syl150051 	xgelldev_t *lldev = (xgelldev_t *)arg;
17433115Syl150051 	xge_hal_device_t *hldev = lldev->devh;
17441256Syl150051 
17451256Syl150051 	xge_debug_ll(XGE_TRACE, "M_MULTICAST add %d", add);
17461256Syl150051 
17471256Syl150051 	mutex_enter(&lldev->genlock);
17481256Syl150051 
17491256Syl150051 	if (!lldev->is_initialized) {
17501256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not set multicast",
17511256Syl150051 		    XGELL_IFNAME, lldev->instance);
17521256Syl150051 		mutex_exit(&lldev->genlock);
17531256Syl150051 		return (EIO);
17541256Syl150051 	}
17551256Syl150051 
17561256Syl150051 	/* FIXME: missing HAL functionality: enable_one() */
17571256Syl150051 
17581256Syl150051 	status = (add) ?
17591256Syl150051 	    xge_hal_device_mcast_enable(hldev) :
17601256Syl150051 	    xge_hal_device_mcast_disable(hldev);
17611256Syl150051 
17621256Syl150051 	if (status != XGE_HAL_OK) {
17631256Syl150051 		xge_debug_ll(XGE_ERR, "failed to %s multicast, status %d",
17641256Syl150051 		    add ? "enable" : "disable", status);
17651256Syl150051 		mutex_exit(&lldev->genlock);
17661256Syl150051 		return (EIO);
17671256Syl150051 	}
17681256Syl150051 
17691256Syl150051 	mutex_exit(&lldev->genlock);
17701256Syl150051 
17711256Syl150051 	return (0);
17721256Syl150051 }
17731256Syl150051 
17741256Syl150051 
17751256Syl150051 /*
17761256Syl150051  * xgell_m_promisc
17771256Syl150051  * @arg: pointer to device private strucutre(hldev)
17781256Syl150051  * @on:
17791256Syl150051  *
17801256Syl150051  * This function is called by MAC Layer to enable or
17811256Syl150051  * disable the reception of all the packets on the medium
17821256Syl150051  */
17831256Syl150051 static int
17841256Syl150051 xgell_m_promisc(void *arg, boolean_t on)
17851256Syl150051 {
17863115Syl150051 	xgelldev_t *lldev = (xgelldev_t *)arg;
17873115Syl150051 	xge_hal_device_t *hldev = lldev->devh;
17881256Syl150051 
17891256Syl150051 	mutex_enter(&lldev->genlock);
17901256Syl150051 
17911256Syl150051 	xge_debug_ll(XGE_TRACE, "%s", "MAC_PROMISC_SET");
17921256Syl150051 
17931256Syl150051 	if (!lldev->is_initialized) {
17941256Syl150051 		xge_debug_ll(XGE_ERR, "%s%d: can not set promiscuous",
17951256Syl150051 		    XGELL_IFNAME, lldev->instance);
17961256Syl150051 		mutex_exit(&lldev->genlock);
17971256Syl150051 		return (EIO);
17981256Syl150051 	}
17991256Syl150051 
18001256Syl150051 	if (on) {
18011256Syl150051 		xge_hal_device_promisc_enable(hldev);
18021256Syl150051 	} else {
18031256Syl150051 		xge_hal_device_promisc_disable(hldev);
18041256Syl150051 	}
18051256Syl150051 
18061256Syl150051 	mutex_exit(&lldev->genlock);
18071256Syl150051 
18081256Syl150051 	return (0);
18091256Syl150051 }
18101256Syl150051 
18111256Syl150051 /*
18122311Sseb  * xgell_m_stat
18131256Syl150051  * @arg: pointer to device private strucutre(hldev)
18141256Syl150051  *
18152311Sseb  * This function is called by MAC Layer to get network statistics
18161256Syl150051  * from the driver.
18171256Syl150051  */
18182311Sseb static int
18192311Sseb xgell_m_stat(void *arg, uint_t stat, uint64_t *val)
18201256Syl150051 {
18211256Syl150051 	xge_hal_stats_hw_info_t *hw_info;
18223115Syl150051 	xgelldev_t *lldev = (xgelldev_t *)arg;
18233115Syl150051 	xge_hal_device_t *hldev = lldev->devh;
18241256Syl150051 
18251256Syl150051 	xge_debug_ll(XGE_TRACE, "%s", "MAC_STATS_GET");
18261256Syl150051 
1827*6937Sxw161283 	mutex_enter(&lldev->genlock);
18281256Syl150051 
18291256Syl150051 	if (!lldev->is_initialized) {
18301256Syl150051 		mutex_exit(&lldev->genlock);
18312311Sseb 		return (EAGAIN);
18321256Syl150051 	}
18331256Syl150051 
18341256Syl150051 	if (xge_hal_stats_hw(hldev, &hw_info) != XGE_HAL_OK) {
18351256Syl150051 		mutex_exit(&lldev->genlock);
18362311Sseb 		return (EAGAIN);
18371256Syl150051 	}
18381256Syl150051 
18391256Syl150051 	switch (stat) {
18401256Syl150051 	case MAC_STAT_IFSPEED:
18412311Sseb 		*val = 10000000000ull; /* 10G */
18421256Syl150051 		break;
18431256Syl150051 
18441256Syl150051 	case MAC_STAT_MULTIRCV:
18453115Syl150051 		*val = ((u64) hw_info->rmac_vld_mcst_frms_oflow << 32) |
18463115Syl150051 		    hw_info->rmac_vld_mcst_frms;
18471256Syl150051 		break;
18481256Syl150051 
18491256Syl150051 	case MAC_STAT_BRDCSTRCV:
18503115Syl150051 		*val = ((u64) hw_info->rmac_vld_bcst_frms_oflow << 32) |
18513115Syl150051 		    hw_info->rmac_vld_bcst_frms;
18521256Syl150051 		break;
18531256Syl150051 
18541256Syl150051 	case MAC_STAT_MULTIXMT:
18553115Syl150051 		*val = ((u64) hw_info->tmac_mcst_frms_oflow << 32) |
18563115Syl150051 		    hw_info->tmac_mcst_frms;
18571256Syl150051 		break;
18581256Syl150051 
18591256Syl150051 	case MAC_STAT_BRDCSTXMT:
18603115Syl150051 		*val = ((u64) hw_info->tmac_bcst_frms_oflow << 32) |
18613115Syl150051 		    hw_info->tmac_bcst_frms;
18621256Syl150051 		break;
18631256Syl150051 
18641256Syl150051 	case MAC_STAT_RBYTES:
18653115Syl150051 		*val = ((u64) hw_info->rmac_ttl_octets_oflow << 32) |
18663115Syl150051 		    hw_info->rmac_ttl_octets;
18671256Syl150051 		break;
18681256Syl150051 
18691256Syl150051 	case MAC_STAT_NORCVBUF:
18702311Sseb 		*val = hw_info->rmac_drop_frms;
18711256Syl150051 		break;
18721256Syl150051 
18731256Syl150051 	case MAC_STAT_IERRORS:
18743115Syl150051 		*val = ((u64) hw_info->rmac_discarded_frms_oflow << 32) |
18753115Syl150051 		    hw_info->rmac_discarded_frms;
18761256Syl150051 		break;
18771256Syl150051 
18781256Syl150051 	case MAC_STAT_OBYTES:
18793115Syl150051 		*val = ((u64) hw_info->tmac_ttl_octets_oflow << 32) |
18803115Syl150051 		    hw_info->tmac_ttl_octets;
18811256Syl150051 		break;
18821256Syl150051 
18831256Syl150051 	case MAC_STAT_NOXMTBUF:
18842311Sseb 		*val = hw_info->tmac_drop_frms;
18851256Syl150051 		break;
18861256Syl150051 
18871256Syl150051 	case MAC_STAT_OERRORS:
18883115Syl150051 		*val = ((u64) hw_info->tmac_any_err_frms_oflow << 32) |
18893115Syl150051 		    hw_info->tmac_any_err_frms;
18901256Syl150051 		break;
18911256Syl150051 
18921256Syl150051 	case MAC_STAT_IPACKETS:
18933115Syl150051 		*val = ((u64) hw_info->rmac_vld_frms_oflow << 32) |
18943115Syl150051 		    hw_info->rmac_vld_frms;
18951256Syl150051 		break;
18961256Syl150051 
18971256Syl150051 	case MAC_STAT_OPACKETS:
18983115Syl150051 		*val = ((u64) hw_info->tmac_frms_oflow << 32) |
18993115Syl150051 		    hw_info->tmac_frms;
19002311Sseb 		break;
19012311Sseb 
19022311Sseb 	case ETHER_STAT_FCS_ERRORS:
19032311Sseb 		*val = hw_info->rmac_fcs_err_frms;
19041256Syl150051 		break;
19051256Syl150051 
19062311Sseb 	case ETHER_STAT_TOOLONG_ERRORS:
19072311Sseb 		*val = hw_info->rmac_long_frms;
19081256Syl150051 		break;
19091256Syl150051 
19102311Sseb 	case ETHER_STAT_LINK_DUPLEX:
19112311Sseb 		*val = LINK_DUPLEX_FULL;
19121256Syl150051 		break;
19131256Syl150051 
19141256Syl150051 	default:
19152311Sseb 		mutex_exit(&lldev->genlock);
19162311Sseb 		return (ENOTSUP);
19171256Syl150051 	}
19181256Syl150051 
19191256Syl150051 	mutex_exit(&lldev->genlock);
19201256Syl150051 
19212311Sseb 	return (0);
19221256Syl150051 }
19231256Syl150051 
19241256Syl150051 /*
19251256Syl150051  * xgell_device_alloc - Allocate new LL device
19261256Syl150051  */
19271256Syl150051 int
19281256Syl150051 xgell_device_alloc(xge_hal_device_h devh,
19291256Syl150051     dev_info_t *dev_info, xgelldev_t **lldev_out)
19301256Syl150051 {
19311256Syl150051 	xgelldev_t *lldev;
19321256Syl150051 	xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
19331256Syl150051 	int instance = ddi_get_instance(dev_info);
19341256Syl150051 
19351256Syl150051 	*lldev_out = NULL;
19361256Syl150051 
19371256Syl150051 	xge_debug_ll(XGE_TRACE, "trying to register etherenet device %s%d...",
19381256Syl150051 	    XGELL_IFNAME, instance);
19391256Syl150051 
19401256Syl150051 	lldev = kmem_zalloc(sizeof (xgelldev_t), KM_SLEEP);
19411256Syl150051 
19421256Syl150051 	lldev->devh = hldev;
19431256Syl150051 	lldev->instance = instance;
19441256Syl150051 	lldev->dev_info = dev_info;
19451256Syl150051 
19461256Syl150051 	*lldev_out = lldev;
19471256Syl150051 
19481256Syl150051 	ddi_set_driver_private(dev_info, (caddr_t)hldev);
19491256Syl150051 
19501256Syl150051 	return (DDI_SUCCESS);
19511256Syl150051 }
19521256Syl150051 
19531256Syl150051 /*
19541256Syl150051  * xgell_device_free
19551256Syl150051  */
19561256Syl150051 void
19571256Syl150051 xgell_device_free(xgelldev_t *lldev)
19581256Syl150051 {
19591256Syl150051 	xge_debug_ll(XGE_TRACE, "freeing device %s%d",
19601256Syl150051 	    XGELL_IFNAME, lldev->instance);
19611256Syl150051 
19621256Syl150051 	kmem_free(lldev, sizeof (xgelldev_t));
19631256Syl150051 }
19641256Syl150051 
19651256Syl150051 /*
19661256Syl150051  * xgell_ioctl
19671256Syl150051  */
19681256Syl150051 static void
19691256Syl150051 xgell_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
19701256Syl150051 {
19713115Syl150051 	xgelldev_t *lldev = arg;
19721256Syl150051 	struct iocblk *iocp;
19731256Syl150051 	int err = 0;
19741256Syl150051 	int cmd;
19751256Syl150051 	int need_privilege = 1;
19761256Syl150051 	int ret = 0;
19771256Syl150051 
19781256Syl150051 
19791256Syl150051 	iocp = (struct iocblk *)mp->b_rptr;
19801256Syl150051 	iocp->ioc_error = 0;
19811256Syl150051 	cmd = iocp->ioc_cmd;
19821256Syl150051 	xge_debug_ll(XGE_TRACE, "MAC_IOCTL cmd 0x%x", cmd);
19831256Syl150051 	switch (cmd) {
19841256Syl150051 	case ND_GET:
19851256Syl150051 		need_privilege = 0;
19861256Syl150051 		/* FALLTHRU */
19871256Syl150051 	case ND_SET:
19881256Syl150051 		break;
19891256Syl150051 	default:
19901256Syl150051 		xge_debug_ll(XGE_TRACE, "unknown cmd 0x%x", cmd);
19911256Syl150051 		miocnak(wq, mp, 0, EINVAL);
19921256Syl150051 		return;
19931256Syl150051 	}
19941256Syl150051 
19951256Syl150051 	if (need_privilege) {
19961256Syl150051 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
19971256Syl150051 		if (err != 0) {
19981256Syl150051 			xge_debug_ll(XGE_ERR,
19991256Syl150051 			    "drv_priv(): rejected cmd 0x%x, err %d",
20001256Syl150051 			    cmd, err);
20011256Syl150051 			miocnak(wq, mp, 0, err);
20021256Syl150051 			return;
20031256Syl150051 		}
20041256Syl150051 	}
20051256Syl150051 
20061256Syl150051 	switch (cmd) {
20071256Syl150051 	case ND_GET:
20081256Syl150051 		/*
20091256Syl150051 		 * If nd_getset() returns B_FALSE, the command was
20101256Syl150051 		 * not valid (e.g. unknown name), so we just tell the
20111256Syl150051 		 * top-level ioctl code to send a NAK (with code EINVAL).
20121256Syl150051 		 *
20131256Syl150051 		 * Otherwise, nd_getset() will have built the reply to
20141256Syl150051 		 * be sent (but not actually sent it), so we tell the
20151256Syl150051 		 * caller to send the prepared reply.
20161256Syl150051 		 */
20171256Syl150051 		ret = nd_getset(wq, lldev->ndp, mp);
2018*6937Sxw161283 		xge_debug_ll(XGE_TRACE, "%s", "got ndd get ioctl");
20191256Syl150051 		break;
20201256Syl150051 
20211256Syl150051 	case ND_SET:
20221256Syl150051 		ret = nd_getset(wq, lldev->ndp, mp);
2023*6937Sxw161283 		xge_debug_ll(XGE_TRACE, "%s", "got ndd set ioctl");
20241256Syl150051 		break;
20251256Syl150051 
20261256Syl150051 	default:
20271256Syl150051 		break;
20281256Syl150051 	}
20291256Syl150051 
20301256Syl150051 	if (ret == B_FALSE) {
20311256Syl150051 		xge_debug_ll(XGE_ERR,
20321256Syl150051 		    "nd_getset(): rejected cmd 0x%x, err %d",
20331256Syl150051 		    cmd, err);
20341256Syl150051 		miocnak(wq, mp, 0, EINVAL);
20351256Syl150051 	} else {
20361256Syl150051 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
20371256Syl150051 		    M_IOCACK : M_IOCNAK;
20381256Syl150051 		qreply(wq, mp);
20391256Syl150051 	}
20401256Syl150051 }
20411256Syl150051 
20422311Sseb /* ARGSUSED */
20432311Sseb static boolean_t
20442311Sseb xgell_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
20451256Syl150051 {
20463115Syl150051 	xgelldev_t *lldev = arg;
20473115Syl150051 
20482311Sseb 	switch (cap) {
20492311Sseb 	case MAC_CAPAB_HCKSUM: {
20502311Sseb 		uint32_t *hcksum_txflags = cap_data;
20512311Sseb 		*hcksum_txflags = HCKSUM_INET_FULL_V4 | HCKSUM_INET_FULL_V6 |
20522311Sseb 		    HCKSUM_IPHDRCKSUM;
20532311Sseb 		break;
20542311Sseb 	}
20553115Syl150051 	case MAC_CAPAB_LSO: {
20563115Syl150051 		mac_capab_lso_t *cap_lso = cap_data;
20573115Syl150051 
20583115Syl150051 		if (lldev->config.lso_enable) {
20593115Syl150051 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
20603115Syl150051 			cap_lso->lso_basic_tcp_ipv4.lso_max = XGELL_LSO_MAXLEN;
20613115Syl150051 			break;
20623115Syl150051 		} else {
20633115Syl150051 			return (B_FALSE);
20643115Syl150051 		}
20653115Syl150051 	}
20662311Sseb 	default:
20672311Sseb 		return (B_FALSE);
20682311Sseb 	}
20692311Sseb 	return (B_TRUE);
20701256Syl150051 }
20711256Syl150051 
20721256Syl150051 static int
20731256Syl150051 xgell_stats_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
20741256Syl150051 {
20751256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)cp;
20761256Syl150051 	xge_hal_status_e status;
20771256Syl150051 	int count = 0, retsize;
20781256Syl150051 	char *buf;
20791256Syl150051 
20801256Syl150051 	buf = kmem_alloc(XGELL_STATS_BUFSIZE, KM_SLEEP);
20811256Syl150051 	if (buf == NULL) {
20821256Syl150051 		return (ENOSPC);
20831256Syl150051 	}
20841256Syl150051 
20851256Syl150051 	status = xge_hal_aux_stats_tmac_read(lldev->devh, XGELL_STATS_BUFSIZE,
20861256Syl150051 	    buf, &retsize);
20871256Syl150051 	if (status != XGE_HAL_OK) {
20881256Syl150051 		kmem_free(buf, XGELL_STATS_BUFSIZE);
20891256Syl150051 		xge_debug_ll(XGE_ERR, "tmac_read(): status %d", status);
20901256Syl150051 		return (EINVAL);
20911256Syl150051 	}
20921256Syl150051 	count += retsize;
20931256Syl150051 
20941256Syl150051 	status = xge_hal_aux_stats_rmac_read(lldev->devh,
20951256Syl150051 	    XGELL_STATS_BUFSIZE - count,
20961256Syl150051 	    buf+count, &retsize);
20971256Syl150051 	if (status != XGE_HAL_OK) {
20981256Syl150051 		kmem_free(buf, XGELL_STATS_BUFSIZE);
20991256Syl150051 		xge_debug_ll(XGE_ERR, "rmac_read(): status %d", status);
21001256Syl150051 		return (EINVAL);
21011256Syl150051 	}
21021256Syl150051 	count += retsize;
21031256Syl150051 
21041256Syl150051 	status = xge_hal_aux_stats_pci_read(lldev->devh,
21051256Syl150051 	    XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
21061256Syl150051 	if (status != XGE_HAL_OK) {
21071256Syl150051 		kmem_free(buf, XGELL_STATS_BUFSIZE);
21081256Syl150051 		xge_debug_ll(XGE_ERR, "pci_read(): status %d", status);
21091256Syl150051 		return (EINVAL);
21101256Syl150051 	}
21111256Syl150051 	count += retsize;
21121256Syl150051 
21131256Syl150051 	status = xge_hal_aux_stats_sw_dev_read(lldev->devh,
21141256Syl150051 	    XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
21151256Syl150051 	if (status != XGE_HAL_OK) {
21161256Syl150051 		kmem_free(buf, XGELL_STATS_BUFSIZE);
21171256Syl150051 		xge_debug_ll(XGE_ERR, "sw_dev_read(): status %d", status);
21181256Syl150051 		return (EINVAL);
21191256Syl150051 	}
21201256Syl150051 	count += retsize;
21211256Syl150051 
21221256Syl150051 	status = xge_hal_aux_stats_hal_read(lldev->devh,
21231256Syl150051 	    XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
21241256Syl150051 	if (status != XGE_HAL_OK) {
21251256Syl150051 		kmem_free(buf, XGELL_STATS_BUFSIZE);
21261256Syl150051 		xge_debug_ll(XGE_ERR, "pci_read(): status %d", status);
21271256Syl150051 		return (EINVAL);
21281256Syl150051 	}
21291256Syl150051 	count += retsize;
21301256Syl150051 
21311256Syl150051 	*(buf + count - 1) = '\0'; /* remove last '\n' */
21321256Syl150051 	(void) mi_mpprintf(mp, "%s", buf);
21331256Syl150051 	kmem_free(buf, XGELL_STATS_BUFSIZE);
21341256Syl150051 
21351256Syl150051 	return (0);
21361256Syl150051 }
21371256Syl150051 
21381256Syl150051 static int
21391256Syl150051 xgell_pciconf_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
21401256Syl150051 {
21411256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)cp;
21421256Syl150051 	xge_hal_status_e status;
21431256Syl150051 	int retsize;
21441256Syl150051 	char *buf;
21451256Syl150051 
21461256Syl150051 	buf = kmem_alloc(XGELL_PCICONF_BUFSIZE, KM_SLEEP);
21471256Syl150051 	if (buf == NULL) {
21481256Syl150051 		return (ENOSPC);
21491256Syl150051 	}
21501256Syl150051 	status = xge_hal_aux_pci_config_read(lldev->devh, XGELL_PCICONF_BUFSIZE,
21511256Syl150051 	    buf, &retsize);
21521256Syl150051 	if (status != XGE_HAL_OK) {
21531256Syl150051 		kmem_free(buf, XGELL_PCICONF_BUFSIZE);
21541256Syl150051 		xge_debug_ll(XGE_ERR, "pci_config_read(): status %d", status);
21551256Syl150051 		return (EINVAL);
21561256Syl150051 	}
21571256Syl150051 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
21581256Syl150051 	(void) mi_mpprintf(mp, "%s", buf);
21591256Syl150051 	kmem_free(buf, XGELL_PCICONF_BUFSIZE);
21601256Syl150051 
21611256Syl150051 	return (0);
21621256Syl150051 }
21631256Syl150051 
21641256Syl150051 static int
21651256Syl150051 xgell_about_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
21661256Syl150051 {
21671256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)cp;
21681256Syl150051 	xge_hal_status_e status;
21691256Syl150051 	int retsize;
21701256Syl150051 	char *buf;
21711256Syl150051 
21721256Syl150051 	buf = kmem_alloc(XGELL_ABOUT_BUFSIZE, KM_SLEEP);
21731256Syl150051 	if (buf == NULL) {
21741256Syl150051 		return (ENOSPC);
21751256Syl150051 	}
21761256Syl150051 	status = xge_hal_aux_about_read(lldev->devh, XGELL_ABOUT_BUFSIZE,
21771256Syl150051 	    buf, &retsize);
21781256Syl150051 	if (status != XGE_HAL_OK) {
21791256Syl150051 		kmem_free(buf, XGELL_ABOUT_BUFSIZE);
21801256Syl150051 		xge_debug_ll(XGE_ERR, "about_read(): status %d", status);
21811256Syl150051 		return (EINVAL);
21821256Syl150051 	}
21831256Syl150051 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
21841256Syl150051 	(void) mi_mpprintf(mp, "%s", buf);
21851256Syl150051 	kmem_free(buf, XGELL_ABOUT_BUFSIZE);
21861256Syl150051 
21871256Syl150051 	return (0);
21881256Syl150051 }
21891256Syl150051 
21901256Syl150051 static unsigned long bar0_offset = 0x110; /* adapter_control */
21911256Syl150051 
21921256Syl150051 static int
21931256Syl150051 xgell_bar0_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
21941256Syl150051 {
21951256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)cp;
21961256Syl150051 	xge_hal_status_e status;
21971256Syl150051 	int retsize;
21981256Syl150051 	char *buf;
21991256Syl150051 
22001256Syl150051 	buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
22011256Syl150051 	if (buf == NULL) {
22021256Syl150051 		return (ENOSPC);
22031256Syl150051 	}
22041256Syl150051 	status = xge_hal_aux_bar0_read(lldev->devh, bar0_offset,
22051256Syl150051 	    XGELL_IOCTL_BUFSIZE, buf, &retsize);
22061256Syl150051 	if (status != XGE_HAL_OK) {
22071256Syl150051 		kmem_free(buf, XGELL_IOCTL_BUFSIZE);
22081256Syl150051 		xge_debug_ll(XGE_ERR, "bar0_read(): status %d", status);
22091256Syl150051 		return (EINVAL);
22101256Syl150051 	}
22111256Syl150051 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
22121256Syl150051 	(void) mi_mpprintf(mp, "%s", buf);
22131256Syl150051 	kmem_free(buf, XGELL_IOCTL_BUFSIZE);
22141256Syl150051 
22151256Syl150051 	return (0);
22161256Syl150051 }
22171256Syl150051 
22181256Syl150051 static int
22191256Syl150051 xgell_bar0_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *credp)
22201256Syl150051 {
22211256Syl150051 	unsigned long old_offset = bar0_offset;
22221256Syl150051 	char *end;
22231256Syl150051 
22241256Syl150051 	if (value && *value == '0' &&
22251256Syl150051 	    (*(value + 1) == 'x' || *(value + 1) == 'X')) {
22261256Syl150051 		value += 2;
22271256Syl150051 	}
22281256Syl150051 
22291256Syl150051 	bar0_offset = mi_strtol(value, &end, 16);
22301256Syl150051 	if (end == value) {
22311256Syl150051 		bar0_offset = old_offset;
22321256Syl150051 		return (EINVAL);
22331256Syl150051 	}
22341256Syl150051 
22351256Syl150051 	xge_debug_ll(XGE_TRACE, "bar0: new value %s:%lX", value, bar0_offset);
22361256Syl150051 
22371256Syl150051 	return (0);
22381256Syl150051 }
22391256Syl150051 
22401256Syl150051 static int
22411256Syl150051 xgell_debug_level_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
22421256Syl150051 {
22431256Syl150051 	char *buf;
22441256Syl150051 
22451256Syl150051 	buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
22461256Syl150051 	if (buf == NULL) {
22471256Syl150051 		return (ENOSPC);
22481256Syl150051 	}
22491256Syl150051 	(void) mi_mpprintf(mp, "debug_level %d", xge_hal_driver_debug_level());
22501256Syl150051 	kmem_free(buf, XGELL_IOCTL_BUFSIZE);
22511256Syl150051 
22521256Syl150051 	return (0);
22531256Syl150051 }
22541256Syl150051 
22551256Syl150051 static int
22561256Syl150051 xgell_debug_level_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
22571256Syl150051     cred_t *credp)
22581256Syl150051 {
22591256Syl150051 	int level;
22601256Syl150051 	char *end;
22611256Syl150051 
22621256Syl150051 	level = mi_strtol(value, &end, 10);
22631256Syl150051 	if (level < XGE_NONE || level > XGE_ERR || end == value) {
22641256Syl150051 		return (EINVAL);
22651256Syl150051 	}
22661256Syl150051 
22671256Syl150051 	xge_hal_driver_debug_level_set(level);
22681256Syl150051 
22691256Syl150051 	return (0);
22701256Syl150051 }
22711256Syl150051 
22721256Syl150051 static int
22731256Syl150051 xgell_debug_module_mask_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
22741256Syl150051 {
22751256Syl150051 	char *buf;
22761256Syl150051 
22771256Syl150051 	buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
22781256Syl150051 	if (buf == NULL) {
22791256Syl150051 		return (ENOSPC);
22801256Syl150051 	}
22811256Syl150051 	(void) mi_mpprintf(mp, "debug_module_mask 0x%08x",
22821256Syl150051 	    xge_hal_driver_debug_module_mask());
22831256Syl150051 	kmem_free(buf, XGELL_IOCTL_BUFSIZE);
22841256Syl150051 
22851256Syl150051 	return (0);
22861256Syl150051 }
22871256Syl150051 
22881256Syl150051 static int
22891256Syl150051 xgell_debug_module_mask_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
22901256Syl150051 			    cred_t *credp)
22911256Syl150051 {
22921256Syl150051 	u32 mask;
22931256Syl150051 	char *end;
22941256Syl150051 
22951256Syl150051 	if (value && *value == '0' &&
22961256Syl150051 	    (*(value + 1) == 'x' || *(value + 1) == 'X')) {
22971256Syl150051 		value += 2;
22981256Syl150051 	}
22991256Syl150051 
23001256Syl150051 	mask = mi_strtol(value, &end, 16);
23011256Syl150051 	if (end == value) {
23021256Syl150051 		return (EINVAL);
23031256Syl150051 	}
23041256Syl150051 
23051256Syl150051 	xge_hal_driver_debug_module_mask_set(mask);
23061256Syl150051 
23071256Syl150051 	return (0);
23081256Syl150051 }
23091256Syl150051 
23101256Syl150051 static int
23111256Syl150051 xgell_devconfig_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
23121256Syl150051 {
23131256Syl150051 	xgelldev_t *lldev = (xgelldev_t *)(void *)cp;
23141256Syl150051 	xge_hal_status_e status;
23151256Syl150051 	int retsize;
23161256Syl150051 	char *buf;
23171256Syl150051 
23181256Syl150051 	buf = kmem_alloc(XGELL_DEVCONF_BUFSIZE, KM_SLEEP);
23191256Syl150051 	if (buf == NULL) {
23201256Syl150051 		return (ENOSPC);
23211256Syl150051 	}
23221256Syl150051 	status = xge_hal_aux_device_config_read(lldev->devh,
2323*6937Sxw161283 	    XGELL_DEVCONF_BUFSIZE,
2324*6937Sxw161283 	    buf, &retsize);
23251256Syl150051 	if (status != XGE_HAL_OK) {
23261256Syl150051 		kmem_free(buf, XGELL_DEVCONF_BUFSIZE);
23271256Syl150051 		xge_debug_ll(XGE_ERR, "device_config_read(): status %d",
23281256Syl150051 		    status);
23291256Syl150051 		return (EINVAL);
23301256Syl150051 	}
23311256Syl150051 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
23321256Syl150051 	(void) mi_mpprintf(mp, "%s", buf);
23331256Syl150051 	kmem_free(buf, XGELL_DEVCONF_BUFSIZE);
23341256Syl150051 
23351256Syl150051 	return (0);
23361256Syl150051 }
23371256Syl150051 
23381256Syl150051 /*
23391256Syl150051  * xgell_device_register
23401256Syl150051  * @devh: pointer on HAL device
23411256Syl150051  * @config: pointer on this network device configuration
23421256Syl150051  * @ll_out: output pointer. Will be assigned to valid LL device.
23431256Syl150051  *
23441256Syl150051  * This function will allocate and register network device
23451256Syl150051  */
23461256Syl150051 int
23471256Syl150051 xgell_device_register(xgelldev_t *lldev, xgell_config_t *config)
23481256Syl150051 {
23493115Syl150051 	mac_register_t *macp = NULL;
23501256Syl150051 	xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh;
23511256Syl150051 
23521256Syl150051 	if (nd_load(&lldev->ndp, "pciconf", xgell_pciconf_get, NULL,
23532311Sseb 	    (caddr_t)lldev) == B_FALSE)
23542311Sseb 		goto xgell_ndd_fail;
23551256Syl150051 
23561256Syl150051 	if (nd_load(&lldev->ndp, "about", xgell_about_get, NULL,
23572311Sseb 	    (caddr_t)lldev) == B_FALSE)
23582311Sseb 		goto xgell_ndd_fail;
23591256Syl150051 
23601256Syl150051 	if (nd_load(&lldev->ndp, "stats", xgell_stats_get, NULL,
23612311Sseb 	    (caddr_t)lldev) == B_FALSE)
23622311Sseb 		goto xgell_ndd_fail;
23631256Syl150051 
23641256Syl150051 	if (nd_load(&lldev->ndp, "bar0", xgell_bar0_get, xgell_bar0_set,
23652311Sseb 	    (caddr_t)lldev) == B_FALSE)
23662311Sseb 		goto xgell_ndd_fail;
23671256Syl150051 
23681256Syl150051 	if (nd_load(&lldev->ndp, "debug_level", xgell_debug_level_get,
23692311Sseb 	    xgell_debug_level_set, (caddr_t)lldev) == B_FALSE)
23702311Sseb 		goto xgell_ndd_fail;
23711256Syl150051 
23721256Syl150051 	if (nd_load(&lldev->ndp, "debug_module_mask",
23731256Syl150051 	    xgell_debug_module_mask_get, xgell_debug_module_mask_set,
23742311Sseb 	    (caddr_t)lldev) == B_FALSE)
23752311Sseb 		goto xgell_ndd_fail;
23761256Syl150051 
23771256Syl150051 	if (nd_load(&lldev->ndp, "devconfig", xgell_devconfig_get, NULL,
23782311Sseb 	    (caddr_t)lldev) == B_FALSE)
23792311Sseb 		goto xgell_ndd_fail;
23801256Syl150051 
23811256Syl150051 	bcopy(config, &lldev->config, sizeof (xgell_config_t));
23821256Syl150051 
2383*6937Sxw161283 	mutex_init(&lldev->genlock, NULL, MUTEX_DRIVER,
2384*6937Sxw161283 	    DDI_INTR_PRI(hldev->irqh));
23851256Syl150051 
23862311Sseb 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
23872311Sseb 		goto xgell_register_fail;
23882311Sseb 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
23893115Syl150051 	macp->m_driver = lldev;
23902311Sseb 	macp->m_dip = lldev->dev_info;
23912311Sseb 	macp->m_src_addr = hldev->macaddr[0];
23922311Sseb 	macp->m_callbacks = &xgell_m_callbacks;
23932311Sseb 	macp->m_min_sdu = 0;
23942311Sseb 	macp->m_max_sdu = hldev->config.mtu;
23955895Syz147064 	macp->m_margin = VLAN_TAGSZ;
23961256Syl150051 	/*
23971256Syl150051 	 * Finally, we're ready to register ourselves with the Nemo
23981256Syl150051 	 * interface; if this succeeds, we're all ready to start()
23991256Syl150051 	 */
24003115Syl150051 
24013115Syl150051 	if (mac_register(macp, &lldev->mh) != 0)
24022311Sseb 		goto xgell_register_fail;
24031256Syl150051 
24043392Syl150051 	/* Always free the macp after register */
24053392Syl150051 	if (macp != NULL)
24063392Syl150051 		mac_free(macp);
24073392Syl150051 
24083115Syl150051 	/* Calculate tx_copied_max here ??? */
24093115Syl150051 	lldev->tx_copied_max = hldev->config.fifo.max_frags *
2410*6937Sxw161283 	    hldev->config.fifo.alignment_size *
2411*6937Sxw161283 	    hldev->config.fifo.max_aligned_frags;
24123115Syl150051 
24131256Syl150051 	xge_debug_ll(XGE_TRACE, "etherenet device %s%d registered",
24141256Syl150051 	    XGELL_IFNAME, lldev->instance);
24151256Syl150051 
24161256Syl150051 	return (DDI_SUCCESS);
24172311Sseb 
24182311Sseb xgell_ndd_fail:
24192311Sseb 	nd_free(&lldev->ndp);
24202311Sseb 	xge_debug_ll(XGE_ERR, "%s", "unable to load ndd parameter");
24212311Sseb 	return (DDI_FAILURE);
24222311Sseb 
24232311Sseb xgell_register_fail:
24243115Syl150051 	if (macp != NULL)
24253115Syl150051 		mac_free(macp);
24262311Sseb 	nd_free(&lldev->ndp);
24272311Sseb 	mutex_destroy(&lldev->genlock);
24282311Sseb 	xge_debug_ll(XGE_ERR, "%s", "unable to register networking device");
24292311Sseb 	return (DDI_FAILURE);
24301256Syl150051 }
24311256Syl150051 
24321256Syl150051 /*
24331256Syl150051  * xgell_device_unregister
24341256Syl150051  * @devh: pointer on HAL device
24351256Syl150051  * @lldev: pointer to valid LL device.
24361256Syl150051  *
24371256Syl150051  * This function will unregister and free network device
24381256Syl150051  */
24391256Syl150051 int
24401256Syl150051 xgell_device_unregister(xgelldev_t *lldev)
24411256Syl150051 {
24422311Sseb 	if (mac_unregister(lldev->mh) != 0) {
24431256Syl150051 		xge_debug_ll(XGE_ERR, "unable to unregister device %s%d",
24441256Syl150051 		    XGELL_IFNAME, lldev->instance);
24451256Syl150051 		return (DDI_FAILURE);
24461256Syl150051 	}
24471256Syl150051 
24481256Syl150051 	mutex_destroy(&lldev->genlock);
24491256Syl150051 
24501256Syl150051 	nd_free(&lldev->ndp);
24511256Syl150051 
24521256Syl150051 	xge_debug_ll(XGE_TRACE, "etherenet device %s%d unregistered",
24531256Syl150051 	    XGELL_IFNAME, lldev->instance);
24541256Syl150051 
24551256Syl150051 	return (DDI_SUCCESS);
24561256Syl150051 }
2457