xref: /illumos-gate/usr/src/uts/common/io/chxge/pe.c (revision 4e2c3273)
1d39a76e7Sxw /*
2d39a76e7Sxw  * CDDL HEADER START
3d39a76e7Sxw  *
4d39a76e7Sxw  * The contents of this file are subject to the terms of the
5d39a76e7Sxw  * Common Development and Distribution License (the "License").
6d39a76e7Sxw  * You may not use this file except in compliance with the License.
7d39a76e7Sxw  *
8d39a76e7Sxw  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9d39a76e7Sxw  * or http://www.opensolaris.org/os/licensing.
10d39a76e7Sxw  * See the License for the specific language governing permissions
11d39a76e7Sxw  * and limitations under the License.
12d39a76e7Sxw  *
13d39a76e7Sxw  * When distributing Covered Code, include this CDDL HEADER in each
14d39a76e7Sxw  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15d39a76e7Sxw  * If applicable, add the following below this CDDL HEADER, with the
16d39a76e7Sxw  * fields enclosed by brackets "[]" replaced with your own identifying
17d39a76e7Sxw  * information: Portions Copyright [yyyy] [name of copyright owner]
18d39a76e7Sxw  *
19d39a76e7Sxw  * CDDL HEADER END
20d39a76e7Sxw  */
21d39a76e7Sxw 
22d39a76e7Sxw /*
23d39a76e7Sxw  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24d39a76e7Sxw  * Use is subject to license terms.
25d39a76e7Sxw  */
26d39a76e7Sxw 
27d39a76e7Sxw /*
28d39a76e7Sxw  * This file is part of the Chelsio T1 Ethernet driver.
29d39a76e7Sxw  *
30d39a76e7Sxw  * Copyright (C) 2003-2005 Chelsio Communications.  All rights reserved.
31d39a76e7Sxw  */
32d39a76e7Sxw 
33d39a76e7Sxw /*
34d39a76e7Sxw  * Solaris Multithreaded STREAMS Chelsio PCI Ethernet Driver.
35d39a76e7Sxw  * Interface code
36d39a76e7Sxw  */
37d39a76e7Sxw 
38d39a76e7Sxw #include <sys/types.h>
39d39a76e7Sxw #include <sys/systm.h>
40d39a76e7Sxw #include <sys/cmn_err.h>
41d39a76e7Sxw #include <sys/ddi.h>
42d39a76e7Sxw #include <sys/sunddi.h>
43d39a76e7Sxw #include <sys/byteorder.h>
44d39a76e7Sxw #include <sys/atomic.h>
45d39a76e7Sxw #include <sys/ethernet.h>
46d39a76e7Sxw #if PE_PROFILING_ENABLED
47d39a76e7Sxw #include <sys/time.h>
48d39a76e7Sxw #endif
49d39a76e7Sxw #include <sys/gld.h>
50d39a76e7Sxw #include "ostypes.h"
51d39a76e7Sxw #include "common.h"
52d39a76e7Sxw #include "oschtoe.h"
53d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_1G
54d39a76e7Sxw #include "fpga_defs.h"
55d39a76e7Sxw #endif
56d39a76e7Sxw #include "regs.h"
57d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
58d39a76e7Sxw #include "mc3.h"
59d39a76e7Sxw #include "mc4.h"
60d39a76e7Sxw #endif
61d39a76e7Sxw #include "sge.h"
62d39a76e7Sxw #include "tp.h"
63d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
64d39a76e7Sxw #include "ulp.h"
65d39a76e7Sxw #endif
66d39a76e7Sxw #include "espi.h"
67d39a76e7Sxw #include "elmer0.h"
68d39a76e7Sxw #include "gmac.h"
69d39a76e7Sxw #include "cphy.h"
70d39a76e7Sxw #include "suni1x10gexp_regs.h"
71d39a76e7Sxw #include "ch.h"
72d39a76e7Sxw 
73d39a76e7Sxw #define	MLEN(mp) ((mp)->b_wptr - (mp)->b_rptr)
74d39a76e7Sxw 
75d39a76e7Sxw extern uint32_t buffers_in_use[];
76d39a76e7Sxw extern kmutex_t in_use_l;
77d39a76e7Sxw extern uint32_t in_use_index;
78d39a76e7Sxw 
79d39a76e7Sxw static void link_start(ch_t *sa, struct pe_port_t *pp);
80d39a76e7Sxw static ch_esb_t *ch_alloc_small_esbbuf(ch_t *sa, uint32_t i);
81d39a76e7Sxw static ch_esb_t *ch_alloc_big_esbbuf(ch_t *sa, uint32_t i);
82d39a76e7Sxw void ch_big_rbuf_recycle(ch_esb_t *rbp);
83d39a76e7Sxw void ch_small_rbuf_recycle(ch_esb_t *rbp);
84d39a76e7Sxw static const struct board_info *pe_sa_init(ch_t *sa);
85d39a76e7Sxw static int ch_set_config_data(ch_t *chp);
86d39a76e7Sxw void pe_rbuf_pool_free(ch_t *chp);
87d39a76e7Sxw static void pe_free_driver_resources(ch_t *sa);
88d39a76e7Sxw static void update_mtu_tab(ch_t *adapter);
89d39a76e7Sxw static int pe_change_mtu(ch_t *chp);
90d39a76e7Sxw 
91d39a76e7Sxw /*
92d39a76e7Sxw  * CPL5 Defines (from netinet/cpl5_commands.h)
93d39a76e7Sxw  */
94d39a76e7Sxw #define	FLITSTOBYTES	8
95d39a76e7Sxw 
96d39a76e7Sxw #define	CPL_FORMAT_0_SIZE 8
97d39a76e7Sxw #define	CPL_FORMAT_1_SIZE 16
98d39a76e7Sxw #define	CPL_FORMAT_2_SIZE 24
99d39a76e7Sxw #define	CPL_FORMAT_3_SIZE 32
100d39a76e7Sxw #define	CPL_FORMAT_4_SIZE 40
101d39a76e7Sxw #define	CPL_FORMAT_5_SIZE 48
102d39a76e7Sxw 
103d39a76e7Sxw #define	TID_MASK 0xffffff
104d39a76e7Sxw 
105d39a76e7Sxw #define	PE_LINK_SPEED_AUTONEG	5
106d39a76e7Sxw 
107d39a76e7Sxw static int pe_small_rbuf_pool_init(ch_t *sa);
108d39a76e7Sxw static int pe_big_rbuf_pool_init(ch_t *sa);
109d39a76e7Sxw static int pe_make_fake_arp(ch_t *chp, unsigned char *arpp);
110d39a76e7Sxw static uint32_t pe_get_ip(unsigned char *arpp);
111d39a76e7Sxw 
112d39a76e7Sxw /*
113d39a76e7Sxw  * May be set in /etc/system to 0 to use default latency timer for 10G.
114d39a76e7Sxw  * See PCI register 0xc definition.
115d39a76e7Sxw  */
116d39a76e7Sxw int enable_latency_timer = 1;
117d39a76e7Sxw 
118d39a76e7Sxw /*
119d39a76e7Sxw  * May be set in /etc/system to 0 to disable hardware checksum for
120d39a76e7Sxw  * TCP and UDP.
121d39a76e7Sxw  */
122d39a76e7Sxw int enable_checksum_offload = 1;
123d39a76e7Sxw 
124d39a76e7Sxw /*
125d39a76e7Sxw  * Multiplier for freelist pool.
126d39a76e7Sxw  */
127d39a76e7Sxw int fl_sz_multiplier = 6;
128d39a76e7Sxw 
129d39a76e7Sxw uint_t
pe_intr(ch_t * sa)130d39a76e7Sxw pe_intr(ch_t *sa)
131d39a76e7Sxw {
132d39a76e7Sxw 	mutex_enter(&sa->ch_intr);
133d39a76e7Sxw 
134d39a76e7Sxw 	if (sge_data_in(sa->sge)) {
135d39a76e7Sxw 		sa->isr_intr++;
136d39a76e7Sxw 		mutex_exit(&sa->ch_intr);
137d39a76e7Sxw 		return (DDI_INTR_CLAIMED);
138d39a76e7Sxw 	}
139d39a76e7Sxw 
140d39a76e7Sxw 	mutex_exit(&sa->ch_intr);
141d39a76e7Sxw 
142d39a76e7Sxw 	return (DDI_INTR_UNCLAIMED);
143d39a76e7Sxw }
144d39a76e7Sxw 
145d39a76e7Sxw /*
146d39a76e7Sxw  * Each setup struct will call this function to
147d39a76e7Sxw  * initialize.
148d39a76e7Sxw  */
149d39a76e7Sxw void
pe_init(void * xsa)150d39a76e7Sxw pe_init(void* xsa)
151d39a76e7Sxw {
152d39a76e7Sxw 	ch_t *sa = NULL;
153d39a76e7Sxw 	int i = 0;
154d39a76e7Sxw 
155d39a76e7Sxw 	sa = (ch_t *)xsa;
156d39a76e7Sxw 
157d39a76e7Sxw 	/*
158d39a76e7Sxw 	 * Need to count the number of times this routine is called
159d39a76e7Sxw 	 * because we only want the resources to be allocated once.
160d39a76e7Sxw 	 * The 7500 has four ports and so this routine can be called
161d39a76e7Sxw 	 * once for each port.
162d39a76e7Sxw 	 */
163d39a76e7Sxw 	if (sa->init_counter == 0) {
164d39a76e7Sxw 		for_each_port(sa, i) {
165d39a76e7Sxw 
166d39a76e7Sxw 			/*
167d39a76e7Sxw 			 * We only want to initialize the line if it is down.
168d39a76e7Sxw 			 */
169d39a76e7Sxw 			if (sa->port[i].line_up == 0) {
170d39a76e7Sxw 				link_start(sa, &sa->port[i]);
171d39a76e7Sxw 				sa->port[i].line_up = 1;
172d39a76e7Sxw 			}
173d39a76e7Sxw 		}
174d39a76e7Sxw 
175d39a76e7Sxw 		(void) t1_init_hw_modules(sa);
176d39a76e7Sxw 
177d39a76e7Sxw 		/*
178d39a76e7Sxw 		 * Enable/Disable checksum offloading.
179d39a76e7Sxw 		 */
180d39a76e7Sxw 		if (sa->ch_config.cksum_enabled) {
181d39a76e7Sxw 			if (sa->config_data.offload_ip_cksum) {
182d39a76e7Sxw 				/* Notify that HW will do the checksum. */
183d39a76e7Sxw 				t1_tp_set_ip_checksum_offload(sa->tp, 1);
184d39a76e7Sxw 			}
185d39a76e7Sxw 
186d39a76e7Sxw 			if (sa->config_data.offload_tcp_cksum) {
187d39a76e7Sxw 				/* Notify that HW will do the checksum. */
188d39a76e7Sxw 				t1_tp_set_tcp_checksum_offload(sa->tp, 1);
189d39a76e7Sxw 			}
190d39a76e7Sxw 
191d39a76e7Sxw 			if (sa->config_data.offload_udp_cksum) {
192d39a76e7Sxw 				/* Notify that HW will do the checksum. */
193d39a76e7Sxw 				t1_tp_set_udp_checksum_offload(sa->tp, 1);
194d39a76e7Sxw 			}
195d39a76e7Sxw 		}
196d39a76e7Sxw 
197d39a76e7Sxw 		sa->ch_flags |= PEINITDONE;
198d39a76e7Sxw 
199d39a76e7Sxw 		sa->init_counter++;
200d39a76e7Sxw 	}
201d39a76e7Sxw 
202d39a76e7Sxw 	/*
203d39a76e7Sxw 	 * Enable interrupts after starting the SGE so
204d39a76e7Sxw 	 * that the SGE is ready to handle interrupts.
205d39a76e7Sxw 	 */
206d39a76e7Sxw 	(void) sge_start(sa->sge);
207d39a76e7Sxw 	t1_interrupts_enable(sa);
208d39a76e7Sxw 
209d39a76e7Sxw 	/*
210d39a76e7Sxw 	 * set mtu (either 1500 or bigger)
211d39a76e7Sxw 	 */
212d39a76e7Sxw 	(void) pe_change_mtu(sa);
213d39a76e7Sxw #ifdef HOST_PAUSE
214d39a76e7Sxw 	/*
215d39a76e7Sxw 	 * get the configured value of the MAC.
216d39a76e7Sxw 	 */
217d39a76e7Sxw 	(void) t1_tpi_read(sa, SUNI1x10GEXP_REG_TXXG_CONFIG_1 << 2,
218d39a76e7Sxw 	    &sa->txxg_cfg1);
219d39a76e7Sxw #endif
220d39a76e7Sxw }
221d39a76e7Sxw 
222d39a76e7Sxw /* ARGSUSED */
223d39a76e7Sxw static void
link_start(ch_t * sa,struct pe_port_t * p)224d39a76e7Sxw link_start(ch_t *sa, struct pe_port_t *p)
225d39a76e7Sxw {
226d39a76e7Sxw 	struct cmac *mac = p->mac;
227d39a76e7Sxw 
228d39a76e7Sxw 	mac->ops->reset(mac);
229d39a76e7Sxw 	if (mac->ops->macaddress_set)
230d39a76e7Sxw 		mac->ops->macaddress_set(mac, p->enaddr);
231d39a76e7Sxw 	(void) t1_link_start(p->phy, mac, &p->link_config);
232d39a76e7Sxw 	mac->ops->enable(mac, MAC_DIRECTION_RX | MAC_DIRECTION_TX);
233d39a76e7Sxw }
234d39a76e7Sxw 
235d39a76e7Sxw /*
236d39a76e7Sxw  * turn off interrupts...
237d39a76e7Sxw  */
238d39a76e7Sxw void
pe_stop(ch_t * sa)239d39a76e7Sxw pe_stop(ch_t *sa)
240d39a76e7Sxw {
241d39a76e7Sxw 	t1_interrupts_disable(sa);
242d39a76e7Sxw 	(void) sge_stop(sa->sge);
243d39a76e7Sxw 
244d39a76e7Sxw 	/*
245d39a76e7Sxw 	 * we can still be running an interrupt thread in sge_data_in().
246d39a76e7Sxw 	 * If we are, we'll block on the ch_intr lock
247d39a76e7Sxw 	 */
248d39a76e7Sxw 	mutex_enter(&sa->ch_intr);
249d39a76e7Sxw 	mutex_exit(&sa->ch_intr);
250d39a76e7Sxw }
251d39a76e7Sxw 
252d39a76e7Sxw /*
253d39a76e7Sxw  * output mblk to SGE level and out to the wire.
254d39a76e7Sxw  */
255d39a76e7Sxw 
256d39a76e7Sxw int
pe_start(ch_t * sa,mblk_t * mp,uint32_t flg)257d39a76e7Sxw pe_start(ch_t *sa, mblk_t *mp, uint32_t flg)
258d39a76e7Sxw {
259d39a76e7Sxw 	mblk_t *m0 = mp;
260d39a76e7Sxw 	cmdQ_ce_t cm[16];
261d39a76e7Sxw 	cmdQ_ce_t *cmp;
262d39a76e7Sxw 	cmdQ_ce_t *hmp = &cm[0]; /* head of cm table (may be kmem_alloed) */
263d39a76e7Sxw 	int cm_flg = 0;		/* flag (1 - if kmem-alloced) */
264d39a76e7Sxw 	int nseg = 0;		/* number cmdQ_ce entries created */
265d39a76e7Sxw 	int mseg = 16;		/* maximum entries in hmp arrary */
266d39a76e7Sxw 	int freeme = 0;		/* we have an mblk to free in case of error */
267d39a76e7Sxw 	uint32_t ch_bind_dma_handle(ch_t *, int, caddr_t, cmdQ_ce_t *,
268d39a76e7Sxw 	    uint32_t);
269d39a76e7Sxw #if defined(__sparc)
270d39a76e7Sxw 	uint32_t ch_bind_dvma_handle(ch_t *, int, caddr_t, cmdQ_ce_t *,
271d39a76e7Sxw 	    uint32_t);
272d39a76e7Sxw #endif
273d39a76e7Sxw 	int rv;			/* return value on error */
274d39a76e7Sxw 
275d39a76e7Sxw #ifdef CONFIG_CHELSIO_T1_OFFLOAD
276d39a76e7Sxw 	if (flg & CH_OFFLOAD) {
277d39a76e7Sxw 		hmp->ce_pa = ((tbuf_t *)mp)->tb_pa;
278d39a76e7Sxw 		hmp->ce_dh = NULL;
279d39a76e7Sxw 		hmp->ce_flg = DH_TOE;
280d39a76e7Sxw 		hmp->ce_len = ((tbuf_t *)mp)->tb_len;
281d39a76e7Sxw 		hmp->ce_mp = mp;
282d39a76e7Sxw 
283d39a76e7Sxw 		/* make sure data is flushed to physical memory */
284d39a76e7Sxw 		(void) ddi_dma_sync((ddi_dma_handle_t)((tbuf_t *)mp)->tb_dh,
285d39a76e7Sxw 		    (off_t)0, hmp->ce_len, DDI_DMA_SYNC_FORDEV);
286d39a76e7Sxw 
287d39a76e7Sxw 		if (sge_data_out(sa->sge, 0, mp, hmp, 1, flg) == 0) {
288d39a76e7Sxw 			return (0);
289d39a76e7Sxw 		}
290d39a76e7Sxw 
291d39a76e7Sxw 		/*
292d39a76e7Sxw 		 * set a flag so we'll restart upper layer when
293d39a76e7Sxw 		 * resources become available.
294d39a76e7Sxw 		 */
295d39a76e7Sxw 		sa->ch_blked = 1;
296d39a76e7Sxw 		return (1);
297d39a76e7Sxw 	}
298d39a76e7Sxw #endif	/* CONFIG_CHELSIO_T1_OFFLOAD */
299d39a76e7Sxw 
300d39a76e7Sxw 	/* writes from toe will always have CPL header in place */
301d39a76e7Sxw 	if (flg & CH_NO_CPL) {
302d39a76e7Sxw 		struct cpl_tx_pkt *cpl;
303d39a76e7Sxw 
304d39a76e7Sxw 		/* PR2928 & PR3309 */
30511abda1eSToomas Soome 		if (sa->ch_ip == 0) {
306d39a76e7Sxw 			ushort_t ethertype = ntohs(*(short *)&mp->b_rptr[12]);
307d39a76e7Sxw 			if (ethertype == ETHERTYPE_ARP) {
308d39a76e7Sxw 				if (is_T2(sa)) {
309d39a76e7Sxw 					/*
310d39a76e7Sxw 					 * We assume here that the arp will be
311d39a76e7Sxw 					 * contained in one mblk.
312d39a76e7Sxw 					 */
313d39a76e7Sxw 					if (pe_make_fake_arp(sa, mp->b_rptr)) {
314d39a76e7Sxw 						freemsg(mp);
315d39a76e7Sxw 						sa->oerr++;
316d39a76e7Sxw 						return (0);
317d39a76e7Sxw 					}
318d39a76e7Sxw 				} else {
319d39a76e7Sxw 					sa->ch_ip = pe_get_ip(mp->b_rptr);
320d39a76e7Sxw 				}
321d39a76e7Sxw 			}
322d39a76e7Sxw 		}
323d39a76e7Sxw 
324d39a76e7Sxw 		/*
325d39a76e7Sxw 		 * if space in front of packet big enough for CPL
326d39a76e7Sxw 		 * header, then use it. We'll allocate an mblk
327d39a76e7Sxw 		 * otherwise.
328d39a76e7Sxw 		 */
329d39a76e7Sxw 		if ((mp->b_rptr - mp->b_datap->db_base) >= SZ_CPL_TX_PKT) {
330d39a76e7Sxw 
331d39a76e7Sxw 			mp->b_rptr -= SZ_CPL_TX_PKT;
332d39a76e7Sxw 
333d39a76e7Sxw 		} else {
334d39a76e7Sxw 
335d39a76e7Sxw #ifdef SUN_KSTATS
336d39a76e7Sxw 			sa->sge->intr_cnt.tx_need_cpl_space++;
337d39a76e7Sxw #endif
338d39a76e7Sxw 			m0 = allocb(SZ_CPL_TX_PKT, BPRI_HI);
339d39a76e7Sxw 			if (m0 == NULL) {
340d39a76e7Sxw 				freemsg(mp);
341d39a76e7Sxw 				sa->oerr++;
342d39a76e7Sxw 				return (0);
343d39a76e7Sxw 			}
344d39a76e7Sxw 
345d39a76e7Sxw 			m0->b_wptr = m0->b_rptr + SZ_CPL_TX_PKT;
346d39a76e7Sxw 			m0->b_cont = mp;
347d39a76e7Sxw 			freeme = 1;
348d39a76e7Sxw 
349d39a76e7Sxw 			mp = m0;
350d39a76e7Sxw 		}
351d39a76e7Sxw 
352d39a76e7Sxw 		/* fill in cpl header */
353d39a76e7Sxw 		cpl = (struct cpl_tx_pkt *)mp->b_rptr;
354d39a76e7Sxw 		cpl->opcode = CPL_TX_PKT;
355d39a76e7Sxw 		cpl->iff = 0;		/* XXX port 0 needs fixing with NEMO */
356d39a76e7Sxw 		cpl->ip_csum_dis = 1;	/* no IP header cksum */
357d39a76e7Sxw 		cpl->l4_csum_dis =
358d39a76e7Sxw 		    flg & CH_NO_HWCKSUM;	/* CH_NO_HWCKSUM == 1 */
359d39a76e7Sxw 		cpl->vlan_valid = 0;		/* no vlan */
360d39a76e7Sxw 	}
361d39a76e7Sxw 
362d39a76e7Sxw 	if (m0->b_cont) {
363d39a76e7Sxw 
364d39a76e7Sxw #ifdef SUN_KSTATS
365d39a76e7Sxw 			sa->sge->intr_cnt.tx_multi_mblks++;
366d39a76e7Sxw #endif
367d39a76e7Sxw 
368d39a76e7Sxw 		while (mp) {
369d39a76e7Sxw 			int lseg;	/* added by ch_bind_dma_handle() */
370d39a76e7Sxw 			int len;
371d39a76e7Sxw 
372d39a76e7Sxw 			len = MLEN(mp);
373d39a76e7Sxw 			/* skip mlks with no data */
374d39a76e7Sxw 			if (len == 0) {
375d39a76e7Sxw 				mp = mp->b_cont;
376d39a76e7Sxw 				continue;
377d39a76e7Sxw 			}
378d39a76e7Sxw 
379d39a76e7Sxw 			/*
380d39a76e7Sxw 			 * if we've run out of space on stack, then we
381d39a76e7Sxw 			 * allocate a temporary buffer to hold the
382d39a76e7Sxw 			 * information. This will kill the the performance,
383d39a76e7Sxw 			 * but since it shouldn't really occur, we can live
384d39a76e7Sxw 			 * with it. Since jumbo frames may map multiple
385d39a76e7Sxw 			 * descriptors, we reallocate the hmp[] array before
386d39a76e7Sxw 			 * we reach the end.
387d39a76e7Sxw 			 */
388d39a76e7Sxw 			if (nseg >= (mseg-4)) {
389d39a76e7Sxw 				cmdQ_ce_t *buf;
390d39a76e7Sxw 				int j;
391d39a76e7Sxw 
392d39a76e7Sxw 				buf = kmem_alloc(sizeof (cmdQ_ce_t) * 2 * mseg,
393d39a76e7Sxw 				    KM_SLEEP);
394d39a76e7Sxw 
395d39a76e7Sxw 				for (j = 0; j < nseg; j++)
396d39a76e7Sxw 					buf[j] = hmp[j];
397d39a76e7Sxw 
398d39a76e7Sxw 				if (cm_flg) {
399d39a76e7Sxw 					kmem_free(hmp,
400d39a76e7Sxw 					    mseg * sizeof (cmdQ_ce_t));
401d39a76e7Sxw 				} else
402d39a76e7Sxw 					cm_flg = 1;
403d39a76e7Sxw 
404d39a76e7Sxw 				hmp = buf;
405d39a76e7Sxw 				mseg = 2*mseg;
406d39a76e7Sxw 
407d39a76e7Sxw 				/*
408d39a76e7Sxw 				 * We've used up ch table on stack
409d39a76e7Sxw 				 */
410d39a76e7Sxw 			}
411d39a76e7Sxw 
412d39a76e7Sxw #if defined(__sparc)
413d39a76e7Sxw 			if (sa->ch_config.enable_dvma) {
414d39a76e7Sxw 				lseg = ch_bind_dvma_handle(sa, len,
415d39a76e7Sxw 				    (void *)mp->b_rptr,
416d39a76e7Sxw 				    &hmp[nseg], mseg - nseg);
417*4e2c3273SToomas Soome 				if (lseg == 0) {
418d39a76e7Sxw 					sa->sge->intr_cnt.tx_no_dvma1++;
419d39a76e7Sxw 					if ((lseg = ch_bind_dma_handle(sa, len,
420d39a76e7Sxw 					    (void *)mp->b_rptr,
421d39a76e7Sxw 					    &hmp[nseg],
422*4e2c3273SToomas Soome 					    mseg - nseg)) == 0) {
423d39a76e7Sxw 						sa->sge->intr_cnt.tx_no_dma1++;
424d39a76e7Sxw 
425d39a76e7Sxw 						/*
426d39a76e7Sxw 						 * ran out of space. Gonna bale
427d39a76e7Sxw 						 */
428d39a76e7Sxw 						rv = 0;
429d39a76e7Sxw 
430d39a76e7Sxw 						/*
431d39a76e7Sxw 						 * we may have processed
432d39a76e7Sxw 						 * previous mblks and have
433d39a76e7Sxw 						 * descriptors. If so, we need
434d39a76e7Sxw 						 * to free the meta struct
435d39a76e7Sxw 						 * entries before freeing
436d39a76e7Sxw 						 * the mblk.
437d39a76e7Sxw 						 */
438d39a76e7Sxw 						if (nseg)
439d39a76e7Sxw 							goto error;
440d39a76e7Sxw 						goto error1;
441d39a76e7Sxw 					}
442d39a76e7Sxw 				}
443d39a76e7Sxw 			} else {
444d39a76e7Sxw 				lseg = ch_bind_dma_handle(sa, len,
445d39a76e7Sxw 				    (void *)mp->b_rptr, &hmp[nseg],
446d39a76e7Sxw 				    mseg - nseg);
447*4e2c3273SToomas Soome 				if (lseg == 0) {
448d39a76e7Sxw 					sa->sge->intr_cnt.tx_no_dma1++;
449d39a76e7Sxw 
450d39a76e7Sxw 					/*
451d39a76e7Sxw 					 * ran out of space. Gona bale
452d39a76e7Sxw 					 */
453d39a76e7Sxw 					rv = 0;
454d39a76e7Sxw 
455d39a76e7Sxw 					/*
456d39a76e7Sxw 					 * we may have processed previous
457d39a76e7Sxw 					 * mblks and have descriptors. If so,
458d39a76e7Sxw 					 * we need to free the meta struct
459d39a76e7Sxw 					 * entries before freeing the mblk.
460d39a76e7Sxw 					 */
461d39a76e7Sxw 					if (nseg)
462d39a76e7Sxw 						goto error;
463d39a76e7Sxw 					goto error1;
464d39a76e7Sxw 				}
465d39a76e7Sxw 			}
466d39a76e7Sxw #else	/* defined(__sparc) */
467d39a76e7Sxw 			lseg = ch_bind_dma_handle(sa, len,
468d39a76e7Sxw 			    (void *)mp->b_rptr, &hmp[nseg],
469d39a76e7Sxw 			    mseg - nseg);
47011abda1eSToomas Soome 			if (lseg == 0) {
471d39a76e7Sxw 				sa->sge->intr_cnt.tx_no_dma1++;
472d39a76e7Sxw 
473d39a76e7Sxw 				/*
474d39a76e7Sxw 				 * ran out of space. Gona bale
475d39a76e7Sxw 				 */
476d39a76e7Sxw 				rv = 0;
477d39a76e7Sxw 
478d39a76e7Sxw 				/*
479d39a76e7Sxw 				 * we may have processed previous mblks and
480d39a76e7Sxw 				 * have descriptors. If so, we need to free
481d39a76e7Sxw 				 * the meta struct entries before freeing
482d39a76e7Sxw 				 * the mblk.
483d39a76e7Sxw 				 */
484d39a76e7Sxw 				if (nseg)
485d39a76e7Sxw 					goto error;
486d39a76e7Sxw 				goto error1;
487d39a76e7Sxw 			}
488d39a76e7Sxw #endif	/* defined(__sparc) */
489d39a76e7Sxw 			nseg += lseg;
490d39a76e7Sxw 			mp = mp->b_cont;
491d39a76e7Sxw 		}
492d39a76e7Sxw 
493d39a76e7Sxw 		/*
494d39a76e7Sxw 		 * SHOULD NEVER OCCUR, BUT...
495d39a76e7Sxw 		 * no data if nseg 0 or
496d39a76e7Sxw 		 * nseg 1 and a CPL mblk (CPL mblk only with offload mode)
497d39a76e7Sxw 		 * and no data
498d39a76e7Sxw 		 */
499d39a76e7Sxw 		if ((nseg == 0) || (freeme && (nseg == 1))) {
500d39a76e7Sxw 			rv = 0;
501d39a76e7Sxw 			goto error1;
502d39a76e7Sxw 		}
503d39a76e7Sxw 
504d39a76e7Sxw 	} else {
505d39a76e7Sxw 		int len;
506d39a76e7Sxw 
507d39a76e7Sxw 		/* we assume that we always have data with one packet */
508d39a76e7Sxw 		len = MLEN(mp);
509d39a76e7Sxw 
510d39a76e7Sxw #if defined(__sparc)
511d39a76e7Sxw 		if (sa->ch_config.enable_dvma) {
512d39a76e7Sxw 			nseg = ch_bind_dvma_handle(sa, len,
513d39a76e7Sxw 			    (void *)mp->b_rptr,
514d39a76e7Sxw 			    &hmp[0], 16);
515*4e2c3273SToomas Soome 			if (nseg == 0) {
516d39a76e7Sxw 				sa->sge->intr_cnt.tx_no_dvma2++;
517d39a76e7Sxw 				nseg = ch_bind_dma_handle(sa, len,
518d39a76e7Sxw 				    (void *)mp->b_rptr,
519d39a76e7Sxw 				    &hmp[0], 16);
520*4e2c3273SToomas Soome 				if (nseg == 0) {
521d39a76e7Sxw 					sa->sge->intr_cnt.tx_no_dma2++;
522d39a76e7Sxw 
523d39a76e7Sxw 					/*
524d39a76e7Sxw 					 * ran out of space. Gona bale
525d39a76e7Sxw 					 */
526d39a76e7Sxw 					rv = 0;
527d39a76e7Sxw 					goto error1;
528d39a76e7Sxw 				}
529d39a76e7Sxw 			}
530d39a76e7Sxw 		} else {
531d39a76e7Sxw 			nseg = ch_bind_dma_handle(sa, len,
532d39a76e7Sxw 			    (void *)mp->b_rptr, &hmp[0], 16);
533*4e2c3273SToomas Soome 			if (nseg == 0) {
534d39a76e7Sxw 				sa->sge->intr_cnt.tx_no_dma2++;
535d39a76e7Sxw 
536d39a76e7Sxw 				/*
537d39a76e7Sxw 				 * ran out of space. Gona bale
538d39a76e7Sxw 				 */
539d39a76e7Sxw 				rv = 0;
540d39a76e7Sxw 				goto error1;
541d39a76e7Sxw 			}
542d39a76e7Sxw 		}
543d39a76e7Sxw #else	/* defined(__sparc) */
544d39a76e7Sxw 		nseg = ch_bind_dma_handle(sa, len,
545d39a76e7Sxw 		    (void *)mp->b_rptr, &hmp[0], 16);
54611abda1eSToomas Soome 		if (nseg == 0) {
547d39a76e7Sxw 			sa->sge->intr_cnt.tx_no_dma2++;
548d39a76e7Sxw 
549d39a76e7Sxw 			/*
550d39a76e7Sxw 			 * ran out of space. Gona bale
551d39a76e7Sxw 			 */
552d39a76e7Sxw 			rv = 0;
553d39a76e7Sxw 			goto error1;
554d39a76e7Sxw 		}
555d39a76e7Sxw #endif	/* defined(__sparc) */
556d39a76e7Sxw 
557d39a76e7Sxw 		/*
558d39a76e7Sxw 		 * dummy arp message to handle PR3309 & PR2928
559d39a76e7Sxw 		 */
560d39a76e7Sxw 		if (flg & CH_ARP)
561d39a76e7Sxw 			hmp->ce_flg |= DH_ARP;
562d39a76e7Sxw 	}
563d39a76e7Sxw 
564d39a76e7Sxw 	if (sge_data_out(sa->sge, 0, m0, hmp, nseg, flg) == 0) {
565d39a76e7Sxw 		if (cm_flg)
566d39a76e7Sxw 			kmem_free(hmp, mseg * sizeof (cmdQ_ce_t));
567d39a76e7Sxw 		return (0);
568d39a76e7Sxw 	}
569d39a76e7Sxw 
570d39a76e7Sxw 	/*
571d39a76e7Sxw 	 * set a flag so we'll restart upper layer when
572d39a76e7Sxw 	 * resources become available.
573d39a76e7Sxw 	 */
574d39a76e7Sxw 	if ((flg & CH_ARP) == 0)
575d39a76e7Sxw 		sa->ch_blked = 1;
576d39a76e7Sxw 	rv = 1;
577d39a76e7Sxw 
578d39a76e7Sxw error:
579d39a76e7Sxw 	/*
580d39a76e7Sxw 	 * unmap the physical addresses allocated earlier.
581d39a76e7Sxw 	 */
582d39a76e7Sxw 	cmp = hmp;
583d39a76e7Sxw 	for (--nseg; nseg >= 0; nseg--) {
584d39a76e7Sxw 		if (cmp->ce_dh) {
585d39a76e7Sxw 			if (cmp->ce_flg == DH_DMA)
586d39a76e7Sxw 				ch_unbind_dma_handle(sa, cmp->ce_dh);
587d39a76e7Sxw #if defined(__sparc)
588d39a76e7Sxw 			else
589d39a76e7Sxw 				ch_unbind_dvma_handle(sa, cmp->ce_dh);
590d39a76e7Sxw #endif
591d39a76e7Sxw 		}
592d39a76e7Sxw 		cmp++;
593d39a76e7Sxw 	}
594d39a76e7Sxw 
595d39a76e7Sxw error1:
596d39a76e7Sxw 
597d39a76e7Sxw 	/* free the temporary array */
598d39a76e7Sxw 	if (cm_flg)
599d39a76e7Sxw 		kmem_free(hmp, mseg * sizeof (cmdQ_ce_t));
600d39a76e7Sxw 
601d39a76e7Sxw 	/*
602d39a76e7Sxw 	 * if we've allocated an mblk above, then we need to free it
603d39a76e7Sxw 	 * before returning. This is safe since we haven't done anything to
604d39a76e7Sxw 	 * the original message. The caller, gld, will still have a pointer
605d39a76e7Sxw 	 * to the original mblk.
606d39a76e7Sxw 	 */
607d39a76e7Sxw 	if (rv == 1) {
608d39a76e7Sxw 		if (freeme) {
609d39a76e7Sxw 			/* we had to allocate an mblk. Free it. */
610d39a76e7Sxw 			freeb(m0);
611d39a76e7Sxw 		} else {
612d39a76e7Sxw 			/* adjust the mblk back to original start */
613d39a76e7Sxw 			if (flg & CH_NO_CPL)
614d39a76e7Sxw 				m0->b_rptr += SZ_CPL_TX_PKT;
615d39a76e7Sxw 		}
616d39a76e7Sxw 	} else {
617d39a76e7Sxw 		freemsg(m0);
618d39a76e7Sxw 		sa->oerr++;
619d39a76e7Sxw 	}
620d39a76e7Sxw 
621d39a76e7Sxw 	return (rv);
622d39a76e7Sxw }
623d39a76e7Sxw 
624d39a76e7Sxw /* KLUDGE ALERT. HARD WIRED TO PORT ZERO */
625d39a76e7Sxw void
pe_set_mac(ch_t * sa,unsigned char * ac_enaddr)626d39a76e7Sxw pe_set_mac(ch_t *sa, unsigned char *ac_enaddr)
627d39a76e7Sxw {
628d39a76e7Sxw 	sa->port[0].mac->ops->macaddress_set(sa->port[0].mac, ac_enaddr);
629d39a76e7Sxw }
630d39a76e7Sxw 
631d39a76e7Sxw /* KLUDGE ALERT. HARD WIRED TO PORT ZERO */
632d39a76e7Sxw unsigned char *
pe_get_mac(ch_t * sa)633d39a76e7Sxw pe_get_mac(ch_t *sa)
634d39a76e7Sxw {
635d39a76e7Sxw 	return (sa->port[0].enaddr);
636d39a76e7Sxw }
637d39a76e7Sxw 
638d39a76e7Sxw /* KLUDGE ALERT. HARD WIRED TO ONE PORT */
639d39a76e7Sxw void
pe_set_promiscuous(ch_t * sa,int flag)640d39a76e7Sxw pe_set_promiscuous(ch_t *sa, int flag)
641d39a76e7Sxw {
642d39a76e7Sxw 	struct cmac *mac = sa->port[0].mac;
643d39a76e7Sxw 	struct t1_rx_mode rm;
644d39a76e7Sxw 
645d39a76e7Sxw 	switch (flag) {
646d39a76e7Sxw 	case 0:		/* turn off promiscuous mode */
647d39a76e7Sxw 		sa->ch_flags &= ~(PEPROMISC|PEALLMULTI);
648d39a76e7Sxw 		break;
649d39a76e7Sxw 
650d39a76e7Sxw 	case 1:		/* turn on promiscuous mode */
651d39a76e7Sxw 		sa->ch_flags |= PEPROMISC;
652d39a76e7Sxw 		break;
653d39a76e7Sxw 
654d39a76e7Sxw 	case 2:		/* turn on multicast reception */
655d39a76e7Sxw 		sa->ch_flags |= PEALLMULTI;
656d39a76e7Sxw 		break;
657d39a76e7Sxw 	}
658d39a76e7Sxw 
659d39a76e7Sxw 	mutex_enter(&sa->ch_mc_lck);
660d39a76e7Sxw 	rm.chp = sa;
661d39a76e7Sxw 	rm.mc = sa->ch_mc;
662d39a76e7Sxw 
663d39a76e7Sxw 	mac->ops->set_rx_mode(mac, &rm);
664d39a76e7Sxw 	mutex_exit(&sa->ch_mc_lck);
665d39a76e7Sxw }
666d39a76e7Sxw 
667d39a76e7Sxw int
pe_set_mc(ch_t * sa,uint8_t * ep,int flg)668d39a76e7Sxw pe_set_mc(ch_t *sa, uint8_t *ep, int flg)
669d39a76e7Sxw {
670d39a76e7Sxw 	struct cmac *mac = sa->port[0].mac;
671d39a76e7Sxw 	struct t1_rx_mode rm;
672d39a76e7Sxw 
673d39a76e7Sxw 	if (flg == GLD_MULTI_ENABLE) {
674d39a76e7Sxw 		ch_mc_t *mcp;
675d39a76e7Sxw 
676d39a76e7Sxw 		mcp = (ch_mc_t *)kmem_zalloc(sizeof (struct ch_mc),
677d39a76e7Sxw 		    KM_NOSLEEP);
678d39a76e7Sxw 		if (mcp == NULL)
679d39a76e7Sxw 			return (GLD_NORESOURCES);
680d39a76e7Sxw 
681d39a76e7Sxw 		bcopy(ep, &mcp->cmc_mca, 6);
682d39a76e7Sxw 
683d39a76e7Sxw 		mutex_enter(&sa->ch_mc_lck);
684d39a76e7Sxw 		mcp->cmc_next = sa->ch_mc;
685d39a76e7Sxw 		sa->ch_mc = mcp;
686d39a76e7Sxw 		sa->ch_mc_cnt++;
687d39a76e7Sxw 		mutex_exit(&sa->ch_mc_lck);
688d39a76e7Sxw 
689d39a76e7Sxw 	} else if (flg == GLD_MULTI_DISABLE) {
690d39a76e7Sxw 		ch_mc_t **p = &sa->ch_mc;
691d39a76e7Sxw 		ch_mc_t *q = NULL;
692d39a76e7Sxw 
693d39a76e7Sxw 		mutex_enter(&sa->ch_mc_lck);
694d39a76e7Sxw 		p = &sa->ch_mc;
695d39a76e7Sxw 		while (*p) {
696d39a76e7Sxw 			if (bcmp(ep, (*p)->cmc_mca, 6) == 0) {
697d39a76e7Sxw 				q = *p;
698d39a76e7Sxw 				*p = (*p)->cmc_next;
699d39a76e7Sxw 				kmem_free(q, sizeof (*q));
700d39a76e7Sxw 				sa->ch_mc_cnt--;
701d39a76e7Sxw 				break;
702d39a76e7Sxw 			}
703d39a76e7Sxw 
704d39a76e7Sxw 			p = &(*p)->cmc_next;
705d39a76e7Sxw 		}
706d39a76e7Sxw 		mutex_exit(&sa->ch_mc_lck);
707d39a76e7Sxw 
708d39a76e7Sxw 		if (q == NULL)
709d39a76e7Sxw 			return (GLD_BADARG);
710d39a76e7Sxw 	} else
711d39a76e7Sxw 		return (GLD_BADARG);
712d39a76e7Sxw 
713d39a76e7Sxw 	mutex_enter(&sa->ch_mc_lck);
714d39a76e7Sxw 	rm.chp = sa;
715d39a76e7Sxw 	rm.mc = sa->ch_mc;
716d39a76e7Sxw 
717d39a76e7Sxw 	mac->ops->set_rx_mode(mac, &rm);
718d39a76e7Sxw 	mutex_exit(&sa->ch_mc_lck);
719d39a76e7Sxw 
720d39a76e7Sxw 	return (GLD_SUCCESS);
721d39a76e7Sxw }
722d39a76e7Sxw 
723d39a76e7Sxw /*
724d39a76e7Sxw  * return: speed       - bandwidth of interface
725d39a76e7Sxw  * return: intrcnt     - # interrupts
726d39a76e7Sxw  * return: norcvbuf    - # recedived packets dropped by driver
727d39a76e7Sxw  * return: oerrors     - # bad send packets
728d39a76e7Sxw  * return: ierrors     - # bad receive packets
729d39a76e7Sxw  * return: underrun    - # bad underrun xmit packets
730d39a76e7Sxw  * return: overrun     - # bad overrun recv packets
731d39a76e7Sxw  * return: framing     - # bad aligned recv packets
732d39a76e7Sxw  * return: crc         - # bad FCS (crc) recv packets
733d39a76e7Sxw  * return: carrier     - times carrier was lost
734d39a76e7Sxw  * return: collisions  - # xmit collisions
735d39a76e7Sxw  * return: xcollisions - # xmit pkts dropped due to collisions
736d39a76e7Sxw  * return: late        - # late xmit collisions
737d39a76e7Sxw  * return: defer       - # deferred xmit packets
738d39a76e7Sxw  * return: xerrs       - # xmit dropped packets
739d39a76e7Sxw  * return: rerrs       - # recv dropped packets
740d39a76e7Sxw  * return: toolong     - # recv pkts too long
741d39a76e7Sxw  * return: runt        - # recv runt pkts
742d39a76e7Sxw  * return: multixmt    - # multicast pkts xmitted
743d39a76e7Sxw  * return: multircv    - # multicast pkts recved
744d39a76e7Sxw  * return: brdcstxmt   - # broadcast pkts xmitted
745d39a76e7Sxw  * return: brdcstrcv   - # broadcast pkts rcv
746d39a76e7Sxw  */
747d39a76e7Sxw 
748d39a76e7Sxw int
pe_get_stats(ch_t * sa,uint64_t * speed,uint32_t * intrcnt,uint32_t * norcvbuf,uint32_t * oerrors,uint32_t * ierrors,uint32_t * underrun,uint32_t * overrun,uint32_t * framing,uint32_t * crc,uint32_t * carrier,uint32_t * collisions,uint32_t * xcollisions,uint32_t * late,uint32_t * defer,uint32_t * xerrs,uint32_t * rerrs,uint32_t * toolong,uint32_t * runt,ulong_t * multixmt,ulong_t * multircv,ulong_t * brdcstxmt,ulong_t * brdcstrcv)749d39a76e7Sxw pe_get_stats(ch_t *sa, uint64_t *speed, uint32_t *intrcnt, uint32_t *norcvbuf,
750d39a76e7Sxw     uint32_t *oerrors, uint32_t *ierrors, uint32_t *underrun,
751d39a76e7Sxw     uint32_t *overrun, uint32_t *framing, uint32_t *crc,
752d39a76e7Sxw     uint32_t *carrier, uint32_t *collisions, uint32_t *xcollisions,
753d39a76e7Sxw     uint32_t *late, uint32_t *defer, uint32_t *xerrs, uint32_t *rerrs,
754d39a76e7Sxw     uint32_t *toolong, uint32_t *runt, ulong_t  *multixmt, ulong_t  *multircv,
755d39a76e7Sxw     ulong_t  *brdcstxmt, ulong_t  *brdcstrcv)
756d39a76e7Sxw {
757d39a76e7Sxw 	struct pe_port_t *pt;
758d39a76e7Sxw 	int line_speed;
759d39a76e7Sxw 	int line_duplex;
760d39a76e7Sxw 	int line_is_active;
761d39a76e7Sxw 	uint64_t v;
762d39a76e7Sxw 	const struct cmac_statistics *sp;
763d39a76e7Sxw 
764d39a76e7Sxw 	pt = &(sa->port[0]);
765d39a76e7Sxw 	(void) pt->phy->ops->get_link_status(pt->phy,
766d39a76e7Sxw 	    &line_is_active, &line_speed, &line_duplex, NULL);
767d39a76e7Sxw 
768d39a76e7Sxw 	switch (line_speed) {
769d39a76e7Sxw 	case SPEED_10:
770d39a76e7Sxw 		*speed = 10000000;
771d39a76e7Sxw 		break;
772d39a76e7Sxw 	case SPEED_100:
773d39a76e7Sxw 		*speed = 100000000;
774d39a76e7Sxw 		break;
775d39a76e7Sxw 	case SPEED_1000:
776d39a76e7Sxw 		*speed = 1000000000;
777d39a76e7Sxw 		break;
778d39a76e7Sxw 	case SPEED_10000:
779d39a76e7Sxw 		/*
780d39a76e7Sxw 		 * kludge to get 10,000,000,000 constant (and keep
781d39a76e7Sxw 		 * compiler happy).
782d39a76e7Sxw 		 */
783d39a76e7Sxw 		v = 10000000;
784d39a76e7Sxw 		v *= 1000;
785d39a76e7Sxw 		*speed = v;
786d39a76e7Sxw 		break;
787d39a76e7Sxw 	default:
788d39a76e7Sxw 		goto error;
789d39a76e7Sxw 	}
790d39a76e7Sxw 
791d39a76e7Sxw 	*intrcnt = sa->isr_intr;
792d39a76e7Sxw 	*norcvbuf = sa->norcvbuf;
793d39a76e7Sxw 
794d39a76e7Sxw 	sp = sa->port[0].mac->ops->statistics_update(sa->port[0].mac,
795d39a76e7Sxw 	    MAC_STATS_UPDATE_FULL);
796d39a76e7Sxw 
797d39a76e7Sxw 	*ierrors = sp->RxOctetsBad;
798d39a76e7Sxw 
799d39a76e7Sxw 	/*
800d39a76e7Sxw 	 * not sure this is correct. # aborted at driver level +
801d39a76e7Sxw 	 * # at hardware level
802d39a76e7Sxw 	 */
803d39a76e7Sxw 	*oerrors = sa->oerr + sp->TxFramesAbortedDueToXSCollisions +
804d39a76e7Sxw 	    sp->TxUnderrun + sp->TxLengthErrors +
805d39a76e7Sxw 	    sp->TxInternalMACXmitError +
806d39a76e7Sxw 	    sp->TxFramesWithExcessiveDeferral +
807d39a76e7Sxw 	    sp->TxFCSErrors;
808d39a76e7Sxw 
809d39a76e7Sxw 	*underrun = sp->TxUnderrun;
810d39a76e7Sxw 	*overrun = sp->RxFrameTooLongErrors;
811d39a76e7Sxw 	*framing = sp->RxAlignErrors;
812d39a76e7Sxw 	*crc = sp->RxFCSErrors;
813d39a76e7Sxw 	*carrier = 0;		/* need to find this */
814d39a76e7Sxw 	*collisions = sp->TxTotalCollisions;
815d39a76e7Sxw 	*xcollisions = sp->TxFramesAbortedDueToXSCollisions;
816d39a76e7Sxw 	*late = sp->TxLateCollisions;
817d39a76e7Sxw 	*defer = sp->TxFramesWithDeferredXmissions;
818d39a76e7Sxw 	*xerrs = sp->TxUnderrun + sp->TxLengthErrors +
819d39a76e7Sxw 	    sp->TxInternalMACXmitError + sp->TxFCSErrors;
820d39a76e7Sxw 	*rerrs = sp->RxSymbolErrors + sp->RxSequenceErrors + sp->RxRuntErrors +
821d39a76e7Sxw 	    sp->RxJabberErrors + sp->RxInternalMACRcvError +
822d39a76e7Sxw 	    sp->RxInRangeLengthErrors + sp->RxOutOfRangeLengthField;
823d39a76e7Sxw 	*toolong = sp->RxFrameTooLongErrors;
824d39a76e7Sxw 	*runt = sp->RxRuntErrors;
825d39a76e7Sxw 
826d39a76e7Sxw 	*multixmt = sp->TxMulticastFramesOK;
827d39a76e7Sxw 	*multircv = sp->RxMulticastFramesOK;
828d39a76e7Sxw 	*brdcstxmt = sp->TxBroadcastFramesOK;
829d39a76e7Sxw 	*brdcstrcv = sp->RxBroadcastFramesOK;
830d39a76e7Sxw 
831d39a76e7Sxw 	return (0);
832d39a76e7Sxw 
833d39a76e7Sxw error:
834d39a76e7Sxw 	*speed = 0;
835d39a76e7Sxw 	*intrcnt = 0;
836d39a76e7Sxw 	*norcvbuf = 0;
837d39a76e7Sxw 	*norcvbuf = 0;
838d39a76e7Sxw 	*oerrors = 0;
839d39a76e7Sxw 	*ierrors = 0;
840d39a76e7Sxw 	*underrun = 0;
841d39a76e7Sxw 	*overrun = 0;
842d39a76e7Sxw 	*framing = 0;
843d39a76e7Sxw 	*crc = 0;
844d39a76e7Sxw 	*carrier = 0;
845d39a76e7Sxw 	*collisions = 0;
846d39a76e7Sxw 	*xcollisions = 0;
847d39a76e7Sxw 	*late = 0;
848d39a76e7Sxw 	*defer = 0;
849d39a76e7Sxw 	*xerrs = 0;
850d39a76e7Sxw 	*rerrs = 0;
851d39a76e7Sxw 	*toolong = 0;
852d39a76e7Sxw 	*runt = 0;
853d39a76e7Sxw 	*multixmt = 0;
854d39a76e7Sxw 	*multircv = 0;
855d39a76e7Sxw 	*brdcstxmt = 0;
856d39a76e7Sxw 	*brdcstrcv = 0;
857d39a76e7Sxw 
858d39a76e7Sxw 	return (1);
859d39a76e7Sxw }
860d39a76e7Sxw 
861d39a76e7Sxw uint32_t ch_gtm = 0;		/* Default: Global Tunnel Mode off */
862d39a76e7Sxw uint32_t ch_global_config = 0x07000000;	/* Default: errors, warnings, status */
863d39a76e7Sxw uint32_t ch_is_asic = 0;	/* Default: non-ASIC */
864d39a76e7Sxw uint32_t ch_link_speed = PE_LINK_SPEED_AUTONEG;	/* Default: auto-negoiate */
865d39a76e7Sxw uint32_t ch_num_of_ports = 1;	/* Default: 1 port */
866d39a76e7Sxw uint32_t ch_tp_reset_cm = 1;	/* Default: reset CM memory map */
867d39a76e7Sxw uint32_t ch_phy_tx_fifo = 0;	/* Default: 0 phy tx fifo depth */
868d39a76e7Sxw uint32_t ch_phy_rx_fifo = 0;	/* Default: 0 phy rx fifo depth */
869d39a76e7Sxw uint32_t ch_phy_force_master = 1;	/* Default: link always master mode */
870d39a76e7Sxw uint32_t ch_mc5_rtbl_size = 2048;	/* Default: TCAM routing table size */
871d39a76e7Sxw uint32_t ch_mc5_dbsvr_size = 128;	/* Default: TCAM server size */
872