xref: /illumos-gate/usr/src/uts/intel/io/dnet/dnet.c (revision f879aa94)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
54ab75253Smrj  * Common Development and Distribution License (the "License").
64ab75253Smrj  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
214ab75253Smrj 
227c478bd9Sstevel@tonic-gate /*
230dc2366fSVenugopal Iyer  * Copyright 2010 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * dnet -- DEC 21x4x
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  * Currently supports:
327c478bd9Sstevel@tonic-gate  *	21040, 21041, 21140, 21142, 21143
337c478bd9Sstevel@tonic-gate  *	SROM versions 1, 3, 3.03, 4
347c478bd9Sstevel@tonic-gate  *	TP, AUI, BNC, 100BASETX, 100BASET4
357c478bd9Sstevel@tonic-gate  *
367c478bd9Sstevel@tonic-gate  * XXX NEEDSWORK
377c478bd9Sstevel@tonic-gate  *	All media SHOULD work, FX is untested
387c478bd9Sstevel@tonic-gate  *
3998e8d175SSteven Stallion  * Depends on the Generic LAN Driver utility functions in /kernel/misc/mac
407c478bd9Sstevel@tonic-gate  */
417c478bd9Sstevel@tonic-gate 
427c478bd9Sstevel@tonic-gate #define	BUG_4010796	/* See 4007871, 4010796 */
437c478bd9Sstevel@tonic-gate 
447c478bd9Sstevel@tonic-gate #include <sys/types.h>
457c478bd9Sstevel@tonic-gate #include <sys/errno.h>
467c478bd9Sstevel@tonic-gate #include <sys/param.h>
477c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
487c478bd9Sstevel@tonic-gate #include <sys/stream.h>
497c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
507c478bd9Sstevel@tonic-gate #include <sys/conf.h>
517c478bd9Sstevel@tonic-gate #include <sys/devops.h>
527c478bd9Sstevel@tonic-gate #include <sys/ksynch.h>
537c478bd9Sstevel@tonic-gate #include <sys/stat.h>
547c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
557c478bd9Sstevel@tonic-gate #include <sys/debug.h>
567c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
577c478bd9Sstevel@tonic-gate #include <sys/ethernet.h>
5898e8d175SSteven Stallion #include <sys/vlan.h>
5998e8d175SSteven Stallion #include <sys/mac.h>
6098e8d175SSteven Stallion #include <sys/mac_ether.h>
6198e8d175SSteven Stallion #include <sys/mac_provider.h>
627c478bd9Sstevel@tonic-gate #include <sys/pci.h>
637c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
647c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
6598e8d175SSteven Stallion #include <sys/strsun.h>
667c478bd9Sstevel@tonic-gate 
67bdb9230aSGarrett D'Amore #include "dnet_mii.h"
68bdb9230aSGarrett D'Amore #include "dnet.h"
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  *	Declarations and Module Linkage
727c478bd9Sstevel@tonic-gate  */
737c478bd9Sstevel@tonic-gate 
747c478bd9Sstevel@tonic-gate #define	IDENT	"DNET 21x4x"
757c478bd9Sstevel@tonic-gate 
767c478bd9Sstevel@tonic-gate /*
777c478bd9Sstevel@tonic-gate  * #define	DNET_NOISY
787c478bd9Sstevel@tonic-gate  * #define	SROMDEBUG
797c478bd9Sstevel@tonic-gate  * #define	SROMDUMPSTRUCTURES
807c478bd9Sstevel@tonic-gate  */
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
837c478bd9Sstevel@tonic-gate #ifdef DNET_NOISY
847c478bd9Sstevel@tonic-gate int	dnetdebug = -1;
857c478bd9Sstevel@tonic-gate #else
867c478bd9Sstevel@tonic-gate int	dnetdebug = 0;
877c478bd9Sstevel@tonic-gate #endif
887c478bd9Sstevel@tonic-gate #endif
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate /* used for message allocated using desballoc() */
917c478bd9Sstevel@tonic-gate struct free_ptr {
927c478bd9Sstevel@tonic-gate 	struct free_rtn	free_rtn;
937c478bd9Sstevel@tonic-gate 	caddr_t buf;
947c478bd9Sstevel@tonic-gate };
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate struct rbuf_list {
977c478bd9Sstevel@tonic-gate 	struct rbuf_list	*rbuf_next;	/* next in the list */
987c478bd9Sstevel@tonic-gate 	caddr_t			rbuf_vaddr;	/* virual addr of the buf */
998ef10d20Sgd 	uint32_t		rbuf_paddr;	/* physical addr of the buf */
1008ef10d20Sgd 	uint32_t		rbuf_endpaddr;	/* physical addr at the end */
1017c478bd9Sstevel@tonic-gate 	ddi_dma_handle_t	rbuf_dmahdl;	/* dma handle */
1027c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t	rbuf_acchdl;	/* handle for DDI functions */
1037c478bd9Sstevel@tonic-gate };
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate /* Required system entry points */
10698e8d175SSteven Stallion static int dnet_probe(dev_info_t *);
10798e8d175SSteven Stallion static int dnet_attach(dev_info_t *, ddi_attach_cmd_t);
10898e8d175SSteven Stallion static int dnet_detach(dev_info_t *, ddi_detach_cmd_t);
10998e8d175SSteven Stallion static int dnet_quiesce(dev_info_t *);
11098e8d175SSteven Stallion 
11198e8d175SSteven Stallion /* Required driver entry points for GLDv3 */
11298e8d175SSteven Stallion static int dnet_m_start(void *);
11398e8d175SSteven Stallion static void dnet_m_stop(void *);
11498e8d175SSteven Stallion static int dnet_m_getstat(void *, uint_t, uint64_t *);
11598e8d175SSteven Stallion static int dnet_m_setpromisc(void *, boolean_t);
11698e8d175SSteven Stallion static int dnet_m_multicst(void *, boolean_t, const uint8_t *);
11798e8d175SSteven Stallion static int dnet_m_unicst(void *, const uint8_t *);
11898e8d175SSteven Stallion static mblk_t *dnet_m_tx(void *, mblk_t *);
11998e8d175SSteven Stallion 
12098e8d175SSteven Stallion static uint_t dnet_intr(caddr_t);
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate /* Internal functions used by the above entry points */
1237c478bd9Sstevel@tonic-gate static void write_gpr(struct dnetinstance *dnetp, uint32_t val);
12498e8d175SSteven Stallion static void dnet_reset_board(struct dnetinstance *);
12598e8d175SSteven Stallion static void dnet_init_board(struct dnetinstance *);
12698e8d175SSteven Stallion static void dnet_chip_init(struct dnetinstance *);
12798e8d175SSteven Stallion static uint32_t hashindex(const uint8_t *);
12898e8d175SSteven Stallion static int dnet_start(struct dnetinstance *);
12998e8d175SSteven Stallion static int dnet_set_addr(struct dnetinstance *);
13098e8d175SSteven Stallion 
13198e8d175SSteven Stallion static boolean_t dnet_send(struct dnetinstance *, mblk_t *);
1327c478bd9Sstevel@tonic-gate 
13398e8d175SSteven Stallion static void dnet_getp(struct dnetinstance *);
13498e8d175SSteven Stallion static void update_rx_stats(struct dnetinstance *, int);
13598e8d175SSteven Stallion static void update_tx_stats(struct dnetinstance *, int);
1367c478bd9Sstevel@tonic-gate 
1377c478bd9Sstevel@tonic-gate /* Media Selection Setup Routines */
13898e8d175SSteven Stallion static void set_gpr(struct dnetinstance *);
13998e8d175SSteven Stallion static void set_opr(struct dnetinstance *);
14098e8d175SSteven Stallion static void set_sia(struct dnetinstance *);
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate /* Buffer Management Routines */
14398e8d175SSteven Stallion static int dnet_alloc_bufs(struct dnetinstance *);
14498e8d175SSteven Stallion static void dnet_free_bufs(struct dnetinstance *);
14598e8d175SSteven Stallion static void dnet_init_txrx_bufs(struct dnetinstance *);
14698e8d175SSteven Stallion static int alloc_descriptor(struct dnetinstance *);
14798e8d175SSteven Stallion static void dnet_reclaim_Tx_desc(struct dnetinstance *);
1487c478bd9Sstevel@tonic-gate static int dnet_rbuf_init(dev_info_t *, int);
1497c478bd9Sstevel@tonic-gate static int dnet_rbuf_destroy();
1507c478bd9Sstevel@tonic-gate static struct rbuf_list *dnet_rbuf_alloc(dev_info_t *, int);
1517c478bd9Sstevel@tonic-gate static void dnet_rbuf_free(caddr_t);
1527c478bd9Sstevel@tonic-gate static void dnet_freemsg_buf(struct free_ptr *);
1537c478bd9Sstevel@tonic-gate 
15498e8d175SSteven Stallion static void setup_block(struct dnetinstance *);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate /* SROM read functions */
1578ef10d20Sgd static int dnet_read_srom(dev_info_t *, int, ddi_acc_handle_t, caddr_t,
1588ef10d20Sgd     uchar_t *, int);
1598ef10d20Sgd static void dnet_read21040addr(dev_info_t *, ddi_acc_handle_t, caddr_t,
1608ef10d20Sgd     uchar_t *, int *);
1618ef10d20Sgd static void dnet_read21140srom(ddi_acc_handle_t, caddr_t, uchar_t *, int);
1627c478bd9Sstevel@tonic-gate static int get_alternative_srom_image(dev_info_t *, uchar_t *, int);
1637c478bd9Sstevel@tonic-gate static void dnet_print_srom(SROM_FORMAT *sr);
1647c478bd9Sstevel@tonic-gate static void dnet_dump_leaf(LEAF_FORMAT *leaf);
1657c478bd9Sstevel@tonic-gate static void dnet_dump_block(media_block_t *block);
1667c478bd9Sstevel@tonic-gate #ifdef BUG_4010796
1677c478bd9Sstevel@tonic-gate static void set_alternative_srom_image(dev_info_t *, uchar_t *, int);
16898e8d175SSteven Stallion static int dnet_hack(dev_info_t *);
1697c478bd9Sstevel@tonic-gate #endif
1707c478bd9Sstevel@tonic-gate 
17198e8d175SSteven Stallion static int dnet_hack_interrupts(struct dnetinstance *, int);
1727c478bd9Sstevel@tonic-gate static int dnet_detach_hacked_interrupt(dev_info_t *devinfo);
17398e8d175SSteven Stallion static void enable_interrupts(struct dnetinstance *);
1747c478bd9Sstevel@tonic-gate 
1757c478bd9Sstevel@tonic-gate /* SROM parsing functions */
1767c478bd9Sstevel@tonic-gate static void dnet_parse_srom(struct dnetinstance *dnetp, SROM_FORMAT *sr,
1777c478bd9Sstevel@tonic-gate     uchar_t *vi);
1787c478bd9Sstevel@tonic-gate static void parse_controller_leaf(struct dnetinstance *dnetp, LEAF_FORMAT *leaf,
1797c478bd9Sstevel@tonic-gate     uchar_t *vi);
1807c478bd9Sstevel@tonic-gate static uchar_t *parse_media_block(struct dnetinstance *dnetp,
1817c478bd9Sstevel@tonic-gate     media_block_t *block, uchar_t *vi);
1827c478bd9Sstevel@tonic-gate static int check_srom_valid(uchar_t *);
1837c478bd9Sstevel@tonic-gate static void dnet_dumpbin(char *msg, uchar_t *, int size, int len);
1847c478bd9Sstevel@tonic-gate static void setup_legacy_blocks();
1857c478bd9Sstevel@tonic-gate /* Active Media Determination Routines */
18698e8d175SSteven Stallion static void find_active_media(struct dnetinstance *);
18798e8d175SSteven Stallion static int send_test_packet(struct dnetinstance *);
18898e8d175SSteven Stallion static int dnet_link_sense(struct dnetinstance *);
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate /* PHY MII Routines */
1917c478bd9Sstevel@tonic-gate static ushort_t dnet_mii_read(dev_info_t *dip, int phy_addr, int reg_num);
1927c478bd9Sstevel@tonic-gate static void dnet_mii_write(dev_info_t *dip, int phy_addr, int reg_num,
1937c478bd9Sstevel@tonic-gate 			int reg_dat);
1947c478bd9Sstevel@tonic-gate static void write_mii(struct dnetinstance *, uint32_t, int);
1957c478bd9Sstevel@tonic-gate static void mii_tristate(struct dnetinstance *);
19698e8d175SSteven Stallion static void do_phy(struct dnetinstance *);
1977c478bd9Sstevel@tonic-gate static void dnet_mii_link_cb(dev_info_t *, int, enum mii_phy_state);
1987c478bd9Sstevel@tonic-gate static void set_leaf(SROM_FORMAT *sr, LEAF_FORMAT *leaf);
1997c478bd9Sstevel@tonic-gate 
2007c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
2017c478bd9Sstevel@tonic-gate uint32_t dnet_usecelapsed(struct dnetinstance *dnetp);
2027c478bd9Sstevel@tonic-gate void dnet_timestamp(struct dnetinstance *, char *);
2037c478bd9Sstevel@tonic-gate void dnet_usectimeout(struct dnetinstance *, uint32_t, int, timercb_t);
2047c478bd9Sstevel@tonic-gate #endif
2057c478bd9Sstevel@tonic-gate static char *media_str[] = {
2067c478bd9Sstevel@tonic-gate 	"10BaseT",
2077c478bd9Sstevel@tonic-gate 	"10Base2",
2087c478bd9Sstevel@tonic-gate 	"10Base5",
2097c478bd9Sstevel@tonic-gate 	"100BaseTX",
2107c478bd9Sstevel@tonic-gate 	"10BaseT FD",
2117c478bd9Sstevel@tonic-gate 	"100BaseTX FD",
2127c478bd9Sstevel@tonic-gate 	"100BaseT4",
2137c478bd9Sstevel@tonic-gate 	"100BaseFX",
2147c478bd9Sstevel@tonic-gate 	"100BaseFX FD",
2157c478bd9Sstevel@tonic-gate 	"MII"
2167c478bd9Sstevel@tonic-gate };
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate /* default SROM info for cards with no SROMs */
2197c478bd9Sstevel@tonic-gate static LEAF_FORMAT leaf_default_100;
2207c478bd9Sstevel@tonic-gate static LEAF_FORMAT leaf_asante;
2217c478bd9Sstevel@tonic-gate static LEAF_FORMAT leaf_phylegacy;
2227c478bd9Sstevel@tonic-gate static LEAF_FORMAT leaf_cogent_100;
2237c478bd9Sstevel@tonic-gate static LEAF_FORMAT leaf_21041;
2247c478bd9Sstevel@tonic-gate static LEAF_FORMAT leaf_21040;
2257c478bd9Sstevel@tonic-gate 
22698e8d175SSteven Stallion /* rx buffer size (rounded up to 4) */
22798e8d175SSteven Stallion int rx_buf_size = (ETHERMAX + ETHERFCSL + VLAN_TAGSZ + 3) & ~3;
2287c478bd9Sstevel@tonic-gate 
2297c478bd9Sstevel@tonic-gate int max_rx_desc_21040 = MAX_RX_DESC_21040;
2307c478bd9Sstevel@tonic-gate int max_rx_desc_21140 = MAX_RX_DESC_21140;
2317c478bd9Sstevel@tonic-gate int max_tx_desc = MAX_TX_DESC;
2327c478bd9Sstevel@tonic-gate int dnet_xmit_threshold = MAX_TX_DESC >> 2;	/* XXX need tuning? */
2337c478bd9Sstevel@tonic-gate 
2347c478bd9Sstevel@tonic-gate static kmutex_t dnet_rbuf_lock;		/* mutex to protect rbuf_list data */
2357c478bd9Sstevel@tonic-gate 
2367c478bd9Sstevel@tonic-gate /* used for buffers allocated by ddi_dma_mem_alloc() */
2377c478bd9Sstevel@tonic-gate static ddi_dma_attr_t dma_attr = {
2387c478bd9Sstevel@tonic-gate 	DMA_ATTR_V0,		/* dma_attr version */
2397c478bd9Sstevel@tonic-gate 	0,			/* dma_attr_addr_lo */
2407c478bd9Sstevel@tonic-gate 	(uint64_t)0xFFFFFFFF,	/* dma_attr_addr_hi */
2417c478bd9Sstevel@tonic-gate 	0x7FFFFFFF,		/* dma_attr_count_max */
2427c478bd9Sstevel@tonic-gate 	4,			/* dma_attr_align */
2437c478bd9Sstevel@tonic-gate 	0x3F,			/* dma_attr_burstsizes */
2447c478bd9Sstevel@tonic-gate 	1,			/* dma_attr_minxfer */
2457c478bd9Sstevel@tonic-gate 	(uint64_t)0xFFFFFFFF,	/* dma_attr_maxxfer */
2467c478bd9Sstevel@tonic-gate 	(uint64_t)0xFFFFFFFF,	/* dma_attr_seg */
2477c478bd9Sstevel@tonic-gate 	1,			/* dma_attr_sgllen */
2487c478bd9Sstevel@tonic-gate 	1,			/* dma_attr_granular */
2497c478bd9Sstevel@tonic-gate 	0,			/* dma_attr_flags */
2507c478bd9Sstevel@tonic-gate };
2517c478bd9Sstevel@tonic-gate 
2527c478bd9Sstevel@tonic-gate /* used for buffers allocated for rbuf, allow 2 cookies */
2537c478bd9Sstevel@tonic-gate static ddi_dma_attr_t dma_attr_rb = {
2547c478bd9Sstevel@tonic-gate 	DMA_ATTR_V0,		/* dma_attr version */
2557c478bd9Sstevel@tonic-gate 	0,			/* dma_attr_addr_lo */
2567c478bd9Sstevel@tonic-gate 	(uint64_t)0xFFFFFFFF,	/* dma_attr_addr_hi */
2577c478bd9Sstevel@tonic-gate 	0x7FFFFFFF,		/* dma_attr_count_max */
2587c478bd9Sstevel@tonic-gate 	4,			/* dma_attr_align */
2597c478bd9Sstevel@tonic-gate 	0x3F,			/* dma_attr_burstsizes */
2607c478bd9Sstevel@tonic-gate 	1,			/* dma_attr_minxfer */
2617c478bd9Sstevel@tonic-gate 	(uint64_t)0xFFFFFFFF,	/* dma_attr_maxxfer */
2627c478bd9Sstevel@tonic-gate 	(uint64_t)0xFFFFFFFF,	/* dma_attr_seg */
2637c478bd9Sstevel@tonic-gate 	2,			/* dma_attr_sgllen */
2647c478bd9Sstevel@tonic-gate 	1,			/* dma_attr_granular */
2657c478bd9Sstevel@tonic-gate 	0,			/* dma_attr_flags */
2667c478bd9Sstevel@tonic-gate };
2677c478bd9Sstevel@tonic-gate /* used for buffers which are NOT from ddi_dma_mem_alloc() - xmit side */
2687c478bd9Sstevel@tonic-gate static ddi_dma_attr_t dma_attr_tx = {
2697c478bd9Sstevel@tonic-gate 	DMA_ATTR_V0,		/* dma_attr version */
2707c478bd9Sstevel@tonic-gate 	0,			/* dma_attr_addr_lo */
2717c478bd9Sstevel@tonic-gate 	(uint64_t)0xFFFFFFFF,	/* dma_attr_addr_hi */
2727c478bd9Sstevel@tonic-gate 	0x7FFFFFFF,		/* dma_attr_count_max */
2737c478bd9Sstevel@tonic-gate 	1,			/* dma_attr_align */
2747c478bd9Sstevel@tonic-gate 	0x3F,			/* dma_attr_burstsizes */
2757c478bd9Sstevel@tonic-gate 	1,			/* dma_attr_minxfer */
2767c478bd9Sstevel@tonic-gate 	(uint64_t)0xFFFFFFFF,	/* dma_attr_maxxfer */
2777c478bd9Sstevel@tonic-gate 	(uint64_t)0xFFFFFFFF,	/* dma_attr_seg */
2787c478bd9Sstevel@tonic-gate 	0x7FFF,			/* dma_attr_sgllen */
2797c478bd9Sstevel@tonic-gate 	1,			/* dma_attr_granular */
2807c478bd9Sstevel@tonic-gate 	0,			/* dma_attr_flags */
2817c478bd9Sstevel@tonic-gate };
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate static ddi_device_acc_attr_t accattr = {
2847c478bd9Sstevel@tonic-gate 	DDI_DEVICE_ATTR_V0,
2857c478bd9Sstevel@tonic-gate 	DDI_NEVERSWAP_ACC,
2867c478bd9Sstevel@tonic-gate 	DDI_STRICTORDER_ACC,
2877c478bd9Sstevel@tonic-gate };
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate uchar_t dnet_broadcastaddr[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate /* Standard Module linkage initialization for a Streams driver */
2927c478bd9Sstevel@tonic-gate extern struct mod_ops mod_driverops;
2937c478bd9Sstevel@tonic-gate 
29498e8d175SSteven Stallion DDI_DEFINE_STREAM_OPS(dnet_devops, nulldev, dnet_probe, dnet_attach,
29598e8d175SSteven Stallion     dnet_detach, nodev, NULL, D_MP, NULL, dnet_quiesce);
2967c478bd9Sstevel@tonic-gate 
29798e8d175SSteven Stallion static struct modldrv dnet_modldrv = {
2987c478bd9Sstevel@tonic-gate 	&mod_driverops,		/* Type of module.  This one is a driver */
2998ef10d20Sgd 	IDENT,			/* short description */
30098e8d175SSteven Stallion 	&dnet_devops		/* driver specific ops */
3017c478bd9Sstevel@tonic-gate };
3027c478bd9Sstevel@tonic-gate 
30398e8d175SSteven Stallion static struct modlinkage dnet_modlinkage = {
30498e8d175SSteven Stallion 	MODREV_1,		/* ml_rev */
30598e8d175SSteven Stallion 	{ &dnet_modldrv, NULL }	/* ml_linkage */
3067c478bd9Sstevel@tonic-gate };
3077c478bd9Sstevel@tonic-gate 
30898e8d175SSteven Stallion static mac_callbacks_t dnet_m_callbacks = {
30998e8d175SSteven Stallion 	0,			/* mc_callbacks */
31098e8d175SSteven Stallion 	dnet_m_getstat,		/* mc_getstat */
31198e8d175SSteven Stallion 	dnet_m_start,		/* mc_start */
31298e8d175SSteven Stallion 	dnet_m_stop,		/* mc_stop */
31398e8d175SSteven Stallion 	dnet_m_setpromisc,	/* mc_setpromisc */
31498e8d175SSteven Stallion 	dnet_m_multicst,	/* mc_multicst */
31598e8d175SSteven Stallion 	dnet_m_unicst,		/* mc_unicst */
31698e8d175SSteven Stallion 	dnet_m_tx,		/* mc_tx */
3170dc2366fSVenugopal Iyer 	NULL,
31898e8d175SSteven Stallion 	NULL,			/* mc_ioctl */
31998e8d175SSteven Stallion 	NULL,			/* mc_getcapab */
32098e8d175SSteven Stallion 	NULL,			/* mc_open */
32198e8d175SSteven Stallion 	NULL			/* mc_close */
32298e8d175SSteven Stallion };
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate /*
3257c478bd9Sstevel@tonic-gate  * Passed to the hacked interrupt for multiport Cogent and ZNYX cards with
3267c478bd9Sstevel@tonic-gate  * dodgy interrupt routing
3277c478bd9Sstevel@tonic-gate  */
3287c478bd9Sstevel@tonic-gate #define	MAX_INST 8 /* Maximum instances on a multiport adapter. */
3297c478bd9Sstevel@tonic-gate struct hackintr_inf
3307c478bd9Sstevel@tonic-gate {
33198e8d175SSteven Stallion 	struct dnetinstance *dnetps[MAX_INST]; /* dnetps for each port */
3327c478bd9Sstevel@tonic-gate 	dev_info_t *devinfo;		    /* Devinfo of the primary device */
3337c478bd9Sstevel@tonic-gate 	kmutex_t lock;
3347c478bd9Sstevel@tonic-gate 		/* Ensures the interrupt doesn't get called while detaching */
3357c478bd9Sstevel@tonic-gate };
3367c478bd9Sstevel@tonic-gate static char hackintr_propname[] = "InterruptData";
3377c478bd9Sstevel@tonic-gate static char macoffset_propname[] = "MAC_offset";
3387c478bd9Sstevel@tonic-gate static char speed_propname[] = "speed";
3397c478bd9Sstevel@tonic-gate static char ofloprob_propname[] = "dmaworkaround";
3407c478bd9Sstevel@tonic-gate static char duplex_propname[] = "full-duplex"; /* Must agree with MII */
3417c478bd9Sstevel@tonic-gate static char printsrom_propname[] = "print-srom";
3427c478bd9Sstevel@tonic-gate 
3437c478bd9Sstevel@tonic-gate static uint_t dnet_hack_intr(struct hackintr_inf *);
3447c478bd9Sstevel@tonic-gate 
3457c478bd9Sstevel@tonic-gate int
_init(void)3467c478bd9Sstevel@tonic-gate _init(void)
3477c478bd9Sstevel@tonic-gate {
3487c478bd9Sstevel@tonic-gate 	int i;
3497c478bd9Sstevel@tonic-gate 
3507c478bd9Sstevel@tonic-gate 	/* Configure fake sroms for legacy cards */
3517c478bd9Sstevel@tonic-gate 	mutex_init(&dnet_rbuf_lock, NULL, MUTEX_DRIVER, NULL);
3527c478bd9Sstevel@tonic-gate 	setup_legacy_blocks();
35398e8d175SSteven Stallion 
35498e8d175SSteven Stallion 	mac_init_ops(&dnet_devops, "dnet");
35598e8d175SSteven Stallion 
35698e8d175SSteven Stallion 	if ((i = mod_install(&dnet_modlinkage)) != 0) {
35798e8d175SSteven Stallion 		mac_fini_ops(&dnet_devops);
3587c478bd9Sstevel@tonic-gate 		mutex_destroy(&dnet_rbuf_lock);
3597c478bd9Sstevel@tonic-gate 	}
3607c478bd9Sstevel@tonic-gate 	return (i);
3617c478bd9Sstevel@tonic-gate }
3627c478bd9Sstevel@tonic-gate 
3637c478bd9Sstevel@tonic-gate int
_fini(void)3647c478bd9Sstevel@tonic-gate _fini(void)
3657c478bd9Sstevel@tonic-gate {
3667c478bd9Sstevel@tonic-gate 	int i;
36798e8d175SSteven Stallion 
36898e8d175SSteven Stallion 	if ((i = mod_remove(&dnet_modlinkage)) == 0) {
36998e8d175SSteven Stallion 		mac_fini_ops(&dnet_devops);
37098e8d175SSteven Stallion 
3717c478bd9Sstevel@tonic-gate 		/* loop until all the receive buffers are freed */
3727c478bd9Sstevel@tonic-gate 		while (dnet_rbuf_destroy() != 0) {
3737c478bd9Sstevel@tonic-gate 			delay(drv_usectohz(100000));
3747c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
3757c478bd9Sstevel@tonic-gate 			if (dnetdebug & DNETDDI)
3767c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "dnet _fini delay");
3777c478bd9Sstevel@tonic-gate #endif
3787c478bd9Sstevel@tonic-gate 		}
3797c478bd9Sstevel@tonic-gate 		mutex_destroy(&dnet_rbuf_lock);
3807c478bd9Sstevel@tonic-gate 	}
3817c478bd9Sstevel@tonic-gate 	return (i);
3827c478bd9Sstevel@tonic-gate }
3837c478bd9Sstevel@tonic-gate 
3847c478bd9Sstevel@tonic-gate int
_info(struct modinfo * modinfop)3857c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
3867c478bd9Sstevel@tonic-gate {
38798e8d175SSteven Stallion 	return (mod_info(&dnet_modlinkage, modinfop));
3887c478bd9Sstevel@tonic-gate }
3897c478bd9Sstevel@tonic-gate 
3907c478bd9Sstevel@tonic-gate /*
3917c478bd9Sstevel@tonic-gate  * probe(9E) -- Determine if a device is present
3927c478bd9Sstevel@tonic-gate  */
3937c478bd9Sstevel@tonic-gate static int
dnet_probe(dev_info_t * devinfo)39498e8d175SSteven Stallion dnet_probe(dev_info_t *devinfo)
3957c478bd9Sstevel@tonic-gate {
3967c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t handle;
3977c478bd9Sstevel@tonic-gate 	uint16_t	vendorid;
3987c478bd9Sstevel@tonic-gate 	uint16_t	deviceid;
3997c478bd9Sstevel@tonic-gate 
4007c478bd9Sstevel@tonic-gate 	if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS)
4017c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
4027c478bd9Sstevel@tonic-gate 
4037c478bd9Sstevel@tonic-gate 	vendorid = pci_config_get16(handle, PCI_CONF_VENID);
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate 	if (vendorid != DEC_VENDOR_ID) {
4067c478bd9Sstevel@tonic-gate 		pci_config_teardown(&handle);
4077c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
4087c478bd9Sstevel@tonic-gate 	}
4097c478bd9Sstevel@tonic-gate 
4107c478bd9Sstevel@tonic-gate 	deviceid = pci_config_get16(handle, PCI_CONF_DEVID);
4117c478bd9Sstevel@tonic-gate 	switch (deviceid) {
4127c478bd9Sstevel@tonic-gate 	case DEVICE_ID_21040:
4137c478bd9Sstevel@tonic-gate 	case DEVICE_ID_21041:
4147c478bd9Sstevel@tonic-gate 	case DEVICE_ID_21140:
4157c478bd9Sstevel@tonic-gate 	case DEVICE_ID_21143: /* And 142 */
4167c478bd9Sstevel@tonic-gate 		break;
4177c478bd9Sstevel@tonic-gate 	default:
4187c478bd9Sstevel@tonic-gate 		pci_config_teardown(&handle);
4197c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
4207c478bd9Sstevel@tonic-gate 	}
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate 	pci_config_teardown(&handle);
4237c478bd9Sstevel@tonic-gate #ifndef BUG_4010796
4247c478bd9Sstevel@tonic-gate 	return (DDI_PROBE_SUCCESS);
4257c478bd9Sstevel@tonic-gate #else
42698e8d175SSteven Stallion 	return (dnet_hack(devinfo));
4277c478bd9Sstevel@tonic-gate #endif
4287c478bd9Sstevel@tonic-gate }
4297c478bd9Sstevel@tonic-gate 
4307c478bd9Sstevel@tonic-gate #ifdef BUG_4010796
4317c478bd9Sstevel@tonic-gate /*
4327c478bd9Sstevel@tonic-gate  * If we have a device, but we cannot presently access its SROM data,
4337c478bd9Sstevel@tonic-gate  * then we return DDI_PROBE_PARTIAL and hope that sometime later we
4347c478bd9Sstevel@tonic-gate  * will be able to get at the SROM data.  This can only happen if we
4357c478bd9Sstevel@tonic-gate  * are a secondary port with no SROM, and the bootstrap failed to set
4367c478bd9Sstevel@tonic-gate  * our DNET_SROM property, and our primary sibling has not yet probed.
4377c478bd9Sstevel@tonic-gate  */
4387c478bd9Sstevel@tonic-gate static int
dnet_hack(dev_info_t * devinfo)43998e8d175SSteven Stallion dnet_hack(dev_info_t *devinfo)
4407c478bd9Sstevel@tonic-gate {
441*f879aa94SToomas Soome 	uchar_t		vendor_info[SROM_SIZE];
4427c478bd9Sstevel@tonic-gate 	uint32_t	csr;
4437c478bd9Sstevel@tonic-gate 	uint16_t	deviceid;
4447c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t handle;
4457c478bd9Sstevel@tonic-gate 	uint32_t	retval;
4467c478bd9Sstevel@tonic-gate 	int		secondary;
4477c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t io_handle;
4488ef10d20Sgd 	caddr_t		io_reg;
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate #define	DNET_PCI_RNUMBER	1
4517c478bd9Sstevel@tonic-gate 
4527c478bd9Sstevel@tonic-gate 	if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS)
4537c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
4547c478bd9Sstevel@tonic-gate 
4557c478bd9Sstevel@tonic-gate 	deviceid = pci_config_get16(handle, PCI_CONF_DEVID);
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate 	/*
4587c478bd9Sstevel@tonic-gate 	 * Turn on Master Enable and IO Enable bits.
4597c478bd9Sstevel@tonic-gate 	 */
4607c478bd9Sstevel@tonic-gate 	csr = pci_config_get32(handle, PCI_CONF_COMM);
4617c478bd9Sstevel@tonic-gate 	pci_config_put32(handle, PCI_CONF_COMM, (csr |PCI_COMM_ME|PCI_COMM_IO));
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	pci_config_teardown(&handle);
4647c478bd9Sstevel@tonic-gate 
4657c478bd9Sstevel@tonic-gate 	/* Now map I/O register */
4667c478bd9Sstevel@tonic-gate 	if (ddi_regs_map_setup(devinfo, DNET_PCI_RNUMBER,
4678ef10d20Sgd 	    &io_reg, 0, 0, &accattr, &io_handle) != DDI_SUCCESS) {
4687c478bd9Sstevel@tonic-gate 		return (DDI_PROBE_FAILURE);
4697c478bd9Sstevel@tonic-gate 	}
4707c478bd9Sstevel@tonic-gate 
4717c478bd9Sstevel@tonic-gate 	/*
4727c478bd9Sstevel@tonic-gate 	 * Reset the chip
4737c478bd9Sstevel@tonic-gate 	 */
4744ab75253Smrj 	ddi_put32(io_handle, REG32(io_reg, BUS_MODE_REG), SW_RESET);
4757c478bd9Sstevel@tonic-gate 	drv_usecwait(3);
4764ab75253Smrj 	ddi_put32(io_handle, REG32(io_reg, BUS_MODE_REG), 0);
4777c478bd9Sstevel@tonic-gate 	drv_usecwait(8);
4787c478bd9Sstevel@tonic-gate 
4797c478bd9Sstevel@tonic-gate 	secondary = dnet_read_srom(devinfo, deviceid, io_handle,
4807c478bd9Sstevel@tonic-gate 	    io_reg, vendor_info, sizeof (vendor_info));
4817c478bd9Sstevel@tonic-gate 
4827c478bd9Sstevel@tonic-gate 	switch (secondary) {
4837c478bd9Sstevel@tonic-gate 	case -1:
4847c478bd9Sstevel@tonic-gate 		/* We can't access our SROM data! */
4857c478bd9Sstevel@tonic-gate 		retval = DDI_PROBE_PARTIAL;
4867c478bd9Sstevel@tonic-gate 		break;
4877c478bd9Sstevel@tonic-gate 	case 0:
4887c478bd9Sstevel@tonic-gate 		retval = DDI_PROBE_SUCCESS;
4897c478bd9Sstevel@tonic-gate 		break;
4907c478bd9Sstevel@tonic-gate 	default:
4917c478bd9Sstevel@tonic-gate 		retval = DDI_PROBE_SUCCESS;
4927c478bd9Sstevel@tonic-gate 	}
4937c478bd9Sstevel@tonic-gate 
4947c478bd9Sstevel@tonic-gate 	ddi_regs_map_free(&io_handle);
4957c478bd9Sstevel@tonic-gate 	return (retval);
4967c478bd9Sstevel@tonic-gate }
4977c478bd9Sstevel@tonic-gate #endif /* BUG_4010796 */
4987c478bd9Sstevel@tonic-gate 
4997c478bd9Sstevel@tonic-gate /*
5007c478bd9Sstevel@tonic-gate  * attach(9E) -- Attach a device to the system
5017c478bd9Sstevel@tonic-gate  *
5027c478bd9Sstevel@tonic-gate  * Called once for each board successfully probed.
5037c478bd9Sstevel@tonic-gate  */
5047c478bd9Sstevel@tonic-gate static int
dnet_attach(dev_info_t * devinfo,ddi_attach_cmd_t cmd)50598e8d175SSteven Stallion dnet_attach(dev_info_t *devinfo, ddi_attach_cmd_t cmd)
5067c478bd9Sstevel@tonic-gate {
5077c478bd9Sstevel@tonic-gate 	uint16_t revid;
508*f879aa94SToomas Soome 	struct dnetinstance	*dnetp;		/* Our private device info */
50998e8d175SSteven Stallion 	mac_register_t		*macp;
510*f879aa94SToomas Soome 	uchar_t			vendor_info[SROM_SIZE];
5117c478bd9Sstevel@tonic-gate 	uint32_t		csr;
5127c478bd9Sstevel@tonic-gate 	uint16_t		deviceid;
513*f879aa94SToomas Soome 	ddi_acc_handle_t	handle;
5147c478bd9Sstevel@tonic-gate 	int			secondary;
5157c478bd9Sstevel@tonic-gate 
5167c478bd9Sstevel@tonic-gate #define	DNET_PCI_RNUMBER	1
5177c478bd9Sstevel@tonic-gate 
5188ef10d20Sgd 	switch (cmd) {
5198ef10d20Sgd 	case DDI_ATTACH:
5208ef10d20Sgd 		break;
5218ef10d20Sgd 
5228ef10d20Sgd 	case DDI_RESUME:
52398e8d175SSteven Stallion 		/* Get the driver private (dnetinstance) structure */
52498e8d175SSteven Stallion 		dnetp = ddi_get_driver_private(devinfo);
5258ef10d20Sgd 
5268ef10d20Sgd 		mutex_enter(&dnetp->intrlock);
5278ef10d20Sgd 		mutex_enter(&dnetp->txlock);
52898e8d175SSteven Stallion 		dnet_reset_board(dnetp);
52998e8d175SSteven Stallion 		dnet_init_board(dnetp);
5308ef10d20Sgd 		dnetp->suspended = B_FALSE;
5318ef10d20Sgd 
5328ef10d20Sgd 		if (dnetp->running) {
53398e8d175SSteven Stallion 			dnetp->need_tx_update = B_FALSE;
5348ef10d20Sgd 			mutex_exit(&dnetp->txlock);
53598e8d175SSteven Stallion 			(void) dnet_start(dnetp);
5368ef10d20Sgd 			mutex_exit(&dnetp->intrlock);
53798e8d175SSteven Stallion 			mac_tx_update(dnetp->mac_handle);
5388ef10d20Sgd 		} else {
5398ef10d20Sgd 			mutex_exit(&dnetp->txlock);
5408ef10d20Sgd 			mutex_exit(&dnetp->intrlock);
5418ef10d20Sgd 		}
5428ef10d20Sgd 		return (DDI_SUCCESS);
5438ef10d20Sgd 	default:
5447c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5458ef10d20Sgd 	}
54698e8d175SSteven Stallion 
5477c478bd9Sstevel@tonic-gate 	if (pci_config_setup(devinfo, &handle) != DDI_SUCCESS)
5487c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5497c478bd9Sstevel@tonic-gate 
5507c478bd9Sstevel@tonic-gate 	deviceid = pci_config_get16(handle, PCI_CONF_DEVID);
5517c478bd9Sstevel@tonic-gate 	switch (deviceid) {
5527c478bd9Sstevel@tonic-gate 	case DEVICE_ID_21040:
5537c478bd9Sstevel@tonic-gate 	case DEVICE_ID_21041:
5547c478bd9Sstevel@tonic-gate 	case DEVICE_ID_21140:
5557c478bd9Sstevel@tonic-gate 	case DEVICE_ID_21143: /* And 142 */
5567c478bd9Sstevel@tonic-gate 		break;
5577c478bd9Sstevel@tonic-gate 	default:
5587c478bd9Sstevel@tonic-gate 		pci_config_teardown(&handle);
5597c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5607c478bd9Sstevel@tonic-gate 	}
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate 	/*
5637c478bd9Sstevel@tonic-gate 	 * Turn on Master Enable and IO Enable bits.
5647c478bd9Sstevel@tonic-gate 	 */
5657c478bd9Sstevel@tonic-gate 	csr = pci_config_get32(handle, PCI_CONF_COMM);
5667c478bd9Sstevel@tonic-gate 	pci_config_put32(handle, PCI_CONF_COMM, (csr |PCI_COMM_ME|PCI_COMM_IO));
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	/* Make sure the device is not asleep */
5697c478bd9Sstevel@tonic-gate 	csr = pci_config_get32(handle, PCI_DNET_CONF_CFDD);
5707c478bd9Sstevel@tonic-gate 	pci_config_put32(handle, PCI_DNET_CONF_CFDD,
5717c478bd9Sstevel@tonic-gate 	    csr &  ~(CFDD_SLEEP|CFDD_SNOOZE));
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate 	revid = pci_config_get8(handle, PCI_CONF_REVID);
5747c478bd9Sstevel@tonic-gate 	pci_config_teardown(&handle);
5757c478bd9Sstevel@tonic-gate 
57698e8d175SSteven Stallion 	dnetp = kmem_zalloc(sizeof (struct dnetinstance), KM_SLEEP);
57798e8d175SSteven Stallion 	ddi_set_driver_private(devinfo, dnetp);
5787c478bd9Sstevel@tonic-gate 
5797c478bd9Sstevel@tonic-gate 	/* Now map I/O register */
5808ef10d20Sgd 	if (ddi_regs_map_setup(devinfo, DNET_PCI_RNUMBER, &dnetp->io_reg,
5818ef10d20Sgd 	    0, 0, &accattr, &dnetp->io_handle) != DDI_SUCCESS) {
5827c478bd9Sstevel@tonic-gate 		kmem_free(dnetp, sizeof (struct dnetinstance));
5837c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5847c478bd9Sstevel@tonic-gate 	}
5857c478bd9Sstevel@tonic-gate 
5867c478bd9Sstevel@tonic-gate 	dnetp->devinfo = devinfo;
5877c478bd9Sstevel@tonic-gate 	dnetp->board_type = deviceid;
5887c478bd9Sstevel@tonic-gate 
5897c478bd9Sstevel@tonic-gate 	/*
5907c478bd9Sstevel@tonic-gate 	 * Get the iblock cookie with which to initialize the mutexes.
5917c478bd9Sstevel@tonic-gate 	 */
59298e8d175SSteven Stallion 	if (ddi_get_iblock_cookie(devinfo, 0, &dnetp->icookie)
5937c478bd9Sstevel@tonic-gate 	    != DDI_SUCCESS)
5947c478bd9Sstevel@tonic-gate 		goto fail;
5957c478bd9Sstevel@tonic-gate 
5967c478bd9Sstevel@tonic-gate 	/*
5977c478bd9Sstevel@tonic-gate 	 * Initialize mutex's for this device.
5987c478bd9Sstevel@tonic-gate 	 * Do this before registering the interrupt handler to avoid
5997c478bd9Sstevel@tonic-gate 	 * condition where interrupt handler can try using uninitialized
6007c478bd9Sstevel@tonic-gate 	 * mutex.
6017c478bd9Sstevel@tonic-gate 	 * Lock ordering rules: always lock intrlock first before
6027c478bd9Sstevel@tonic-gate 	 * txlock if both are required.
6037c478bd9Sstevel@tonic-gate 	 */
60498e8d175SSteven Stallion 	mutex_init(&dnetp->txlock, NULL, MUTEX_DRIVER, dnetp->icookie);
60598e8d175SSteven Stallion 	mutex_init(&dnetp->intrlock, NULL, MUTEX_DRIVER, dnetp->icookie);
6067c478bd9Sstevel@tonic-gate 
6077c478bd9Sstevel@tonic-gate 	/*
6087c478bd9Sstevel@tonic-gate 	 * Get the BNC/TP indicator from the conf file for 21040
6097c478bd9Sstevel@tonic-gate 	 */
6107c478bd9Sstevel@tonic-gate 	dnetp->bnc_indicator =
61117de24c9Svb 	    ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
61217de24c9Svb 	    "bncaui", -1);
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate 	/*
6157c478bd9Sstevel@tonic-gate 	 * For 21140 check the data rate set in the conf file. Default is
6167c478bd9Sstevel@tonic-gate 	 * 100Mb/s. Disallow connections at settings that would conflict
6177c478bd9Sstevel@tonic-gate 	 * with what's in the conf file
6187c478bd9Sstevel@tonic-gate 	 */
6197c478bd9Sstevel@tonic-gate 	dnetp->speed =
62017de24c9Svb 	    ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
62117de24c9Svb 	    speed_propname, 0);
6227c478bd9Sstevel@tonic-gate 	dnetp->full_duplex =
62317de24c9Svb 	    ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
62417de24c9Svb 	    duplex_propname, -1);
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	if (dnetp->speed == 100) {
6277c478bd9Sstevel@tonic-gate 		dnetp->disallowed_media |= (1UL<<MEDIA_TP) | (1UL<<MEDIA_TP_FD);
6287c478bd9Sstevel@tonic-gate 	} else if (dnetp->speed == 10) {
6297c478bd9Sstevel@tonic-gate 		dnetp->disallowed_media |=
6307c478bd9Sstevel@tonic-gate 		    (1UL<<MEDIA_SYM_SCR) | (1UL<<MEDIA_SYM_SCR_FD);
6317c478bd9Sstevel@tonic-gate 	}
6327c478bd9Sstevel@tonic-gate 
6337c478bd9Sstevel@tonic-gate 	if (dnetp->full_duplex == 1) {
6347c478bd9Sstevel@tonic-gate 		dnetp->disallowed_media |=
6357c478bd9Sstevel@tonic-gate 		    (1UL<<MEDIA_TP) | (1UL<<MEDIA_SYM_SCR);
6367c478bd9Sstevel@tonic-gate 	} else if (dnetp->full_duplex == 0) {
6377c478bd9Sstevel@tonic-gate 		dnetp->disallowed_media |=
6387c478bd9Sstevel@tonic-gate 		    (1UL<<MEDIA_TP_FD) | (1UL<<MEDIA_SYM_SCR_FD);
6397c478bd9Sstevel@tonic-gate 	}
6407c478bd9Sstevel@tonic-gate 
6417c478bd9Sstevel@tonic-gate 	if (dnetp->bnc_indicator == 0) /* Disable BNC and AUI media */
6427c478bd9Sstevel@tonic-gate 		dnetp->disallowed_media |= (1UL<<MEDIA_BNC) | (1UL<<MEDIA_AUI);
6437c478bd9Sstevel@tonic-gate 	else if (dnetp->bnc_indicator == 1) /* Force BNC only */
6447c478bd9Sstevel@tonic-gate 		dnetp->disallowed_media =  (uint32_t)~(1U<<MEDIA_BNC);
6457c478bd9Sstevel@tonic-gate 	else if (dnetp->bnc_indicator == 2) /* Force AUI only */
6467c478bd9Sstevel@tonic-gate 		dnetp->disallowed_media = (uint32_t)~(1U<<MEDIA_AUI);
6477c478bd9Sstevel@tonic-gate 
64898e8d175SSteven Stallion 	dnet_reset_board(dnetp);
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	secondary = dnet_read_srom(devinfo, dnetp->board_type, dnetp->io_handle,
6517c478bd9Sstevel@tonic-gate 	    dnetp->io_reg, vendor_info, sizeof (vendor_info));
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	if (secondary == -1) /* ASSERT (vendor_info not big enough) */
6547c478bd9Sstevel@tonic-gate 		goto fail1;
6557c478bd9Sstevel@tonic-gate 
6567c478bd9Sstevel@tonic-gate 	dnet_parse_srom(dnetp, &dnetp->sr, vendor_info);
6577c478bd9Sstevel@tonic-gate 
6587c478bd9Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
6597c478bd9Sstevel@tonic-gate 	    printsrom_propname, 0))
6607c478bd9Sstevel@tonic-gate 		dnet_print_srom(&dnetp->sr);
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	dnetp->sr.netaddr[ETHERADDRL-1] += secondary;	/* unique ether addr */
6637c478bd9Sstevel@tonic-gate 
6647c478bd9Sstevel@tonic-gate 	BCOPY((caddr_t)dnetp->sr.netaddr,
66517de24c9Svb 	    (caddr_t)dnetp->vendor_addr, ETHERADDRL);
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	BCOPY((caddr_t)dnetp->sr.netaddr,
66817de24c9Svb 	    (caddr_t)dnetp->curr_macaddr, ETHERADDRL);
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 	/*
6717c478bd9Sstevel@tonic-gate 	 * determine whether to implement workaround from DEC
6727c478bd9Sstevel@tonic-gate 	 * for DMA overrun errata.
6737c478bd9Sstevel@tonic-gate 	 */
6747c478bd9Sstevel@tonic-gate 	dnetp->overrun_workaround =
6757c478bd9Sstevel@tonic-gate 	    ((dnetp->board_type == DEVICE_ID_21140 && revid >= 0x20) ||
6767c478bd9Sstevel@tonic-gate 	    (dnetp->board_type == DEVICE_ID_21143 && revid <= 0x30)) ? 1 : 0;
6777c478bd9Sstevel@tonic-gate 
6787c478bd9Sstevel@tonic-gate 	dnetp->overrun_workaround =
67917de24c9Svb 	    ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
68017de24c9Svb 	    ofloprob_propname, dnetp->overrun_workaround);
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	/*
6837c478bd9Sstevel@tonic-gate 	 * Add the interrupt handler if dnet_hack_interrupts() returns 0.
6847c478bd9Sstevel@tonic-gate 	 * Otherwise dnet_hack_interrupts() itself adds the handler.
6857c478bd9Sstevel@tonic-gate 	 */
68698e8d175SSteven Stallion 	if (!dnet_hack_interrupts(dnetp, secondary)) {
6877c478bd9Sstevel@tonic-gate 		(void) ddi_add_intr(devinfo, 0, NULL,
68898e8d175SSteven Stallion 		    NULL, dnet_intr, (caddr_t)dnetp);
6897c478bd9Sstevel@tonic-gate 	}
6907c478bd9Sstevel@tonic-gate 
6917c478bd9Sstevel@tonic-gate 	dnetp->max_tx_desc = max_tx_desc;
6927c478bd9Sstevel@tonic-gate 	dnetp->max_rx_desc = max_rx_desc_21040;
6937c478bd9Sstevel@tonic-gate 	if (dnetp->board_type != DEVICE_ID_21040 &&
6947c478bd9Sstevel@tonic-gate 	    dnetp->board_type != DEVICE_ID_21041 &&
6957c478bd9Sstevel@tonic-gate 	    dnetp->speed != 10)
6967c478bd9Sstevel@tonic-gate 		dnetp->max_rx_desc = max_rx_desc_21140;
6977c478bd9Sstevel@tonic-gate 
6987c478bd9Sstevel@tonic-gate 	/* Allocate the TX and RX descriptors/buffers. */
69998e8d175SSteven Stallion 	if (dnet_alloc_bufs(dnetp) == FAILURE) {
7007c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "DNET: Not enough DMA memory for buffers.");
7017c478bd9Sstevel@tonic-gate 		goto fail2;
7027c478bd9Sstevel@tonic-gate 	}
7037c478bd9Sstevel@tonic-gate 
7047c478bd9Sstevel@tonic-gate 	/*
70598e8d175SSteven Stallion 	 *	Register ourselves with the GLDv3 interface
7067c478bd9Sstevel@tonic-gate 	 */
70798e8d175SSteven Stallion 	if ((macp = mac_alloc(MAC_VERSION)) == NULL)
70898e8d175SSteven Stallion 		goto fail2;
70998e8d175SSteven Stallion 
71098e8d175SSteven Stallion 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
71198e8d175SSteven Stallion 	macp->m_driver = dnetp;
71298e8d175SSteven Stallion 	macp->m_dip = devinfo;
71398e8d175SSteven Stallion 	macp->m_src_addr = dnetp->curr_macaddr;
71498e8d175SSteven Stallion 	macp->m_callbacks = &dnet_m_callbacks;
71598e8d175SSteven Stallion 	macp->m_min_sdu = 0;
71698e8d175SSteven Stallion 	macp->m_max_sdu = ETHERMTU;
71798e8d175SSteven Stallion 	macp->m_margin = VLAN_TAGSZ;
71898e8d175SSteven Stallion 
71998e8d175SSteven Stallion 	if (mac_register(macp, &dnetp->mac_handle) == 0) {
72098e8d175SSteven Stallion 		mac_free(macp);
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 		mutex_enter(&dnetp->intrlock);
72398e8d175SSteven Stallion 
7247c478bd9Sstevel@tonic-gate 		dnetp->phyaddr = -1;
7257c478bd9Sstevel@tonic-gate 		if (dnetp->board_type == DEVICE_ID_21140 ||
7267c478bd9Sstevel@tonic-gate 		    dnetp->board_type == DEVICE_ID_21143)
72798e8d175SSteven Stallion 			do_phy(dnetp);	/* Initialize the PHY, if any */
72898e8d175SSteven Stallion 		find_active_media(dnetp);
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 		/* if the chosen media is non-MII, stop the port monitor */
7317c478bd9Sstevel@tonic-gate 		if (dnetp->selected_media_block->media_code != MEDIA_MII &&
7327c478bd9Sstevel@tonic-gate 		    dnetp->mii != NULL) {
7337c478bd9Sstevel@tonic-gate 			mii_destroy(dnetp->mii);
7347c478bd9Sstevel@tonic-gate 			dnetp->mii = NULL;
7357c478bd9Sstevel@tonic-gate 			dnetp->phyaddr = -1;
7367c478bd9Sstevel@tonic-gate 		}
7377c478bd9Sstevel@tonic-gate 
7387c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
7397c478bd9Sstevel@tonic-gate 		if (dnetdebug & DNETSENSE)
7407c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "dnet: link configured : %s",
7417c478bd9Sstevel@tonic-gate 			    media_str[dnetp->selected_media_block->media_code]);
7427c478bd9Sstevel@tonic-gate #endif
7437c478bd9Sstevel@tonic-gate 		bzero(dnetp->setup_buf_vaddr, SETUPBUF_SIZE);
74498e8d175SSteven Stallion 
74598e8d175SSteven Stallion 		dnet_reset_board(dnetp);
74698e8d175SSteven Stallion 		dnet_init_board(dnetp);
74798e8d175SSteven Stallion 
7487c478bd9Sstevel@tonic-gate 		mutex_exit(&dnetp->intrlock);
74998e8d175SSteven Stallion 
75098e8d175SSteven Stallion 		(void) dnet_m_unicst(dnetp, dnetp->curr_macaddr);
75198e8d175SSteven Stallion 		(void) dnet_m_multicst(dnetp, B_TRUE, dnet_broadcastaddr);
75298e8d175SSteven Stallion 
7537c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
7547c478bd9Sstevel@tonic-gate 	}
75598e8d175SSteven Stallion 
75698e8d175SSteven Stallion 	mac_free(macp);
7577c478bd9Sstevel@tonic-gate fail2:
7587c478bd9Sstevel@tonic-gate 	/* XXX function return value ignored */
7597c478bd9Sstevel@tonic-gate 	/*
7607c478bd9Sstevel@tonic-gate 	 * dnet_detach_hacked_interrupt() will remove
7617c478bd9Sstevel@tonic-gate 	 * interrupt for the non-hacked case also.
7627c478bd9Sstevel@tonic-gate 	 */
7637c478bd9Sstevel@tonic-gate 	(void) dnet_detach_hacked_interrupt(devinfo);
76498e8d175SSteven Stallion 	dnet_free_bufs(dnetp);
7657c478bd9Sstevel@tonic-gate fail1:
7667c478bd9Sstevel@tonic-gate 	mutex_destroy(&dnetp->txlock);
7677c478bd9Sstevel@tonic-gate 	mutex_destroy(&dnetp->intrlock);
7687c478bd9Sstevel@tonic-gate fail:
7697c478bd9Sstevel@tonic-gate 	ddi_regs_map_free(&dnetp->io_handle);
7707c478bd9Sstevel@tonic-gate 	kmem_free(dnetp, sizeof (struct dnetinstance));
7717c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
7727c478bd9Sstevel@tonic-gate }
7737c478bd9Sstevel@tonic-gate 
7747c478bd9Sstevel@tonic-gate /*
7757c478bd9Sstevel@tonic-gate  * detach(9E) -- Detach a device from the system
7767c478bd9Sstevel@tonic-gate  */
7777c478bd9Sstevel@tonic-gate static int
dnet_detach(dev_info_t * devinfo,ddi_detach_cmd_t cmd)77898e8d175SSteven Stallion dnet_detach(dev_info_t *devinfo, ddi_detach_cmd_t cmd)
7797c478bd9Sstevel@tonic-gate {
7807c478bd9Sstevel@tonic-gate 	int32_t rc;
7817c478bd9Sstevel@tonic-gate 	struct dnetinstance *dnetp;		/* Our private device info */
7827c478bd9Sstevel@tonic-gate 	int32_t		proplen;
7837c478bd9Sstevel@tonic-gate 
78498e8d175SSteven Stallion 	/* Get the driver private (dnetinstance) structure */
78598e8d175SSteven Stallion 	dnetp = ddi_get_driver_private(devinfo);
7867c478bd9Sstevel@tonic-gate 
7878ef10d20Sgd 	switch (cmd) {
7888ef10d20Sgd 	case DDI_DETACH:
7898ef10d20Sgd 		break;
7908ef10d20Sgd 
7918ef10d20Sgd 	case DDI_SUSPEND:
7928ef10d20Sgd 		/*
7938ef10d20Sgd 		 * NB: dnetp->suspended can only be modified (marked true)
7948ef10d20Sgd 		 * if both intrlock and txlock are held.  This keeps both
7958ef10d20Sgd 		 * tx and rx code paths excluded.
7968ef10d20Sgd 		 */
7978ef10d20Sgd 		mutex_enter(&dnetp->intrlock);
7988ef10d20Sgd 		mutex_enter(&dnetp->txlock);
7998ef10d20Sgd 		dnetp->suspended = B_TRUE;
80098e8d175SSteven Stallion 		dnet_reset_board(dnetp);
8018ef10d20Sgd 		mutex_exit(&dnetp->txlock);
8028ef10d20Sgd 		mutex_exit(&dnetp->intrlock);
8038ef10d20Sgd 		return (DDI_SUCCESS);
8048ef10d20Sgd 
8058ef10d20Sgd 	default:
8068ef10d20Sgd 		return (DDI_FAILURE);
8078ef10d20Sgd 	}
8088ef10d20Sgd 
8097c478bd9Sstevel@tonic-gate 	/*
81098e8d175SSteven Stallion 	 *	Unregister ourselves from the GLDv3 interface
8117c478bd9Sstevel@tonic-gate 	 */
81298e8d175SSteven Stallion 	if (mac_unregister(dnetp->mac_handle) != 0)
8137c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8147c478bd9Sstevel@tonic-gate 
8157c478bd9Sstevel@tonic-gate 	/* stop the board if it is running */
81698e8d175SSteven Stallion 	dnet_reset_board(dnetp);
8177c478bd9Sstevel@tonic-gate 
8187c478bd9Sstevel@tonic-gate 	if ((rc = dnet_detach_hacked_interrupt(devinfo)) != DDI_SUCCESS)
8197c478bd9Sstevel@tonic-gate 		return (rc);
8207c478bd9Sstevel@tonic-gate 
8217c478bd9Sstevel@tonic-gate 	if (dnetp->mii != NULL)
8227c478bd9Sstevel@tonic-gate 		mii_destroy(dnetp->mii);
8237c478bd9Sstevel@tonic-gate 
8247c478bd9Sstevel@tonic-gate 	/* Free leaf information */
8257c478bd9Sstevel@tonic-gate 	set_leaf(&dnetp->sr, NULL);
8267c478bd9Sstevel@tonic-gate 
8277c478bd9Sstevel@tonic-gate 	ddi_regs_map_free(&dnetp->io_handle);
82898e8d175SSteven Stallion 	dnet_free_bufs(dnetp);
8297c478bd9Sstevel@tonic-gate 	mutex_destroy(&dnetp->txlock);
8307c478bd9Sstevel@tonic-gate 	mutex_destroy(&dnetp->intrlock);
8317c478bd9Sstevel@tonic-gate 	kmem_free(dnetp, sizeof (struct dnetinstance));
8327c478bd9Sstevel@tonic-gate 
8337c478bd9Sstevel@tonic-gate #ifdef BUG_4010796
8347c478bd9Sstevel@tonic-gate 	if (ddi_getproplen(DDI_DEV_T_ANY, devinfo, 0,
8357c478bd9Sstevel@tonic-gate 	    "DNET_HACK", &proplen) != DDI_PROP_SUCCESS)
8367c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 	/*
8397c478bd9Sstevel@tonic-gate 	 * We must remove the properties we added, because if we leave
8407c478bd9Sstevel@tonic-gate 	 * them in the devinfo nodes and the driver is unloaded, when
8417c478bd9Sstevel@tonic-gate 	 * the driver is reloaded the info will still be there, causing
8427c478bd9Sstevel@tonic-gate 	 * nodes which had returned PROBE_PARTIAL the first time to
8437c478bd9Sstevel@tonic-gate 	 * instead return PROBE_SUCCESS, in turn causing the nodes to be
8447c478bd9Sstevel@tonic-gate 	 * attached in a different order, causing their PPA numbers to
8457c478bd9Sstevel@tonic-gate 	 * be different the second time around, which is undesirable.
8467c478bd9Sstevel@tonic-gate 	 */
8477c478bd9Sstevel@tonic-gate 	(void) ddi_prop_remove(DDI_DEV_T_NONE, devinfo, "DNET_HACK");
8487c478bd9Sstevel@tonic-gate 	(void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo),
84917de24c9Svb 	    "DNET_SROM");
8507c478bd9Sstevel@tonic-gate 	(void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo),
85117de24c9Svb 	    "DNET_DEVNUM");
8527c478bd9Sstevel@tonic-gate #endif
8537c478bd9Sstevel@tonic-gate 
8547c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8557c478bd9Sstevel@tonic-gate }
8567c478bd9Sstevel@tonic-gate 
85798e8d175SSteven Stallion int
dnet_quiesce(dev_info_t * dip)85898e8d175SSteven Stallion dnet_quiesce(dev_info_t *dip)
8597c478bd9Sstevel@tonic-gate {
86098e8d175SSteven Stallion 	struct dnetinstance *dnetp = ddi_get_driver_private(dip);
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	/*
86398e8d175SSteven Stallion 	 * Reset chip (disables interrupts).
8647c478bd9Sstevel@tonic-gate 	 */
86598e8d175SSteven Stallion 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG), 0);
86698e8d175SSteven Stallion 	ddi_put32(dnetp->io_handle,
86798e8d175SSteven Stallion 	    REG32(dnetp->io_reg, BUS_MODE_REG), SW_RESET);
8687c478bd9Sstevel@tonic-gate 
86998e8d175SSteven Stallion 	return (DDI_SUCCESS);
8707c478bd9Sstevel@tonic-gate }
8717c478bd9Sstevel@tonic-gate 
8727c478bd9Sstevel@tonic-gate static void
dnet_reset_board(struct dnetinstance * dnetp)87398e8d175SSteven Stallion dnet_reset_board(struct dnetinstance *dnetp)
8747c478bd9Sstevel@tonic-gate {
8757c478bd9Sstevel@tonic-gate 	uint32_t	val;
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate 	/*
8787c478bd9Sstevel@tonic-gate 	 * before initializing the dnet should be in STOP state
8797c478bd9Sstevel@tonic-gate 	 */
88017de24c9Svb 	val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG));
8814ab75253Smrj 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG),
88217de24c9Svb 	    val & ~(START_TRANSMIT | START_RECEIVE));
8837c478bd9Sstevel@tonic-gate 
8847c478bd9Sstevel@tonic-gate 	/*
8857c478bd9Sstevel@tonic-gate 	 * Reset the chip
8867c478bd9Sstevel@tonic-gate 	 */
8874ab75253Smrj 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG), 0);
8884ab75253Smrj 	ddi_put32(dnetp->io_handle,
88917de24c9Svb 	    REG32(dnetp->io_reg, BUS_MODE_REG), SW_RESET);
8907c478bd9Sstevel@tonic-gate 	drv_usecwait(5);
8917c478bd9Sstevel@tonic-gate }
8927c478bd9Sstevel@tonic-gate 
8937c478bd9Sstevel@tonic-gate /*
8947c478bd9Sstevel@tonic-gate  * dnet_init_board() -- initialize the specified network board short of
8957c478bd9Sstevel@tonic-gate  * actually starting the board.  Call after dnet_reset_board().
8967c478bd9Sstevel@tonic-gate  * called with intrlock held.
8977c478bd9Sstevel@tonic-gate  */
8987c478bd9Sstevel@tonic-gate static void
dnet_init_board(struct dnetinstance * dnetp)89998e8d175SSteven Stallion dnet_init_board(struct dnetinstance *dnetp)
9007c478bd9Sstevel@tonic-gate {
90198e8d175SSteven Stallion 	set_opr(dnetp);
90298e8d175SSteven Stallion 	set_gpr(dnetp);
90398e8d175SSteven Stallion 	set_sia(dnetp);
90498e8d175SSteven Stallion 	dnet_chip_init(dnetp);
9057c478bd9Sstevel@tonic-gate }
9067c478bd9Sstevel@tonic-gate 
9077c478bd9Sstevel@tonic-gate /* dnet_chip_init() - called with intrlock held */
9087c478bd9Sstevel@tonic-gate static void
dnet_chip_init(struct dnetinstance * dnetp)90998e8d175SSteven Stallion dnet_chip_init(struct dnetinstance *dnetp)
9107c478bd9Sstevel@tonic-gate {
9114ab75253Smrj 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, BUS_MODE_REG),
91217de24c9Svb 	    CACHE_ALIGN | BURST_SIZE);		/* CSR0 */
9137c478bd9Sstevel@tonic-gate 
9147c478bd9Sstevel@tonic-gate 	/*
9157c478bd9Sstevel@tonic-gate 	 * Initialize the TX and RX descriptors/buffers
9167c478bd9Sstevel@tonic-gate 	 */
91798e8d175SSteven Stallion 	dnet_init_txrx_bufs(dnetp);
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 	/*
9207c478bd9Sstevel@tonic-gate 	 * Set the base address of the Rx descriptor list in CSR3
9217c478bd9Sstevel@tonic-gate 	 */
9224ab75253Smrj 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, RX_BASE_ADDR_REG),
9238ef10d20Sgd 	    dnetp->rx_desc_paddr);
9247c478bd9Sstevel@tonic-gate 
9257c478bd9Sstevel@tonic-gate 	/*
9267c478bd9Sstevel@tonic-gate 	 * Set the base address of the Tx descrptor list in CSR4
9277c478bd9Sstevel@tonic-gate 	 */
9284ab75253Smrj 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, TX_BASE_ADDR_REG),
9298ef10d20Sgd 	    dnetp->tx_desc_paddr);
9307c478bd9Sstevel@tonic-gate 
9317c478bd9Sstevel@tonic-gate 	dnetp->tx_current_desc = dnetp->rx_current_desc = 0;
9327c478bd9Sstevel@tonic-gate 	dnetp->transmitted_desc = 0;
9337c478bd9Sstevel@tonic-gate 	dnetp->free_desc = dnetp->max_tx_desc;
93498e8d175SSteven Stallion 	enable_interrupts(dnetp);
9357c478bd9Sstevel@tonic-gate }
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate /*
9387c478bd9Sstevel@tonic-gate  *	dnet_start() -- start the board receiving and allow transmits.
9397c478bd9Sstevel@tonic-gate  *  Called with intrlock held.
9407c478bd9Sstevel@tonic-gate  */
9417c478bd9Sstevel@tonic-gate static int
dnet_start(struct dnetinstance * dnetp)94298e8d175SSteven Stallion dnet_start(struct dnetinstance *dnetp)
9437c478bd9Sstevel@tonic-gate {
94498e8d175SSteven Stallion 	uint32_t val;
9457c478bd9Sstevel@tonic-gate 
9467c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
9477c478bd9Sstevel@tonic-gate 	/*
9487c478bd9Sstevel@tonic-gate 	 * start the board and enable receiving
9497c478bd9Sstevel@tonic-gate 	 */
95017de24c9Svb 	val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG));
9514ab75253Smrj 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG),
95217de24c9Svb 	    val | START_TRANSMIT);
95398e8d175SSteven Stallion 	(void) dnet_set_addr(dnetp);
95417de24c9Svb 	val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG));
9554ab75253Smrj 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG),
95617de24c9Svb 	    val | START_RECEIVE);
95798e8d175SSteven Stallion 	enable_interrupts(dnetp);
9587c478bd9Sstevel@tonic-gate 	return (0);
9597c478bd9Sstevel@tonic-gate }
9607c478bd9Sstevel@tonic-gate 
9617c478bd9Sstevel@tonic-gate static int
dnet_m_start(void * arg)96298e8d175SSteven Stallion dnet_m_start(void *arg)
9637c478bd9Sstevel@tonic-gate {
96498e8d175SSteven Stallion 	struct dnetinstance *dnetp = arg;
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	mutex_enter(&dnetp->intrlock);
9678ef10d20Sgd 	dnetp->running = B_TRUE;
9687c478bd9Sstevel@tonic-gate 	/*
9697c478bd9Sstevel@tonic-gate 	 * start the board and enable receiving
9707c478bd9Sstevel@tonic-gate 	 */
9718ef10d20Sgd 	if (!dnetp->suspended)
97298e8d175SSteven Stallion 		(void) dnet_start(dnetp);
9737c478bd9Sstevel@tonic-gate 	mutex_exit(&dnetp->intrlock);
9747c478bd9Sstevel@tonic-gate 	return (0);
9757c478bd9Sstevel@tonic-gate }
9767c478bd9Sstevel@tonic-gate 
97798e8d175SSteven Stallion static void
dnet_m_stop(void * arg)97898e8d175SSteven Stallion dnet_m_stop(void *arg)
9797c478bd9Sstevel@tonic-gate {
98098e8d175SSteven Stallion 	struct dnetinstance *dnetp = arg;
98198e8d175SSteven Stallion 	uint32_t val;
9827c478bd9Sstevel@tonic-gate 
9837c478bd9Sstevel@tonic-gate 	/*
9847c478bd9Sstevel@tonic-gate 	 * stop the board and disable transmit/receive
9857c478bd9Sstevel@tonic-gate 	 */
9867c478bd9Sstevel@tonic-gate 	mutex_enter(&dnetp->intrlock);
9878ef10d20Sgd 	if (!dnetp->suspended) {
9888ef10d20Sgd 		val = ddi_get32(dnetp->io_handle,
9898ef10d20Sgd 		    REG32(dnetp->io_reg, OPN_MODE_REG));
9908ef10d20Sgd 		ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG),
9918ef10d20Sgd 		    val & ~(START_TRANSMIT | START_RECEIVE));
9928ef10d20Sgd 	}
99332607e28SSteven Stallion 	mac_link_update(dnetp->mac_handle, LINK_STATE_UNKNOWN);
9948ef10d20Sgd 	dnetp->running = B_FALSE;
9957c478bd9Sstevel@tonic-gate 	mutex_exit(&dnetp->intrlock);
9967c478bd9Sstevel@tonic-gate }
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate /*
9997c478bd9Sstevel@tonic-gate  *	dnet_set_addr() -- set the physical network address on the board
10007c478bd9Sstevel@tonic-gate  *  Called with intrlock held.
10017c478bd9Sstevel@tonic-gate  */
10027c478bd9Sstevel@tonic-gate static int
dnet_set_addr(struct dnetinstance * dnetp)100398e8d175SSteven Stallion dnet_set_addr(struct dnetinstance *dnetp)
10047c478bd9Sstevel@tonic-gate {
10057c478bd9Sstevel@tonic-gate 	struct tx_desc_type *desc;
1006*f879aa94SToomas Soome 	int		current_desc;
10078ef10d20Sgd 	uint32_t	val;
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
10108ef10d20Sgd 
10118ef10d20Sgd 	val = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG));
10127c478bd9Sstevel@tonic-gate 	if (!(val & START_TRANSMIT))
10137c478bd9Sstevel@tonic-gate 		return (0);
10147c478bd9Sstevel@tonic-gate 
10157c478bd9Sstevel@tonic-gate 	current_desc = dnetp->tx_current_desc;
10167c478bd9Sstevel@tonic-gate 	desc = &dnetp->tx_desc[current_desc];
10177c478bd9Sstevel@tonic-gate 
10187c478bd9Sstevel@tonic-gate 	mutex_enter(&dnetp->txlock);
10197c478bd9Sstevel@tonic-gate 	dnetp->need_saddr = 0;
10207c478bd9Sstevel@tonic-gate 	mutex_exit(&dnetp->txlock);
10217c478bd9Sstevel@tonic-gate 
102298e8d175SSteven Stallion 	if ((alloc_descriptor(dnetp)) == FAILURE) {
10237c478bd9Sstevel@tonic-gate 		mutex_enter(&dnetp->txlock);
10247c478bd9Sstevel@tonic-gate 		dnetp->need_saddr = 1;
10257c478bd9Sstevel@tonic-gate 		mutex_exit(&dnetp->txlock);
10267c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
10277c478bd9Sstevel@tonic-gate 		if (dnetdebug & DNETTRACE)
10287c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "DNET saddr:alloc descriptor failure");
10297c478bd9Sstevel@tonic-gate #endif
10307c478bd9Sstevel@tonic-gate 		return (0);
10317c478bd9Sstevel@tonic-gate 	}
10327c478bd9Sstevel@tonic-gate 
10338ef10d20Sgd 	desc->buffer1			= dnetp->setup_buf_paddr;
10348ef10d20Sgd 	desc->buffer2			= 0;
1035*f879aa94SToomas Soome 	desc->desc1.buffer_size1	= SETUPBUF_SIZE;
1036*f879aa94SToomas Soome 	desc->desc1.buffer_size2	= 0;
10377c478bd9Sstevel@tonic-gate 	desc->desc1.setup_packet	= 1;
10387c478bd9Sstevel@tonic-gate 	desc->desc1.first_desc		= 0;
1039*f879aa94SToomas Soome 	desc->desc1.last_desc		= 0;
1040*f879aa94SToomas Soome 	desc->desc1.filter_type0	= 1;
1041*f879aa94SToomas Soome 	desc->desc1.filter_type1	= 1;
10427c478bd9Sstevel@tonic-gate 	desc->desc1.int_on_comp		= 1;
10437c478bd9Sstevel@tonic-gate 
10448ef10d20Sgd 	desc->desc0.own = 1;
10458ef10d20Sgd 	ddi_put8(dnetp->io_handle, REG8(dnetp->io_reg, TX_POLL_REG),
10468ef10d20Sgd 	    TX_POLL_DEMAND);
10478ef10d20Sgd 	return (0);
10488ef10d20Sgd }
10498ef10d20Sgd 
10508ef10d20Sgd static int
dnet_m_unicst(void * arg,const uint8_t * macaddr)105198e8d175SSteven Stallion dnet_m_unicst(void *arg, const uint8_t *macaddr)
10528ef10d20Sgd {
105398e8d175SSteven Stallion 	struct dnetinstance *dnetp = arg;
10548ef10d20Sgd 	uint32_t	index;
10558ef10d20Sgd 	uint32_t	*hashp;
10568ef10d20Sgd 
10578ef10d20Sgd 	mutex_enter(&dnetp->intrlock);
10588ef10d20Sgd 
10598ef10d20Sgd 	bcopy(macaddr, dnetp->curr_macaddr, ETHERADDRL);
10608ef10d20Sgd 
10617c478bd9Sstevel@tonic-gate 	/*
10627c478bd9Sstevel@tonic-gate 	 * As we are using Imperfect filtering, the broadcast address has to
10637c478bd9Sstevel@tonic-gate 	 * be set explicitly in the 512 bit hash table.  Hence the index into
10647c478bd9Sstevel@tonic-gate 	 * the hash table is calculated and the bit set to enable reception
10657c478bd9Sstevel@tonic-gate 	 * of broadcast packets.
10667c478bd9Sstevel@tonic-gate 	 *
10677c478bd9Sstevel@tonic-gate 	 * We also use HASH_ONLY mode, without using the perfect filter for
10687c478bd9Sstevel@tonic-gate 	 * our station address, because there appears to be a bug in the
10697c478bd9Sstevel@tonic-gate 	 * 21140 where it fails to receive the specified perfect filter
10707c478bd9Sstevel@tonic-gate 	 * address.
10717c478bd9Sstevel@tonic-gate 	 *
10727c478bd9Sstevel@tonic-gate 	 * Since dlsdmult comes through here, it doesn't matter that the count
10737c478bd9Sstevel@tonic-gate 	 * is wrong for the two bits that correspond to the cases below. The
10747c478bd9Sstevel@tonic-gate 	 * worst that could happen is that we'd leave on a bit for an old
10757c478bd9Sstevel@tonic-gate 	 * macaddr, in the case where the macaddr gets changed, which is rare.
10767c478bd9Sstevel@tonic-gate 	 * Since filtering is imperfect, it is OK if that happens.
10777c478bd9Sstevel@tonic-gate 	 */
10787c478bd9Sstevel@tonic-gate 	hashp = (uint32_t *)dnetp->setup_buf_vaddr;
107998e8d175SSteven Stallion 	index = hashindex((uint8_t *)dnet_broadcastaddr);
10807c478bd9Sstevel@tonic-gate 	hashp[ index / 16 ] |= 1 << (index % 16);
10817c478bd9Sstevel@tonic-gate 
108298e8d175SSteven Stallion 	index = hashindex((uint8_t *)dnetp->curr_macaddr);
10837c478bd9Sstevel@tonic-gate 	hashp[ index / 16 ] |= 1 << (index % 16);
10847c478bd9Sstevel@tonic-gate 
10858ef10d20Sgd 	if (!dnetp->suspended)
108698e8d175SSteven Stallion 		(void) dnet_set_addr(dnetp);
10877c478bd9Sstevel@tonic-gate 	mutex_exit(&dnetp->intrlock);
10887c478bd9Sstevel@tonic-gate 	return (0);
10897c478bd9Sstevel@tonic-gate }
10907c478bd9Sstevel@tonic-gate 
10917c478bd9Sstevel@tonic-gate static int
dnet_m_multicst(void * arg,boolean_t add,const uint8_t * macaddr)109298e8d175SSteven Stallion dnet_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
10937c478bd9Sstevel@tonic-gate {
109498e8d175SSteven Stallion 	struct dnetinstance *dnetp = arg;
10957c478bd9Sstevel@tonic-gate 	uint32_t	index;
10967c478bd9Sstevel@tonic-gate 	uint32_t	*hashp;
10977c478bd9Sstevel@tonic-gate 	uint32_t	retval;
10987c478bd9Sstevel@tonic-gate 
10997c478bd9Sstevel@tonic-gate 	mutex_enter(&dnetp->intrlock);
110098e8d175SSteven Stallion 	index = hashindex(macaddr);
11017c478bd9Sstevel@tonic-gate 	hashp = (uint32_t *)dnetp->setup_buf_vaddr;
110298e8d175SSteven Stallion 	if (add) {
11037c478bd9Sstevel@tonic-gate 		if (dnetp->multicast_cnt[index]++) {
11047c478bd9Sstevel@tonic-gate 			mutex_exit(&dnetp->intrlock);
11057c478bd9Sstevel@tonic-gate 			return (0);
11067c478bd9Sstevel@tonic-gate 		}
11077c478bd9Sstevel@tonic-gate 		hashp[ index / 16 ] |= 1 << (index % 16);
11087c478bd9Sstevel@tonic-gate 	} else {
11097c478bd9Sstevel@tonic-gate 		if (--dnetp->multicast_cnt[index]) {
11107c478bd9Sstevel@tonic-gate 			mutex_exit(&dnetp->intrlock);
11117c478bd9Sstevel@tonic-gate 			return (0);
11127c478bd9Sstevel@tonic-gate 		}
11137c478bd9Sstevel@tonic-gate 		hashp[ index / 16 ] &= ~ (1 << (index % 16));
11147c478bd9Sstevel@tonic-gate 	}
11158ef10d20Sgd 	if (!dnetp->suspended)
111698e8d175SSteven Stallion 		retval = dnet_set_addr(dnetp);
11178ef10d20Sgd 	else
11188ef10d20Sgd 		retval = 0;
11197c478bd9Sstevel@tonic-gate 	mutex_exit(&dnetp->intrlock);
11207c478bd9Sstevel@tonic-gate 	return (retval);
11217c478bd9Sstevel@tonic-gate }
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate /*
11247c478bd9Sstevel@tonic-gate  * A hashing function used for setting the
11257c478bd9Sstevel@tonic-gate  * node address or a multicast address
11267c478bd9Sstevel@tonic-gate  */
11277c478bd9Sstevel@tonic-gate static uint32_t
hashindex(const uint8_t * address)112898e8d175SSteven Stallion hashindex(const uint8_t *address)
11297c478bd9Sstevel@tonic-gate {
11307c478bd9Sstevel@tonic-gate 	uint32_t	crc = (uint32_t)HASH_CRC;
1131*f879aa94SToomas Soome 	uint32_t const	POLY = HASH_POLY;
11327c478bd9Sstevel@tonic-gate 	uint32_t	msb;
1133*f879aa94SToomas Soome 	int32_t		byteslength;
1134*f879aa94SToomas Soome 	uint8_t		currentbyte;
1135*f879aa94SToomas Soome 	uint32_t	index;
1136*f879aa94SToomas Soome 	int32_t		bit;
11377c478bd9Sstevel@tonic-gate 	int32_t		shift;
11387c478bd9Sstevel@tonic-gate 
11397c478bd9Sstevel@tonic-gate 	for (byteslength = 0; byteslength < ETHERADDRL; byteslength++) {
11407c478bd9Sstevel@tonic-gate 		currentbyte = address[byteslength];
11417c478bd9Sstevel@tonic-gate 		for (bit = 0; bit < 8; bit++) {
11427c478bd9Sstevel@tonic-gate 			msb = crc >> 31;
11437c478bd9Sstevel@tonic-gate 			crc <<= 1;
11447c478bd9Sstevel@tonic-gate 			if (msb ^ (currentbyte & 1)) {
11457c478bd9Sstevel@tonic-gate 				crc ^= POLY;
11467c478bd9Sstevel@tonic-gate 				crc |= 0x00000001;
11477c478bd9Sstevel@tonic-gate 			}
11487c478bd9Sstevel@tonic-gate 			currentbyte >>= 1;
11497c478bd9Sstevel@tonic-gate 		}
11507c478bd9Sstevel@tonic-gate 	}
11517c478bd9Sstevel@tonic-gate 
115217de24c9Svb 	for (index = 0, bit = 23, shift = 8; shift >= 0; bit++, shift--) {
115317de24c9Svb 		index |= (((crc >> bit) & 1) << shift);
11547c478bd9Sstevel@tonic-gate 	}
11557c478bd9Sstevel@tonic-gate 	return (index);
11567c478bd9Sstevel@tonic-gate }
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate static int
dnet_m_setpromisc(void * arg,boolean_t on)115998e8d175SSteven Stallion dnet_m_setpromisc(void *arg, boolean_t on)
11607c478bd9Sstevel@tonic-gate {
116198e8d175SSteven Stallion 	struct dnetinstance *dnetp = arg;
11627c478bd9Sstevel@tonic-gate 	uint32_t val;
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	mutex_enter(&dnetp->intrlock);
11657c478bd9Sstevel@tonic-gate 	if (dnetp->promisc == on) {
11667c478bd9Sstevel@tonic-gate 		mutex_exit(&dnetp->intrlock);
116798e8d175SSteven Stallion 		return (0);
11687c478bd9Sstevel@tonic-gate 	}
11697c478bd9Sstevel@tonic-gate 	dnetp->promisc = on;
11707c478bd9Sstevel@tonic-gate 
11718ef10d20Sgd 	if (!dnetp->suspended) {
11728ef10d20Sgd 		val = ddi_get32(dnetp->io_handle,
11738ef10d20Sgd 		    REG32(dnetp->io_reg, OPN_MODE_REG));
117498e8d175SSteven Stallion 		if (on)
11758ef10d20Sgd 			ddi_put32(dnetp->io_handle,
11768ef10d20Sgd 			    REG32(dnetp->io_reg, OPN_MODE_REG),
11778ef10d20Sgd 			    val | PROM_MODE);
11788ef10d20Sgd 		else
11798ef10d20Sgd 			ddi_put32(dnetp->io_handle,
11808ef10d20Sgd 			    REG32(dnetp->io_reg, OPN_MODE_REG),
11818ef10d20Sgd 			    val & (~PROM_MODE));
11828ef10d20Sgd 	}
11837c478bd9Sstevel@tonic-gate 	mutex_exit(&dnetp->intrlock);
118498e8d175SSteven Stallion 	return (0);
11857c478bd9Sstevel@tonic-gate }
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate static int
dnet_m_getstat(void * arg,uint_t stat,uint64_t * val)118898e8d175SSteven Stallion dnet_m_getstat(void *arg, uint_t stat, uint64_t *val)
11897c478bd9Sstevel@tonic-gate {
119098e8d175SSteven Stallion 	struct dnetinstance *dnetp = arg;
119198e8d175SSteven Stallion 
119298e8d175SSteven Stallion 	switch (stat) {
119398e8d175SSteven Stallion 	case MAC_STAT_IFSPEED:
119432607e28SSteven Stallion 		if (!dnetp->running) {
119532607e28SSteven Stallion 			*val = 0;
119632607e28SSteven Stallion 		} else {
119732607e28SSteven Stallion 			*val = (dnetp->mii_up ?
119832607e28SSteven Stallion 			    dnetp->mii_speed : dnetp->speed) * 1000000;
119932607e28SSteven Stallion 		}
120098e8d175SSteven Stallion 		break;
120198e8d175SSteven Stallion 
120298e8d175SSteven Stallion 	case MAC_STAT_NORCVBUF:
120398e8d175SSteven Stallion 		*val = dnetp->stat_norcvbuf;
120498e8d175SSteven Stallion 		break;
120598e8d175SSteven Stallion 
120698e8d175SSteven Stallion 	case MAC_STAT_IERRORS:
120798e8d175SSteven Stallion 		*val = dnetp->stat_errrcv;
120898e8d175SSteven Stallion 		break;
120998e8d175SSteven Stallion 
121098e8d175SSteven Stallion 	case MAC_STAT_OERRORS:
121198e8d175SSteven Stallion 		*val = dnetp->stat_errxmt;
121298e8d175SSteven Stallion 		break;
121398e8d175SSteven Stallion 
121498e8d175SSteven Stallion 	case MAC_STAT_COLLISIONS:
121598e8d175SSteven Stallion 		*val = dnetp->stat_collisions;
121698e8d175SSteven Stallion 		break;
121798e8d175SSteven Stallion 
121898e8d175SSteven Stallion 	case ETHER_STAT_DEFER_XMTS:
121998e8d175SSteven Stallion 		*val = dnetp->stat_defer;
122098e8d175SSteven Stallion 		break;
122198e8d175SSteven Stallion 
122298e8d175SSteven Stallion 	case ETHER_STAT_CARRIER_ERRORS:
122398e8d175SSteven Stallion 		*val = dnetp->stat_nocarrier;
122498e8d175SSteven Stallion 		break;
122598e8d175SSteven Stallion 
122698e8d175SSteven Stallion 	case ETHER_STAT_TOOSHORT_ERRORS:
122798e8d175SSteven Stallion 		*val = dnetp->stat_short;
122898e8d175SSteven Stallion 		break;
122998e8d175SSteven Stallion 
123098e8d175SSteven Stallion 	case ETHER_STAT_LINK_DUPLEX:
123198e8d175SSteven Stallion 		if (!dnetp->running) {
123298e8d175SSteven Stallion 			*val = LINK_DUPLEX_UNKNOWN;
123398e8d175SSteven Stallion 
123432607e28SSteven Stallion 		} else if (dnetp->mii_up) {
123598e8d175SSteven Stallion 			*val = dnetp->mii_duplex ?
123698e8d175SSteven Stallion 			    LINK_DUPLEX_FULL : LINK_DUPLEX_HALF;
123798e8d175SSteven Stallion 		} else {
123898e8d175SSteven Stallion 			*val = dnetp->full_duplex ?
123998e8d175SSteven Stallion 			    LINK_DUPLEX_FULL : LINK_DUPLEX_HALF;
124098e8d175SSteven Stallion 		}
124198e8d175SSteven Stallion 		break;
124298e8d175SSteven Stallion 
124398e8d175SSteven Stallion 	case ETHER_STAT_TX_LATE_COLLISIONS:
124498e8d175SSteven Stallion 		*val = dnetp->stat_xmtlatecoll;
124598e8d175SSteven Stallion 		break;
124698e8d175SSteven Stallion 
124798e8d175SSteven Stallion 	case ETHER_STAT_EX_COLLISIONS:
124898e8d175SSteven Stallion 		*val = dnetp->stat_excoll;
124998e8d175SSteven Stallion 		break;
125098e8d175SSteven Stallion 
125198e8d175SSteven Stallion 	case MAC_STAT_OVERFLOWS:
125298e8d175SSteven Stallion 		*val = dnetp->stat_overflow;
125398e8d175SSteven Stallion 		break;
125498e8d175SSteven Stallion 
125598e8d175SSteven Stallion 	case MAC_STAT_UNDERFLOWS:
125698e8d175SSteven Stallion 		*val = dnetp->stat_underflow;
125798e8d175SSteven Stallion 		break;
125898e8d175SSteven Stallion 
125998e8d175SSteven Stallion 	default:
126098e8d175SSteven Stallion 		return (ENOTSUP);
12618ef10d20Sgd 	}
12627c478bd9Sstevel@tonic-gate 
126398e8d175SSteven Stallion 	return (0);
12647c478bd9Sstevel@tonic-gate }
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate #define	NextTXIndex(index) (((index)+1) % dnetp->max_tx_desc)
12677c478bd9Sstevel@tonic-gate #define	PrevTXIndex(index) (((index)-1) < 0 ? dnetp->max_tx_desc - 1: (index)-1)
12687c478bd9Sstevel@tonic-gate 
126998e8d175SSteven Stallion static mblk_t *
dnet_m_tx(void * arg,mblk_t * mp)127098e8d175SSteven Stallion dnet_m_tx(void *arg, mblk_t *mp)
12717c478bd9Sstevel@tonic-gate {
127298e8d175SSteven Stallion 	struct dnetinstance *dnetp = arg;
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	mutex_enter(&dnetp->txlock);
127598e8d175SSteven Stallion 
12768ef10d20Sgd 	/* if suspended, drop the packet on the floor, we missed it */
12778ef10d20Sgd 	if (dnetp->suspended) {
12788ef10d20Sgd 		mutex_exit(&dnetp->txlock);
12798ef10d20Sgd 		freemsg(mp);
128098e8d175SSteven Stallion 		return (NULL);
12818ef10d20Sgd 	}
128298e8d175SSteven Stallion 
12837c478bd9Sstevel@tonic-gate 	if (dnetp->need_saddr) {
12847c478bd9Sstevel@tonic-gate 		/* XXX function return value ignored */
12857c478bd9Sstevel@tonic-gate 		mutex_exit(&dnetp->txlock);
12867c478bd9Sstevel@tonic-gate 		mutex_enter(&dnetp->intrlock);
128798e8d175SSteven Stallion 		(void) dnet_set_addr(dnetp);
12887c478bd9Sstevel@tonic-gate 		mutex_exit(&dnetp->intrlock);
12897c478bd9Sstevel@tonic-gate 		mutex_enter(&dnetp->txlock);
12907c478bd9Sstevel@tonic-gate 	}
12917c478bd9Sstevel@tonic-gate 
129298e8d175SSteven Stallion 	while (mp != NULL) {
129398e8d175SSteven Stallion 		if (!dnet_send(dnetp, mp)) {
129498e8d175SSteven Stallion 			mutex_exit(&dnetp->txlock);
129598e8d175SSteven Stallion 			return (mp);
129698e8d175SSteven Stallion 		}
129798e8d175SSteven Stallion 		mp = mp->b_next;
129898e8d175SSteven Stallion 	}
129998e8d175SSteven Stallion 
130098e8d175SSteven Stallion 	mutex_exit(&dnetp->txlock);
130198e8d175SSteven Stallion 
130298e8d175SSteven Stallion 	/*
130398e8d175SSteven Stallion 	 * Enable xmit interrupt in case we are running out of xmit descriptors
130498e8d175SSteven Stallion 	 * or there are more packets on the queue waiting to be transmitted.
130598e8d175SSteven Stallion 	 */
130698e8d175SSteven Stallion 	mutex_enter(&dnetp->intrlock);
130798e8d175SSteven Stallion 
130898e8d175SSteven Stallion 	enable_interrupts(dnetp);
130998e8d175SSteven Stallion 
131098e8d175SSteven Stallion 	/*
131198e8d175SSteven Stallion 	 * Kick the transmitter
131298e8d175SSteven Stallion 	 */
131398e8d175SSteven Stallion 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, TX_POLL_REG),
131498e8d175SSteven Stallion 	    TX_POLL_DEMAND);
131598e8d175SSteven Stallion 
131698e8d175SSteven Stallion 	mutex_exit(&dnetp->intrlock);
131798e8d175SSteven Stallion 
131898e8d175SSteven Stallion 	return (NULL);
131998e8d175SSteven Stallion }
132098e8d175SSteven Stallion 
132198e8d175SSteven Stallion static boolean_t
dnet_send(struct dnetinstance * dnetp,mblk_t * mp)132298e8d175SSteven Stallion dnet_send(struct dnetinstance *dnetp, mblk_t *mp)
132398e8d175SSteven Stallion {
132498e8d175SSteven Stallion 	struct tx_desc_type	*ring = dnetp->tx_desc;
132598e8d175SSteven Stallion 	int		mblen, totlen;
132698e8d175SSteven Stallion 	int		index, end_index, start_index;
132798e8d175SSteven Stallion 	int		avail;
132898e8d175SSteven Stallion 	int		error;
132998e8d175SSteven Stallion 	int		bufn;
133098e8d175SSteven Stallion 	int		retval;
133198e8d175SSteven Stallion 	mblk_t		*bp;
133298e8d175SSteven Stallion 
133398e8d175SSteven Stallion 	ASSERT(MUTEX_HELD(&dnetp->txlock));
1334*f879aa94SToomas Soome 	end_index = 0;
133598e8d175SSteven Stallion 
13367c478bd9Sstevel@tonic-gate 	/* reclaim any xmit descriptors completed */
133798e8d175SSteven Stallion 	dnet_reclaim_Tx_desc(dnetp);
13387c478bd9Sstevel@tonic-gate 
13397c478bd9Sstevel@tonic-gate 	/*
13407c478bd9Sstevel@tonic-gate 	 * Use the data buffers from the message and construct the
13417c478bd9Sstevel@tonic-gate 	 * scatter/gather list by calling ddi_dma_addr_bind_handle().
13427c478bd9Sstevel@tonic-gate 	 */
134398e8d175SSteven Stallion 	error = 0;
13447c478bd9Sstevel@tonic-gate 	totlen = 0;
13457c478bd9Sstevel@tonic-gate 	bp = mp;
13467c478bd9Sstevel@tonic-gate 	bufn = 0;
13477c478bd9Sstevel@tonic-gate 	index = start_index = dnetp->tx_current_desc;
13487c478bd9Sstevel@tonic-gate 	avail = dnetp->free_desc;
13497c478bd9Sstevel@tonic-gate 	while (bp != NULL) {
13507c478bd9Sstevel@tonic-gate 		uint_t ncookies;
13517c478bd9Sstevel@tonic-gate 		ddi_dma_cookie_t dma_cookie;
13527c478bd9Sstevel@tonic-gate 
135398e8d175SSteven Stallion 		mblen = MBLKL(bp);
13547c478bd9Sstevel@tonic-gate 
13557c478bd9Sstevel@tonic-gate 		if (!mblen) {	/* skip zero-length message blocks */
13567c478bd9Sstevel@tonic-gate 			bp = bp->b_cont;
13577c478bd9Sstevel@tonic-gate 			continue;
13587c478bd9Sstevel@tonic-gate 		}
13597c478bd9Sstevel@tonic-gate 
13607c478bd9Sstevel@tonic-gate 		retval = ddi_dma_addr_bind_handle(dnetp->dma_handle_tx, NULL,
13617c478bd9Sstevel@tonic-gate 		    (caddr_t)bp->b_rptr, mblen,
13627c478bd9Sstevel@tonic-gate 		    DDI_DMA_WRITE | DDI_DMA_STREAMING, DDI_DMA_SLEEP, 0,
13637c478bd9Sstevel@tonic-gate 		    &dma_cookie, &ncookies);
13647c478bd9Sstevel@tonic-gate 
13657c478bd9Sstevel@tonic-gate 		switch (retval) {
13667c478bd9Sstevel@tonic-gate 		case DDI_DMA_MAPPED:
13677c478bd9Sstevel@tonic-gate 			break;		/* everything's fine */
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 		case DDI_DMA_NORESOURCES:
13707c478bd9Sstevel@tonic-gate 			error = 1;	/* allow retry by gld */
13717c478bd9Sstevel@tonic-gate 			break;
13727c478bd9Sstevel@tonic-gate 
13737c478bd9Sstevel@tonic-gate 		case DDI_DMA_NOMAPPING:
13747c478bd9Sstevel@tonic-gate 		case DDI_DMA_INUSE:
13757c478bd9Sstevel@tonic-gate 		case DDI_DMA_TOOBIG:
13767c478bd9Sstevel@tonic-gate 		default:
13777c478bd9Sstevel@tonic-gate 			error = 2;	/* error, no retry */
13787c478bd9Sstevel@tonic-gate 			break;
13797c478bd9Sstevel@tonic-gate 		}
13807c478bd9Sstevel@tonic-gate 
13817c478bd9Sstevel@tonic-gate 		/*
13827c478bd9Sstevel@tonic-gate 		 * we can use two cookies per descriptor (i.e buffer1 and
13837c478bd9Sstevel@tonic-gate 		 * buffer2) so we need at least (ncookies+1)/2 descriptors.
13847c478bd9Sstevel@tonic-gate 		 */
13857c478bd9Sstevel@tonic-gate 		if (((ncookies + 1) >> 1) > dnetp->free_desc) {
13867c478bd9Sstevel@tonic-gate 			(void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
13877c478bd9Sstevel@tonic-gate 			error = 1;
13887c478bd9Sstevel@tonic-gate 			break;
13897c478bd9Sstevel@tonic-gate 		}
13907c478bd9Sstevel@tonic-gate 
13917c478bd9Sstevel@tonic-gate 		/* setup the descriptors for this data buffer */
13927c478bd9Sstevel@tonic-gate 		while (ncookies) {
13937c478bd9Sstevel@tonic-gate 			end_index = index;
13947c478bd9Sstevel@tonic-gate 			if (bufn % 2) {
139517de24c9Svb 				ring[index].buffer2 =
139617de24c9Svb 				    (uint32_t)dma_cookie.dmac_address;
139717de24c9Svb 				ring[index].desc1.buffer_size2 =
139817de24c9Svb 				    dma_cookie.dmac_size;
139917de24c9Svb 				index = NextTXIndex(index); /* goto next desc */
14007c478bd9Sstevel@tonic-gate 			} else {
140117de24c9Svb 				/* initialize the descriptor */
140217de24c9Svb 				ASSERT(ring[index].desc0.own == 0);
140317de24c9Svb 				*(uint32_t *)&ring[index].desc0 = 0;
140417de24c9Svb 				*(uint32_t *)&ring[index].desc1 &=
140517de24c9Svb 				    DNET_END_OF_RING;
140617de24c9Svb 				ring[index].buffer1 =
140717de24c9Svb 				    (uint32_t)dma_cookie.dmac_address;
140817de24c9Svb 				ring[index].desc1.buffer_size1 =
140917de24c9Svb 				    dma_cookie.dmac_size;
141017de24c9Svb 				ring[index].buffer2 = (uint32_t)(0);
141117de24c9Svb 				dnetp->free_desc--;
141217de24c9Svb 				ASSERT(dnetp->free_desc >= 0);
14137c478bd9Sstevel@tonic-gate 			}
14147c478bd9Sstevel@tonic-gate 			totlen += dma_cookie.dmac_size;
14157c478bd9Sstevel@tonic-gate 			bufn++;
14167c478bd9Sstevel@tonic-gate 			if (--ncookies)
141717de24c9Svb 				ddi_dma_nextcookie(dnetp->dma_handle_tx,
141817de24c9Svb 				    &dma_cookie);
14197c478bd9Sstevel@tonic-gate 		}
14207c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
14217c478bd9Sstevel@tonic-gate 		bp = bp->b_cont;
14227c478bd9Sstevel@tonic-gate 	}
14237c478bd9Sstevel@tonic-gate 
14247c478bd9Sstevel@tonic-gate 	if (error == 1) {
14257c478bd9Sstevel@tonic-gate 		dnetp->stat_defer++;
14267c478bd9Sstevel@tonic-gate 		dnetp->free_desc = avail;
142798e8d175SSteven Stallion 		dnetp->need_tx_update = B_TRUE;
142898e8d175SSteven Stallion 		return (B_FALSE);
14297c478bd9Sstevel@tonic-gate 	} else if (error) {
14307c478bd9Sstevel@tonic-gate 		dnetp->free_desc = avail;
14317c478bd9Sstevel@tonic-gate 		freemsg(mp);
143298e8d175SSteven Stallion 		return (B_TRUE);	/* Drop packet, don't retry */
14337c478bd9Sstevel@tonic-gate 	}
14347c478bd9Sstevel@tonic-gate 
143598e8d175SSteven Stallion 	if (totlen > ETHERMAX + VLAN_TAGSZ) {
14367c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "DNET: tried to send large %d packet", totlen);
14377c478bd9Sstevel@tonic-gate 		dnetp->free_desc = avail;
14387c478bd9Sstevel@tonic-gate 		freemsg(mp);
143998e8d175SSteven Stallion 		return (B_TRUE);	/* Don't repeat this attempt */
14407c478bd9Sstevel@tonic-gate 	}
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	/*
14437c478bd9Sstevel@tonic-gate 	 * Remeber the message buffer pointer to do freemsg() at xmit
14447c478bd9Sstevel@tonic-gate 	 * interrupt time.
14457c478bd9Sstevel@tonic-gate 	 */
14467c478bd9Sstevel@tonic-gate 	dnetp->tx_msgbufp[end_index] = mp;
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 	/*
14497c478bd9Sstevel@tonic-gate 	 * Now set the first/last buffer and own bits
14507c478bd9Sstevel@tonic-gate 	 * Since the 21040 looks for these bits set in the
14517c478bd9Sstevel@tonic-gate 	 * first buffer, work backwards in multiple buffers.
14527c478bd9Sstevel@tonic-gate 	 */
14537c478bd9Sstevel@tonic-gate 	ring[end_index].desc1.last_desc = 1;
14547c478bd9Sstevel@tonic-gate 	ring[end_index].desc1.int_on_comp = 1;
14557c478bd9Sstevel@tonic-gate 	for (index = end_index; index != start_index;
14567c478bd9Sstevel@tonic-gate 	    index = PrevTXIndex(index))
14577c478bd9Sstevel@tonic-gate 		ring[index].desc0.own = 1;
14587c478bd9Sstevel@tonic-gate 	ring[start_index].desc1.first_desc = 1;
14597c478bd9Sstevel@tonic-gate 	ring[start_index].desc0.own = 1;
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	dnetp->tx_current_desc = NextTXIndex(end_index);
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	/*
14647c478bd9Sstevel@tonic-gate 	 * Safety check: make sure end-of-ring is set in last desc.
14657c478bd9Sstevel@tonic-gate 	 */
14667c478bd9Sstevel@tonic-gate 	ASSERT(ring[dnetp->max_tx_desc-1].desc1.end_of_ring != 0);
14677c478bd9Sstevel@tonic-gate 
146898e8d175SSteven Stallion 	return (B_TRUE);
14697c478bd9Sstevel@tonic-gate }
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate /*
147298e8d175SSteven Stallion  *	dnet_intr() -- interrupt from board to inform us that a receive or
14737c478bd9Sstevel@tonic-gate  *	transmit has completed.
14747c478bd9Sstevel@tonic-gate  */
14757c478bd9Sstevel@tonic-gate static uint_t
dnet_intr(caddr_t arg)147698e8d175SSteven Stallion dnet_intr(caddr_t arg)
14777c478bd9Sstevel@tonic-gate {
147898e8d175SSteven Stallion 	struct dnetinstance *dnetp = (struct dnetinstance *)arg;
147998e8d175SSteven Stallion 	uint32_t int_status;
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate 	mutex_enter(&dnetp->intrlock);
148298e8d175SSteven Stallion 
14838ef10d20Sgd 	if (dnetp->suspended) {
14848ef10d20Sgd 		mutex_exit(&dnetp->intrlock);
14858ef10d20Sgd 		return (DDI_INTR_UNCLAIMED);
14868ef10d20Sgd 	}
14878ef10d20Sgd 
14884ab75253Smrj 	int_status = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg,
148917de24c9Svb 	    STATUS_REG));
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 	/*
14927c478bd9Sstevel@tonic-gate 	 * If interrupt was not from this board
14937c478bd9Sstevel@tonic-gate 	 */
14947c478bd9Sstevel@tonic-gate 	if (!(int_status & (NORMAL_INTR_SUMM | ABNORMAL_INTR_SUMM))) {
14957c478bd9Sstevel@tonic-gate 		mutex_exit(&dnetp->intrlock);
14967c478bd9Sstevel@tonic-gate 		return (DDI_INTR_UNCLAIMED);
14977c478bd9Sstevel@tonic-gate 	}
14987c478bd9Sstevel@tonic-gate 
14997c478bd9Sstevel@tonic-gate 	dnetp->stat_intr++;
15007c478bd9Sstevel@tonic-gate 
15017c478bd9Sstevel@tonic-gate 	if (int_status & GPTIMER_INTR) {
15024ab75253Smrj 		ddi_put32(dnetp->io_handle,
150317de24c9Svb 		    REG32(dnetp->io_reg, STATUS_REG), GPTIMER_INTR);
15047c478bd9Sstevel@tonic-gate 		if (dnetp->timer.cb)
15057c478bd9Sstevel@tonic-gate 			dnetp->timer.cb(dnetp);
15067c478bd9Sstevel@tonic-gate 		else
15077c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "dnet: unhandled timer interrupt");
15087c478bd9Sstevel@tonic-gate 	}
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 	if (int_status & TX_INTR) {
15114ab75253Smrj 		ddi_put32(dnetp->io_handle,
151217de24c9Svb 		    REG32(dnetp->io_reg, STATUS_REG), TX_INTR);
15137c478bd9Sstevel@tonic-gate 		mutex_enter(&dnetp->txlock);
151498e8d175SSteven Stallion 		if (dnetp->need_tx_update) {
15157c478bd9Sstevel@tonic-gate 			mutex_exit(&dnetp->txlock);
15167c478bd9Sstevel@tonic-gate 			mutex_exit(&dnetp->intrlock);
151798e8d175SSteven Stallion 			mac_tx_update(dnetp->mac_handle);
15187c478bd9Sstevel@tonic-gate 			mutex_enter(&dnetp->intrlock);
15197c478bd9Sstevel@tonic-gate 			mutex_enter(&dnetp->txlock);
152098e8d175SSteven Stallion 			dnetp->need_tx_update = B_FALSE;
15217c478bd9Sstevel@tonic-gate 		}
15227c478bd9Sstevel@tonic-gate 		/* reclaim any xmit descriptors that are completed */
152398e8d175SSteven Stallion 		dnet_reclaim_Tx_desc(dnetp);
15247c478bd9Sstevel@tonic-gate 		mutex_exit(&dnetp->txlock);
15257c478bd9Sstevel@tonic-gate 	}
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 	/*
15287c478bd9Sstevel@tonic-gate 	 * Check if receive interrupt bit is set
15297c478bd9Sstevel@tonic-gate 	 */
153017de24c9Svb 	if (int_status & (RX_INTR | RX_UNAVAIL_INTR)) {
15314ab75253Smrj 		ddi_put32(dnetp->io_handle,
153217de24c9Svb 		    REG32(dnetp->io_reg, STATUS_REG),
153317de24c9Svb 		    int_status & (RX_INTR | RX_UNAVAIL_INTR));
153498e8d175SSteven Stallion 		dnet_getp(dnetp);
15357c478bd9Sstevel@tonic-gate 	}
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate 	if (int_status & ABNORMAL_INTR_SUMM) {
15387c478bd9Sstevel@tonic-gate 		/*
15397c478bd9Sstevel@tonic-gate 		 * Check for system error
15407c478bd9Sstevel@tonic-gate 		 */
15417c478bd9Sstevel@tonic-gate 		if (int_status & SYS_ERR) {
15427c478bd9Sstevel@tonic-gate 			if ((int_status & SYS_ERR_BITS) == MASTER_ABORT)
15437c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "DNET: Bus Master Abort");
15447c478bd9Sstevel@tonic-gate 			if ((int_status & SYS_ERR_BITS) == TARGET_ABORT)
15457c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "DNET: Bus Target Abort");
15467c478bd9Sstevel@tonic-gate 			if ((int_status & SYS_ERR_BITS) == PARITY_ERROR)
15477c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "DNET: Parity error");
15487c478bd9Sstevel@tonic-gate 		}
15497c478bd9Sstevel@tonic-gate 
15507c478bd9Sstevel@tonic-gate 		/*
15517c478bd9Sstevel@tonic-gate 		 * If the jabber has timed out then reset the chip
15527c478bd9Sstevel@tonic-gate 		 */
15537c478bd9Sstevel@tonic-gate 		if (int_status & TX_JABBER_TIMEOUT)
15547c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "DNET: Jabber timeout.");
15557c478bd9Sstevel@tonic-gate 
15567c478bd9Sstevel@tonic-gate 		/*
15577c478bd9Sstevel@tonic-gate 		 * If an underflow has occurred, reset the chip
15587c478bd9Sstevel@tonic-gate 		 */
15597c478bd9Sstevel@tonic-gate 		if (int_status & TX_UNDERFLOW)
15607c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "DNET: Tx Underflow.");
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
15637c478bd9Sstevel@tonic-gate 		if (dnetdebug & DNETINT)
15647c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "Trying to reset...");
15657c478bd9Sstevel@tonic-gate #endif
156698e8d175SSteven Stallion 		dnet_reset_board(dnetp);
156798e8d175SSteven Stallion 		dnet_init_board(dnetp);
15687c478bd9Sstevel@tonic-gate 		/* XXX function return value ignored */
156998e8d175SSteven Stallion 		(void) dnet_start(dnetp);
15707c478bd9Sstevel@tonic-gate 	}
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate 	/*
157398e8d175SSteven Stallion 	 * Enable the interrupts. Enable xmit interrupt in case we are
15747c478bd9Sstevel@tonic-gate 	 * running out of free descriptors or if there are packets
15757c478bd9Sstevel@tonic-gate 	 * in the queue waiting to be transmitted.
15767c478bd9Sstevel@tonic-gate 	 */
157798e8d175SSteven Stallion 	enable_interrupts(dnetp);
15787c478bd9Sstevel@tonic-gate 	mutex_exit(&dnetp->intrlock);
15797c478bd9Sstevel@tonic-gate 	return (DDI_INTR_CLAIMED);	/* Indicate it was our interrupt */
15807c478bd9Sstevel@tonic-gate }
15817c478bd9Sstevel@tonic-gate 
15827c478bd9Sstevel@tonic-gate static void
dnet_getp(struct dnetinstance * dnetp)158398e8d175SSteven Stallion dnet_getp(struct dnetinstance *dnetp)
15847c478bd9Sstevel@tonic-gate {
15857c478bd9Sstevel@tonic-gate 	int packet_length, index;
15867c478bd9Sstevel@tonic-gate 	mblk_t	*mp;
1587*f879aa94SToomas Soome 	caddr_t	virtual_address;
15887c478bd9Sstevel@tonic-gate 	struct	rx_desc_type *desc = dnetp->rx_desc;
15897c478bd9Sstevel@tonic-gate 	int marker = dnetp->rx_current_desc;
15907c478bd9Sstevel@tonic-gate 	int misses;
15917c478bd9Sstevel@tonic-gate 
15927c478bd9Sstevel@tonic-gate 	if (!dnetp->overrun_workaround) {
15937c478bd9Sstevel@tonic-gate 		/*
15947c478bd9Sstevel@tonic-gate 		 * If the workaround is not in place, we must still update
15957c478bd9Sstevel@tonic-gate 		 * the missed frame statistic from the on-chip counter.
15967c478bd9Sstevel@tonic-gate 		 */
15974ab75253Smrj 		misses = ddi_get32(dnetp->io_handle,
15987c478bd9Sstevel@tonic-gate 		    REG32(dnetp->io_reg, MISSED_FRAME_REG));
15997c478bd9Sstevel@tonic-gate 		dnetp->stat_missed += (misses & MISSED_FRAME_MASK);
16007c478bd9Sstevel@tonic-gate 	}
16017c478bd9Sstevel@tonic-gate 
16027c478bd9Sstevel@tonic-gate 	/* While host owns the current descriptor */
16037c478bd9Sstevel@tonic-gate 	while (!(desc[dnetp->rx_current_desc].desc0.own)) {
16047c478bd9Sstevel@tonic-gate 		struct free_ptr *frp;
16057c478bd9Sstevel@tonic-gate 		caddr_t newbuf;
16067c478bd9Sstevel@tonic-gate 		struct rbuf_list *rp;
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 		index = dnetp->rx_current_desc;
16097c478bd9Sstevel@tonic-gate 		ASSERT(desc[index].desc0.first_desc != 0);
16107c478bd9Sstevel@tonic-gate 
16117c478bd9Sstevel@tonic-gate 		/*
16127c478bd9Sstevel@tonic-gate 		 * DMA overrun errata from DEC: avoid possible bus hangs
16137c478bd9Sstevel@tonic-gate 		 * and data corruption
16147c478bd9Sstevel@tonic-gate 		 */
16157c478bd9Sstevel@tonic-gate 		if (dnetp->overrun_workaround &&
16167c478bd9Sstevel@tonic-gate 		    marker == dnetp->rx_current_desc) {
16177c478bd9Sstevel@tonic-gate 			int opn;
16187c478bd9Sstevel@tonic-gate 			do {
16197c478bd9Sstevel@tonic-gate 				marker = (marker+1) % dnetp->max_rx_desc;
16207c478bd9Sstevel@tonic-gate 			} while (!(dnetp->rx_desc[marker].desc0.own) &&
16217c478bd9Sstevel@tonic-gate 			    marker != index);
16227c478bd9Sstevel@tonic-gate 
16234ab75253Smrj 			misses = ddi_get32(dnetp->io_handle,
16247c478bd9Sstevel@tonic-gate 			    REG32(dnetp->io_reg, MISSED_FRAME_REG));
16257c478bd9Sstevel@tonic-gate 			dnetp->stat_missed +=
16267c478bd9Sstevel@tonic-gate 			    (misses & MISSED_FRAME_MASK);
16277c478bd9Sstevel@tonic-gate 			if (misses & OVERFLOW_COUNTER_MASK) {
16287c478bd9Sstevel@tonic-gate 				/*
16297c478bd9Sstevel@tonic-gate 				 * Overflow(s) have occurred : stop receiver,
16307c478bd9Sstevel@tonic-gate 				 * and wait until in stopped state
16317c478bd9Sstevel@tonic-gate 				 */
16324ab75253Smrj 				opn = ddi_get32(dnetp->io_handle,
16337c478bd9Sstevel@tonic-gate 				    REG32(dnetp->io_reg, OPN_MODE_REG));
16344ab75253Smrj 				ddi_put32(dnetp->io_handle,
16357c478bd9Sstevel@tonic-gate 				    REG32(dnetp->io_reg, OPN_MODE_REG),
16367c478bd9Sstevel@tonic-gate 				    opn & ~(START_RECEIVE));
16377c478bd9Sstevel@tonic-gate 
16387c478bd9Sstevel@tonic-gate 				do {
16397c478bd9Sstevel@tonic-gate 					drv_usecwait(10);
16404ab75253Smrj 				} while ((ddi_get32(dnetp->io_handle,
16417c478bd9Sstevel@tonic-gate 				    REG32(dnetp->io_reg, STATUS_REG)) &
16427c478bd9Sstevel@tonic-gate 				    RECEIVE_PROCESS_STATE) != 0);
16437c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
16447c478bd9Sstevel@tonic-gate 				if (dnetdebug & DNETRECV)
16457c478bd9Sstevel@tonic-gate 					cmn_err(CE_CONT, "^*");
16467c478bd9Sstevel@tonic-gate #endif
16477c478bd9Sstevel@tonic-gate 				/* Discard probably corrupt frames */
16487c478bd9Sstevel@tonic-gate 				while (!(dnetp->rx_desc[index].desc0.own)) {
16497c478bd9Sstevel@tonic-gate 					dnetp->rx_desc[index].desc0.own = 1;
16507c478bd9Sstevel@tonic-gate 					index = (index+1) % dnetp->max_rx_desc;
16517c478bd9Sstevel@tonic-gate 					dnetp->stat_missed++;
16527c478bd9Sstevel@tonic-gate 				}
16537c478bd9Sstevel@tonic-gate 
16547c478bd9Sstevel@tonic-gate 				/* restart the receiver */
16554ab75253Smrj 				opn = ddi_get32(dnetp->io_handle,
16567c478bd9Sstevel@tonic-gate 				    REG32(dnetp->io_reg, OPN_MODE_REG));
16574ab75253Smrj 				ddi_put32(dnetp->io_handle,
16587c478bd9Sstevel@tonic-gate 				    REG32(dnetp->io_reg, OPN_MODE_REG),
16597c478bd9Sstevel@tonic-gate 				    opn | START_RECEIVE);
16607c478bd9Sstevel@tonic-gate 				marker = dnetp->rx_current_desc = index;
16617c478bd9Sstevel@tonic-gate 				continue;
16627c478bd9Sstevel@tonic-gate 			}
16637c478bd9Sstevel@tonic-gate 			/*
16647c478bd9Sstevel@tonic-gate 			 * At this point, we know that all packets before
16657c478bd9Sstevel@tonic-gate 			 * "marker" were received before a dma overrun occurred
16667c478bd9Sstevel@tonic-gate 			 */
16677c478bd9Sstevel@tonic-gate 		}
16687c478bd9Sstevel@tonic-gate 
16697c478bd9Sstevel@tonic-gate 		/*
16707c478bd9Sstevel@tonic-gate 		 * If we get an oversized packet it could span multiple
16717c478bd9Sstevel@tonic-gate 		 * descriptors.  If this happens an error bit should be set.
16727c478bd9Sstevel@tonic-gate 		 */
16737c478bd9Sstevel@tonic-gate 		while (desc[index].desc0.last_desc == 0) {
16747c478bd9Sstevel@tonic-gate 			index = (index + 1) % dnetp->max_rx_desc;
16757c478bd9Sstevel@tonic-gate 			if (desc[index].desc0.own)
16767c478bd9Sstevel@tonic-gate 				return;	/* not done receiving large packet */
16777c478bd9Sstevel@tonic-gate 		}
16787c478bd9Sstevel@tonic-gate 		while (dnetp->rx_current_desc != index) {
16797c478bd9Sstevel@tonic-gate 			desc[dnetp->rx_current_desc].desc0.own = 1;
16807c478bd9Sstevel@tonic-gate 			dnetp->rx_current_desc =
16817c478bd9Sstevel@tonic-gate 			    (dnetp->rx_current_desc + 1) % dnetp->max_rx_desc;
16827c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
16837c478bd9Sstevel@tonic-gate 			if (dnetdebug & DNETRECV)
16847c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN, "dnet: received large packet");
16857c478bd9Sstevel@tonic-gate #endif
16867c478bd9Sstevel@tonic-gate 		}
16877c478bd9Sstevel@tonic-gate 
16887c478bd9Sstevel@tonic-gate 		packet_length = desc[index].desc0.frame_len;
16897c478bd9Sstevel@tonic-gate 
16907c478bd9Sstevel@tonic-gate 		/*
16917c478bd9Sstevel@tonic-gate 		 * Remove CRC from received data. This is an artefact of the
16927c478bd9Sstevel@tonic-gate 		 * 21x4x chip and should not be passed higher up the network
16937c478bd9Sstevel@tonic-gate 		 * stack.
16947c478bd9Sstevel@tonic-gate 		 */
16957c478bd9Sstevel@tonic-gate 		packet_length -= ETHERFCSL;
16967c478bd9Sstevel@tonic-gate 
16977c478bd9Sstevel@tonic-gate 		/* get the virtual address of the packet received */
16987c478bd9Sstevel@tonic-gate 		virtual_address =
16997c478bd9Sstevel@tonic-gate 		    dnetp->rx_buf_vaddr[index];
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 		/*
17027c478bd9Sstevel@tonic-gate 		 * If no packet errors then do:
1703*f879aa94SToomas Soome 		 *	1. Allocate a new receive buffer so that we can
17047c478bd9Sstevel@tonic-gate 		 *	   use the current buffer as streams buffer to
17057c478bd9Sstevel@tonic-gate 		 *	   avoid bcopy.
17067c478bd9Sstevel@tonic-gate 		 *	2. If we got a new receive buffer then allocate
17077c478bd9Sstevel@tonic-gate 		 *	   an mblk using desballoc().
17087c478bd9Sstevel@tonic-gate 		 *	3. Otherwise use the mblk from allocb() and do
17097c478bd9Sstevel@tonic-gate 		 *	   the bcopy.
17107c478bd9Sstevel@tonic-gate 		 */
17117c478bd9Sstevel@tonic-gate 		frp = NULL;
17127c478bd9Sstevel@tonic-gate 		rp = NULL;
17137c478bd9Sstevel@tonic-gate 		newbuf = NULL;
17147c478bd9Sstevel@tonic-gate 		mp = NULL;
171598e8d175SSteven Stallion 		if (!desc[index].desc0.err_summary ||
171698e8d175SSteven Stallion 		    (desc[index].desc0.frame2long &&
171798e8d175SSteven Stallion 		    packet_length < rx_buf_size)) {
17187c478bd9Sstevel@tonic-gate 			ASSERT(packet_length < rx_buf_size);
17197c478bd9Sstevel@tonic-gate 			/*
17207c478bd9Sstevel@tonic-gate 			 * Allocate another receive buffer for this descriptor.
17217c478bd9Sstevel@tonic-gate 			 * If we fail to allocate then we do the normal bcopy.
17227c478bd9Sstevel@tonic-gate 			 */
17237c478bd9Sstevel@tonic-gate 			rp = dnet_rbuf_alloc(dnetp->devinfo, 0);
17247c478bd9Sstevel@tonic-gate 			if (rp != NULL) {
17257c478bd9Sstevel@tonic-gate 				newbuf = rp->rbuf_vaddr;
17267c478bd9Sstevel@tonic-gate 				frp = kmem_zalloc(sizeof (*frp), KM_NOSLEEP);
17277c478bd9Sstevel@tonic-gate 				if (frp != NULL) {
172817de24c9Svb 					frp->free_rtn.free_func =
172917de24c9Svb 					    dnet_freemsg_buf;
173017de24c9Svb 					frp->free_rtn.free_arg = (char *)frp;
173117de24c9Svb 					frp->buf = virtual_address;
173217de24c9Svb 					mp = desballoc(
173317de24c9Svb 					    (uchar_t *)virtual_address,
173417de24c9Svb 					    packet_length, 0, &frp->free_rtn);
173517de24c9Svb 					if (mp == NULL) {
173617de24c9Svb 						kmem_free(frp, sizeof (*frp));
173717de24c9Svb 						dnet_rbuf_free((caddr_t)newbuf);
173817de24c9Svb 						frp = NULL;
173917de24c9Svb 						newbuf = NULL;
174017de24c9Svb 					}
17417c478bd9Sstevel@tonic-gate 				}
17427c478bd9Sstevel@tonic-gate 			}
17437c478bd9Sstevel@tonic-gate 			if (mp == NULL) {
17447c478bd9Sstevel@tonic-gate 				if (newbuf != NULL)
17457c478bd9Sstevel@tonic-gate 					dnet_rbuf_free((caddr_t)newbuf);
17467c478bd9Sstevel@tonic-gate 				mp = allocb(packet_length, 0);
17477c478bd9Sstevel@tonic-gate 			}
17487c478bd9Sstevel@tonic-gate 		}
17497c478bd9Sstevel@tonic-gate 
175098e8d175SSteven Stallion 		if ((desc[index].desc0.err_summary &&
175198e8d175SSteven Stallion 		    packet_length >= rx_buf_size) || mp == NULL) {
17527c478bd9Sstevel@tonic-gate 
17537c478bd9Sstevel@tonic-gate 			/* Update gld statistics */
17547c478bd9Sstevel@tonic-gate 			if (desc[index].desc0.err_summary)
175598e8d175SSteven Stallion 				update_rx_stats(dnetp, index);
17567c478bd9Sstevel@tonic-gate 			else
17577c478bd9Sstevel@tonic-gate 				dnetp->stat_norcvbuf++;
17587c478bd9Sstevel@tonic-gate 
17597c478bd9Sstevel@tonic-gate 			/*
17607c478bd9Sstevel@tonic-gate 			 * Reset ownership of the descriptor.
17617c478bd9Sstevel@tonic-gate 			 */
17627c478bd9Sstevel@tonic-gate 			desc[index].desc0.own = 1;
17637c478bd9Sstevel@tonic-gate 			dnetp->rx_current_desc =
17647c478bd9Sstevel@tonic-gate 			    (dnetp->rx_current_desc+1) % dnetp->max_rx_desc;
17657c478bd9Sstevel@tonic-gate 
17667c478bd9Sstevel@tonic-gate 			/* Demand receive polling by the chip */
17674ab75253Smrj 			ddi_put32(dnetp->io_handle,
17687c478bd9Sstevel@tonic-gate 			    REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND);
17697c478bd9Sstevel@tonic-gate 
17707c478bd9Sstevel@tonic-gate 			continue;
17717c478bd9Sstevel@tonic-gate 		}
17727c478bd9Sstevel@tonic-gate 
17737c478bd9Sstevel@tonic-gate 		if (newbuf != NULL) {
17747c478bd9Sstevel@tonic-gate 			uint32_t end_paddr;
17757c478bd9Sstevel@tonic-gate 			/* attach the new buffer to the rx descriptor */
17767c478bd9Sstevel@tonic-gate 			dnetp->rx_buf_vaddr[index] = newbuf;
1777483028f5Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			dnetp->rx_buf_paddr[index] = rp->rbuf_paddr;
17788ef10d20Sgd 			desc[index].buffer1 = rp->rbuf_paddr;
17797c478bd9Sstevel@tonic-gate 			desc[index].desc1.buffer_size1 = rx_buf_size;
17807c478bd9Sstevel@tonic-gate 			desc[index].desc1.buffer_size2 = 0;
17818ef10d20Sgd 			end_paddr = rp->rbuf_endpaddr;
17827c478bd9Sstevel@tonic-gate 			if ((desc[index].buffer1 & ~dnetp->pgmask) !=
17837c478bd9Sstevel@tonic-gate 			    (end_paddr & ~dnetp->pgmask)) {
17847c478bd9Sstevel@tonic-gate 				/* discontiguous */
17857c478bd9Sstevel@tonic-gate 				desc[index].buffer2 = end_paddr&~dnetp->pgmask;
17867c478bd9Sstevel@tonic-gate 				desc[index].desc1.buffer_size2 =
17877c478bd9Sstevel@tonic-gate 				    (end_paddr & dnetp->pgmask) + 1;
17887c478bd9Sstevel@tonic-gate 				desc[index].desc1.buffer_size1 =
17897c478bd9Sstevel@tonic-gate 				    rx_buf_size-desc[index].desc1.buffer_size2;
17907c478bd9Sstevel@tonic-gate 			}
17917c478bd9Sstevel@tonic-gate 		} else {
179217de24c9Svb 			/* couldn't allocate another buffer; copy the data */
179317de24c9Svb 			BCOPY((caddr_t)virtual_address, (caddr_t)mp->b_wptr,
179417de24c9Svb 			    packet_length);
17957c478bd9Sstevel@tonic-gate 		}
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 		mp->b_wptr += packet_length;
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate 		desc[dnetp->rx_current_desc].desc0.own = 1;
18007c478bd9Sstevel@tonic-gate 
18017c478bd9Sstevel@tonic-gate 		/*
18027c478bd9Sstevel@tonic-gate 		 * Increment receive desc index. This is for the scan of
18037c478bd9Sstevel@tonic-gate 		 * next packet
18047c478bd9Sstevel@tonic-gate 		 */
18057c478bd9Sstevel@tonic-gate 		dnetp->rx_current_desc =
180617de24c9Svb 		    (dnetp->rx_current_desc+1) % dnetp->max_rx_desc;
18077c478bd9Sstevel@tonic-gate 
18087c478bd9Sstevel@tonic-gate 		/* Demand polling by chip */
18094ab75253Smrj 		ddi_put32(dnetp->io_handle,
181017de24c9Svb 		    REG32(dnetp->io_reg, RX_POLL_REG), RX_POLL_DEMAND);
18117c478bd9Sstevel@tonic-gate 
18127c478bd9Sstevel@tonic-gate 		/* send the packet upstream */
18137c478bd9Sstevel@tonic-gate 		mutex_exit(&dnetp->intrlock);
181498e8d175SSteven Stallion 		mac_rx(dnetp->mac_handle, NULL, mp);
18157c478bd9Sstevel@tonic-gate 		mutex_enter(&dnetp->intrlock);
18167c478bd9Sstevel@tonic-gate 	}
18177c478bd9Sstevel@tonic-gate }
18187c478bd9Sstevel@tonic-gate /*
18197c478bd9Sstevel@tonic-gate  * Function to update receive statistics
18207c478bd9Sstevel@tonic-gate  */
18217c478bd9Sstevel@tonic-gate static void
update_rx_stats(struct dnetinstance * dnetp,int index)182298e8d175SSteven Stallion update_rx_stats(struct dnetinstance *dnetp, int index)
18237c478bd9Sstevel@tonic-gate {
18247c478bd9Sstevel@tonic-gate 	struct rx_desc_type *descp = &(dnetp->rx_desc[index]);
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate 	/*
18277c478bd9Sstevel@tonic-gate 	 * Update gld statistics
18287c478bd9Sstevel@tonic-gate 	 */
18297c478bd9Sstevel@tonic-gate 	dnetp->stat_errrcv++;
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	if (descp->desc0.overflow)	{
18327c478bd9Sstevel@tonic-gate 		/* FIFO Overrun */
18337c478bd9Sstevel@tonic-gate 		dnetp->stat_overflow++;
18347c478bd9Sstevel@tonic-gate 	}
18357c478bd9Sstevel@tonic-gate 
18367c478bd9Sstevel@tonic-gate 	if (descp->desc0.collision) {
18377c478bd9Sstevel@tonic-gate 		/*EMPTY*/
18387c478bd9Sstevel@tonic-gate 		/* Late Colllision on receive */
18397c478bd9Sstevel@tonic-gate 		/* no appropriate counter */
18407c478bd9Sstevel@tonic-gate 	}
18417c478bd9Sstevel@tonic-gate 
18427c478bd9Sstevel@tonic-gate 	if (descp->desc0.crc) {
18437c478bd9Sstevel@tonic-gate 		/* CRC Error */
18447c478bd9Sstevel@tonic-gate 		dnetp->stat_crc++;
18457c478bd9Sstevel@tonic-gate 	}
18467c478bd9Sstevel@tonic-gate 
18477c478bd9Sstevel@tonic-gate 	if (descp->desc0.runt_frame) {
18487c478bd9Sstevel@tonic-gate 		/* Runt Error */
18497c478bd9Sstevel@tonic-gate 		dnetp->stat_short++;
18507c478bd9Sstevel@tonic-gate 	}
18517c478bd9Sstevel@tonic-gate 
18527c478bd9Sstevel@tonic-gate 	if (descp->desc0.desc_err) {
18537c478bd9Sstevel@tonic-gate 		/*EMPTY*/
18547c478bd9Sstevel@tonic-gate 		/* Not enough receive descriptors */
185598e8d175SSteven Stallion 		/* This condition is accounted in dnet_intr() */
18567c478bd9Sstevel@tonic-gate 	}
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate 	if (descp->desc0.frame2long) {
18597c478bd9Sstevel@tonic-gate 		dnetp->stat_frame++;
18607c478bd9Sstevel@tonic-gate 	}
18617c478bd9Sstevel@tonic-gate }
18627c478bd9Sstevel@tonic-gate 
18637c478bd9Sstevel@tonic-gate /*
18647c478bd9Sstevel@tonic-gate  * Function to update transmit statistics
18657c478bd9Sstevel@tonic-gate  */
18667c478bd9Sstevel@tonic-gate static void
update_tx_stats(struct dnetinstance * dnetp,int index)186798e8d175SSteven Stallion update_tx_stats(struct dnetinstance *dnetp, int index)
18687c478bd9Sstevel@tonic-gate {
18697c478bd9Sstevel@tonic-gate 	struct tx_desc_type *descp = &(dnetp->tx_desc[index]);
18707c478bd9Sstevel@tonic-gate 	int	fd;
18717c478bd9Sstevel@tonic-gate 	media_block_t	*block = dnetp->selected_media_block;
18727c478bd9Sstevel@tonic-gate 
18737c478bd9Sstevel@tonic-gate 
18747c478bd9Sstevel@tonic-gate 	/* Update gld statistics */
18757c478bd9Sstevel@tonic-gate 	dnetp->stat_errxmt++;
18767c478bd9Sstevel@tonic-gate 
18777c478bd9Sstevel@tonic-gate 	/* If we're in full-duplex don't count collisions or carrier loss. */
18787c478bd9Sstevel@tonic-gate 	if (dnetp->mii_up) {
18797c478bd9Sstevel@tonic-gate 		fd = dnetp->mii_duplex;
18807c478bd9Sstevel@tonic-gate 	} else {
18817c478bd9Sstevel@tonic-gate 		/* Rely on media code */
188217de24c9Svb 		fd = block->media_code == MEDIA_TP_FD ||
188317de24c9Svb 		    block->media_code == MEDIA_SYM_SCR_FD;
18847c478bd9Sstevel@tonic-gate 	}
18857c478bd9Sstevel@tonic-gate 
18867c478bd9Sstevel@tonic-gate 	if (descp->desc0.collision_count && !fd) {
188717de24c9Svb 		dnetp->stat_collisions += descp->desc0.collision_count;
18887c478bd9Sstevel@tonic-gate 	}
18897c478bd9Sstevel@tonic-gate 
18907c478bd9Sstevel@tonic-gate 	if (descp->desc0.late_collision && !fd) {
18917c478bd9Sstevel@tonic-gate 		dnetp->stat_xmtlatecoll++;
18927c478bd9Sstevel@tonic-gate 	}
18937c478bd9Sstevel@tonic-gate 
18947c478bd9Sstevel@tonic-gate 	if (descp->desc0.excess_collision && !fd) {
18957c478bd9Sstevel@tonic-gate 		dnetp->stat_excoll++;
18967c478bd9Sstevel@tonic-gate 	}
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 	if (descp->desc0.underflow) {
18997c478bd9Sstevel@tonic-gate 		dnetp->stat_underflow++;
19007c478bd9Sstevel@tonic-gate 	}
19017c478bd9Sstevel@tonic-gate 
19027c478bd9Sstevel@tonic-gate #if 0
19037c478bd9Sstevel@tonic-gate 	if (descp->desc0.tx_jabber_to) {
19047c478bd9Sstevel@tonic-gate 		/* no appropriate counter */
19057c478bd9Sstevel@tonic-gate 	}
19067c478bd9Sstevel@tonic-gate #endif
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 	if (descp->desc0.carrier_loss && !fd) {
19097c478bd9Sstevel@tonic-gate 		dnetp->stat_nocarrier++;
19107c478bd9Sstevel@tonic-gate 	}
19117c478bd9Sstevel@tonic-gate 
19127c478bd9Sstevel@tonic-gate 	if (descp->desc0.no_carrier && !fd) {
19137c478bd9Sstevel@tonic-gate 		dnetp->stat_nocarrier++;
19147c478bd9Sstevel@tonic-gate 	}
19157c478bd9Sstevel@tonic-gate }
19167c478bd9Sstevel@tonic-gate 
19177c478bd9Sstevel@tonic-gate /*
19187c478bd9Sstevel@tonic-gate  *	========== Media Selection Setup Routines ==========
19197c478bd9Sstevel@tonic-gate  */
19207c478bd9Sstevel@tonic-gate 
19217c478bd9Sstevel@tonic-gate 
19227c478bd9Sstevel@tonic-gate static void
write_gpr(struct dnetinstance * dnetp,uint32_t val)19237c478bd9Sstevel@tonic-gate write_gpr(struct dnetinstance *dnetp, uint32_t val)
19247c478bd9Sstevel@tonic-gate {
19257c478bd9Sstevel@tonic-gate #ifdef DEBUG
19267c478bd9Sstevel@tonic-gate 	if (dnetdebug & DNETREGCFG)
19277c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "GPR: %x", val);
19287c478bd9Sstevel@tonic-gate #endif
19297c478bd9Sstevel@tonic-gate 	switch (dnetp->board_type) {
19307c478bd9Sstevel@tonic-gate 	case DEVICE_ID_21143:
19317c478bd9Sstevel@tonic-gate 		/* Set the correct bit for a control write */
19327c478bd9Sstevel@tonic-gate 		if (val & GPR_CONTROL_WRITE)
19337c478bd9Sstevel@tonic-gate 			val |= CWE_21143, val &= ~GPR_CONTROL_WRITE;
19347c478bd9Sstevel@tonic-gate 		/* Write to upper half of CSR15 */
19357c478bd9Sstevel@tonic-gate 		dnetp->gprsia = (dnetp->gprsia & 0xffff) | (val << 16);
19364ab75253Smrj 		ddi_put32(dnetp->io_handle,
193717de24c9Svb 		    REG32(dnetp->io_reg, SIA_GENERAL_REG), dnetp->gprsia);
19387c478bd9Sstevel@tonic-gate 		break;
19397c478bd9Sstevel@tonic-gate 	default:
19407c478bd9Sstevel@tonic-gate 		/* Set the correct bit for a control write */
19417c478bd9Sstevel@tonic-gate 		if (val & GPR_CONTROL_WRITE)
19427c478bd9Sstevel@tonic-gate 			val |= CWE_21140, val &= ~GPR_CONTROL_WRITE;
194317de24c9Svb 		ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_REG), val);
19447c478bd9Sstevel@tonic-gate 		break;
19457c478bd9Sstevel@tonic-gate 	}
19467c478bd9Sstevel@tonic-gate }
19477c478bd9Sstevel@tonic-gate 
19487c478bd9Sstevel@tonic-gate static uint32_t
read_gpr(struct dnetinstance * dnetp)19497c478bd9Sstevel@tonic-gate read_gpr(struct dnetinstance *dnetp)
19507c478bd9Sstevel@tonic-gate {
19517c478bd9Sstevel@tonic-gate 	switch (dnetp->board_type) {
19527c478bd9Sstevel@tonic-gate 	case DEVICE_ID_21143:
19537c478bd9Sstevel@tonic-gate 		/* Read upper half of CSR15 */
19544ab75253Smrj 		return (ddi_get32(dnetp->io_handle,
195517de24c9Svb 		    REG32(dnetp->io_reg, SIA_GENERAL_REG)) >> 16);
19567c478bd9Sstevel@tonic-gate 	default:
19574ab75253Smrj 		return (ddi_get32(dnetp->io_handle,
195817de24c9Svb 		    REG32(dnetp->io_reg, GP_REG)));
19597c478bd9Sstevel@tonic-gate 	}
19607c478bd9Sstevel@tonic-gate }
19617c478bd9Sstevel@tonic-gate 
19627c478bd9Sstevel@tonic-gate static void
set_gpr(struct dnetinstance * dnetp)196398e8d175SSteven Stallion set_gpr(struct dnetinstance *dnetp)
19647c478bd9Sstevel@tonic-gate {
19657c478bd9Sstevel@tonic-gate 	uint32_t *sequence;
19667c478bd9Sstevel@tonic-gate 	int len;
19677c478bd9Sstevel@tonic-gate 	LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf];
19687c478bd9Sstevel@tonic-gate 	media_block_t *block = dnetp->selected_media_block;
19697c478bd9Sstevel@tonic-gate 	int i;
19707c478bd9Sstevel@tonic-gate 
19717c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, dnetp->devinfo,
19727c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "gpr-sequence", (caddr_t)&sequence,
19737c478bd9Sstevel@tonic-gate 	    &len) == DDI_PROP_SUCCESS) {
19747c478bd9Sstevel@tonic-gate 		for (i = 0; i < len / sizeof (uint32_t); i++)
19757c478bd9Sstevel@tonic-gate 			write_gpr(dnetp, sequence[i]);
19767c478bd9Sstevel@tonic-gate 		kmem_free(sequence, len);
1977a8320b74Smeem 	} else {
19787c478bd9Sstevel@tonic-gate 		/*
19797c478bd9Sstevel@tonic-gate 		 * Write the reset sequence if this is the first time this
19807c478bd9Sstevel@tonic-gate 		 * block has been selected.
19817c478bd9Sstevel@tonic-gate 		 */
19827c478bd9Sstevel@tonic-gate 		if (block->rstseqlen) {
19837c478bd9Sstevel@tonic-gate 			for (i = 0; i < block->rstseqlen; i++)
19847c478bd9Sstevel@tonic-gate 				write_gpr(dnetp, block->rstseq[i]);
19857c478bd9Sstevel@tonic-gate 			/*
19867c478bd9Sstevel@tonic-gate 			 * XXX Legacy blocks do not have reset sequences, so the
19877c478bd9Sstevel@tonic-gate 			 * static blocks will never be modified by this
19887c478bd9Sstevel@tonic-gate 			 */
19897c478bd9Sstevel@tonic-gate 			block->rstseqlen = 0;
19907c478bd9Sstevel@tonic-gate 		}
19917c478bd9Sstevel@tonic-gate 		if (leaf->gpr)
19927c478bd9Sstevel@tonic-gate 			write_gpr(dnetp, leaf->gpr | GPR_CONTROL_WRITE);
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate 		/* write GPR sequence each time */
19957c478bd9Sstevel@tonic-gate 		for (i = 0; i < block->gprseqlen; i++)
19967c478bd9Sstevel@tonic-gate 			write_gpr(dnetp, block->gprseq[i]);
19977c478bd9Sstevel@tonic-gate 	}
19987c478bd9Sstevel@tonic-gate 
19997c478bd9Sstevel@tonic-gate 	/* This has possibly caused a PHY to reset.  Let MII know */
20007c478bd9Sstevel@tonic-gate 	if (dnetp->phyaddr != -1)
20017c478bd9Sstevel@tonic-gate 		/* XXX function return value ignored */
20027c478bd9Sstevel@tonic-gate 		(void) mii_sync(dnetp->mii, dnetp->phyaddr);
20037c478bd9Sstevel@tonic-gate 	drv_usecwait(5);
20047c478bd9Sstevel@tonic-gate }
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate /* set_opr() - must be called with intrlock held */
20077c478bd9Sstevel@tonic-gate 
20087c478bd9Sstevel@tonic-gate static void
set_opr(struct dnetinstance * dnetp)200998e8d175SSteven Stallion set_opr(struct dnetinstance *dnetp)
20107c478bd9Sstevel@tonic-gate {
20117c478bd9Sstevel@tonic-gate 	uint32_t fd, mb1, sf;
20127c478bd9Sstevel@tonic-gate 
2013*f879aa94SToomas Soome 	int		opnmode_len;
20147c478bd9Sstevel@tonic-gate 	uint32_t val;
20157c478bd9Sstevel@tonic-gate 	media_block_t *block = dnetp->selected_media_block;
20167c478bd9Sstevel@tonic-gate 
20177c478bd9Sstevel@tonic-gate 	ASSERT(block);
20187c478bd9Sstevel@tonic-gate 
20197c478bd9Sstevel@tonic-gate 	/* Check for custom "opnmode_reg" property */
20207c478bd9Sstevel@tonic-gate 	opnmode_len = sizeof (val);
20217c478bd9Sstevel@tonic-gate 	if (ddi_prop_op(DDI_DEV_T_ANY, dnetp->devinfo,
20227c478bd9Sstevel@tonic-gate 	    PROP_LEN_AND_VAL_BUF, DDI_PROP_DONTPASS, "opnmode_reg",
20237c478bd9Sstevel@tonic-gate 	    (caddr_t)&val, &opnmode_len) != DDI_PROP_SUCCESS)
20247c478bd9Sstevel@tonic-gate 		opnmode_len = 0;
20257c478bd9Sstevel@tonic-gate 
20267c478bd9Sstevel@tonic-gate 	/* Some bits exist only on 21140 and greater */
20277c478bd9Sstevel@tonic-gate 	if (dnetp->board_type != DEVICE_ID_21040 &&
20287c478bd9Sstevel@tonic-gate 	    dnetp->board_type != DEVICE_ID_21041) {
20297c478bd9Sstevel@tonic-gate 		mb1 = OPN_REG_MB1;
20307c478bd9Sstevel@tonic-gate 		sf = STORE_AND_FORWARD;
20317c478bd9Sstevel@tonic-gate 	} else {
20327c478bd9Sstevel@tonic-gate 		mb1 = sf = 0;
20337c478bd9Sstevel@tonic-gate 		mb1 = OPN_REG_MB1; /* Needed for 21040? */
20347c478bd9Sstevel@tonic-gate 	}
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate 	if (opnmode_len) {
20374ab75253Smrj 		ddi_put32(dnetp->io_handle,
203817de24c9Svb 		    REG32(dnetp->io_reg, OPN_MODE_REG), val);
203998e8d175SSteven Stallion 		dnet_reset_board(dnetp);
20404ab75253Smrj 		ddi_put32(dnetp->io_handle,
204117de24c9Svb 		    REG32(dnetp->io_reg, OPN_MODE_REG), val);
20427c478bd9Sstevel@tonic-gate 		return;
20437c478bd9Sstevel@tonic-gate 	}
20447c478bd9Sstevel@tonic-gate 
20457c478bd9Sstevel@tonic-gate 	/*
20467c478bd9Sstevel@tonic-gate 	 * Set each bit in CSR6 that we want
20477c478bd9Sstevel@tonic-gate 	 */
20487c478bd9Sstevel@tonic-gate 
20497c478bd9Sstevel@tonic-gate 	/* Always want these bits set */
20507c478bd9Sstevel@tonic-gate 	val = HASH_FILTERING | HASH_ONLY | TX_THRESHOLD_160 | mb1 | sf;
20517c478bd9Sstevel@tonic-gate 
20527c478bd9Sstevel@tonic-gate 	/* Promiscuous mode */
20537c478bd9Sstevel@tonic-gate 	val |= dnetp->promisc ? PROM_MODE : 0;
20547c478bd9Sstevel@tonic-gate 
20557c478bd9Sstevel@tonic-gate 	/* Scrambler for SYM style media */
20567c478bd9Sstevel@tonic-gate 	val |= ((block->command & CMD_SCR) && !dnetp->disable_scrambler) ?
205717de24c9Svb 	    SCRAMBLER_MODE : 0;
20587c478bd9Sstevel@tonic-gate 
20597c478bd9Sstevel@tonic-gate 	/* Full duplex */
20607c478bd9Sstevel@tonic-gate 	if (dnetp->mii_up) {
20617c478bd9Sstevel@tonic-gate 		fd = dnetp->mii_duplex;
20627c478bd9Sstevel@tonic-gate 	} else {
20637c478bd9Sstevel@tonic-gate 		/* Rely on media code */
206417de24c9Svb 		fd = block->media_code == MEDIA_TP_FD ||
20657c478bd9Sstevel@tonic-gate 		    block->media_code == MEDIA_SYM_SCR_FD;
20667c478bd9Sstevel@tonic-gate 	}
20677c478bd9Sstevel@tonic-gate 
20687c478bd9Sstevel@tonic-gate 	/* Port select (and therefore, heartbeat disable) */
20697c478bd9Sstevel@tonic-gate 	val |= block->command & CMD_PS ? (PORT_SELECT | HEARTBEAT_DISABLE) : 0;
20707c478bd9Sstevel@tonic-gate 
20717c478bd9Sstevel@tonic-gate 	/* PCS function */
20727c478bd9Sstevel@tonic-gate 	val |= (block->command) & CMD_PCS ? PCS_FUNCTION : 0;
20737c478bd9Sstevel@tonic-gate 	val |= fd ? FULL_DUPLEX : 0;
20747c478bd9Sstevel@tonic-gate 
20757c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
20767c478bd9Sstevel@tonic-gate 	if (dnetdebug & DNETREGCFG)
20777c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "OPN: %x", val);
20787c478bd9Sstevel@tonic-gate #endif
20794ab75253Smrj 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val);
208098e8d175SSteven Stallion 	dnet_reset_board(dnetp);
20814ab75253Smrj 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, OPN_MODE_REG), val);
20827c478bd9Sstevel@tonic-gate }
20837c478bd9Sstevel@tonic-gate 
20847c478bd9Sstevel@tonic-gate static void
set_sia(struct dnetinstance * dnetp)208598e8d175SSteven Stallion set_sia(struct dnetinstance *dnetp)
20867c478bd9Sstevel@tonic-gate {
20877c478bd9Sstevel@tonic-gate 	media_block_t *block = dnetp->selected_media_block;
20887c478bd9Sstevel@tonic-gate 
20897c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
20907c478bd9Sstevel@tonic-gate 	if (block->type == 2) {
20917c478bd9Sstevel@tonic-gate 		int sia_delay;
20927c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
20937c478bd9Sstevel@tonic-gate 		if (dnetdebug & DNETREGCFG)
20947c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
20957c478bd9Sstevel@tonic-gate 			    "SIA: CSR13: %x, CSR14: %x, CSR15: %x",
20967c478bd9Sstevel@tonic-gate 			    block->un.sia.csr13,
20977c478bd9Sstevel@tonic-gate 			    block->un.sia.csr14,
20987c478bd9Sstevel@tonic-gate 			    block->un.sia.csr15);
20997c478bd9Sstevel@tonic-gate #endif
21007c478bd9Sstevel@tonic-gate 		sia_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
21017c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "sia-delay", 10000);
21027c478bd9Sstevel@tonic-gate 
21034ab75253Smrj 		ddi_put32(dnetp->io_handle,
210417de24c9Svb 		    REG32(dnetp->io_reg, SIA_CONNECT_REG), 0);
21057c478bd9Sstevel@tonic-gate 
210617de24c9Svb 		ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, SIA_TXRX_REG),
21077c478bd9Sstevel@tonic-gate 		    block->un.sia.csr14);
21087c478bd9Sstevel@tonic-gate 
21097c478bd9Sstevel@tonic-gate 		/*
21107c478bd9Sstevel@tonic-gate 		 * For '143, we need to write through a copy of the register
21117c478bd9Sstevel@tonic-gate 		 * to keep the GP half intact
21127c478bd9Sstevel@tonic-gate 		 */
21137c478bd9Sstevel@tonic-gate 		dnetp->gprsia = (dnetp->gprsia&0xffff0000)|block->un.sia.csr15;
21144ab75253Smrj 		ddi_put32(dnetp->io_handle,
21157c478bd9Sstevel@tonic-gate 		    REG32(dnetp->io_reg, SIA_GENERAL_REG),
21167c478bd9Sstevel@tonic-gate 		    dnetp->gprsia);
21177c478bd9Sstevel@tonic-gate 
21184ab75253Smrj 		ddi_put32(dnetp->io_handle,
21197c478bd9Sstevel@tonic-gate 		    REG32(dnetp->io_reg, SIA_CONNECT_REG),
21207c478bd9Sstevel@tonic-gate 		    block->un.sia.csr13);
21217c478bd9Sstevel@tonic-gate 
21227c478bd9Sstevel@tonic-gate 		drv_usecwait(sia_delay);
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate 	} else if (dnetp->board_type != DEVICE_ID_21140) {
21254ab75253Smrj 		ddi_put32(dnetp->io_handle,
21267c478bd9Sstevel@tonic-gate 		    REG32(dnetp->io_reg, SIA_CONNECT_REG), 0);
21274ab75253Smrj 		ddi_put32(dnetp->io_handle,
21287c478bd9Sstevel@tonic-gate 		    REG32(dnetp->io_reg, SIA_TXRX_REG), 0);
21297c478bd9Sstevel@tonic-gate 	}
21307c478bd9Sstevel@tonic-gate }
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate /*
21337c478bd9Sstevel@tonic-gate  * This function (re)allocates the receive and transmit buffers and
21347c478bd9Sstevel@tonic-gate  * descriptors.  It can be called more than once per instance, though
21357c478bd9Sstevel@tonic-gate  * currently it is only called from attach.  It should only be called
21367c478bd9Sstevel@tonic-gate  * while the device is reset.
21377c478bd9Sstevel@tonic-gate  */
21387c478bd9Sstevel@tonic-gate static int
dnet_alloc_bufs(struct dnetinstance * dnetp)213998e8d175SSteven Stallion dnet_alloc_bufs(struct dnetinstance *dnetp)
21407c478bd9Sstevel@tonic-gate {
21417c478bd9Sstevel@tonic-gate 	int i;
21427c478bd9Sstevel@tonic-gate 	size_t len;
21437c478bd9Sstevel@tonic-gate 	int page_size;
21447c478bd9Sstevel@tonic-gate 	int realloc = 0;
21457c478bd9Sstevel@tonic-gate 	int nrecv_desc_old = 0;
21467c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t cookie;
21477c478bd9Sstevel@tonic-gate 	uint_t ncookies;
21487c478bd9Sstevel@tonic-gate 
21497c478bd9Sstevel@tonic-gate 	/*
21507c478bd9Sstevel@tonic-gate 	 * check if we are trying to reallocate with different xmit/recv
21517c478bd9Sstevel@tonic-gate 	 * descriptor ring sizes.
21527c478bd9Sstevel@tonic-gate 	 */
21537c478bd9Sstevel@tonic-gate 	if ((dnetp->tx_desc != NULL) &&
21547c478bd9Sstevel@tonic-gate 	    (dnetp->nxmit_desc != dnetp->max_tx_desc))
21557c478bd9Sstevel@tonic-gate 		realloc = 1;
21567c478bd9Sstevel@tonic-gate 
21577c478bd9Sstevel@tonic-gate 	if ((dnetp->rx_desc != NULL) &&
21587c478bd9Sstevel@tonic-gate 	    (dnetp->nrecv_desc != dnetp->max_rx_desc))
21597c478bd9Sstevel@tonic-gate 		realloc = 1;
21607c478bd9Sstevel@tonic-gate 
21617c478bd9Sstevel@tonic-gate 	/* free up the old buffers if we are reallocating them */
21627c478bd9Sstevel@tonic-gate 	if (realloc) {
21637c478bd9Sstevel@tonic-gate 		nrecv_desc_old = dnetp->nrecv_desc;
216498e8d175SSteven Stallion 		dnet_free_bufs(dnetp); /* free the old buffers */
21657c478bd9Sstevel@tonic-gate 	}
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate 	if (dnetp->dma_handle == NULL)
21687c478bd9Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
21697c478bd9Sstevel@tonic-gate 		    DDI_DMA_SLEEP, 0, &dnetp->dma_handle) != DDI_SUCCESS)
21707c478bd9Sstevel@tonic-gate 			return (FAILURE);
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 	if (dnetp->dma_handle_tx == NULL)
21737c478bd9Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr_tx,
21747c478bd9Sstevel@tonic-gate 		    DDI_DMA_SLEEP, 0, &dnetp->dma_handle_tx) != DDI_SUCCESS)
21757c478bd9Sstevel@tonic-gate 			return (FAILURE);
21767c478bd9Sstevel@tonic-gate 
21777c478bd9Sstevel@tonic-gate 	if (dnetp->dma_handle_txdesc == NULL)
21787c478bd9Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
21797c478bd9Sstevel@tonic-gate 		    DDI_DMA_SLEEP, 0, &dnetp->dma_handle_txdesc) != DDI_SUCCESS)
21807c478bd9Sstevel@tonic-gate 			return (FAILURE);
21817c478bd9Sstevel@tonic-gate 
21827c478bd9Sstevel@tonic-gate 	if (dnetp->dma_handle_setbuf == NULL)
21837c478bd9Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(dnetp->devinfo, &dma_attr,
21847c478bd9Sstevel@tonic-gate 		    DDI_DMA_SLEEP, 0, &dnetp->dma_handle_setbuf) != DDI_SUCCESS)
21857c478bd9Sstevel@tonic-gate 			return (FAILURE);
21867c478bd9Sstevel@tonic-gate 
21877c478bd9Sstevel@tonic-gate 	page_size = ddi_ptob(dnetp->devinfo, 1);
21888ef10d20Sgd 
21897c478bd9Sstevel@tonic-gate 	dnetp->pgmask = page_size - 1;
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate 	/* allocate setup buffer if necessary */
21927c478bd9Sstevel@tonic-gate 	if (dnetp->setup_buf_vaddr == NULL) {
21937c478bd9Sstevel@tonic-gate 		if (ddi_dma_mem_alloc(dnetp->dma_handle_setbuf,
21947c478bd9Sstevel@tonic-gate 		    SETUPBUF_SIZE, &accattr, DDI_DMA_STREAMING,
21957c478bd9Sstevel@tonic-gate 		    DDI_DMA_DONTWAIT, 0, (caddr_t *)&dnetp->setup_buf_vaddr,
21967c478bd9Sstevel@tonic-gate 		    &len, &dnetp->setup_buf_acchdl) != DDI_SUCCESS)
21977c478bd9Sstevel@tonic-gate 			return (FAILURE);
21987c478bd9Sstevel@tonic-gate 
21997c478bd9Sstevel@tonic-gate 		if (ddi_dma_addr_bind_handle(dnetp->dma_handle_setbuf,
22007c478bd9Sstevel@tonic-gate 		    NULL, dnetp->setup_buf_vaddr, SETUPBUF_SIZE,
22017c478bd9Sstevel@tonic-gate 		    DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
22027c478bd9Sstevel@tonic-gate 		    NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
22037c478bd9Sstevel@tonic-gate 			return (FAILURE);
22047c478bd9Sstevel@tonic-gate 
22058ef10d20Sgd 		dnetp->setup_buf_paddr = cookie.dmac_address;
22067c478bd9Sstevel@tonic-gate 		bzero(dnetp->setup_buf_vaddr, len);
22077c478bd9Sstevel@tonic-gate 	}
22087c478bd9Sstevel@tonic-gate 
22097c478bd9Sstevel@tonic-gate 	/* allocate xmit descriptor array of size dnetp->max_tx_desc */
22107c478bd9Sstevel@tonic-gate 	if (dnetp->tx_desc == NULL) {
22117c478bd9Sstevel@tonic-gate 		if (ddi_dma_mem_alloc(dnetp->dma_handle_txdesc,
22127c478bd9Sstevel@tonic-gate 		    sizeof (struct tx_desc_type) * dnetp->max_tx_desc,
22137c478bd9Sstevel@tonic-gate 		    &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
22147c478bd9Sstevel@tonic-gate 		    (caddr_t *)&dnetp->tx_desc, &len,
22157c478bd9Sstevel@tonic-gate 		    &dnetp->tx_desc_acchdl) != DDI_SUCCESS)
22167c478bd9Sstevel@tonic-gate 			return (FAILURE);
22177c478bd9Sstevel@tonic-gate 
22187c478bd9Sstevel@tonic-gate 		if (ddi_dma_addr_bind_handle(dnetp->dma_handle_txdesc,
22197c478bd9Sstevel@tonic-gate 		    NULL, (caddr_t)dnetp->tx_desc,
22207c478bd9Sstevel@tonic-gate 		    sizeof (struct tx_desc_type) * dnetp->max_tx_desc,
22217c478bd9Sstevel@tonic-gate 		    DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
22227c478bd9Sstevel@tonic-gate 		    NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
22237c478bd9Sstevel@tonic-gate 			return (FAILURE);
22248ef10d20Sgd 		dnetp->tx_desc_paddr = cookie.dmac_address;
22257c478bd9Sstevel@tonic-gate 		bzero(dnetp->tx_desc, len);
22267c478bd9Sstevel@tonic-gate 		dnetp->nxmit_desc = dnetp->max_tx_desc;
22277c478bd9Sstevel@tonic-gate 
22287c478bd9Sstevel@tonic-gate 		dnetp->tx_msgbufp =
22297c478bd9Sstevel@tonic-gate 		    kmem_zalloc(dnetp->max_tx_desc * sizeof (mblk_t **),
223017de24c9Svb 		    KM_SLEEP);
22317c478bd9Sstevel@tonic-gate 	}
22327c478bd9Sstevel@tonic-gate 
22337c478bd9Sstevel@tonic-gate 	/* allocate receive descriptor array of size dnetp->max_rx_desc */
22347c478bd9Sstevel@tonic-gate 	if (dnetp->rx_desc == NULL) {
22357c478bd9Sstevel@tonic-gate 		int ndesc;
22367c478bd9Sstevel@tonic-gate 
22377c478bd9Sstevel@tonic-gate 		if (ddi_dma_mem_alloc(dnetp->dma_handle,
22387c478bd9Sstevel@tonic-gate 		    sizeof (struct rx_desc_type) * dnetp->max_rx_desc,
22397c478bd9Sstevel@tonic-gate 		    &accattr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
22407c478bd9Sstevel@tonic-gate 		    (caddr_t *)&dnetp->rx_desc, &len,
22417c478bd9Sstevel@tonic-gate 		    &dnetp->rx_desc_acchdl) != DDI_SUCCESS)
22427c478bd9Sstevel@tonic-gate 			return (FAILURE);
22437c478bd9Sstevel@tonic-gate 
22447c478bd9Sstevel@tonic-gate 		if (ddi_dma_addr_bind_handle(dnetp->dma_handle,
22457c478bd9Sstevel@tonic-gate 		    NULL, (caddr_t)dnetp->rx_desc,
22467c478bd9Sstevel@tonic-gate 		    sizeof (struct rx_desc_type) * dnetp->max_rx_desc,
22477c478bd9Sstevel@tonic-gate 		    DDI_DMA_RDWR | DDI_DMA_STREAMING, DDI_DMA_SLEEP,
22487c478bd9Sstevel@tonic-gate 		    NULL, &cookie, &ncookies) != DDI_DMA_MAPPED)
22497c478bd9Sstevel@tonic-gate 			return (FAILURE);
22507c478bd9Sstevel@tonic-gate 
22518ef10d20Sgd 		dnetp->rx_desc_paddr = cookie.dmac_address;
22527c478bd9Sstevel@tonic-gate 		bzero(dnetp->rx_desc, len);
22537c478bd9Sstevel@tonic-gate 		dnetp->nrecv_desc = dnetp->max_rx_desc;
22547c478bd9Sstevel@tonic-gate 
22557c478bd9Sstevel@tonic-gate 		dnetp->rx_buf_vaddr =
22567c478bd9Sstevel@tonic-gate 		    kmem_zalloc(dnetp->max_rx_desc * sizeof (caddr_t),
225717de24c9Svb 		    KM_SLEEP);
22587c478bd9Sstevel@tonic-gate 		dnetp->rx_buf_paddr =
22598ef10d20Sgd 		    kmem_zalloc(dnetp->max_rx_desc * sizeof (uint32_t),
226017de24c9Svb 		    KM_SLEEP);
22617c478bd9Sstevel@tonic-gate 		/*
22627c478bd9Sstevel@tonic-gate 		 * Allocate or add to the pool of receive buffers.  The pool
22637c478bd9Sstevel@tonic-gate 		 * is shared among all instances of dnet.
22647c478bd9Sstevel@tonic-gate 		 *
22657c478bd9Sstevel@tonic-gate 		 * XXX NEEDSWORK
22667c478bd9Sstevel@tonic-gate 		 *
22677c478bd9Sstevel@tonic-gate 		 * We arbitrarily allocate twice as many receive buffers as
22687c478bd9Sstevel@tonic-gate 		 * receive descriptors because we use the buffers for streams
22697c478bd9Sstevel@tonic-gate 		 * messages to pass the packets up the stream.  We should
22707c478bd9Sstevel@tonic-gate 		 * instead have initialized constants reflecting
22717c478bd9Sstevel@tonic-gate 		 * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also
22727c478bd9Sstevel@tonic-gate 		 * probably have a total maximum for the free pool, so that we
22737c478bd9Sstevel@tonic-gate 		 * don't get out of hand when someone puts in an 8-port board.
22747c478bd9Sstevel@tonic-gate 		 * The maximum for the entire pool should be the total number
22757c478bd9Sstevel@tonic-gate 		 * of descriptors for all attached instances together, plus the
22767c478bd9Sstevel@tonic-gate 		 * total maximum for the free pool.  This maximum would only be
22777c478bd9Sstevel@tonic-gate 		 * reached after some number of instances allocate buffers:
22787c478bd9Sstevel@tonic-gate 		 * each instance would add (max_rx_buf-max_rx_desc) to the free
22797c478bd9Sstevel@tonic-gate 		 * pool.
22807c478bd9Sstevel@tonic-gate 		 */
22817c478bd9Sstevel@tonic-gate 		ndesc = dnetp->max_rx_desc - nrecv_desc_old;
22827c478bd9Sstevel@tonic-gate 		if ((ndesc > 0) &&
22837c478bd9Sstevel@tonic-gate 		    (dnet_rbuf_init(dnetp->devinfo, ndesc * 2) != 0))
22847c478bd9Sstevel@tonic-gate 			return (FAILURE);
22857c478bd9Sstevel@tonic-gate 
22867c478bd9Sstevel@tonic-gate 		for (i = 0; i < dnetp->max_rx_desc; i++) {
22877c478bd9Sstevel@tonic-gate 			struct rbuf_list *rp;
22887c478bd9Sstevel@tonic-gate 
22897c478bd9Sstevel@tonic-gate 			rp = dnet_rbuf_alloc(dnetp->devinfo, 1);
22907c478bd9Sstevel@tonic-gate 			if (rp == NULL)
22917c478bd9Sstevel@tonic-gate 				return (FAILURE);
22927c478bd9Sstevel@tonic-gate 			dnetp->rx_buf_vaddr[i] = rp->rbuf_vaddr;
2293483028f5Svitezslav batrla - Sun Microsystems - Prague Czech Republic 			dnetp->rx_buf_paddr[i] = rp->rbuf_paddr;
22947c478bd9Sstevel@tonic-gate 		}
22957c478bd9Sstevel@tonic-gate 	}
22967c478bd9Sstevel@tonic-gate 
22977c478bd9Sstevel@tonic-gate 	return (SUCCESS);
22987c478bd9Sstevel@tonic-gate }
22997c478bd9Sstevel@tonic-gate /*
23007c478bd9Sstevel@tonic-gate  * free descriptors/buffers allocated for this device instance.  This routine
23017c478bd9Sstevel@tonic-gate  * should only be called while the device is reset.
23027c478bd9Sstevel@tonic-gate  */
23037c478bd9Sstevel@tonic-gate static void
dnet_free_bufs(struct dnetinstance * dnetp)230498e8d175SSteven Stallion dnet_free_bufs(struct dnetinstance *dnetp)
23057c478bd9Sstevel@tonic-gate {
23067c478bd9Sstevel@tonic-gate 	int i;
23077c478bd9Sstevel@tonic-gate 	/* free up any xmit descriptors/buffers */
23087c478bd9Sstevel@tonic-gate 	if (dnetp->tx_desc != NULL) {
23097c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&dnetp->tx_desc_acchdl);
23107c478bd9Sstevel@tonic-gate 		dnetp->tx_desc = NULL;
23117c478bd9Sstevel@tonic-gate 		/* we use streams buffers for DMA in xmit process */
23127c478bd9Sstevel@tonic-gate 		if (dnetp->tx_msgbufp != NULL) {
231317de24c9Svb 			/* free up any streams message buffers unclaimed */
231417de24c9Svb 			for (i = 0; i < dnetp->nxmit_desc; i++) {
231517de24c9Svb 				if (dnetp->tx_msgbufp[i] != NULL) {
231617de24c9Svb 					freemsg(dnetp->tx_msgbufp[i]);
231717de24c9Svb 				}
23187c478bd9Sstevel@tonic-gate 			}
231917de24c9Svb 			kmem_free(dnetp->tx_msgbufp,
232017de24c9Svb 			    dnetp->nxmit_desc * sizeof (mblk_t **));
232117de24c9Svb 			dnetp->tx_msgbufp = NULL;
23227c478bd9Sstevel@tonic-gate 		}
23237c478bd9Sstevel@tonic-gate 		dnetp->nxmit_desc = 0;
23247c478bd9Sstevel@tonic-gate 	}
23257c478bd9Sstevel@tonic-gate 
23267c478bd9Sstevel@tonic-gate 	/* free up any receive descriptors/buffers */
23277c478bd9Sstevel@tonic-gate 	if (dnetp->rx_desc != NULL) {
23287c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&dnetp->rx_desc_acchdl);
23297c478bd9Sstevel@tonic-gate 		dnetp->rx_desc = NULL;
23307c478bd9Sstevel@tonic-gate 		if (dnetp->rx_buf_vaddr != NULL) {
23317c478bd9Sstevel@tonic-gate 			/* free up the attached rbufs if any */
23327c478bd9Sstevel@tonic-gate 			for (i = 0; i < dnetp->nrecv_desc; i++) {
233317de24c9Svb 				if (dnetp->rx_buf_vaddr[i])
233417de24c9Svb 					dnet_rbuf_free(
233517de24c9Svb 					    (caddr_t)dnetp->rx_buf_vaddr[i]);
23367c478bd9Sstevel@tonic-gate 			}
233717de24c9Svb 			kmem_free(dnetp->rx_buf_vaddr,
233817de24c9Svb 			    dnetp->nrecv_desc * sizeof (caddr_t));
233917de24c9Svb 			kmem_free(dnetp->rx_buf_paddr,
23408ef10d20Sgd 			    dnetp->nrecv_desc * sizeof (uint32_t));
234117de24c9Svb 			dnetp->rx_buf_vaddr = NULL;
234217de24c9Svb 			dnetp->rx_buf_paddr = NULL;
23437c478bd9Sstevel@tonic-gate 		}
23447c478bd9Sstevel@tonic-gate 		dnetp->nrecv_desc = 0;
23457c478bd9Sstevel@tonic-gate 	}
23467c478bd9Sstevel@tonic-gate 
23477c478bd9Sstevel@tonic-gate 	if (dnetp->setup_buf_vaddr != NULL) {
23487c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&dnetp->setup_buf_acchdl);
23497c478bd9Sstevel@tonic-gate 		dnetp->setup_buf_vaddr = NULL;
23507c478bd9Sstevel@tonic-gate 	}
23517c478bd9Sstevel@tonic-gate 
23527c478bd9Sstevel@tonic-gate 	if (dnetp->dma_handle != NULL) {
23537c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(dnetp->dma_handle);
23547c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&dnetp->dma_handle);
23557c478bd9Sstevel@tonic-gate 		dnetp->dma_handle = NULL;
23567c478bd9Sstevel@tonic-gate 	}
23577c478bd9Sstevel@tonic-gate 
23587c478bd9Sstevel@tonic-gate 	if (dnetp->dma_handle_tx != NULL) {
23597c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(dnetp->dma_handle_tx);
23607c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&dnetp->dma_handle_tx);
23617c478bd9Sstevel@tonic-gate 		dnetp->dma_handle_tx = NULL;
23627c478bd9Sstevel@tonic-gate 	}
23637c478bd9Sstevel@tonic-gate 
23647c478bd9Sstevel@tonic-gate 	if (dnetp->dma_handle_txdesc != NULL) {
23657c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(dnetp->dma_handle_txdesc);
23667c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&dnetp->dma_handle_txdesc);
23677c478bd9Sstevel@tonic-gate 		dnetp->dma_handle_txdesc = NULL;
23687c478bd9Sstevel@tonic-gate 	}
23697c478bd9Sstevel@tonic-gate 
23707c478bd9Sstevel@tonic-gate 	if (dnetp->dma_handle_setbuf != NULL) {
23717c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(dnetp->dma_handle_setbuf);
23727c478bd9Sstevel@tonic-gate 		ddi_dma_free_handle(&dnetp->dma_handle_setbuf);
23737c478bd9Sstevel@tonic-gate 		dnetp->dma_handle_setbuf = NULL;
23747c478bd9Sstevel@tonic-gate 	}
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate }
23777c478bd9Sstevel@tonic-gate 
23787c478bd9Sstevel@tonic-gate /*
23797c478bd9Sstevel@tonic-gate  * Initialize transmit and receive descriptors.
23807c478bd9Sstevel@tonic-gate  */
23817c478bd9Sstevel@tonic-gate static void
dnet_init_txrx_bufs(struct dnetinstance * dnetp)238298e8d175SSteven Stallion dnet_init_txrx_bufs(struct dnetinstance *dnetp)
23837c478bd9Sstevel@tonic-gate {
23847c478bd9Sstevel@tonic-gate 	int		i;
23857c478bd9Sstevel@tonic-gate 
23867c478bd9Sstevel@tonic-gate 	/*
23877c478bd9Sstevel@tonic-gate 	 * Initilize all the Tx descriptors
23887c478bd9Sstevel@tonic-gate 	 */
23897c478bd9Sstevel@tonic-gate 	for (i = 0; i < dnetp->nxmit_desc; i++) {
23907c478bd9Sstevel@tonic-gate 		/*
23917c478bd9Sstevel@tonic-gate 		 * We may be resetting the device due to errors,
23927c478bd9Sstevel@tonic-gate 		 * so free up any streams message buffer unclaimed.
23937c478bd9Sstevel@tonic-gate 		 */
23947c478bd9Sstevel@tonic-gate 		if (dnetp->tx_msgbufp[i] != NULL) {
23957c478bd9Sstevel@tonic-gate 			freemsg(dnetp->tx_msgbufp[i]);
23967c478bd9Sstevel@tonic-gate 			dnetp->tx_msgbufp[i] = NULL;
23977c478bd9Sstevel@tonic-gate 		}
23987c478bd9Sstevel@tonic-gate 		*(uint32_t *)&dnetp->tx_desc[i].desc0 = 0;
23997c478bd9Sstevel@tonic-gate 		*(uint32_t *)&dnetp->tx_desc[i].desc1 = 0;
24008ef10d20Sgd 		dnetp->tx_desc[i].buffer1 = 0;
24018ef10d20Sgd 		dnetp->tx_desc[i].buffer2 = 0;
24027c478bd9Sstevel@tonic-gate 	}
24037c478bd9Sstevel@tonic-gate 	dnetp->tx_desc[i - 1].desc1.end_of_ring = 1;
24047c478bd9Sstevel@tonic-gate 
24057c478bd9Sstevel@tonic-gate 	/*
24067c478bd9Sstevel@tonic-gate 	 * Initialize the Rx descriptors
24077c478bd9Sstevel@tonic-gate 	 */
24087c478bd9Sstevel@tonic-gate 	for (i = 0; i < dnetp->nrecv_desc; i++) {
24097c478bd9Sstevel@tonic-gate 		uint32_t end_paddr;
24107c478bd9Sstevel@tonic-gate 		*(uint32_t *)&dnetp->rx_desc[i].desc0 = 0;
24117c478bd9Sstevel@tonic-gate 		*(uint32_t *)&dnetp->rx_desc[i].desc1 = 0;
24127c478bd9Sstevel@tonic-gate 		dnetp->rx_desc[i].desc0.own = 1;
24137c478bd9Sstevel@tonic-gate 		dnetp->rx_desc[i].desc1.buffer_size1 = rx_buf_size;
24148ef10d20Sgd 		dnetp->rx_desc[i].buffer1 = dnetp->rx_buf_paddr[i];
24158ef10d20Sgd 		dnetp->rx_desc[i].buffer2 = 0;
24168ef10d20Sgd 		end_paddr = dnetp->rx_buf_paddr[i]+rx_buf_size-1;
24177c478bd9Sstevel@tonic-gate 
24187c478bd9Sstevel@tonic-gate 		if ((dnetp->rx_desc[i].buffer1 & ~dnetp->pgmask) !=
24197c478bd9Sstevel@tonic-gate 		    (end_paddr & ~dnetp->pgmask)) {
24207c478bd9Sstevel@tonic-gate 			/* discontiguous */
24217c478bd9Sstevel@tonic-gate 			dnetp->rx_desc[i].buffer2 = end_paddr&~dnetp->pgmask;
24227c478bd9Sstevel@tonic-gate 			dnetp->rx_desc[i].desc1.buffer_size2 =
24237c478bd9Sstevel@tonic-gate 			    (end_paddr & dnetp->pgmask) + 1;
24247c478bd9Sstevel@tonic-gate 			dnetp->rx_desc[i].desc1.buffer_size1 =
24257c478bd9Sstevel@tonic-gate 			    rx_buf_size-dnetp->rx_desc[i].desc1.buffer_size2;
24267c478bd9Sstevel@tonic-gate 		}
24277c478bd9Sstevel@tonic-gate 	}
24287c478bd9Sstevel@tonic-gate 	dnetp->rx_desc[i - 1].desc1.end_of_ring = 1;
24297c478bd9Sstevel@tonic-gate }
24307c478bd9Sstevel@tonic-gate 
24317c478bd9Sstevel@tonic-gate static int
alloc_descriptor(struct dnetinstance * dnetp)243298e8d175SSteven Stallion alloc_descriptor(struct dnetinstance *dnetp)
24337c478bd9Sstevel@tonic-gate {
24347c478bd9Sstevel@tonic-gate 	int index;
24357c478bd9Sstevel@tonic-gate 	struct tx_desc_type    *ring = dnetp->tx_desc;
24367c478bd9Sstevel@tonic-gate 
24377c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
24387c478bd9Sstevel@tonic-gate alloctop:
24397c478bd9Sstevel@tonic-gate 	mutex_enter(&dnetp->txlock);
24407c478bd9Sstevel@tonic-gate 	index = dnetp->tx_current_desc;
24417c478bd9Sstevel@tonic-gate 
244298e8d175SSteven Stallion 	dnet_reclaim_Tx_desc(dnetp);
24437c478bd9Sstevel@tonic-gate 
24447c478bd9Sstevel@tonic-gate 	/* we do have free descriptors, right? */
24457c478bd9Sstevel@tonic-gate 	if (dnetp->free_desc <= 0) {
24467c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
24477c478bd9Sstevel@tonic-gate 		if (dnetdebug & DNETRECV)
24487c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "dnet: Ring buffer is full");
24497c478bd9Sstevel@tonic-gate #endif
24507c478bd9Sstevel@tonic-gate 		mutex_exit(&dnetp->txlock);
24517c478bd9Sstevel@tonic-gate 		return (FAILURE);
24527c478bd9Sstevel@tonic-gate 	}
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 	/* sanity, make sure the next descriptor is free for use (should be) */
24557c478bd9Sstevel@tonic-gate 	if (ring[index].desc0.own) {
24567c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
24577c478bd9Sstevel@tonic-gate 		if (dnetdebug & DNETRECV)
24587c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
245917de24c9Svb 			    "dnet: next descriptor is not free for use");
24607c478bd9Sstevel@tonic-gate #endif
24617c478bd9Sstevel@tonic-gate 		mutex_exit(&dnetp->txlock);
24627c478bd9Sstevel@tonic-gate 		return (FAILURE);
24637c478bd9Sstevel@tonic-gate 	}
24647c478bd9Sstevel@tonic-gate 	if (dnetp->need_saddr) {
24657c478bd9Sstevel@tonic-gate 		mutex_exit(&dnetp->txlock);
24667c478bd9Sstevel@tonic-gate 		/* XXX function return value ignored */
24678ef10d20Sgd 		if (!dnetp->suspended)
246898e8d175SSteven Stallion 			(void) dnet_set_addr(dnetp);
24697c478bd9Sstevel@tonic-gate 		goto alloctop;
24707c478bd9Sstevel@tonic-gate 	}
24717c478bd9Sstevel@tonic-gate 
24727c478bd9Sstevel@tonic-gate 	*(uint32_t *)&ring[index].desc0 = 0;  /* init descs */
24737c478bd9Sstevel@tonic-gate 	*(uint32_t *)&ring[index].desc1 &= DNET_END_OF_RING;
24747c478bd9Sstevel@tonic-gate 
24757c478bd9Sstevel@tonic-gate 	/* hardware will own this descriptor when poll activated */
24767c478bd9Sstevel@tonic-gate 	dnetp->free_desc--;
24777c478bd9Sstevel@tonic-gate 
24787c478bd9Sstevel@tonic-gate 	/* point to next free descriptor to be used */
24797c478bd9Sstevel@tonic-gate 	dnetp->tx_current_desc = NextTXIndex(index);
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate #ifdef DNET_NOISY
24827c478bd9Sstevel@tonic-gate 	cmn_err(CE_WARN, "sfree 0x%x, transmitted 0x%x, tx_current 0x%x",
24837c478bd9Sstevel@tonic-gate 	    dnetp->free_desc, dnetp->transmitted_desc, dnetp->tx_current_desc);
24847c478bd9Sstevel@tonic-gate #endif
24857c478bd9Sstevel@tonic-gate 	mutex_exit(&dnetp->txlock);
24867c478bd9Sstevel@tonic-gate 	return (SUCCESS);
24877c478bd9Sstevel@tonic-gate }
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate /*
24907c478bd9Sstevel@tonic-gate  * dnet_reclaim_Tx_desc() - called with txlock held.
24917c478bd9Sstevel@tonic-gate  */
24927c478bd9Sstevel@tonic-gate static void
dnet_reclaim_Tx_desc(struct dnetinstance * dnetp)249398e8d175SSteven Stallion dnet_reclaim_Tx_desc(struct dnetinstance *dnetp)
24947c478bd9Sstevel@tonic-gate {
24957c478bd9Sstevel@tonic-gate 	struct tx_desc_type	*desc = dnetp->tx_desc;
24967c478bd9Sstevel@tonic-gate 	int index;
24977c478bd9Sstevel@tonic-gate 
24987c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->txlock));
24997c478bd9Sstevel@tonic-gate 
25007c478bd9Sstevel@tonic-gate 	index = dnetp->transmitted_desc;
25017c478bd9Sstevel@tonic-gate 	while (((dnetp->free_desc == 0) || (index != dnetp->tx_current_desc)) &&
25027c478bd9Sstevel@tonic-gate 	    !(desc[index].desc0.own)) {
25037c478bd9Sstevel@tonic-gate 		/*
25047c478bd9Sstevel@tonic-gate 		 * Check for Tx Error that gets set
25057c478bd9Sstevel@tonic-gate 		 * in the last desc.
25067c478bd9Sstevel@tonic-gate 		 */
25077c478bd9Sstevel@tonic-gate 		if (desc[index].desc1.setup_packet == 0 &&
25087c478bd9Sstevel@tonic-gate 		    desc[index].desc1.last_desc &&
25097c478bd9Sstevel@tonic-gate 		    desc[index].desc0.err_summary)
251098e8d175SSteven Stallion 			update_tx_stats(dnetp, index);
25117c478bd9Sstevel@tonic-gate 
25127c478bd9Sstevel@tonic-gate 		/*
25137c478bd9Sstevel@tonic-gate 		 * If we have used the streams message buffer for this
25147c478bd9Sstevel@tonic-gate 		 * descriptor then free up the message now.
25157c478bd9Sstevel@tonic-gate 		 */
25167c478bd9Sstevel@tonic-gate 		if (dnetp->tx_msgbufp[index] != NULL) {
25177c478bd9Sstevel@tonic-gate 			freemsg(dnetp->tx_msgbufp[index]);
25187c478bd9Sstevel@tonic-gate 			dnetp->tx_msgbufp[index] = NULL;
25197c478bd9Sstevel@tonic-gate 		}
25207c478bd9Sstevel@tonic-gate 		dnetp->free_desc++;
25217c478bd9Sstevel@tonic-gate 		index = (index+1) % dnetp->max_tx_desc;
25227c478bd9Sstevel@tonic-gate 	}
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate 	dnetp->transmitted_desc = index;
25257c478bd9Sstevel@tonic-gate }
25267c478bd9Sstevel@tonic-gate 
25277c478bd9Sstevel@tonic-gate /*
25287c478bd9Sstevel@tonic-gate  * Receive buffer allocation/freeing routines.
25297c478bd9Sstevel@tonic-gate  *
25307c478bd9Sstevel@tonic-gate  * There is a common pool of receive buffers shared by all dnet instances.
25317c478bd9Sstevel@tonic-gate  *
25327c478bd9Sstevel@tonic-gate  * XXX NEEDSWORK
25337c478bd9Sstevel@tonic-gate  *
25347c478bd9Sstevel@tonic-gate  * We arbitrarily allocate twice as many receive buffers as
25357c478bd9Sstevel@tonic-gate  * receive descriptors because we use the buffers for streams
25367c478bd9Sstevel@tonic-gate  * messages to pass the packets up the stream.  We should
25377c478bd9Sstevel@tonic-gate  * instead have initialized constants reflecting
25387c478bd9Sstevel@tonic-gate  * MAX_RX_BUF_2104x and MAX_RX_BUF_2114x, and we should also
25397c478bd9Sstevel@tonic-gate  * probably have a total maximum for the free pool, so that we
25407c478bd9Sstevel@tonic-gate  * don't get out of hand when someone puts in an 8-port board.
25417c478bd9Sstevel@tonic-gate  * The maximum for the entire pool should be the total number
25427c478bd9Sstevel@tonic-gate  * of descriptors for all attached instances together, plus the
25437c478bd9Sstevel@tonic-gate  * total maximum for the free pool.  This maximum would only be
25447c478bd9Sstevel@tonic-gate  * reached after some number of instances allocate buffers:
25457c478bd9Sstevel@tonic-gate  * each instance would add (max_rx_buf-max_rx_desc) to the free
25467c478bd9Sstevel@tonic-gate  * pool.
25477c478bd9Sstevel@tonic-gate  */
25487c478bd9Sstevel@tonic-gate 
25497c478bd9Sstevel@tonic-gate static struct rbuf_list *rbuf_usedlist_head;
25507c478bd9Sstevel@tonic-gate static struct rbuf_list *rbuf_freelist_head;
25517c478bd9Sstevel@tonic-gate static struct rbuf_list *rbuf_usedlist_end;	/* last buffer allocated */
25527c478bd9Sstevel@tonic-gate 
25537c478bd9Sstevel@tonic-gate static int rbuf_freebufs;	/* no. of free buffers in the pool */
25547c478bd9Sstevel@tonic-gate static int rbuf_pool_size;	/* total no. of buffers in the pool */
25557c478bd9Sstevel@tonic-gate 
25567c478bd9Sstevel@tonic-gate /* initialize/add 'nbufs' buffers to the rbuf pool */
25577c478bd9Sstevel@tonic-gate /* ARGSUSED */
25587c478bd9Sstevel@tonic-gate static int
dnet_rbuf_init(dev_info_t * dip,int nbufs)25597c478bd9Sstevel@tonic-gate dnet_rbuf_init(dev_info_t *dip, int nbufs)
25607c478bd9Sstevel@tonic-gate {
25617c478bd9Sstevel@tonic-gate 	int i;
25627c478bd9Sstevel@tonic-gate 	struct rbuf_list *rp;
25637c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t cookie;
25647c478bd9Sstevel@tonic-gate 	uint_t ncookies;
25657c478bd9Sstevel@tonic-gate 	size_t len;
25667c478bd9Sstevel@tonic-gate 
25677c478bd9Sstevel@tonic-gate 	mutex_enter(&dnet_rbuf_lock);
25687c478bd9Sstevel@tonic-gate 
25697c478bd9Sstevel@tonic-gate 	/* allocate buffers and add them to the pool */
25707c478bd9Sstevel@tonic-gate 	for (i = 0; i < nbufs; i++) {
25717c478bd9Sstevel@tonic-gate 		/* allocate rbuf_list element */
25727c478bd9Sstevel@tonic-gate 		rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP);
25737c478bd9Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP,
257417de24c9Svb 		    0, &rp->rbuf_dmahdl) != DDI_SUCCESS)
25757c478bd9Sstevel@tonic-gate 			goto fail_kfree;
25767c478bd9Sstevel@tonic-gate 
25777c478bd9Sstevel@tonic-gate 		/* allocate dma memory for the buffer */
25787c478bd9Sstevel@tonic-gate 		if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr,
25797c478bd9Sstevel@tonic-gate 		    DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
25807c478bd9Sstevel@tonic-gate 		    &rp->rbuf_vaddr, &len,
25817c478bd9Sstevel@tonic-gate 		    &rp->rbuf_acchdl) != DDI_SUCCESS)
25827c478bd9Sstevel@tonic-gate 			goto fail_freehdl;
25837c478bd9Sstevel@tonic-gate 
25847c478bd9Sstevel@tonic-gate 		if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL,
25857c478bd9Sstevel@tonic-gate 		    rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
25867c478bd9Sstevel@tonic-gate 		    DDI_DMA_SLEEP, NULL, &cookie,
25877c478bd9Sstevel@tonic-gate 		    &ncookies) != DDI_DMA_MAPPED)
25887c478bd9Sstevel@tonic-gate 			goto fail_free;
25897c478bd9Sstevel@tonic-gate 
25907c478bd9Sstevel@tonic-gate 		if (ncookies > 2)
25917c478bd9Sstevel@tonic-gate 			goto fail_unbind;
25927c478bd9Sstevel@tonic-gate 		if (ncookies == 1) {
25938ef10d20Sgd 			rp->rbuf_endpaddr =
25948ef10d20Sgd 			    cookie.dmac_address + rx_buf_size - 1;
25957c478bd9Sstevel@tonic-gate 		} else {
25967c478bd9Sstevel@tonic-gate 			ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie);
25978ef10d20Sgd 			rp->rbuf_endpaddr =
25988ef10d20Sgd 			    cookie.dmac_address + cookie.dmac_size - 1;
25997c478bd9Sstevel@tonic-gate 		}
26008ef10d20Sgd 		rp->rbuf_paddr = cookie.dmac_address;
26017c478bd9Sstevel@tonic-gate 
26027c478bd9Sstevel@tonic-gate 		rp->rbuf_next = rbuf_freelist_head;
26037c478bd9Sstevel@tonic-gate 		rbuf_freelist_head = rp;
26047c478bd9Sstevel@tonic-gate 		rbuf_pool_size++;
26057c478bd9Sstevel@tonic-gate 		rbuf_freebufs++;
26067c478bd9Sstevel@tonic-gate 	}
26077c478bd9Sstevel@tonic-gate 
26087c478bd9Sstevel@tonic-gate 	mutex_exit(&dnet_rbuf_lock);
26097c478bd9Sstevel@tonic-gate 	return (0);
26107c478bd9Sstevel@tonic-gate fail_unbind:
26117c478bd9Sstevel@tonic-gate 	(void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
26127c478bd9Sstevel@tonic-gate fail_free:
26137c478bd9Sstevel@tonic-gate 	ddi_dma_mem_free(&rp->rbuf_acchdl);
26147c478bd9Sstevel@tonic-gate fail_freehdl:
26157c478bd9Sstevel@tonic-gate 	ddi_dma_free_handle(&rp->rbuf_dmahdl);
26167c478bd9Sstevel@tonic-gate fail_kfree:
26177c478bd9Sstevel@tonic-gate 	kmem_free(rp, sizeof (struct rbuf_list));
26187c478bd9Sstevel@tonic-gate 
26197c478bd9Sstevel@tonic-gate 	mutex_exit(&dnet_rbuf_lock);
26207c478bd9Sstevel@tonic-gate 	return (-1);
26217c478bd9Sstevel@tonic-gate }
26227c478bd9Sstevel@tonic-gate 
26237c478bd9Sstevel@tonic-gate /*
26247c478bd9Sstevel@tonic-gate  * Try to free up all the rbufs in the pool. Returns 0 if it frees up all
26257c478bd9Sstevel@tonic-gate  * buffers. The buffers in the used list are considered busy so these
26267c478bd9Sstevel@tonic-gate  * buffers are not freed.
26277c478bd9Sstevel@tonic-gate  */
26287c478bd9Sstevel@tonic-gate static int
dnet_rbuf_destroy()26297c478bd9Sstevel@tonic-gate dnet_rbuf_destroy()
26307c478bd9Sstevel@tonic-gate {
26317c478bd9Sstevel@tonic-gate 	struct rbuf_list *rp, *next;
26327c478bd9Sstevel@tonic-gate 
26337c478bd9Sstevel@tonic-gate 	mutex_enter(&dnet_rbuf_lock);
26347c478bd9Sstevel@tonic-gate 
26357c478bd9Sstevel@tonic-gate 	for (rp = rbuf_freelist_head; rp; rp = next) {
26367c478bd9Sstevel@tonic-gate 		next = rp->rbuf_next;
26377c478bd9Sstevel@tonic-gate 		ddi_dma_mem_free(&rp->rbuf_acchdl);
26387c478bd9Sstevel@tonic-gate 		(void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
26397c478bd9Sstevel@tonic-gate 		kmem_free(rp, sizeof (struct rbuf_list));
26407c478bd9Sstevel@tonic-gate 		rbuf_pool_size--;
26417c478bd9Sstevel@tonic-gate 		rbuf_freebufs--;
26427c478bd9Sstevel@tonic-gate 	}
26437c478bd9Sstevel@tonic-gate 	rbuf_freelist_head = NULL;
26447c478bd9Sstevel@tonic-gate 
26457c478bd9Sstevel@tonic-gate 	if (rbuf_pool_size) { /* pool is still not empty */
26467c478bd9Sstevel@tonic-gate 		mutex_exit(&dnet_rbuf_lock);
26477c478bd9Sstevel@tonic-gate 		return (-1);
26487c478bd9Sstevel@tonic-gate 	}
26497c478bd9Sstevel@tonic-gate 	mutex_exit(&dnet_rbuf_lock);
26507c478bd9Sstevel@tonic-gate 	return (0);
26517c478bd9Sstevel@tonic-gate }
26527c478bd9Sstevel@tonic-gate static struct rbuf_list *
dnet_rbuf_alloc(dev_info_t * dip,int cansleep)26537c478bd9Sstevel@tonic-gate dnet_rbuf_alloc(dev_info_t *dip, int cansleep)
26547c478bd9Sstevel@tonic-gate {
26557c478bd9Sstevel@tonic-gate 	struct rbuf_list *rp;
26567c478bd9Sstevel@tonic-gate 	size_t len;
26577c478bd9Sstevel@tonic-gate 	ddi_dma_cookie_t cookie;
26587c478bd9Sstevel@tonic-gate 	uint_t ncookies;
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate 	mutex_enter(&dnet_rbuf_lock);
26617c478bd9Sstevel@tonic-gate 
26627c478bd9Sstevel@tonic-gate 	if (rbuf_freelist_head == NULL) {
26637c478bd9Sstevel@tonic-gate 
26647c478bd9Sstevel@tonic-gate 		if (!cansleep) {
26657c478bd9Sstevel@tonic-gate 			mutex_exit(&dnet_rbuf_lock);
26667c478bd9Sstevel@tonic-gate 			return (NULL);
26677c478bd9Sstevel@tonic-gate 		}
26687c478bd9Sstevel@tonic-gate 
26697c478bd9Sstevel@tonic-gate 		/* allocate rbuf_list element */
26707c478bd9Sstevel@tonic-gate 		rp = kmem_zalloc(sizeof (struct rbuf_list), KM_SLEEP);
26717c478bd9Sstevel@tonic-gate 		if (ddi_dma_alloc_handle(dip, &dma_attr_rb, DDI_DMA_SLEEP,
267217de24c9Svb 		    0, &rp->rbuf_dmahdl) != DDI_SUCCESS)
26737c478bd9Sstevel@tonic-gate 			goto fail_kfree;
26747c478bd9Sstevel@tonic-gate 
26757c478bd9Sstevel@tonic-gate 		/* allocate dma memory for the buffer */
26767c478bd9Sstevel@tonic-gate 		if (ddi_dma_mem_alloc(rp->rbuf_dmahdl, rx_buf_size, &accattr,
26777c478bd9Sstevel@tonic-gate 		    DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, 0,
26787c478bd9Sstevel@tonic-gate 		    &rp->rbuf_vaddr, &len,
26797c478bd9Sstevel@tonic-gate 		    &rp->rbuf_acchdl) != DDI_SUCCESS)
26807c478bd9Sstevel@tonic-gate 			goto fail_freehdl;
26817c478bd9Sstevel@tonic-gate 
26827c478bd9Sstevel@tonic-gate 		if (ddi_dma_addr_bind_handle(rp->rbuf_dmahdl, NULL,
26837c478bd9Sstevel@tonic-gate 		    rp->rbuf_vaddr, len, DDI_DMA_RDWR | DDI_DMA_STREAMING,
26847c478bd9Sstevel@tonic-gate 		    DDI_DMA_SLEEP, NULL, &cookie,
26857c478bd9Sstevel@tonic-gate 		    &ncookies) != DDI_DMA_MAPPED)
26867c478bd9Sstevel@tonic-gate 			goto fail_free;
26877c478bd9Sstevel@tonic-gate 
26887c478bd9Sstevel@tonic-gate 		if (ncookies > 2)
26897c478bd9Sstevel@tonic-gate 			goto fail_unbind;
26907c478bd9Sstevel@tonic-gate 		if (ncookies == 1) {
26918ef10d20Sgd 			rp->rbuf_endpaddr =
26928ef10d20Sgd 			    cookie.dmac_address + rx_buf_size - 1;
26937c478bd9Sstevel@tonic-gate 		} else {
26947c478bd9Sstevel@tonic-gate 			ddi_dma_nextcookie(rp->rbuf_dmahdl, &cookie);
26958ef10d20Sgd 			rp->rbuf_endpaddr =
26968ef10d20Sgd 			    cookie.dmac_address + cookie.dmac_size - 1;
26977c478bd9Sstevel@tonic-gate 		}
26988ef10d20Sgd 		rp->rbuf_paddr = cookie.dmac_address;
26997c478bd9Sstevel@tonic-gate 
27007c478bd9Sstevel@tonic-gate 		rbuf_freelist_head = rp;
27017c478bd9Sstevel@tonic-gate 		rbuf_pool_size++;
27027c478bd9Sstevel@tonic-gate 		rbuf_freebufs++;
27037c478bd9Sstevel@tonic-gate 	}
27047c478bd9Sstevel@tonic-gate 
27057c478bd9Sstevel@tonic-gate 	/* take the buffer from the head of the free list */
27067c478bd9Sstevel@tonic-gate 	rp = rbuf_freelist_head;
27077c478bd9Sstevel@tonic-gate 	rbuf_freelist_head = rbuf_freelist_head->rbuf_next;
27087c478bd9Sstevel@tonic-gate 
27097c478bd9Sstevel@tonic-gate 	/* update the used list; put the entry at the end */
27107c478bd9Sstevel@tonic-gate 	if (rbuf_usedlist_head == NULL)
27117c478bd9Sstevel@tonic-gate 		rbuf_usedlist_head = rp;
27127c478bd9Sstevel@tonic-gate 	else
27137c478bd9Sstevel@tonic-gate 		rbuf_usedlist_end->rbuf_next = rp;
27147c478bd9Sstevel@tonic-gate 	rp->rbuf_next = NULL;
27157c478bd9Sstevel@tonic-gate 	rbuf_usedlist_end = rp;
27167c478bd9Sstevel@tonic-gate 	rbuf_freebufs--;
27177c478bd9Sstevel@tonic-gate 
27187c478bd9Sstevel@tonic-gate 	mutex_exit(&dnet_rbuf_lock);
27197c478bd9Sstevel@tonic-gate 
27207c478bd9Sstevel@tonic-gate 	return (rp);
27217c478bd9Sstevel@tonic-gate fail_unbind:
27227c478bd9Sstevel@tonic-gate 	(void) ddi_dma_unbind_handle(rp->rbuf_dmahdl);
27237c478bd9Sstevel@tonic-gate fail_free:
27247c478bd9Sstevel@tonic-gate 	ddi_dma_mem_free(&rp->rbuf_acchdl);
27257c478bd9Sstevel@tonic-gate fail_freehdl:
27267c478bd9Sstevel@tonic-gate 	ddi_dma_free_handle(&rp->rbuf_dmahdl);
27277c478bd9Sstevel@tonic-gate fail_kfree:
27287c478bd9Sstevel@tonic-gate 	kmem_free(rp, sizeof (struct rbuf_list));
27297c478bd9Sstevel@tonic-gate 	mutex_exit(&dnet_rbuf_lock);
27307c478bd9Sstevel@tonic-gate 	return (NULL);
27317c478bd9Sstevel@tonic-gate }
27327c478bd9Sstevel@tonic-gate 
27337c478bd9Sstevel@tonic-gate static void
dnet_rbuf_free(caddr_t vaddr)27347c478bd9Sstevel@tonic-gate dnet_rbuf_free(caddr_t vaddr)
27357c478bd9Sstevel@tonic-gate {
27367c478bd9Sstevel@tonic-gate 	struct rbuf_list *rp, *prev;
27377c478bd9Sstevel@tonic-gate 
27387c478bd9Sstevel@tonic-gate 	ASSERT(vaddr != NULL);
27397c478bd9Sstevel@tonic-gate 	ASSERT(rbuf_usedlist_head != NULL);
27407c478bd9Sstevel@tonic-gate 
27417c478bd9Sstevel@tonic-gate 	mutex_enter(&dnet_rbuf_lock);
27427c478bd9Sstevel@tonic-gate 
27437c478bd9Sstevel@tonic-gate 	/* find the entry in the used list */
27447c478bd9Sstevel@tonic-gate 	for (prev = rp = rbuf_usedlist_head; rp; rp = rp->rbuf_next) {
27457c478bd9Sstevel@tonic-gate 		if (rp->rbuf_vaddr == vaddr)
27467c478bd9Sstevel@tonic-gate 			break;
27477c478bd9Sstevel@tonic-gate 		prev = rp;
27487c478bd9Sstevel@tonic-gate 	}
27497c478bd9Sstevel@tonic-gate 
27507c478bd9Sstevel@tonic-gate 	if (rp == NULL) {
27517c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "DNET: rbuf_free: bad addr 0x%p",
275217de24c9Svb 		    (void *)vaddr);
27537c478bd9Sstevel@tonic-gate 		mutex_exit(&dnet_rbuf_lock);
27547c478bd9Sstevel@tonic-gate 		return;
27557c478bd9Sstevel@tonic-gate 	}
27567c478bd9Sstevel@tonic-gate 
27577c478bd9Sstevel@tonic-gate 	/* update the used list and put the buffer back in the free list */
27587c478bd9Sstevel@tonic-gate 	if (rbuf_usedlist_head != rp) {
27597c478bd9Sstevel@tonic-gate 		prev->rbuf_next = rp->rbuf_next;
27607c478bd9Sstevel@tonic-gate 		if (rbuf_usedlist_end == rp)
27617c478bd9Sstevel@tonic-gate 			rbuf_usedlist_end = prev;
27627c478bd9Sstevel@tonic-gate 	} else {
27637c478bd9Sstevel@tonic-gate 		rbuf_usedlist_head = rp->rbuf_next;
27647c478bd9Sstevel@tonic-gate 		if (rbuf_usedlist_end == rp)
27657c478bd9Sstevel@tonic-gate 			rbuf_usedlist_end = NULL;
27667c478bd9Sstevel@tonic-gate 	}
27677c478bd9Sstevel@tonic-gate 	rp->rbuf_next = rbuf_freelist_head;
27687c478bd9Sstevel@tonic-gate 	rbuf_freelist_head = rp;
27697c478bd9Sstevel@tonic-gate 	rbuf_freebufs++;
27707c478bd9Sstevel@tonic-gate 
27717c478bd9Sstevel@tonic-gate 	mutex_exit(&dnet_rbuf_lock);
27727c478bd9Sstevel@tonic-gate }
27737c478bd9Sstevel@tonic-gate 
27747c478bd9Sstevel@tonic-gate /*
27757c478bd9Sstevel@tonic-gate  * Free the receive buffer used in a stream's message block allocated
27767c478bd9Sstevel@tonic-gate  * thru desballoc().
27777c478bd9Sstevel@tonic-gate  */
27787c478bd9Sstevel@tonic-gate static void
dnet_freemsg_buf(struct free_ptr * frp)27797c478bd9Sstevel@tonic-gate dnet_freemsg_buf(struct free_ptr *frp)
27807c478bd9Sstevel@tonic-gate {
27817c478bd9Sstevel@tonic-gate 	dnet_rbuf_free((caddr_t)frp->buf); /* buffer goes back to the pool */
27827c478bd9Sstevel@tonic-gate 	kmem_free(frp, sizeof (*frp)); /* free up the free_rtn structure */
27837c478bd9Sstevel@tonic-gate }
27847c478bd9Sstevel@tonic-gate 
27857c478bd9Sstevel@tonic-gate /*
27867c478bd9Sstevel@tonic-gate  *	========== SROM Read Routines ==========
27877c478bd9Sstevel@tonic-gate  */
27887c478bd9Sstevel@tonic-gate 
27897c478bd9Sstevel@tonic-gate /*
27907c478bd9Sstevel@tonic-gate  * The following code gets the SROM information, either by reading it
27917c478bd9Sstevel@tonic-gate  * from the device or, failing that, by reading a property.
27927c478bd9Sstevel@tonic-gate  */
27937c478bd9Sstevel@tonic-gate static int
dnet_read_srom(dev_info_t * devinfo,int board_type,ddi_acc_handle_t io_handle,caddr_t io_reg,uchar_t * vi,int maxlen)27947c478bd9Sstevel@tonic-gate dnet_read_srom(dev_info_t *devinfo, int board_type, ddi_acc_handle_t io_handle,
27958ef10d20Sgd     caddr_t io_reg, uchar_t *vi, int maxlen)
27967c478bd9Sstevel@tonic-gate {
27977c478bd9Sstevel@tonic-gate 	int all_ones, zerocheck, i;
27987c478bd9Sstevel@tonic-gate 
27997c478bd9Sstevel@tonic-gate 	/*
28007c478bd9Sstevel@tonic-gate 	 * Load SROM into vendor_info
28017c478bd9Sstevel@tonic-gate 	 */
28027c478bd9Sstevel@tonic-gate 	if (board_type == DEVICE_ID_21040)
28037c478bd9Sstevel@tonic-gate 		dnet_read21040addr(devinfo, io_handle, io_reg, vi, &maxlen);
28047c478bd9Sstevel@tonic-gate 	else
28057c478bd9Sstevel@tonic-gate 		/* 21041/21140 serial rom */
28067c478bd9Sstevel@tonic-gate 		dnet_read21140srom(io_handle, io_reg, vi, maxlen);
28077c478bd9Sstevel@tonic-gate 	/*
28087c478bd9Sstevel@tonic-gate 	 * If the dumpsrom property is present in the conf file, print
28097c478bd9Sstevel@tonic-gate 	 * the contents of the SROM to the console
28107c478bd9Sstevel@tonic-gate 	 */
28117c478bd9Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
281217de24c9Svb 	    "dumpsrom", 0))
28137c478bd9Sstevel@tonic-gate 		dnet_dumpbin("SROM", vi, 1, maxlen);
28147c478bd9Sstevel@tonic-gate 
28157c478bd9Sstevel@tonic-gate 	for (zerocheck = i = 0, all_ones = 0xff; i < maxlen; i++) {
28167c478bd9Sstevel@tonic-gate 		zerocheck |= vi[i];
28177c478bd9Sstevel@tonic-gate 		all_ones &= vi[i];
28187c478bd9Sstevel@tonic-gate 	}
28197c478bd9Sstevel@tonic-gate 	if (zerocheck == 0 || all_ones == 0xff) {
28207c478bd9Sstevel@tonic-gate 		return (get_alternative_srom_image(devinfo, vi, maxlen));
28217c478bd9Sstevel@tonic-gate 	} else {
28227c478bd9Sstevel@tonic-gate #ifdef BUG_4010796
28237c478bd9Sstevel@tonic-gate 		set_alternative_srom_image(devinfo, vi, maxlen);
28247c478bd9Sstevel@tonic-gate #endif
28257c478bd9Sstevel@tonic-gate 		return (0);	/* Primary */
28267c478bd9Sstevel@tonic-gate 	}
28277c478bd9Sstevel@tonic-gate }
28287c478bd9Sstevel@tonic-gate 
28297c478bd9Sstevel@tonic-gate /*
28307c478bd9Sstevel@tonic-gate  * The function reads the ethernet address of the 21040 adapter
28317c478bd9Sstevel@tonic-gate  */
28327c478bd9Sstevel@tonic-gate static void
dnet_read21040addr(dev_info_t * dip,ddi_acc_handle_t io_handle,caddr_t io_reg,uchar_t * addr,int * len)28338ef10d20Sgd dnet_read21040addr(dev_info_t *dip, ddi_acc_handle_t io_handle, caddr_t io_reg,
28347c478bd9Sstevel@tonic-gate     uchar_t *addr, int *len)
28357c478bd9Sstevel@tonic-gate {
28367c478bd9Sstevel@tonic-gate 	uint32_t	val;
28377c478bd9Sstevel@tonic-gate 	int		i;
28387c478bd9Sstevel@tonic-gate 
28397c478bd9Sstevel@tonic-gate 	/* No point reading more than the ethernet address */
28407c478bd9Sstevel@tonic-gate 	*len = ddi_getprop(DDI_DEV_T_ANY, dip,
28417c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, macoffset_propname, 0) + ETHERADDRL;
28427c478bd9Sstevel@tonic-gate 
28437c478bd9Sstevel@tonic-gate 	/* Reset ROM pointer */
28444ab75253Smrj 	ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG), 0);
28457c478bd9Sstevel@tonic-gate 	for (i = 0; i < *len; i++) {
28467c478bd9Sstevel@tonic-gate 		do {
28474ab75253Smrj 			val = ddi_get32(io_handle,
284817de24c9Svb 			    REG32(io_reg, ETHER_ROM_REG));
28497c478bd9Sstevel@tonic-gate 		} while (val & 0x80000000);
28507c478bd9Sstevel@tonic-gate 		addr[i] = val & 0xFF;
28517c478bd9Sstevel@tonic-gate 	}
28527c478bd9Sstevel@tonic-gate }
28537c478bd9Sstevel@tonic-gate 
28547c478bd9Sstevel@tonic-gate #define	drv_nsecwait(x)	drv_usecwait(((x)+999)/1000) /* XXX */
28557c478bd9Sstevel@tonic-gate 
28567c478bd9Sstevel@tonic-gate /*
28577c478bd9Sstevel@tonic-gate  * The function reads the SROM	of the 21140 adapter
28587c478bd9Sstevel@tonic-gate  */
28597c478bd9Sstevel@tonic-gate static void
dnet_read21140srom(ddi_acc_handle_t io_handle,caddr_t io_reg,uchar_t * addr,int maxlen)28608ef10d20Sgd dnet_read21140srom(ddi_acc_handle_t io_handle, caddr_t io_reg, uchar_t *addr,
28617c478bd9Sstevel@tonic-gate     int maxlen)
28627c478bd9Sstevel@tonic-gate {
2863*f879aa94SToomas Soome 	uint32_t	i, j;
28647c478bd9Sstevel@tonic-gate 	uint32_t	dout;
28657c478bd9Sstevel@tonic-gate 	uint16_t	word;
28667c478bd9Sstevel@tonic-gate 	uint8_t		rom_addr;
28677c478bd9Sstevel@tonic-gate 	uint8_t		bit;
28687c478bd9Sstevel@tonic-gate 
28697c478bd9Sstevel@tonic-gate 
28707c478bd9Sstevel@tonic-gate 	rom_addr = 0;
28717c478bd9Sstevel@tonic-gate 	for (i = 0; i <	maxlen; i += 2) {
28724ab75253Smrj 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
287317de24c9Svb 		    READ_OP | SEL_ROM);
28747c478bd9Sstevel@tonic-gate 		drv_nsecwait(30);
28754ab75253Smrj 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
287617de24c9Svb 		    READ_OP | SEL_ROM | SEL_CHIP);
28777c478bd9Sstevel@tonic-gate 		drv_nsecwait(50);
28784ab75253Smrj 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
287917de24c9Svb 		    READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
28807c478bd9Sstevel@tonic-gate 		drv_nsecwait(250);
28814ab75253Smrj 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
288217de24c9Svb 		    READ_OP | SEL_ROM | SEL_CHIP);
28837c478bd9Sstevel@tonic-gate 		drv_nsecwait(100);
28847c478bd9Sstevel@tonic-gate 
28857c478bd9Sstevel@tonic-gate 		/* command */
28864ab75253Smrj 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
288717de24c9Svb 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
28887c478bd9Sstevel@tonic-gate 		drv_nsecwait(150);
28894ab75253Smrj 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
289017de24c9Svb 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK);
28917c478bd9Sstevel@tonic-gate 		drv_nsecwait(250);
28924ab75253Smrj 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
289317de24c9Svb 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
28947c478bd9Sstevel@tonic-gate 		drv_nsecwait(250);
28954ab75253Smrj 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
289617de24c9Svb 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN | SEL_CLK);
28977c478bd9Sstevel@tonic-gate 		drv_nsecwait(250);
28984ab75253Smrj 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
289917de24c9Svb 		    READ_OP | SEL_ROM | SEL_CHIP | DATA_IN);
29007c478bd9Sstevel@tonic-gate 		drv_nsecwait(100);
29014ab75253Smrj 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
290217de24c9Svb 		    READ_OP | SEL_ROM | SEL_CHIP);
29037c478bd9Sstevel@tonic-gate 		drv_nsecwait(150);
29044ab75253Smrj 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
290517de24c9Svb 		    READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
29067c478bd9Sstevel@tonic-gate 		drv_nsecwait(250);
29074ab75253Smrj 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
290817de24c9Svb 		    READ_OP | SEL_ROM | SEL_CHIP);
29097c478bd9Sstevel@tonic-gate 		drv_nsecwait(100);
29107c478bd9Sstevel@tonic-gate 
29117c478bd9Sstevel@tonic-gate 		/* Address */
29127c478bd9Sstevel@tonic-gate 		for (j = HIGH_ADDRESS_BIT; j >= 1; j >>= 1) {
29137c478bd9Sstevel@tonic-gate 			bit = (rom_addr & j) ? DATA_IN : 0;
29144ab75253Smrj 			ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
29157c478bd9Sstevel@tonic-gate 			    READ_OP | SEL_ROM | SEL_CHIP | bit);
29167c478bd9Sstevel@tonic-gate 			drv_nsecwait(150);
29174ab75253Smrj 			ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
29187c478bd9Sstevel@tonic-gate 			    READ_OP | SEL_ROM | SEL_CHIP | bit | SEL_CLK);
29197c478bd9Sstevel@tonic-gate 			drv_nsecwait(250);
29204ab75253Smrj 			ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
29217c478bd9Sstevel@tonic-gate 			    READ_OP | SEL_ROM | SEL_CHIP | bit);
29227c478bd9Sstevel@tonic-gate 			drv_nsecwait(100);
29237c478bd9Sstevel@tonic-gate 		}
29247c478bd9Sstevel@tonic-gate 		drv_nsecwait(150);
29257c478bd9Sstevel@tonic-gate 
29267c478bd9Sstevel@tonic-gate 		/* Data */
29277c478bd9Sstevel@tonic-gate 		word = 0;
29287c478bd9Sstevel@tonic-gate 		for (j = 0x8000; j >= 1; j >>= 1) {
29294ab75253Smrj 			ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
293017de24c9Svb 			    READ_OP | SEL_ROM | SEL_CHIP | SEL_CLK);
29317c478bd9Sstevel@tonic-gate 			drv_nsecwait(100);
29324ab75253Smrj 			dout = ddi_get32(io_handle,
293317de24c9Svb 			    REG32(io_reg, ETHER_ROM_REG));
29347c478bd9Sstevel@tonic-gate 			drv_nsecwait(150);
29357c478bd9Sstevel@tonic-gate 			if (dout & DATA_OUT)
29367c478bd9Sstevel@tonic-gate 				word |= j;
29374ab75253Smrj 			ddi_put32(io_handle,
293817de24c9Svb 			    REG32(io_reg, ETHER_ROM_REG),
293917de24c9Svb 			    READ_OP | SEL_ROM | SEL_CHIP);
29407c478bd9Sstevel@tonic-gate 			drv_nsecwait(250);
29417c478bd9Sstevel@tonic-gate 		}
29427c478bd9Sstevel@tonic-gate 		addr[i] = (word & 0x0000FF);
29437c478bd9Sstevel@tonic-gate 		addr[i + 1] = (word >> 8);
29447c478bd9Sstevel@tonic-gate 		rom_addr++;
29454ab75253Smrj 		ddi_put32(io_handle, REG32(io_reg, ETHER_ROM_REG),
294617de24c9Svb 		    READ_OP | SEL_ROM);
29477c478bd9Sstevel@tonic-gate 		drv_nsecwait(100);
29487c478bd9Sstevel@tonic-gate 	}
29497c478bd9Sstevel@tonic-gate }
29507c478bd9Sstevel@tonic-gate 
29517c478bd9Sstevel@tonic-gate 
29527c478bd9Sstevel@tonic-gate /*
29537c478bd9Sstevel@tonic-gate  * XXX NEEDSWORK
29547c478bd9Sstevel@tonic-gate  *
29557c478bd9Sstevel@tonic-gate  * Some lame multiport cards have only one SROM, which can be accessed
29567c478bd9Sstevel@tonic-gate  * only from the "first" 21x4x chip, whichever that one is.  If we can't
29577c478bd9Sstevel@tonic-gate  * get at our SROM, we look for its contents in a property instead, which
29587c478bd9Sstevel@tonic-gate  * we rely on the bootstrap to have properly set.
29597c478bd9Sstevel@tonic-gate  * #ifdef BUG_4010796
29607c478bd9Sstevel@tonic-gate  * We also have a hack to try to set it ourselves, when the "first" port
29617c478bd9Sstevel@tonic-gate  * attaches, if it has not already been properly set.  However, this method
29627c478bd9Sstevel@tonic-gate  * is not reliable, since it makes the unwarrented assumption that the
29637c478bd9Sstevel@tonic-gate  * "first" port will attach first.
29647c478bd9Sstevel@tonic-gate  * #endif
29657c478bd9Sstevel@tonic-gate  */
29667c478bd9Sstevel@tonic-gate 
29677c478bd9Sstevel@tonic-gate static int
get_alternative_srom_image(dev_info_t * devinfo,uchar_t * vi,int len)29687c478bd9Sstevel@tonic-gate get_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len)
29697c478bd9Sstevel@tonic-gate {
29707c478bd9Sstevel@tonic-gate 	int	l = len;
29717c478bd9Sstevel@tonic-gate 
29727c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
29737c478bd9Sstevel@tonic-gate 	    "DNET_SROM", (caddr_t)vi, &len) != DDI_PROP_SUCCESS &&
29747c478bd9Sstevel@tonic-gate 	    (len = l) && ddi_getlongprop_buf(DDI_DEV_T_ANY,
29757c478bd9Sstevel@tonic-gate 	    ddi_get_parent(devinfo), DDI_PROP_DONTPASS, "DNET_SROM",
29767c478bd9Sstevel@tonic-gate 	    (caddr_t)vi, &len) != DDI_PROP_SUCCESS)
29777c478bd9Sstevel@tonic-gate 		return (-1);	/* Can't find it! */
29787c478bd9Sstevel@tonic-gate 
29797c478bd9Sstevel@tonic-gate 	/*
29807c478bd9Sstevel@tonic-gate 	 * The return value from this routine specifies which port number
29817c478bd9Sstevel@tonic-gate 	 * we are.  The primary port is denoted port 0.  On a QUAD card we
29827c478bd9Sstevel@tonic-gate 	 * should return 1, 2, and 3 from this routine.  The return value
29837c478bd9Sstevel@tonic-gate 	 * is used to modify the ethernet address from the SROM data.
29847c478bd9Sstevel@tonic-gate 	 */
29857c478bd9Sstevel@tonic-gate 
29867c478bd9Sstevel@tonic-gate #ifdef BUG_4010796
29877c478bd9Sstevel@tonic-gate 	{
29887c478bd9Sstevel@tonic-gate 	/*
29897c478bd9Sstevel@tonic-gate 	 * For the present, we remember the device number of our primary
29907c478bd9Sstevel@tonic-gate 	 * sibling and hope we and our other siblings are consecutively
29917c478bd9Sstevel@tonic-gate 	 * numbered up from there.  In the future perhaps the bootstrap
29927c478bd9Sstevel@tonic-gate 	 * will pass us the necessary information telling us which physical
29937c478bd9Sstevel@tonic-gate 	 * port we really are.
29947c478bd9Sstevel@tonic-gate 	 */
29957c478bd9Sstevel@tonic-gate 	pci_regspec_t	*assignp;
29967c478bd9Sstevel@tonic-gate 	int		assign_len;
2997*f879aa94SToomas Soome 	int		devnum;
29987c478bd9Sstevel@tonic-gate 	int		primary_devnum;
29997c478bd9Sstevel@tonic-gate 
30007c478bd9Sstevel@tonic-gate 	primary_devnum = ddi_getprop(DDI_DEV_T_ANY, devinfo, 0,
30017c478bd9Sstevel@tonic-gate 	    "DNET_DEVNUM", -1);
30027c478bd9Sstevel@tonic-gate 	if (primary_devnum == -1)
30037c478bd9Sstevel@tonic-gate 		return (1);	/* XXX NEEDSWORK -- We have no better idea */
30047c478bd9Sstevel@tonic-gate 
30057c478bd9Sstevel@tonic-gate 	if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
30067c478bd9Sstevel@tonic-gate 	    "assigned-addresses", (caddr_t)&assignp,
30077c478bd9Sstevel@tonic-gate 	    &assign_len)) != DDI_PROP_SUCCESS)
30087c478bd9Sstevel@tonic-gate 		return (1);	/* XXX NEEDSWORK -- We have no better idea */
30097c478bd9Sstevel@tonic-gate 
30107c478bd9Sstevel@tonic-gate 	devnum = PCI_REG_DEV_G(assignp->pci_phys_hi);
30117c478bd9Sstevel@tonic-gate 	kmem_free(assignp, assign_len);
30127c478bd9Sstevel@tonic-gate 	return (devnum - primary_devnum);
30137c478bd9Sstevel@tonic-gate 	}
30147c478bd9Sstevel@tonic-gate #else
30157c478bd9Sstevel@tonic-gate 	return (1);	/* XXX NEEDSWORK -- We have no better idea */
30167c478bd9Sstevel@tonic-gate #endif
30177c478bd9Sstevel@tonic-gate }
30187c478bd9Sstevel@tonic-gate 
30197c478bd9Sstevel@tonic-gate 
30207c478bd9Sstevel@tonic-gate #ifdef BUG_4010796
30217c478bd9Sstevel@tonic-gate static void
set_alternative_srom_image(dev_info_t * devinfo,uchar_t * vi,int len)30227c478bd9Sstevel@tonic-gate set_alternative_srom_image(dev_info_t *devinfo, uchar_t *vi, int len)
30237c478bd9Sstevel@tonic-gate {
3024*f879aa94SToomas Soome 	int		proplen;
30257c478bd9Sstevel@tonic-gate 	pci_regspec_t	*assignp;
30267c478bd9Sstevel@tonic-gate 	int		assign_len;
3027*f879aa94SToomas Soome 	int		devnum;
30287c478bd9Sstevel@tonic-gate 
30297c478bd9Sstevel@tonic-gate 	if (ddi_getproplen(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
30307c478bd9Sstevel@tonic-gate 	    "DNET_SROM", &proplen) == DDI_PROP_SUCCESS ||
30317c478bd9Sstevel@tonic-gate 	    ddi_getproplen(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
30327c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "DNET_SROM", &proplen) == DDI_PROP_SUCCESS)
30337c478bd9Sstevel@tonic-gate 		return;		/* Already done! */
30347c478bd9Sstevel@tonic-gate 
30357c478bd9Sstevel@tonic-gate 	/* function return value ignored */
30367c478bd9Sstevel@tonic-gate 	(void) ddi_prop_update_byte_array(DDI_DEV_T_NONE,
30377c478bd9Sstevel@tonic-gate 	    ddi_get_parent(devinfo), "DNET_SROM", (uchar_t *)vi, len);
30387c478bd9Sstevel@tonic-gate 	(void) ddi_prop_update_string(DDI_DEV_T_NONE, devinfo,
30397c478bd9Sstevel@tonic-gate 	    "DNET_HACK", "hack");
30407c478bd9Sstevel@tonic-gate 
30417c478bd9Sstevel@tonic-gate 	if ((ddi_getlongprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
30427c478bd9Sstevel@tonic-gate 	    "assigned-addresses", (caddr_t)&assignp,
30437c478bd9Sstevel@tonic-gate 	    &assign_len)) == DDI_PROP_SUCCESS) {
30447c478bd9Sstevel@tonic-gate 		devnum = PCI_REG_DEV_G(assignp->pci_phys_hi);
30457c478bd9Sstevel@tonic-gate 		kmem_free(assignp, assign_len);
30467c478bd9Sstevel@tonic-gate 		/* function return value ignored */
30477c478bd9Sstevel@tonic-gate 		(void) ddi_prop_update_int(DDI_DEV_T_NONE,
30487c478bd9Sstevel@tonic-gate 		    ddi_get_parent(devinfo), "DNET_DEVNUM", devnum);
30497c478bd9Sstevel@tonic-gate 	}
30507c478bd9Sstevel@tonic-gate }
30517c478bd9Sstevel@tonic-gate #endif
30527c478bd9Sstevel@tonic-gate 
30537c478bd9Sstevel@tonic-gate /*
30547c478bd9Sstevel@tonic-gate  *	========== SROM Parsing Routines ==========
30557c478bd9Sstevel@tonic-gate  */
30567c478bd9Sstevel@tonic-gate 
30577c478bd9Sstevel@tonic-gate static int
check_srom_valid(uchar_t * vi)30587c478bd9Sstevel@tonic-gate check_srom_valid(uchar_t *vi)
30597c478bd9Sstevel@tonic-gate {
30607c478bd9Sstevel@tonic-gate 	int		word, bit;
30617c478bd9Sstevel@tonic-gate 	uint8_t		crc;
30627c478bd9Sstevel@tonic-gate 	uint16_t	*wvi;		/* word16 pointer to vendor info */
30637c478bd9Sstevel@tonic-gate 	uint16_t	bitval;
30647c478bd9Sstevel@tonic-gate 
30657c478bd9Sstevel@tonic-gate 	/* verify that the number of controllers on the card is within range */
30667c478bd9Sstevel@tonic-gate 	if (vi[SROM_ADAPTER_CNT] < 1 || vi[SROM_ADAPTER_CNT] > MAX_ADAPTERS)
30677c478bd9Sstevel@tonic-gate 		return (0);
30687c478bd9Sstevel@tonic-gate 
30697c478bd9Sstevel@tonic-gate 	/*
30707c478bd9Sstevel@tonic-gate 	 * version 1 and 3 of this card did not check the id block CRC value
30717c478bd9Sstevel@tonic-gate 	 * and this can't be changed without retesting every supported card
30727c478bd9Sstevel@tonic-gate 	 *
30737c478bd9Sstevel@tonic-gate 	 * however version 4 of the SROM can have this test applied
30747c478bd9Sstevel@tonic-gate 	 * without fear of breaking something that used to work.
30757c478bd9Sstevel@tonic-gate 	 * the CRC algorithm is taken from the Intel document
30767c478bd9Sstevel@tonic-gate 	 *	"21x4 Serial ROM Format"
30777c478bd9Sstevel@tonic-gate 	 *	version 4.09
30787c478bd9Sstevel@tonic-gate 	 *	3-Mar-1999
30797c478bd9Sstevel@tonic-gate 	 */
30807c478bd9Sstevel@tonic-gate 
30817c478bd9Sstevel@tonic-gate 	switch (vi[SROM_VERSION]) {
30827c478bd9Sstevel@tonic-gate 	case 1:
30837c478bd9Sstevel@tonic-gate 	    /* fallthru */
30847c478bd9Sstevel@tonic-gate 	case 3:
308517de24c9Svb 		return (vi[SROM_MBZ] == 0 &&	/* must be zero */
308617de24c9Svb 		    vi[SROM_MBZ2] == 0 &&	/* must be zero */
308717de24c9Svb 		    vi[SROM_MBZ3] == 0);	/* must be zero */
30887c478bd9Sstevel@tonic-gate 
30897c478bd9Sstevel@tonic-gate 	case 4:
309017de24c9Svb 		wvi = (uint16_t *)vi;
309117de24c9Svb 		crc = 0xff;
309217de24c9Svb 		for (word = 0; word < 9; word++)
309317de24c9Svb 			for (bit = 15; bit >= 0; bit--) {
309417de24c9Svb 				if (word == 8 && bit == 7)
309517de24c9Svb 					return (crc == vi[16]);
309617de24c9Svb 				bitval =
309717de24c9Svb 				    ((wvi[word] >> bit) & 1) ^ ((crc >> 7) & 1);
309817de24c9Svb 				crc <<= 1;
309917de24c9Svb 				if (bitval == 1) {
310017de24c9Svb 					crc ^= 7;
310117de24c9Svb 				}
310217de24c9Svb 			}
3103daefc4e3SToomas Soome 		/* FALLTHROUGH */
31047c478bd9Sstevel@tonic-gate 
31057c478bd9Sstevel@tonic-gate 	default:
31067c478bd9Sstevel@tonic-gate 		return (0);
31077c478bd9Sstevel@tonic-gate 	}
31087c478bd9Sstevel@tonic-gate }
31097c478bd9Sstevel@tonic-gate 
31107c478bd9Sstevel@tonic-gate /*
31117c478bd9Sstevel@tonic-gate  *	========== Active Media Determination Routines ==========
31127c478bd9Sstevel@tonic-gate  */
31137c478bd9Sstevel@tonic-gate 
31147c478bd9Sstevel@tonic-gate /* This routine is also called for V3 Compact and extended type 0 SROMs */
31157c478bd9Sstevel@tonic-gate static int
is_fdmedia(int media)31167c478bd9Sstevel@tonic-gate is_fdmedia(int media)
31177c478bd9Sstevel@tonic-gate {
31187c478bd9Sstevel@tonic-gate 	if (media == MEDIA_TP_FD || media == MEDIA_SYM_SCR_FD)
31197c478bd9Sstevel@tonic-gate 		return (1);
31207c478bd9Sstevel@tonic-gate 	else
31217c478bd9Sstevel@tonic-gate 		return (0);
31227c478bd9Sstevel@tonic-gate }
31237c478bd9Sstevel@tonic-gate 
31247c478bd9Sstevel@tonic-gate /*
31257c478bd9Sstevel@tonic-gate  * "Linkset" is used to merge media that use the same link test check. So,
31267c478bd9Sstevel@tonic-gate  * if the TP link is added to the linkset, so is the TP Full duplex link.
31277c478bd9Sstevel@tonic-gate  * Used to avoid checking the same link status twice.
31287c478bd9Sstevel@tonic-gate  */
31297c478bd9Sstevel@tonic-gate static void
linkset_add(uint32_t * set,int media)31307c478bd9Sstevel@tonic-gate linkset_add(uint32_t *set, int media)
31317c478bd9Sstevel@tonic-gate {
31327c478bd9Sstevel@tonic-gate 	if (media == MEDIA_TP_FD || media == MEDIA_TP)
31337c478bd9Sstevel@tonic-gate 		*set |= (1UL<<MEDIA_TP_FD) | (1UL<<MEDIA_TP);
31347c478bd9Sstevel@tonic-gate 	else if (media == MEDIA_SYM_SCR_FD || media == MEDIA_SYM_SCR)
31357c478bd9Sstevel@tonic-gate 		*set |= (1UL<<MEDIA_SYM_SCR_FD) | (1UL<<MEDIA_SYM_SCR);
31367c478bd9Sstevel@tonic-gate 	else *set |= 1UL<<media;
31377c478bd9Sstevel@tonic-gate }
31387c478bd9Sstevel@tonic-gate static int
linkset_isset(uint32_t linkset,int media)31397c478bd9Sstevel@tonic-gate linkset_isset(uint32_t linkset, int media)
31407c478bd9Sstevel@tonic-gate {
31417c478bd9Sstevel@tonic-gate 	return (((1UL<<media)  & linkset) ? 1:0);
31427c478bd9Sstevel@tonic-gate }
31437c478bd9Sstevel@tonic-gate 
31447c478bd9Sstevel@tonic-gate /*
31457c478bd9Sstevel@tonic-gate  * The following code detects which Media is connected for 21041/21140
31467c478bd9Sstevel@tonic-gate  * Expect to change this code to support new 21140 variants.
31477c478bd9Sstevel@tonic-gate  * find_active_media() - called with intrlock held.
31487c478bd9Sstevel@tonic-gate  */
31497c478bd9Sstevel@tonic-gate static void
find_active_media(struct dnetinstance * dnetp)315098e8d175SSteven Stallion find_active_media(struct dnetinstance *dnetp)
31517c478bd9Sstevel@tonic-gate {
31527c478bd9Sstevel@tonic-gate 	int i;
31537c478bd9Sstevel@tonic-gate 	media_block_t *block;
31547c478bd9Sstevel@tonic-gate 	media_block_t *best_allowed = NULL;
31557c478bd9Sstevel@tonic-gate 	media_block_t *hd_found = NULL;
31567c478bd9Sstevel@tonic-gate 	media_block_t *fd_found = NULL;
31577c478bd9Sstevel@tonic-gate 	LEAF_FORMAT *leaf = &dnetp->sr.leaf[dnetp->leaf];
31587c478bd9Sstevel@tonic-gate 	uint32_t checked = 0, links_up = 0;
31597c478bd9Sstevel@tonic-gate 
31607c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
316198e8d175SSteven Stallion 
31627c478bd9Sstevel@tonic-gate 	dnetp->selected_media_block = leaf->default_block;
31637c478bd9Sstevel@tonic-gate 
31647c478bd9Sstevel@tonic-gate 	if (dnetp->phyaddr != -1) {
31657c478bd9Sstevel@tonic-gate 		dnetp->selected_media_block = leaf->mii_block;
316698e8d175SSteven Stallion 		setup_block(dnetp);
31677c478bd9Sstevel@tonic-gate 
31687c478bd9Sstevel@tonic-gate 		if (ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
31697c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "portmon", 1)) {
31707c478bd9Sstevel@tonic-gate 			/* XXX return value ignored */
31717c478bd9Sstevel@tonic-gate 			(void) mii_start_portmon(dnetp->mii, dnet_mii_link_cb,
31727c478bd9Sstevel@tonic-gate 			    &dnetp->intrlock);
31737c478bd9Sstevel@tonic-gate 			/*
31747c478bd9Sstevel@tonic-gate 			 * If the port monitor detects the link is already
31757c478bd9Sstevel@tonic-gate 			 * up, there is no point going through the rest of the
31767c478bd9Sstevel@tonic-gate 			 * link sense
31777c478bd9Sstevel@tonic-gate 			 */
31787c478bd9Sstevel@tonic-gate 			if (dnetp->mii_up) {
31797c478bd9Sstevel@tonic-gate 				return;
31807c478bd9Sstevel@tonic-gate 			}
31817c478bd9Sstevel@tonic-gate 		}
31827c478bd9Sstevel@tonic-gate 	}
31837c478bd9Sstevel@tonic-gate 
31847c478bd9Sstevel@tonic-gate 	/*
31857c478bd9Sstevel@tonic-gate 	 * Media is searched for in order of Precedence. This DEC SROM spec
31867c478bd9Sstevel@tonic-gate 	 * tells us that the first media entry in the SROM is the lowest
31877c478bd9Sstevel@tonic-gate 	 * precedence and should be checked last. This is why we go to the last
31887c478bd9Sstevel@tonic-gate 	 * Media block and work back to the beginning.
31897c478bd9Sstevel@tonic-gate 	 *
31907c478bd9Sstevel@tonic-gate 	 * However, some older SROMs (Cogent EM110's etc.) have this the wrong
31917c478bd9Sstevel@tonic-gate 	 * way around. As a result, following the SROM spec would result in a
31927c478bd9Sstevel@tonic-gate 	 * 10 link being chosen over a 100 link if both media are available.
31937c478bd9Sstevel@tonic-gate 	 * So we continue trying the media until we have at least tried the
31947c478bd9Sstevel@tonic-gate 	 * DEFAULT media.
31957c478bd9Sstevel@tonic-gate 	 */
31967c478bd9Sstevel@tonic-gate 
31977c478bd9Sstevel@tonic-gate 	/* Search for an active medium, and select it */
31987c478bd9Sstevel@tonic-gate 	for (block = leaf->block + leaf->block_count  - 1;
31997c478bd9Sstevel@tonic-gate 	    block >= leaf->block; block--) {
32007c478bd9Sstevel@tonic-gate 		int media = block->media_code;
32017c478bd9Sstevel@tonic-gate 
32027c478bd9Sstevel@tonic-gate 		/* User settings disallow selection of this block */
32037c478bd9Sstevel@tonic-gate 		if (dnetp->disallowed_media & (1UL<<media))
32047c478bd9Sstevel@tonic-gate 			continue;
32057c478bd9Sstevel@tonic-gate 
32067c478bd9Sstevel@tonic-gate 		/* We may not be able to pick the default */
32077c478bd9Sstevel@tonic-gate 		if (best_allowed == NULL || block == leaf->default_block)
32087c478bd9Sstevel@tonic-gate 			best_allowed = block;
32097c478bd9Sstevel@tonic-gate #ifdef DEBUG
32107c478bd9Sstevel@tonic-gate 		if (dnetdebug & DNETSENSE)
321117de24c9Svb 			cmn_err(CE_NOTE, "Testing %s medium (block type %d)",
321217de24c9Svb 			    media_str[media], block->type);
32137c478bd9Sstevel@tonic-gate #endif
32147c478bd9Sstevel@tonic-gate 
32157c478bd9Sstevel@tonic-gate 		dnetp->selected_media_block = block;
32167c478bd9Sstevel@tonic-gate 		switch (block->type) {
32177c478bd9Sstevel@tonic-gate 
32187c478bd9Sstevel@tonic-gate 		case 2: /* SIA Media block: Best we can do is send a packet */
321998e8d175SSteven Stallion 			setup_block(dnetp);
322098e8d175SSteven Stallion 			if (send_test_packet(dnetp)) {
32217c478bd9Sstevel@tonic-gate 				if (!is_fdmedia(media))
32227c478bd9Sstevel@tonic-gate 					return;
32237c478bd9Sstevel@tonic-gate 				if (!fd_found)
32247c478bd9Sstevel@tonic-gate 					fd_found = block;
32257c478bd9Sstevel@tonic-gate 			}
32267c478bd9Sstevel@tonic-gate 			break;
32277c478bd9Sstevel@tonic-gate 
32287c478bd9Sstevel@tonic-gate 		/* SYM/SCR or TP block: Use the link-sense bits */
32297c478bd9Sstevel@tonic-gate 		case 0:
32307c478bd9Sstevel@tonic-gate 			if (!linkset_isset(checked, media)) {
32317c478bd9Sstevel@tonic-gate 				linkset_add(&checked, media);
32327c478bd9Sstevel@tonic-gate 				if (((media == MEDIA_BNC ||
32337c478bd9Sstevel@tonic-gate 				    media == MEDIA_AUI) &&
323498e8d175SSteven Stallion 				    send_test_packet(dnetp)) ||
323598e8d175SSteven Stallion 				    dnet_link_sense(dnetp))
32367c478bd9Sstevel@tonic-gate 					linkset_add(&links_up, media);
32377c478bd9Sstevel@tonic-gate 			}
32387c478bd9Sstevel@tonic-gate 
32397c478bd9Sstevel@tonic-gate 			if (linkset_isset(links_up, media)) {
32407c478bd9Sstevel@tonic-gate 				/*
32417c478bd9Sstevel@tonic-gate 				 * Half Duplex is *always* the favoured media.
32427c478bd9Sstevel@tonic-gate 				 * Full Duplex can be set and forced via the
32437c478bd9Sstevel@tonic-gate 				 * conf file.
32447c478bd9Sstevel@tonic-gate 				 */
32457c478bd9Sstevel@tonic-gate 				if (!is_fdmedia(media) &&
32467c478bd9Sstevel@tonic-gate 				    dnetp->selected_media_block ==
32477c478bd9Sstevel@tonic-gate 				    leaf->default_block) {
32487c478bd9Sstevel@tonic-gate 					/*
32497c478bd9Sstevel@tonic-gate 					 * Cogent cards have the media in
32507c478bd9Sstevel@tonic-gate 					 * opposite order to the spec.,
32517c478bd9Sstevel@tonic-gate 					 * this code forces the media test to
32527c478bd9Sstevel@tonic-gate 					 * keep going until the default media
32537c478bd9Sstevel@tonic-gate 					 * is tested.
32547c478bd9Sstevel@tonic-gate 					 *
32557c478bd9Sstevel@tonic-gate 					 * In Cogent case, 10, 10FD, 100FD, 100
32567c478bd9Sstevel@tonic-gate 					 * 100 is the default but 10 could have
32577c478bd9Sstevel@tonic-gate 					 * been detected and would have been
32587c478bd9Sstevel@tonic-gate 					 * chosen but now we force it through to
32597c478bd9Sstevel@tonic-gate 					 * 100.
32607c478bd9Sstevel@tonic-gate 					 */
326198e8d175SSteven Stallion 					setup_block(dnetp);
32627c478bd9Sstevel@tonic-gate 					return;
32637c478bd9Sstevel@tonic-gate 				} else if (!is_fdmedia(media)) {
32647c478bd9Sstevel@tonic-gate 					/*
32657c478bd9Sstevel@tonic-gate 					 * This allows all the others to work
32667c478bd9Sstevel@tonic-gate 					 * properly by remembering the media
32677c478bd9Sstevel@tonic-gate 					 * that works and not defaulting to
32687c478bd9Sstevel@tonic-gate 					 * a FD link.
32697c478bd9Sstevel@tonic-gate 					 */
32707c478bd9Sstevel@tonic-gate 						if (hd_found == NULL)
32717c478bd9Sstevel@tonic-gate 							hd_found = block;
32727c478bd9Sstevel@tonic-gate 				} else if (fd_found == NULL) {
32737c478bd9Sstevel@tonic-gate 					/*
32747c478bd9Sstevel@tonic-gate 					 * No media have already been found
32757c478bd9Sstevel@tonic-gate 					 * so far, this is FD, it works so
32767c478bd9Sstevel@tonic-gate 					 * remember it and if no others are
32777c478bd9Sstevel@tonic-gate 					 * detected, use it.
32787c478bd9Sstevel@tonic-gate 					 */
32797c478bd9Sstevel@tonic-gate 					fd_found = block;
32807c478bd9Sstevel@tonic-gate 				}
32817c478bd9Sstevel@tonic-gate 			}
32827c478bd9Sstevel@tonic-gate 			break;
32837c478bd9Sstevel@tonic-gate 
32847c478bd9Sstevel@tonic-gate 		/*
32857c478bd9Sstevel@tonic-gate 		 * MII block: May take up to a second or so to settle if
32867c478bd9Sstevel@tonic-gate 		 * setup causes a PHY reset
32877c478bd9Sstevel@tonic-gate 		 */
32887c478bd9Sstevel@tonic-gate 		case 1: case 3:
328998e8d175SSteven Stallion 			setup_block(dnetp);
32907c478bd9Sstevel@tonic-gate 			for (i = 0; ; i++) {
32917c478bd9Sstevel@tonic-gate 				if (mii_linkup(dnetp->mii, dnetp->phyaddr)) {
32927c478bd9Sstevel@tonic-gate 					/* XXX function return value ignored */
32937c478bd9Sstevel@tonic-gate 					(void) mii_getspeed(dnetp->mii,
329417de24c9Svb 					    dnetp->phyaddr,
329517de24c9Svb 					    &dnetp->mii_speed,
329617de24c9Svb 					    &dnetp->mii_duplex);
32977c478bd9Sstevel@tonic-gate 					dnetp->mii_up = 1;
32987c478bd9Sstevel@tonic-gate 					leaf->mii_block = block;
32997c478bd9Sstevel@tonic-gate 					return;
33007c478bd9Sstevel@tonic-gate 				}
33017c478bd9Sstevel@tonic-gate 				if (i == 10)
33027c478bd9Sstevel@tonic-gate 					break;
33037c478bd9Sstevel@tonic-gate 				delay(drv_usectohz(150000));
33047c478bd9Sstevel@tonic-gate 			}
33057c478bd9Sstevel@tonic-gate 			dnetp->mii_up = 0;
33067c478bd9Sstevel@tonic-gate 			break;
33077c478bd9Sstevel@tonic-gate 		}
33087c478bd9Sstevel@tonic-gate 	} /* for loop */
33097c478bd9Sstevel@tonic-gate 	if (hd_found) {
33107c478bd9Sstevel@tonic-gate 		dnetp->selected_media_block = hd_found;
33117c478bd9Sstevel@tonic-gate 	} else if (fd_found) {
33127c478bd9Sstevel@tonic-gate 		dnetp->selected_media_block = fd_found;
33137c478bd9Sstevel@tonic-gate 	} else {
33147c478bd9Sstevel@tonic-gate 		if (best_allowed == NULL)
33157c478bd9Sstevel@tonic-gate 			best_allowed = leaf->default_block;
33167c478bd9Sstevel@tonic-gate 		dnetp->selected_media_block = best_allowed;
33177c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "!dnet: Default media selected\n");
33187c478bd9Sstevel@tonic-gate 	}
331998e8d175SSteven Stallion 	setup_block(dnetp);
33207c478bd9Sstevel@tonic-gate }
33217c478bd9Sstevel@tonic-gate 
33227c478bd9Sstevel@tonic-gate /*
33237c478bd9Sstevel@tonic-gate  * Do anything neccessary to select the selected_media_block.
33247c478bd9Sstevel@tonic-gate  * setup_block() - called with intrlock held.
33257c478bd9Sstevel@tonic-gate  */
33267c478bd9Sstevel@tonic-gate static void
setup_block(struct dnetinstance * dnetp)332798e8d175SSteven Stallion setup_block(struct dnetinstance *dnetp)
33287c478bd9Sstevel@tonic-gate {
332998e8d175SSteven Stallion 	dnet_reset_board(dnetp);
333098e8d175SSteven Stallion 	dnet_init_board(dnetp);
33317c478bd9Sstevel@tonic-gate 	/* XXX function return value ignored */
333298e8d175SSteven Stallion 	(void) dnet_start(dnetp);
33337c478bd9Sstevel@tonic-gate }
33347c478bd9Sstevel@tonic-gate 
33357c478bd9Sstevel@tonic-gate /* dnet_link_sense() - called with intrlock held */
33367c478bd9Sstevel@tonic-gate static int
dnet_link_sense(struct dnetinstance * dnetp)333798e8d175SSteven Stallion dnet_link_sense(struct dnetinstance *dnetp)
33387c478bd9Sstevel@tonic-gate {
33397c478bd9Sstevel@tonic-gate 	/*
33407c478bd9Sstevel@tonic-gate 	 * This routine makes use of the command word from the srom config.
33417c478bd9Sstevel@tonic-gate 	 * Details of the auto-sensing information contained in this can
33427c478bd9Sstevel@tonic-gate 	 * be found in the "Digital Semiconductor 21X4 Serial ROM Format v3.03"
33437c478bd9Sstevel@tonic-gate 	 * spec. Section 4.3.2.1, and 4.5.2.1.3
33447c478bd9Sstevel@tonic-gate 	 */
33457c478bd9Sstevel@tonic-gate 	media_block_t *block = dnetp->selected_media_block;
33467c478bd9Sstevel@tonic-gate 	uint32_t link, status, mask, polarity;
33477c478bd9Sstevel@tonic-gate 	int settletime, stabletime, waittime, upsamples;
33487c478bd9Sstevel@tonic-gate 	int delay_100, delay_10;
33497c478bd9Sstevel@tonic-gate 
33507c478bd9Sstevel@tonic-gate 
33517c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
33527c478bd9Sstevel@tonic-gate 	/* Don't autosense if the medium does not support it */
33537c478bd9Sstevel@tonic-gate 	if (block->command & (1 << 15)) {
33547c478bd9Sstevel@tonic-gate 		/* This should be the default block */
33557c478bd9Sstevel@tonic-gate 		if (block->command & (1UL<<14))
33567c478bd9Sstevel@tonic-gate 			dnetp->sr.leaf[dnetp->leaf].default_block = block;
33577c478bd9Sstevel@tonic-gate 		return (0);
33587c478bd9Sstevel@tonic-gate 	}
33597c478bd9Sstevel@tonic-gate 
33607c478bd9Sstevel@tonic-gate 	delay_100 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
33617c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "autosense-delay-100", 2000);
33627c478bd9Sstevel@tonic-gate 
33637c478bd9Sstevel@tonic-gate 	delay_10 = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
33647c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "autosense-delay-10", 400);
33657c478bd9Sstevel@tonic-gate 
33667c478bd9Sstevel@tonic-gate 	/*
33677c478bd9Sstevel@tonic-gate 	 * Scrambler may need to be disabled for link sensing
33687c478bd9Sstevel@tonic-gate 	 * to work
33697c478bd9Sstevel@tonic-gate 	 */
33707c478bd9Sstevel@tonic-gate 	dnetp->disable_scrambler = 1;
337198e8d175SSteven Stallion 	setup_block(dnetp);
33727c478bd9Sstevel@tonic-gate 	dnetp->disable_scrambler = 0;
33737c478bd9Sstevel@tonic-gate 
33747c478bd9Sstevel@tonic-gate 	if (block->media_code == MEDIA_TP || block->media_code == MEDIA_TP_FD)
33757c478bd9Sstevel@tonic-gate 		settletime = delay_10;
33767c478bd9Sstevel@tonic-gate 	else
33777c478bd9Sstevel@tonic-gate 		settletime = delay_100;
33787c478bd9Sstevel@tonic-gate 	stabletime = settletime / 4;
33797c478bd9Sstevel@tonic-gate 
33807c478bd9Sstevel@tonic-gate 	mask = 1 << ((block->command & CMD_MEDIABIT_MASK) >> 1);
33817c478bd9Sstevel@tonic-gate 	polarity = block->command & CMD_POL ? 0xffffffff : 0;
33827c478bd9Sstevel@tonic-gate 
33837c478bd9Sstevel@tonic-gate 	for (waittime = 0, upsamples = 0;
33847c478bd9Sstevel@tonic-gate 	    waittime <= settletime + stabletime && upsamples < 8;
33857c478bd9Sstevel@tonic-gate 	    waittime += stabletime/8) {
33867c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(stabletime*1000 / 8));
33877c478bd9Sstevel@tonic-gate 		status = read_gpr(dnetp);
33887c478bd9Sstevel@tonic-gate 		link = (status^polarity) & mask;
33897c478bd9Sstevel@tonic-gate 		if (link)
33907c478bd9Sstevel@tonic-gate 			upsamples++;
33917c478bd9Sstevel@tonic-gate 		else
33927c478bd9Sstevel@tonic-gate 			upsamples = 0;
33937c478bd9Sstevel@tonic-gate 	}
33947c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
33957c478bd9Sstevel@tonic-gate 	if (dnetdebug & DNETSENSE)
33967c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "%s upsamples:%d stat:%x polarity:%x "
33977c478bd9Sstevel@tonic-gate 		    "mask:%x link:%x",
33987c478bd9Sstevel@tonic-gate 		    upsamples == 8 ? "UP":"DOWN",
33997c478bd9Sstevel@tonic-gate 		    upsamples, status, polarity, mask, link);
34007c478bd9Sstevel@tonic-gate #endif
34017c478bd9Sstevel@tonic-gate 	if (upsamples == 8)
34027c478bd9Sstevel@tonic-gate 		return (1);
34037c478bd9Sstevel@tonic-gate 	return (0);
34047c478bd9Sstevel@tonic-gate }
34057c478bd9Sstevel@tonic-gate 
34067c478bd9Sstevel@tonic-gate static int
send_test_packet(struct dnetinstance * dnetp)340798e8d175SSteven Stallion send_test_packet(struct dnetinstance *dnetp)
34087c478bd9Sstevel@tonic-gate {
34097c478bd9Sstevel@tonic-gate 	int packet_delay;
34107c478bd9Sstevel@tonic-gate 	struct tx_desc_type *desc;
34117c478bd9Sstevel@tonic-gate 	int bufindex;
34127c478bd9Sstevel@tonic-gate 	int media_code = dnetp->selected_media_block->media_code;
34137c478bd9Sstevel@tonic-gate 	uint32_t del;
34147c478bd9Sstevel@tonic-gate 
34157c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
34167c478bd9Sstevel@tonic-gate 	/*
34177c478bd9Sstevel@tonic-gate 	 * For a successful test packet, the card must have settled into
34187c478bd9Sstevel@tonic-gate 	 * its current setting.  Almost all cards we've tested manage to
34197c478bd9Sstevel@tonic-gate 	 * do this with all media within 50ms.  However, the SMC 8432
34207c478bd9Sstevel@tonic-gate 	 * requires 300ms to settle into BNC mode.  We now only do this
34217c478bd9Sstevel@tonic-gate 	 * from attach, and we do sleeping delay() instead of drv_usecwait()
34227c478bd9Sstevel@tonic-gate 	 * so we hope this .2 second delay won't cause too much suffering.
34237c478bd9Sstevel@tonic-gate 	 * ALSO: with an autonegotiating hub, an aditional 1 second delay is
34247c478bd9Sstevel@tonic-gate 	 * required. This is done if the media type is TP
34257c478bd9Sstevel@tonic-gate 	 */
34267c478bd9Sstevel@tonic-gate 	if (media_code == MEDIA_TP || media_code == MEDIA_TP_FD) {
34277c478bd9Sstevel@tonic-gate 		packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
34287c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "test_packet_delay_tp", 1300000);
34297c478bd9Sstevel@tonic-gate 	} else {
34307c478bd9Sstevel@tonic-gate 		packet_delay = ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
34317c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, "test_packet_delay", 300000);
34327c478bd9Sstevel@tonic-gate 	}
34337c478bd9Sstevel@tonic-gate 	delay(drv_usectohz(packet_delay));
34347c478bd9Sstevel@tonic-gate 
34357c478bd9Sstevel@tonic-gate 	desc = dnetp->tx_desc;
34367c478bd9Sstevel@tonic-gate 
34377c478bd9Sstevel@tonic-gate 	bufindex = dnetp->tx_current_desc;
343898e8d175SSteven Stallion 	if (alloc_descriptor(dnetp) == FAILURE) {
34397c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "DNET: send_test_packet: alloc_descriptor"
34407c478bd9Sstevel@tonic-gate 		    "failed");
34417c478bd9Sstevel@tonic-gate 		return (0);
34427c478bd9Sstevel@tonic-gate 	}
34437c478bd9Sstevel@tonic-gate 
34447c478bd9Sstevel@tonic-gate 	/*
34457c478bd9Sstevel@tonic-gate 	 * use setup buffer as the buffer for the test packet
34467c478bd9Sstevel@tonic-gate 	 * instead of allocating one.
34477c478bd9Sstevel@tonic-gate 	 */
34487c478bd9Sstevel@tonic-gate 
34497c478bd9Sstevel@tonic-gate 	ASSERT(dnetp->setup_buf_vaddr != NULL);
34507c478bd9Sstevel@tonic-gate 	/* Put something decent in dest address so we don't annoy other cards */
34517c478bd9Sstevel@tonic-gate 	BCOPY((caddr_t)dnetp->curr_macaddr,
345217de24c9Svb 	    (caddr_t)dnetp->setup_buf_vaddr, ETHERADDRL);
34537c478bd9Sstevel@tonic-gate 	BCOPY((caddr_t)dnetp->curr_macaddr,
345417de24c9Svb 	    (caddr_t)dnetp->setup_buf_vaddr+ETHERADDRL, ETHERADDRL);
34557c478bd9Sstevel@tonic-gate 
34568ef10d20Sgd 	desc[bufindex].buffer1 = dnetp->setup_buf_paddr;
34577c478bd9Sstevel@tonic-gate 	desc[bufindex].desc1.buffer_size1 = SETUPBUF_SIZE;
34587c478bd9Sstevel@tonic-gate 	desc[bufindex].buffer2 = (uint32_t)(0);
34597c478bd9Sstevel@tonic-gate 	desc[bufindex].desc1.first_desc = 1;
34607c478bd9Sstevel@tonic-gate 	desc[bufindex].desc1.last_desc = 1;
34617c478bd9Sstevel@tonic-gate 	desc[bufindex].desc1.int_on_comp = 1;
34627c478bd9Sstevel@tonic-gate 	desc[bufindex].desc0.own = 1;
34637c478bd9Sstevel@tonic-gate 
34644ab75253Smrj 	ddi_put8(dnetp->io_handle, REG8(dnetp->io_reg, TX_POLL_REG),
346517de24c9Svb 	    TX_POLL_DEMAND);
34667c478bd9Sstevel@tonic-gate 
34677c478bd9Sstevel@tonic-gate 	/*
34687c478bd9Sstevel@tonic-gate 	 * Give enough time for the chip to transmit the packet
34697c478bd9Sstevel@tonic-gate 	 */
34707c478bd9Sstevel@tonic-gate #if 1
34717c478bd9Sstevel@tonic-gate 	del = 1000;
34727c478bd9Sstevel@tonic-gate 	while (desc[bufindex].desc0.own && --del)
34737c478bd9Sstevel@tonic-gate 		drv_usecwait(10);	/* quickly wait up to 10ms */
34747c478bd9Sstevel@tonic-gate 	if (desc[bufindex].desc0.own)
34757c478bd9Sstevel@tonic-gate 		delay(drv_usectohz(200000));	/* nicely wait a longer time */
34767c478bd9Sstevel@tonic-gate #else
34777c478bd9Sstevel@tonic-gate 	del = 0x10000;
34787c478bd9Sstevel@tonic-gate 	while (desc[bufindex].desc0.own && --del)
34797c478bd9Sstevel@tonic-gate 		drv_usecwait(10);
34807c478bd9Sstevel@tonic-gate #endif
34817c478bd9Sstevel@tonic-gate 
34827c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
34837c478bd9Sstevel@tonic-gate 	if (dnetdebug & DNETSENSE)
34847c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "desc0 bits = %u, %u, %u, %u, %u, %u",
348517de24c9Svb 		    desc[bufindex].desc0.own,
348617de24c9Svb 		    desc[bufindex].desc0.err_summary,
348717de24c9Svb 		    desc[bufindex].desc0.carrier_loss,
348817de24c9Svb 		    desc[bufindex].desc0.no_carrier,
348917de24c9Svb 		    desc[bufindex].desc0.late_collision,
349017de24c9Svb 		    desc[bufindex].desc0.link_fail);
34917c478bd9Sstevel@tonic-gate #endif
34927c478bd9Sstevel@tonic-gate 	if (desc[bufindex].desc0.own) /* it shouldn't take this long, error */
349317de24c9Svb 		return (0);
34947c478bd9Sstevel@tonic-gate 
34957c478bd9Sstevel@tonic-gate 	return (!desc[bufindex].desc0.err_summary);
34967c478bd9Sstevel@tonic-gate }
34977c478bd9Sstevel@tonic-gate 
34987c478bd9Sstevel@tonic-gate /* enable_interrupts - called with intrlock held */
34997c478bd9Sstevel@tonic-gate static void
enable_interrupts(struct dnetinstance * dnetp)350098e8d175SSteven Stallion enable_interrupts(struct dnetinstance *dnetp)
35017c478bd9Sstevel@tonic-gate {
35027c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
35037c478bd9Sstevel@tonic-gate 	/* Don't enable interrupts if they have been forced off */
35047c478bd9Sstevel@tonic-gate 	if (dnetp->interrupts_disabled)
35057c478bd9Sstevel@tonic-gate 		return;
35064ab75253Smrj 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, INT_MASK_REG),
350798e8d175SSteven Stallion 	    ABNORMAL_INTR_MASK | NORMAL_INTR_MASK | SYSTEM_ERROR_MASK |
35087c478bd9Sstevel@tonic-gate 	    (dnetp->timer.cb ? GPTIMER_INTR : 0) |
350998e8d175SSteven Stallion 	    RX_INTERRUPT_MASK |
351098e8d175SSteven Stallion 	    TX_INTERRUPT_MASK | TX_JABBER_MASK | TX_UNDERFLOW_MASK);
35117c478bd9Sstevel@tonic-gate }
35127c478bd9Sstevel@tonic-gate 
35137c478bd9Sstevel@tonic-gate /*
35147c478bd9Sstevel@tonic-gate  * Some older multiport cards are non-PCI compliant in their interrupt routing.
35157c478bd9Sstevel@tonic-gate  * Second and subsequent devices are incorrectly configured by the BIOS
35167c478bd9Sstevel@tonic-gate  * (either in their ILINE configuration or the MP Configuration Table for PC+MP
35177c478bd9Sstevel@tonic-gate  * systems).
351898e8d175SSteven Stallion  * The hack stops registering the interrupt routine for the FIRST
351998e8d175SSteven Stallion  * device on the adapter, and registers its own. It builds up a table
352098e8d175SSteven Stallion  * of dnetp structures for each device, and the new interrupt routine
352198e8d175SSteven Stallion  * calls dnet_intr for each of them.
35227c478bd9Sstevel@tonic-gate  * Known cards that suffer from this problem are:
35237c478bd9Sstevel@tonic-gate  *	All Cogent multiport cards;
3524*f879aa94SToomas Soome  *	Znyx 314;
35257c478bd9Sstevel@tonic-gate  *	Znyx 315.
35267c478bd9Sstevel@tonic-gate  *
35277c478bd9Sstevel@tonic-gate  * XXX NEEDSWORK -- see comments above get_alternative_srom_image(). This
35287c478bd9Sstevel@tonic-gate  * hack relies on the fact that the offending cards will have only one SROM.
35297c478bd9Sstevel@tonic-gate  * It uses this fact to identify devices that are on the same multiport
35307c478bd9Sstevel@tonic-gate  * adapter, as opposed to multiple devices from the same vendor (as
35317c478bd9Sstevel@tonic-gate  * indicated by "secondary")
35327c478bd9Sstevel@tonic-gate  */
35337c478bd9Sstevel@tonic-gate static int
dnet_hack_interrupts(struct dnetinstance * dnetp,int secondary)353498e8d175SSteven Stallion dnet_hack_interrupts(struct dnetinstance *dnetp, int secondary)
35357c478bd9Sstevel@tonic-gate {
35367c478bd9Sstevel@tonic-gate 	int i;
35377c478bd9Sstevel@tonic-gate 	struct hackintr_inf *hackintr_inf;
35387c478bd9Sstevel@tonic-gate 	dev_info_t *devinfo = dnetp->devinfo;
35397c478bd9Sstevel@tonic-gate 	uint32_t oui = 0;	/* Organizationally Unique ID */
35407c478bd9Sstevel@tonic-gate 
35417c478bd9Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_ANY, devinfo, DDI_PROP_DONTPASS,
35427c478bd9Sstevel@tonic-gate 	    "no_INTA_workaround", 0) != 0)
35437c478bd9Sstevel@tonic-gate 		return (0);
35447c478bd9Sstevel@tonic-gate 
35457c478bd9Sstevel@tonic-gate 	for (i = 0; i < 3; i++)
35467c478bd9Sstevel@tonic-gate 		oui = (oui << 8) | dnetp->vendor_addr[i];
35477c478bd9Sstevel@tonic-gate 
35487c478bd9Sstevel@tonic-gate 	/* Check wheather or not we need to implement the hack */
35497c478bd9Sstevel@tonic-gate 
35507c478bd9Sstevel@tonic-gate 	switch (oui) {
35517c478bd9Sstevel@tonic-gate 	case ZNYX_ETHER:
35527c478bd9Sstevel@tonic-gate 		/* Znyx multiport 21040 cards <<==>> ZX314 or ZX315 */
35537c478bd9Sstevel@tonic-gate 		if (dnetp->board_type != DEVICE_ID_21040)
35547c478bd9Sstevel@tonic-gate 			return (0);
35557c478bd9Sstevel@tonic-gate 		break;
35567c478bd9Sstevel@tonic-gate 
35577c478bd9Sstevel@tonic-gate 	case COGENT_ETHER:
35587c478bd9Sstevel@tonic-gate 		/* All known Cogent multiport cards */
35597c478bd9Sstevel@tonic-gate 		break;
35607c478bd9Sstevel@tonic-gate 
35617c478bd9Sstevel@tonic-gate 	case ADAPTEC_ETHER:
35627c478bd9Sstevel@tonic-gate 		/* Adaptec multiport cards */
35637c478bd9Sstevel@tonic-gate 		break;
35647c478bd9Sstevel@tonic-gate 
35657c478bd9Sstevel@tonic-gate 	default:
35667c478bd9Sstevel@tonic-gate 		/* Other cards work correctly */
35677c478bd9Sstevel@tonic-gate 		return (0);
35687c478bd9Sstevel@tonic-gate 	}
35697c478bd9Sstevel@tonic-gate 
35707c478bd9Sstevel@tonic-gate 	/* card is (probably) non-PCI compliant in its interrupt routing */
35717c478bd9Sstevel@tonic-gate 
35727c478bd9Sstevel@tonic-gate 
35737c478bd9Sstevel@tonic-gate 	if (!secondary) {
35747c478bd9Sstevel@tonic-gate 
35757c478bd9Sstevel@tonic-gate 		/*
35767c478bd9Sstevel@tonic-gate 		 * If we have already registered a hacked interrupt, and
35777c478bd9Sstevel@tonic-gate 		 * this is also a 'primary' adapter, then this is NOT part of
35787c478bd9Sstevel@tonic-gate 		 * a multiport card, but a second card on the same PCI bus.
35797c478bd9Sstevel@tonic-gate 		 * BUGID: 4057747
35807c478bd9Sstevel@tonic-gate 		 */
35817c478bd9Sstevel@tonic-gate 		if (ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
35827c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, hackintr_propname, 0) != 0)
35837c478bd9Sstevel@tonic-gate 			return (0);
35847c478bd9Sstevel@tonic-gate 				/* ... Primary not part of a multiport device */
35857c478bd9Sstevel@tonic-gate 
35867c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
35877c478bd9Sstevel@tonic-gate 		if (dnetdebug & DNETTRACE)
35887c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "dnet: Implementing hardware "
358917de24c9Svb 			    "interrupt flaw workaround");
35907c478bd9Sstevel@tonic-gate #endif
35917c478bd9Sstevel@tonic-gate 		dnetp->hackintr_inf = hackintr_inf =
35927c478bd9Sstevel@tonic-gate 		    kmem_zalloc(sizeof (struct hackintr_inf), KM_SLEEP);
35937c478bd9Sstevel@tonic-gate 		if (hackintr_inf == NULL)
35947c478bd9Sstevel@tonic-gate 			goto fail;
35957c478bd9Sstevel@tonic-gate 
359698e8d175SSteven Stallion 		hackintr_inf->dnetps[0] = dnetp;
35977c478bd9Sstevel@tonic-gate 		hackintr_inf->devinfo = devinfo;
35987c478bd9Sstevel@tonic-gate 
35997c478bd9Sstevel@tonic-gate 		/*
36007c478bd9Sstevel@tonic-gate 		 * Add a property to allow successive attaches to find the
36017c478bd9Sstevel@tonic-gate 		 * table
36027c478bd9Sstevel@tonic-gate 		 */
36037c478bd9Sstevel@tonic-gate 
36047c478bd9Sstevel@tonic-gate 		if (ddi_prop_update_byte_array(DDI_DEV_T_NONE,
36057c478bd9Sstevel@tonic-gate 		    ddi_get_parent(devinfo), hackintr_propname,
36067c478bd9Sstevel@tonic-gate 		    (uchar_t *)&dnetp->hackintr_inf,
36077c478bd9Sstevel@tonic-gate 		    sizeof (void *)) != DDI_PROP_SUCCESS)
36087c478bd9Sstevel@tonic-gate 			goto fail;
36097c478bd9Sstevel@tonic-gate 
36107c478bd9Sstevel@tonic-gate 
36117c478bd9Sstevel@tonic-gate 		/* Register our hacked interrupt routine */
361298e8d175SSteven Stallion 		if (ddi_add_intr(devinfo, 0, &dnetp->icookie, NULL,
36137c478bd9Sstevel@tonic-gate 		    (uint_t (*)(char *))dnet_hack_intr,
36147c478bd9Sstevel@tonic-gate 		    (caddr_t)hackintr_inf) != DDI_SUCCESS) {
36157c478bd9Sstevel@tonic-gate 			/* XXX function return value ignored */
36167c478bd9Sstevel@tonic-gate 			(void) ddi_prop_remove(DDI_DEV_T_NONE,
361717de24c9Svb 			    ddi_get_parent(devinfo),
361817de24c9Svb 			    hackintr_propname);
36197c478bd9Sstevel@tonic-gate 			goto fail;
36207c478bd9Sstevel@tonic-gate 		}
36217c478bd9Sstevel@tonic-gate 
36227c478bd9Sstevel@tonic-gate 		/*
36237c478bd9Sstevel@tonic-gate 		 * Mutex required to ensure interrupt routine has completed
36247c478bd9Sstevel@tonic-gate 		 * when detaching devices
36257c478bd9Sstevel@tonic-gate 		 */
36267c478bd9Sstevel@tonic-gate 		mutex_init(&hackintr_inf->lock, NULL, MUTEX_DRIVER,
362798e8d175SSteven Stallion 		    dnetp->icookie);
36287c478bd9Sstevel@tonic-gate 
36297c478bd9Sstevel@tonic-gate 		/* Stop GLD registering an interrupt */
36307c478bd9Sstevel@tonic-gate 		return (-1);
36317c478bd9Sstevel@tonic-gate 	} else {
36327c478bd9Sstevel@tonic-gate 
363398e8d175SSteven Stallion 		/* Add the dnetp for this secondary device to the table */
36347c478bd9Sstevel@tonic-gate 
36357c478bd9Sstevel@tonic-gate 		hackintr_inf = (struct hackintr_inf *)(uintptr_t)
36367c478bd9Sstevel@tonic-gate 		    ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
363717de24c9Svb 		    DDI_PROP_DONTPASS, hackintr_propname, 0);
36387c478bd9Sstevel@tonic-gate 
36397c478bd9Sstevel@tonic-gate 		if (hackintr_inf == NULL)
36407c478bd9Sstevel@tonic-gate 			goto fail;
36417c478bd9Sstevel@tonic-gate 
36427c478bd9Sstevel@tonic-gate 		/* Find an empty slot */
36437c478bd9Sstevel@tonic-gate 		for (i = 0; i < MAX_INST; i++)
364498e8d175SSteven Stallion 			if (hackintr_inf->dnetps[i] == NULL)
36457c478bd9Sstevel@tonic-gate 				break;
36467c478bd9Sstevel@tonic-gate 
36477c478bd9Sstevel@tonic-gate 		/* More than 8 ports on adapter ?! */
36487c478bd9Sstevel@tonic-gate 		if (i == MAX_INST)
36497c478bd9Sstevel@tonic-gate 			goto fail;
36507c478bd9Sstevel@tonic-gate 
365198e8d175SSteven Stallion 		hackintr_inf->dnetps[i] = dnetp;
36527c478bd9Sstevel@tonic-gate 
36537c478bd9Sstevel@tonic-gate 		/*
36547c478bd9Sstevel@tonic-gate 		 * Allow GLD to register a handler for this
36557c478bd9Sstevel@tonic-gate 		 * device. If the card is actually broken, as we suspect, this
36567c478bd9Sstevel@tonic-gate 		 * handler will never get called. However, by registering the
36577c478bd9Sstevel@tonic-gate 		 * interrupt handler, we can copy gracefully with new multiport
36587c478bd9Sstevel@tonic-gate 		 * Cogent cards that decide to fix the hardware problem
36597c478bd9Sstevel@tonic-gate 		 */
36607c478bd9Sstevel@tonic-gate 		return (0);
36617c478bd9Sstevel@tonic-gate 	}
36627c478bd9Sstevel@tonic-gate 
36637c478bd9Sstevel@tonic-gate fail:
36647c478bd9Sstevel@tonic-gate 	cmn_err(CE_WARN, "dnet: Could not work around hardware interrupt"
36657c478bd9Sstevel@tonic-gate 	    " routing problem");
36667c478bd9Sstevel@tonic-gate 	return (0);
36677c478bd9Sstevel@tonic-gate }
36687c478bd9Sstevel@tonic-gate 
36697c478bd9Sstevel@tonic-gate /*
367098e8d175SSteven Stallion  * Call dnet_intr for all adapters on a multiport card
36717c478bd9Sstevel@tonic-gate  */
36727c478bd9Sstevel@tonic-gate static uint_t
dnet_hack_intr(struct hackintr_inf * hackintr_inf)36737c478bd9Sstevel@tonic-gate dnet_hack_intr(struct hackintr_inf *hackintr_inf)
36747c478bd9Sstevel@tonic-gate {
36757c478bd9Sstevel@tonic-gate 	int i;
36767c478bd9Sstevel@tonic-gate 	int claimed = DDI_INTR_UNCLAIMED;
36777c478bd9Sstevel@tonic-gate 
36787c478bd9Sstevel@tonic-gate 	/* Stop detaches while processing interrupts */
36797c478bd9Sstevel@tonic-gate 	mutex_enter(&hackintr_inf->lock);
36807c478bd9Sstevel@tonic-gate 
36817c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_INST; i++) {
368298e8d175SSteven Stallion 		if (hackintr_inf->dnetps[i] &&
368398e8d175SSteven Stallion 		    dnet_intr((caddr_t)hackintr_inf->dnetps[i]) ==
368498e8d175SSteven Stallion 		    DDI_INTR_CLAIMED) {
36857c478bd9Sstevel@tonic-gate 			claimed = DDI_INTR_CLAIMED;
368698e8d175SSteven Stallion 		}
36877c478bd9Sstevel@tonic-gate 	}
36887c478bd9Sstevel@tonic-gate 	mutex_exit(&hackintr_inf->lock);
36897c478bd9Sstevel@tonic-gate 	return (claimed);
36907c478bd9Sstevel@tonic-gate }
36917c478bd9Sstevel@tonic-gate 
36927c478bd9Sstevel@tonic-gate /*
36937c478bd9Sstevel@tonic-gate  * This removes the detaching device from the table procesed by the hacked
36947c478bd9Sstevel@tonic-gate  * interrupt routine. Because the interrupts from all devices come in to the
36957c478bd9Sstevel@tonic-gate  * same interrupt handler, ALL devices must stop interrupting once the
36967c478bd9Sstevel@tonic-gate  * primary device detaches. This isn't a problem at present, because all
36977c478bd9Sstevel@tonic-gate  * instances of a device are detached when the driver is unloaded.
36987c478bd9Sstevel@tonic-gate  */
36997c478bd9Sstevel@tonic-gate static int
dnet_detach_hacked_interrupt(dev_info_t * devinfo)37007c478bd9Sstevel@tonic-gate dnet_detach_hacked_interrupt(dev_info_t *devinfo)
37017c478bd9Sstevel@tonic-gate {
37027c478bd9Sstevel@tonic-gate 	int i;
37037c478bd9Sstevel@tonic-gate 	struct hackintr_inf *hackintr_inf;
370498e8d175SSteven Stallion 	struct dnetinstance *altdnetp, *dnetp =
370598e8d175SSteven Stallion 	    ddi_get_driver_private(devinfo);
37067c478bd9Sstevel@tonic-gate 
37077c478bd9Sstevel@tonic-gate 	hackintr_inf = (struct hackintr_inf *)(uintptr_t)
37087c478bd9Sstevel@tonic-gate 	    ddi_getprop(DDI_DEV_T_ANY, ddi_get_parent(devinfo),
37097c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, hackintr_propname, 0);
37107c478bd9Sstevel@tonic-gate 
37117c478bd9Sstevel@tonic-gate 	/*
37127c478bd9Sstevel@tonic-gate 	 * No hackintr_inf implies hack was not required or the primary has
37137c478bd9Sstevel@tonic-gate 	 * detached, and our interrupts are already disabled
37147c478bd9Sstevel@tonic-gate 	 */
37157c478bd9Sstevel@tonic-gate 	if (!hackintr_inf) {
37167c478bd9Sstevel@tonic-gate 		/* remove the interrupt for the non-hacked case */
371798e8d175SSteven Stallion 		ddi_remove_intr(devinfo, 0, dnetp->icookie);
37187c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
37197c478bd9Sstevel@tonic-gate 	}
37207c478bd9Sstevel@tonic-gate 
37217c478bd9Sstevel@tonic-gate 	/* Remove this device from the handled table */
37227c478bd9Sstevel@tonic-gate 	mutex_enter(&hackintr_inf->lock);
37237c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_INST; i++) {
372498e8d175SSteven Stallion 		if (hackintr_inf->dnetps[i] == dnetp) {
372598e8d175SSteven Stallion 			hackintr_inf->dnetps[i] = NULL;
37267c478bd9Sstevel@tonic-gate 			break;
37277c478bd9Sstevel@tonic-gate 		}
37287c478bd9Sstevel@tonic-gate 	}
37297c478bd9Sstevel@tonic-gate 
37307c478bd9Sstevel@tonic-gate 	mutex_exit(&hackintr_inf->lock);
37317c478bd9Sstevel@tonic-gate 
37327c478bd9Sstevel@tonic-gate 	/* Not the primary card, we are done */
37337c478bd9Sstevel@tonic-gate 	if (devinfo != hackintr_inf->devinfo)
37347c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
37357c478bd9Sstevel@tonic-gate 
37367c478bd9Sstevel@tonic-gate 	/*
37377c478bd9Sstevel@tonic-gate 	 * This is the primary card. All remaining adapters on this device
37387c478bd9Sstevel@tonic-gate 	 * must have their interrupts disabled before we remove the handler
37397c478bd9Sstevel@tonic-gate 	 */
37407c478bd9Sstevel@tonic-gate 	for (i = 0; i < MAX_INST; i++) {
374198e8d175SSteven Stallion 		if ((altdnetp = hackintr_inf->dnetps[i]) != NULL) {
37427c478bd9Sstevel@tonic-gate 			altdnetp->interrupts_disabled = 1;
37434ab75253Smrj 			ddi_put32(altdnetp->io_handle,
374417de24c9Svb 			    REG32(altdnetp->io_reg, INT_MASK_REG), 0);
37457c478bd9Sstevel@tonic-gate 		}
37467c478bd9Sstevel@tonic-gate 	}
37477c478bd9Sstevel@tonic-gate 
37487c478bd9Sstevel@tonic-gate 	/* It should now be safe to remove the interrupt handler */
37497c478bd9Sstevel@tonic-gate 
375098e8d175SSteven Stallion 	ddi_remove_intr(devinfo, 0, dnetp->icookie);
37517c478bd9Sstevel@tonic-gate 	mutex_destroy(&hackintr_inf->lock);
37527c478bd9Sstevel@tonic-gate 	/* XXX function return value ignored */
37537c478bd9Sstevel@tonic-gate 	(void) ddi_prop_remove(DDI_DEV_T_NONE, ddi_get_parent(devinfo),
37547c478bd9Sstevel@tonic-gate 	    hackintr_propname);
37557c478bd9Sstevel@tonic-gate 	kmem_free(hackintr_inf, sizeof (struct hackintr_inf));
37567c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
37577c478bd9Sstevel@tonic-gate }
3758a8320b74Smeem 
37597c478bd9Sstevel@tonic-gate /* do_phy() - called with intrlock held */
37607c478bd9Sstevel@tonic-gate static void
do_phy(struct dnetinstance * dnetp)376198e8d175SSteven Stallion do_phy(struct dnetinstance *dnetp)
37627c478bd9Sstevel@tonic-gate {
37637c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
37647c478bd9Sstevel@tonic-gate 	LEAF_FORMAT *leaf = dnetp->sr.leaf + dnetp->leaf;
37657c478bd9Sstevel@tonic-gate 	media_block_t *block;
37667c478bd9Sstevel@tonic-gate 	int phy;
37677c478bd9Sstevel@tonic-gate 
37687c478bd9Sstevel@tonic-gate 	dip = dnetp->devinfo;
37697c478bd9Sstevel@tonic-gate 
37707c478bd9Sstevel@tonic-gate 	/*
37717c478bd9Sstevel@tonic-gate 	 * Find and configure the PHY media block. If NO PHY blocks are
37727c478bd9Sstevel@tonic-gate 	 * found on the SROM, but a PHY device is present, we assume the card
37737c478bd9Sstevel@tonic-gate 	 * is a legacy device, and that there is ONLY a PHY interface on the
37747c478bd9Sstevel@tonic-gate 	 * card (ie, no BNC or AUI, and 10BaseT is implemented by the PHY
37757c478bd9Sstevel@tonic-gate 	 */
37767c478bd9Sstevel@tonic-gate 
37777c478bd9Sstevel@tonic-gate 	for (block = leaf->block + leaf->block_count -1;
37787c478bd9Sstevel@tonic-gate 	    block >= leaf->block; block --) {
37797c478bd9Sstevel@tonic-gate 		if (block->type == 3 || block->type == 1) {
37807c478bd9Sstevel@tonic-gate 			leaf->mii_block = block;
37817c478bd9Sstevel@tonic-gate 			break;
37827c478bd9Sstevel@tonic-gate 		}
37837c478bd9Sstevel@tonic-gate 	}
37847c478bd9Sstevel@tonic-gate 
37857c478bd9Sstevel@tonic-gate 	/*
37867c478bd9Sstevel@tonic-gate 	 * If no MII block, select default, and hope this configuration will
37877c478bd9Sstevel@tonic-gate 	 * allow the phy to be read/written if it is present
37887c478bd9Sstevel@tonic-gate 	 */
37897c478bd9Sstevel@tonic-gate 	dnetp->selected_media_block = leaf->mii_block ?
379017de24c9Svb 	    leaf->mii_block : leaf->default_block;
37917c478bd9Sstevel@tonic-gate 
379298e8d175SSteven Stallion 	setup_block(dnetp);
37937c478bd9Sstevel@tonic-gate 	/* XXX function return value ignored */
37947c478bd9Sstevel@tonic-gate 	(void) mii_create(dip, dnet_mii_write, dnet_mii_read, &dnetp->mii);
37957c478bd9Sstevel@tonic-gate 
37967c478bd9Sstevel@tonic-gate 	/*
37977c478bd9Sstevel@tonic-gate 	 * We try PHY 0 LAST because it is less likely to be connected
37987c478bd9Sstevel@tonic-gate 	 */
37997c478bd9Sstevel@tonic-gate 	for (phy = 1; phy < 33; phy++)
38007c478bd9Sstevel@tonic-gate 		if (mii_probe_phy(dnetp->mii, phy % 32) == MII_SUCCESS &&
380117de24c9Svb 		    mii_init_phy(dnetp->mii, phy % 32) == MII_SUCCESS) {
38027c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
38037c478bd9Sstevel@tonic-gate 			if (dnetdebug & DNETSENSE)
38047c478bd9Sstevel@tonic-gate 				cmn_err(CE_NOTE, "dnet: "
380517de24c9Svb 				    "PHY at address %d", phy % 32);
38067c478bd9Sstevel@tonic-gate #endif
38077c478bd9Sstevel@tonic-gate 			dnetp->phyaddr = phy % 32;
38087c478bd9Sstevel@tonic-gate 			if (!leaf->mii_block) {
38097c478bd9Sstevel@tonic-gate 				/* Legacy card, change the leaf node */
38107c478bd9Sstevel@tonic-gate 				set_leaf(&dnetp->sr, &leaf_phylegacy);
38117c478bd9Sstevel@tonic-gate 			}
38127c478bd9Sstevel@tonic-gate 			return;
38137c478bd9Sstevel@tonic-gate 		}
38147c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
38157c478bd9Sstevel@tonic-gate 	if (dnetdebug & DNETSENSE)
38167c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "dnet: No PHY found");
38177c478bd9Sstevel@tonic-gate #endif
38187c478bd9Sstevel@tonic-gate }
38197c478bd9Sstevel@tonic-gate 
38207c478bd9Sstevel@tonic-gate static ushort_t
dnet_mii_read(dev_info_t * dip,int phy_addr,int reg_num)38217c478bd9Sstevel@tonic-gate dnet_mii_read(dev_info_t *dip, int phy_addr, int reg_num)
38227c478bd9Sstevel@tonic-gate {
38237c478bd9Sstevel@tonic-gate 	struct dnetinstance *dnetp;
38247c478bd9Sstevel@tonic-gate 
38257c478bd9Sstevel@tonic-gate 	uint32_t command_word;
38267c478bd9Sstevel@tonic-gate 	uint32_t tmp;
38277c478bd9Sstevel@tonic-gate 	uint32_t data = 0;
38287c478bd9Sstevel@tonic-gate 	int i;
38297c478bd9Sstevel@tonic-gate 	int bits_in_ushort = ((sizeof (ushort_t))*8);
38307c478bd9Sstevel@tonic-gate 	int turned_around = 0;
38317c478bd9Sstevel@tonic-gate 
383298e8d175SSteven Stallion 	dnetp = ddi_get_driver_private(dip);
38337c478bd9Sstevel@tonic-gate 
38347c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
38357c478bd9Sstevel@tonic-gate 	/* Write Preamble */
38367c478bd9Sstevel@tonic-gate 	write_mii(dnetp, MII_PRE, 2*bits_in_ushort);
38377c478bd9Sstevel@tonic-gate 
38387c478bd9Sstevel@tonic-gate 	/* Prepare command word */
38397c478bd9Sstevel@tonic-gate 	command_word = (uint32_t)phy_addr << MII_PHY_ADDR_ALIGN;
38407c478bd9Sstevel@tonic-gate 	command_word |= (uint32_t)reg_num << MII_REG_ADDR_ALIGN;
38417c478bd9Sstevel@tonic-gate 	command_word |= MII_READ_FRAME;
38427c478bd9Sstevel@tonic-gate 
38437c478bd9Sstevel@tonic-gate 	write_mii(dnetp, command_word, bits_in_ushort-2);
38447c478bd9Sstevel@tonic-gate 
38457c478bd9Sstevel@tonic-gate 	mii_tristate(dnetp);
38467c478bd9Sstevel@tonic-gate 
38477c478bd9Sstevel@tonic-gate 	/* Check that the PHY generated a zero bit the 2nd clock */
384817de24c9Svb 	tmp = ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG));
38497c478bd9Sstevel@tonic-gate 
38507c478bd9Sstevel@tonic-gate 	turned_around = (tmp & MII_DATA_IN) ? 0 : 1;
38517c478bd9Sstevel@tonic-gate 
38527c478bd9Sstevel@tonic-gate 	/* read data WORD */
38537c478bd9Sstevel@tonic-gate 	for (i = 0; i < bits_in_ushort; i++) {
38544ab75253Smrj 		ddi_put32(dnetp->io_handle,
38557c478bd9Sstevel@tonic-gate 		    REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ);
38567c478bd9Sstevel@tonic-gate 		drv_usecwait(MII_DELAY);
38574ab75253Smrj 		ddi_put32(dnetp->io_handle,
38587c478bd9Sstevel@tonic-gate 		    REG32(dnetp->io_reg, ETHER_ROM_REG), MII_READ | MII_CLOCK);
38597c478bd9Sstevel@tonic-gate 		drv_usecwait(MII_DELAY);
38604ab75253Smrj 		tmp = ddi_get32(dnetp->io_handle,
38617c478bd9Sstevel@tonic-gate 		    REG32(dnetp->io_reg, ETHER_ROM_REG));
38627c478bd9Sstevel@tonic-gate 		drv_usecwait(MII_DELAY);
38637c478bd9Sstevel@tonic-gate 		data = (data << 1) | (tmp >> MII_DATA_IN_POSITION) & 0x0001;
38647c478bd9Sstevel@tonic-gate 	}
38657c478bd9Sstevel@tonic-gate 
38667c478bd9Sstevel@tonic-gate 	mii_tristate(dnetp);
38677c478bd9Sstevel@tonic-gate 	return (turned_around ? data: -1);
38687c478bd9Sstevel@tonic-gate }
38697c478bd9Sstevel@tonic-gate 
38707c478bd9Sstevel@tonic-gate static void
dnet_mii_write(dev_info_t * dip,int phy_addr,int reg_num,int reg_dat)38717c478bd9Sstevel@tonic-gate dnet_mii_write(dev_info_t *dip, int phy_addr, int reg_num, int reg_dat)
38727c478bd9Sstevel@tonic-gate {
38737c478bd9Sstevel@tonic-gate 	struct dnetinstance *dnetp;
38747c478bd9Sstevel@tonic-gate 	uint32_t command_word;
38757c478bd9Sstevel@tonic-gate 	int bits_in_ushort = ((sizeof (ushort_t))*8);
3876a8320b74Smeem 
387798e8d175SSteven Stallion 	dnetp = ddi_get_driver_private(dip);
38787c478bd9Sstevel@tonic-gate 
38797c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
38807c478bd9Sstevel@tonic-gate 	write_mii(dnetp, MII_PRE, 2*bits_in_ushort);
38817c478bd9Sstevel@tonic-gate 
38827c478bd9Sstevel@tonic-gate 	/* Prepare command word */
38837c478bd9Sstevel@tonic-gate 	command_word = ((uint32_t)phy_addr << MII_PHY_ADDR_ALIGN);
38847c478bd9Sstevel@tonic-gate 	command_word |= ((uint32_t)reg_num << MII_REG_ADDR_ALIGN);
38857c478bd9Sstevel@tonic-gate 	command_word |= (MII_WRITE_FRAME | (uint32_t)reg_dat);
38867c478bd9Sstevel@tonic-gate 
38877c478bd9Sstevel@tonic-gate 	write_mii(dnetp, command_word, 2*bits_in_ushort);
38887c478bd9Sstevel@tonic-gate 	mii_tristate(dnetp);
38897c478bd9Sstevel@tonic-gate }
38907c478bd9Sstevel@tonic-gate 
38917c478bd9Sstevel@tonic-gate /*
38927c478bd9Sstevel@tonic-gate  * Write data size bits from mii_data to the MII control lines.
38937c478bd9Sstevel@tonic-gate  */
38947c478bd9Sstevel@tonic-gate static void
write_mii(struct dnetinstance * dnetp,uint32_t mii_data,int data_size)38957c478bd9Sstevel@tonic-gate write_mii(struct dnetinstance *dnetp, uint32_t mii_data, int data_size)
38967c478bd9Sstevel@tonic-gate {
38977c478bd9Sstevel@tonic-gate 	int i;
38987c478bd9Sstevel@tonic-gate 	uint32_t dbit;
38997c478bd9Sstevel@tonic-gate 
39007c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
39017c478bd9Sstevel@tonic-gate 	for (i = data_size; i > 0; i--) {
39027c478bd9Sstevel@tonic-gate 		dbit = ((mii_data >>
39037c478bd9Sstevel@tonic-gate 		    (31 - MII_WRITE_DATA_POSITION)) & MII_WRITE_DATA);
39044ab75253Smrj 		ddi_put32(dnetp->io_handle,
39057c478bd9Sstevel@tonic-gate 		    REG32(dnetp->io_reg, ETHER_ROM_REG),
39067c478bd9Sstevel@tonic-gate 		    MII_WRITE | dbit);
39077c478bd9Sstevel@tonic-gate 		drv_usecwait(MII_DELAY);
39084ab75253Smrj 		ddi_put32(dnetp->io_handle,
39097c478bd9Sstevel@tonic-gate 		    REG32(dnetp->io_reg, ETHER_ROM_REG),
39107c478bd9Sstevel@tonic-gate 		    MII_WRITE | MII_CLOCK | dbit);
39117c478bd9Sstevel@tonic-gate 		drv_usecwait(MII_DELAY);
39127c478bd9Sstevel@tonic-gate 		mii_data <<= 1;
39137c478bd9Sstevel@tonic-gate 	}
39147c478bd9Sstevel@tonic-gate }
39157c478bd9Sstevel@tonic-gate 
39167c478bd9Sstevel@tonic-gate /*
39177c478bd9Sstevel@tonic-gate  * Put the MDIO port in tri-state for the turn around bits
39187c478bd9Sstevel@tonic-gate  * in MII read and at end of MII management sequence.
39197c478bd9Sstevel@tonic-gate  */
39207c478bd9Sstevel@tonic-gate static void
mii_tristate(struct dnetinstance * dnetp)39217c478bd9Sstevel@tonic-gate mii_tristate(struct dnetinstance *dnetp)
39227c478bd9Sstevel@tonic-gate {
39237c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
39244ab75253Smrj 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG),
39257c478bd9Sstevel@tonic-gate 	    MII_WRITE_TS);
39267c478bd9Sstevel@tonic-gate 	drv_usecwait(MII_DELAY);
39274ab75253Smrj 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, ETHER_ROM_REG),
39287c478bd9Sstevel@tonic-gate 	    MII_WRITE_TS | MII_CLOCK);
39297c478bd9Sstevel@tonic-gate 	drv_usecwait(MII_DELAY);
39307c478bd9Sstevel@tonic-gate }
39317c478bd9Sstevel@tonic-gate 
39327c478bd9Sstevel@tonic-gate 
39337c478bd9Sstevel@tonic-gate static void
set_leaf(SROM_FORMAT * sr,LEAF_FORMAT * leaf)39347c478bd9Sstevel@tonic-gate set_leaf(SROM_FORMAT *sr, LEAF_FORMAT *leaf)
39357c478bd9Sstevel@tonic-gate {
39367c478bd9Sstevel@tonic-gate 	if (sr->leaf && !sr->leaf->is_static)
39377c478bd9Sstevel@tonic-gate 		kmem_free(sr->leaf, sr->adapters * sizeof (LEAF_FORMAT));
39387c478bd9Sstevel@tonic-gate 	sr->leaf = leaf;
39397c478bd9Sstevel@tonic-gate }
39407c478bd9Sstevel@tonic-gate 
39417c478bd9Sstevel@tonic-gate /*
39427c478bd9Sstevel@tonic-gate  * Callback from MII module. Makes sure that the CSR registers are
39437c478bd9Sstevel@tonic-gate  * configured properly if the PHY changes mode.
39447c478bd9Sstevel@tonic-gate  */
39457c478bd9Sstevel@tonic-gate /* ARGSUSED */
39467c478bd9Sstevel@tonic-gate /* dnet_mii_link_cb - called with intrlock held */
39477c478bd9Sstevel@tonic-gate static void
dnet_mii_link_cb(dev_info_t * dip,int phy,enum mii_phy_state state)39487c478bd9Sstevel@tonic-gate dnet_mii_link_cb(dev_info_t *dip, int phy, enum mii_phy_state state)
39497c478bd9Sstevel@tonic-gate {
395098e8d175SSteven Stallion 	struct dnetinstance *dnetp = ddi_get_driver_private(dip);
39517c478bd9Sstevel@tonic-gate 	LEAF_FORMAT *leaf;
39527c478bd9Sstevel@tonic-gate 
39537c478bd9Sstevel@tonic-gate 	ASSERT(MUTEX_HELD(&dnetp->intrlock));
395498e8d175SSteven Stallion 
39557c478bd9Sstevel@tonic-gate 	leaf = dnetp->sr.leaf + dnetp->leaf;
39567c478bd9Sstevel@tonic-gate 	if (state == phy_state_linkup) {
39577c478bd9Sstevel@tonic-gate 		dnetp->mii_up = 1;
395898e8d175SSteven Stallion 
395998e8d175SSteven Stallion 		(void) mii_getspeed(dnetp->mii, dnetp->phyaddr,
396098e8d175SSteven Stallion 		    &dnetp->mii_speed, &dnetp->mii_duplex);
396198e8d175SSteven Stallion 
39627c478bd9Sstevel@tonic-gate 		dnetp->selected_media_block = leaf->mii_block;
396398e8d175SSteven Stallion 		setup_block(dnetp);
39647c478bd9Sstevel@tonic-gate 	} else {
39657c478bd9Sstevel@tonic-gate 		/* NEEDSWORK: Probably can call find_active_media here */
39667c478bd9Sstevel@tonic-gate 		dnetp->mii_up = 0;
396798e8d175SSteven Stallion 
39687c478bd9Sstevel@tonic-gate 		if (leaf->default_block->media_code == MEDIA_MII)
39697c478bd9Sstevel@tonic-gate 			dnetp->selected_media_block = leaf->default_block;
397098e8d175SSteven Stallion 		setup_block(dnetp);
397198e8d175SSteven Stallion 	}
397298e8d175SSteven Stallion 
397332607e28SSteven Stallion 	if (dnetp->running) {
397432607e28SSteven Stallion 		mac_link_update(dnetp->mac_handle,
397532607e28SSteven Stallion 		    (dnetp->mii_up ? LINK_STATE_UP : LINK_STATE_DOWN));
39767c478bd9Sstevel@tonic-gate 	}
39777c478bd9Sstevel@tonic-gate }
39787c478bd9Sstevel@tonic-gate 
39797c478bd9Sstevel@tonic-gate /*
39807c478bd9Sstevel@tonic-gate  * SROM parsing routines.
39817c478bd9Sstevel@tonic-gate  * Refer to the Digital 3.03 SROM spec while reading this! (references refer
39827c478bd9Sstevel@tonic-gate  * to this document)
39837c478bd9Sstevel@tonic-gate  * Where possible ALL vendor specific changes should be localised here. The
39847c478bd9Sstevel@tonic-gate  * SROM data should be capable of describing any programmatic irregularities
39857c478bd9Sstevel@tonic-gate  * of DNET cards (via SIA or GP registers, in particular), so vendor specific
39867c478bd9Sstevel@tonic-gate  * code elsewhere should not be required
39877c478bd9Sstevel@tonic-gate  */
39887c478bd9Sstevel@tonic-gate static void
dnet_parse_srom(struct dnetinstance * dnetp,SROM_FORMAT * sr,uchar_t * vi)39897c478bd9Sstevel@tonic-gate dnet_parse_srom(struct dnetinstance *dnetp, SROM_FORMAT *sr, uchar_t *vi)
39907c478bd9Sstevel@tonic-gate {
39917c478bd9Sstevel@tonic-gate 	uint32_t ether_mfg = 0;
39927c478bd9Sstevel@tonic-gate 	int i;
39937c478bd9Sstevel@tonic-gate 	uchar_t *p;
39947c478bd9Sstevel@tonic-gate 
39957c478bd9Sstevel@tonic-gate 	if (!ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
39967c478bd9Sstevel@tonic-gate 	    DDI_PROP_DONTPASS, "no_sromconfig", 0))
39977c478bd9Sstevel@tonic-gate 		dnetp->sr.init_from_srom = check_srom_valid(vi);
39987c478bd9Sstevel@tonic-gate 
39997c478bd9Sstevel@tonic-gate 	if (dnetp->sr.init_from_srom && dnetp->board_type != DEVICE_ID_21040) {
40007c478bd9Sstevel@tonic-gate 		/* Section 2/3: General SROM Format/ ID Block */
40017c478bd9Sstevel@tonic-gate 		p = vi+18;
40027c478bd9Sstevel@tonic-gate 		sr->version = *p++;
40037c478bd9Sstevel@tonic-gate 		sr->adapters = *p++;
4004a8320b74Smeem 
40057c478bd9Sstevel@tonic-gate 		sr->leaf =
40067c478bd9Sstevel@tonic-gate 		    kmem_zalloc(sr->adapters * sizeof (LEAF_FORMAT), KM_SLEEP);
40077c478bd9Sstevel@tonic-gate 		for (i = 0; i < 6; i++)
40087c478bd9Sstevel@tonic-gate 			sr->netaddr[i] = *p++;
40097c478bd9Sstevel@tonic-gate 
40107c478bd9Sstevel@tonic-gate 		for (i = 0; i < sr->adapters; i++) {
40117c478bd9Sstevel@tonic-gate 			uchar_t devno = *p++;
40127c478bd9Sstevel@tonic-gate 			uint16_t offset = *p++;
40137c478bd9Sstevel@tonic-gate 			offset |= *p++ << 8;
40147c478bd9Sstevel@tonic-gate 			sr->leaf[i].device_number = devno;
40157c478bd9Sstevel@tonic-gate 			parse_controller_leaf(dnetp, sr->leaf+i, vi+offset);
40167c478bd9Sstevel@tonic-gate 		}
40177c478bd9Sstevel@tonic-gate 		/*
40187c478bd9Sstevel@tonic-gate 		 * 'Orrible hack for cogent cards. The 6911A board seems to
40197c478bd9Sstevel@tonic-gate 		 * have an incorrect SROM. (From the OEMDEMO program
40207c478bd9Sstevel@tonic-gate 		 * supplied by cogent, it seems that the ROM matches a setup
40217c478bd9Sstevel@tonic-gate 		 * or a board with a QSI or ICS PHY.
40227c478bd9Sstevel@tonic-gate 		 */
40237c478bd9Sstevel@tonic-gate 		for (i = 0; i < 3; i++)
40247c478bd9Sstevel@tonic-gate 			ether_mfg = (ether_mfg << 8) | sr->netaddr[i];
40257c478bd9Sstevel@tonic-gate 
40267c478bd9Sstevel@tonic-gate 		if (ether_mfg == ADAPTEC_ETHER) {
40277c478bd9Sstevel@tonic-gate 			static uint16_t cogent_gprseq[] = {0x821, 0};
40287c478bd9Sstevel@tonic-gate 			switch (vi[COGENT_SROM_ID]) {
40297c478bd9Sstevel@tonic-gate 			case COGENT_ANA6911A_C:
40307c478bd9Sstevel@tonic-gate 			case COGENT_ANA6911AC_C:
40317c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
40327c478bd9Sstevel@tonic-gate 				if (dnetdebug & DNETTRACE)
40337c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
40347c478bd9Sstevel@tonic-gate 					    "Suspected bad GPR sequence."
40357c478bd9Sstevel@tonic-gate 					    " Making a guess (821,0)");
40367c478bd9Sstevel@tonic-gate #endif
40377c478bd9Sstevel@tonic-gate 
40387c478bd9Sstevel@tonic-gate 				/* XXX function return value ignored */
40397c478bd9Sstevel@tonic-gate 				(void) ddi_prop_update_byte_array(
40407c478bd9Sstevel@tonic-gate 				    DDI_DEV_T_NONE, dnetp->devinfo,
40417c478bd9Sstevel@tonic-gate 				    "gpr-sequence", (uchar_t *)cogent_gprseq,
40427c478bd9Sstevel@tonic-gate 				    sizeof (cogent_gprseq));
40437c478bd9Sstevel@tonic-gate 				break;
40447c478bd9Sstevel@tonic-gate 			}
40457c478bd9Sstevel@tonic-gate 		}
40467c478bd9Sstevel@tonic-gate 	} else {
40477c478bd9Sstevel@tonic-gate 		/*
40487c478bd9Sstevel@tonic-gate 		 * Adhoc SROM, check for some cards which need special handling
40497c478bd9Sstevel@tonic-gate 		 * Assume vendor info contains ether address in first six bytes
40507c478bd9Sstevel@tonic-gate 		 */
40517c478bd9Sstevel@tonic-gate 
40527c478bd9Sstevel@tonic-gate 		uchar_t *mac = vi + ddi_getprop(DDI_DEV_T_ANY, dnetp->devinfo,
40537c478bd9Sstevel@tonic-gate 		    DDI_PROP_DONTPASS, macoffset_propname, 0);
40547c478bd9Sstevel@tonic-gate 
40557c478bd9Sstevel@tonic-gate 		for (i = 0; i < 6; i++)
40567c478bd9Sstevel@tonic-gate 			sr->netaddr[i] = mac[i];
40577c478bd9Sstevel@tonic-gate 
40587c478bd9Sstevel@tonic-gate 		if (dnetp->board_type == DEVICE_ID_21140) {
40597c478bd9Sstevel@tonic-gate 			for (i = 0; i < 3; i++)
40607c478bd9Sstevel@tonic-gate 				ether_mfg = (ether_mfg << 8) | mac[i];
40617c478bd9Sstevel@tonic-gate 
40627c478bd9Sstevel@tonic-gate 			switch (ether_mfg) {
40637c478bd9Sstevel@tonic-gate 			case ASANTE_ETHER:
40647c478bd9Sstevel@tonic-gate 				dnetp->vendor_21140 = ASANTE_TYPE;
40657c478bd9Sstevel@tonic-gate 				dnetp->vendor_revision = 0;
40667c478bd9Sstevel@tonic-gate 				set_leaf(sr, &leaf_asante);
40677c478bd9Sstevel@tonic-gate 				sr->adapters = 1;
40687c478bd9Sstevel@tonic-gate 				break;
40697c478bd9Sstevel@tonic-gate 
40707c478bd9Sstevel@tonic-gate 			case COGENT_ETHER:
40717c478bd9Sstevel@tonic-gate 			case ADAPTEC_ETHER:
40727c478bd9Sstevel@tonic-gate 				dnetp->vendor_21140 = COGENT_EM_TYPE;
40737c478bd9Sstevel@tonic-gate 				dnetp->vendor_revision =
40747c478bd9Sstevel@tonic-gate 				    vi[VENDOR_REVISION_OFFSET];
40757c478bd9Sstevel@tonic-gate 				set_leaf(sr, &leaf_cogent_100);
40767c478bd9Sstevel@tonic-gate 				sr->adapters = 1;
40777c478bd9Sstevel@tonic-gate 				break;
40787c478bd9Sstevel@tonic-gate 
40797c478bd9Sstevel@tonic-gate 			default:
40807c478bd9Sstevel@tonic-gate 				dnetp->vendor_21140 = DEFAULT_TYPE;
40817c478bd9Sstevel@tonic-gate 				dnetp->vendor_revision = 0;
40827c478bd9Sstevel@tonic-gate 				set_leaf(sr, &leaf_default_100);
40837c478bd9Sstevel@tonic-gate 				sr->adapters = 1;
40847c478bd9Sstevel@tonic-gate 				break;
40857c478bd9Sstevel@tonic-gate 			}
40867c478bd9Sstevel@tonic-gate 		} else if (dnetp->board_type == DEVICE_ID_21041) {
40877c478bd9Sstevel@tonic-gate 			set_leaf(sr, &leaf_21041);
40887c478bd9Sstevel@tonic-gate 		} else if (dnetp->board_type == DEVICE_ID_21040) {
40897c478bd9Sstevel@tonic-gate 			set_leaf(sr, &leaf_21040);
40907c478bd9Sstevel@tonic-gate 		}
40917c478bd9Sstevel@tonic-gate 	}
40927c478bd9Sstevel@tonic-gate }
40937c478bd9Sstevel@tonic-gate 
40947c478bd9Sstevel@tonic-gate /* Section 4.2, 4.3, 4.4, 4.5 */
40957c478bd9Sstevel@tonic-gate static void
parse_controller_leaf(struct dnetinstance * dnetp,LEAF_FORMAT * leaf,uchar_t * vi)40967c478bd9Sstevel@tonic-gate parse_controller_leaf(struct dnetinstance *dnetp, LEAF_FORMAT *leaf,
4097*f879aa94SToomas Soome     uchar_t *vi)
40987c478bd9Sstevel@tonic-gate {
40997c478bd9Sstevel@tonic-gate 	int i;
41007c478bd9Sstevel@tonic-gate 
41017c478bd9Sstevel@tonic-gate 	leaf->selected_contype = *vi++;
41027c478bd9Sstevel@tonic-gate 	leaf->selected_contype |= *vi++ << 8;
41037c478bd9Sstevel@tonic-gate 
41047c478bd9Sstevel@tonic-gate 	if (dnetp->board_type == DEVICE_ID_21140) /* Sect. 4.3 */
41057c478bd9Sstevel@tonic-gate 		leaf->gpr = *vi++;
41067c478bd9Sstevel@tonic-gate 
41077c478bd9Sstevel@tonic-gate 	leaf->block_count = *vi++;
41087c478bd9Sstevel@tonic-gate 
41097c478bd9Sstevel@tonic-gate 	if (leaf->block_count > MAX_MEDIA) {
41107c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "dnet: Too many media in SROM!");
41117c478bd9Sstevel@tonic-gate 		leaf->block_count = 1;
41127c478bd9Sstevel@tonic-gate 	}
41137c478bd9Sstevel@tonic-gate 	for (i = 0; i <= leaf->block_count; i++) {
41147c478bd9Sstevel@tonic-gate 		vi = parse_media_block(dnetp, leaf->block + i, vi);
41157c478bd9Sstevel@tonic-gate 		if (leaf->block[i].command & CMD_DEFAULT_MEDIUM)
41167c478bd9Sstevel@tonic-gate 			leaf->default_block = leaf->block+i;
41177c478bd9Sstevel@tonic-gate 	}
41187c478bd9Sstevel@tonic-gate 	/* No explicit default block: use last in the ROM */
41197c478bd9Sstevel@tonic-gate 	if (leaf->default_block == NULL)
41207c478bd9Sstevel@tonic-gate 		leaf->default_block = leaf->block + leaf->block_count -1;
41217c478bd9Sstevel@tonic-gate 
41227c478bd9Sstevel@tonic-gate }
41237c478bd9Sstevel@tonic-gate 
41247c478bd9Sstevel@tonic-gate static uchar_t *
parse_media_block(struct dnetinstance * dnetp,media_block_t * block,uchar_t * vi)41257c478bd9Sstevel@tonic-gate parse_media_block(struct dnetinstance *dnetp, media_block_t *block, uchar_t *vi)
41267c478bd9Sstevel@tonic-gate {
41277c478bd9Sstevel@tonic-gate 	int i;
41287c478bd9Sstevel@tonic-gate 
41297c478bd9Sstevel@tonic-gate 	/*
41307c478bd9Sstevel@tonic-gate 	 * There are three kinds of media block we need to worry about:
41317c478bd9Sstevel@tonic-gate 	 * The 21041 blocks.
41327c478bd9Sstevel@tonic-gate 	 * 21140 blocks from a version 1 SROM
41337c478bd9Sstevel@tonic-gate 	 * 2114[023] block from a version 3 SROM
41347c478bd9Sstevel@tonic-gate 	 */
41357c478bd9Sstevel@tonic-gate 
41367c478bd9Sstevel@tonic-gate 	if (dnetp->board_type == DEVICE_ID_21041) {
41377c478bd9Sstevel@tonic-gate 		/* Section 4.2 */
41387c478bd9Sstevel@tonic-gate 		block->media_code = *vi & 0x3f;
41397c478bd9Sstevel@tonic-gate 		block->type = 2;
41407c478bd9Sstevel@tonic-gate 		if (*vi++ & 0x40) {
41417c478bd9Sstevel@tonic-gate 			block->un.sia.csr13 = *vi++;
41427c478bd9Sstevel@tonic-gate 			block->un.sia.csr13 |= *vi++ << 8;
41437c478bd9Sstevel@tonic-gate 			block->un.sia.csr14 = *vi++;
41447c478bd9Sstevel@tonic-gate 			block->un.sia.csr14 |= *vi++ << 8;
41457c478bd9Sstevel@tonic-gate 			block->un.sia.csr15 = *vi++;
41467c478bd9Sstevel@tonic-gate 			block->un.sia.csr15 |= *vi++ << 8;
41477c478bd9Sstevel@tonic-gate 		} else {
41487c478bd9Sstevel@tonic-gate 			/* No media data (csrs 13,14,15). Insert defaults */
41497c478bd9Sstevel@tonic-gate 			switch (block->media_code) {
41507c478bd9Sstevel@tonic-gate 			case MEDIA_TP:
41517c478bd9Sstevel@tonic-gate 				block->un.sia.csr13 = 0xef01;
41527c478bd9Sstevel@tonic-gate 				block->un.sia.csr14 = 0x7f3f;
41537c478bd9Sstevel@tonic-gate 				block->un.sia.csr15 = 0x0008;
41547c478bd9Sstevel@tonic-gate 				break;
41557c478bd9Sstevel@tonic-gate 			case MEDIA_TP_FD:
41567c478bd9Sstevel@tonic-gate 				block->un.sia.csr13 = 0xef01;
41577c478bd9Sstevel@tonic-gate 				block->un.sia.csr14 = 0x7f3d;
41587c478bd9Sstevel@tonic-gate 				block->un.sia.csr15 = 0x0008;
41597c478bd9Sstevel@tonic-gate 				break;
41607c478bd9Sstevel@tonic-gate 			case MEDIA_BNC:
41617c478bd9Sstevel@tonic-gate 				block->un.sia.csr13 = 0xef09;
41627c478bd9Sstevel@tonic-gate 				block->un.sia.csr14 = 0x0705;
41637c478bd9Sstevel@tonic-gate 				block->un.sia.csr15 = 0x0006;
41647c478bd9Sstevel@tonic-gate 				break;
41657c478bd9Sstevel@tonic-gate 			case MEDIA_AUI:
41667c478bd9Sstevel@tonic-gate 				block->un.sia.csr13 = 0xef09;
41677c478bd9Sstevel@tonic-gate 				block->un.sia.csr14 = 0x0705;
41687c478bd9Sstevel@tonic-gate 				block->un.sia.csr15 = 0x000e;
41697c478bd9Sstevel@tonic-gate 				break;
41707c478bd9Sstevel@tonic-gate 			}
41717c478bd9Sstevel@tonic-gate 		}
41727c478bd9Sstevel@tonic-gate 	} else  if (*vi & 0x80) {  /* Extended format: Section 4.3.2.2 */
41737c478bd9Sstevel@tonic-gate 		int blocklen = *vi++ & 0x7f;
41747c478bd9Sstevel@tonic-gate 		block->type = *vi++;
41757c478bd9Sstevel@tonic-gate 		switch (block->type) {
41767c478bd9Sstevel@tonic-gate 		case 0: /* "non-MII": Section 4.3.2.2.1 */
41777c478bd9Sstevel@tonic-gate 			block->media_code = (*vi++) & 0x3f;
41787c478bd9Sstevel@tonic-gate 			block->gprseqlen = 1;
41797c478bd9Sstevel@tonic-gate 			block->gprseq[0] = *vi++;
41807c478bd9Sstevel@tonic-gate 			block->command = *vi++;
41817c478bd9Sstevel@tonic-gate 			block->command |= *vi++ << 8;
41827c478bd9Sstevel@tonic-gate 			break;
41837c478bd9Sstevel@tonic-gate 
41847c478bd9Sstevel@tonic-gate 		case 1: /* MII/PHY: Section 4.3.2.2.2 */
41857c478bd9Sstevel@tonic-gate 			block->command = CMD_PS;
41867c478bd9Sstevel@tonic-gate 			block->media_code = MEDIA_MII;
41877c478bd9Sstevel@tonic-gate 				/* This is whats needed in CSR6 */
41887c478bd9Sstevel@tonic-gate 
41897c478bd9Sstevel@tonic-gate 			block->un.mii.phy_num = *vi++;
41907c478bd9Sstevel@tonic-gate 			block->gprseqlen = *vi++;
41917c478bd9Sstevel@tonic-gate 
41927c478bd9Sstevel@tonic-gate 			for (i = 0; i < block->gprseqlen; i++)
41937c478bd9Sstevel@tonic-gate 				block->gprseq[i] = *vi++;
41947c478bd9Sstevel@tonic-gate 			block->rstseqlen = *vi++;
41957c478bd9Sstevel@tonic-gate 			for (i = 0; i < block->rstseqlen; i++)
41967c478bd9Sstevel@tonic-gate 				block->rstseq[i] = *vi++;
41977c478bd9Sstevel@tonic-gate 
41987c478bd9Sstevel@tonic-gate 			block->un.mii.mediacaps = *vi++;
41997c478bd9Sstevel@tonic-gate 			block->un.mii.mediacaps |= *vi++ << 8;
42007c478bd9Sstevel@tonic-gate 			block->un.mii.nwayadvert = *vi++;
42017c478bd9Sstevel@tonic-gate 			block->un.mii.nwayadvert |= *vi++ << 8;
42027c478bd9Sstevel@tonic-gate 			block->un.mii.fdxmask = *vi++;
42037c478bd9Sstevel@tonic-gate 			block->un.mii.fdxmask |= *vi++ << 8;
42047c478bd9Sstevel@tonic-gate 			block->un.mii.ttmmask = *vi++;
42057c478bd9Sstevel@tonic-gate 			block->un.mii.ttmmask |= *vi++ << 8;
42067c478bd9Sstevel@tonic-gate 			break;
42077c478bd9Sstevel@tonic-gate 
42087c478bd9Sstevel@tonic-gate 		case 2: /* SIA Media: Section 4.4.2.1.1 */
42097c478bd9Sstevel@tonic-gate 			block->media_code = *vi & 0x3f;
42107c478bd9Sstevel@tonic-gate 			if (*vi++ & 0x40) {
42117c478bd9Sstevel@tonic-gate 				block->un.sia.csr13 = *vi++;
42127c478bd9Sstevel@tonic-gate 				block->un.sia.csr13 |= *vi++ << 8;
42137c478bd9Sstevel@tonic-gate 				block->un.sia.csr14 = *vi++;
42147c478bd9Sstevel@tonic-gate 				block->un.sia.csr14 |= *vi++ << 8;
42157c478bd9Sstevel@tonic-gate 				block->un.sia.csr15 = *vi++;
42167c478bd9Sstevel@tonic-gate 				block->un.sia.csr15 |= *vi++ << 8;
42177c478bd9Sstevel@tonic-gate 			} else {
42187c478bd9Sstevel@tonic-gate 				/*
42197c478bd9Sstevel@tonic-gate 				 * SIA values not provided by SROM; provide
42207c478bd9Sstevel@tonic-gate 				 * defaults. See appendix D of 2114[23] manuals.
42217c478bd9Sstevel@tonic-gate 				 */
42227c478bd9Sstevel@tonic-gate 				switch (block->media_code) {
42237c478bd9Sstevel@tonic-gate 				case MEDIA_BNC:
42247c478bd9Sstevel@tonic-gate 					block->un.sia.csr13 = 0x0009;
42257c478bd9Sstevel@tonic-gate 					block->un.sia.csr14 = 0x0705;
42267c478bd9Sstevel@tonic-gate 					block->un.sia.csr15 = 0x0000;
42277c478bd9Sstevel@tonic-gate 					break;
42287c478bd9Sstevel@tonic-gate 				case MEDIA_AUI:
42297c478bd9Sstevel@tonic-gate 					block->un.sia.csr13 = 0x0009;
42307c478bd9Sstevel@tonic-gate 					block->un.sia.csr14 = 0x0705;
42317c478bd9Sstevel@tonic-gate 					block->un.sia.csr15 = 0x0008;
42327c478bd9Sstevel@tonic-gate 					break;
42337c478bd9Sstevel@tonic-gate 				case MEDIA_TP:
42347c478bd9Sstevel@tonic-gate 					block->un.sia.csr13 = 0x0001;
42357c478bd9Sstevel@tonic-gate 					block->un.sia.csr14 = 0x7f3f;
42367c478bd9Sstevel@tonic-gate 					block->un.sia.csr15 = 0x0000;
42377c478bd9Sstevel@tonic-gate 					break;
42387c478bd9Sstevel@tonic-gate 				case MEDIA_TP_FD:
42397c478bd9Sstevel@tonic-gate 					block->un.sia.csr13 = 0x0001;
42407c478bd9Sstevel@tonic-gate 					block->un.sia.csr14 = 0x7f3d;
42417c478bd9Sstevel@tonic-gate 					block->un.sia.csr15 = 0x0000;
42427c478bd9Sstevel@tonic-gate 					break;
42437c478bd9Sstevel@tonic-gate 				default:
42447c478bd9Sstevel@tonic-gate 					block->un.sia.csr13 = 0x0000;
42457c478bd9Sstevel@tonic-gate 					block->un.sia.csr14 = 0x0000;
42467c478bd9Sstevel@tonic-gate 					block->un.sia.csr15 = 0x0000;
42477c478bd9Sstevel@tonic-gate 				}
42487c478bd9Sstevel@tonic-gate 			}
42497c478bd9Sstevel@tonic-gate 
42507c478bd9Sstevel@tonic-gate 			/* Treat GP control/data as a GPR sequence */
42517c478bd9Sstevel@tonic-gate 			block->gprseqlen = 2;
42527c478bd9Sstevel@tonic-gate 			block->gprseq[0] = *vi++;
42537c478bd9Sstevel@tonic-gate 			block->gprseq[0] |= *vi++ << 8;
42547c478bd9Sstevel@tonic-gate 			block->gprseq[0] |= GPR_CONTROL_WRITE;
42557c478bd9Sstevel@tonic-gate 			block->gprseq[1] = *vi++;
42567c478bd9Sstevel@tonic-gate 			block->gprseq[1] |= *vi++ << 8;
42577c478bd9Sstevel@tonic-gate 			break;
42587c478bd9Sstevel@tonic-gate 
42597c478bd9Sstevel@tonic-gate 		case 3: /* MII/PHY : Section 4.4.2.1.2 */
42607c478bd9Sstevel@tonic-gate 			block->command = CMD_PS;
42617c478bd9Sstevel@tonic-gate 			block->media_code = MEDIA_MII;
42627c478bd9Sstevel@tonic-gate 			block->un.mii.phy_num = *vi++;
42637c478bd9Sstevel@tonic-gate 
42647c478bd9Sstevel@tonic-gate 			block->gprseqlen = *vi++;
42657c478bd9Sstevel@tonic-gate 			for (i = 0; i < block->gprseqlen; i++) {
42667c478bd9Sstevel@tonic-gate 				block->gprseq[i] = *vi++;
42677c478bd9Sstevel@tonic-gate 				block->gprseq[i] |= *vi++ << 8;
42687c478bd9Sstevel@tonic-gate 			}
42697c478bd9Sstevel@tonic-gate 
42707c478bd9Sstevel@tonic-gate 			block->rstseqlen = *vi++;
42717c478bd9Sstevel@tonic-gate 			for (i = 0; i < block->rstseqlen; i++) {
42727c478bd9Sstevel@tonic-gate 				block->rstseq[i] = *vi++;
42737c478bd9Sstevel@tonic-gate 				block->rstseq[i] |= *vi++ << 8;
42747c478bd9Sstevel@tonic-gate 			}
42757c478bd9Sstevel@tonic-gate 			block->un.mii.mediacaps = *vi++;
42767c478bd9Sstevel@tonic-gate 			block->un.mii.mediacaps |= *vi++ << 8;
42777c478bd9Sstevel@tonic-gate 			block->un.mii.nwayadvert = *vi++;
42787c478bd9Sstevel@tonic-gate 			block->un.mii.nwayadvert |= *vi++ << 8;
42797c478bd9Sstevel@tonic-gate 			block->un.mii.fdxmask = *vi++;
42807c478bd9Sstevel@tonic-gate 			block->un.mii.fdxmask |= *vi++ << 8;
42817c478bd9Sstevel@tonic-gate 			block->un.mii.ttmmask = *vi++;
42827c478bd9Sstevel@tonic-gate 			block->un.mii.ttmmask |= *vi++ << 8;
42837c478bd9Sstevel@tonic-gate 			block->un.mii.miiintr |= *vi++;
42847c478bd9Sstevel@tonic-gate 			break;
42857c478bd9Sstevel@tonic-gate 
42867c478bd9Sstevel@tonic-gate 		case 4: /* SYM Media: 4.5.2.1.3 */
42877c478bd9Sstevel@tonic-gate 			block->media_code = *vi++ & 0x3f;
42887c478bd9Sstevel@tonic-gate 			/* Treat GP control and data as a GPR sequence */
42897c478bd9Sstevel@tonic-gate 			block->gprseqlen = 2;
42907c478bd9Sstevel@tonic-gate 			block->gprseq[0] = *vi++;
42917c478bd9Sstevel@tonic-gate 			block->gprseq[0] |= *vi++ << 8;
42927c478bd9Sstevel@tonic-gate 			block->gprseq[0] |= GPR_CONTROL_WRITE;
42937c478bd9Sstevel@tonic-gate 			block->gprseq[1]  = *vi++;
42947c478bd9Sstevel@tonic-gate 			block->gprseq[1] |= *vi++ << 8;
42957c478bd9Sstevel@tonic-gate 			block->command = *vi++;
42969fe7edecSgd 			block->command |= *vi++ << 8;
42977c478bd9Sstevel@tonic-gate 			break;
42987c478bd9Sstevel@tonic-gate 
42997c478bd9Sstevel@tonic-gate 		case 5: /* GPR reset sequence:  Section 4.5.2.1.4 */
43007c478bd9Sstevel@tonic-gate 			block->rstseqlen = *vi++;
43017c478bd9Sstevel@tonic-gate 			for (i = 0; i < block->rstseqlen; i++)
43027c478bd9Sstevel@tonic-gate 				block->rstseq[i] = *vi++;
43037c478bd9Sstevel@tonic-gate 			break;
43047c478bd9Sstevel@tonic-gate 
43057c478bd9Sstevel@tonic-gate 		default: /* Unknown media block. Skip it. */
43067c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "dnet: Unsupported SROM block.");
43077c478bd9Sstevel@tonic-gate 			vi += blocklen;
43087c478bd9Sstevel@tonic-gate 			break;
43097c478bd9Sstevel@tonic-gate 		}
43107c478bd9Sstevel@tonic-gate 	} else { /* Compact format (or V1 SROM): Section 4.3.2.1 */
43117c478bd9Sstevel@tonic-gate 		block->type = 0;
43127c478bd9Sstevel@tonic-gate 		block->media_code = *vi++ & 0x3f;
43137c478bd9Sstevel@tonic-gate 		block->gprseqlen = 1;
43147c478bd9Sstevel@tonic-gate 		block->gprseq[0] = *vi++;
43157c478bd9Sstevel@tonic-gate 		block->command = *vi++;
43167c478bd9Sstevel@tonic-gate 		block->command |= (*vi++) << 8;
43177c478bd9Sstevel@tonic-gate 	}
43187c478bd9Sstevel@tonic-gate 	return (vi);
43197c478bd9Sstevel@tonic-gate }
43207c478bd9Sstevel@tonic-gate 
43217c478bd9Sstevel@tonic-gate 
43227c478bd9Sstevel@tonic-gate /*
43237c478bd9Sstevel@tonic-gate  * An alternative to doing this would be to store the legacy ROMs in binary
43247c478bd9Sstevel@tonic-gate  * format in the conf file, and in read_srom, pick out the data. This would
43257c478bd9Sstevel@tonic-gate  * then allow the parser to continue on as normal. This makes it a little
43267c478bd9Sstevel@tonic-gate  * easier to read.
43277c478bd9Sstevel@tonic-gate  */
43287c478bd9Sstevel@tonic-gate static void
setup_legacy_blocks()43297c478bd9Sstevel@tonic-gate setup_legacy_blocks()
43307c478bd9Sstevel@tonic-gate {
43317c478bd9Sstevel@tonic-gate 	LEAF_FORMAT *leaf;
43327c478bd9Sstevel@tonic-gate 	media_block_t *block;
43337c478bd9Sstevel@tonic-gate 
43347c478bd9Sstevel@tonic-gate 	/* Default FAKE SROM */
43357c478bd9Sstevel@tonic-gate 	leaf = &leaf_default_100;
43367c478bd9Sstevel@tonic-gate 	leaf->is_static = 1;
43377c478bd9Sstevel@tonic-gate 	leaf->default_block = &leaf->block[3];
43387c478bd9Sstevel@tonic-gate 	leaf->block_count = 4; /* 100 cards are highly unlikely to have BNC */
43397c478bd9Sstevel@tonic-gate 	block = leaf->block;
43407c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_TP_FD;
43417c478bd9Sstevel@tonic-gate 	block->type = 0;
43427c478bd9Sstevel@tonic-gate 	block->command = 0x8e;  /* PCS, PS off, media sense: bit7, pol=1 */
43437c478bd9Sstevel@tonic-gate 	block++;
43447c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_TP;
43457c478bd9Sstevel@tonic-gate 	block->type = 0;
43467c478bd9Sstevel@tonic-gate 	block->command = 0x8e;  /* PCS, PS off, media sense: bit7, pol=1 */
43477c478bd9Sstevel@tonic-gate 	block++;
43487c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_SYM_SCR_FD;
43497c478bd9Sstevel@tonic-gate 	block->type = 0;
43507c478bd9Sstevel@tonic-gate 	block->command = 0x6d;  /* PCS, PS, SCR on, media sense: bit6, pol=0 */
43517c478bd9Sstevel@tonic-gate 	block++;
43527c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_SYM_SCR;
43537c478bd9Sstevel@tonic-gate 	block->type = 0;
43547c478bd9Sstevel@tonic-gate 	block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
43557c478bd9Sstevel@tonic-gate 
43567c478bd9Sstevel@tonic-gate 	/* COGENT FAKE SROM */
43577c478bd9Sstevel@tonic-gate 	leaf = &leaf_cogent_100;
43587c478bd9Sstevel@tonic-gate 	leaf->is_static = 1;
43597c478bd9Sstevel@tonic-gate 	leaf->default_block = &leaf->block[4];
43607c478bd9Sstevel@tonic-gate 	leaf->block_count = 5; /* 100TX, 100TX-FD, 10T 10T-FD, BNC */
43617c478bd9Sstevel@tonic-gate 	block = leaf->block; /* BNC */
43627c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_BNC;
43637c478bd9Sstevel@tonic-gate 	block->type = 0;
43647c478bd9Sstevel@tonic-gate 	block->command =  0x8000; /* No media sense, PCS, SCR, PS all off */
43657c478bd9Sstevel@tonic-gate 	block->gprseqlen = 2;
43667c478bd9Sstevel@tonic-gate 	block->rstseqlen = 0;
43677c478bd9Sstevel@tonic-gate 	block->gprseq[0] = 0x13f;
43687c478bd9Sstevel@tonic-gate 	block->gprseq[1] = 1;
43697c478bd9Sstevel@tonic-gate 
43707c478bd9Sstevel@tonic-gate 	block++;
43717c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_TP_FD;
43727c478bd9Sstevel@tonic-gate 	block->type = 0;
43737c478bd9Sstevel@tonic-gate 	block->command = 0x8e;  /* PCS, PS off, media sense: bit7, pol=1 */
43747c478bd9Sstevel@tonic-gate 	block->gprseqlen = 2;
43757c478bd9Sstevel@tonic-gate 	block->rstseqlen = 0;
43767c478bd9Sstevel@tonic-gate 	block->gprseq[0] = 0x13f;
43777c478bd9Sstevel@tonic-gate 	block->gprseq[1] = 0x26;
43787c478bd9Sstevel@tonic-gate 
43797c478bd9Sstevel@tonic-gate 	block++; /* 10BaseT */
43807c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_TP;
43817c478bd9Sstevel@tonic-gate 	block->type = 0;
43827c478bd9Sstevel@tonic-gate 	block->command = 0x8e;  /* PCS, PS off, media sense: bit7, pol=1 */
43837c478bd9Sstevel@tonic-gate 	block->gprseqlen = 2;
43847c478bd9Sstevel@tonic-gate 	block->rstseqlen = 0;
43857c478bd9Sstevel@tonic-gate 	block->gprseq[0] = 0x13f;
43867c478bd9Sstevel@tonic-gate 	block->gprseq[1] = 0x3e;
43877c478bd9Sstevel@tonic-gate 
43887c478bd9Sstevel@tonic-gate 	block++; /* 100BaseTX-FD */
43897c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_SYM_SCR_FD;
43907c478bd9Sstevel@tonic-gate 	block->type = 0;
43917c478bd9Sstevel@tonic-gate 	block->command = 0x6d;  /* PCS, PS, SCR on, media sense: bit6, pol=0 */
43927c478bd9Sstevel@tonic-gate 	block->gprseqlen = 2;
43937c478bd9Sstevel@tonic-gate 	block->rstseqlen = 0;
43947c478bd9Sstevel@tonic-gate 	block->gprseq[0] = 0x13f;
43957c478bd9Sstevel@tonic-gate 	block->gprseq[1] = 1;
43967c478bd9Sstevel@tonic-gate 
43977c478bd9Sstevel@tonic-gate 	block++; /* 100BaseTX */
43987c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_SYM_SCR;
43997c478bd9Sstevel@tonic-gate 	block->type = 0;
44007c478bd9Sstevel@tonic-gate 	block->command = 0x406d; /* PCS, PS, SCR on, media sense: bit6, pol=0 */
44017c478bd9Sstevel@tonic-gate 	block->gprseqlen = 2;
44027c478bd9Sstevel@tonic-gate 	block->rstseqlen = 0;
44037c478bd9Sstevel@tonic-gate 	block->gprseq[0] = 0x13f;
44047c478bd9Sstevel@tonic-gate 	block->gprseq[1] = 1;
44057c478bd9Sstevel@tonic-gate 
44067c478bd9Sstevel@tonic-gate 	/* Generic legacy card with a PHY. */
44077c478bd9Sstevel@tonic-gate 	leaf = &leaf_phylegacy;
44087c478bd9Sstevel@tonic-gate 	leaf->block_count = 1;
44097c478bd9Sstevel@tonic-gate 	leaf->mii_block = leaf->block;
44107c478bd9Sstevel@tonic-gate 	leaf->default_block = &leaf->block[0];
44117c478bd9Sstevel@tonic-gate 	leaf->is_static = 1;
44127c478bd9Sstevel@tonic-gate 	block = leaf->block;
44137c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_MII;
44147c478bd9Sstevel@tonic-gate 	block->type = 1; /* MII Block type 1 */
44157c478bd9Sstevel@tonic-gate 	block->command = 1; /* Port select */
44167c478bd9Sstevel@tonic-gate 	block->gprseqlen = 0;
44177c478bd9Sstevel@tonic-gate 	block->rstseqlen = 0;
44187c478bd9Sstevel@tonic-gate 
44197c478bd9Sstevel@tonic-gate 	/* ASANTE FAKE SROM */
44207c478bd9Sstevel@tonic-gate 	leaf = &leaf_asante;
44217c478bd9Sstevel@tonic-gate 	leaf->is_static = 1;
44227c478bd9Sstevel@tonic-gate 	leaf->default_block = &leaf->block[0];
44237c478bd9Sstevel@tonic-gate 	leaf->block_count = 1;
44247c478bd9Sstevel@tonic-gate 	block = leaf->block;
44257c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_MII;
44267c478bd9Sstevel@tonic-gate 	block->type = 1; /* MII Block type 1 */
44277c478bd9Sstevel@tonic-gate 	block->command = 1; /* Port select */
44287c478bd9Sstevel@tonic-gate 	block->gprseqlen = 3;
44297c478bd9Sstevel@tonic-gate 	block->rstseqlen = 0;
44307c478bd9Sstevel@tonic-gate 	block->gprseq[0] = 0x180;
44317c478bd9Sstevel@tonic-gate 	block->gprseq[1] = 0x80;
44327c478bd9Sstevel@tonic-gate 	block->gprseq[2] = 0x0;
44337c478bd9Sstevel@tonic-gate 
44347c478bd9Sstevel@tonic-gate 	/* LEGACY 21041 card FAKE SROM */
44357c478bd9Sstevel@tonic-gate 	leaf = &leaf_21041;
44367c478bd9Sstevel@tonic-gate 	leaf->is_static = 1;
44377c478bd9Sstevel@tonic-gate 	leaf->block_count = 4;  /* SIA Blocks for TP, TPfd, BNC, AUI */
44387c478bd9Sstevel@tonic-gate 	leaf->default_block = &leaf->block[3];
44397c478bd9Sstevel@tonic-gate 
44407c478bd9Sstevel@tonic-gate 	block = leaf->block;
44417c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_AUI;
44427c478bd9Sstevel@tonic-gate 	block->type = 2;
44437c478bd9Sstevel@tonic-gate 	block->un.sia.csr13 = 0xef09;
44447c478bd9Sstevel@tonic-gate 	block->un.sia.csr14 = 0x0705;
44457c478bd9Sstevel@tonic-gate 	block->un.sia.csr15 = 0x000e;
44467c478bd9Sstevel@tonic-gate 
44477c478bd9Sstevel@tonic-gate 	block++;
44487c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_TP_FD;
44497c478bd9Sstevel@tonic-gate 	block->type = 2;
44507c478bd9Sstevel@tonic-gate 	block->un.sia.csr13 = 0xef01;
44517c478bd9Sstevel@tonic-gate 	block->un.sia.csr14 = 0x7f3d;
44527c478bd9Sstevel@tonic-gate 	block->un.sia.csr15 = 0x0008;
44537c478bd9Sstevel@tonic-gate 
44547c478bd9Sstevel@tonic-gate 	block++;
44557c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_BNC;
44567c478bd9Sstevel@tonic-gate 	block->type = 2;
44577c478bd9Sstevel@tonic-gate 	block->un.sia.csr13 = 0xef09;
44587c478bd9Sstevel@tonic-gate 	block->un.sia.csr14 = 0x0705;
44597c478bd9Sstevel@tonic-gate 	block->un.sia.csr15 = 0x0006;
44607c478bd9Sstevel@tonic-gate 
44617c478bd9Sstevel@tonic-gate 	block++;
44627c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_TP;
44637c478bd9Sstevel@tonic-gate 	block->type = 2;
44647c478bd9Sstevel@tonic-gate 	block->un.sia.csr13 = 0xef01;
44657c478bd9Sstevel@tonic-gate 	block->un.sia.csr14 = 0x7f3f;
44667c478bd9Sstevel@tonic-gate 	block->un.sia.csr15 = 0x0008;
44677c478bd9Sstevel@tonic-gate 
44687c478bd9Sstevel@tonic-gate 	/* LEGACY 21040 card FAKE SROM */
44697c478bd9Sstevel@tonic-gate 	leaf = &leaf_21040;
44707c478bd9Sstevel@tonic-gate 	leaf->is_static = 1;
44717c478bd9Sstevel@tonic-gate 	leaf->block_count = 4;  /* SIA Blocks for TP, TPfd, BNC, AUI */
44727c478bd9Sstevel@tonic-gate 	block = leaf->block;
44737c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_AUI;
44747c478bd9Sstevel@tonic-gate 	block->type = 2;
44757c478bd9Sstevel@tonic-gate 	block->un.sia.csr13 = 0x8f09;
44767c478bd9Sstevel@tonic-gate 	block->un.sia.csr14 = 0x0705;
44777c478bd9Sstevel@tonic-gate 	block->un.sia.csr15 = 0x000e;
44787c478bd9Sstevel@tonic-gate 	block++;
44797c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_TP_FD;
44807c478bd9Sstevel@tonic-gate 	block->type = 2;
44817c478bd9Sstevel@tonic-gate 	block->un.sia.csr13 = 0x0f01;
44827c478bd9Sstevel@tonic-gate 	block->un.sia.csr14 = 0x7f3d;
44837c478bd9Sstevel@tonic-gate 	block->un.sia.csr15 = 0x0008;
44847c478bd9Sstevel@tonic-gate 	block++;
44857c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_BNC;
44867c478bd9Sstevel@tonic-gate 	block->type = 2;
44877c478bd9Sstevel@tonic-gate 	block->un.sia.csr13 = 0xef09;
44887c478bd9Sstevel@tonic-gate 	block->un.sia.csr14 = 0x0705;
44897c478bd9Sstevel@tonic-gate 	block->un.sia.csr15 = 0x0006;
44907c478bd9Sstevel@tonic-gate 	block++;
44917c478bd9Sstevel@tonic-gate 	block->media_code = MEDIA_TP;
44927c478bd9Sstevel@tonic-gate 	block->type = 2;
44937c478bd9Sstevel@tonic-gate 	block->un.sia.csr13 = 0x8f01;
44947c478bd9Sstevel@tonic-gate 	block->un.sia.csr14 = 0x7f3f;
44957c478bd9Sstevel@tonic-gate 	block->un.sia.csr15 = 0x0008;
44967c478bd9Sstevel@tonic-gate }
44977c478bd9Sstevel@tonic-gate 
44987c478bd9Sstevel@tonic-gate static void
dnet_print_srom(SROM_FORMAT * sr)44997c478bd9Sstevel@tonic-gate dnet_print_srom(SROM_FORMAT *sr)
45007c478bd9Sstevel@tonic-gate {
45017c478bd9Sstevel@tonic-gate 	int i;
45027c478bd9Sstevel@tonic-gate 	uchar_t *a = sr->netaddr;
45037c478bd9Sstevel@tonic-gate 	cmn_err(CE_NOTE, "SROM Dump: %d. ver %d, Num adapters %d,"
450417de24c9Svb 	    "Addr:%x:%x:%x:%x:%x:%x",
450517de24c9Svb 	    sr->init_from_srom, sr->version, sr->adapters,
450617de24c9Svb 	    a[0], a[1], a[2], a[3], a[4], a[5]);
45077c478bd9Sstevel@tonic-gate 
45087c478bd9Sstevel@tonic-gate 	for (i = 0; i < sr->adapters; i++)
45097c478bd9Sstevel@tonic-gate 		dnet_dump_leaf(sr->leaf+i);
45107c478bd9Sstevel@tonic-gate }
45117c478bd9Sstevel@tonic-gate 
45127c478bd9Sstevel@tonic-gate static void
dnet_dump_leaf(LEAF_FORMAT * leaf)45137c478bd9Sstevel@tonic-gate dnet_dump_leaf(LEAF_FORMAT *leaf)
45147c478bd9Sstevel@tonic-gate {
45157c478bd9Sstevel@tonic-gate 	int i;
45167c478bd9Sstevel@tonic-gate 	cmn_err(CE_NOTE, "Leaf: Device %d, block_count %d, gpr: %x",
451717de24c9Svb 	    leaf->device_number, leaf->block_count, leaf->gpr);
45187c478bd9Sstevel@tonic-gate 	for (i = 0; i < leaf->block_count; i++)
45197c478bd9Sstevel@tonic-gate 		dnet_dump_block(leaf->block+i);
45207c478bd9Sstevel@tonic-gate }
45217c478bd9Sstevel@tonic-gate 
45227c478bd9Sstevel@tonic-gate static void
dnet_dump_block(media_block_t * block)45237c478bd9Sstevel@tonic-gate dnet_dump_block(media_block_t *block)
45247c478bd9Sstevel@tonic-gate {
45257c478bd9Sstevel@tonic-gate 	cmn_err(CE_NOTE, "Block(%p): type %x, media %s, command: %x ",
45267c478bd9Sstevel@tonic-gate 	    (void *)block,
45277c478bd9Sstevel@tonic-gate 	    block->type, media_str[block->media_code], block->command);
45287c478bd9Sstevel@tonic-gate 	dnet_dumpbin("\tGPR Seq", (uchar_t *)block->gprseq, 2,
45297c478bd9Sstevel@tonic-gate 	    block->gprseqlen *2);
45307c478bd9Sstevel@tonic-gate 	dnet_dumpbin("\tGPR Reset", (uchar_t *)block->rstseq, 2,
45317c478bd9Sstevel@tonic-gate 	    block->rstseqlen *2);
45327c478bd9Sstevel@tonic-gate 	switch (block->type) {
45337c478bd9Sstevel@tonic-gate 	case 1: case 3:
45347c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "\tMII Info: phy %d, nway %x, fdx"
453517de24c9Svb 		    "%x, ttm %x, mediacap %x",
453617de24c9Svb 		    block->un.mii.phy_num, block->un.mii.nwayadvert,
453717de24c9Svb 		    block->un.mii.fdxmask, block->un.mii.ttmmask,
453817de24c9Svb 		    block->un.mii.mediacaps);
45397c478bd9Sstevel@tonic-gate 		break;
45407c478bd9Sstevel@tonic-gate 	case 2:
45417c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "\tSIA Regs: CSR13:%x, CSR14:%x, CSR15:%x",
454217de24c9Svb 		    block->un.sia.csr13, block->un.sia.csr14,
454317de24c9Svb 		    block->un.sia.csr15);
45447c478bd9Sstevel@tonic-gate 		break;
45457c478bd9Sstevel@tonic-gate 	}
45467c478bd9Sstevel@tonic-gate }
45477c478bd9Sstevel@tonic-gate 
45487c478bd9Sstevel@tonic-gate 
45497c478bd9Sstevel@tonic-gate /* Utility to print out binary info dumps. Handy for SROMs, etc */
45507c478bd9Sstevel@tonic-gate 
45517c478bd9Sstevel@tonic-gate static int
hexcode(unsigned val)45527c478bd9Sstevel@tonic-gate hexcode(unsigned val)
45537c478bd9Sstevel@tonic-gate {
45547c478bd9Sstevel@tonic-gate 	if (val <= 9)
45557c478bd9Sstevel@tonic-gate 		return (val +'0');
45567c478bd9Sstevel@tonic-gate 	if (val <= 15)
45577c478bd9Sstevel@tonic-gate 		return (val + 'a' - 10);
45587c478bd9Sstevel@tonic-gate 	return (-1);
45597c478bd9Sstevel@tonic-gate }
45607c478bd9Sstevel@tonic-gate 
45617c478bd9Sstevel@tonic-gate static void
dnet_dumpbin(char * msg,unsigned char * data,int size,int len)45627c478bd9Sstevel@tonic-gate dnet_dumpbin(char *msg, unsigned char *data, int size, int len)
45637c478bd9Sstevel@tonic-gate {
45647c478bd9Sstevel@tonic-gate 	char hex[128], *p = hex;
45657c478bd9Sstevel@tonic-gate 	char ascii[128], *q = ascii;
45667c478bd9Sstevel@tonic-gate 	int i, j;
45677c478bd9Sstevel@tonic-gate 
45687c478bd9Sstevel@tonic-gate 	if (!len)
45697c478bd9Sstevel@tonic-gate 		return;
45707c478bd9Sstevel@tonic-gate 
45717c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i += size) {
45727c478bd9Sstevel@tonic-gate 		for (j = size - 1; j >= 0; j--) { /* PORTABILITY: byte order */
45737c478bd9Sstevel@tonic-gate 			*p++ = hexcode(data[i+j] >> 4);
45747c478bd9Sstevel@tonic-gate 			*p++ = hexcode(data[i+j] & 0xf);
45757c478bd9Sstevel@tonic-gate 			*q++ = (data[i+j] < 32 || data[i+j] > 127) ?
45767c478bd9Sstevel@tonic-gate 			    '.' : data[i];
45777c478bd9Sstevel@tonic-gate 		}
45787c478bd9Sstevel@tonic-gate 		*p++ = ' ';
45797c478bd9Sstevel@tonic-gate 		if (q-ascii >= 8) {
45807c478bd9Sstevel@tonic-gate 			*p = *q = 0;
45817c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii);
45827c478bd9Sstevel@tonic-gate 			p = hex;
45837c478bd9Sstevel@tonic-gate 			q = ascii;
45847c478bd9Sstevel@tonic-gate 		}
45857c478bd9Sstevel@tonic-gate 	}
45867c478bd9Sstevel@tonic-gate 	if (p != hex) {
45877c478bd9Sstevel@tonic-gate 		while ((p - hex) < 8*3)
458817de24c9Svb 			*p++ = ' ';
45897c478bd9Sstevel@tonic-gate 		*p = *q = 0;
45907c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "%s: %s\t%s", msg, hex, ascii);
45917c478bd9Sstevel@tonic-gate 	}
45927c478bd9Sstevel@tonic-gate }
45937c478bd9Sstevel@tonic-gate 
45947c478bd9Sstevel@tonic-gate #ifdef DNETDEBUG
45957c478bd9Sstevel@tonic-gate void
dnet_usectimeout(struct dnetinstance * dnetp,uint32_t usecs,int contin,timercb_t cback)45967c478bd9Sstevel@tonic-gate dnet_usectimeout(struct dnetinstance *dnetp, uint32_t usecs, int contin,
45977c478bd9Sstevel@tonic-gate     timercb_t cback)
45987c478bd9Sstevel@tonic-gate {
45997c478bd9Sstevel@tonic-gate 	mutex_enter(&dnetp->intrlock);
46007c478bd9Sstevel@tonic-gate 	dnetp->timer.start_ticks = (usecs * 100) / 8192;
46017c478bd9Sstevel@tonic-gate 	dnetp->timer.cb = cback;
46028ef10d20Sgd 	ddi_put32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG),
46038ef10d20Sgd 	    dnetp->timer.start_ticks | (contin ? GPTIMER_CONT : 0));
46047c478bd9Sstevel@tonic-gate 	if (dnetp->timer.cb)
460598e8d175SSteven Stallion 		enable_interrupts(dnetp);
46067c478bd9Sstevel@tonic-gate 	mutex_exit(&dnetp->intrlock);
46077c478bd9Sstevel@tonic-gate }
46087c478bd9Sstevel@tonic-gate 
46097c478bd9Sstevel@tonic-gate uint32_t
dnet_usecelapsed(struct dnetinstance * dnetp)46107c478bd9Sstevel@tonic-gate dnet_usecelapsed(struct dnetinstance *dnetp)
46117c478bd9Sstevel@tonic-gate {
46127c478bd9Sstevel@tonic-gate 	uint32_t ticks = dnetp->timer.start_ticks -
46138ef10d20Sgd 	    (ddi_get32(dnetp->io_handle, REG32(dnetp->io_reg, GP_TIMER_REG)) &
46148ef10d20Sgd 	    0xffff);
46157c478bd9Sstevel@tonic-gate 	return ((ticks * 8192) / 100);
46167c478bd9Sstevel@tonic-gate }
46177c478bd9Sstevel@tonic-gate 
46187c478bd9Sstevel@tonic-gate /* ARGSUSED */
46197c478bd9Sstevel@tonic-gate void
dnet_timestamp(struct dnetinstance * dnetp,char * buf)46207c478bd9Sstevel@tonic-gate dnet_timestamp(struct dnetinstance *dnetp,  char *buf)
46217c478bd9Sstevel@tonic-gate {
46227c478bd9Sstevel@tonic-gate 	uint32_t elapsed = dnet_usecelapsed(dnetp);
46237c478bd9Sstevel@tonic-gate 	char loc[32], *p = loc;
46247c478bd9Sstevel@tonic-gate 	int firstdigit = 1;
46257c478bd9Sstevel@tonic-gate 	uint32_t divisor;
46267c478bd9Sstevel@tonic-gate 
46277c478bd9Sstevel@tonic-gate 	while (*p++ = *buf++)
46287c478bd9Sstevel@tonic-gate 		;
46297c478bd9Sstevel@tonic-gate 	p--;
46307c478bd9Sstevel@tonic-gate 
46317c478bd9Sstevel@tonic-gate 	for (divisor = 1000000000; divisor /= 10; ) {
46327c478bd9Sstevel@tonic-gate 		int digit = (elapsed / divisor);
46337c478bd9Sstevel@tonic-gate 		elapsed -= digit * divisor;
46347c478bd9Sstevel@tonic-gate 		if (!firstdigit || digit) {
46357c478bd9Sstevel@tonic-gate 			*p++ = digit + '0';
46367c478bd9Sstevel@tonic-gate 			firstdigit = 0;
46377c478bd9Sstevel@tonic-gate 		}
46387c478bd9Sstevel@tonic-gate 
46397c478bd9Sstevel@tonic-gate 	}
46407c478bd9Sstevel@tonic-gate 
46417c478bd9Sstevel@tonic-gate 	/* Actual zero, output it */
46427c478bd9Sstevel@tonic-gate 	if (firstdigit)
46437c478bd9Sstevel@tonic-gate 		*p++ = '0';
46447c478bd9Sstevel@tonic-gate 
46457c478bd9Sstevel@tonic-gate 	*p++ = '-';
46467c478bd9Sstevel@tonic-gate 	*p++ = '>';
46477c478bd9Sstevel@tonic-gate 	*p++ = 0;
4648a8320b74Smeem 
46497c478bd9Sstevel@tonic-gate 	printf(loc);
46507c478bd9Sstevel@tonic-gate 	dnet_usectimeout(dnetp, 1000000, 0, 0);
46517c478bd9Sstevel@tonic-gate }
46527c478bd9Sstevel@tonic-gate 
46537c478bd9Sstevel@tonic-gate #endif
4654