xref: /illumos-gate/usr/src/uts/common/io/xge/drv/xgell.c (revision 3c785c4c)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 #pragma ident	"%Z%%M%	%I%	%E% SMI"
28 
29 /*
30  *  Copyright (c) 2002-2005 Neterion, Inc.
31  *  All right Reserved.
32  *
33  *  FileName :    xgell.c
34  *
35  *  Description:  Xge Link Layer data path implementation
36  *
37  */
38 
39 #include "xgell.h"
40 
41 #include <netinet/ip.h>
42 #include <netinet/tcp.h>
43 #include <netinet/udp.h>
44 
45 #define	XGELL_MAX_FRAME_SIZE(hldev)	((hldev)->config.mtu +	\
46     sizeof (struct ether_vlan_header))
47 
48 #define	HEADROOM		2	/* for DIX-only packets */
49 
50 void header_free_func(void *arg) { }
51 frtn_t header_frtn = {header_free_func, NULL};
52 
53 /* DMA attributes used for Tx side */
54 static struct ddi_dma_attr tx_dma_attr = {
55 	DMA_ATTR_V0,			/* dma_attr_version */
56 	0x0ULL,				/* dma_attr_addr_lo */
57 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_addr_hi */
58 	0xFFFFFFFFULL,			/* dma_attr_count_max */
59 	0x1ULL,				/* dma_attr_align */
60 	0xFFF,				/* dma_attr_burstsizes */
61 	1,				/* dma_attr_minxfer */
62 	0xFFFFFFFFULL,			/* dma_attr_maxxfer */
63 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_seg */
64 	18,				/* dma_attr_sgllen */
65 	1,				/* dma_attr_granular */
66 	0				/* dma_attr_flags */
67 };
68 
69 /* Aligned DMA attributes used for Tx side */
70 struct ddi_dma_attr tx_dma_attr_align = {
71 	DMA_ATTR_V0,			/* dma_attr_version */
72 	0x0ULL,				/* dma_attr_addr_lo */
73 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_addr_hi */
74 	0xFFFFFFFFULL,			/* dma_attr_count_max */
75 	4096,				/* dma_attr_align */
76 	0xFFF,				/* dma_attr_burstsizes */
77 	1,				/* dma_attr_minxfer */
78 	0xFFFFFFFFULL,			/* dma_attr_maxxfer */
79 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_seg */
80 	4,				/* dma_attr_sgllen */
81 	1,				/* dma_attr_granular */
82 	0				/* dma_attr_flags */
83 };
84 
85 /*
86  * DMA attributes used when using ddi_dma_mem_alloc to
87  * allocat HAL descriptors and Rx buffers during replenish
88  */
89 static struct ddi_dma_attr hal_dma_attr = {
90 	DMA_ATTR_V0,			/* dma_attr_version */
91 	0x0ULL,				/* dma_attr_addr_lo */
92 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_addr_hi */
93 	0xFFFFFFFFULL,			/* dma_attr_count_max */
94 	0x1ULL,				/* dma_attr_align */
95 	0xFFF,				/* dma_attr_burstsizes */
96 	1,				/* dma_attr_minxfer */
97 	0xFFFFFFFFULL,			/* dma_attr_maxxfer */
98 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_seg */
99 	1,				/* dma_attr_sgllen */
100 	1,				/* dma_attr_granular */
101 	0				/* dma_attr_flags */
102 };
103 
104 /*
105  * Aligned DMA attributes used when using ddi_dma_mem_alloc to
106  * allocat HAL descriptors and Rx buffers during replenish
107  */
108 struct ddi_dma_attr hal_dma_attr_aligned = {
109 	DMA_ATTR_V0,			/* dma_attr_version */
110 	0x0ULL,				/* dma_attr_addr_lo */
111 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_addr_hi */
112 	0xFFFFFFFFULL,			/* dma_attr_count_max */
113 	4096,				/* dma_attr_align */
114 	0xFFF,				/* dma_attr_burstsizes */
115 	1,				/* dma_attr_minxfer */
116 	0xFFFFFFFFULL,			/* dma_attr_maxxfer */
117 	0xFFFFFFFFFFFFFFFFULL,		/* dma_attr_seg */
118 	1,				/* dma_attr_sgllen */
119 	1,				/* dma_attr_granular */
120 	0				/* dma_attr_flags */
121 };
122 
123 struct ddi_dma_attr *p_hal_dma_attr = &hal_dma_attr;
124 struct ddi_dma_attr *p_hal_dma_attr_aligned = &hal_dma_attr_aligned;
125 
126 static int		xgell_m_stat(void *, uint_t, uint64_t *);
127 static int		xgell_m_start(void *);
128 static void		xgell_m_stop(void *);
129 static int		xgell_m_promisc(void *, boolean_t);
130 static int		xgell_m_multicst(void *, boolean_t, const uint8_t *);
131 static int		xgell_m_unicst(void *, const uint8_t *);
132 static void		xgell_m_ioctl(void *, queue_t *, mblk_t *);
133 static mblk_t 		*xgell_m_tx(void *, mblk_t *);
134 static boolean_t	xgell_m_getcapab(void *, mac_capab_t, void *);
135 
136 #define	XGELL_M_CALLBACK_FLAGS	(MC_IOCTL | MC_GETCAPAB)
137 
138 static mac_callbacks_t xgell_m_callbacks = {
139 	XGELL_M_CALLBACK_FLAGS,
140 	xgell_m_stat,
141 	xgell_m_start,
142 	xgell_m_stop,
143 	xgell_m_promisc,
144 	xgell_m_multicst,
145 	xgell_m_unicst,
146 	xgell_m_tx,
147 	NULL,
148 	xgell_m_ioctl,
149 	xgell_m_getcapab
150 };
151 
152 /*
153  * xge_device_poll
154  *
155  * Cyclic should call me every 1s. xge_callback_event_queued should call me
156  * when HAL hope event was rescheduled.
157  */
158 /*ARGSUSED*/
159 void
160 xge_device_poll(void *data)
161 {
162 	xgelldev_t *lldev = xge_hal_device_private(data);
163 
164 	mutex_enter(&lldev->genlock);
165 	if (lldev->is_initialized) {
166 		xge_hal_device_poll(data);
167 		lldev->timeout_id = timeout(xge_device_poll, data,
168 		    XGE_DEV_POLL_TICKS);
169 	} else if (lldev->in_reset == 1) {
170 		lldev->timeout_id = timeout(xge_device_poll, data,
171 		    XGE_DEV_POLL_TICKS);
172 	} else {
173 		lldev->timeout_id = 0;
174 	}
175 	mutex_exit(&lldev->genlock);
176 }
177 
178 /*
179  * xge_device_poll_now
180  *
181  * Will call xge_device_poll() immediately
182  */
183 void
184 xge_device_poll_now(void *data)
185 {
186 	xgelldev_t *lldev = xge_hal_device_private(data);
187 
188 	mutex_enter(&lldev->genlock);
189 	if (lldev->is_initialized) {
190 		xge_hal_device_poll(data);
191 	}
192 	mutex_exit(&lldev->genlock);
193 }
194 
195 /*
196  * xgell_callback_link_up
197  *
198  * This function called by HAL to notify HW link up state change.
199  */
200 void
201 xgell_callback_link_up(void *userdata)
202 {
203 	xgelldev_t *lldev = (xgelldev_t *)userdata;
204 
205 	mac_link_update(lldev->mh, LINK_STATE_UP);
206 	/* Link states should be reported to user whenever it changes */
207 	cmn_err(CE_NOTE, "!%s%d: Link is up [10 Gbps Full Duplex]",
208 	    XGELL_IFNAME, lldev->instance);
209 }
210 
211 /*
212  * xgell_callback_link_down
213  *
214  * This function called by HAL to notify HW link down state change.
215  */
216 void
217 xgell_callback_link_down(void *userdata)
218 {
219 	xgelldev_t *lldev = (xgelldev_t *)userdata;
220 
221 	mac_link_update(lldev->mh, LINK_STATE_DOWN);
222 	/* Link states should be reported to user whenever it changes */
223 	cmn_err(CE_NOTE, "!%s%d: Link is down", XGELL_IFNAME,
224 	    lldev->instance);
225 }
226 
227 /*
228  * xgell_rx_buffer_replenish_all
229  *
230  * To replenish all freed dtr(s) with buffers in free pool. It's called by
231  * xgell_rx_buffer_recycle() or xgell_rx_1b_compl().
232  * Must be called with pool_lock held.
233  */
234 static void
235 xgell_rx_buffer_replenish_all(xgelldev_t *lldev)
236 {
237 	xge_hal_dtr_h dtr;
238 	xgell_rx_buffer_t *rx_buffer;
239 	xgell_rxd_priv_t *rxd_priv;
240 
241 	xge_assert(mutex_owned(&lldev->bf_pool.pool_lock));
242 
243 	while ((lldev->bf_pool.free > 0) &&
244 	    (xge_hal_ring_dtr_reserve(lldev->ring_main.channelh, &dtr) ==
245 	    XGE_HAL_OK)) {
246 		rx_buffer = lldev->bf_pool.head;
247 		lldev->bf_pool.head = rx_buffer->next;
248 		lldev->bf_pool.free--;
249 
250 		xge_assert(rx_buffer);
251 		xge_assert(rx_buffer->dma_addr);
252 
253 		rxd_priv = (xgell_rxd_priv_t *)
254 		    xge_hal_ring_dtr_private(lldev->ring_main.channelh, dtr);
255 		xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr,
256 		    lldev->bf_pool.size);
257 
258 		rxd_priv->rx_buffer = rx_buffer;
259 		xge_hal_ring_dtr_post(lldev->ring_main.channelh, dtr);
260 	}
261 }
262 
263 /*
264  * xgell_rx_buffer_release
265  *
266  * The only thing done here is to put the buffer back to the pool.
267  * Calling this function need be protected by mutex, bf_pool.pool_lock.
268  */
269 static void
270 xgell_rx_buffer_release(xgell_rx_buffer_t *rx_buffer)
271 {
272 	xgelldev_t *lldev = rx_buffer->lldev;
273 
274 	xge_assert(mutex_owned(&lldev->bf_pool.pool_lock));
275 
276 	/* Put the buffer back to pool */
277 	rx_buffer->next = lldev->bf_pool.head;
278 	lldev->bf_pool.head = rx_buffer;
279 
280 	lldev->bf_pool.free++;
281 }
282 
283 /*
284  * xgell_rx_buffer_recycle
285  *
286  * Called by desballoc() to "free" the resource.
287  * We will try to replenish all descripters.
288  */
289 static void
290 xgell_rx_buffer_recycle(char *arg)
291 {
292 	xgell_rx_buffer_t *rx_buffer = (xgell_rx_buffer_t *)arg;
293 	xgelldev_t *lldev = rx_buffer->lldev;
294 
295 	mutex_enter(&lldev->bf_pool.pool_lock);
296 
297 	xgell_rx_buffer_release(rx_buffer);
298 	lldev->bf_pool.post--;
299 
300 	/*
301 	 * Before finding a good way to set this hiwat, just always call to
302 	 * replenish_all. *TODO*
303 	 */
304 	if (lldev->is_initialized != 0) {
305 		xgell_rx_buffer_replenish_all(lldev);
306 	}
307 
308 	mutex_exit(&lldev->bf_pool.pool_lock);
309 }
310 
311 /*
312  * xgell_rx_buffer_alloc
313  *
314  * Allocate one rx buffer and return with the pointer to the buffer.
315  * Return NULL if failed.
316  */
317 static xgell_rx_buffer_t *
318 xgell_rx_buffer_alloc(xgelldev_t *lldev)
319 {
320 	xge_hal_device_t *hldev;
321 	void *vaddr;
322 	ddi_dma_handle_t dma_handle;
323 	ddi_acc_handle_t dma_acch;
324 	dma_addr_t dma_addr;
325 	uint_t ncookies;
326 	ddi_dma_cookie_t dma_cookie;
327 	size_t real_size;
328 	extern ddi_device_acc_attr_t *p_xge_dev_attr;
329 	xgell_rx_buffer_t *rx_buffer;
330 
331 	hldev = (xge_hal_device_t *)lldev->devh;
332 
333 	if (ddi_dma_alloc_handle(hldev->pdev, p_hal_dma_attr, DDI_DMA_SLEEP,
334 	    0, &dma_handle) != DDI_SUCCESS) {
335 		xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA handle",
336 		    XGELL_IFNAME, lldev->instance);
337 		goto handle_failed;
338 	}
339 
340 	/* reserve some space at the end of the buffer for recycling */
341 	if (ddi_dma_mem_alloc(dma_handle, HEADROOM + lldev->bf_pool.size +
342 	    sizeof (xgell_rx_buffer_t), p_xge_dev_attr, DDI_DMA_STREAMING,
343 	    DDI_DMA_SLEEP, 0, (caddr_t *)&vaddr, &real_size, &dma_acch) !=
344 	    DDI_SUCCESS) {
345 		xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory",
346 		    XGELL_IFNAME, lldev->instance);
347 		goto mem_failed;
348 	}
349 
350 	if (HEADROOM + lldev->bf_pool.size + sizeof (xgell_rx_buffer_t) >
351 	    real_size) {
352 		xge_debug_ll(XGE_ERR, "%s%d: can not allocate DMA-able memory",
353 		    XGELL_IFNAME, lldev->instance);
354 		goto bind_failed;
355 	}
356 
357 	if (ddi_dma_addr_bind_handle(dma_handle, NULL, (char *)vaddr + HEADROOM,
358 	    lldev->bf_pool.size, DDI_DMA_READ | DDI_DMA_STREAMING,
359 	    DDI_DMA_SLEEP, 0, &dma_cookie, &ncookies) != DDI_SUCCESS) {
360 		xge_debug_ll(XGE_ERR, "%s%d: out of mapping for mblk",
361 		    XGELL_IFNAME, lldev->instance);
362 		goto bind_failed;
363 	}
364 
365 	if (ncookies != 1 || dma_cookie.dmac_size < lldev->bf_pool.size) {
366 		xge_debug_ll(XGE_ERR, "%s%d: can not handle partial DMA",
367 		    XGELL_IFNAME, lldev->instance);
368 		goto check_failed;
369 	}
370 
371 	dma_addr = dma_cookie.dmac_laddress;
372 
373 	rx_buffer = (xgell_rx_buffer_t *)((char *)vaddr + real_size -
374 	    sizeof (xgell_rx_buffer_t));
375 	rx_buffer->next = NULL;
376 	rx_buffer->vaddr = vaddr;
377 	rx_buffer->dma_addr = dma_addr;
378 	rx_buffer->dma_handle = dma_handle;
379 	rx_buffer->dma_acch = dma_acch;
380 	rx_buffer->lldev = lldev;
381 	rx_buffer->frtn.free_func = xgell_rx_buffer_recycle;
382 	rx_buffer->frtn.free_arg = (void *)rx_buffer;
383 
384 	return (rx_buffer);
385 
386 check_failed:
387 	(void) ddi_dma_unbind_handle(dma_handle);
388 bind_failed:
389 	XGE_OS_MEMORY_CHECK_FREE(vaddr, 0);
390 	ddi_dma_mem_free(&dma_acch);
391 mem_failed:
392 	ddi_dma_free_handle(&dma_handle);
393 handle_failed:
394 
395 	return (NULL);
396 }
397 
398 /*
399  * xgell_rx_destroy_buffer_pool
400  *
401  * Destroy buffer pool. If there is still any buffer hold by upper layer,
402  * recorded by bf_pool.post, return DDI_FAILURE to reject to be unloaded.
403  */
404 static int
405 xgell_rx_destroy_buffer_pool(xgelldev_t *lldev)
406 {
407 	xgell_rx_buffer_t *rx_buffer;
408 	ddi_dma_handle_t  dma_handle;
409 	ddi_acc_handle_t  dma_acch;
410 	int i;
411 
412 	/*
413 	 * If there is any posted buffer, the driver should reject to be
414 	 * detached. Need notice upper layer to release them.
415 	 */
416 	if (lldev->bf_pool.post != 0) {
417 		xge_debug_ll(XGE_ERR,
418 		    "%s%d has some buffers not be recycled, try later!",
419 		    XGELL_IFNAME, lldev->instance);
420 		return (DDI_FAILURE);
421 	}
422 
423 	/*
424 	 * Relase buffers one by one.
425 	 */
426 	for (i = lldev->bf_pool.total; i > 0; i--) {
427 		rx_buffer = lldev->bf_pool.head;
428 		xge_assert(rx_buffer != NULL);
429 
430 		lldev->bf_pool.head = rx_buffer->next;
431 
432 		dma_handle = rx_buffer->dma_handle;
433 		dma_acch = rx_buffer->dma_acch;
434 
435 		if (ddi_dma_unbind_handle(dma_handle) != DDI_SUCCESS) {
436 			xge_debug_ll(XGE_ERR, "failed to unbind DMA handle!");
437 			lldev->bf_pool.head = rx_buffer;
438 			return (DDI_FAILURE);
439 		}
440 		ddi_dma_mem_free(&dma_acch);
441 		ddi_dma_free_handle(&dma_handle);
442 
443 		lldev->bf_pool.total--;
444 		lldev->bf_pool.free--;
445 	}
446 
447 	mutex_destroy(&lldev->bf_pool.pool_lock);
448 	return (DDI_SUCCESS);
449 }
450 
451 /*
452  * xgell_rx_create_buffer_pool
453  *
454  * Initialize RX buffer pool for all RX rings. Refer to rx_buffer_pool_t.
455  */
456 static int
457 xgell_rx_create_buffer_pool(xgelldev_t *lldev)
458 {
459 	xge_hal_device_t *hldev;
460 	xgell_rx_buffer_t *rx_buffer;
461 	int i;
462 
463 	hldev = (xge_hal_device_t *)lldev->devh;
464 
465 	lldev->bf_pool.total = 0;
466 	lldev->bf_pool.size = XGELL_MAX_FRAME_SIZE(hldev);
467 	lldev->bf_pool.head = NULL;
468 	lldev->bf_pool.free = 0;
469 	lldev->bf_pool.post = 0;
470 	lldev->bf_pool.post_hiwat = lldev->config.rx_buffer_post_hiwat;
471 
472 	mutex_init(&lldev->bf_pool.pool_lock, NULL, MUTEX_DRIVER,
473 	    hldev->irqh);
474 
475 	/*
476 	 * Allocate buffers one by one. If failed, destroy whole pool by
477 	 * call to xgell_rx_destroy_buffer_pool().
478 	 */
479 	for (i = 0; i < lldev->config.rx_buffer_total; i++) {
480 		if ((rx_buffer = xgell_rx_buffer_alloc(lldev)) == NULL) {
481 			(void) xgell_rx_destroy_buffer_pool(lldev);
482 			return (DDI_FAILURE);
483 		}
484 
485 		rx_buffer->next = lldev->bf_pool.head;
486 		lldev->bf_pool.head = rx_buffer;
487 
488 		lldev->bf_pool.total++;
489 		lldev->bf_pool.free++;
490 	}
491 
492 	return (DDI_SUCCESS);
493 }
494 
495 /*
496  * xgell_rx_dtr_replenish
497  *
498  * Replenish descriptor with rx_buffer in RX buffer pool.
499  * The dtr should be post right away.
500  */
501 xge_hal_status_e
502 xgell_rx_dtr_replenish(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, int index,
503     void *userdata, xge_hal_channel_reopen_e reopen)
504 {
505 	xgell_ring_t *ring = userdata;
506 	xgelldev_t *lldev = ring->lldev;
507 	xgell_rx_buffer_t *rx_buffer;
508 	xgell_rxd_priv_t *rxd_priv;
509 
510 	if (lldev->bf_pool.head == NULL) {
511 		xge_debug_ll(XGE_ERR, "no more available rx DMA buffer!");
512 		return (XGE_HAL_FAIL);
513 	}
514 	rx_buffer = lldev->bf_pool.head;
515 	lldev->bf_pool.head = rx_buffer->next;
516 	lldev->bf_pool.free--;
517 
518 	xge_assert(rx_buffer);
519 	xge_assert(rx_buffer->dma_addr);
520 
521 	rxd_priv = (xgell_rxd_priv_t *)
522 	    xge_hal_ring_dtr_private(lldev->ring_main.channelh, dtr);
523 	xge_hal_ring_dtr_1b_set(dtr, rx_buffer->dma_addr, lldev->bf_pool.size);
524 
525 	rxd_priv->rx_buffer = rx_buffer;
526 
527 	return (XGE_HAL_OK);
528 }
529 
530 /*
531  * xgell_get_ip_offset
532  *
533  * Calculate the offset to IP header.
534  */
535 static inline int
536 xgell_get_ip_offset(xge_hal_dtr_info_t *ext_info)
537 {
538 	int ip_off;
539 
540 	/* get IP-header offset */
541 	switch (ext_info->frame) {
542 	case XGE_HAL_FRAME_TYPE_DIX:
543 		ip_off = XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE;
544 		break;
545 	case XGE_HAL_FRAME_TYPE_IPX:
546 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
547 		    XGE_HAL_HEADER_802_2_SIZE +
548 		    XGE_HAL_HEADER_SNAP_SIZE);
549 		break;
550 	case XGE_HAL_FRAME_TYPE_LLC:
551 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
552 		    XGE_HAL_HEADER_802_2_SIZE);
553 		break;
554 	case XGE_HAL_FRAME_TYPE_SNAP:
555 		ip_off = (XGE_HAL_HEADER_ETHERNET_II_802_3_SIZE +
556 		    XGE_HAL_HEADER_SNAP_SIZE);
557 		break;
558 	default:
559 		ip_off = 0;
560 		break;
561 	}
562 
563 	if ((ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4 ||
564 	    ext_info->proto & XGE_HAL_FRAME_PROTO_IPV6) &&
565 	    (ext_info->proto & XGE_HAL_FRAME_PROTO_VLAN_TAGGED)) {
566 		ip_off += XGE_HAL_HEADER_VLAN_SIZE;
567 	}
568 
569 	return (ip_off);
570 }
571 
572 /*
573  * xgell_rx_hcksum_assoc
574  *
575  * Judge the packet type and then call to hcksum_assoc() to associate
576  * h/w checksum information.
577  */
578 static inline void
579 xgell_rx_hcksum_assoc(mblk_t *mp, char *vaddr, int pkt_length,
580     xge_hal_dtr_info_t *ext_info)
581 {
582 	int cksum_flags = 0;
583 
584 	if (!(ext_info->proto & XGE_HAL_FRAME_PROTO_IP_FRAGMENTED)) {
585 		if (ext_info->proto & XGE_HAL_FRAME_PROTO_TCP_OR_UDP) {
586 			if (ext_info->l3_cksum == XGE_HAL_L3_CKSUM_OK) {
587 				cksum_flags |= HCK_IPV4_HDRCKSUM;
588 			}
589 			if (ext_info->l4_cksum == XGE_HAL_L4_CKSUM_OK) {
590 				cksum_flags |= HCK_FULLCKSUM_OK;
591 			}
592 			if (cksum_flags) {
593 				cksum_flags |= HCK_FULLCKSUM;
594 				(void) hcksum_assoc(mp, NULL, NULL, 0,
595 				    0, 0, 0, cksum_flags, 0);
596 			}
597 		}
598 	} else if (ext_info->proto &
599 	    (XGE_HAL_FRAME_PROTO_IPV4 | XGE_HAL_FRAME_PROTO_IPV6)) {
600 		/*
601 		 * Just pass the partial cksum up to IP.
602 		 */
603 		int ip_off = xgell_get_ip_offset(ext_info);
604 		int start, end = pkt_length - ip_off;
605 
606 		if (ext_info->proto & XGE_HAL_FRAME_PROTO_IPV4) {
607 			struct ip *ip =
608 			    (struct ip *)(vaddr + ip_off);
609 			start = ip->ip_hl * 4 + ip_off;
610 		} else {
611 			start = ip_off + 40;
612 		}
613 		cksum_flags |= HCK_PARTIALCKSUM;
614 		(void) hcksum_assoc(mp, NULL, NULL, start, 0,
615 		    end, ntohs(ext_info->l4_cksum), cksum_flags,
616 		    0);
617 	}
618 }
619 
620 /*
621  * xgell_rx_1b_msg_alloc
622  *
623  * Allocate message header for data buffer, and decide if copy the packet to
624  * new data buffer to release big rx_buffer to save memory.
625  *
626  * If the pkt_length <= XGELL_RX_DMA_LOWAT, call allocb() to allocate
627  * new message and copy the payload in.
628  */
629 static mblk_t *
630 xgell_rx_1b_msg_alloc(xgelldev_t *lldev, xgell_rx_buffer_t *rx_buffer,
631     int pkt_length, xge_hal_dtr_info_t *ext_info, boolean_t *copyit)
632 {
633 	mblk_t *mp;
634 	char *vaddr;
635 
636 	vaddr = (char *)rx_buffer->vaddr + HEADROOM;
637 	/*
638 	 * Copy packet into new allocated message buffer, if pkt_length
639 	 * is less than XGELL_RX_DMA_LOWAT
640 	 */
641 	if (*copyit || pkt_length <= lldev->config.rx_dma_lowat) {
642 		if ((mp = allocb(pkt_length, 0)) == NULL) {
643 			return (NULL);
644 		}
645 		bcopy(vaddr, mp->b_rptr, pkt_length);
646 		mp->b_wptr = mp->b_rptr + pkt_length;
647 		*copyit = B_TRUE;
648 		return (mp);
649 	}
650 
651 	/*
652 	 * Just allocate mblk for current data buffer
653 	 */
654 	if ((mp = (mblk_t *)desballoc((unsigned char *)vaddr, pkt_length, 0,
655 	    &rx_buffer->frtn)) == NULL) {
656 		/* Drop it */
657 		return (NULL);
658 	}
659 	/*
660 	 * Adjust the b_rptr/b_wptr in the mblk_t structure.
661 	 */
662 	mp->b_wptr += pkt_length;
663 
664 	return (mp);
665 }
666 
667 /*
668  * xgell_rx_1b_compl
669  *
670  * If the interrupt is because of a received frame or if the receive ring
671  * contains fresh as yet un-processed frames, this function is called.
672  */
673 static xge_hal_status_e
674 xgell_rx_1b_compl(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
675     void *userdata)
676 {
677 	xgelldev_t *lldev = ((xgell_ring_t *)userdata)->lldev;
678 	xgell_rx_buffer_t *rx_buffer;
679 	mblk_t *mp_head = NULL;
680 	mblk_t *mp_end  = NULL;
681 	int pkt_burst = 0;
682 
683 	mutex_enter(&lldev->bf_pool.pool_lock);
684 
685 	do {
686 		int pkt_length;
687 		dma_addr_t dma_data;
688 		mblk_t *mp;
689 		boolean_t copyit = B_FALSE;
690 
691 		xgell_rxd_priv_t *rxd_priv = ((xgell_rxd_priv_t *)
692 		    xge_hal_ring_dtr_private(channelh, dtr));
693 		xge_hal_dtr_info_t ext_info;
694 
695 		rx_buffer = rxd_priv->rx_buffer;
696 
697 		xge_hal_ring_dtr_1b_get(channelh, dtr, &dma_data, &pkt_length);
698 		xge_hal_ring_dtr_info_get(channelh, dtr, &ext_info);
699 
700 		xge_assert(dma_data == rx_buffer->dma_addr);
701 
702 		if (t_code != 0) {
703 			xge_debug_ll(XGE_ERR, "%s%d: rx: dtr 0x%"PRIx64
704 			    " completed due to error t_code %01x", XGELL_IFNAME,
705 			    lldev->instance, (uint64_t)(uintptr_t)dtr, t_code);
706 
707 			(void) xge_hal_device_handle_tcode(channelh, dtr,
708 			    t_code);
709 			xge_hal_ring_dtr_free(channelh, dtr); /* drop it */
710 			xgell_rx_buffer_release(rx_buffer);
711 			continue;
712 		}
713 
714 		/*
715 		 * Sync the DMA memory
716 		 */
717 		if (ddi_dma_sync(rx_buffer->dma_handle, 0, pkt_length,
718 		    DDI_DMA_SYNC_FORKERNEL) != DDI_SUCCESS) {
719 			xge_debug_ll(XGE_ERR, "%s%d: rx: can not do DMA sync",
720 			    XGELL_IFNAME, lldev->instance);
721 			xge_hal_ring_dtr_free(channelh, dtr); /* drop it */
722 			xgell_rx_buffer_release(rx_buffer);
723 			continue;
724 		}
725 
726 		/*
727 		 * Allocate message for the packet.
728 		 */
729 		if (lldev->bf_pool.post > lldev->bf_pool.post_hiwat) {
730 			copyit = B_TRUE;
731 		} else {
732 			copyit = B_FALSE;
733 		}
734 
735 		mp = xgell_rx_1b_msg_alloc(lldev, rx_buffer, pkt_length,
736 		    &ext_info, &copyit);
737 
738 		xge_hal_ring_dtr_free(channelh, dtr);
739 
740 		/*
741 		 * Release the buffer and recycle it later
742 		 */
743 		if ((mp == NULL) || copyit) {
744 			xgell_rx_buffer_release(rx_buffer);
745 		} else {
746 			/*
747 			 * Count it since the buffer should be loaned up.
748 			 */
749 			lldev->bf_pool.post++;
750 		}
751 		if (mp == NULL) {
752 			xge_debug_ll(XGE_ERR,
753 			    "%s%d: rx: can not allocate mp mblk",
754 			    XGELL_IFNAME, lldev->instance);
755 			continue;
756 		}
757 
758 		/*
759 		 * Associate cksum_flags per packet type and h/w
760 		 * cksum flags.
761 		 */
762 		xgell_rx_hcksum_assoc(mp, (char *)rx_buffer->vaddr +
763 		    HEADROOM, pkt_length, &ext_info);
764 
765 		if (mp_head == NULL) {
766 			mp_head = mp;
767 			mp_end = mp;
768 		} else {
769 			mp_end->b_next = mp;
770 			mp_end = mp;
771 		}
772 
773 		if (++pkt_burst < lldev->config.rx_pkt_burst)
774 			continue;
775 
776 		if (lldev->bf_pool.post > lldev->bf_pool.post_hiwat) {
777 			/* Replenish rx buffers */
778 			xgell_rx_buffer_replenish_all(lldev);
779 		}
780 		mutex_exit(&lldev->bf_pool.pool_lock);
781 		if (mp_head != NULL) {
782 			mac_rx(lldev->mh, ((xgell_ring_t *)userdata)->handle,
783 			    mp_head);
784 		}
785 		mp_head = mp_end  = NULL;
786 		pkt_burst = 0;
787 		mutex_enter(&lldev->bf_pool.pool_lock);
788 
789 	} while (xge_hal_ring_dtr_next_completed(channelh, &dtr, &t_code) ==
790 	    XGE_HAL_OK);
791 
792 	/*
793 	 * Always call replenish_all to recycle rx_buffers.
794 	 */
795 	xgell_rx_buffer_replenish_all(lldev);
796 	mutex_exit(&lldev->bf_pool.pool_lock);
797 
798 	if (mp_head != NULL) {
799 		mac_rx(lldev->mh, ((xgell_ring_t *)userdata)->handle, mp_head);
800 	}
801 
802 	return (XGE_HAL_OK);
803 }
804 
805 /*
806  * xgell_xmit_compl
807  *
808  * If an interrupt was raised to indicate DMA complete of the Tx packet,
809  * this function is called. It identifies the last TxD whose buffer was
810  * freed and frees all skbs whose data have already DMA'ed into the NICs
811  * internal memory.
812  */
813 static xge_hal_status_e
814 xgell_xmit_compl(xge_hal_channel_h channelh, xge_hal_dtr_h dtr, u8 t_code,
815     void *userdata)
816 {
817 	xgelldev_t *lldev = userdata;
818 
819 	do {
820 		xgell_txd_priv_t *txd_priv = ((xgell_txd_priv_t *)
821 		    xge_hal_fifo_dtr_private(dtr));
822 		mblk_t *mp = txd_priv->mblk;
823 		int i;
824 
825 		if (t_code) {
826 			xge_debug_ll(XGE_TRACE, "%s%d: tx: dtr 0x%"PRIx64
827 			    " completed due to error t_code %01x", XGELL_IFNAME,
828 			    lldev->instance, (uint64_t)(uintptr_t)dtr, t_code);
829 
830 			(void) xge_hal_device_handle_tcode(channelh, dtr,
831 			    t_code);
832 		}
833 
834 		for (i = 0; i < txd_priv->handle_cnt; i++) {
835 			xge_assert(txd_priv->dma_handles[i]);
836 			(void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]);
837 			ddi_dma_free_handle(&txd_priv->dma_handles[i]);
838 			txd_priv->dma_handles[i] = 0;
839 		}
840 
841 		xge_hal_fifo_dtr_free(channelh, dtr);
842 
843 		freemsg(mp);
844 		lldev->resched_avail++;
845 
846 	} while (xge_hal_fifo_dtr_next_completed(channelh, &dtr, &t_code) ==
847 	    XGE_HAL_OK);
848 
849 	if (lldev->resched_retry &&
850 	    xge_queue_produce_context(xge_hal_device_queue(lldev->devh),
851 	    XGELL_EVENT_RESCHED_NEEDED, lldev) == XGE_QUEUE_OK) {
852 	    xge_debug_ll(XGE_TRACE, "%s%d: IRQ produced event for queue %d",
853 		XGELL_IFNAME, lldev->instance,
854 		((xge_hal_channel_t *)lldev->fifo_channel)->post_qid);
855 		lldev->resched_send = lldev->resched_avail;
856 		lldev->resched_retry = 0;
857 	}
858 
859 	return (XGE_HAL_OK);
860 }
861 
862 /*
863  * xgell_send
864  * @hldev: pointer to xge_hal_device_t strucutre
865  * @mblk: pointer to network buffer, i.e. mblk_t structure
866  *
867  * Called by the xgell_m_tx to transmit the packet to the XFRAME firmware.
868  * A pointer to an M_DATA message that contains the packet is passed to
869  * this routine.
870  */
871 static boolean_t
872 xgell_send(xgelldev_t *lldev, mblk_t *mp)
873 {
874 	mblk_t *bp;
875 	boolean_t retry;
876 	xge_hal_device_t *hldev = lldev->devh;
877 	xge_hal_status_e status;
878 	xge_hal_dtr_h dtr;
879 	xgell_txd_priv_t *txd_priv;
880 	uint32_t hckflags;
881 	uint32_t mss;
882 	int handle_cnt, frag_cnt, ret, i, copied;
883 	boolean_t used_copy;
884 
885 _begin:
886 	retry = B_FALSE;
887 	handle_cnt = frag_cnt = 0;
888 
889 	if (!lldev->is_initialized || lldev->in_reset)
890 		return (B_FALSE);
891 
892 	/*
893 	 * If the free Tx dtrs count reaches the lower threshold,
894 	 * inform the gld to stop sending more packets till the free
895 	 * dtrs count exceeds higher threshold. Driver informs the
896 	 * gld through gld_sched call, when the free dtrs count exceeds
897 	 * the higher threshold.
898 	 */
899 	if (xge_hal_channel_dtr_count(lldev->fifo_channel)
900 	    <= XGELL_TX_LEVEL_LOW) {
901 		xge_debug_ll(XGE_TRACE, "%s%d: queue %d: err on xmit,"
902 		    "free descriptors count at low threshold %d",
903 		    XGELL_IFNAME, lldev->instance,
904 		    ((xge_hal_channel_t *)lldev->fifo_channel)->post_qid,
905 		    XGELL_TX_LEVEL_LOW);
906 		retry = B_TRUE;
907 		goto _exit;
908 	}
909 
910 	status = xge_hal_fifo_dtr_reserve(lldev->fifo_channel, &dtr);
911 	if (status != XGE_HAL_OK) {
912 		switch (status) {
913 		case XGE_HAL_INF_CHANNEL_IS_NOT_READY:
914 			xge_debug_ll(XGE_ERR,
915 			    "%s%d: channel %d is not ready.", XGELL_IFNAME,
916 			    lldev->instance,
917 			    ((xge_hal_channel_t *)
918 			    lldev->fifo_channel)->post_qid);
919 			retry = B_TRUE;
920 			goto _exit;
921 		case XGE_HAL_INF_OUT_OF_DESCRIPTORS:
922 			xge_debug_ll(XGE_TRACE, "%s%d: queue %d: error in xmit,"
923 			    " out of descriptors.", XGELL_IFNAME,
924 			    lldev->instance,
925 			    ((xge_hal_channel_t *)
926 			    lldev->fifo_channel)->post_qid);
927 			retry = B_TRUE;
928 			goto _exit;
929 		default:
930 			return (B_FALSE);
931 		}
932 	}
933 
934 	txd_priv = xge_hal_fifo_dtr_private(dtr);
935 	txd_priv->mblk = mp;
936 
937 	/*
938 	 * VLAN tag should be passed down along with MAC header, so h/w needn't
939 	 * do insertion.
940 	 *
941 	 * For NIC driver that has to strip and re-insert VLAN tag, the example
942 	 * is the other implementation for xge. The driver can simple bcopy()
943 	 * ether_vlan_header to overwrite VLAN tag and let h/w insert the tag
944 	 * automatically, since it's impossible that GLD sends down mp(s) with
945 	 * splited ether_vlan_header.
946 	 *
947 	 * struct ether_vlan_header *evhp;
948 	 * uint16_t tci;
949 	 *
950 	 * evhp = (struct ether_vlan_header *)mp->b_rptr;
951 	 * if (evhp->ether_tpid == htons(VLAN_TPID)) {
952 	 *	tci = ntohs(evhp->ether_tci);
953 	 *	(void) bcopy(mp->b_rptr, mp->b_rptr + VLAN_TAGSZ,
954 	 *	    2 * ETHERADDRL);
955 	 *	mp->b_rptr += VLAN_TAGSZ;
956 	 *
957 	 *	xge_hal_fifo_dtr_vlan_set(dtr, tci);
958 	 * }
959 	 */
960 
961 	copied = 0;
962 	used_copy = B_FALSE;
963 	for (bp = mp; bp != NULL; bp = bp->b_cont) {
964 		int mblen;
965 		uint_t ncookies;
966 		ddi_dma_cookie_t dma_cookie;
967 		ddi_dma_handle_t dma_handle;
968 
969 		/* skip zero-length message blocks */
970 		mblen = MBLKL(bp);
971 		if (mblen == 0) {
972 			continue;
973 		}
974 
975 		/*
976 		 * Check the message length to decide to DMA or bcopy() data
977 		 * to tx descriptor(s).
978 		 */
979 		if (mblen < lldev->config.tx_dma_lowat &&
980 		    (copied + mblen) < lldev->tx_copied_max) {
981 			xge_hal_status_e rc;
982 			rc = xge_hal_fifo_dtr_buffer_append(lldev->fifo_channel,
983 			    dtr, bp->b_rptr, mblen);
984 			if (rc == XGE_HAL_OK) {
985 				used_copy = B_TRUE;
986 				copied += mblen;
987 				continue;
988 			} else if (used_copy) {
989 				xge_hal_fifo_dtr_buffer_finalize(
990 					lldev->fifo_channel, dtr, frag_cnt++);
991 				used_copy = B_FALSE;
992 			}
993 		} else if (used_copy) {
994 			xge_hal_fifo_dtr_buffer_finalize(lldev->fifo_channel,
995 			    dtr, frag_cnt++);
996 			used_copy = B_FALSE;
997 		}
998 
999 		ret = ddi_dma_alloc_handle(lldev->dev_info, &tx_dma_attr,
1000 		    DDI_DMA_DONTWAIT, 0, &dma_handle);
1001 		if (ret != DDI_SUCCESS) {
1002 			xge_debug_ll(XGE_ERR,
1003 			    "%s%d: can not allocate dma handle", XGELL_IFNAME,
1004 			    lldev->instance);
1005 			goto _exit_cleanup;
1006 		}
1007 
1008 		ret = ddi_dma_addr_bind_handle(dma_handle, NULL,
1009 		    (caddr_t)bp->b_rptr, mblen,
1010 		    DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
1011 		    &dma_cookie, &ncookies);
1012 
1013 		switch (ret) {
1014 		case DDI_DMA_MAPPED:
1015 			/* everything's fine */
1016 			break;
1017 
1018 		case DDI_DMA_NORESOURCES:
1019 			xge_debug_ll(XGE_ERR,
1020 			    "%s%d: can not bind dma address",
1021 			    XGELL_IFNAME, lldev->instance);
1022 			ddi_dma_free_handle(&dma_handle);
1023 			goto _exit_cleanup;
1024 
1025 		case DDI_DMA_NOMAPPING:
1026 		case DDI_DMA_INUSE:
1027 		case DDI_DMA_TOOBIG:
1028 		default:
1029 			/* drop packet, don't retry */
1030 			xge_debug_ll(XGE_ERR,
1031 			    "%s%d: can not map message buffer",
1032 			    XGELL_IFNAME, lldev->instance);
1033 			ddi_dma_free_handle(&dma_handle);
1034 			goto _exit_cleanup;
1035 		}
1036 
1037 		if (ncookies + frag_cnt > hldev->config.fifo.max_frags) {
1038 			xge_debug_ll(XGE_ERR, "%s%d: too many fragments, "
1039 			    "requested c:%d+f:%d", XGELL_IFNAME,
1040 			    lldev->instance, ncookies, frag_cnt);
1041 			(void) ddi_dma_unbind_handle(dma_handle);
1042 			ddi_dma_free_handle(&dma_handle);
1043 			goto _exit_cleanup;
1044 		}
1045 
1046 		/* setup the descriptors for this data buffer */
1047 		while (ncookies) {
1048 			xge_hal_fifo_dtr_buffer_set(lldev->fifo_channel, dtr,
1049 			    frag_cnt++, dma_cookie.dmac_laddress,
1050 			    dma_cookie.dmac_size);
1051 			if (--ncookies) {
1052 				ddi_dma_nextcookie(dma_handle, &dma_cookie);
1053 			}
1054 
1055 		}
1056 
1057 		txd_priv->dma_handles[handle_cnt++] = dma_handle;
1058 
1059 		if (bp->b_cont &&
1060 		    (frag_cnt + XGE_HAL_DEFAULT_FIFO_FRAGS_THRESHOLD >=
1061 			hldev->config.fifo.max_frags)) {
1062 			mblk_t *nmp;
1063 
1064 			xge_debug_ll(XGE_TRACE,
1065 			    "too many FRAGs [%d], pull up them", frag_cnt);
1066 
1067 			if ((nmp = msgpullup(bp->b_cont, -1)) == NULL) {
1068 				/* Drop packet, don't retry */
1069 				xge_debug_ll(XGE_ERR,
1070 				    "%s%d: can not pullup message buffer",
1071 				    XGELL_IFNAME, lldev->instance);
1072 				goto _exit_cleanup;
1073 			}
1074 			freemsg(bp->b_cont);
1075 			bp->b_cont = nmp;
1076 		}
1077 	}
1078 
1079 	/* finalize unfinished copies */
1080 	if (used_copy) {
1081 		xge_hal_fifo_dtr_buffer_finalize(lldev->fifo_channel, dtr,
1082 		    frag_cnt++);
1083 	}
1084 
1085 	txd_priv->handle_cnt = handle_cnt;
1086 
1087 	/*
1088 	 * If LSO is required, just call xge_hal_fifo_dtr_mss_set(dtr, mss) to
1089 	 * do all necessary work.
1090 	 */
1091 	hcksum_retrieve(mp, NULL, NULL, NULL, NULL, NULL, &mss, &hckflags);
1092 	if ((hckflags & HW_LSO) && (mss != 0)) {
1093 		xge_hal_fifo_dtr_mss_set(dtr, mss);
1094 	}
1095 
1096 	if (hckflags & HCK_IPV4_HDRCKSUM) {
1097 		xge_hal_fifo_dtr_cksum_set_bits(dtr,
1098 		    XGE_HAL_TXD_TX_CKO_IPV4_EN);
1099 	}
1100 	if (hckflags & HCK_FULLCKSUM) {
1101 		xge_hal_fifo_dtr_cksum_set_bits(dtr, XGE_HAL_TXD_TX_CKO_TCP_EN |
1102 		    XGE_HAL_TXD_TX_CKO_UDP_EN);
1103 	}
1104 
1105 	xge_hal_fifo_dtr_post(lldev->fifo_channel, dtr);
1106 
1107 	return (B_TRUE);
1108 
1109 _exit_cleanup:
1110 
1111 	for (i = 0; i < handle_cnt; i++) {
1112 		(void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]);
1113 		ddi_dma_free_handle(&txd_priv->dma_handles[i]);
1114 		txd_priv->dma_handles[i] = 0;
1115 	}
1116 
1117 	xge_hal_fifo_dtr_free(lldev->fifo_channel, dtr);
1118 
1119 _exit:
1120 	if (retry) {
1121 		if (lldev->resched_avail != lldev->resched_send &&
1122 		    xge_queue_produce_context(xge_hal_device_queue(lldev->devh),
1123 		    XGELL_EVENT_RESCHED_NEEDED, lldev) == XGE_QUEUE_OK) {
1124 			lldev->resched_send = lldev->resched_avail;
1125 			return (B_FALSE);
1126 		} else {
1127 			lldev->resched_retry = 1;
1128 		}
1129 	}
1130 
1131 	freemsg(mp);
1132 	return (B_TRUE);
1133 }
1134 
1135 /*
1136  * xge_m_tx
1137  * @arg: pointer to the xgelldev_t structure
1138  * @resid: resource id
1139  * @mp: pointer to the message buffer
1140  *
1141  * Called by MAC Layer to send a chain of packets
1142  */
1143 static mblk_t *
1144 xgell_m_tx(void *arg, mblk_t *mp)
1145 {
1146 	xgelldev_t *lldev = arg;
1147 	mblk_t *next;
1148 
1149 	while (mp != NULL) {
1150 		next = mp->b_next;
1151 		mp->b_next = NULL;
1152 
1153 		if (!xgell_send(lldev, mp)) {
1154 			mp->b_next = next;
1155 			break;
1156 		}
1157 		mp = next;
1158 	}
1159 
1160 	return (mp);
1161 }
1162 
1163 /*
1164  * xgell_rx_dtr_term
1165  *
1166  * Function will be called by HAL to terminate all DTRs for
1167  * Ring(s) type of channels.
1168  */
1169 static void
1170 xgell_rx_dtr_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
1171     xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen)
1172 {
1173 	xgell_rxd_priv_t *rxd_priv =
1174 	    ((xgell_rxd_priv_t *)xge_hal_ring_dtr_private(channelh, dtrh));
1175 	xgell_rx_buffer_t *rx_buffer = rxd_priv->rx_buffer;
1176 
1177 	if (state == XGE_HAL_DTR_STATE_POSTED) {
1178 		xgelldev_t *lldev = rx_buffer->lldev;
1179 
1180 		mutex_enter(&lldev->bf_pool.pool_lock);
1181 		xge_hal_ring_dtr_free(channelh, dtrh);
1182 		xgell_rx_buffer_release(rx_buffer);
1183 		mutex_exit(&lldev->bf_pool.pool_lock);
1184 	}
1185 }
1186 
1187 /*
1188  * xgell_tx_term
1189  *
1190  * Function will be called by HAL to terminate all DTRs for
1191  * Fifo(s) type of channels.
1192  */
1193 static void
1194 xgell_tx_term(xge_hal_channel_h channelh, xge_hal_dtr_h dtrh,
1195     xge_hal_dtr_state_e state, void *userdata, xge_hal_channel_reopen_e reopen)
1196 {
1197 	xgell_txd_priv_t *txd_priv =
1198 	    ((xgell_txd_priv_t *)xge_hal_fifo_dtr_private(dtrh));
1199 	mblk_t *mp = txd_priv->mblk;
1200 	int i;
1201 
1202 	/*
1203 	 * for Tx we must clean up the DTR *only* if it has been
1204 	 * posted!
1205 	 */
1206 	if (state != XGE_HAL_DTR_STATE_POSTED) {
1207 		return;
1208 	}
1209 
1210 	for (i = 0; i < txd_priv->handle_cnt; i++) {
1211 		xge_assert(txd_priv->dma_handles[i]);
1212 		(void) ddi_dma_unbind_handle(txd_priv->dma_handles[i]);
1213 		ddi_dma_free_handle(&txd_priv->dma_handles[i]);
1214 		txd_priv->dma_handles[i] = 0;
1215 	}
1216 
1217 	xge_hal_fifo_dtr_free(channelh, dtrh);
1218 
1219 	freemsg(mp);
1220 }
1221 
1222 /*
1223  * xgell_tx_open
1224  * @lldev: the link layer object
1225  *
1226  * Initialize and open all Tx channels;
1227  */
1228 static boolean_t
1229 xgell_tx_open(xgelldev_t *lldev)
1230 {
1231 	xge_hal_status_e status;
1232 	u64 adapter_status;
1233 	xge_hal_channel_attr_t attr;
1234 
1235 	attr.post_qid		= 0;
1236 	attr.compl_qid		= 0;
1237 	attr.callback		= xgell_xmit_compl;
1238 	attr.per_dtr_space	= sizeof (xgell_txd_priv_t);
1239 	attr.flags		= 0;
1240 	attr.type		= XGE_HAL_CHANNEL_TYPE_FIFO;
1241 	attr.userdata		= lldev;
1242 	attr.dtr_init		= NULL;
1243 	attr.dtr_term		= xgell_tx_term;
1244 
1245 	if (xge_hal_device_status(lldev->devh, &adapter_status)) {
1246 		xge_debug_ll(XGE_ERR, "%s%d: device is not ready "
1247 		    "adaper status reads 0x%"PRIx64, XGELL_IFNAME,
1248 		    lldev->instance, (uint64_t)adapter_status);
1249 		return (B_FALSE);
1250 	}
1251 
1252 	status = xge_hal_channel_open(lldev->devh, &attr,
1253 	    &lldev->fifo_channel, XGE_HAL_CHANNEL_OC_NORMAL);
1254 	if (status != XGE_HAL_OK) {
1255 		xge_debug_ll(XGE_ERR, "%s%d: cannot open Tx channel "
1256 		    "got status code %d", XGELL_IFNAME,
1257 		    lldev->instance, status);
1258 		return (B_FALSE);
1259 	}
1260 
1261 	return (B_TRUE);
1262 }
1263 
1264 /*
1265  * xgell_rx_open
1266  * @lldev: the link layer object
1267  *
1268  * Initialize and open all Rx channels;
1269  */
1270 static boolean_t
1271 xgell_rx_open(xgelldev_t *lldev)
1272 {
1273 	xge_hal_status_e status;
1274 	u64 adapter_status;
1275 	xge_hal_channel_attr_t attr;
1276 
1277 	attr.post_qid		= XGELL_RING_MAIN_QID;
1278 	attr.compl_qid		= 0;
1279 	attr.callback		= xgell_rx_1b_compl;
1280 	attr.per_dtr_space	= sizeof (xgell_rxd_priv_t);
1281 	attr.flags		= 0;
1282 	attr.type		= XGE_HAL_CHANNEL_TYPE_RING;
1283 	attr.dtr_init		= xgell_rx_dtr_replenish;
1284 	attr.dtr_term		= xgell_rx_dtr_term;
1285 
1286 	if (xge_hal_device_status(lldev->devh, &adapter_status)) {
1287 		xge_debug_ll(XGE_ERR,
1288 		    "%s%d: device is not ready adaper status reads 0x%"PRIx64,
1289 		    XGELL_IFNAME, lldev->instance,
1290 		    (uint64_t)adapter_status);
1291 		return (B_FALSE);
1292 	}
1293 
1294 	lldev->ring_main.lldev = lldev;
1295 	attr.userdata = &lldev->ring_main;
1296 
1297 	status = xge_hal_channel_open(lldev->devh, &attr,
1298 	    &lldev->ring_main.channelh, XGE_HAL_CHANNEL_OC_NORMAL);
1299 	if (status != XGE_HAL_OK) {
1300 		xge_debug_ll(XGE_ERR, "%s%d: cannot open Rx channel got status "
1301 		    " code %d", XGELL_IFNAME, lldev->instance, status);
1302 		return (B_FALSE);
1303 	}
1304 
1305 	return (B_TRUE);
1306 }
1307 
1308 static int
1309 xgell_initiate_start(xgelldev_t *lldev)
1310 {
1311 	xge_hal_status_e status;
1312 	xge_hal_device_t *hldev = lldev->devh;
1313 	int maxpkt = hldev->config.mtu;
1314 
1315 	/* check initial mtu before enabling the device */
1316 	status = xge_hal_device_mtu_check(lldev->devh, maxpkt);
1317 	if (status != XGE_HAL_OK) {
1318 		xge_debug_ll(XGE_ERR, "%s%d: MTU size %d is invalid",
1319 		    XGELL_IFNAME, lldev->instance, maxpkt);
1320 		return (EINVAL);
1321 	}
1322 
1323 	/* set initial mtu before enabling the device */
1324 	status = xge_hal_device_mtu_set(lldev->devh, maxpkt);
1325 	if (status != XGE_HAL_OK) {
1326 		xge_debug_ll(XGE_ERR, "%s%d: can not set new MTU %d",
1327 		    XGELL_IFNAME, lldev->instance, maxpkt);
1328 		return (EIO);
1329 	}
1330 
1331 	/* tune jumbo/normal frame UFC counters */
1332 	hldev->config.ring.queue[XGELL_RING_MAIN_QID].rti.ufc_b = \
1333 		maxpkt > XGE_HAL_DEFAULT_MTU ?
1334 			XGE_HAL_DEFAULT_RX_UFC_B_J :
1335 			XGE_HAL_DEFAULT_RX_UFC_B_N;
1336 
1337 	hldev->config.ring.queue[XGELL_RING_MAIN_QID].rti.ufc_c = \
1338 		maxpkt > XGE_HAL_DEFAULT_MTU ?
1339 			XGE_HAL_DEFAULT_RX_UFC_C_J :
1340 			XGE_HAL_DEFAULT_RX_UFC_C_N;
1341 
1342 	/* now, enable the device */
1343 	status = xge_hal_device_enable(lldev->devh);
1344 	if (status != XGE_HAL_OK) {
1345 		xge_debug_ll(XGE_ERR, "%s%d: can not enable the device",
1346 		    XGELL_IFNAME, lldev->instance);
1347 		return (EIO);
1348 	}
1349 
1350 	if (!xgell_rx_open(lldev)) {
1351 		status = xge_hal_device_disable(lldev->devh);
1352 		if (status != XGE_HAL_OK) {
1353 			u64 adapter_status;
1354 			(void) xge_hal_device_status(lldev->devh,
1355 			    &adapter_status);
1356 			xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
1357 			    "the device. adaper status 0x%"PRIx64
1358 			    " returned status %d",
1359 			    XGELL_IFNAME, lldev->instance,
1360 			    (uint64_t)adapter_status, status);
1361 		}
1362 		xge_os_mdelay(1500);
1363 		return (ENOMEM);
1364 	}
1365 
1366 	if (!xgell_tx_open(lldev)) {
1367 		status = xge_hal_device_disable(lldev->devh);
1368 		if (status != XGE_HAL_OK) {
1369 			u64 adapter_status;
1370 			(void) xge_hal_device_status(lldev->devh,
1371 			    &adapter_status);
1372 			xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
1373 			    "the device. adaper status 0x%"PRIx64
1374 			    " returned status %d",
1375 			    XGELL_IFNAME, lldev->instance,
1376 			    (uint64_t)adapter_status, status);
1377 		}
1378 		xge_os_mdelay(1500);
1379 		xge_hal_channel_close(lldev->ring_main.channelh,
1380 		    XGE_HAL_CHANNEL_OC_NORMAL);
1381 		return (ENOMEM);
1382 	}
1383 
1384 	/* time to enable interrupts */
1385 	xge_hal_device_intr_enable(lldev->devh);
1386 
1387 	lldev->is_initialized = 1;
1388 
1389 	return (0);
1390 }
1391 
1392 static void
1393 xgell_initiate_stop(xgelldev_t *lldev)
1394 {
1395 	xge_hal_status_e status;
1396 
1397 	lldev->is_initialized = 0;
1398 
1399 	status = xge_hal_device_disable(lldev->devh);
1400 	if (status != XGE_HAL_OK) {
1401 		u64 adapter_status;
1402 		(void) xge_hal_device_status(lldev->devh, &adapter_status);
1403 		xge_debug_ll(XGE_ERR, "%s%d: can not safely disable "
1404 		    "the device. adaper status 0x%"PRIx64" returned status %d",
1405 		    XGELL_IFNAME, lldev->instance,
1406 		    (uint64_t)adapter_status, status);
1407 	}
1408 	xge_hal_device_intr_disable(lldev->devh);
1409 
1410 	xge_debug_ll(XGE_TRACE, "%s",
1411 	    "waiting for device irq to become quiescent...");
1412 	xge_os_mdelay(1500);
1413 
1414 	xge_queue_flush(xge_hal_device_queue(lldev->devh));
1415 
1416 	xge_hal_channel_close(lldev->ring_main.channelh,
1417 	    XGE_HAL_CHANNEL_OC_NORMAL);
1418 
1419 	xge_hal_channel_close(lldev->fifo_channel,
1420 	    XGE_HAL_CHANNEL_OC_NORMAL);
1421 }
1422 
1423 /*
1424  * xgell_m_start
1425  * @arg: pointer to device private strucutre(hldev)
1426  *
1427  * This function is called by MAC Layer to enable the XFRAME
1428  * firmware to generate interrupts and also prepare the
1429  * driver to call mac_rx for delivering receive packets
1430  * to MAC Layer.
1431  */
1432 static int
1433 xgell_m_start(void *arg)
1434 {
1435 	xgelldev_t *lldev = arg;
1436 	xge_hal_device_t *hldev = lldev->devh;
1437 	int ret;
1438 
1439 	xge_debug_ll(XGE_TRACE, "%s%d: M_START", XGELL_IFNAME,
1440 	    lldev->instance);
1441 
1442 	mutex_enter(&lldev->genlock);
1443 
1444 	if (lldev->is_initialized) {
1445 		xge_debug_ll(XGE_ERR, "%s%d: device is already initialized",
1446 		    XGELL_IFNAME, lldev->instance);
1447 		mutex_exit(&lldev->genlock);
1448 		return (EINVAL);
1449 	}
1450 
1451 	hldev->terminating = 0;
1452 	if (ret = xgell_initiate_start(lldev)) {
1453 		mutex_exit(&lldev->genlock);
1454 		return (ret);
1455 	}
1456 
1457 	lldev->timeout_id = timeout(xge_device_poll, hldev, XGE_DEV_POLL_TICKS);
1458 
1459 	mutex_exit(&lldev->genlock);
1460 
1461 	return (0);
1462 }
1463 
1464 /*
1465  * xgell_m_stop
1466  * @arg: pointer to device private data (hldev)
1467  *
1468  * This function is called by the MAC Layer to disable
1469  * the XFRAME firmware for generating any interrupts and
1470  * also stop the driver from calling mac_rx() for
1471  * delivering data packets to the MAC Layer.
1472  */
1473 static void
1474 xgell_m_stop(void *arg)
1475 {
1476 	xgelldev_t *lldev = arg;
1477 	xge_hal_device_t *hldev = lldev->devh;
1478 
1479 	xge_debug_ll(XGE_TRACE, "%s", "MAC_STOP");
1480 
1481 	mutex_enter(&lldev->genlock);
1482 	if (!lldev->is_initialized) {
1483 		xge_debug_ll(XGE_ERR, "%s", "device is not initialized...");
1484 		mutex_exit(&lldev->genlock);
1485 		return;
1486 	}
1487 
1488 	xge_hal_device_terminating(hldev);
1489 	xgell_initiate_stop(lldev);
1490 
1491 	/* reset device */
1492 	(void) xge_hal_device_reset(lldev->devh);
1493 
1494 	mutex_exit(&lldev->genlock);
1495 
1496 	if (lldev->timeout_id != 0) {
1497 		(void) untimeout(lldev->timeout_id);
1498 	}
1499 
1500 	xge_debug_ll(XGE_TRACE, "%s", "returning back to MAC Layer...");
1501 }
1502 
1503 /*
1504  * xgell_onerr_reset
1505  * @lldev: pointer to xgelldev_t structure
1506  *
1507  * This function is called by HAL Event framework to reset the HW
1508  * This function is must be called with genlock taken.
1509  */
1510 int
1511 xgell_onerr_reset(xgelldev_t *lldev)
1512 {
1513 	int rc = 0;
1514 
1515 	if (!lldev->is_initialized) {
1516 		xge_debug_ll(XGE_ERR, "%s%d: can not reset",
1517 		    XGELL_IFNAME, lldev->instance);
1518 		return (rc);
1519 	}
1520 
1521 	lldev->in_reset = 1;
1522 	xgell_initiate_stop(lldev);
1523 
1524 	/* reset device */
1525 	(void) xge_hal_device_reset(lldev->devh);
1526 
1527 	rc = xgell_initiate_start(lldev);
1528 	lldev->in_reset = 0;
1529 
1530 	return (rc);
1531 }
1532 
1533 
1534 /*
1535  * xgell_m_unicst
1536  * @arg: pointer to device private strucutre(hldev)
1537  * @mac_addr:
1538  *
1539  * This function is called by MAC Layer to set the physical address
1540  * of the XFRAME firmware.
1541  */
1542 static int
1543 xgell_m_unicst(void *arg, const uint8_t *macaddr)
1544 {
1545 	xge_hal_status_e status;
1546 	xgelldev_t *lldev = (xgelldev_t *)arg;
1547 	xge_hal_device_t *hldev = lldev->devh;
1548 	xge_debug_ll(XGE_TRACE, "%s", "MAC_UNICST");
1549 
1550 	xge_debug_ll(XGE_TRACE, "%s", "M_UNICAST");
1551 
1552 	mutex_enter(&lldev->genlock);
1553 
1554 	xge_debug_ll(XGE_TRACE,
1555 	    "setting macaddr: 0x%02x-%02x-%02x-%02x-%02x-%02x",
1556 	    macaddr[0], macaddr[1], macaddr[2],
1557 	    macaddr[3], macaddr[4], macaddr[5]);
1558 
1559 	status = xge_hal_device_macaddr_set(hldev, 0, (uchar_t *)macaddr);
1560 	if (status != XGE_HAL_OK) {
1561 		xge_debug_ll(XGE_ERR, "%s%d: can not set mac address",
1562 		    XGELL_IFNAME, lldev->instance);
1563 		mutex_exit(&lldev->genlock);
1564 		return (EIO);
1565 	}
1566 
1567 	mutex_exit(&lldev->genlock);
1568 
1569 	return (0);
1570 }
1571 
1572 
1573 /*
1574  * xgell_m_multicst
1575  * @arg: pointer to device private strucutre(hldev)
1576  * @add:
1577  * @mc_addr:
1578  *
1579  * This function is called by MAC Layer to enable or
1580  * disable device-level reception of specific multicast addresses.
1581  */
1582 static int
1583 xgell_m_multicst(void *arg, boolean_t add, const uint8_t *mc_addr)
1584 {
1585 	xge_hal_status_e status;
1586 	xgelldev_t *lldev = (xgelldev_t *)arg;
1587 	xge_hal_device_t *hldev = lldev->devh;
1588 
1589 	xge_debug_ll(XGE_TRACE, "M_MULTICAST add %d", add);
1590 
1591 	mutex_enter(&lldev->genlock);
1592 
1593 	if (!lldev->is_initialized) {
1594 		xge_debug_ll(XGE_ERR, "%s%d: can not set multicast",
1595 		    XGELL_IFNAME, lldev->instance);
1596 		mutex_exit(&lldev->genlock);
1597 		return (EIO);
1598 	}
1599 
1600 	/* FIXME: missing HAL functionality: enable_one() */
1601 
1602 	status = (add) ?
1603 	    xge_hal_device_mcast_enable(hldev) :
1604 	    xge_hal_device_mcast_disable(hldev);
1605 
1606 	if (status != XGE_HAL_OK) {
1607 		xge_debug_ll(XGE_ERR, "failed to %s multicast, status %d",
1608 		    add ? "enable" : "disable", status);
1609 		mutex_exit(&lldev->genlock);
1610 		return (EIO);
1611 	}
1612 
1613 	mutex_exit(&lldev->genlock);
1614 
1615 	return (0);
1616 }
1617 
1618 
1619 /*
1620  * xgell_m_promisc
1621  * @arg: pointer to device private strucutre(hldev)
1622  * @on:
1623  *
1624  * This function is called by MAC Layer to enable or
1625  * disable the reception of all the packets on the medium
1626  */
1627 static int
1628 xgell_m_promisc(void *arg, boolean_t on)
1629 {
1630 	xgelldev_t *lldev = (xgelldev_t *)arg;
1631 	xge_hal_device_t *hldev = lldev->devh;
1632 
1633 	mutex_enter(&lldev->genlock);
1634 
1635 	xge_debug_ll(XGE_TRACE, "%s", "MAC_PROMISC_SET");
1636 
1637 	if (!lldev->is_initialized) {
1638 		xge_debug_ll(XGE_ERR, "%s%d: can not set promiscuous",
1639 		    XGELL_IFNAME, lldev->instance);
1640 		mutex_exit(&lldev->genlock);
1641 		return (EIO);
1642 	}
1643 
1644 	if (on) {
1645 		xge_hal_device_promisc_enable(hldev);
1646 	} else {
1647 		xge_hal_device_promisc_disable(hldev);
1648 	}
1649 
1650 	mutex_exit(&lldev->genlock);
1651 
1652 	return (0);
1653 }
1654 
1655 /*
1656  * xgell_m_stat
1657  * @arg: pointer to device private strucutre(hldev)
1658  *
1659  * This function is called by MAC Layer to get network statistics
1660  * from the driver.
1661  */
1662 static int
1663 xgell_m_stat(void *arg, uint_t stat, uint64_t *val)
1664 {
1665 	xge_hal_stats_hw_info_t *hw_info;
1666 	xgelldev_t *lldev = (xgelldev_t *)arg;
1667 	xge_hal_device_t *hldev = lldev->devh;
1668 
1669 	xge_debug_ll(XGE_TRACE, "%s", "MAC_STATS_GET");
1670 
1671 	if (!mutex_tryenter(&lldev->genlock))
1672 		return (EAGAIN);
1673 
1674 	if (!lldev->is_initialized) {
1675 		mutex_exit(&lldev->genlock);
1676 		return (EAGAIN);
1677 	}
1678 
1679 	if (xge_hal_stats_hw(hldev, &hw_info) != XGE_HAL_OK) {
1680 		mutex_exit(&lldev->genlock);
1681 		return (EAGAIN);
1682 	}
1683 
1684 	switch (stat) {
1685 	case MAC_STAT_IFSPEED:
1686 		*val = 10000000000ull; /* 10G */
1687 		break;
1688 
1689 	case MAC_STAT_MULTIRCV:
1690 		*val = ((u64) hw_info->rmac_vld_mcst_frms_oflow << 32) |
1691 		    hw_info->rmac_vld_mcst_frms;
1692 		break;
1693 
1694 	case MAC_STAT_BRDCSTRCV:
1695 		*val = ((u64) hw_info->rmac_vld_bcst_frms_oflow << 32) |
1696 		    hw_info->rmac_vld_bcst_frms;
1697 		break;
1698 
1699 	case MAC_STAT_MULTIXMT:
1700 		*val = ((u64) hw_info->tmac_mcst_frms_oflow << 32) |
1701 		    hw_info->tmac_mcst_frms;
1702 		break;
1703 
1704 	case MAC_STAT_BRDCSTXMT:
1705 		*val = ((u64) hw_info->tmac_bcst_frms_oflow << 32) |
1706 		    hw_info->tmac_bcst_frms;
1707 		break;
1708 
1709 	case MAC_STAT_RBYTES:
1710 		*val = ((u64) hw_info->rmac_ttl_octets_oflow << 32) |
1711 		    hw_info->rmac_ttl_octets;
1712 		break;
1713 
1714 	case MAC_STAT_NORCVBUF:
1715 		*val = hw_info->rmac_drop_frms;
1716 		break;
1717 
1718 	case MAC_STAT_IERRORS:
1719 		*val = ((u64) hw_info->rmac_discarded_frms_oflow << 32) |
1720 		    hw_info->rmac_discarded_frms;
1721 		break;
1722 
1723 	case MAC_STAT_OBYTES:
1724 		*val = ((u64) hw_info->tmac_ttl_octets_oflow << 32) |
1725 		    hw_info->tmac_ttl_octets;
1726 		break;
1727 
1728 	case MAC_STAT_NOXMTBUF:
1729 		*val = hw_info->tmac_drop_frms;
1730 		break;
1731 
1732 	case MAC_STAT_OERRORS:
1733 		*val = ((u64) hw_info->tmac_any_err_frms_oflow << 32) |
1734 		    hw_info->tmac_any_err_frms;
1735 		break;
1736 
1737 	case MAC_STAT_IPACKETS:
1738 		*val = ((u64) hw_info->rmac_vld_frms_oflow << 32) |
1739 		    hw_info->rmac_vld_frms;
1740 		break;
1741 
1742 	case MAC_STAT_OPACKETS:
1743 		*val = ((u64) hw_info->tmac_frms_oflow << 32) |
1744 		    hw_info->tmac_frms;
1745 		break;
1746 
1747 	case ETHER_STAT_FCS_ERRORS:
1748 		*val = hw_info->rmac_fcs_err_frms;
1749 		break;
1750 
1751 	case ETHER_STAT_TOOLONG_ERRORS:
1752 		*val = hw_info->rmac_long_frms;
1753 		break;
1754 
1755 	case ETHER_STAT_LINK_DUPLEX:
1756 		*val = LINK_DUPLEX_FULL;
1757 		break;
1758 
1759 	default:
1760 		mutex_exit(&lldev->genlock);
1761 		return (ENOTSUP);
1762 	}
1763 
1764 	mutex_exit(&lldev->genlock);
1765 
1766 	return (0);
1767 }
1768 
1769 /*
1770  * xgell_device_alloc - Allocate new LL device
1771  */
1772 int
1773 xgell_device_alloc(xge_hal_device_h devh,
1774     dev_info_t *dev_info, xgelldev_t **lldev_out)
1775 {
1776 	xgelldev_t *lldev;
1777 	xge_hal_device_t *hldev = (xge_hal_device_t *)devh;
1778 	int instance = ddi_get_instance(dev_info);
1779 
1780 	*lldev_out = NULL;
1781 
1782 	xge_debug_ll(XGE_TRACE, "trying to register etherenet device %s%d...",
1783 	    XGELL_IFNAME, instance);
1784 
1785 	lldev = kmem_zalloc(sizeof (xgelldev_t), KM_SLEEP);
1786 
1787 	lldev->devh = hldev;
1788 	lldev->instance = instance;
1789 	lldev->dev_info = dev_info;
1790 
1791 	*lldev_out = lldev;
1792 
1793 	ddi_set_driver_private(dev_info, (caddr_t)hldev);
1794 
1795 	return (DDI_SUCCESS);
1796 }
1797 
1798 /*
1799  * xgell_device_free
1800  */
1801 void
1802 xgell_device_free(xgelldev_t *lldev)
1803 {
1804 	xge_debug_ll(XGE_TRACE, "freeing device %s%d",
1805 	    XGELL_IFNAME, lldev->instance);
1806 
1807 	kmem_free(lldev, sizeof (xgelldev_t));
1808 }
1809 
1810 /*
1811  * xgell_ioctl
1812  */
1813 static void
1814 xgell_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
1815 {
1816 	xgelldev_t *lldev = arg;
1817 	struct iocblk *iocp;
1818 	int err = 0;
1819 	int cmd;
1820 	int need_privilege = 1;
1821 	int ret = 0;
1822 
1823 
1824 	iocp = (struct iocblk *)mp->b_rptr;
1825 	iocp->ioc_error = 0;
1826 	cmd = iocp->ioc_cmd;
1827 	xge_debug_ll(XGE_TRACE, "MAC_IOCTL cmd 0x%x", cmd);
1828 	switch (cmd) {
1829 	case ND_GET:
1830 		need_privilege = 0;
1831 		/* FALLTHRU */
1832 	case ND_SET:
1833 		break;
1834 	default:
1835 		xge_debug_ll(XGE_TRACE, "unknown cmd 0x%x", cmd);
1836 		miocnak(wq, mp, 0, EINVAL);
1837 		return;
1838 	}
1839 
1840 	if (need_privilege) {
1841 		err = secpolicy_net_config(iocp->ioc_cr, B_FALSE);
1842 		if (err != 0) {
1843 			xge_debug_ll(XGE_ERR,
1844 			    "drv_priv(): rejected cmd 0x%x, err %d",
1845 			    cmd, err);
1846 			miocnak(wq, mp, 0, err);
1847 			return;
1848 		}
1849 	}
1850 
1851 	switch (cmd) {
1852 	case ND_GET:
1853 		/*
1854 		 * If nd_getset() returns B_FALSE, the command was
1855 		 * not valid (e.g. unknown name), so we just tell the
1856 		 * top-level ioctl code to send a NAK (with code EINVAL).
1857 		 *
1858 		 * Otherwise, nd_getset() will have built the reply to
1859 		 * be sent (but not actually sent it), so we tell the
1860 		 * caller to send the prepared reply.
1861 		 */
1862 		ret = nd_getset(wq, lldev->ndp, mp);
1863 		xge_debug_ll(XGE_TRACE, "got ndd get ioctl");
1864 		break;
1865 
1866 	case ND_SET:
1867 		ret = nd_getset(wq, lldev->ndp, mp);
1868 		xge_debug_ll(XGE_TRACE, "got ndd set ioctl");
1869 		break;
1870 
1871 	default:
1872 		break;
1873 	}
1874 
1875 	if (ret == B_FALSE) {
1876 		xge_debug_ll(XGE_ERR,
1877 		    "nd_getset(): rejected cmd 0x%x, err %d",
1878 		    cmd, err);
1879 		miocnak(wq, mp, 0, EINVAL);
1880 	} else {
1881 		mp->b_datap->db_type = iocp->ioc_error == 0 ?
1882 		    M_IOCACK : M_IOCNAK;
1883 		qreply(wq, mp);
1884 	}
1885 }
1886 
1887 /* ARGSUSED */
1888 static boolean_t
1889 xgell_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
1890 {
1891 	xgelldev_t *lldev = arg;
1892 
1893 	switch (cap) {
1894 	case MAC_CAPAB_HCKSUM: {
1895 		uint32_t *hcksum_txflags = cap_data;
1896 		*hcksum_txflags = HCKSUM_INET_FULL_V4 | HCKSUM_INET_FULL_V6 |
1897 		    HCKSUM_IPHDRCKSUM;
1898 		break;
1899 	}
1900 	case MAC_CAPAB_LSO: {
1901 		mac_capab_lso_t *cap_lso = cap_data;
1902 
1903 		if (lldev->config.lso_enable) {
1904 			cap_lso->lso_flags = LSO_TX_BASIC_TCP_IPV4;
1905 			cap_lso->lso_basic_tcp_ipv4.lso_max = XGELL_LSO_MAXLEN;
1906 			break;
1907 		} else {
1908 			return (B_FALSE);
1909 		}
1910 	}
1911 	default:
1912 		return (B_FALSE);
1913 	}
1914 	return (B_TRUE);
1915 }
1916 
1917 static int
1918 xgell_stats_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
1919 {
1920 	xgelldev_t *lldev = (xgelldev_t *)cp;
1921 	xge_hal_status_e status;
1922 	int count = 0, retsize;
1923 	char *buf;
1924 
1925 	buf = kmem_alloc(XGELL_STATS_BUFSIZE, KM_SLEEP);
1926 	if (buf == NULL) {
1927 		return (ENOSPC);
1928 	}
1929 
1930 	status = xge_hal_aux_stats_tmac_read(lldev->devh, XGELL_STATS_BUFSIZE,
1931 	    buf, &retsize);
1932 	if (status != XGE_HAL_OK) {
1933 		kmem_free(buf, XGELL_STATS_BUFSIZE);
1934 		xge_debug_ll(XGE_ERR, "tmac_read(): status %d", status);
1935 		return (EINVAL);
1936 	}
1937 	count += retsize;
1938 
1939 	status = xge_hal_aux_stats_rmac_read(lldev->devh,
1940 	    XGELL_STATS_BUFSIZE - count,
1941 	    buf+count, &retsize);
1942 	if (status != XGE_HAL_OK) {
1943 		kmem_free(buf, XGELL_STATS_BUFSIZE);
1944 		xge_debug_ll(XGE_ERR, "rmac_read(): status %d", status);
1945 		return (EINVAL);
1946 	}
1947 	count += retsize;
1948 
1949 	status = xge_hal_aux_stats_pci_read(lldev->devh,
1950 	    XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
1951 	if (status != XGE_HAL_OK) {
1952 		kmem_free(buf, XGELL_STATS_BUFSIZE);
1953 		xge_debug_ll(XGE_ERR, "pci_read(): status %d", status);
1954 		return (EINVAL);
1955 	}
1956 	count += retsize;
1957 
1958 	status = xge_hal_aux_stats_sw_dev_read(lldev->devh,
1959 	    XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
1960 	if (status != XGE_HAL_OK) {
1961 		kmem_free(buf, XGELL_STATS_BUFSIZE);
1962 		xge_debug_ll(XGE_ERR, "sw_dev_read(): status %d", status);
1963 		return (EINVAL);
1964 	}
1965 	count += retsize;
1966 
1967 	status = xge_hal_aux_stats_hal_read(lldev->devh,
1968 	    XGELL_STATS_BUFSIZE - count, buf + count, &retsize);
1969 	if (status != XGE_HAL_OK) {
1970 		kmem_free(buf, XGELL_STATS_BUFSIZE);
1971 		xge_debug_ll(XGE_ERR, "pci_read(): status %d", status);
1972 		return (EINVAL);
1973 	}
1974 	count += retsize;
1975 
1976 	*(buf + count - 1) = '\0'; /* remove last '\n' */
1977 	(void) mi_mpprintf(mp, "%s", buf);
1978 	kmem_free(buf, XGELL_STATS_BUFSIZE);
1979 
1980 	return (0);
1981 }
1982 
1983 static int
1984 xgell_pciconf_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
1985 {
1986 	xgelldev_t *lldev = (xgelldev_t *)cp;
1987 	xge_hal_status_e status;
1988 	int retsize;
1989 	char *buf;
1990 
1991 	buf = kmem_alloc(XGELL_PCICONF_BUFSIZE, KM_SLEEP);
1992 	if (buf == NULL) {
1993 		return (ENOSPC);
1994 	}
1995 	status = xge_hal_aux_pci_config_read(lldev->devh, XGELL_PCICONF_BUFSIZE,
1996 	    buf, &retsize);
1997 	if (status != XGE_HAL_OK) {
1998 		kmem_free(buf, XGELL_PCICONF_BUFSIZE);
1999 		xge_debug_ll(XGE_ERR, "pci_config_read(): status %d", status);
2000 		return (EINVAL);
2001 	}
2002 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
2003 	(void) mi_mpprintf(mp, "%s", buf);
2004 	kmem_free(buf, XGELL_PCICONF_BUFSIZE);
2005 
2006 	return (0);
2007 }
2008 
2009 static int
2010 xgell_about_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2011 {
2012 	xgelldev_t *lldev = (xgelldev_t *)cp;
2013 	xge_hal_status_e status;
2014 	int retsize;
2015 	char *buf;
2016 
2017 	buf = kmem_alloc(XGELL_ABOUT_BUFSIZE, KM_SLEEP);
2018 	if (buf == NULL) {
2019 		return (ENOSPC);
2020 	}
2021 	status = xge_hal_aux_about_read(lldev->devh, XGELL_ABOUT_BUFSIZE,
2022 	    buf, &retsize);
2023 	if (status != XGE_HAL_OK) {
2024 		kmem_free(buf, XGELL_ABOUT_BUFSIZE);
2025 		xge_debug_ll(XGE_ERR, "about_read(): status %d", status);
2026 		return (EINVAL);
2027 	}
2028 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
2029 	(void) mi_mpprintf(mp, "%s", buf);
2030 	kmem_free(buf, XGELL_ABOUT_BUFSIZE);
2031 
2032 	return (0);
2033 }
2034 
2035 static unsigned long bar0_offset = 0x110; /* adapter_control */
2036 
2037 static int
2038 xgell_bar0_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2039 {
2040 	xgelldev_t *lldev = (xgelldev_t *)cp;
2041 	xge_hal_status_e status;
2042 	int retsize;
2043 	char *buf;
2044 
2045 	buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
2046 	if (buf == NULL) {
2047 		return (ENOSPC);
2048 	}
2049 	status = xge_hal_aux_bar0_read(lldev->devh, bar0_offset,
2050 	    XGELL_IOCTL_BUFSIZE, buf, &retsize);
2051 	if (status != XGE_HAL_OK) {
2052 		kmem_free(buf, XGELL_IOCTL_BUFSIZE);
2053 		xge_debug_ll(XGE_ERR, "bar0_read(): status %d", status);
2054 		return (EINVAL);
2055 	}
2056 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
2057 	(void) mi_mpprintf(mp, "%s", buf);
2058 	kmem_free(buf, XGELL_IOCTL_BUFSIZE);
2059 
2060 	return (0);
2061 }
2062 
2063 static int
2064 xgell_bar0_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp, cred_t *credp)
2065 {
2066 	unsigned long old_offset = bar0_offset;
2067 	char *end;
2068 
2069 	if (value && *value == '0' &&
2070 	    (*(value + 1) == 'x' || *(value + 1) == 'X')) {
2071 		value += 2;
2072 	}
2073 
2074 	bar0_offset = mi_strtol(value, &end, 16);
2075 	if (end == value) {
2076 		bar0_offset = old_offset;
2077 		return (EINVAL);
2078 	}
2079 
2080 	xge_debug_ll(XGE_TRACE, "bar0: new value %s:%lX", value, bar0_offset);
2081 
2082 	return (0);
2083 }
2084 
2085 static int
2086 xgell_debug_level_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2087 {
2088 	char *buf;
2089 
2090 	buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
2091 	if (buf == NULL) {
2092 		return (ENOSPC);
2093 	}
2094 	(void) mi_mpprintf(mp, "debug_level %d", xge_hal_driver_debug_level());
2095 	kmem_free(buf, XGELL_IOCTL_BUFSIZE);
2096 
2097 	return (0);
2098 }
2099 
2100 static int
2101 xgell_debug_level_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
2102     cred_t *credp)
2103 {
2104 	int level;
2105 	char *end;
2106 
2107 	level = mi_strtol(value, &end, 10);
2108 	if (level < XGE_NONE || level > XGE_ERR || end == value) {
2109 		return (EINVAL);
2110 	}
2111 
2112 	xge_hal_driver_debug_level_set(level);
2113 
2114 	return (0);
2115 }
2116 
2117 static int
2118 xgell_debug_module_mask_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2119 {
2120 	char *buf;
2121 
2122 	buf = kmem_alloc(XGELL_IOCTL_BUFSIZE, KM_SLEEP);
2123 	if (buf == NULL) {
2124 		return (ENOSPC);
2125 	}
2126 	(void) mi_mpprintf(mp, "debug_module_mask 0x%08x",
2127 	    xge_hal_driver_debug_module_mask());
2128 	kmem_free(buf, XGELL_IOCTL_BUFSIZE);
2129 
2130 	return (0);
2131 }
2132 
2133 static int
2134 xgell_debug_module_mask_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp,
2135 			    cred_t *credp)
2136 {
2137 	u32 mask;
2138 	char *end;
2139 
2140 	if (value && *value == '0' &&
2141 	    (*(value + 1) == 'x' || *(value + 1) == 'X')) {
2142 		value += 2;
2143 	}
2144 
2145 	mask = mi_strtol(value, &end, 16);
2146 	if (end == value) {
2147 		return (EINVAL);
2148 	}
2149 
2150 	xge_hal_driver_debug_module_mask_set(mask);
2151 
2152 	return (0);
2153 }
2154 
2155 static int
2156 xgell_devconfig_get(queue_t *q, mblk_t *mp, caddr_t cp, cred_t *credp)
2157 {
2158 	xgelldev_t *lldev = (xgelldev_t *)(void *)cp;
2159 	xge_hal_status_e status;
2160 	int retsize;
2161 	char *buf;
2162 
2163 	buf = kmem_alloc(XGELL_DEVCONF_BUFSIZE, KM_SLEEP);
2164 	if (buf == NULL) {
2165 		return (ENOSPC);
2166 	}
2167 	status = xge_hal_aux_device_config_read(lldev->devh,
2168 						XGELL_DEVCONF_BUFSIZE,
2169 						buf, &retsize);
2170 	if (status != XGE_HAL_OK) {
2171 		kmem_free(buf, XGELL_DEVCONF_BUFSIZE);
2172 		xge_debug_ll(XGE_ERR, "device_config_read(): status %d",
2173 		    status);
2174 		return (EINVAL);
2175 	}
2176 	*(buf + retsize - 1) = '\0'; /* remove last '\n' */
2177 	(void) mi_mpprintf(mp, "%s", buf);
2178 	kmem_free(buf, XGELL_DEVCONF_BUFSIZE);
2179 
2180 	return (0);
2181 }
2182 
2183 /*
2184  * xgell_device_register
2185  * @devh: pointer on HAL device
2186  * @config: pointer on this network device configuration
2187  * @ll_out: output pointer. Will be assigned to valid LL device.
2188  *
2189  * This function will allocate and register network device
2190  */
2191 int
2192 xgell_device_register(xgelldev_t *lldev, xgell_config_t *config)
2193 {
2194 	mac_register_t *macp = NULL;
2195 	xge_hal_device_t *hldev = (xge_hal_device_t *)lldev->devh;
2196 
2197 	if (nd_load(&lldev->ndp, "pciconf", xgell_pciconf_get, NULL,
2198 	    (caddr_t)lldev) == B_FALSE)
2199 		goto xgell_ndd_fail;
2200 
2201 	if (nd_load(&lldev->ndp, "about", xgell_about_get, NULL,
2202 	    (caddr_t)lldev) == B_FALSE)
2203 		goto xgell_ndd_fail;
2204 
2205 	if (nd_load(&lldev->ndp, "stats", xgell_stats_get, NULL,
2206 	    (caddr_t)lldev) == B_FALSE)
2207 		goto xgell_ndd_fail;
2208 
2209 	if (nd_load(&lldev->ndp, "bar0", xgell_bar0_get, xgell_bar0_set,
2210 	    (caddr_t)lldev) == B_FALSE)
2211 		goto xgell_ndd_fail;
2212 
2213 	if (nd_load(&lldev->ndp, "debug_level", xgell_debug_level_get,
2214 	    xgell_debug_level_set, (caddr_t)lldev) == B_FALSE)
2215 		goto xgell_ndd_fail;
2216 
2217 	if (nd_load(&lldev->ndp, "debug_module_mask",
2218 	    xgell_debug_module_mask_get, xgell_debug_module_mask_set,
2219 	    (caddr_t)lldev) == B_FALSE)
2220 		goto xgell_ndd_fail;
2221 
2222 	if (nd_load(&lldev->ndp, "devconfig", xgell_devconfig_get, NULL,
2223 	    (caddr_t)lldev) == B_FALSE)
2224 		goto xgell_ndd_fail;
2225 
2226 	bcopy(config, &lldev->config, sizeof (xgell_config_t));
2227 
2228 	if (xgell_rx_create_buffer_pool(lldev) != DDI_SUCCESS) {
2229 		nd_free(&lldev->ndp);
2230 		xge_debug_ll(XGE_ERR, "unable to create RX buffer pool");
2231 		return (DDI_FAILURE);
2232 	}
2233 
2234 	mutex_init(&lldev->genlock, NULL, MUTEX_DRIVER, hldev->irqh);
2235 
2236 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
2237 		goto xgell_register_fail;
2238 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
2239 	macp->m_driver = lldev;
2240 	macp->m_dip = lldev->dev_info;
2241 	macp->m_src_addr = hldev->macaddr[0];
2242 	macp->m_callbacks = &xgell_m_callbacks;
2243 	macp->m_min_sdu = 0;
2244 	macp->m_max_sdu = hldev->config.mtu;
2245 	/*
2246 	 * Finally, we're ready to register ourselves with the Nemo
2247 	 * interface; if this succeeds, we're all ready to start()
2248 	 */
2249 
2250 	if (mac_register(macp, &lldev->mh) != 0)
2251 		goto xgell_register_fail;
2252 
2253 	/* Always free the macp after register */
2254 	if (macp != NULL)
2255 		mac_free(macp);
2256 
2257 	/* Calculate tx_copied_max here ??? */
2258 	lldev->tx_copied_max = hldev->config.fifo.max_frags *
2259 		hldev->config.fifo.alignment_size *
2260 		hldev->config.fifo.max_aligned_frags;
2261 
2262 	xge_debug_ll(XGE_TRACE, "etherenet device %s%d registered",
2263 	    XGELL_IFNAME, lldev->instance);
2264 
2265 	return (DDI_SUCCESS);
2266 
2267 xgell_ndd_fail:
2268 	nd_free(&lldev->ndp);
2269 	xge_debug_ll(XGE_ERR, "%s", "unable to load ndd parameter");
2270 	return (DDI_FAILURE);
2271 
2272 xgell_register_fail:
2273 	if (macp != NULL)
2274 		mac_free(macp);
2275 	nd_free(&lldev->ndp);
2276 	mutex_destroy(&lldev->genlock);
2277 	/* Ignore return value, since RX not start */
2278 	(void) xgell_rx_destroy_buffer_pool(lldev);
2279 	xge_debug_ll(XGE_ERR, "%s", "unable to register networking device");
2280 	return (DDI_FAILURE);
2281 }
2282 
2283 /*
2284  * xgell_device_unregister
2285  * @devh: pointer on HAL device
2286  * @lldev: pointer to valid LL device.
2287  *
2288  * This function will unregister and free network device
2289  */
2290 int
2291 xgell_device_unregister(xgelldev_t *lldev)
2292 {
2293 	/*
2294 	 * Destroy RX buffer pool.
2295 	 */
2296 	if (xgell_rx_destroy_buffer_pool(lldev) != DDI_SUCCESS) {
2297 		return (DDI_FAILURE);
2298 	}
2299 
2300 	if (mac_unregister(lldev->mh) != 0) {
2301 		xge_debug_ll(XGE_ERR, "unable to unregister device %s%d",
2302 		    XGELL_IFNAME, lldev->instance);
2303 		return (DDI_FAILURE);
2304 	}
2305 
2306 	mutex_destroy(&lldev->genlock);
2307 
2308 	nd_free(&lldev->ndp);
2309 
2310 	xge_debug_ll(XGE_TRACE, "etherenet device %s%d unregistered",
2311 	    XGELL_IFNAME, lldev->instance);
2312 
2313 	return (DDI_SUCCESS);
2314 }
2315