xref: /illumos-gate/usr/src/uts/common/io/hme/hme.c (revision 0219346b07c8d846112a335f1543309c21e3d8da)
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
5447e4a63Spetede  * Common Development and Distribution License (the "License").
6447e4a63Spetede  * 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  */
217c478bd9Sstevel@tonic-gate /*
22*0219346bSGarrett D'Amore  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate /*
287c478bd9Sstevel@tonic-gate  * SunOS MT STREAMS FEPS(SBus)/Cheerio(PCI) 10/100Mb Ethernet Device Driver
297c478bd9Sstevel@tonic-gate  */
307c478bd9Sstevel@tonic-gate 
317c478bd9Sstevel@tonic-gate #include	<sys/types.h>
327c478bd9Sstevel@tonic-gate #include	<sys/debug.h>
337c478bd9Sstevel@tonic-gate #include	<sys/stream.h>
347c478bd9Sstevel@tonic-gate #include	<sys/cmn_err.h>
357c478bd9Sstevel@tonic-gate #include	<sys/kmem.h>
367c478bd9Sstevel@tonic-gate #include	<sys/crc32.h>
3785025c03Sgd #include	<sys/modctl.h>
3885025c03Sgd #include	<sys/conf.h>
397c478bd9Sstevel@tonic-gate #include	<sys/strsun.h>
407c478bd9Sstevel@tonic-gate #include	<sys/kstat.h>
417c478bd9Sstevel@tonic-gate #include	<inet/common.h>
427c478bd9Sstevel@tonic-gate #include	<inet/mi.h>
437c478bd9Sstevel@tonic-gate #include	<inet/nd.h>
4485025c03Sgd #include	<sys/pattr.h>
457c478bd9Sstevel@tonic-gate #include	<sys/dlpi.h>
4685025c03Sgd #include	<sys/strsubr.h>
47da14cebeSEric Cheng #include	<sys/mac_provider.h>
4885025c03Sgd #include	<sys/mac_ether.h>
497c478bd9Sstevel@tonic-gate #include	<sys/ethernet.h>
50d62bc4baSyz #include	<sys/vlan.h>
5185025c03Sgd #include	<sys/pci.h>
5285025c03Sgd #include	<sys/policy.h>
5385025c03Sgd #include	<sys/ddi.h>
5485025c03Sgd #include	<sys/sunddi.h>
55*0219346bSGarrett D'Amore #include	"hme_phy.h"
56*0219346bSGarrett D'Amore #include	"hme_mac.h"
57*0219346bSGarrett D'Amore #include	"hme.h"
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate typedef void	(*fptrv_t)();
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate typedef enum {
627c478bd9Sstevel@tonic-gate 	NO_MSG		= 0,
637c478bd9Sstevel@tonic-gate 	AUTOCONFIG_MSG	= 1,
647c478bd9Sstevel@tonic-gate 	STREAMS_MSG	= 2,
657c478bd9Sstevel@tonic-gate 	IOCTL_MSG	= 3,
667c478bd9Sstevel@tonic-gate 	PROTO_MSG	= 4,
677c478bd9Sstevel@tonic-gate 	INIT_MSG	= 5,
687c478bd9Sstevel@tonic-gate 	TX_MSG		= 6,
697c478bd9Sstevel@tonic-gate 	RX_MSG		= 7,
707c478bd9Sstevel@tonic-gate 	INTR_MSG	= 8,
717c478bd9Sstevel@tonic-gate 	UNINIT_MSG	= 9,
727c478bd9Sstevel@tonic-gate 	CONFIG_MSG	= 10,
737c478bd9Sstevel@tonic-gate 	PROP_MSG	= 11,
747c478bd9Sstevel@tonic-gate 	ENTER_MSG	= 12,
757c478bd9Sstevel@tonic-gate 	RESUME_MSG	= 13,
767c478bd9Sstevel@tonic-gate 	AUTONEG_MSG	= 14,
777c478bd9Sstevel@tonic-gate 	NAUTONEG_MSG	= 15,
787c478bd9Sstevel@tonic-gate 	FATAL_ERR_MSG	= 16,
797c478bd9Sstevel@tonic-gate 	NFATAL_ERR_MSG	= 17,
807c478bd9Sstevel@tonic-gate 	NDD_MSG		= 18,
817c478bd9Sstevel@tonic-gate 	PHY_MSG		= 19,
827c478bd9Sstevel@tonic-gate 	XCVR_MSG	= 20,
837c478bd9Sstevel@tonic-gate 	NOXCVR_MSG	= 21,
847c478bd9Sstevel@tonic-gate 	NSUPPORT_MSG	= 22,
857c478bd9Sstevel@tonic-gate 	ERX_MSG		= 23,
867c478bd9Sstevel@tonic-gate 	FREE_MSG	= 24,
877c478bd9Sstevel@tonic-gate 	IPG_MSG		= 25,
887c478bd9Sstevel@tonic-gate 	DDI_MSG		= 26,
897c478bd9Sstevel@tonic-gate 	DEFAULT_MSG	= 27,
907c478bd9Sstevel@tonic-gate 	DISPLAY_MSG	= 28,
917c478bd9Sstevel@tonic-gate 	LATECOLL_MSG	= 29,
927c478bd9Sstevel@tonic-gate 	MIFPOLL_MSG	= 30,
9385025c03Sgd 	LINKPULSE_MSG	= 31
947c478bd9Sstevel@tonic-gate } msg_t;
957c478bd9Sstevel@tonic-gate 
967c478bd9Sstevel@tonic-gate msg_t	hme_debug_level =	NO_MSG;
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate static char	*msg_string[] = {
997c478bd9Sstevel@tonic-gate 	"NONE       ",
1007c478bd9Sstevel@tonic-gate 	"AUTOCONFIG ",
1017c478bd9Sstevel@tonic-gate 	"STREAMS    ",
1027c478bd9Sstevel@tonic-gate 	"IOCTL      ",
1037c478bd9Sstevel@tonic-gate 	"PROTO      ",
1047c478bd9Sstevel@tonic-gate 	"INIT       ",
1057c478bd9Sstevel@tonic-gate 	"TX         ",
1067c478bd9Sstevel@tonic-gate 	"RX         ",
1077c478bd9Sstevel@tonic-gate 	"INTR       ",
1087c478bd9Sstevel@tonic-gate 	"UNINIT		",
1097c478bd9Sstevel@tonic-gate 	"CONFIG	",
1107c478bd9Sstevel@tonic-gate 	"PROP	",
1117c478bd9Sstevel@tonic-gate 	"ENTER	",
1127c478bd9Sstevel@tonic-gate 	"RESUME	",
1137c478bd9Sstevel@tonic-gate 	"AUTONEG	",
1147c478bd9Sstevel@tonic-gate 	"NAUTONEG	",
1157c478bd9Sstevel@tonic-gate 	"FATAL_ERR	",
1167c478bd9Sstevel@tonic-gate 	"NFATAL_ERR	",
1177c478bd9Sstevel@tonic-gate 	"NDD	",
1187c478bd9Sstevel@tonic-gate 	"PHY	",
1197c478bd9Sstevel@tonic-gate 	"XCVR	",
1207c478bd9Sstevel@tonic-gate 	"NOXCVR	",
1217c478bd9Sstevel@tonic-gate 	"NSUPPOR	",
1227c478bd9Sstevel@tonic-gate 	"ERX	",
1237c478bd9Sstevel@tonic-gate 	"FREE	",
1247c478bd9Sstevel@tonic-gate 	"IPG	",
1257c478bd9Sstevel@tonic-gate 	"DDI	",
1267c478bd9Sstevel@tonic-gate 	"DEFAULT	",
1277c478bd9Sstevel@tonic-gate 	"DISPLAY	"
1287c478bd9Sstevel@tonic-gate 	"LATECOLL_MSG	",
1297c478bd9Sstevel@tonic-gate 	"MIFPOLL_MSG	",
13085025c03Sgd 	"LINKPULSE_MSG	"
1317c478bd9Sstevel@tonic-gate };
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate #define	SEVERITY_NONE	0
1347c478bd9Sstevel@tonic-gate #define	SEVERITY_LOW	0
1357c478bd9Sstevel@tonic-gate #define	SEVERITY_MID	1
1367c478bd9Sstevel@tonic-gate #define	SEVERITY_HIGH	2
1377c478bd9Sstevel@tonic-gate #define	SEVERITY_UNKNOWN 99
1387c478bd9Sstevel@tonic-gate 
1397c478bd9Sstevel@tonic-gate #define	FEPS_URUN_BUG
1407c478bd9Sstevel@tonic-gate #define	HME_CODEVIOL_BUG
1417c478bd9Sstevel@tonic-gate 
1427c478bd9Sstevel@tonic-gate #define	KIOIP	KSTAT_INTR_PTR(hmep->hme_intrstats)
1437c478bd9Sstevel@tonic-gate 
1447c478bd9Sstevel@tonic-gate /*
1457c478bd9Sstevel@tonic-gate  * The following variables are used for checking fixes in Sbus/FEPS 2.0
1467c478bd9Sstevel@tonic-gate  */
1477c478bd9Sstevel@tonic-gate static	int	hme_urun_fix = 0;	/* Bug fixed in Sbus/FEPS 2.0 */
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate /*
1507c478bd9Sstevel@tonic-gate  * The following variables are used for configuring various features
1517c478bd9Sstevel@tonic-gate  */
1527c478bd9Sstevel@tonic-gate static	int	hme_64bit_enable =	1;	/* Use 64-bit sbus transfers */
1537c478bd9Sstevel@tonic-gate static	int	hme_reject_own =	1;	/* Reject packets with own SA */
1547c478bd9Sstevel@tonic-gate static	int	hme_autoneg_enable =	1;	/* Enable auto-negotiation */
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate static	int	hme_ngu_enable =	1; /* to enable Never Give Up mode */
1577c478bd9Sstevel@tonic-gate static	int	hme_mifpoll_enable =	1; /* to enable mif poll */
1587c478bd9Sstevel@tonic-gate 
1597c478bd9Sstevel@tonic-gate /*
1607c478bd9Sstevel@tonic-gate  * The following variables are used for configuring link-operation.
1617c478bd9Sstevel@tonic-gate  * Later these parameters may be changed per interface using "ndd" command
1627c478bd9Sstevel@tonic-gate  * These parameters may also be specified as properties using the .conf
1637c478bd9Sstevel@tonic-gate  * file mechanism for each interface.
1647c478bd9Sstevel@tonic-gate  */
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate static	int	hme_lance_mode =	1;	/* to enable lance mode */
1677c478bd9Sstevel@tonic-gate static	int	hme_ipg0 =		16;
1687c478bd9Sstevel@tonic-gate static	int	hme_ipg1 =		8;
1697c478bd9Sstevel@tonic-gate static	int	hme_ipg2 =		4;
1707c478bd9Sstevel@tonic-gate static	int	hme_use_int_xcvr =	0;
1717c478bd9Sstevel@tonic-gate static	int	hme_pace_size =		0;	/* Do not use pacing */
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate /*
1747c478bd9Sstevel@tonic-gate  * The following variable value will be overridden by "link-pulse-disabled"
1757c478bd9Sstevel@tonic-gate  * property which may be created by OBP or hme.conf file.
1767c478bd9Sstevel@tonic-gate  */
1777c478bd9Sstevel@tonic-gate static	int	hme_link_pulse_disabled = 0;	/* link pulse disabled */
1787c478bd9Sstevel@tonic-gate 
1797c478bd9Sstevel@tonic-gate /*
1807c478bd9Sstevel@tonic-gate  * The following parameters may be configured by the user. If they are not
1817c478bd9Sstevel@tonic-gate  * configured by the user, the values will be based on the capabilities of
1827c478bd9Sstevel@tonic-gate  * the transceiver.
1837c478bd9Sstevel@tonic-gate  * The value "HME_NOTUSR" is ORed with the parameter value to indicate values
1847c478bd9Sstevel@tonic-gate  * which are NOT configured by the user.
1857c478bd9Sstevel@tonic-gate  */
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate #define	HME_NOTUSR	0x0f000000
1887c478bd9Sstevel@tonic-gate #define	HME_MASK_1BIT	0x1
1897c478bd9Sstevel@tonic-gate #define	HME_MASK_5BIT	0x1f
1907c478bd9Sstevel@tonic-gate #define	HME_MASK_8BIT	0xff
1917c478bd9Sstevel@tonic-gate 
1927c478bd9Sstevel@tonic-gate static	int	hme_adv_autoneg_cap = HME_NOTUSR | 0;
1937c478bd9Sstevel@tonic-gate static	int	hme_adv_100T4_cap = HME_NOTUSR | 0;
1947c478bd9Sstevel@tonic-gate static	int	hme_adv_100fdx_cap = HME_NOTUSR | 0;
1957c478bd9Sstevel@tonic-gate static	int	hme_adv_100hdx_cap = HME_NOTUSR | 0;
1967c478bd9Sstevel@tonic-gate static	int	hme_adv_10fdx_cap = HME_NOTUSR | 0;
1977c478bd9Sstevel@tonic-gate static	int	hme_adv_10hdx_cap = HME_NOTUSR | 0;
1987c478bd9Sstevel@tonic-gate 
1997c478bd9Sstevel@tonic-gate /*
2007c478bd9Sstevel@tonic-gate  * PHY_IDR1 and PHY_IDR2 values to identify National Semiconductor's DP83840
2017c478bd9Sstevel@tonic-gate  * Rev C chip which needs some work-arounds.
2027c478bd9Sstevel@tonic-gate  */
2037c478bd9Sstevel@tonic-gate #define	HME_NSIDR1	0x2000
2047c478bd9Sstevel@tonic-gate #define	HME_NSIDR2	0x5c00 /* IDR2 register for with revision no. 0 */
2057c478bd9Sstevel@tonic-gate 
2067c478bd9Sstevel@tonic-gate /*
2077c478bd9Sstevel@tonic-gate  * PHY_IDR1 and PHY_IDR2 values to identify Quality Semiconductor's QS6612
2087c478bd9Sstevel@tonic-gate  * chip which needs some work-arounds.
2097c478bd9Sstevel@tonic-gate  * Addition Interface Technologies Group (NPG) 8/28/1997.
2107c478bd9Sstevel@tonic-gate  */
2117c478bd9Sstevel@tonic-gate #define	HME_QSIDR1	0x0181
2127c478bd9Sstevel@tonic-gate #define	HME_QSIDR2	0x4400 /* IDR2 register for with revision no. 0 */
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate /*
2157c478bd9Sstevel@tonic-gate  * The least significant 4 bits of HME_NSIDR2 represent the revision
2167c478bd9Sstevel@tonic-gate  * no. of the DP83840 chip. For Rev-C of DP83840, the rev. no. is 0.
2177c478bd9Sstevel@tonic-gate  * The next revision of the chip is called DP83840A and the value of
2187c478bd9Sstevel@tonic-gate  * HME_NSIDR2 is 0x5c01 for this new chip. All the workarounds specific
2197c478bd9Sstevel@tonic-gate  * to DP83840 chip are valid for both the revisions of the chip.
2207c478bd9Sstevel@tonic-gate  * Assuming that these workarounds are valid for the future revisions
2217c478bd9Sstevel@tonic-gate  * also, we will apply these workarounds independent of the revision no.
2227c478bd9Sstevel@tonic-gate  * Hence we mask out the last 4 bits of the IDR2 register and compare
2237c478bd9Sstevel@tonic-gate  * with 0x5c00 value.
2247c478bd9Sstevel@tonic-gate  */
2257c478bd9Sstevel@tonic-gate 
2267c478bd9Sstevel@tonic-gate #define	HME_DP83840	((hmep->hme_idr1 == HME_NSIDR1) && \
2277c478bd9Sstevel@tonic-gate 			((hmep->hme_idr2 & 0xfff0) == HME_NSIDR2))
2287c478bd9Sstevel@tonic-gate /*
2297c478bd9Sstevel@tonic-gate  * Likewise for the QSI 6612 Fast ethernet phy.
2307c478bd9Sstevel@tonic-gate  * Addition Interface Technologies Group (NPG) 8/28/1997.
2317c478bd9Sstevel@tonic-gate  */
2327c478bd9Sstevel@tonic-gate #define	HME_QS6612	((hmep->hme_idr1 == HME_QSIDR1) && \
2337c478bd9Sstevel@tonic-gate 			((hmep->hme_idr2 & 0xfff0) == HME_QSIDR2))
2347c478bd9Sstevel@tonic-gate /*
2357c478bd9Sstevel@tonic-gate  * All strings used by hme messaging functions
2367c478bd9Sstevel@tonic-gate  */
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate static	char *par_detect_msg =
2397c478bd9Sstevel@tonic-gate 	"Parallel detection fault.";
2407c478bd9Sstevel@tonic-gate 
2417c478bd9Sstevel@tonic-gate static	char *xcvr_no_mii_msg =
2427c478bd9Sstevel@tonic-gate 	"Transceiver does not talk MII.";
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate static	char *xcvr_isolate_msg =
2457c478bd9Sstevel@tonic-gate 	"Transceiver isolate failed.";
2467c478bd9Sstevel@tonic-gate 
2477c478bd9Sstevel@tonic-gate static	char *int_xcvr_msg =
2487c478bd9Sstevel@tonic-gate 	"Internal Transceiver Selected.";
2497c478bd9Sstevel@tonic-gate 
2507c478bd9Sstevel@tonic-gate static	char *ext_xcvr_msg =
2517c478bd9Sstevel@tonic-gate 	"External Transceiver Selected.";
2527c478bd9Sstevel@tonic-gate 
2537c478bd9Sstevel@tonic-gate static	char *no_xcvr_msg =
2547c478bd9Sstevel@tonic-gate 	"No transceiver found.";
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate static	char *burst_size_msg =
2577c478bd9Sstevel@tonic-gate 	"Could not identify the burst size";
2587c478bd9Sstevel@tonic-gate 
2597c478bd9Sstevel@tonic-gate static	char *unk_rx_ringsz_msg =
2607c478bd9Sstevel@tonic-gate 	"Unknown receive RINGSZ";
2617c478bd9Sstevel@tonic-gate 
2627c478bd9Sstevel@tonic-gate static  char *add_intr_fail_msg =
2637c478bd9Sstevel@tonic-gate 	"ddi_add_intr(9F) failed";
2647c478bd9Sstevel@tonic-gate 
2657c478bd9Sstevel@tonic-gate static  char *mregs_4global_reg_fail_msg =
2667c478bd9Sstevel@tonic-gate 	"ddi_regs_map_setup(9F) for global reg failed";
2677c478bd9Sstevel@tonic-gate 
2687c478bd9Sstevel@tonic-gate static	char *mregs_4etx_reg_fail_msg =
2697c478bd9Sstevel@tonic-gate 	"ddi_map_regs for etx reg failed";
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate static	char *mregs_4erx_reg_fail_msg =
2727c478bd9Sstevel@tonic-gate 	"ddi_map_regs for erx reg failed";
2737c478bd9Sstevel@tonic-gate 
2747c478bd9Sstevel@tonic-gate static	char *mregs_4bmac_reg_fail_msg =
2757c478bd9Sstevel@tonic-gate 	"ddi_map_regs for bmac reg failed";
2767c478bd9Sstevel@tonic-gate 
2777c478bd9Sstevel@tonic-gate static	char *mregs_4mif_reg_fail_msg =
2787c478bd9Sstevel@tonic-gate 	"ddi_map_regs for mif reg failed";
2797c478bd9Sstevel@tonic-gate 
2807c478bd9Sstevel@tonic-gate static  char *param_reg_fail_msg =
2817c478bd9Sstevel@tonic-gate 	"parameter register error";
2827c478bd9Sstevel@tonic-gate 
2837c478bd9Sstevel@tonic-gate static	char *init_fail_gen_msg =
2847c478bd9Sstevel@tonic-gate 	"Failed to initialize hardware/driver";
2857c478bd9Sstevel@tonic-gate 
2867c478bd9Sstevel@tonic-gate static	char *ddi_nregs_fail_msg =
2877c478bd9Sstevel@tonic-gate 	"ddi_dev_nregs failed(9F), returned %d";
2887c478bd9Sstevel@tonic-gate 
2897c478bd9Sstevel@tonic-gate static	char *bad_num_regs_msg =
2907c478bd9Sstevel@tonic-gate 	"Invalid number of registers.";
2917c478bd9Sstevel@tonic-gate 
2927c478bd9Sstevel@tonic-gate static	char *anar_not_set_msg =
2937c478bd9Sstevel@tonic-gate 	"External Transceiver: anar not set with speed selection";
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate static	char *par_detect_anar_not_set_msg =
2967c478bd9Sstevel@tonic-gate 	"External Transceiver: anar not set with speed selection";
2977c478bd9Sstevel@tonic-gate 
2987c478bd9Sstevel@tonic-gate 
2997c478bd9Sstevel@tonic-gate /* FATAL ERR msgs */
3007c478bd9Sstevel@tonic-gate /*
3017c478bd9Sstevel@tonic-gate  * Function prototypes.
3027c478bd9Sstevel@tonic-gate  */
303f2cd0f02Sgd /* these two are global so that qfe can use them */
304f2cd0f02Sgd int hmeattach(dev_info_t *, ddi_attach_cmd_t);
305f2cd0f02Sgd int hmedetach(dev_info_t *, ddi_detach_cmd_t);
306*0219346bSGarrett D'Amore int hmequiesce(dev_info_t *);
30785025c03Sgd static	boolean_t hmeinit_xfer_params(struct hme *);
3087c478bd9Sstevel@tonic-gate static	uint_t hmestop(struct hme *);
3097c478bd9Sstevel@tonic-gate static	void hmestatinit(struct hme *);
3107c478bd9Sstevel@tonic-gate static	int hmeallocthings(struct hme *);
311*0219346bSGarrett D'Amore static	void hmefreethings(struct hme *);
312*0219346bSGarrett D'Amore static	int hmeallocbuf(struct hme *, hmebuf_t *, int);
313*0219346bSGarrett D'Amore static	int hmeallocbufs(struct hme *);
3147c478bd9Sstevel@tonic-gate static	void hmefreebufs(struct hme *);
3157c478bd9Sstevel@tonic-gate static	void hmeget_hm_rev_property(struct hme *);
31685025c03Sgd static	boolean_t hmestart(struct hme *, mblk_t *);
31785025c03Sgd static	uint_t hmeintr(caddr_t);
3187c478bd9Sstevel@tonic-gate static	void hmereclaim(struct hme *);
3197c478bd9Sstevel@tonic-gate static	int hmeinit(struct hme *);
3207c478bd9Sstevel@tonic-gate static	void hmeuninit(struct hme *hmep);
321*0219346bSGarrett D'Amore static 	mblk_t *hmeread(struct hme *, hmebuf_t *, uint32_t);
3227c478bd9Sstevel@tonic-gate static	void hmesavecntrs(struct hme *);
3237c478bd9Sstevel@tonic-gate static	void hme_fatal_err(struct hme *, uint_t);
3247c478bd9Sstevel@tonic-gate static	void hme_nonfatal_err(struct hme *, uint_t);
3257c478bd9Sstevel@tonic-gate static	int hmeburstsizes(struct hme *);
3267c478bd9Sstevel@tonic-gate static	void hme_start_mifpoll(struct hme *);
3277c478bd9Sstevel@tonic-gate static	void hme_stop_mifpoll(struct hme *);
3287c478bd9Sstevel@tonic-gate static	void hme_param_cleanup(struct hme *);
3297c478bd9Sstevel@tonic-gate static	int hme_param_get(queue_t *q, mblk_t *mp, caddr_t cp);
3307c478bd9Sstevel@tonic-gate static	int hme_param_register(struct hme *, hmeparam_t *, int);
3317c478bd9Sstevel@tonic-gate static	int hme_param_set(queue_t *, mblk_t *, char *, caddr_t);
3327c478bd9Sstevel@tonic-gate static	void send_bit(struct hme *, uint_t);
3337c478bd9Sstevel@tonic-gate static	uint_t get_bit(struct hme *);
3347c478bd9Sstevel@tonic-gate static	uint_t get_bit_std(struct hme *);
3357c478bd9Sstevel@tonic-gate static	uint_t hme_bb_mii_read(struct hme *, uchar_t, uint16_t *);
3367c478bd9Sstevel@tonic-gate static	void hme_bb_mii_write(struct hme *, uchar_t, uint16_t);
3377c478bd9Sstevel@tonic-gate static	void hme_bb_force_idle(struct hme *);
3387c478bd9Sstevel@tonic-gate static	uint_t hme_mii_read(struct hme *, uchar_t, uint16_t *);
3397c478bd9Sstevel@tonic-gate static	void hme_mii_write(struct hme *, uchar_t, uint16_t);
3407c478bd9Sstevel@tonic-gate static	void hme_stop_timer(struct hme *);
3417c478bd9Sstevel@tonic-gate static	void hme_start_timer(struct hme *, fptrv_t, int);
3427c478bd9Sstevel@tonic-gate static	int hme_select_speed(struct hme *, int);
3437c478bd9Sstevel@tonic-gate static	void hme_reset_transceiver(struct hme *);
3447c478bd9Sstevel@tonic-gate static	void hme_check_transceiver(struct hme *);
3457c478bd9Sstevel@tonic-gate static	void hme_setup_link_default(struct hme *);
3467c478bd9Sstevel@tonic-gate static	void hme_setup_link_status(struct hme *);
3477c478bd9Sstevel@tonic-gate static	void hme_setup_link_control(struct hme *);
3487c478bd9Sstevel@tonic-gate static	int hme_check_txhung(struct hme *hmep);
3497c478bd9Sstevel@tonic-gate static	void hme_check_link(void *);
3507c478bd9Sstevel@tonic-gate 
3517c478bd9Sstevel@tonic-gate static	void hme_init_xcvr_info(struct hme *);
3527c478bd9Sstevel@tonic-gate static	void hme_disable_link_pulse(struct hme *);
3537c478bd9Sstevel@tonic-gate static	void hme_force_speed(void *);
3547c478bd9Sstevel@tonic-gate static	void hme_get_autoinfo(struct hme *);
3557c478bd9Sstevel@tonic-gate static	int hme_try_auto_negotiation(struct hme *);
3567c478bd9Sstevel@tonic-gate static	void hme_try_speed(void *);
3577c478bd9Sstevel@tonic-gate static	void hme_link_now_up(struct hme *);
3587c478bd9Sstevel@tonic-gate static	void hme_setup_mac_address(struct hme *, dev_info_t *);
3597c478bd9Sstevel@tonic-gate 
3607c478bd9Sstevel@tonic-gate static	void hme_nd_free(caddr_t *nd_pparam);
3617c478bd9Sstevel@tonic-gate static	int hme_nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp);
3627c478bd9Sstevel@tonic-gate static	boolean_t hme_nd_load(caddr_t *nd_pparam, char *name,
36385025c03Sgd     pfi_t get_pfi, pfi_t set_pfi, caddr_t data);
3647c478bd9Sstevel@tonic-gate 
365*0219346bSGarrett D'Amore static void hme_fault_msg(struct hme *, uint_t, msg_t, char *, ...);
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate static void hme_check_acc_handle(char *, uint_t, struct hme *,
36885025c03Sgd     ddi_acc_handle_t);
3697c478bd9Sstevel@tonic-gate 
37085025c03Sgd /*
37185025c03Sgd  * Nemo (GLDv3) Functions.
37285025c03Sgd  */
37385025c03Sgd static int	hme_m_stat(void *, uint_t, uint64_t *);
37485025c03Sgd static int	hme_m_start(void *);
37585025c03Sgd static void	hme_m_stop(void *);
37685025c03Sgd static int	hme_m_promisc(void *, boolean_t);
37785025c03Sgd static int	hme_m_multicst(void *, boolean_t, const uint8_t *);
37885025c03Sgd static int	hme_m_unicst(void *, const uint8_t *);
37985025c03Sgd static mblk_t	*hme_m_tx(void *, mblk_t *);
38085025c03Sgd static void	hme_m_ioctl(void *, queue_t *, mblk_t *);
38185025c03Sgd static boolean_t	hme_m_getcapab(void *, mac_capab_t, void *);
38285025c03Sgd 
38385025c03Sgd static mac_callbacks_t hme_m_callbacks = {
38485025c03Sgd 	MC_IOCTL | MC_GETCAPAB,
38585025c03Sgd 	hme_m_stat,
38685025c03Sgd 	hme_m_start,
38785025c03Sgd 	hme_m_stop,
38885025c03Sgd 	hme_m_promisc,
38985025c03Sgd 	hme_m_multicst,
39085025c03Sgd 	hme_m_unicst,
39185025c03Sgd 	hme_m_tx,
39285025c03Sgd 	hme_m_ioctl,
39385025c03Sgd 	hme_m_getcapab,
39485025c03Sgd };
39585025c03Sgd 
39685025c03Sgd DDI_DEFINE_STREAM_OPS(hme_dev_ops, nulldev, nulldev, hmeattach, hmedetach,
397*0219346bSGarrett D'Amore     nodev, NULL, D_MP, NULL, hmequiesce);
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate #define	HME_FAULT_MSG1(p, s, t, f) \
400*0219346bSGarrett D'Amore     hme_fault_msg((p), (s), (t), (f));
4017c478bd9Sstevel@tonic-gate 
4027c478bd9Sstevel@tonic-gate #define	HME_FAULT_MSG2(p, s, t, f, a) \
403*0219346bSGarrett D'Amore     hme_fault_msg((p), (s), (t), (f), (a));
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate #define	HME_FAULT_MSG3(p, s, t, f, a, b) \
406*0219346bSGarrett D'Amore     hme_fault_msg((p), (s), (t), (f), (a), (b));
4077c478bd9Sstevel@tonic-gate 
4087c478bd9Sstevel@tonic-gate #define	HME_FAULT_MSG4(p, s, t, f, a, b, c) \
409*0219346bSGarrett D'Amore     hme_fault_msg((p), (s), (t), (f), (a), (b), (c));
4107c478bd9Sstevel@tonic-gate 
4117c478bd9Sstevel@tonic-gate #define	CHECK_MIFREG() \
4127c478bd9Sstevel@tonic-gate 	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_mifregh)
4137c478bd9Sstevel@tonic-gate #define	CHECK_ETXREG() \
4147c478bd9Sstevel@tonic-gate 	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_etxregh)
4157c478bd9Sstevel@tonic-gate #define	CHECK_ERXREG() \
4167c478bd9Sstevel@tonic-gate 	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_erxregh)
4177c478bd9Sstevel@tonic-gate #define	CHECK_MACREG() \
4187c478bd9Sstevel@tonic-gate 	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_bmacregh)
4197c478bd9Sstevel@tonic-gate #define	CHECK_GLOBREG() \
4207c478bd9Sstevel@tonic-gate 	hme_check_acc_handle(__FILE__, __LINE__, hmep, hmep->hme_globregh)
4217c478bd9Sstevel@tonic-gate 
4227c478bd9Sstevel@tonic-gate /*
4237c478bd9Sstevel@tonic-gate  * Claim the device is ultra-capable of burst in the beginning.  Use
4247c478bd9Sstevel@tonic-gate  * the value returned by ddi_dma_burstsizes() to actually set the HME
4257c478bd9Sstevel@tonic-gate  * global configuration register later.
4267c478bd9Sstevel@tonic-gate  *
4277c478bd9Sstevel@tonic-gate  * Sbus/FEPS supports burst sizes of 16, 32 and 64 bytes. Also, it supports
4287c478bd9Sstevel@tonic-gate  * 32-bit and 64-bit Sbus transfers. Hence the dlim_burstsizes field contains
4297c478bd9Sstevel@tonic-gate  * the the burstsizes in both the lo and hi words.
4307c478bd9Sstevel@tonic-gate  */
4317c478bd9Sstevel@tonic-gate #define	HMELIMADDRLO	((uint64_t)0x00000000)
4327c478bd9Sstevel@tonic-gate #define	HMELIMADDRHI	((uint64_t)0xffffffff)
4337c478bd9Sstevel@tonic-gate 
434*0219346bSGarrett D'Amore /*
435*0219346bSGarrett D'Amore  * Note that rx and tx data buffers can be arbitrarily aligned, but
436*0219346bSGarrett D'Amore  * that the descriptor rings need to be aligned on 2K boundaries, per
437*0219346bSGarrett D'Amore  * the spec.
438*0219346bSGarrett D'Amore  */
4397c478bd9Sstevel@tonic-gate static ddi_dma_attr_t hme_dma_attr = {
4407c478bd9Sstevel@tonic-gate 	DMA_ATTR_V0,		/* version number. */
4417c478bd9Sstevel@tonic-gate 	(uint64_t)HMELIMADDRLO,	/* low address */
4427c478bd9Sstevel@tonic-gate 	(uint64_t)HMELIMADDRHI,	/* high address */
4437c478bd9Sstevel@tonic-gate 	(uint64_t)0x00ffffff,	/* address counter max */
444*0219346bSGarrett D'Amore 	(uint64_t)HME_HMDALIGN,	/* alignment */
4457c478bd9Sstevel@tonic-gate 	(uint_t)0x00700070,	/* dlim_burstsizes for 32 and 64 bit xfers */
4467c478bd9Sstevel@tonic-gate 	(uint32_t)0x1,		/* minimum transfer size */
4477c478bd9Sstevel@tonic-gate 	(uint64_t)0x7fffffff,	/* maximum transfer size */
4487c478bd9Sstevel@tonic-gate 	(uint64_t)0x00ffffff,	/* maximum segment size */
4497c478bd9Sstevel@tonic-gate 	1,			/* scatter/gather list length */
4507c478bd9Sstevel@tonic-gate 	512,			/* granularity */
4517c478bd9Sstevel@tonic-gate 	0			/* attribute flags */
4527c478bd9Sstevel@tonic-gate };
4537c478bd9Sstevel@tonic-gate 
454*0219346bSGarrett D'Amore static ddi_device_acc_attr_t hme_buf_attr = {
455*0219346bSGarrett D'Amore 	DDI_DEVICE_ATTR_V0,
456*0219346bSGarrett D'Amore 	DDI_NEVERSWAP_ACC,
457*0219346bSGarrett D'Amore 	DDI_STRICTORDER_ACC,	/* probably could allow merging & caching */
458*0219346bSGarrett D'Amore 	DDI_DEFAULT_ACC,
4597c478bd9Sstevel@tonic-gate };
4607c478bd9Sstevel@tonic-gate 
4617c478bd9Sstevel@tonic-gate static uchar_t pci_latency_timer = 0;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate /*
4647c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
4657c478bd9Sstevel@tonic-gate  */
4667c478bd9Sstevel@tonic-gate static struct modldrv modldrv = {
4677c478bd9Sstevel@tonic-gate 	&mod_driverops,	/* Type of module.  This one is a driver */
46885025c03Sgd 	"Sun HME 10/100 Mb Ethernet",
46985025c03Sgd 	&hme_dev_ops,	/* driver ops */
4707c478bd9Sstevel@tonic-gate };
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
4737c478bd9Sstevel@tonic-gate 	MODREV_1, &modldrv, NULL
4747c478bd9Sstevel@tonic-gate };
4757c478bd9Sstevel@tonic-gate 
4767c478bd9Sstevel@tonic-gate /*
4777c478bd9Sstevel@tonic-gate  * Internal PHY Id:
4787c478bd9Sstevel@tonic-gate  */
4797c478bd9Sstevel@tonic-gate 
4807c478bd9Sstevel@tonic-gate #define	HME_BB1	0x15	/* Babybac1, Rev 1.5 */
4817c478bd9Sstevel@tonic-gate #define	HME_BB2 0x20	/* Babybac2, Rev 0 */
4827c478bd9Sstevel@tonic-gate 
4837c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<  Register operations >>>>>>>>>>>>>>>>>>>>> */
4847c478bd9Sstevel@tonic-gate 
4857c478bd9Sstevel@tonic-gate #define	GET_MIFREG(reg) \
4867c478bd9Sstevel@tonic-gate 	ddi_get32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg)
4877c478bd9Sstevel@tonic-gate #define	PUT_MIFREG(reg, value) \
4887c478bd9Sstevel@tonic-gate 	ddi_put32(hmep->hme_mifregh, (uint32_t *)&hmep->hme_mifregp->reg, value)
4897c478bd9Sstevel@tonic-gate 
4907c478bd9Sstevel@tonic-gate #define	GET_ETXREG(reg) \
4917c478bd9Sstevel@tonic-gate 	ddi_get32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg)
4927c478bd9Sstevel@tonic-gate #define	PUT_ETXREG(reg, value) \
4937c478bd9Sstevel@tonic-gate 	ddi_put32(hmep->hme_etxregh, (uint32_t *)&hmep->hme_etxregp->reg, value)
4947c478bd9Sstevel@tonic-gate #define	GET_ERXREG(reg) \
4957c478bd9Sstevel@tonic-gate 	ddi_get32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg)
4967c478bd9Sstevel@tonic-gate #define	PUT_ERXREG(reg, value) \
4977c478bd9Sstevel@tonic-gate 	ddi_put32(hmep->hme_erxregh, (uint32_t *)&hmep->hme_erxregp->reg, value)
4987c478bd9Sstevel@tonic-gate #define	GET_MACREG(reg) \
4997c478bd9Sstevel@tonic-gate 	ddi_get32(hmep->hme_bmacregh, (uint32_t *)&hmep->hme_bmacregp->reg)
5007c478bd9Sstevel@tonic-gate #define	PUT_MACREG(reg, value) \
5017c478bd9Sstevel@tonic-gate 	ddi_put32(hmep->hme_bmacregh, \
5027c478bd9Sstevel@tonic-gate 		(uint32_t *)&hmep->hme_bmacregp->reg, value)
5037c478bd9Sstevel@tonic-gate #define	GET_GLOBREG(reg) \
5047c478bd9Sstevel@tonic-gate 	ddi_get32(hmep->hme_globregh, (uint32_t *)&hmep->hme_globregp->reg)
5057c478bd9Sstevel@tonic-gate #define	PUT_GLOBREG(reg, value) \
5067c478bd9Sstevel@tonic-gate 	ddi_put32(hmep->hme_globregh, \
5077c478bd9Sstevel@tonic-gate 		(uint32_t *)&hmep->hme_globregp->reg, value)
508*0219346bSGarrett D'Amore #define	PUT_TMD(ptr, paddr, len, flags)					\
509*0219346bSGarrett D'Amore 	ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_addr, paddr); \
510*0219346bSGarrett D'Amore 	ddi_put32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags,	\
511*0219346bSGarrett D'Amore 	    len | flags)
512*0219346bSGarrett D'Amore #define	GET_TMD_FLAGS(ptr)					\
513*0219346bSGarrett D'Amore 	ddi_get32(hmep->hme_tmd_acch, &hmep->hme_tmdp[ptr].tmd_flags)
514*0219346bSGarrett D'Amore #define	PUT_RMD(ptr, paddr) \
515*0219346bSGarrett D'Amore 	ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_addr, paddr); \
516*0219346bSGarrett D'Amore 	ddi_put32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags,	\
517*0219346bSGarrett D'Amore 	    (uint32_t)(HMEBUFSIZE << HMERMD_BUFSIZE_SHIFT) | HMERMD_OWN)
518*0219346bSGarrett D'Amore #define	GET_RMD_FLAGS(ptr)					\
519*0219346bSGarrett D'Amore 	ddi_get32(hmep->hme_rmd_acch, &hmep->hme_rmdp[ptr].rmd_flags)
520*0219346bSGarrett D'Amore 
5217c478bd9Sstevel@tonic-gate #define	GET_ROM8(offset) \
5227c478bd9Sstevel@tonic-gate 	ddi_get8((hmep->hme_romh), (offset))
5237c478bd9Sstevel@tonic-gate 
5247c478bd9Sstevel@tonic-gate /*
5257c478bd9Sstevel@tonic-gate  * Ether_copy is not endian-correct. Define an endian-correct version.
5267c478bd9Sstevel@tonic-gate  */
5277c478bd9Sstevel@tonic-gate #define	ether_bcopy(a, b) (bcopy(a, b, 6))
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate /*
5307c478bd9Sstevel@tonic-gate  * Ether-type is specifically big-endian, but data region is unknown endian
5317c478bd9Sstevel@tonic-gate  */
53285025c03Sgd #define	get_ether_type(ptr) \
53385025c03Sgd 	(((((uint8_t *)ptr)[12] << 8) | (((uint8_t *)ptr)[13])))
5347c478bd9Sstevel@tonic-gate 
5357c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<  Configuration Parameters >>>>>>>>>>>>>>>>>>>>> */
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate #define	BMAC_DEFAULT_JAMSIZE	(0x04)		/* jamsize equals 4 */
5387c478bd9Sstevel@tonic-gate #define	BMAC_LONG_JAMSIZE	(0x10)		/* jamsize equals 0x10 */
5397c478bd9Sstevel@tonic-gate static	int 	jamsize = BMAC_DEFAULT_JAMSIZE;
5407c478bd9Sstevel@tonic-gate 
5417c478bd9Sstevel@tonic-gate 
5427c478bd9Sstevel@tonic-gate /*
5437c478bd9Sstevel@tonic-gate  * Calculate the bit in the multicast address filter that selects the given
5447c478bd9Sstevel@tonic-gate  * address.
5457c478bd9Sstevel@tonic-gate  */
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate static uint32_t
54885025c03Sgd hmeladrf_bit(const uint8_t *addr)
5497c478bd9Sstevel@tonic-gate {
5507c478bd9Sstevel@tonic-gate 	uint32_t crc;
5517c478bd9Sstevel@tonic-gate 
5527c478bd9Sstevel@tonic-gate 	CRC32(crc, addr, ETHERADDRL, -1U, crc32_table);
5537c478bd9Sstevel@tonic-gate 
5547c478bd9Sstevel@tonic-gate 	/*
5557c478bd9Sstevel@tonic-gate 	 * Just want the 6 most significant bits.
5567c478bd9Sstevel@tonic-gate 	 */
5577c478bd9Sstevel@tonic-gate 	return (crc >> 26);
5587c478bd9Sstevel@tonic-gate }
5597c478bd9Sstevel@tonic-gate 
5607c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<<<  Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */
5617c478bd9Sstevel@tonic-gate 
5627c478bd9Sstevel@tonic-gate static int hme_internal_phy_id = HME_BB2;	/* Internal PHY is Babybac2  */
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate 
5657c478bd9Sstevel@tonic-gate static void
5667c478bd9Sstevel@tonic-gate send_bit(struct hme *hmep, uint32_t x)
5677c478bd9Sstevel@tonic-gate {
5687c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbdata, x);
5697c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW);
5707c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH);
5717c478bd9Sstevel@tonic-gate }
5727c478bd9Sstevel@tonic-gate 
5737c478bd9Sstevel@tonic-gate /*
5747c478bd9Sstevel@tonic-gate  * To read the MII register bits from the Babybac1 transceiver
5757c478bd9Sstevel@tonic-gate  */
5767c478bd9Sstevel@tonic-gate static uint32_t
5777c478bd9Sstevel@tonic-gate get_bit(struct hme *hmep)
5787c478bd9Sstevel@tonic-gate {
5797c478bd9Sstevel@tonic-gate 	uint32_t	x;
5807c478bd9Sstevel@tonic-gate 
5817c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW);
5827c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH);
5837c478bd9Sstevel@tonic-gate 	if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER)
5847c478bd9Sstevel@tonic-gate 		x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM0) ? 1 : 0;
5857c478bd9Sstevel@tonic-gate 	else
5867c478bd9Sstevel@tonic-gate 		x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM1) ? 1 : 0;
5877c478bd9Sstevel@tonic-gate 	return (x);
5887c478bd9Sstevel@tonic-gate }
5897c478bd9Sstevel@tonic-gate 
5907c478bd9Sstevel@tonic-gate 
5917c478bd9Sstevel@tonic-gate /*
5927c478bd9Sstevel@tonic-gate  * To read the MII register bits according to the IEEE Standard
5937c478bd9Sstevel@tonic-gate  */
5947c478bd9Sstevel@tonic-gate static uint32_t
5957c478bd9Sstevel@tonic-gate get_bit_std(struct hme *hmep)
5967c478bd9Sstevel@tonic-gate {
5977c478bd9Sstevel@tonic-gate 	uint32_t	x;
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, HME_BBCLK_LOW);
6007c478bd9Sstevel@tonic-gate 	drv_usecwait(1);	/* wait for  >330 ns for stable data */
6017c478bd9Sstevel@tonic-gate 	if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER)
6027c478bd9Sstevel@tonic-gate 		x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM0) ? 1 : 0;
6037c478bd9Sstevel@tonic-gate 	else
6047c478bd9Sstevel@tonic-gate 		x = (GET_MIFREG(mif_cfg) & HME_MIF_CFGM1) ? 1 : 0;
6057c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbclk, HME_BBCLK_HIGH);
6067c478bd9Sstevel@tonic-gate 	return (x);
6077c478bd9Sstevel@tonic-gate }
6087c478bd9Sstevel@tonic-gate 
6097c478bd9Sstevel@tonic-gate #define	SEND_BIT(x)		send_bit(hmep, x)
6107c478bd9Sstevel@tonic-gate #define	GET_BIT(x)		x = get_bit(hmep)
6117c478bd9Sstevel@tonic-gate #define	GET_BIT_STD(x)		x = get_bit_std(hmep)
6127c478bd9Sstevel@tonic-gate 
6137c478bd9Sstevel@tonic-gate 
6147c478bd9Sstevel@tonic-gate static void
6157c478bd9Sstevel@tonic-gate hme_bb_mii_write(struct hme *hmep, uint8_t regad, uint16_t data)
6167c478bd9Sstevel@tonic-gate {
6177c478bd9Sstevel@tonic-gate 	uint8_t	phyad;
6187c478bd9Sstevel@tonic-gate 	int	i;
6197c478bd9Sstevel@tonic-gate 
6207c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbopenb, 1);	/* Enable the MII driver */
6217c478bd9Sstevel@tonic-gate 	phyad = hmep->hme_phyad;
6227c478bd9Sstevel@tonic-gate 	(void) hme_bb_force_idle(hmep);
6237c478bd9Sstevel@tonic-gate 	SEND_BIT(0); SEND_BIT(1);	/* <ST> */
6247c478bd9Sstevel@tonic-gate 	SEND_BIT(0); SEND_BIT(1);	/* <OP> */
6257c478bd9Sstevel@tonic-gate 
6267c478bd9Sstevel@tonic-gate 	for (i = 4; i >= 0; i--) {		/* <AAAAA> */
6277c478bd9Sstevel@tonic-gate 		SEND_BIT((phyad >> i) & 1);
6287c478bd9Sstevel@tonic-gate 	}
6297c478bd9Sstevel@tonic-gate 
6307c478bd9Sstevel@tonic-gate 	for (i = 4; i >= 0; i--) {		/* <RRRRR> */
6317c478bd9Sstevel@tonic-gate 		SEND_BIT((regad >> i) & 1);
6327c478bd9Sstevel@tonic-gate 	}
6337c478bd9Sstevel@tonic-gate 
6347c478bd9Sstevel@tonic-gate 	SEND_BIT(1); SEND_BIT(0);	/* <TA> */
6357c478bd9Sstevel@tonic-gate 
6367c478bd9Sstevel@tonic-gate 	for (i = 0xf; i >= 0; i--) {	/* <DDDDDDDDDDDDDDDD> */
6377c478bd9Sstevel@tonic-gate 		SEND_BIT((data >> i) & 1);
6387c478bd9Sstevel@tonic-gate 	}
6397c478bd9Sstevel@tonic-gate 
6407c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbopenb, 0);	/* Disable the MII driver */
6417c478bd9Sstevel@tonic-gate 	CHECK_MIFREG();
6427c478bd9Sstevel@tonic-gate }
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */
6457c478bd9Sstevel@tonic-gate static uint_t
6467c478bd9Sstevel@tonic-gate hme_bb_mii_read(struct hme *hmep, uint8_t regad, uint16_t *datap)
6477c478bd9Sstevel@tonic-gate {
6487c478bd9Sstevel@tonic-gate 	uint8_t		phyad;
6497c478bd9Sstevel@tonic-gate 	int		i;
6507c478bd9Sstevel@tonic-gate 	uint32_t	x;
6517c478bd9Sstevel@tonic-gate 	uint32_t	y;
6527c478bd9Sstevel@tonic-gate 
6537c478bd9Sstevel@tonic-gate 	*datap = 0;
6547c478bd9Sstevel@tonic-gate 
6557c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbopenb, 1);	/* Enable the MII driver */
6567c478bd9Sstevel@tonic-gate 	phyad = hmep->hme_phyad;
6577c478bd9Sstevel@tonic-gate 	(void) hme_bb_force_idle(hmep);
6587c478bd9Sstevel@tonic-gate 	SEND_BIT(0); SEND_BIT(1);	/* <ST> */
6597c478bd9Sstevel@tonic-gate 	SEND_BIT(1); SEND_BIT(0);	/* <OP> */
6607c478bd9Sstevel@tonic-gate 	for (i = 4; i >= 0; i--) {		/* <AAAAA> */
6617c478bd9Sstevel@tonic-gate 		SEND_BIT((phyad >> i) & 1);
6627c478bd9Sstevel@tonic-gate 	}
6637c478bd9Sstevel@tonic-gate 	for (i = 4; i >= 0; i--) {		/* <RRRRR> */
6647c478bd9Sstevel@tonic-gate 		SEND_BIT((regad >> i) & 1);
6657c478bd9Sstevel@tonic-gate 	}
6667c478bd9Sstevel@tonic-gate 
6677c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_bbopenb, 0);	/* Disable the MII driver */
6687c478bd9Sstevel@tonic-gate 
6697c478bd9Sstevel@tonic-gate 	if ((hme_internal_phy_id == HME_BB2) ||
67085025c03Sgd 	    (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER)) {
6717c478bd9Sstevel@tonic-gate 		GET_BIT_STD(x);
6727c478bd9Sstevel@tonic-gate 		GET_BIT_STD(y);		/* <TA> */
6737c478bd9Sstevel@tonic-gate 		for (i = 0xf; i >= 0; i--) {	/* <DDDDDDDDDDDDDDDD> */
6747c478bd9Sstevel@tonic-gate 			GET_BIT_STD(x);
6757c478bd9Sstevel@tonic-gate 			*datap += (x << i);
6767c478bd9Sstevel@tonic-gate 		}
6777c478bd9Sstevel@tonic-gate 		/*
6787c478bd9Sstevel@tonic-gate 		 * Kludge to get the Transceiver out of hung mode
6797c478bd9Sstevel@tonic-gate 		 */
6807c478bd9Sstevel@tonic-gate 		GET_BIT_STD(x);
6817c478bd9Sstevel@tonic-gate 		GET_BIT_STD(x);
6827c478bd9Sstevel@tonic-gate 		GET_BIT_STD(x);
6837c478bd9Sstevel@tonic-gate 	} else {
6847c478bd9Sstevel@tonic-gate 		GET_BIT(x);
6857c478bd9Sstevel@tonic-gate 		GET_BIT(y);		/* <TA> */
6867c478bd9Sstevel@tonic-gate 		for (i = 0xf; i >= 0; i--) {	/* <DDDDDDDDDDDDDDDD> */
6877c478bd9Sstevel@tonic-gate 			GET_BIT(x);
6887c478bd9Sstevel@tonic-gate 			*datap += (x << i);
6897c478bd9Sstevel@tonic-gate 		}
6907c478bd9Sstevel@tonic-gate 		/*
6917c478bd9Sstevel@tonic-gate 		 * Kludge to get the Transceiver out of hung mode
6927c478bd9Sstevel@tonic-gate 		 */
6937c478bd9Sstevel@tonic-gate 		GET_BIT(x);
6947c478bd9Sstevel@tonic-gate 		GET_BIT(x);
6957c478bd9Sstevel@tonic-gate 		GET_BIT(x);
6967c478bd9Sstevel@tonic-gate 	}
6977c478bd9Sstevel@tonic-gate 	CHECK_MIFREG();
6987c478bd9Sstevel@tonic-gate 	return (y);
6997c478bd9Sstevel@tonic-gate }
7007c478bd9Sstevel@tonic-gate 
7017c478bd9Sstevel@tonic-gate 
7027c478bd9Sstevel@tonic-gate static void
7037c478bd9Sstevel@tonic-gate hme_bb_force_idle(struct hme *hmep)
7047c478bd9Sstevel@tonic-gate {
7057c478bd9Sstevel@tonic-gate 	int	i;
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	for (i = 0; i < 33; i++) {
7087c478bd9Sstevel@tonic-gate 		SEND_BIT(1);
7097c478bd9Sstevel@tonic-gate 	}
7107c478bd9Sstevel@tonic-gate }
7117c478bd9Sstevel@tonic-gate 
7127c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<End of Bit Bang Operations >>>>>>>>>>>>>>>>>>>>>>>> */
7137c478bd9Sstevel@tonic-gate 
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<< Frame Register used for MII operations >>>>>>>>>>>>>>>>>>>> */
7167c478bd9Sstevel@tonic-gate 
7177c478bd9Sstevel@tonic-gate /* Return 0 if OK, 1 if error (Transceiver does not talk management) */
7187c478bd9Sstevel@tonic-gate static uint_t
7197c478bd9Sstevel@tonic-gate hme_mii_read(struct hme *hmep, uchar_t regad, uint16_t *datap)
7207c478bd9Sstevel@tonic-gate {
7217c478bd9Sstevel@tonic-gate 	uint32_t	frame;
7227c478bd9Sstevel@tonic-gate 	uint8_t		phyad;
7237c478bd9Sstevel@tonic-gate 
7247c478bd9Sstevel@tonic-gate 	if (hmep->hme_transceiver == HME_NO_TRANSCEIVER)
7257c478bd9Sstevel@tonic-gate 		return (1);	/* No transceiver present */
7267c478bd9Sstevel@tonic-gate 
7277c478bd9Sstevel@tonic-gate 	if (!hmep->hme_frame_enable)
7287c478bd9Sstevel@tonic-gate 		return (hme_bb_mii_read(hmep, regad, datap));
7297c478bd9Sstevel@tonic-gate 
7307c478bd9Sstevel@tonic-gate 	phyad = hmep->hme_phyad;
7317c478bd9Sstevel@tonic-gate 
732*0219346bSGarrett D'Amore 	PUT_MIFREG(mif_frame,
733*0219346bSGarrett D'Amore 	    HME_MIF_FRREAD | (phyad << HME_MIF_FRPHYAD_SHIFT) |
734*0219346bSGarrett D'Amore 	    (regad << HME_MIF_FRREGAD_SHIFT));
7357c478bd9Sstevel@tonic-gate /*
7367c478bd9Sstevel@tonic-gate  *	HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY);
7377c478bd9Sstevel@tonic-gate  */
738*0219346bSGarrett D'Amore 	HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300);
739*0219346bSGarrett D'Amore 	frame = GET_MIFREG(mif_frame);
7407c478bd9Sstevel@tonic-gate 	CHECK_MIFREG();
7417c478bd9Sstevel@tonic-gate 	if ((frame & HME_MIF_FRTA0) == 0) {
7427c478bd9Sstevel@tonic-gate 
7437c478bd9Sstevel@tonic-gate 
7447c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, NAUTONEG_MSG,
745*0219346bSGarrett D'Amore 		    "MIF Read failure");
7467c478bd9Sstevel@tonic-gate 		return (1);
7477c478bd9Sstevel@tonic-gate 	} else {
7487c478bd9Sstevel@tonic-gate 		*datap = (uint16_t)(frame & HME_MIF_FRDATA);
7497c478bd9Sstevel@tonic-gate 		return (0);
7507c478bd9Sstevel@tonic-gate 	}
7517c478bd9Sstevel@tonic-gate 
7527c478bd9Sstevel@tonic-gate }
7537c478bd9Sstevel@tonic-gate 
7547c478bd9Sstevel@tonic-gate static void
7557c478bd9Sstevel@tonic-gate hme_mii_write(struct hme *hmep, uint8_t regad, uint16_t data)
7567c478bd9Sstevel@tonic-gate {
7577c478bd9Sstevel@tonic-gate 	uint32_t frame;
7587c478bd9Sstevel@tonic-gate 	uint8_t	phyad;
7597c478bd9Sstevel@tonic-gate 
7607c478bd9Sstevel@tonic-gate 	if (!hmep->hme_frame_enable) {
7617c478bd9Sstevel@tonic-gate 		hme_bb_mii_write(hmep, regad, data);
7627c478bd9Sstevel@tonic-gate 		return;
7637c478bd9Sstevel@tonic-gate 	}
7647c478bd9Sstevel@tonic-gate 
7657c478bd9Sstevel@tonic-gate 	phyad = hmep->hme_phyad;
7667c478bd9Sstevel@tonic-gate 
767*0219346bSGarrett D'Amore 	PUT_MIFREG(mif_frame,
768*0219346bSGarrett D'Amore 	    HME_MIF_FRWRITE | (phyad << HME_MIF_FRPHYAD_SHIFT) |
769*0219346bSGarrett D'Amore 	    (regad << HME_MIF_FRREGAD_SHIFT) | data);
7707c478bd9Sstevel@tonic-gate /*
7717c478bd9Sstevel@tonic-gate  *	HMEDELAY((*framerp & HME_MIF_FRTA0), HMEMAXRSTDELAY);
7727c478bd9Sstevel@tonic-gate  */
773*0219346bSGarrett D'Amore 	HMEDELAY((GET_MIFREG(mif_frame) & HME_MIF_FRTA0), 300);
774*0219346bSGarrett D'Amore 	frame = GET_MIFREG(mif_frame);
7757c478bd9Sstevel@tonic-gate 	CHECK_MIFREG();
7767c478bd9Sstevel@tonic-gate 	if ((frame & HME_MIF_FRTA0) == 0) {
7777c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_MID, NAUTONEG_MSG,
778*0219346bSGarrett D'Amore 		    "MIF Write failure");
7797c478bd9Sstevel@tonic-gate 	}
7807c478bd9Sstevel@tonic-gate }
7817c478bd9Sstevel@tonic-gate 
7827c478bd9Sstevel@tonic-gate /*
7837c478bd9Sstevel@tonic-gate  * hme_stop_timer function is used by a function before doing link-related
7847c478bd9Sstevel@tonic-gate  * processing. It locks the "hme_linklock" to protect the link-related data
7857c478bd9Sstevel@tonic-gate  * structures. This lock will be subsequently released in hme_start_timer().
7867c478bd9Sstevel@tonic-gate  */
7877c478bd9Sstevel@tonic-gate static void
7887c478bd9Sstevel@tonic-gate hme_stop_timer(struct hme *hmep)
7897c478bd9Sstevel@tonic-gate {
7907c478bd9Sstevel@tonic-gate 	timeout_id_t	tid;
7917c478bd9Sstevel@tonic-gate 
7927c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_linklock);
7937c478bd9Sstevel@tonic-gate 
7947c478bd9Sstevel@tonic-gate 	if (hmep->hme_timerid) {
7957c478bd9Sstevel@tonic-gate 		tid = hmep->hme_timerid;
7967c478bd9Sstevel@tonic-gate 		hmep->hme_timerid = 0;
7977c478bd9Sstevel@tonic-gate 		mutex_exit(&hmep->hme_linklock);
7987c478bd9Sstevel@tonic-gate 		(void) untimeout(tid);
7997c478bd9Sstevel@tonic-gate 		mutex_enter(&hmep->hme_linklock);
8007c478bd9Sstevel@tonic-gate 	}
8017c478bd9Sstevel@tonic-gate }
8027c478bd9Sstevel@tonic-gate 
8037c478bd9Sstevel@tonic-gate static void
8047c478bd9Sstevel@tonic-gate hme_start_timer(struct hme *hmep, fptrv_t func, int msec)
8057c478bd9Sstevel@tonic-gate {
806228fdff0Sgd 	hmep->hme_timerid = timeout(func, hmep, drv_usectohz(1000 * msec));
8077c478bd9Sstevel@tonic-gate 
8087c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_linklock);
8097c478bd9Sstevel@tonic-gate }
8107c478bd9Sstevel@tonic-gate 
8117c478bd9Sstevel@tonic-gate /*
8127c478bd9Sstevel@tonic-gate  * hme_select_speed is required only when auto-negotiation is not supported.
8137c478bd9Sstevel@tonic-gate  * It should be used only for the Internal Transceiver and not the External
8147c478bd9Sstevel@tonic-gate  * transceiver because we wouldn't know how to generate Link Down state on
8157c478bd9Sstevel@tonic-gate  * the wire.
8167c478bd9Sstevel@tonic-gate  * Currently it is required to support Electron 1.1 Build machines. When all
8177c478bd9Sstevel@tonic-gate  * these machines are upgraded to 1.2 or better, remove this function.
8187c478bd9Sstevel@tonic-gate  *
8197c478bd9Sstevel@tonic-gate  * Returns 1 if the link is up, 0 otherwise.
8207c478bd9Sstevel@tonic-gate  */
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate static int
8237c478bd9Sstevel@tonic-gate hme_select_speed(struct hme *hmep, int speed)
8247c478bd9Sstevel@tonic-gate {
8257c478bd9Sstevel@tonic-gate 	uint16_t	stat;
8267c478bd9Sstevel@tonic-gate 	uint16_t	fdx;
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	if (hmep->hme_linkup_cnt)  /* not first time */
8297c478bd9Sstevel@tonic-gate 		goto read_status;
8307c478bd9Sstevel@tonic-gate 
8317c478bd9Sstevel@tonic-gate 	if (hmep->hme_fdx)
8327c478bd9Sstevel@tonic-gate 		fdx = PHY_BMCR_FDX;
8337c478bd9Sstevel@tonic-gate 	else
8347c478bd9Sstevel@tonic-gate 		fdx = 0;
8357c478bd9Sstevel@tonic-gate 
8367c478bd9Sstevel@tonic-gate 	switch (speed) {
8377c478bd9Sstevel@tonic-gate 	case HME_SPEED_100:
8387c478bd9Sstevel@tonic-gate 
8397c478bd9Sstevel@tonic-gate 		switch (hmep->hme_transceiver) {
8407c478bd9Sstevel@tonic-gate 		case HME_INTERNAL_TRANSCEIVER:
8417c478bd9Sstevel@tonic-gate 			hme_mii_write(hmep, HME_PHY_BMCR, fdx | PHY_BMCR_100M);
8427c478bd9Sstevel@tonic-gate 			break;
8437c478bd9Sstevel@tonic-gate 		case HME_EXTERNAL_TRANSCEIVER:
8447c478bd9Sstevel@tonic-gate 			if (hmep->hme_delay == 0) {
8457c478bd9Sstevel@tonic-gate 				hme_mii_write(hmep, HME_PHY_BMCR,
84685025c03Sgd 				    fdx | PHY_BMCR_100M);
8477c478bd9Sstevel@tonic-gate 			}
8487c478bd9Sstevel@tonic-gate 			break;
8497c478bd9Sstevel@tonic-gate 		default:
8507c478bd9Sstevel@tonic-gate 			break;
8517c478bd9Sstevel@tonic-gate 		}
8527c478bd9Sstevel@tonic-gate 		break;
8537c478bd9Sstevel@tonic-gate 	case HME_SPEED_10:
8547c478bd9Sstevel@tonic-gate 		switch (hmep->hme_transceiver) {
8557c478bd9Sstevel@tonic-gate 		case HME_INTERNAL_TRANSCEIVER:
8567c478bd9Sstevel@tonic-gate 			hme_mii_write(hmep, HME_PHY_BMCR, fdx);
8577c478bd9Sstevel@tonic-gate 			break;
8587c478bd9Sstevel@tonic-gate 		case HME_EXTERNAL_TRANSCEIVER:
8597c478bd9Sstevel@tonic-gate 			if (hmep->hme_delay == 0) {
8607c478bd9Sstevel@tonic-gate 				hme_mii_write(hmep, HME_PHY_BMCR, fdx);
8617c478bd9Sstevel@tonic-gate 			}
8627c478bd9Sstevel@tonic-gate 			break;
8637c478bd9Sstevel@tonic-gate 		default:
8647c478bd9Sstevel@tonic-gate 			break;
8657c478bd9Sstevel@tonic-gate 		}
8667c478bd9Sstevel@tonic-gate 		break;
8677c478bd9Sstevel@tonic-gate 	default:
8687c478bd9Sstevel@tonic-gate 		return (0);
8697c478bd9Sstevel@tonic-gate 	}
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate 	if (!hmep->hme_linkup_cnt) {  /* first time; select speed */
8727c478bd9Sstevel@tonic-gate 		(void) hme_mii_read(hmep, HME_PHY_BMSR, &stat);
8737c478bd9Sstevel@tonic-gate 		hmep->hme_linkup_cnt++;
8747c478bd9Sstevel@tonic-gate 		return (0);
8757c478bd9Sstevel@tonic-gate 	}
8767c478bd9Sstevel@tonic-gate 
8777c478bd9Sstevel@tonic-gate read_status:
8787c478bd9Sstevel@tonic-gate 	hmep->hme_linkup_cnt++;
8797c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_BMSR, &stat);
8807c478bd9Sstevel@tonic-gate 	if (stat & PHY_BMSR_LNKSTS)
8817c478bd9Sstevel@tonic-gate 		return (1);
8827c478bd9Sstevel@tonic-gate 	else
8837c478bd9Sstevel@tonic-gate 		return (0);
8847c478bd9Sstevel@tonic-gate }
8857c478bd9Sstevel@tonic-gate 
8867c478bd9Sstevel@tonic-gate 
8877c478bd9Sstevel@tonic-gate #define	HME_PHYRST_PERIOD 600	/* 600 milliseconds, instead of 500 */
8887c478bd9Sstevel@tonic-gate #define	HME_PDOWN_PERIOD 256	/* 256 milliseconds  power down period to */
8897c478bd9Sstevel@tonic-gate 				/* insure a good reset of the QSI PHY */
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate static void
8927c478bd9Sstevel@tonic-gate hme_reset_transceiver(struct hme *hmep)
8937c478bd9Sstevel@tonic-gate {
8947c478bd9Sstevel@tonic-gate 	uint32_t	cfg;
8957c478bd9Sstevel@tonic-gate 	uint16_t	stat;
8967c478bd9Sstevel@tonic-gate 	uint16_t	anar;
8977c478bd9Sstevel@tonic-gate 	uint16_t	control;
8987c478bd9Sstevel@tonic-gate 	uint16_t	csc;
8997c478bd9Sstevel@tonic-gate 	int		n;
9007c478bd9Sstevel@tonic-gate 
9017c478bd9Sstevel@tonic-gate 	cfg = GET_MIFREG(mif_cfg);
9027c478bd9Sstevel@tonic-gate 
9037c478bd9Sstevel@tonic-gate 	if (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER) {
9047c478bd9Sstevel@tonic-gate 		/* Isolate the Internal Transceiver */
9057c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_cfg, (cfg & ~HME_MIF_CFGPS));
9067c478bd9Sstevel@tonic-gate 		hmep->hme_phyad = HME_INTERNAL_PHYAD;
9077c478bd9Sstevel@tonic-gate 		hmep->hme_transceiver = HME_INTERNAL_TRANSCEIVER;
9087c478bd9Sstevel@tonic-gate 		hme_mii_write(hmep, HME_PHY_BMCR, (PHY_BMCR_ISOLATE |
90985025c03Sgd 		    PHY_BMCR_PWRDN | PHY_BMCR_LPBK));
9107c478bd9Sstevel@tonic-gate 		if (hme_mii_read(hmep, HME_PHY_BMCR, &control) == 1)
9117c478bd9Sstevel@tonic-gate 			goto start_again;
9127c478bd9Sstevel@tonic-gate 
9137c478bd9Sstevel@tonic-gate 		/* select the External transceiver */
9147c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_cfg, (cfg | HME_MIF_CFGPS));
9157c478bd9Sstevel@tonic-gate 		hmep->hme_transceiver = HME_EXTERNAL_TRANSCEIVER;
9167c478bd9Sstevel@tonic-gate 		hmep->hme_phyad = HME_EXTERNAL_PHYAD;
9177c478bd9Sstevel@tonic-gate 
9187c478bd9Sstevel@tonic-gate 	} else if (cfg & HME_MIF_CFGM1) {
9197c478bd9Sstevel@tonic-gate 		/* Isolate the External transceiver, if present */
9207c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_cfg, (cfg | HME_MIF_CFGPS));
9217c478bd9Sstevel@tonic-gate 		hmep->hme_phyad = HME_EXTERNAL_PHYAD;
9227c478bd9Sstevel@tonic-gate 		hmep->hme_transceiver = HME_EXTERNAL_TRANSCEIVER;
9237c478bd9Sstevel@tonic-gate 		hme_mii_write(hmep, HME_PHY_BMCR, (PHY_BMCR_ISOLATE |
92485025c03Sgd 		    PHY_BMCR_PWRDN | PHY_BMCR_LPBK));
9257c478bd9Sstevel@tonic-gate 		if (hme_mii_read(hmep, HME_PHY_BMCR, &control) == 1)
9267c478bd9Sstevel@tonic-gate 			goto start_again;
9277c478bd9Sstevel@tonic-gate 
9287c478bd9Sstevel@tonic-gate 		/* select the Internal transceiver */
9297c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_cfg, (cfg & ~HME_MIF_CFGPS));
9307c478bd9Sstevel@tonic-gate 		hmep->hme_transceiver = HME_INTERNAL_TRANSCEIVER;
9317c478bd9Sstevel@tonic-gate 		hmep->hme_phyad = HME_INTERNAL_PHYAD;
9327c478bd9Sstevel@tonic-gate 	}
9337c478bd9Sstevel@tonic-gate 
9347c478bd9Sstevel@tonic-gate 	hme_mii_write(hmep, HME_PHY_BMCR, PHY_BMCR_PWRDN);
9357c478bd9Sstevel@tonic-gate 	drv_usecwait((clock_t)HME_PDOWN_PERIOD);
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	/*
9387c478bd9Sstevel@tonic-gate 	 * Now reset the transceiver.
9397c478bd9Sstevel@tonic-gate 	 */
9407c478bd9Sstevel@tonic-gate 	hme_mii_write(hmep, HME_PHY_BMCR, PHY_BMCR_RESET);
9417c478bd9Sstevel@tonic-gate 
9427c478bd9Sstevel@tonic-gate 	/*
9437c478bd9Sstevel@tonic-gate 	 * Check for transceiver reset completion.
9447c478bd9Sstevel@tonic-gate 	 */
9457c478bd9Sstevel@tonic-gate 	n = HME_PHYRST_PERIOD / HMEWAITPERIOD;
9467c478bd9Sstevel@tonic-gate 
9477c478bd9Sstevel@tonic-gate 	while (--n > 0) {
9487c478bd9Sstevel@tonic-gate 		if (hme_mii_read(hmep, HME_PHY_BMCR, &control) == 1) {
9497c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG,
95085025c03Sgd 			    xcvr_no_mii_msg);
9517c478bd9Sstevel@tonic-gate 			goto start_again;
9527c478bd9Sstevel@tonic-gate 		}
9537c478bd9Sstevel@tonic-gate 		if ((control & PHY_BMCR_RESET) == 0)
9547c478bd9Sstevel@tonic-gate 			goto reset_issued;
9557c478bd9Sstevel@tonic-gate 		if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER)
9567c478bd9Sstevel@tonic-gate 			drv_usecwait((clock_t)HMEWAITPERIOD);
9577c478bd9Sstevel@tonic-gate 		else
9587c478bd9Sstevel@tonic-gate 			drv_usecwait((clock_t)(500 * HMEWAITPERIOD));
9597c478bd9Sstevel@tonic-gate 	}
9607c478bd9Sstevel@tonic-gate 	/*
9617c478bd9Sstevel@tonic-gate 	 * phy reset failure
9627c478bd9Sstevel@tonic-gate 	 */
9637c478bd9Sstevel@tonic-gate 	hmep->phyfail++;
9647c478bd9Sstevel@tonic-gate 	goto start_again;
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate reset_issued:
9677c478bd9Sstevel@tonic-gate 
9687c478bd9Sstevel@tonic-gate 	/*
9697c478bd9Sstevel@tonic-gate 	 * Get the PHY id registers. We need this to implement work-arounds
9707c478bd9Sstevel@tonic-gate 	 * for bugs in transceivers which use the National DP83840 PHY chip.
9717c478bd9Sstevel@tonic-gate 	 * National should fix this in the next release.
9727c478bd9Sstevel@tonic-gate 	 */
9737c478bd9Sstevel@tonic-gate 
9747c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_BMSR, &stat);
9757c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_IDR1, &hmep->hme_idr1);
9767c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_IDR2, &hmep->hme_idr2);
9777c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_ANAR, &anar);
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	hme_init_xcvr_info(hmep);
9807c478bd9Sstevel@tonic-gate 
9817c478bd9Sstevel@tonic-gate 	hmep->hme_bmcr = control;
9827c478bd9Sstevel@tonic-gate 	hmep->hme_anar = anar;
9837c478bd9Sstevel@tonic-gate 	hmep->hme_bmsr = stat;
9847c478bd9Sstevel@tonic-gate 
9857c478bd9Sstevel@tonic-gate 	/*
9867c478bd9Sstevel@tonic-gate 	 * The strapping of AN0 and AN1 pins on DP83840 cannot select
9877c478bd9Sstevel@tonic-gate 	 * 10FDX, 100FDX and Auto-negotiation. So select it here for the
9887c478bd9Sstevel@tonic-gate 	 * Internal Transceiver.
9897c478bd9Sstevel@tonic-gate 	 */
9907c478bd9Sstevel@tonic-gate 	if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER) {
9917c478bd9Sstevel@tonic-gate 		anar = (PHY_ANAR_TXFDX | PHY_ANAR_10FDX |
99285025c03Sgd 		    PHY_ANAR_TX | PHY_ANAR_10 | PHY_SELECTOR);
9937c478bd9Sstevel@tonic-gate 	}
9947c478bd9Sstevel@tonic-gate 	/*
9957c478bd9Sstevel@tonic-gate 	 * Modify control and bmsr based on anar for Rev-C of DP83840.
9967c478bd9Sstevel@tonic-gate 	 */
9977c478bd9Sstevel@tonic-gate 	if (HME_DP83840) {
9987c478bd9Sstevel@tonic-gate 		n = 0;
9997c478bd9Sstevel@tonic-gate 		if (anar & PHY_ANAR_TXFDX) {
10007c478bd9Sstevel@tonic-gate 			stat |= PHY_BMSR_100FDX;
10017c478bd9Sstevel@tonic-gate 			n++;
10027c478bd9Sstevel@tonic-gate 		} else
10037c478bd9Sstevel@tonic-gate 			stat &= ~PHY_BMSR_100FDX;
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 		if (anar & PHY_ANAR_TX) {
10067c478bd9Sstevel@tonic-gate 			stat |= PHY_BMSR_100HDX;
10077c478bd9Sstevel@tonic-gate 			n++;
10087c478bd9Sstevel@tonic-gate 		} else
10097c478bd9Sstevel@tonic-gate 			stat &= ~PHY_BMSR_100HDX;
10107c478bd9Sstevel@tonic-gate 
10117c478bd9Sstevel@tonic-gate 		if (anar & PHY_ANAR_10FDX) {
10127c478bd9Sstevel@tonic-gate 			stat |= PHY_BMSR_10FDX;
10137c478bd9Sstevel@tonic-gate 			n++;
10147c478bd9Sstevel@tonic-gate 		} else
10157c478bd9Sstevel@tonic-gate 			stat &= ~PHY_BMSR_10FDX;
10167c478bd9Sstevel@tonic-gate 
10177c478bd9Sstevel@tonic-gate 		if (anar & PHY_ANAR_10) {
10187c478bd9Sstevel@tonic-gate 			stat |= PHY_BMSR_10HDX;
10197c478bd9Sstevel@tonic-gate 			n++;
10207c478bd9Sstevel@tonic-gate 		} else
10217c478bd9Sstevel@tonic-gate 			stat &= ~PHY_BMSR_10HDX;
10227c478bd9Sstevel@tonic-gate 
10237c478bd9Sstevel@tonic-gate 		if (n == 1) { 	/* only one mode. disable auto-negotiation */
10247c478bd9Sstevel@tonic-gate 			stat &= ~PHY_BMSR_ACFG;
10257c478bd9Sstevel@tonic-gate 			control &= ~PHY_BMCR_ANE;
10267c478bd9Sstevel@tonic-gate 		}
10277c478bd9Sstevel@tonic-gate 		if (n) {
10287c478bd9Sstevel@tonic-gate 			hmep->hme_bmsr = stat;
10297c478bd9Sstevel@tonic-gate 			hmep->hme_bmcr = control;
10307c478bd9Sstevel@tonic-gate 		}
10317c478bd9Sstevel@tonic-gate 	}
10327c478bd9Sstevel@tonic-gate 	hme_setup_link_default(hmep);
10337c478bd9Sstevel@tonic-gate 	hme_setup_link_status(hmep);
10347c478bd9Sstevel@tonic-gate 
10357c478bd9Sstevel@tonic-gate 
10367c478bd9Sstevel@tonic-gate 	/*
10377c478bd9Sstevel@tonic-gate 	 * Place the Transceiver in normal operation mode
10387c478bd9Sstevel@tonic-gate 	 */
10397c478bd9Sstevel@tonic-gate 	hme_mii_write(hmep, HME_PHY_BMCR, (control & ~PHY_BMCR_ISOLATE));
10407c478bd9Sstevel@tonic-gate 
10417c478bd9Sstevel@tonic-gate 	/*
10427c478bd9Sstevel@tonic-gate 	 * check if the transceiver is not in Isolate mode
10437c478bd9Sstevel@tonic-gate 	 */
10447c478bd9Sstevel@tonic-gate 	n = HME_PHYRST_PERIOD / HMEWAITPERIOD;
10457c478bd9Sstevel@tonic-gate 
10467c478bd9Sstevel@tonic-gate 	while (--n > 0) {
10477c478bd9Sstevel@tonic-gate 		if (hme_mii_read(hmep, HME_PHY_BMCR, &control) == 1) {
10487c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG,
104985025c03Sgd 			    xcvr_no_mii_msg);
10507c478bd9Sstevel@tonic-gate 			goto start_again; /* Transceiver does not talk MII */
10517c478bd9Sstevel@tonic-gate 		}
10527c478bd9Sstevel@tonic-gate 		if ((control & PHY_BMCR_ISOLATE) == 0)
10537c478bd9Sstevel@tonic-gate 			goto setconn;
10547c478bd9Sstevel@tonic-gate 		drv_usecwait(HMEWAITPERIOD);
10557c478bd9Sstevel@tonic-gate 	}
10567c478bd9Sstevel@tonic-gate 	HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG,
105785025c03Sgd 	    xcvr_isolate_msg);
10587c478bd9Sstevel@tonic-gate 	goto start_again;	/* transceiver reset failure */
10597c478bd9Sstevel@tonic-gate 
10607c478bd9Sstevel@tonic-gate setconn:
10617c478bd9Sstevel@tonic-gate 
10627c478bd9Sstevel@tonic-gate 	/*
10637c478bd9Sstevel@tonic-gate 	 * Work-around for the late-collision problem with 100m cables.
10647c478bd9Sstevel@tonic-gate 	 * National should fix this in the next release !
10657c478bd9Sstevel@tonic-gate 	 */
10667c478bd9Sstevel@tonic-gate 	if (HME_DP83840) {
10677c478bd9Sstevel@tonic-gate 		(void) hme_mii_read(hmep, HME_PHY_CSC, &csc);
10687c478bd9Sstevel@tonic-gate 
10697c478bd9Sstevel@tonic-gate 		hme_mii_write(hmep, HME_PHY_CSC, (csc | PHY_CSCR_FCONN));
10707c478bd9Sstevel@tonic-gate 	}
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	hmep->hme_linkcheck =		0;
10737c478bd9Sstevel@tonic-gate 	hmep->hme_linkup =		0;
10747c478bd9Sstevel@tonic-gate 	hme_setup_link_status(hmep);
10757c478bd9Sstevel@tonic-gate 	hmep->hme_autoneg =		HME_HWAN_TRY;
10767c478bd9Sstevel@tonic-gate 	hmep->hme_force_linkdown =	HME_FORCE_LINKDOWN;
10777c478bd9Sstevel@tonic-gate 	hmep->hme_linkup_cnt =		0;
10787c478bd9Sstevel@tonic-gate 	hmep->hme_delay =		0;
10797c478bd9Sstevel@tonic-gate 	hme_setup_link_control(hmep);
10807c478bd9Sstevel@tonic-gate 	hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER);
10817c478bd9Sstevel@tonic-gate 
10827c478bd9Sstevel@tonic-gate 	if (hmep->hme_mode == HME_FORCE_SPEED)
10837c478bd9Sstevel@tonic-gate 		hme_force_speed(hmep);
10847c478bd9Sstevel@tonic-gate 	else {
10857c478bd9Sstevel@tonic-gate 		hmep->hme_linkup_10 = 	0;
10867c478bd9Sstevel@tonic-gate 		hmep->hme_tryspeed =	HME_SPEED_100;
10877c478bd9Sstevel@tonic-gate 		hmep->hme_ntries =	HME_NTRIES_LOW;
10887c478bd9Sstevel@tonic-gate 		hmep->hme_nlasttries =	HME_NTRIES_LOW;
10897c478bd9Sstevel@tonic-gate 		hme_try_speed(hmep);
10907c478bd9Sstevel@tonic-gate 	}
10917c478bd9Sstevel@tonic-gate 	return;
10927c478bd9Sstevel@tonic-gate 
10937c478bd9Sstevel@tonic-gate start_again:
10947c478bd9Sstevel@tonic-gate 	hme_start_timer(hmep, hme_check_link, HME_TICKS);
10957c478bd9Sstevel@tonic-gate }
10967c478bd9Sstevel@tonic-gate 
10977c478bd9Sstevel@tonic-gate static void
10987c478bd9Sstevel@tonic-gate hme_check_transceiver(struct hme *hmep)
10997c478bd9Sstevel@tonic-gate {
11007c478bd9Sstevel@tonic-gate 	uint32_t	cfgsav;
11017c478bd9Sstevel@tonic-gate 	uint32_t 	cfg;
11027c478bd9Sstevel@tonic-gate 	uint32_t 	stat;
11037c478bd9Sstevel@tonic-gate 
11047c478bd9Sstevel@tonic-gate 	/*
11057c478bd9Sstevel@tonic-gate 	 * If the MIF Polling is ON, and Internal transceiver is in use, just
11067c478bd9Sstevel@tonic-gate 	 * check for the presence of the External Transceiver.
11077c478bd9Sstevel@tonic-gate 	 * Otherwise:
11087c478bd9Sstevel@tonic-gate 	 * First check to see what transceivers are out there.
11097c478bd9Sstevel@tonic-gate 	 * If an external transceiver is present
11107c478bd9Sstevel@tonic-gate 	 * then use it, regardless of whether there is a Internal transceiver.
11117c478bd9Sstevel@tonic-gate 	 * If Internal transceiver is present and no external transceiver
11127c478bd9Sstevel@tonic-gate 	 * then use the Internal transceiver.
11137c478bd9Sstevel@tonic-gate 	 * If there is no external transceiver and no Internal transceiver,
11147c478bd9Sstevel@tonic-gate 	 * then something is wrong so print an error message.
11157c478bd9Sstevel@tonic-gate 	 */
11167c478bd9Sstevel@tonic-gate 
11177c478bd9Sstevel@tonic-gate 	cfgsav = GET_MIFREG(mif_cfg);
11187c478bd9Sstevel@tonic-gate 
11197c478bd9Sstevel@tonic-gate 	if (hmep->hme_polling_on) {
11207c478bd9Sstevel@tonic-gate 
11217c478bd9Sstevel@tonic-gate 		if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER) {
11227c478bd9Sstevel@tonic-gate 			if ((cfgsav & HME_MIF_CFGM1) && !hme_param_use_intphy) {
11237c478bd9Sstevel@tonic-gate 				hme_stop_mifpoll(hmep);
11247c478bd9Sstevel@tonic-gate 				hmep->hme_phyad = HME_EXTERNAL_PHYAD;
11257c478bd9Sstevel@tonic-gate 				hmep->hme_transceiver =
112685025c03Sgd 				    HME_EXTERNAL_TRANSCEIVER;
11277c478bd9Sstevel@tonic-gate 				PUT_MIFREG(mif_cfg, ((cfgsav & ~HME_MIF_CFGPE)
112885025c03Sgd 				    | HME_MIF_CFGPS));
11297c478bd9Sstevel@tonic-gate 			}
11307c478bd9Sstevel@tonic-gate 		} else if (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER) {
11317c478bd9Sstevel@tonic-gate 			stat = (GET_MIFREG(mif_bsts) >> 16);
11327c478bd9Sstevel@tonic-gate 			if ((stat == 0x00) || (hme_param_use_intphy)) {
11337c478bd9Sstevel@tonic-gate 
11347c478bd9Sstevel@tonic-gate 				hme_stop_mifpoll(hmep);
11357c478bd9Sstevel@tonic-gate 				hmep->hme_phyad = HME_INTERNAL_PHYAD;
11367c478bd9Sstevel@tonic-gate 				hmep->hme_transceiver =
113785025c03Sgd 				    HME_INTERNAL_TRANSCEIVER;
113885025c03Sgd 				PUT_MIFREG(mif_cfg,
113985025c03Sgd 				    (GET_MIFREG(mif_cfg) & ~HME_MIF_CFGPS));
11407c478bd9Sstevel@tonic-gate 			}
11417c478bd9Sstevel@tonic-gate 		}
11427c478bd9Sstevel@tonic-gate 		CHECK_MIFREG();
11437c478bd9Sstevel@tonic-gate 		return;
11447c478bd9Sstevel@tonic-gate 	}
11457c478bd9Sstevel@tonic-gate 
11467c478bd9Sstevel@tonic-gate 	cfg = GET_MIFREG(mif_cfg);
11477c478bd9Sstevel@tonic-gate 	if ((cfg & HME_MIF_CFGM1) && !hme_param_use_intphy) {
11487c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_cfg, (cfgsav | HME_MIF_CFGPS));
11497c478bd9Sstevel@tonic-gate 		hmep->hme_phyad = HME_EXTERNAL_PHYAD;
11507c478bd9Sstevel@tonic-gate 		hmep->hme_transceiver = HME_EXTERNAL_TRANSCEIVER;
11517c478bd9Sstevel@tonic-gate 
11527c478bd9Sstevel@tonic-gate 	} else if (cfg & HME_MIF_CFGM0) {  /* Internal Transceiver OK */
11537c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_cfg, (cfgsav & ~HME_MIF_CFGPS));
11547c478bd9Sstevel@tonic-gate 		hmep->hme_phyad = HME_INTERNAL_PHYAD;
11557c478bd9Sstevel@tonic-gate 		hmep->hme_transceiver = HME_INTERNAL_TRANSCEIVER;
11567c478bd9Sstevel@tonic-gate 
11577c478bd9Sstevel@tonic-gate 	} else {
11587c478bd9Sstevel@tonic-gate 		hmep->hme_transceiver = HME_NO_TRANSCEIVER;
11597c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, XCVR_MSG, no_xcvr_msg);
11607c478bd9Sstevel@tonic-gate 	}
11617c478bd9Sstevel@tonic-gate 	CHECK_MIFREG();
11627c478bd9Sstevel@tonic-gate }
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate static void
11657c478bd9Sstevel@tonic-gate hme_setup_link_default(struct hme *hmep)
11667c478bd9Sstevel@tonic-gate {
11677c478bd9Sstevel@tonic-gate 	uint16_t	bmsr;
11687c478bd9Sstevel@tonic-gate 
11697c478bd9Sstevel@tonic-gate 	bmsr = hmep->hme_bmsr;
11707c478bd9Sstevel@tonic-gate 	if (hme_param_autoneg & HME_NOTUSR)
11717c478bd9Sstevel@tonic-gate 		hme_param_autoneg = HME_NOTUSR |
117285025c03Sgd 		    ((bmsr & PHY_BMSR_ACFG) ? 1 : 0);
11737c478bd9Sstevel@tonic-gate 	if (hme_param_anar_100T4 & HME_NOTUSR)
11747c478bd9Sstevel@tonic-gate 		hme_param_anar_100T4 = HME_NOTUSR |
117585025c03Sgd 		    ((bmsr & PHY_BMSR_100T4) ? 1 : 0);
11767c478bd9Sstevel@tonic-gate 	if (hme_param_anar_100fdx & HME_NOTUSR)
11777c478bd9Sstevel@tonic-gate 		hme_param_anar_100fdx = HME_NOTUSR |
117885025c03Sgd 		    ((bmsr & PHY_BMSR_100FDX) ? 1 : 0);
11797c478bd9Sstevel@tonic-gate 	if (hme_param_anar_100hdx & HME_NOTUSR)
11807c478bd9Sstevel@tonic-gate 		hme_param_anar_100hdx = HME_NOTUSR |
118185025c03Sgd 		    ((bmsr & PHY_BMSR_100HDX) ? 1 : 0);
11827c478bd9Sstevel@tonic-gate 	if (hme_param_anar_10fdx & HME_NOTUSR)
11837c478bd9Sstevel@tonic-gate 		hme_param_anar_10fdx = HME_NOTUSR |
118485025c03Sgd 		    ((bmsr & PHY_BMSR_10FDX) ? 1 : 0);
11857c478bd9Sstevel@tonic-gate 	if (hme_param_anar_10hdx & HME_NOTUSR)
11867c478bd9Sstevel@tonic-gate 		hme_param_anar_10hdx = HME_NOTUSR |
118785025c03Sgd 		    ((bmsr & PHY_BMSR_10HDX) ? 1 : 0);
11887c478bd9Sstevel@tonic-gate }
11897c478bd9Sstevel@tonic-gate 
11907c478bd9Sstevel@tonic-gate static void
11917c478bd9Sstevel@tonic-gate hme_setup_link_status(struct hme *hmep)
11927c478bd9Sstevel@tonic-gate {
11937c478bd9Sstevel@tonic-gate 	uint16_t	tmp;
11947c478bd9Sstevel@tonic-gate 
11957c478bd9Sstevel@tonic-gate 	if (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER)
11967c478bd9Sstevel@tonic-gate 		hme_param_transceiver = 1;
11977c478bd9Sstevel@tonic-gate 	else
11987c478bd9Sstevel@tonic-gate 		hme_param_transceiver = 0;
11997c478bd9Sstevel@tonic-gate 
12007c478bd9Sstevel@tonic-gate 	tmp = hmep->hme_bmsr;
12017c478bd9Sstevel@tonic-gate 	if (tmp & PHY_BMSR_ACFG)
12027c478bd9Sstevel@tonic-gate 		hme_param_bmsr_ancap = 1;
12037c478bd9Sstevel@tonic-gate 	else
12047c478bd9Sstevel@tonic-gate 		hme_param_bmsr_ancap = 0;
12057c478bd9Sstevel@tonic-gate 	if (tmp & PHY_BMSR_100T4)
12067c478bd9Sstevel@tonic-gate 		hme_param_bmsr_100T4 = 1;
12077c478bd9Sstevel@tonic-gate 	else
12087c478bd9Sstevel@tonic-gate 		hme_param_bmsr_100T4 = 0;
12097c478bd9Sstevel@tonic-gate 	if (tmp & PHY_BMSR_100FDX)
12107c478bd9Sstevel@tonic-gate 		hme_param_bmsr_100fdx = 1;
12117c478bd9Sstevel@tonic-gate 	else
12127c478bd9Sstevel@tonic-gate 		hme_param_bmsr_100fdx = 0;
12137c478bd9Sstevel@tonic-gate 	if (tmp & PHY_BMSR_100HDX)
12147c478bd9Sstevel@tonic-gate 		hme_param_bmsr_100hdx = 1;
12157c478bd9Sstevel@tonic-gate 	else
12167c478bd9Sstevel@tonic-gate 		hme_param_bmsr_100hdx = 0;
12177c478bd9Sstevel@tonic-gate 	if (tmp & PHY_BMSR_10FDX)
12187c478bd9Sstevel@tonic-gate 		hme_param_bmsr_10fdx = 1;
12197c478bd9Sstevel@tonic-gate 	else
12207c478bd9Sstevel@tonic-gate 		hme_param_bmsr_10fdx = 0;
12217c478bd9Sstevel@tonic-gate 	if (tmp & PHY_BMSR_10HDX)
12227c478bd9Sstevel@tonic-gate 		hme_param_bmsr_10hdx = 1;
12237c478bd9Sstevel@tonic-gate 	else
12247c478bd9Sstevel@tonic-gate 		hme_param_bmsr_10hdx = 0;
12257c478bd9Sstevel@tonic-gate 
12267c478bd9Sstevel@tonic-gate 	if (hmep->hme_link_pulse_disabled) {
12277c478bd9Sstevel@tonic-gate 		hme_param_linkup =	1;
12287c478bd9Sstevel@tonic-gate 		hme_param_speed =	0;
12297c478bd9Sstevel@tonic-gate 		hme_param_mode =	0;
123085025c03Sgd 		hmep->hme_duplex =	LINK_DUPLEX_HALF;
123185025c03Sgd 		mac_link_update(hmep->hme_mh, LINK_STATE_UP);
12327c478bd9Sstevel@tonic-gate 		return;
12337c478bd9Sstevel@tonic-gate 	}
12347c478bd9Sstevel@tonic-gate 
12357c478bd9Sstevel@tonic-gate 	if (!hmep->hme_linkup) {
12367c478bd9Sstevel@tonic-gate 		hme_param_linkup =	0;
123785025c03Sgd 		hmep->hme_duplex = LINK_DUPLEX_UNKNOWN;
123885025c03Sgd 		mac_link_update(hmep->hme_mh, LINK_STATE_DOWN);
12397c478bd9Sstevel@tonic-gate 		return;
12407c478bd9Sstevel@tonic-gate 	}
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	hme_param_linkup = 1;
12437c478bd9Sstevel@tonic-gate 
12447c478bd9Sstevel@tonic-gate 	if (hmep->hme_fdx == HME_FULL_DUPLEX) {
12457c478bd9Sstevel@tonic-gate 		hme_param_mode = 1;
124685025c03Sgd 		hmep->hme_duplex = LINK_DUPLEX_FULL;
12477c478bd9Sstevel@tonic-gate 	} else {
12487c478bd9Sstevel@tonic-gate 		hme_param_mode = 0;
124985025c03Sgd 		hmep->hme_duplex = LINK_DUPLEX_HALF;
12507c478bd9Sstevel@tonic-gate 	}
12517c478bd9Sstevel@tonic-gate 
125285025c03Sgd 	mac_link_update(hmep->hme_mh, LINK_STATE_UP);
125385025c03Sgd 
12547c478bd9Sstevel@tonic-gate 	if (hmep->hme_mode == HME_FORCE_SPEED) {
12557c478bd9Sstevel@tonic-gate 		if (hmep->hme_forcespeed == HME_SPEED_100)
12567c478bd9Sstevel@tonic-gate 			hme_param_speed = 1;
12577c478bd9Sstevel@tonic-gate 		else
12587c478bd9Sstevel@tonic-gate 			hme_param_speed = 0;
12597c478bd9Sstevel@tonic-gate 		return;
12607c478bd9Sstevel@tonic-gate 	}
12617c478bd9Sstevel@tonic-gate 	if (hmep->hme_tryspeed == HME_SPEED_100)
12627c478bd9Sstevel@tonic-gate 		hme_param_speed = 1;
12637c478bd9Sstevel@tonic-gate 	else
12647c478bd9Sstevel@tonic-gate 		hme_param_speed = 0;
12657c478bd9Sstevel@tonic-gate 
12667c478bd9Sstevel@tonic-gate 
12677c478bd9Sstevel@tonic-gate 	if (!(hmep->hme_aner & PHY_ANER_LPNW)) {
12687c478bd9Sstevel@tonic-gate 		hme_param_aner_lpancap =	0;
12697c478bd9Sstevel@tonic-gate 		hme_param_anlpar_100T4 =	0;
12707c478bd9Sstevel@tonic-gate 		hme_param_anlpar_100fdx =	0;
12717c478bd9Sstevel@tonic-gate 		hme_param_anlpar_100hdx =	0;
12727c478bd9Sstevel@tonic-gate 		hme_param_anlpar_10fdx =	0;
12737c478bd9Sstevel@tonic-gate 		hme_param_anlpar_10hdx =	0;
12747c478bd9Sstevel@tonic-gate 		return;
12757c478bd9Sstevel@tonic-gate 	}
12767c478bd9Sstevel@tonic-gate 	hme_param_aner_lpancap = 1;
12777c478bd9Sstevel@tonic-gate 	tmp = hmep->hme_anlpar;
12787c478bd9Sstevel@tonic-gate 	if (tmp & PHY_ANLPAR_T4)
12797c478bd9Sstevel@tonic-gate 		hme_param_anlpar_100T4 = 1;
12807c478bd9Sstevel@tonic-gate 	else
12817c478bd9Sstevel@tonic-gate 		hme_param_anlpar_100T4 = 0;
12827c478bd9Sstevel@tonic-gate 	if (tmp & PHY_ANLPAR_TXFDX)
12837c478bd9Sstevel@tonic-gate 		hme_param_anlpar_100fdx = 1;
12847c478bd9Sstevel@tonic-gate 	else
12857c478bd9Sstevel@tonic-gate 		hme_param_anlpar_100fdx = 0;
12867c478bd9Sstevel@tonic-gate 	if (tmp & PHY_ANLPAR_TX)
12877c478bd9Sstevel@tonic-gate 		hme_param_anlpar_100hdx = 1;
12887c478bd9Sstevel@tonic-gate 	else
12897c478bd9Sstevel@tonic-gate 		hme_param_anlpar_100hdx = 0;
12907c478bd9Sstevel@tonic-gate 	if (tmp & PHY_ANLPAR_10FDX)
12917c478bd9Sstevel@tonic-gate 		hme_param_anlpar_10fdx = 1;
12927c478bd9Sstevel@tonic-gate 	else
12937c478bd9Sstevel@tonic-gate 		hme_param_anlpar_10fdx = 0;
12947c478bd9Sstevel@tonic-gate 	if (tmp & PHY_ANLPAR_10)
12957c478bd9Sstevel@tonic-gate 		hme_param_anlpar_10hdx = 1;
12967c478bd9Sstevel@tonic-gate 	else
12977c478bd9Sstevel@tonic-gate 		hme_param_anlpar_10hdx = 0;
12987c478bd9Sstevel@tonic-gate }
12997c478bd9Sstevel@tonic-gate 
13007c478bd9Sstevel@tonic-gate static void
13017c478bd9Sstevel@tonic-gate hme_setup_link_control(struct hme *hmep)
13027c478bd9Sstevel@tonic-gate {
1303*0219346bSGarrett D'Amore 	uint16_t anar = PHY_SELECTOR;
13047c478bd9Sstevel@tonic-gate 	uint32_t autoneg = ~HME_NOTUSR & hme_param_autoneg;
13057c478bd9Sstevel@tonic-gate 	uint32_t anar_100T4 = ~HME_NOTUSR & hme_param_anar_100T4;
13067c478bd9Sstevel@tonic-gate 	uint32_t anar_100fdx = ~HME_NOTUSR & hme_param_anar_100fdx;
13077c478bd9Sstevel@tonic-gate 	uint32_t anar_100hdx = ~HME_NOTUSR & hme_param_anar_100hdx;
13087c478bd9Sstevel@tonic-gate 	uint32_t anar_10fdx = ~HME_NOTUSR & hme_param_anar_10fdx;
13097c478bd9Sstevel@tonic-gate 	uint32_t anar_10hdx = ~HME_NOTUSR & hme_param_anar_10hdx;
13107c478bd9Sstevel@tonic-gate 
13117c478bd9Sstevel@tonic-gate 	if (autoneg) {
13127c478bd9Sstevel@tonic-gate 		hmep->hme_mode = HME_AUTO_SPEED;
13137c478bd9Sstevel@tonic-gate 		hmep->hme_tryspeed = HME_SPEED_100;
13147c478bd9Sstevel@tonic-gate 		if (anar_100T4)
13157c478bd9Sstevel@tonic-gate 			anar |= PHY_ANAR_T4;
13167c478bd9Sstevel@tonic-gate 		if (anar_100fdx)
13177c478bd9Sstevel@tonic-gate 			anar |= PHY_ANAR_TXFDX;
13187c478bd9Sstevel@tonic-gate 		if (anar_100hdx)
13197c478bd9Sstevel@tonic-gate 			anar |= PHY_ANAR_TX;
13207c478bd9Sstevel@tonic-gate 		if (anar_10fdx)
13217c478bd9Sstevel@tonic-gate 			anar |= PHY_ANAR_10FDX;
13227c478bd9Sstevel@tonic-gate 		if (anar_10hdx)
13237c478bd9Sstevel@tonic-gate 			anar |= PHY_ANAR_10;
13247c478bd9Sstevel@tonic-gate 		hmep->hme_anar = anar;
13257c478bd9Sstevel@tonic-gate 	} else {
13267c478bd9Sstevel@tonic-gate 		hmep->hme_mode = HME_FORCE_SPEED;
13277c478bd9Sstevel@tonic-gate 		if (anar_100T4) {
13287c478bd9Sstevel@tonic-gate 			hmep->hme_forcespeed = HME_SPEED_100;
13297c478bd9Sstevel@tonic-gate 			hmep->hme_fdx = HME_HALF_DUPLEX;
13307c478bd9Sstevel@tonic-gate 
13317c478bd9Sstevel@tonic-gate 		} else if (anar_100fdx) {
13327c478bd9Sstevel@tonic-gate 			/* 100fdx needs to be checked first for 100BaseFX */
13337c478bd9Sstevel@tonic-gate 			hmep->hme_forcespeed = HME_SPEED_100;
13347c478bd9Sstevel@tonic-gate 			hmep->hme_fdx = HME_FULL_DUPLEX;
13357c478bd9Sstevel@tonic-gate 
13367c478bd9Sstevel@tonic-gate 		} else if (anar_100hdx) {
13377c478bd9Sstevel@tonic-gate 			hmep->hme_forcespeed = HME_SPEED_100;
13387c478bd9Sstevel@tonic-gate 			hmep->hme_fdx = HME_HALF_DUPLEX;
13397c478bd9Sstevel@tonic-gate 		} else if (anar_10hdx) {
13407c478bd9Sstevel@tonic-gate 			/* 10hdx needs to be checked first for MII-AUI */
13417c478bd9Sstevel@tonic-gate 			/* MII-AUI BugIds 1252776,4032280,4035106,4028558 */
13427c478bd9Sstevel@tonic-gate 			hmep->hme_forcespeed = HME_SPEED_10;
13437c478bd9Sstevel@tonic-gate 			hmep->hme_fdx = HME_HALF_DUPLEX;
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 		} else if (anar_10fdx) {
13467c478bd9Sstevel@tonic-gate 			hmep->hme_forcespeed = HME_SPEED_10;
13477c478bd9Sstevel@tonic-gate 			hmep->hme_fdx = HME_FULL_DUPLEX;
13487c478bd9Sstevel@tonic-gate 
13497c478bd9Sstevel@tonic-gate 		} else {
13507c478bd9Sstevel@tonic-gate 			hmep->hme_forcespeed = HME_SPEED_10;
13517c478bd9Sstevel@tonic-gate 			hmep->hme_fdx = HME_HALF_DUPLEX;
13527c478bd9Sstevel@tonic-gate 		}
13537c478bd9Sstevel@tonic-gate 	}
13547c478bd9Sstevel@tonic-gate }
13557c478bd9Sstevel@tonic-gate 
13567c478bd9Sstevel@tonic-gate /* Decide if transmitter went dead and reinitialize everything */
13577c478bd9Sstevel@tonic-gate static int hme_txhung_limit = 3;
13587c478bd9Sstevel@tonic-gate static int
13597c478bd9Sstevel@tonic-gate hme_check_txhung(struct hme *hmep)
13607c478bd9Sstevel@tonic-gate {
13617c478bd9Sstevel@tonic-gate 	boolean_t status;
13627c478bd9Sstevel@tonic-gate 
13637c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_xmitlock);
13647c478bd9Sstevel@tonic-gate 	if (hmep->hme_flags & HMERUNNING)
13657c478bd9Sstevel@tonic-gate 		hmereclaim(hmep);
13667c478bd9Sstevel@tonic-gate 
13677c478bd9Sstevel@tonic-gate 	/* Something needs to be sent out but it is not going out */
1368*0219346bSGarrett D'Amore 	if ((hmep->hme_txindex != hmep->hme_txreclaim) &&
13697c478bd9Sstevel@tonic-gate 	    (hmep->hme_opackets == hmep->hmesave.hme_opackets))
13707c478bd9Sstevel@tonic-gate 		hmep->hme_txhung++;
13717c478bd9Sstevel@tonic-gate 	else
13727c478bd9Sstevel@tonic-gate 		hmep->hme_txhung = 0;
13737c478bd9Sstevel@tonic-gate 
13747c478bd9Sstevel@tonic-gate 	hmep->hmesave.hme_opackets = hmep->hme_opackets;
13757c478bd9Sstevel@tonic-gate 
13767c478bd9Sstevel@tonic-gate 	status = hmep->hme_txhung >= hme_txhung_limit;
13777c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_xmitlock);
13787c478bd9Sstevel@tonic-gate 
13797c478bd9Sstevel@tonic-gate 	return (status);
13807c478bd9Sstevel@tonic-gate }
13817c478bd9Sstevel@tonic-gate 
13827c478bd9Sstevel@tonic-gate /*
13837c478bd9Sstevel@tonic-gate  * 	hme_check_link ()
13847c478bd9Sstevel@tonic-gate  * Called as a result of HME_LINKCHECK_TIMER timeout, to poll for Transceiver
13857c478bd9Sstevel@tonic-gate  * change or when a transceiver change has been detected by the hme_try_speed
13867c478bd9Sstevel@tonic-gate  * function.
13877c478bd9Sstevel@tonic-gate  * This function will also be called from the interrupt handler when polled mode
13887c478bd9Sstevel@tonic-gate  * is used. Before calling this function the interrupt lock should be freed
13897c478bd9Sstevel@tonic-gate  * so that the hmeinit() may be called.
13907c478bd9Sstevel@tonic-gate  * Note that the hmeinit() function calls hme_select_speed() to set the link
13917c478bd9Sstevel@tonic-gate  * speed and check for link status.
13927c478bd9Sstevel@tonic-gate  */
13937c478bd9Sstevel@tonic-gate 
13947c478bd9Sstevel@tonic-gate static void
13957c478bd9Sstevel@tonic-gate hme_check_link(void *arg)
13967c478bd9Sstevel@tonic-gate {
13977c478bd9Sstevel@tonic-gate 	struct hme *hmep = arg;
13987c478bd9Sstevel@tonic-gate 	uint16_t	stat;
13997c478bd9Sstevel@tonic-gate 	uint_t 	temp;
14007c478bd9Sstevel@tonic-gate 
14017c478bd9Sstevel@tonic-gate 	hme_stop_timer(hmep);	/* acquire hme_linklock */
14027c478bd9Sstevel@tonic-gate 
14037c478bd9Sstevel@tonic-gate 	/*
14047c478bd9Sstevel@tonic-gate 	 * This condition was added to work around for
14057c478bd9Sstevel@tonic-gate 	 * a problem with the Synoptics/Bay 28115 switch.
14067c478bd9Sstevel@tonic-gate 	 * Basically if the link is up but no packets
14077c478bd9Sstevel@tonic-gate 	 * are being received. This can be checked using
14087c478bd9Sstevel@tonic-gate 	 * ipackets, which in case of reception will
14097c478bd9Sstevel@tonic-gate 	 * continue to increment after 'hmep->hme_iipackets'
14107c478bd9Sstevel@tonic-gate 	 * has been made equal to it and the 'hme_check_link'
14117c478bd9Sstevel@tonic-gate 	 * timer has expired. Note this could also be done
14127c478bd9Sstevel@tonic-gate 	 * if there's no traffic on the net.
14137c478bd9Sstevel@tonic-gate 	 * 'hmep->hme_ipackets' is incremented in hme_read
14147c478bd9Sstevel@tonic-gate 	 * for successfully received packets.
14157c478bd9Sstevel@tonic-gate 	 */
14167c478bd9Sstevel@tonic-gate 	if ((hmep->hme_flags & HMERUNNING) && (hmep->hme_linkup)) {
14177c478bd9Sstevel@tonic-gate 		if (hmep->hme_ipackets != hmep->hme_iipackets)
14187c478bd9Sstevel@tonic-gate 			/*
14197c478bd9Sstevel@tonic-gate 			 * Receptions are occurring set 'hmep->hme_iipackets'
14207c478bd9Sstevel@tonic-gate 			 * to 'hmep->hme_ipackets' to monitor if receptions
14217c478bd9Sstevel@tonic-gate 			 * occur during the next timeout interval.
14227c478bd9Sstevel@tonic-gate 			 */
14237c478bd9Sstevel@tonic-gate 			hmep->hme_iipackets = hmep->hme_ipackets;
14247c478bd9Sstevel@tonic-gate 		else
14257c478bd9Sstevel@tonic-gate 			/*
14267c478bd9Sstevel@tonic-gate 			 * Receptions not occurring could be due to
14277c478bd9Sstevel@tonic-gate 			 * Synoptics problem, try switchin of data
14287c478bd9Sstevel@tonic-gate 			 * scrabbling. That should bring up the link.
14297c478bd9Sstevel@tonic-gate 			 */
14307c478bd9Sstevel@tonic-gate 			hme_link_now_up(hmep);
14317c478bd9Sstevel@tonic-gate 	}
14327c478bd9Sstevel@tonic-gate 
14337c478bd9Sstevel@tonic-gate 	if ((hmep->hme_flags & HMERUNNING) &&
14347c478bd9Sstevel@tonic-gate 	    (hmep->hme_linkup) && (hme_check_txhung(hmep))) {
14357c478bd9Sstevel@tonic-gate 
14367c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER);
14377c478bd9Sstevel@tonic-gate 		(void) hmeinit(hmep);	/* To reset the transceiver and */
14387c478bd9Sstevel@tonic-gate 					/* to init the interface */
14397c478bd9Sstevel@tonic-gate 		return;
14407c478bd9Sstevel@tonic-gate 	}
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	/*
14437c478bd9Sstevel@tonic-gate 	 * check if the transceiver is the same.
14447c478bd9Sstevel@tonic-gate 	 * init to be done if the external transceiver is
14457c478bd9Sstevel@tonic-gate 	 * connected/disconnected
14467c478bd9Sstevel@tonic-gate 	 */
14477c478bd9Sstevel@tonic-gate 	temp = hmep->hme_transceiver; /* save the transceiver type */
14487c478bd9Sstevel@tonic-gate 	hme_check_transceiver(hmep);
14497c478bd9Sstevel@tonic-gate 	if ((temp != hmep->hme_transceiver) || (hmep->hme_linkup == 0)) {
14507c478bd9Sstevel@tonic-gate 		if (temp != hmep->hme_transceiver) {
14517c478bd9Sstevel@tonic-gate 			if (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER) {
14527c478bd9Sstevel@tonic-gate 				HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN,
145385025c03Sgd 				    XCVR_MSG, ext_xcvr_msg);
14547c478bd9Sstevel@tonic-gate 			} else {
14557c478bd9Sstevel@tonic-gate 				HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN,
145685025c03Sgd 				    XCVR_MSG, int_xcvr_msg);
14577c478bd9Sstevel@tonic-gate 			}
14587c478bd9Sstevel@tonic-gate 		}
14597c478bd9Sstevel@tonic-gate 		hmep->hme_linkcheck = 0;
14607c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER);
146185025c03Sgd 		(void) hmeinit(hmep); /* To reset xcvr and init interface */
14627c478bd9Sstevel@tonic-gate 		return;
14637c478bd9Sstevel@tonic-gate 	}
14647c478bd9Sstevel@tonic-gate 
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 	if (hmep->hme_mifpoll_enable) {
14677c478bd9Sstevel@tonic-gate 		stat = (GET_MIFREG(mif_bsts) >> 16);
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate 		CHECK_MIFREG(); /* Verify */
14707c478bd9Sstevel@tonic-gate 
14717c478bd9Sstevel@tonic-gate 		if (!hmep->hme_mifpoll_flag) {
14727c478bd9Sstevel@tonic-gate 			if (stat & PHY_BMSR_LNKSTS) {
14737c478bd9Sstevel@tonic-gate 				hme_start_timer(hmep, hme_check_link,
147485025c03Sgd 				    HME_LINKCHECK_TIMER);
14757c478bd9Sstevel@tonic-gate 				return;
14767c478bd9Sstevel@tonic-gate 			}
14777c478bd9Sstevel@tonic-gate 			hme_stop_mifpoll(hmep);
14787c478bd9Sstevel@tonic-gate 
14797c478bd9Sstevel@tonic-gate 			temp = (GET_MIFREG(mif_bsts) >> 16);
14807c478bd9Sstevel@tonic-gate 		} else {
14817c478bd9Sstevel@tonic-gate 			hmep->hme_mifpoll_flag = 0;
14827c478bd9Sstevel@tonic-gate 		}
14837c478bd9Sstevel@tonic-gate 	} else {
14847c478bd9Sstevel@tonic-gate 		if (hme_mii_read(hmep, HME_PHY_BMSR, &stat) == 1) {
14857c478bd9Sstevel@tonic-gate 		/* Transceiver does not talk mii */
14867c478bd9Sstevel@tonic-gate 			hme_start_timer(hmep, hme_check_link,
148785025c03Sgd 			    HME_LINKCHECK_TIMER);
14887c478bd9Sstevel@tonic-gate 			return;
14897c478bd9Sstevel@tonic-gate 		}
14907c478bd9Sstevel@tonic-gate 
14917c478bd9Sstevel@tonic-gate 		if (stat & PHY_BMSR_LNKSTS) {
14927c478bd9Sstevel@tonic-gate 			hme_start_timer(hmep, hme_check_link,
149385025c03Sgd 			    HME_LINKCHECK_TIMER);
14947c478bd9Sstevel@tonic-gate 			return;
14957c478bd9Sstevel@tonic-gate 		}
14967c478bd9Sstevel@tonic-gate 	}
14977c478bd9Sstevel@tonic-gate 
14987c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_BMSR, &stat);
149985025c03Sgd 
15007c478bd9Sstevel@tonic-gate 	/*
15017c478bd9Sstevel@tonic-gate 	 * The PHY may have automatically renegotiated link speed and mode.
15027c478bd9Sstevel@tonic-gate 	 * Get the new link speed and mode.
15037c478bd9Sstevel@tonic-gate 	 */
15047c478bd9Sstevel@tonic-gate 	if ((stat & PHY_BMSR_LNKSTS) && hme_autoneg_enable) {
15057c478bd9Sstevel@tonic-gate 		if (hmep->hme_mode == HME_AUTO_SPEED) {
15067c478bd9Sstevel@tonic-gate 			(void) hme_get_autoinfo(hmep);
15077c478bd9Sstevel@tonic-gate 			hme_setup_link_status(hmep);
15087c478bd9Sstevel@tonic-gate 			hme_start_mifpoll(hmep);
15097c478bd9Sstevel@tonic-gate 			if (hmep->hme_fdx != hmep->hme_macfdx) {
15107c478bd9Sstevel@tonic-gate 				hme_start_timer(hmep, hme_check_link,
151185025c03Sgd 				    HME_LINKCHECK_TIMER);
15127c478bd9Sstevel@tonic-gate 				(void) hmeinit(hmep);
15137c478bd9Sstevel@tonic-gate 				return;
15147c478bd9Sstevel@tonic-gate 			}
15157c478bd9Sstevel@tonic-gate 		}
15167c478bd9Sstevel@tonic-gate 		hme_start_mifpoll(hmep);
15177c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER);
15187c478bd9Sstevel@tonic-gate 		return;
15197c478bd9Sstevel@tonic-gate 	}
15207c478bd9Sstevel@tonic-gate 	/* Reset the PHY and bring up the link */
15217c478bd9Sstevel@tonic-gate 	hme_reset_transceiver(hmep);
15227c478bd9Sstevel@tonic-gate }
15237c478bd9Sstevel@tonic-gate 
15247c478bd9Sstevel@tonic-gate static void
15257c478bd9Sstevel@tonic-gate hme_init_xcvr_info(struct hme *hmep)
15267c478bd9Sstevel@tonic-gate {
15277c478bd9Sstevel@tonic-gate 	uint16_t phy_id1, phy_id2;
15287c478bd9Sstevel@tonic-gate 
15297c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_IDR1, &phy_id1);
15307c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_IDR2, &phy_id2);
15317c478bd9Sstevel@tonic-gate }
15327c478bd9Sstevel@tonic-gate 
15337c478bd9Sstevel@tonic-gate /*
15347c478bd9Sstevel@tonic-gate  * Disable link pulses for the Internal Transceiver
15357c478bd9Sstevel@tonic-gate  */
15367c478bd9Sstevel@tonic-gate 
15377c478bd9Sstevel@tonic-gate static void
15387c478bd9Sstevel@tonic-gate hme_disable_link_pulse(struct hme *hmep)
15397c478bd9Sstevel@tonic-gate {
15407c478bd9Sstevel@tonic-gate 	uint16_t	nicr;
15417c478bd9Sstevel@tonic-gate 
15427c478bd9Sstevel@tonic-gate 	hme_mii_write(hmep, HME_PHY_BMCR, 0); /* force 10 Mbps */
15437c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_NICR, &nicr);
15447c478bd9Sstevel@tonic-gate 
15457c478bd9Sstevel@tonic-gate 	hme_mii_write(hmep, HME_PHY_NICR, (nicr & ~PHY_NICR_LD));
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 	hmep->hme_linkup = 1;
15487c478bd9Sstevel@tonic-gate 	hmep->hme_linkcheck = 1;
15497c478bd9Sstevel@tonic-gate 	hme_setup_link_status(hmep);
15507c478bd9Sstevel@tonic-gate 	hme_start_mifpoll(hmep);
15517c478bd9Sstevel@tonic-gate 	hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER);
15527c478bd9Sstevel@tonic-gate }
15537c478bd9Sstevel@tonic-gate 
15547c478bd9Sstevel@tonic-gate static void
15557c478bd9Sstevel@tonic-gate hme_force_speed(void *arg)
15567c478bd9Sstevel@tonic-gate {
15577c478bd9Sstevel@tonic-gate 	struct hme	*hmep = arg;
15587c478bd9Sstevel@tonic-gate 	int		linkup;
15597c478bd9Sstevel@tonic-gate 	uint_t		temp;
15607c478bd9Sstevel@tonic-gate 	uint16_t	csc;
15617c478bd9Sstevel@tonic-gate 
15627c478bd9Sstevel@tonic-gate 	hme_stop_timer(hmep);
15637c478bd9Sstevel@tonic-gate 	if (hmep->hme_fdx != hmep->hme_macfdx) {
15647c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_check_link, HME_TICKS*5);
15657c478bd9Sstevel@tonic-gate 		return;
15667c478bd9Sstevel@tonic-gate 	}
15677c478bd9Sstevel@tonic-gate 	temp = hmep->hme_transceiver; /* save the transceiver type */
15687c478bd9Sstevel@tonic-gate 	hme_check_transceiver(hmep);
15697c478bd9Sstevel@tonic-gate 	if (temp != hmep->hme_transceiver) {
15707c478bd9Sstevel@tonic-gate 		if (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER) {
15717c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG,
157285025c03Sgd 			    ext_xcvr_msg);
15737c478bd9Sstevel@tonic-gate 		} else {
15747c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG,
157585025c03Sgd 			    int_xcvr_msg);
15767c478bd9Sstevel@tonic-gate 		}
15777c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_check_link, HME_TICKS * 10);
15787c478bd9Sstevel@tonic-gate 		return;
15797c478bd9Sstevel@tonic-gate 	}
15807c478bd9Sstevel@tonic-gate 
15817c478bd9Sstevel@tonic-gate 	if ((hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER) &&
158285025c03Sgd 	    (hmep->hme_link_pulse_disabled)) {
15837c478bd9Sstevel@tonic-gate 		hmep->hme_forcespeed = HME_SPEED_10;
15847c478bd9Sstevel@tonic-gate 		hme_disable_link_pulse(hmep);
15857c478bd9Sstevel@tonic-gate 		return;
15867c478bd9Sstevel@tonic-gate 	}
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate 	/*
15897c478bd9Sstevel@tonic-gate 	 * To interoperate with auto-negotiable capable systems
15907c478bd9Sstevel@tonic-gate 	 * the link should be brought down for 1 second.
15917c478bd9Sstevel@tonic-gate 	 * How to do this using only standard registers ?
15927c478bd9Sstevel@tonic-gate 	 */
15937c478bd9Sstevel@tonic-gate 	if (HME_DP83840) {
15947c478bd9Sstevel@tonic-gate 		if (hmep->hme_force_linkdown == HME_FORCE_LINKDOWN) {
15957c478bd9Sstevel@tonic-gate 			hmep->hme_force_linkdown = HME_LINKDOWN_STARTED;
15967c478bd9Sstevel@tonic-gate 			hme_mii_write(hmep, HME_PHY_BMCR, PHY_BMCR_100M);
15977c478bd9Sstevel@tonic-gate 			(void) hme_mii_read(hmep, HME_PHY_CSC, &csc);
15987c478bd9Sstevel@tonic-gate 			hme_mii_write(hmep, HME_PHY_CSC,
159985025c03Sgd 			    (csc | PHY_CSCR_TXOFF));
16007c478bd9Sstevel@tonic-gate 			hme_start_timer(hmep, hme_force_speed, 10 * HME_TICKS);
16017c478bd9Sstevel@tonic-gate 			return;
16027c478bd9Sstevel@tonic-gate 		} else if (hmep->hme_force_linkdown == HME_LINKDOWN_STARTED) {
16037c478bd9Sstevel@tonic-gate 			(void) hme_mii_read(hmep, HME_PHY_CSC, &csc);
16047c478bd9Sstevel@tonic-gate 			hme_mii_write(hmep, HME_PHY_CSC,
160585025c03Sgd 			    (csc & ~PHY_CSCR_TXOFF));
16067c478bd9Sstevel@tonic-gate 			hmep->hme_force_linkdown = HME_LINKDOWN_DONE;
16077c478bd9Sstevel@tonic-gate 		}
16087c478bd9Sstevel@tonic-gate 	} else {
16097c478bd9Sstevel@tonic-gate 		if (hmep->hme_force_linkdown == HME_FORCE_LINKDOWN) {
16107c478bd9Sstevel@tonic-gate 			hmep->hme_force_linkdown = HME_LINKDOWN_STARTED;
16117c478bd9Sstevel@tonic-gate 			hme_mii_write(hmep, HME_PHY_BMCR, PHY_BMCR_LPBK);
16127c478bd9Sstevel@tonic-gate 			hme_start_timer(hmep, hme_force_speed, 10 * HME_TICKS);
16137c478bd9Sstevel@tonic-gate 			return;
16147c478bd9Sstevel@tonic-gate 		} else if (hmep->hme_force_linkdown == HME_LINKDOWN_STARTED) {
16157c478bd9Sstevel@tonic-gate 			hmep->hme_force_linkdown = HME_LINKDOWN_DONE;
16167c478bd9Sstevel@tonic-gate 		}
16177c478bd9Sstevel@tonic-gate 	}
16187c478bd9Sstevel@tonic-gate 
16197c478bd9Sstevel@tonic-gate 
16207c478bd9Sstevel@tonic-gate 	linkup = hme_select_speed(hmep, hmep->hme_forcespeed);
16217c478bd9Sstevel@tonic-gate 	if (hmep->hme_linkup_cnt == 1) {
16227c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_force_speed, SECOND(4));
16237c478bd9Sstevel@tonic-gate 		return;
16247c478bd9Sstevel@tonic-gate 	}
16257c478bd9Sstevel@tonic-gate 	if (linkup) {
16267c478bd9Sstevel@tonic-gate 
16277c478bd9Sstevel@tonic-gate 		hmep->hme_linkup = 1;
16287c478bd9Sstevel@tonic-gate 		hmep->hme_linkcheck = 1;
16297c478bd9Sstevel@tonic-gate 		hmep->hme_ifspeed = hmep->hme_forcespeed;
16307c478bd9Sstevel@tonic-gate 		hme_link_now_up(hmep);
16317c478bd9Sstevel@tonic-gate 		hme_setup_link_status(hmep);
16327c478bd9Sstevel@tonic-gate 		hme_start_mifpoll(hmep);
16337c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER);
16347c478bd9Sstevel@tonic-gate 	} else {
16357c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_force_speed, HME_TICKS);
16367c478bd9Sstevel@tonic-gate 	}
16377c478bd9Sstevel@tonic-gate }
16387c478bd9Sstevel@tonic-gate 
16397c478bd9Sstevel@tonic-gate static void
16407c478bd9Sstevel@tonic-gate hme_get_autoinfo(struct hme *hmep)
16417c478bd9Sstevel@tonic-gate {
16427c478bd9Sstevel@tonic-gate 	uint16_t	anar;
16437c478bd9Sstevel@tonic-gate 	uint16_t	aner;
16447c478bd9Sstevel@tonic-gate 	uint16_t	anlpar;
16457c478bd9Sstevel@tonic-gate 	uint16_t	tmp;
16467c478bd9Sstevel@tonic-gate 	uint16_t	ar;
16477c478bd9Sstevel@tonic-gate 
16487c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_ANER, &aner);
16497c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_ANLPAR, &anlpar);
16507c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_ANAR, &anar);
16517c478bd9Sstevel@tonic-gate 
16527c478bd9Sstevel@tonic-gate 	hmep->hme_anlpar = anlpar;
16537c478bd9Sstevel@tonic-gate 	hmep->hme_aner = aner;
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate 	if (aner & PHY_ANER_LPNW) {
16567c478bd9Sstevel@tonic-gate 
16577c478bd9Sstevel@tonic-gate 		tmp = anar & anlpar;
16587c478bd9Sstevel@tonic-gate 		if (tmp & PHY_ANAR_TXFDX) {
16597c478bd9Sstevel@tonic-gate 			hmep->hme_tryspeed = HME_SPEED_100;
16607c478bd9Sstevel@tonic-gate 			hmep->hme_fdx = HME_FULL_DUPLEX;
16617c478bd9Sstevel@tonic-gate 		} else if (tmp & PHY_ANAR_TX) {
16627c478bd9Sstevel@tonic-gate 			hmep->hme_tryspeed = HME_SPEED_100;
16637c478bd9Sstevel@tonic-gate 			hmep->hme_fdx = HME_HALF_DUPLEX;
16647c478bd9Sstevel@tonic-gate 		} else if (tmp & PHY_ANLPAR_10FDX) {
16657c478bd9Sstevel@tonic-gate 			hmep->hme_tryspeed = HME_SPEED_10;
16667c478bd9Sstevel@tonic-gate 			hmep->hme_fdx = HME_FULL_DUPLEX;
16677c478bd9Sstevel@tonic-gate 		} else if (tmp & PHY_ANLPAR_10) {
16687c478bd9Sstevel@tonic-gate 			hmep->hme_tryspeed = HME_SPEED_10;
16697c478bd9Sstevel@tonic-gate 			hmep->hme_fdx = HME_HALF_DUPLEX;
16707c478bd9Sstevel@tonic-gate 		} else {
16717c478bd9Sstevel@tonic-gate 			if (HME_DP83840) {
16727c478bd9Sstevel@tonic-gate 
16737c478bd9Sstevel@tonic-gate 				hmep->hme_fdx = HME_HALF_DUPLEX;
16747c478bd9Sstevel@tonic-gate 				(void) hme_mii_read(hmep, HME_PHY_AR, &ar);
16757c478bd9Sstevel@tonic-gate 
16767c478bd9Sstevel@tonic-gate 				if (ar & PHY_AR_SPEED10)
16777c478bd9Sstevel@tonic-gate 					hmep->hme_tryspeed = HME_SPEED_10;
16787c478bd9Sstevel@tonic-gate 				else
16797c478bd9Sstevel@tonic-gate 					hmep->hme_tryspeed = HME_SPEED_100;
16807c478bd9Sstevel@tonic-gate 			} else
16817c478bd9Sstevel@tonic-gate 				HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN,
168285025c03Sgd 				    AUTONEG_MSG, anar_not_set_msg);
16837c478bd9Sstevel@tonic-gate 		}
16847c478bd9Sstevel@tonic-gate 	} else {
16857c478bd9Sstevel@tonic-gate 		hmep->hme_fdx = HME_HALF_DUPLEX;
16867c478bd9Sstevel@tonic-gate 		if (anlpar & PHY_ANLPAR_TX)
16877c478bd9Sstevel@tonic-gate 			hmep->hme_tryspeed = HME_SPEED_100;
16887c478bd9Sstevel@tonic-gate 		else if (anlpar & PHY_ANLPAR_10)
16897c478bd9Sstevel@tonic-gate 			hmep->hme_tryspeed = HME_SPEED_10;
16907c478bd9Sstevel@tonic-gate 		else {
16917c478bd9Sstevel@tonic-gate 			if (HME_DP83840) {
16927c478bd9Sstevel@tonic-gate 
16937c478bd9Sstevel@tonic-gate 				(void) hme_mii_read(hmep, HME_PHY_AR, &ar);
16947c478bd9Sstevel@tonic-gate 
16957c478bd9Sstevel@tonic-gate 				if (ar & PHY_AR_SPEED10)
16967c478bd9Sstevel@tonic-gate 					hmep->hme_tryspeed = HME_SPEED_10;
16977c478bd9Sstevel@tonic-gate 				else
16987c478bd9Sstevel@tonic-gate 					hmep->hme_tryspeed = HME_SPEED_100;
16997c478bd9Sstevel@tonic-gate 			} else
17007c478bd9Sstevel@tonic-gate 				HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN,
170185025c03Sgd 				    AUTONEG_MSG, par_detect_anar_not_set_msg);
17027c478bd9Sstevel@tonic-gate 		}
17037c478bd9Sstevel@tonic-gate 	}
17047c478bd9Sstevel@tonic-gate 
17057c478bd9Sstevel@tonic-gate 	hmep->hme_linkup = 1;
17067c478bd9Sstevel@tonic-gate 	hmep->hme_linkcheck = 1;
17077c478bd9Sstevel@tonic-gate 	hmep->hme_ifspeed = hmep->hme_tryspeed;
17087c478bd9Sstevel@tonic-gate 	hme_link_now_up(hmep);
17097c478bd9Sstevel@tonic-gate }
17107c478bd9Sstevel@tonic-gate 
17117c478bd9Sstevel@tonic-gate /*
17127c478bd9Sstevel@tonic-gate  * Return 1 if the link is up or auto-negotiation being tried, 0 otherwise.
17137c478bd9Sstevel@tonic-gate  */
17147c478bd9Sstevel@tonic-gate 
17157c478bd9Sstevel@tonic-gate static int
17167c478bd9Sstevel@tonic-gate hme_try_auto_negotiation(struct hme *hmep)
17177c478bd9Sstevel@tonic-gate {
17187c478bd9Sstevel@tonic-gate 	uint16_t	stat;
17197c478bd9Sstevel@tonic-gate 	uint16_t	aner;
17207c478bd9Sstevel@tonic-gate 
17217c478bd9Sstevel@tonic-gate 	if (hmep->hme_autoneg == HME_HWAN_TRY) {
17227c478bd9Sstevel@tonic-gate 		/* auto negotiation not initiated */
17237c478bd9Sstevel@tonic-gate 		(void) hme_mii_read(hmep, HME_PHY_BMSR, &stat);
17247c478bd9Sstevel@tonic-gate 		if (hme_mii_read(hmep, HME_PHY_BMSR, &stat) == 1) {
17257c478bd9Sstevel@tonic-gate 			/*
17267c478bd9Sstevel@tonic-gate 			 * Transceiver does not talk mii
17277c478bd9Sstevel@tonic-gate 			 */
17287c478bd9Sstevel@tonic-gate 			goto hme_anfail;
17297c478bd9Sstevel@tonic-gate 		}
17307c478bd9Sstevel@tonic-gate 		if ((stat & PHY_BMSR_ACFG) == 0) { /* auto neg. not supported */
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 			return (hmep->hme_autoneg = HME_HWAN_FAILED);
17337c478bd9Sstevel@tonic-gate 		}
17347c478bd9Sstevel@tonic-gate 
17357c478bd9Sstevel@tonic-gate 		/*
17367c478bd9Sstevel@tonic-gate 		 * Read ANER to clear status from previous operations.
17377c478bd9Sstevel@tonic-gate 		 */
17387c478bd9Sstevel@tonic-gate 		if (hme_mii_read(hmep, HME_PHY_ANER, &aner) == 1) {
17397c478bd9Sstevel@tonic-gate 			/*
17407c478bd9Sstevel@tonic-gate 			 * Transceiver does not talk mii
17417c478bd9Sstevel@tonic-gate 			 */
17427c478bd9Sstevel@tonic-gate 			goto hme_anfail;
17437c478bd9Sstevel@tonic-gate 		}
17447c478bd9Sstevel@tonic-gate 
17457c478bd9Sstevel@tonic-gate 		hme_mii_write(hmep, HME_PHY_ANAR, hmep->hme_anar);
17467c478bd9Sstevel@tonic-gate 		hme_mii_write(hmep, HME_PHY_BMCR, PHY_BMCR_ANE | PHY_BMCR_RAN);
17477c478bd9Sstevel@tonic-gate 		/*
17487c478bd9Sstevel@tonic-gate 		 * auto-negotiation initiated
17497c478bd9Sstevel@tonic-gate 		 */
17507c478bd9Sstevel@tonic-gate 		hmep->hme_delay = 0;
17517c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_try_speed, HME_TICKS);
17527c478bd9Sstevel@tonic-gate 		return (hmep->hme_autoneg = HME_HWAN_INPROGRESS);
17537c478bd9Sstevel@tonic-gate 		/*
17547c478bd9Sstevel@tonic-gate 		 * auto-negotiation in progress
17557c478bd9Sstevel@tonic-gate 		 */
17567c478bd9Sstevel@tonic-gate 	}
17577c478bd9Sstevel@tonic-gate 
17587c478bd9Sstevel@tonic-gate 	/*
17597c478bd9Sstevel@tonic-gate 	 * Auto-negotiation has been in progress. Wait for at least
17607c478bd9Sstevel@tonic-gate 	 * least 3000 ms.
17617c478bd9Sstevel@tonic-gate 	 * Changed 8/28/97 to fix bug ID 4070989.
17627c478bd9Sstevel@tonic-gate 	 */
17637c478bd9Sstevel@tonic-gate 	if (hmep->hme_delay < 30) {
17647c478bd9Sstevel@tonic-gate 		hmep->hme_delay++;
17657c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_try_speed, HME_TICKS);
17667c478bd9Sstevel@tonic-gate 		return (hmep->hme_autoneg = HME_HWAN_INPROGRESS);
17677c478bd9Sstevel@tonic-gate 	}
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_BMSR, &stat);
17707c478bd9Sstevel@tonic-gate 	if (hme_mii_read(hmep, HME_PHY_BMSR, &stat) == 1) {
17717c478bd9Sstevel@tonic-gate 		/*
17727c478bd9Sstevel@tonic-gate 		 * Transceiver does not talk mii
17737c478bd9Sstevel@tonic-gate 		 */
17747c478bd9Sstevel@tonic-gate 		goto hme_anfail;
17757c478bd9Sstevel@tonic-gate 	}
17767c478bd9Sstevel@tonic-gate 
17777c478bd9Sstevel@tonic-gate 	if ((stat & PHY_BMSR_ANC) == 0) {
17787c478bd9Sstevel@tonic-gate 		/*
17797c478bd9Sstevel@tonic-gate 		 * wait for a maximum of 5 seconds
17807c478bd9Sstevel@tonic-gate 		 */
17817c478bd9Sstevel@tonic-gate 		if (hmep->hme_delay < 50) {
17827c478bd9Sstevel@tonic-gate 			hmep->hme_delay++;
17837c478bd9Sstevel@tonic-gate 			hme_start_timer(hmep, hme_try_speed, HME_TICKS);
17847c478bd9Sstevel@tonic-gate 			return (hmep->hme_autoneg = HME_HWAN_INPROGRESS);
17857c478bd9Sstevel@tonic-gate 		}
17867c478bd9Sstevel@tonic-gate 		if (HME_DP83840) {
17877c478bd9Sstevel@tonic-gate 			(void) hme_mii_read(hmep, HME_PHY_ANER, &aner);
17887c478bd9Sstevel@tonic-gate 			if (aner & PHY_ANER_MLF) {
17897c478bd9Sstevel@tonic-gate 
17907c478bd9Sstevel@tonic-gate 				return (hmep->hme_autoneg = HME_HWAN_FAILED);
17917c478bd9Sstevel@tonic-gate 			}
17927c478bd9Sstevel@tonic-gate 		}
17937c478bd9Sstevel@tonic-gate 
17947c478bd9Sstevel@tonic-gate 		goto hme_anfail;
17957c478bd9Sstevel@tonic-gate 	}
17967c478bd9Sstevel@tonic-gate 
17977c478bd9Sstevel@tonic-gate 	(void) hme_mii_read(hmep, HME_PHY_ANER, &aner);
17987c478bd9Sstevel@tonic-gate 	if (aner & PHY_ANER_MLF) {
17997c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTONEG_MSG,
180085025c03Sgd 		    par_detect_msg);
18017c478bd9Sstevel@tonic-gate 		goto hme_anfail;
18027c478bd9Sstevel@tonic-gate 	}
18037c478bd9Sstevel@tonic-gate 
18047c478bd9Sstevel@tonic-gate 	if (!(stat & PHY_BMSR_LNKSTS)) {
18057c478bd9Sstevel@tonic-gate 		/*
18067c478bd9Sstevel@tonic-gate 		 * wait for a maximum of 10 seconds
18077c478bd9Sstevel@tonic-gate 		 */
18087c478bd9Sstevel@tonic-gate 		if (hmep->hme_delay < 100) {
18097c478bd9Sstevel@tonic-gate 			hmep->hme_delay++;
18107c478bd9Sstevel@tonic-gate 			hme_start_timer(hmep, hme_try_speed, HME_TICKS);
18117c478bd9Sstevel@tonic-gate 			return (hmep->hme_autoneg = HME_HWAN_INPROGRESS);
18127c478bd9Sstevel@tonic-gate 		}
18137c478bd9Sstevel@tonic-gate 		goto hme_anfail;
18147c478bd9Sstevel@tonic-gate 	} else {
18157c478bd9Sstevel@tonic-gate 		hmep->hme_bmsr |= (PHY_BMSR_LNKSTS);
18167c478bd9Sstevel@tonic-gate 		hme_get_autoinfo(hmep);
18177c478bd9Sstevel@tonic-gate 		hmep->hme_force_linkdown = HME_LINKDOWN_DONE;
18187c478bd9Sstevel@tonic-gate 		hme_setup_link_status(hmep);
18197c478bd9Sstevel@tonic-gate 		hme_start_mifpoll(hmep);
18207c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER);
1821*0219346bSGarrett D'Amore 		if (hmep->hme_fdx != hmep->hme_macfdx) {
18227c478bd9Sstevel@tonic-gate 			(void) hmeinit(hmep);
1823*0219346bSGarrett D'Amore 		}
18247c478bd9Sstevel@tonic-gate 		return (hmep->hme_autoneg = HME_HWAN_SUCCESFUL);
18257c478bd9Sstevel@tonic-gate 	}
18267c478bd9Sstevel@tonic-gate 
18277c478bd9Sstevel@tonic-gate hme_anfail:
18287c478bd9Sstevel@tonic-gate 	hme_start_timer(hmep, hme_try_speed, HME_TICKS);
18297c478bd9Sstevel@tonic-gate 	return (hmep->hme_autoneg = HME_HWAN_TRY);
18307c478bd9Sstevel@tonic-gate }
18317c478bd9Sstevel@tonic-gate 
18327c478bd9Sstevel@tonic-gate /*
18337c478bd9Sstevel@tonic-gate  * This function is used to perform automatic speed detection.
18347c478bd9Sstevel@tonic-gate  * The Internal Transceiver which is based on the National PHY chip
18357c478bd9Sstevel@tonic-gate  * 83840 supports auto-negotiation functionality.
18367c478bd9Sstevel@tonic-gate  * Some External transceivers may not support auto-negotiation.
18377c478bd9Sstevel@tonic-gate  * In that case, the software performs the speed detection.
18387c478bd9Sstevel@tonic-gate  * The software tries to bring down the link for about 2 seconds to
18397c478bd9Sstevel@tonic-gate  * force the Link Partner to notice speed change.
18407c478bd9Sstevel@tonic-gate  * The software speed detection favors the 100 Mbps speed.
18417c478bd9Sstevel@tonic-gate  * It does this by setting the 100 Mbps for longer duration ( 5 seconds )
18427c478bd9Sstevel@tonic-gate  * than the 10 Mbps ( 2 seconds ). Also, even after the link is up
18437c478bd9Sstevel@tonic-gate  * in 10 Mbps once, the 100 Mbps is also tried. Only if the link
18447c478bd9Sstevel@tonic-gate  * is not up in 100 Mbps, the 10 Mbps speed is tried again.
18457c478bd9Sstevel@tonic-gate  */
18467c478bd9Sstevel@tonic-gate static void
18477c478bd9Sstevel@tonic-gate hme_try_speed(void *arg)
18487c478bd9Sstevel@tonic-gate {
18497c478bd9Sstevel@tonic-gate 	struct hme	*hmep = arg;
18507c478bd9Sstevel@tonic-gate 	int		linkup;
18517c478bd9Sstevel@tonic-gate 	uint_t		temp;
18527c478bd9Sstevel@tonic-gate 
18537c478bd9Sstevel@tonic-gate 	hme_stop_timer(hmep);
18547c478bd9Sstevel@tonic-gate 	temp = hmep->hme_transceiver; /* save the transceiver type */
18557c478bd9Sstevel@tonic-gate 	hme_check_transceiver(hmep);
18567c478bd9Sstevel@tonic-gate 	if (temp != hmep->hme_transceiver) {
18577c478bd9Sstevel@tonic-gate 		if (hmep->hme_transceiver == HME_EXTERNAL_TRANSCEIVER) {
18587c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG,
185985025c03Sgd 			    ext_xcvr_msg);
18607c478bd9Sstevel@tonic-gate 		} else {
18617c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, XCVR_MSG,
186285025c03Sgd 			    int_xcvr_msg);
18637c478bd9Sstevel@tonic-gate 		}
18647c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_check_link, 10 * HME_TICKS);
18657c478bd9Sstevel@tonic-gate 		return;
18667c478bd9Sstevel@tonic-gate 	}
18677c478bd9Sstevel@tonic-gate 
18687c478bd9Sstevel@tonic-gate 	if ((hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER) &&
186985025c03Sgd 	    (hmep->hme_link_pulse_disabled)) {
18707c478bd9Sstevel@tonic-gate 		hmep->hme_tryspeed = HME_SPEED_10;
18717c478bd9Sstevel@tonic-gate 		hme_disable_link_pulse(hmep);
18727c478bd9Sstevel@tonic-gate 		return;
18737c478bd9Sstevel@tonic-gate 	}
18747c478bd9Sstevel@tonic-gate 
18757c478bd9Sstevel@tonic-gate 	if (hme_autoneg_enable && (hmep->hme_autoneg != HME_HWAN_FAILED)) {
18767c478bd9Sstevel@tonic-gate 		if (hme_try_auto_negotiation(hmep) != HME_HWAN_FAILED)
18777c478bd9Sstevel@tonic-gate 			return;	/* auto negotiation successful or being tried */
18787c478bd9Sstevel@tonic-gate 	}
18797c478bd9Sstevel@tonic-gate 
18807c478bd9Sstevel@tonic-gate 	linkup = hme_select_speed(hmep, hmep->hme_tryspeed);
18817c478bd9Sstevel@tonic-gate 	if (hmep->hme_linkup_cnt == 1) {
18827c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_try_speed, SECOND(1));
18837c478bd9Sstevel@tonic-gate 		return;
18847c478bd9Sstevel@tonic-gate 	}
18857c478bd9Sstevel@tonic-gate 	if (linkup) {
18867c478bd9Sstevel@tonic-gate 		switch (hmep->hme_tryspeed) {
18877c478bd9Sstevel@tonic-gate 		case HME_SPEED_100:
18887c478bd9Sstevel@tonic-gate 			if (hmep->hme_linkup_cnt == 4) {
18897c478bd9Sstevel@tonic-gate 				hmep->hme_ntries =	HME_NTRIES_LOW;
18907c478bd9Sstevel@tonic-gate 				hmep->hme_nlasttries =	HME_NTRIES_LOW;
18917c478bd9Sstevel@tonic-gate 				hmep->hme_linkup = 1;
18927c478bd9Sstevel@tonic-gate 				hmep->hme_linkcheck = 1;
18937c478bd9Sstevel@tonic-gate 				hme_link_now_up(hmep);
18947c478bd9Sstevel@tonic-gate 				hme_setup_link_status(hmep);
18957c478bd9Sstevel@tonic-gate 				hme_start_mifpoll(hmep);
18967c478bd9Sstevel@tonic-gate 				hme_start_timer(hmep, hme_check_link,
189785025c03Sgd 				    HME_LINKCHECK_TIMER);
1898*0219346bSGarrett D'Amore 				if (hmep->hme_fdx != hmep->hme_macfdx) {
18997c478bd9Sstevel@tonic-gate 					(void) hmeinit(hmep);
1900*0219346bSGarrett D'Amore 				}
19017c478bd9Sstevel@tonic-gate 			} else
19027c478bd9Sstevel@tonic-gate 				hme_start_timer(hmep, hme_try_speed, HME_TICKS);
19037c478bd9Sstevel@tonic-gate 			break;
19047c478bd9Sstevel@tonic-gate 		case HME_SPEED_10:
19057c478bd9Sstevel@tonic-gate 			if (hmep->hme_linkup_cnt == 4) {
19067c478bd9Sstevel@tonic-gate 				if (hmep->hme_linkup_10) {
19077c478bd9Sstevel@tonic-gate 					hmep->hme_linkup_10 = 0;
19087c478bd9Sstevel@tonic-gate 					hmep->hme_ntries = HME_NTRIES_LOW;
19097c478bd9Sstevel@tonic-gate 					hmep->hme_nlasttries = HME_NTRIES_LOW;
19107c478bd9Sstevel@tonic-gate 					hmep->hme_linkup = 1;
19117c478bd9Sstevel@tonic-gate 					hmep->hme_linkcheck = 1;
19127c478bd9Sstevel@tonic-gate 					hmep->hme_ifspeed = HME_SPEED_10;
19137c478bd9Sstevel@tonic-gate 					hme_setup_link_status(hmep);
19147c478bd9Sstevel@tonic-gate 					hme_start_mifpoll(hmep);
19157c478bd9Sstevel@tonic-gate 					hme_start_timer(hmep, hme_check_link,
191685025c03Sgd 					    HME_LINKCHECK_TIMER);
1917*0219346bSGarrett D'Amore 					if (hmep->hme_fdx != hmep->hme_macfdx) {
19187c478bd9Sstevel@tonic-gate 						(void) hmeinit(hmep);
1919*0219346bSGarrett D'Amore 					}
19207c478bd9Sstevel@tonic-gate 				} else {
19217c478bd9Sstevel@tonic-gate 					hmep->hme_linkup_10 = 1;
19227c478bd9Sstevel@tonic-gate 					hmep->hme_tryspeed = HME_SPEED_100;
19237c478bd9Sstevel@tonic-gate 					hmep->hme_force_linkdown =
192485025c03Sgd 					    HME_FORCE_LINKDOWN;
19257c478bd9Sstevel@tonic-gate 					hmep->hme_linkup_cnt = 0;
19267c478bd9Sstevel@tonic-gate 					hmep->hme_ntries = HME_NTRIES_LOW;
19277c478bd9Sstevel@tonic-gate 					hmep->hme_nlasttries = HME_NTRIES_LOW;
19287c478bd9Sstevel@tonic-gate 					hme_start_timer(hmep,
192985025c03Sgd 					    hme_try_speed, HME_TICKS);
19307c478bd9Sstevel@tonic-gate 				}
19317c478bd9Sstevel@tonic-gate 
19327c478bd9Sstevel@tonic-gate 			} else
19337c478bd9Sstevel@tonic-gate 				hme_start_timer(hmep, hme_try_speed, HME_TICKS);
19347c478bd9Sstevel@tonic-gate 			break;
19357c478bd9Sstevel@tonic-gate 		default:
19367c478bd9Sstevel@tonic-gate 			break;
19377c478bd9Sstevel@tonic-gate 		}
19387c478bd9Sstevel@tonic-gate 		return;
19397c478bd9Sstevel@tonic-gate 	}
19407c478bd9Sstevel@tonic-gate 
19417c478bd9Sstevel@tonic-gate 	hmep->hme_ntries--;
19427c478bd9Sstevel@tonic-gate 	hmep->hme_linkup_cnt = 0;
19437c478bd9Sstevel@tonic-gate 	if (hmep->hme_ntries == 0) {
19447c478bd9Sstevel@tonic-gate 		hmep->hme_force_linkdown = HME_FORCE_LINKDOWN;
19457c478bd9Sstevel@tonic-gate 		switch (hmep->hme_tryspeed) {
19467c478bd9Sstevel@tonic-gate 		case HME_SPEED_100:
19477c478bd9Sstevel@tonic-gate 			hmep->hme_tryspeed = HME_SPEED_10;
19487c478bd9Sstevel@tonic-gate 			hmep->hme_ntries = HME_NTRIES_LOW_10;
19497c478bd9Sstevel@tonic-gate 			break;
19507c478bd9Sstevel@tonic-gate 		case HME_SPEED_10:
19517c478bd9Sstevel@tonic-gate 			hmep->hme_ntries = HME_NTRIES_LOW;
19527c478bd9Sstevel@tonic-gate 			hmep->hme_tryspeed = HME_SPEED_100;
19537c478bd9Sstevel@tonic-gate 			break;
19547c478bd9Sstevel@tonic-gate 		default:
19557c478bd9Sstevel@tonic-gate 			break;
19567c478bd9Sstevel@tonic-gate 		}
19577c478bd9Sstevel@tonic-gate 	}
19587c478bd9Sstevel@tonic-gate 	hme_start_timer(hmep, hme_try_speed, HME_TICKS);
19597c478bd9Sstevel@tonic-gate }
19607c478bd9Sstevel@tonic-gate 
19617c478bd9Sstevel@tonic-gate static void
19627c478bd9Sstevel@tonic-gate hme_link_now_up(struct hme *hmep)
19637c478bd9Sstevel@tonic-gate {
19647c478bd9Sstevel@tonic-gate 	uint16_t	btxpc;
19657c478bd9Sstevel@tonic-gate 	/*
19667c478bd9Sstevel@tonic-gate 	 * Work-around for the scramble problem with QSI
19677c478bd9Sstevel@tonic-gate 	 * chip and Synoptics 28115 switch.
19687c478bd9Sstevel@tonic-gate 	 * Addition Interface Technologies Group (NPG) 8/28/1997.
19697c478bd9Sstevel@tonic-gate 	 */
197085025c03Sgd 	if ((HME_QS6612) && ((hmep->hme_tryspeed  == HME_SPEED_100) ||
197185025c03Sgd 	    (hmep->hme_forcespeed == HME_SPEED_100))) {
19727c478bd9Sstevel@tonic-gate 		/*
19737c478bd9Sstevel@tonic-gate 		 * Addition of a check for 'hmep->hme_forcespeed'
19747c478bd9Sstevel@tonic-gate 		 * This is necessary when the autonegotiation is
19757c478bd9Sstevel@tonic-gate 		 * disabled by the 'hme.conf' file. In this case
19767c478bd9Sstevel@tonic-gate 		 * hmep->hme_tryspeed is not initialized. Resulting
19777c478bd9Sstevel@tonic-gate 		 * in the workaround not being applied.
19787c478bd9Sstevel@tonic-gate 		 */
19797c478bd9Sstevel@tonic-gate 		if (hme_mii_read(hmep, HME_PHY_BTXPC, &btxpc) == 0) {
19807c478bd9Sstevel@tonic-gate 			hme_mii_write(hmep, HME_PHY_BTXPC,
198185025c03Sgd 			    (btxpc | PHY_BTXPC_DSCRAM));
19827c478bd9Sstevel@tonic-gate 			drv_usecwait(20);
19837c478bd9Sstevel@tonic-gate 			hme_mii_write(hmep, HME_PHY_BTXPC, btxpc);
19847c478bd9Sstevel@tonic-gate 		}
19857c478bd9Sstevel@tonic-gate 	}
19867c478bd9Sstevel@tonic-gate }
19877c478bd9Sstevel@tonic-gate /* <<<<<<<<<<<<<<<<<<<<<<<<<<<  LOADABLE ENTRIES  >>>>>>>>>>>>>>>>>>>>>>> */
19887c478bd9Sstevel@tonic-gate 
19897c478bd9Sstevel@tonic-gate int
19907c478bd9Sstevel@tonic-gate _init(void)
19917c478bd9Sstevel@tonic-gate {
19927c478bd9Sstevel@tonic-gate 	int	status;
19937c478bd9Sstevel@tonic-gate 
199485025c03Sgd 	mac_init_ops(&hme_dev_ops, "hme");
199585025c03Sgd 	if ((status = mod_install(&modlinkage)) != 0) {
199685025c03Sgd 		mac_fini_ops(&hme_dev_ops);
19977c478bd9Sstevel@tonic-gate 	}
19987c478bd9Sstevel@tonic-gate 	return (status);
19997c478bd9Sstevel@tonic-gate }
20007c478bd9Sstevel@tonic-gate 
20017c478bd9Sstevel@tonic-gate int
20027c478bd9Sstevel@tonic-gate _fini(void)
20037c478bd9Sstevel@tonic-gate {
20047c478bd9Sstevel@tonic-gate 	int	status;
20057c478bd9Sstevel@tonic-gate 
200685025c03Sgd 	if ((status = mod_remove(&modlinkage)) == 0) {
200785025c03Sgd 		mac_fini_ops(&hme_dev_ops);
20087c478bd9Sstevel@tonic-gate 	}
20097c478bd9Sstevel@tonic-gate 	return (status);
20107c478bd9Sstevel@tonic-gate }
20117c478bd9Sstevel@tonic-gate 
20127c478bd9Sstevel@tonic-gate int
20137c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
20147c478bd9Sstevel@tonic-gate {
20157c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
20167c478bd9Sstevel@tonic-gate }
20177c478bd9Sstevel@tonic-gate 
20187c478bd9Sstevel@tonic-gate /*
20197c478bd9Sstevel@tonic-gate  * ddi_dma_sync() a TMD or RMD descriptor.
20207c478bd9Sstevel@tonic-gate  */
2021*0219346bSGarrett D'Amore #define	HMESYNCRMD(num, who)				\
2022*0219346bSGarrett D'Amore 	(void) ddi_dma_sync(hmep->hme_rmd_dmah,		\
2023*0219346bSGarrett D'Amore 	    (num * sizeof (struct hme_rmd)),		\
2024*0219346bSGarrett D'Amore 	    sizeof (struct hme_rmd),			\
2025*0219346bSGarrett D'Amore 	    who)
2026*0219346bSGarrett D'Amore 
2027*0219346bSGarrett D'Amore #define	HMESYNCTMD(num, who)				\
2028*0219346bSGarrett D'Amore 	(void) ddi_dma_sync(hmep->hme_tmd_dmah,		\
2029*0219346bSGarrett D'Amore 	    (num * sizeof (struct hme_tmd)),		\
2030*0219346bSGarrett D'Amore 	    sizeof (struct hme_tmd),			\
2031*0219346bSGarrett D'Amore 	    who)
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate /*
20347c478bd9Sstevel@tonic-gate  * Ethernet broadcast address definition.
20357c478bd9Sstevel@tonic-gate  */
20367c478bd9Sstevel@tonic-gate static	struct ether_addr	etherbroadcastaddr = {
20377c478bd9Sstevel@tonic-gate 	0xff, 0xff, 0xff, 0xff, 0xff, 0xff
20387c478bd9Sstevel@tonic-gate };
20397c478bd9Sstevel@tonic-gate 
20407c478bd9Sstevel@tonic-gate /*
20417c478bd9Sstevel@tonic-gate  * MIB II broadcast/multicast packets
20427c478bd9Sstevel@tonic-gate  */
204385025c03Sgd #define	IS_BROADCAST(pkt) (bcmp(pkt, &etherbroadcastaddr, ETHERADDRL) == 0)
204485025c03Sgd #define	IS_MULTICAST(pkt) ((pkt[0] & 01) == 1)
204585025c03Sgd #define	BUMP_InNUcast(hmep, pkt) \
2046*0219346bSGarrett D'Amore 	if (IS_MULTICAST(pkt)) {			       \
2047*0219346bSGarrett D'Amore 		if (IS_BROADCAST(pkt)) {		       \
2048*0219346bSGarrett D'Amore 			hmep->hme_brdcstrcv++;		       \
2049*0219346bSGarrett D'Amore 		} else {				       \
2050*0219346bSGarrett D'Amore 			hmep->hme_multircv++;		       \
2051*0219346bSGarrett D'Amore 		}					       \
2052*0219346bSGarrett D'Amore 	}
205385025c03Sgd #define	BUMP_OutNUcast(hmep, pkt) \
2054*0219346bSGarrett D'Amore 	if (IS_MULTICAST(pkt)) {			       \
2055*0219346bSGarrett D'Amore 		if (IS_BROADCAST(pkt)) {		       \
2056*0219346bSGarrett D'Amore 			hmep->hme_brdcstxmt++;		       \
2057*0219346bSGarrett D'Amore 		} else {				       \
2058*0219346bSGarrett D'Amore 			hmep->hme_multixmt++;		       \
2059*0219346bSGarrett D'Amore 		}					       \
2060*0219346bSGarrett D'Amore 	}
20617c478bd9Sstevel@tonic-gate 
20627c478bd9Sstevel@tonic-gate static int
20637c478bd9Sstevel@tonic-gate hme_create_prop_from_kw(dev_info_t *dip, char *vpdname, char *vpdstr)
20647c478bd9Sstevel@tonic-gate {
20657c478bd9Sstevel@tonic-gate 	char propstr[80];
20667c478bd9Sstevel@tonic-gate 	int i, needprop = 0;
20677c478bd9Sstevel@tonic-gate 	struct ether_addr local_mac;
20687c478bd9Sstevel@tonic-gate 
20697c478bd9Sstevel@tonic-gate 	if (strcmp(vpdname, "NA") == 0) {
20707c478bd9Sstevel@tonic-gate 		(void) strcpy(propstr, "local-mac-address");
20717c478bd9Sstevel@tonic-gate 		needprop = 1;
20727c478bd9Sstevel@tonic-gate 	} else if (strcmp(vpdname, "Z0") == 0) {
20737c478bd9Sstevel@tonic-gate 		(void) strcpy(propstr, "model");
20747c478bd9Sstevel@tonic-gate 		needprop = 1;
20757c478bd9Sstevel@tonic-gate 	} else if (strcmp(vpdname, "Z1") == 0) {
20767c478bd9Sstevel@tonic-gate 		(void) strcpy(propstr, "board-model");
20777c478bd9Sstevel@tonic-gate 		needprop = 1;
20787c478bd9Sstevel@tonic-gate 	}
20797c478bd9Sstevel@tonic-gate 
20807c478bd9Sstevel@tonic-gate 	if (needprop == 1) {
2081*0219346bSGarrett D'Amore 
20827c478bd9Sstevel@tonic-gate 		if (strcmp(propstr, "local-mac-address") == 0) {
20837c478bd9Sstevel@tonic-gate 			for (i = 0; i < ETHERADDRL; i++)
20847c478bd9Sstevel@tonic-gate 				local_mac.ether_addr_octet[i] =
208585025c03Sgd 				    (uchar_t)vpdstr[i];
20867c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, dip,
208785025c03Sgd 			    DDI_PROP_CANSLEEP, propstr,
208885025c03Sgd 			    (char *)local_mac.ether_addr_octet, ETHERADDRL)
208985025c03Sgd 			    != DDI_SUCCESS) {
20907c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
20917c478bd9Sstevel@tonic-gate 			}
20927c478bd9Sstevel@tonic-gate 		} else {
20937c478bd9Sstevel@tonic-gate 			if (ddi_prop_create(DDI_DEV_T_NONE, dip,
209485025c03Sgd 			    DDI_PROP_CANSLEEP, propstr, vpdstr,
209585025c03Sgd 			    strlen(vpdstr)+1) != DDI_SUCCESS) {
20967c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
20977c478bd9Sstevel@tonic-gate 			}
20987c478bd9Sstevel@tonic-gate 		}
20997c478bd9Sstevel@tonic-gate 	}
21007c478bd9Sstevel@tonic-gate 	return (0);
21017c478bd9Sstevel@tonic-gate }
21027c478bd9Sstevel@tonic-gate 
21037c478bd9Sstevel@tonic-gate /*
21047c478bd9Sstevel@tonic-gate  * Get properties from old VPD
21057c478bd9Sstevel@tonic-gate  * for PCI cards
21067c478bd9Sstevel@tonic-gate  */
21077c478bd9Sstevel@tonic-gate static int
21087c478bd9Sstevel@tonic-gate hme_get_oldvpd_props(dev_info_t *dip, int vpd_base)
21097c478bd9Sstevel@tonic-gate {
21107c478bd9Sstevel@tonic-gate 	struct hme *hmep;
21117c478bd9Sstevel@tonic-gate 	int vpd_start, vpd_len, kw_start, kw_len, kw_ptr;
21127c478bd9Sstevel@tonic-gate 	char kw_namestr[3];
21137c478bd9Sstevel@tonic-gate 	char kw_fieldstr[256];
21147c478bd9Sstevel@tonic-gate 	int i;
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate 	hmep = ddi_get_driver_private(dip);
21177c478bd9Sstevel@tonic-gate 
21187c478bd9Sstevel@tonic-gate 	vpd_start = vpd_base;
21197c478bd9Sstevel@tonic-gate 
21207c478bd9Sstevel@tonic-gate 	if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) {
21217c478bd9Sstevel@tonic-gate 		return (1); /* error */
21227c478bd9Sstevel@tonic-gate 	} else {
21237c478bd9Sstevel@tonic-gate 		vpd_len = 9;
21247c478bd9Sstevel@tonic-gate 	}
21257c478bd9Sstevel@tonic-gate 
21267c478bd9Sstevel@tonic-gate 	/* Get local-mac-address */
21277c478bd9Sstevel@tonic-gate 	kw_start = vpd_start + 3; /* Location of 1st keyword */
21287c478bd9Sstevel@tonic-gate 	kw_ptr = kw_start;
21297c478bd9Sstevel@tonic-gate 	while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */
21307c478bd9Sstevel@tonic-gate 		kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]);
21317c478bd9Sstevel@tonic-gate 		kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]);
21327c478bd9Sstevel@tonic-gate 		kw_namestr[2] = '\0';
21337c478bd9Sstevel@tonic-gate 		kw_len = (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff);
21347c478bd9Sstevel@tonic-gate 		for (i = 0, kw_ptr += 3; i < kw_len; i++)
21357c478bd9Sstevel@tonic-gate 			kw_fieldstr[i] = GET_ROM8(&hmep->hme_romp[kw_ptr+i]);
21367c478bd9Sstevel@tonic-gate 		kw_fieldstr[i] = '\0';
21377c478bd9Sstevel@tonic-gate 		if (hme_create_prop_from_kw(dip, kw_namestr, kw_fieldstr)) {
21387c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
21397c478bd9Sstevel@tonic-gate 		}
21407c478bd9Sstevel@tonic-gate 		kw_ptr += kw_len;
21417c478bd9Sstevel@tonic-gate 	} /* next keyword */
21427c478bd9Sstevel@tonic-gate 
214385025c03Sgd 	if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP, "model",
214485025c03Sgd 	    "SUNW,cheerio", strlen("SUNW,cheerio")+1) != DDI_SUCCESS) {
21457c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
21467c478bd9Sstevel@tonic-gate 	}
21477c478bd9Sstevel@tonic-gate 	return (0);
21487c478bd9Sstevel@tonic-gate }
21497c478bd9Sstevel@tonic-gate 
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate /*
21527c478bd9Sstevel@tonic-gate  * Get properties from new VPD
21537c478bd9Sstevel@tonic-gate  * for CompactPCI cards
21547c478bd9Sstevel@tonic-gate  */
21557c478bd9Sstevel@tonic-gate static int
21567c478bd9Sstevel@tonic-gate hme_get_newvpd_props(dev_info_t *dip, int vpd_base)
21577c478bd9Sstevel@tonic-gate {
21587c478bd9Sstevel@tonic-gate 	struct hme *hmep;
21597c478bd9Sstevel@tonic-gate 	int vpd_start, vpd_len, kw_start, kw_len, kw_ptr;
21607c478bd9Sstevel@tonic-gate 	char kw_namestr[3];
21617c478bd9Sstevel@tonic-gate 	char kw_fieldstr[256];
21627c478bd9Sstevel@tonic-gate 	int maxvpdsize, i;
21637c478bd9Sstevel@tonic-gate 
21647c478bd9Sstevel@tonic-gate 	hmep = ddi_get_driver_private(dip);
21657c478bd9Sstevel@tonic-gate 
21667c478bd9Sstevel@tonic-gate 	maxvpdsize = 1024; /* Real size not known until after it is read */
21677c478bd9Sstevel@tonic-gate 
21687c478bd9Sstevel@tonic-gate 	vpd_start = (int)((GET_ROM8(&(hmep->hme_romp[vpd_base+1])) & 0xff) |
216985025c03Sgd 	    ((GET_ROM8(&hmep->hme_romp[vpd_base+2]) & 0xff) << 8)) +3;
21707c478bd9Sstevel@tonic-gate 	vpd_start = vpd_base + vpd_start;
21717c478bd9Sstevel@tonic-gate 	while (vpd_start < (vpd_base + maxvpdsize)) { /* Get all VPDs */
21727c478bd9Sstevel@tonic-gate 		if ((GET_ROM8(&hmep->hme_romp[vpd_start]) & 0xff) != 0x90) {
21737c478bd9Sstevel@tonic-gate 			break; /* no VPD found */
21747c478bd9Sstevel@tonic-gate 		} else {
21757c478bd9Sstevel@tonic-gate 			vpd_len = (int)((GET_ROM8(&hmep->hme_romp[vpd_start
217685025c03Sgd 			    + 1]) & 0xff) | (GET_ROM8(&hmep->hme_romp[vpd_start
217785025c03Sgd 			    + 2]) & 0xff) << 8);
21787c478bd9Sstevel@tonic-gate 		}
21797c478bd9Sstevel@tonic-gate 		/* Get all keywords in this VPD */
21807c478bd9Sstevel@tonic-gate 		kw_start = vpd_start + 3; /* Location of 1st keyword */
21817c478bd9Sstevel@tonic-gate 		kw_ptr = kw_start;
21827c478bd9Sstevel@tonic-gate 		while ((kw_ptr - kw_start) < vpd_len) { /* Get all keywords */
21837c478bd9Sstevel@tonic-gate 			kw_namestr[0] = GET_ROM8(&hmep->hme_romp[kw_ptr]);
21847c478bd9Sstevel@tonic-gate 			kw_namestr[1] = GET_ROM8(&hmep->hme_romp[kw_ptr+1]);
21857c478bd9Sstevel@tonic-gate 			kw_namestr[2] = '\0';
218685025c03Sgd 			kw_len =
218785025c03Sgd 			    (int)(GET_ROM8(&hmep->hme_romp[kw_ptr+2]) & 0xff);
21887c478bd9Sstevel@tonic-gate 			for (i = 0, kw_ptr += 3; i < kw_len; i++)
218985025c03Sgd 				kw_fieldstr[i] =
219085025c03Sgd 				    GET_ROM8(&hmep->hme_romp[kw_ptr+i]);
21917c478bd9Sstevel@tonic-gate 			kw_fieldstr[i] = '\0';
21927c478bd9Sstevel@tonic-gate 			if (hme_create_prop_from_kw(dip, kw_namestr,
219385025c03Sgd 			    kw_fieldstr)) {
21947c478bd9Sstevel@tonic-gate 				return (DDI_FAILURE);
21957c478bd9Sstevel@tonic-gate 			}
21967c478bd9Sstevel@tonic-gate 			kw_ptr += kw_len;
21977c478bd9Sstevel@tonic-gate 		} /* next keyword */
21987c478bd9Sstevel@tonic-gate 		vpd_start += (vpd_len + 3);
21997c478bd9Sstevel@tonic-gate 	} /* next VPD */
22007c478bd9Sstevel@tonic-gate 	return (0);
22017c478bd9Sstevel@tonic-gate }
22027c478bd9Sstevel@tonic-gate 
22037c478bd9Sstevel@tonic-gate 
22047c478bd9Sstevel@tonic-gate /*
22057c478bd9Sstevel@tonic-gate  * Get properties from VPD
22067c478bd9Sstevel@tonic-gate  */
22077c478bd9Sstevel@tonic-gate static int
22087c478bd9Sstevel@tonic-gate hme_get_vpd_props(dev_info_t *dip)
22097c478bd9Sstevel@tonic-gate {
22107c478bd9Sstevel@tonic-gate 	struct hme *hmep;
22117c478bd9Sstevel@tonic-gate 	int v0, v1, vpd_base;
22127c478bd9Sstevel@tonic-gate 	int i, epromsrchlimit;
22137c478bd9Sstevel@tonic-gate 
22147c478bd9Sstevel@tonic-gate 
22157c478bd9Sstevel@tonic-gate 	hmep = ddi_get_driver_private(dip);
22167c478bd9Sstevel@tonic-gate 
22177c478bd9Sstevel@tonic-gate 	v0 = (int)(GET_ROM8(&(hmep->hme_romp[0])));
22187c478bd9Sstevel@tonic-gate 	v1 = (int)(GET_ROM8(&(hmep->hme_romp[1])));
22197c478bd9Sstevel@tonic-gate 	v0 = ((v0 & 0xff) << 8 | v1);
22207c478bd9Sstevel@tonic-gate 
22217c478bd9Sstevel@tonic-gate 	if ((v0 & 0xffff) != 0x55aa) {
22227c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, " Valid pci prom not found \n");
22237c478bd9Sstevel@tonic-gate 		return (1);
22247c478bd9Sstevel@tonic-gate 	}
22257c478bd9Sstevel@tonic-gate 
22267c478bd9Sstevel@tonic-gate 	epromsrchlimit = 4096;
22277c478bd9Sstevel@tonic-gate 	for (i = 2; i < epromsrchlimit; i++) {
222885025c03Sgd 		/* "PCIR" */
222985025c03Sgd 		if (((GET_ROM8(&(hmep->hme_romp[i])) & 0xff) == 'P') &&
223085025c03Sgd 		    ((GET_ROM8(&(hmep->hme_romp[i+1])) & 0xff) == 'C') &&
223185025c03Sgd 		    ((GET_ROM8(&(hmep->hme_romp[i+2])) & 0xff) == 'I') &&
223285025c03Sgd 		    ((GET_ROM8(&(hmep->hme_romp[i+3])) & 0xff) == 'R')) {
223385025c03Sgd 			vpd_base =
223485025c03Sgd 			    (int)((GET_ROM8(&(hmep->hme_romp[i+8])) & 0xff) |
223585025c03Sgd 			    (GET_ROM8(&(hmep->hme_romp[i+9])) & 0xff) << 8);
22367c478bd9Sstevel@tonic-gate 			break; /* VPD pointer found */
22377c478bd9Sstevel@tonic-gate 		}
22387c478bd9Sstevel@tonic-gate 	}
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate 	/* No VPD found */
22417c478bd9Sstevel@tonic-gate 	if (vpd_base == 0) {
22427c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, " Vital Product Data pointer not found \n");
22437c478bd9Sstevel@tonic-gate 		return (1);
22447c478bd9Sstevel@tonic-gate 	}
22457c478bd9Sstevel@tonic-gate 
22467c478bd9Sstevel@tonic-gate 	v0 = (int)(GET_ROM8(&(hmep->hme_romp[vpd_base])));
22477c478bd9Sstevel@tonic-gate 	if (v0 == 0x82) {
22487c478bd9Sstevel@tonic-gate 		if (hme_get_newvpd_props(dip, vpd_base))
22497c478bd9Sstevel@tonic-gate 			return (1);
22507c478bd9Sstevel@tonic-gate 		return (0);
22517c478bd9Sstevel@tonic-gate 	} else if (v0 == 0x90) {
2252*0219346bSGarrett D'Amore 		/* If we are are SUNW,qfe card, look for the Nth "NA" descr */
2253*0219346bSGarrett D'Amore 		if ((GET_ROM8(&hmep->hme_romp[vpd_base + 12])  != 0x79) &&
2254*0219346bSGarrett D'Amore 		    GET_ROM8(&hmep->hme_romp[vpd_base + 4 * 12]) == 0x79) {
2255*0219346bSGarrett D'Amore 			vpd_base += hmep->hme_devno * 12;
2256*0219346bSGarrett D'Amore 		}
22577c478bd9Sstevel@tonic-gate 		if (hme_get_oldvpd_props(dip, vpd_base))
22587c478bd9Sstevel@tonic-gate 			return (1);
22597c478bd9Sstevel@tonic-gate 		return (0);
22607c478bd9Sstevel@tonic-gate 	} else
22617c478bd9Sstevel@tonic-gate 		return (1);	/* unknown start byte in VPD */
22627c478bd9Sstevel@tonic-gate }
22637c478bd9Sstevel@tonic-gate 
2264*0219346bSGarrett D'Amore /*
2265*0219346bSGarrett D'Amore  * For x86, the BIOS doesn't map the PCI Rom register for the qfe
2266*0219346bSGarrett D'Amore  * cards, so we have to extract it from the ebus bridge that is
2267*0219346bSGarrett D'Amore  * function zero of the same device.  This is a bit of an ugly hack.
2268*0219346bSGarrett D'Amore  * (The ebus bridge leaves the entire ROM mapped at base address
2269*0219346bSGarrett D'Amore  * register 0x10.)
2270*0219346bSGarrett D'Amore  */
2271*0219346bSGarrett D'Amore 
2272*0219346bSGarrett D'Amore typedef struct {
2273*0219346bSGarrett D'Amore 	struct hme 		*hmep;
2274*0219346bSGarrett D'Amore 	dev_info_t		*parent;
2275*0219346bSGarrett D'Amore 	uint8_t			bus, dev;
2276*0219346bSGarrett D'Amore 	ddi_acc_handle_t	acch;
2277*0219346bSGarrett D'Amore 	caddr_t			romp;
2278*0219346bSGarrett D'Amore } ebus_rom_t;
2279*0219346bSGarrett D'Amore 
2280*0219346bSGarrett D'Amore static int
2281*0219346bSGarrett D'Amore hme_mapebusrom(dev_info_t *dip, void *arg)
2282*0219346bSGarrett D'Amore {
2283*0219346bSGarrett D'Amore 	int		*regs;
2284*0219346bSGarrett D'Amore 	unsigned	nregs;
2285*0219346bSGarrett D'Amore 	int		reg;
2286*0219346bSGarrett D'Amore 	ebus_rom_t	*rom = arg;
2287*0219346bSGarrett D'Amore 	struct hme	*hmep = rom->hmep;
2288*0219346bSGarrett D'Amore 
2289*0219346bSGarrett D'Amore 	/*
2290*0219346bSGarrett D'Amore 	 * We only want to look at our peers.  Skip our parent.
2291*0219346bSGarrett D'Amore 	 */
2292*0219346bSGarrett D'Amore 	if (dip == rom->parent) {
2293*0219346bSGarrett D'Amore 		return (DDI_WALK_PRUNESIB);
2294*0219346bSGarrett D'Amore 	}
2295*0219346bSGarrett D'Amore 
2296*0219346bSGarrett D'Amore 	if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0,
2297*0219346bSGarrett D'Amore 	    "reg", &regs, &nregs)) != DDI_PROP_SUCCESS) {
2298*0219346bSGarrett D'Amore 		return (DDI_WALK_PRUNECHILD);
2299*0219346bSGarrett D'Amore 	}
2300*0219346bSGarrett D'Amore 
2301*0219346bSGarrett D'Amore 	if (nregs < 1) {
2302*0219346bSGarrett D'Amore 		ddi_prop_free(regs);
2303*0219346bSGarrett D'Amore 		return (DDI_WALK_PRUNECHILD);
2304*0219346bSGarrett D'Amore 	}
2305*0219346bSGarrett D'Amore 	reg = regs[0];
2306*0219346bSGarrett D'Amore 	ddi_prop_free(regs);
2307*0219346bSGarrett D'Amore 
2308*0219346bSGarrett D'Amore 	/*
2309*0219346bSGarrett D'Amore 	 * Look for function 0 on our bus and device.  If the device doesn't
2310*0219346bSGarrett D'Amore 	 * match, it might be an alternate peer, in which case we don't want
2311*0219346bSGarrett D'Amore 	 * to examine any of its children.
2312*0219346bSGarrett D'Amore 	 */
2313*0219346bSGarrett D'Amore 	if ((PCI_REG_BUS_G(reg) != rom->bus) ||
2314*0219346bSGarrett D'Amore 	    (PCI_REG_DEV_G(reg) != rom->dev) ||
2315*0219346bSGarrett D'Amore 	    (PCI_REG_FUNC_G(reg) != 0)) {
2316*0219346bSGarrett D'Amore 		return (DDI_WALK_PRUNECHILD);
2317*0219346bSGarrett D'Amore 	}
2318*0219346bSGarrett D'Amore 
2319*0219346bSGarrett D'Amore 	(void) ddi_regs_map_setup(dip, 1, &rom->romp, 0, 0, &hmep->hme_dev_attr,
2320*0219346bSGarrett D'Amore 	    &rom->acch);
2321*0219346bSGarrett D'Amore 	/*
2322*0219346bSGarrett D'Amore 	 * If we can't map the registers, the caller will notice that
2323*0219346bSGarrett D'Amore 	 * the acch is NULL.
2324*0219346bSGarrett D'Amore 	 */
2325*0219346bSGarrett D'Amore 	return (DDI_WALK_TERMINATE);
2326*0219346bSGarrett D'Amore }
2327*0219346bSGarrett D'Amore 
2328*0219346bSGarrett D'Amore static int
2329*0219346bSGarrett D'Amore hmeget_promebus(dev_info_t *dip)
2330*0219346bSGarrett D'Amore {
2331*0219346bSGarrett D'Amore 	ebus_rom_t	rom;
2332*0219346bSGarrett D'Amore 	int		*regs;
2333*0219346bSGarrett D'Amore 	unsigned	nregs;
2334*0219346bSGarrett D'Amore 	struct hme	*hmep;
2335*0219346bSGarrett D'Amore 
2336*0219346bSGarrett D'Amore 	hmep = ddi_get_driver_private(dip);
2337*0219346bSGarrett D'Amore 
2338*0219346bSGarrett D'Amore 	bzero(&rom, sizeof (rom));
2339*0219346bSGarrett D'Amore 
2340*0219346bSGarrett D'Amore 	/*
2341*0219346bSGarrett D'Amore 	 * For x86, the BIOS doesn't map the PCI Rom register for the qfe
2342*0219346bSGarrett D'Amore 	 * cards, so we have to extract it from the eBus bridge that is
2343*0219346bSGarrett D'Amore 	 * function zero.  This is a bit of an ugly hack.
2344*0219346bSGarrett D'Amore 	 */
2345*0219346bSGarrett D'Amore 	if ((ddi_prop_lookup_int_array(DDI_DEV_T_ANY, dip, 0,
2346*0219346bSGarrett D'Amore 	    "reg", &regs, &nregs)) != DDI_PROP_SUCCESS) {
2347*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
2348*0219346bSGarrett D'Amore 	}
2349*0219346bSGarrett D'Amore 
2350*0219346bSGarrett D'Amore 	if (nregs < 5) {
2351*0219346bSGarrett D'Amore 		ddi_prop_free(regs);
2352*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
2353*0219346bSGarrett D'Amore 	}
2354*0219346bSGarrett D'Amore 	rom.hmep = hmep;
2355*0219346bSGarrett D'Amore 	rom.bus = PCI_REG_BUS_G(regs[0]);
2356*0219346bSGarrett D'Amore 	rom.dev = PCI_REG_DEV_G(regs[0]);
2357*0219346bSGarrett D'Amore 	hmep->hme_devno = rom.dev;
2358*0219346bSGarrett D'Amore 	rom.parent = ddi_get_parent(dip);
2359*0219346bSGarrett D'Amore 
2360*0219346bSGarrett D'Amore 	/*
2361*0219346bSGarrett D'Amore 	 * The implementation of ddi_walk_devs says that we must not
2362*0219346bSGarrett D'Amore 	 * be called during autoconfiguration.  However, upon close
2363*0219346bSGarrett D'Amore 	 * examination, one will find the following is true:
2364*0219346bSGarrett D'Amore 	 *
2365*0219346bSGarrett D'Amore 	 * 1) since we're called at attach time,
2366*0219346bSGarrett D'Amore 	 *    DEVI_BUSY_OWNED(ddi_get_parent(dip)) is implicitly true.
2367*0219346bSGarrett D'Amore 	 *
2368*0219346bSGarrett D'Amore 	 * 2) we carefully ensure that we prune siblings for all cases
2369*0219346bSGarrett D'Amore 	 *    except our own device, so we can't wind up walking down
2370*0219346bSGarrett D'Amore 	 *    a changing sibling pointer.
2371*0219346bSGarrett D'Amore 	 *
2372*0219346bSGarrett D'Amore 	 * 3) since we are attaching, our peers will already have their
2373*0219346bSGarrett D'Amore 	 *    dev_info nodes on the tree... hence our own sibling pointer
2374*0219346bSGarrett D'Amore 	 *    (and those of our siblings) will be stable.
2375*0219346bSGarrett D'Amore 	 *
2376*0219346bSGarrett D'Amore 	 * 4) also, because of #3, our parents child pointer will be
2377*0219346bSGarrett D'Amore 	 *    stable.
2378*0219346bSGarrett D'Amore 	 *
2379*0219346bSGarrett D'Amore 	 * So it should be safe to do this, because of our carefully
2380*0219346bSGarrett D'Amore 	 * constructed restrictions.
2381*0219346bSGarrett D'Amore 	 */
2382*0219346bSGarrett D'Amore 	ddi_walk_devs(ddi_get_parent(dip), hme_mapebusrom, &rom);
2383*0219346bSGarrett D'Amore 
2384*0219346bSGarrett D'Amore 	if (rom.acch) {
2385*0219346bSGarrett D'Amore 		hmep->hme_romh = rom.acch;
2386*0219346bSGarrett D'Amore 		hmep->hme_romp = (unsigned char *)rom.romp;
2387*0219346bSGarrett D'Amore 		return (DDI_SUCCESS);
2388*0219346bSGarrett D'Amore 	}
2389*0219346bSGarrett D'Amore 	return (DDI_FAILURE);
2390*0219346bSGarrett D'Amore }
2391*0219346bSGarrett D'Amore 
23927c478bd9Sstevel@tonic-gate static int
23937c478bd9Sstevel@tonic-gate hmeget_promprops(dev_info_t *dip)
23947c478bd9Sstevel@tonic-gate {
23957c478bd9Sstevel@tonic-gate 	struct hme *hmep;
23967c478bd9Sstevel@tonic-gate 	int rom_bar;
23977c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t cfg_handle;
23987c478bd9Sstevel@tonic-gate 	struct {
23997c478bd9Sstevel@tonic-gate 		uint16_t vendorid;
24007c478bd9Sstevel@tonic-gate 		uint16_t devid;
24017c478bd9Sstevel@tonic-gate 		uint16_t command;
24027c478bd9Sstevel@tonic-gate 		uint16_t status;
24037c478bd9Sstevel@tonic-gate 		uint32_t junk1;
24047c478bd9Sstevel@tonic-gate 		uint8_t cache_line;
24057c478bd9Sstevel@tonic-gate 		uint8_t latency;
24067c478bd9Sstevel@tonic-gate 		uint8_t header;
24077c478bd9Sstevel@tonic-gate 		uint8_t bist;
24087c478bd9Sstevel@tonic-gate 		uint32_t base;
24097c478bd9Sstevel@tonic-gate 		uint32_t base14;
24107c478bd9Sstevel@tonic-gate 		uint32_t base18;
24117c478bd9Sstevel@tonic-gate 		uint32_t base1c;
24127c478bd9Sstevel@tonic-gate 		uint32_t base20;
24137c478bd9Sstevel@tonic-gate 		uint32_t base24;
24147c478bd9Sstevel@tonic-gate 		uint32_t base28;
24157c478bd9Sstevel@tonic-gate 		uint32_t base2c;
24167c478bd9Sstevel@tonic-gate 		uint32_t base30;
24177c478bd9Sstevel@tonic-gate 	} *cfg_ptr;
24187c478bd9Sstevel@tonic-gate 
24197c478bd9Sstevel@tonic-gate 	hmep = ddi_get_driver_private(dip);
24207c478bd9Sstevel@tonic-gate 
24217c478bd9Sstevel@tonic-gate 
24227c478bd9Sstevel@tonic-gate 	/*
24237c478bd9Sstevel@tonic-gate 	 * map configuration space
24247c478bd9Sstevel@tonic-gate 	 */
24257c478bd9Sstevel@tonic-gate 	if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr,
242685025c03Sgd 	    0, 0, &hmep->hme_dev_attr, &cfg_handle)) {
24277c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
24287c478bd9Sstevel@tonic-gate 	}
24297c478bd9Sstevel@tonic-gate 
24307c478bd9Sstevel@tonic-gate 	/*
24317c478bd9Sstevel@tonic-gate 	 * Enable bus-master and memory accesses
24327c478bd9Sstevel@tonic-gate 	 */
24337c478bd9Sstevel@tonic-gate 	ddi_put16(cfg_handle, &cfg_ptr->command,
243485025c03Sgd 	    PCI_COMM_SERR_ENABLE | PCI_COMM_PARITY_DETECT |
243585025c03Sgd 	    PCI_COMM_MAE | PCI_COMM_ME);
24367c478bd9Sstevel@tonic-gate 
24377c478bd9Sstevel@tonic-gate 	/*
24387c478bd9Sstevel@tonic-gate 	 * Enable rom accesses
24397c478bd9Sstevel@tonic-gate 	 */
24407c478bd9Sstevel@tonic-gate 	rom_bar = ddi_get32(cfg_handle, &cfg_ptr->base30);
24417c478bd9Sstevel@tonic-gate 	ddi_put32(cfg_handle, &cfg_ptr->base30, rom_bar | 1);
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 
2444*0219346bSGarrett D'Amore 	if ((ddi_regs_map_setup(dip, 2, (caddr_t *)&(hmep->hme_romp), 0, 0,
2445*0219346bSGarrett D'Amore 	    &hmep->hme_dev_attr, &hmep->hme_romh) != DDI_SUCCESS) &&
2446*0219346bSGarrett D'Amore 	    (hmeget_promebus(dip) != DDI_SUCCESS)) {
2447*0219346bSGarrett D'Amore 
24487c478bd9Sstevel@tonic-gate 		if (cfg_ptr)
24497c478bd9Sstevel@tonic-gate 			ddi_regs_map_free(&cfg_handle);
24507c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
24517c478bd9Sstevel@tonic-gate 	} else {
24527c478bd9Sstevel@tonic-gate 		if (hme_get_vpd_props(dip))
2453*0219346bSGarrett D'Amore 			return (DDI_FAILURE);
24547c478bd9Sstevel@tonic-gate 	}
24557c478bd9Sstevel@tonic-gate 	if (hmep->hme_romp)
24567c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&hmep->hme_romh);
24577c478bd9Sstevel@tonic-gate 	if (cfg_ptr)
24587c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&cfg_handle);
2459*0219346bSGarrett D'Amore 	return (DDI_SUCCESS);
24607c478bd9Sstevel@tonic-gate 
24617c478bd9Sstevel@tonic-gate }
24627c478bd9Sstevel@tonic-gate 
24637c478bd9Sstevel@tonic-gate static void
24647c478bd9Sstevel@tonic-gate hmeget_hm_rev_property(struct hme *hmep)
24657c478bd9Sstevel@tonic-gate {
24667c478bd9Sstevel@tonic-gate 	int	hm_rev;
24677c478bd9Sstevel@tonic-gate 
24687c478bd9Sstevel@tonic-gate 
24697c478bd9Sstevel@tonic-gate 	hm_rev = hmep->asic_rev;
24707c478bd9Sstevel@tonic-gate 	switch (hm_rev) {
24717c478bd9Sstevel@tonic-gate 	case HME_2P1_REVID:
24727c478bd9Sstevel@tonic-gate 	case HME_2P1_REVID_OBP:
24737c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
247485025c03Sgd 		    "SBus 2.1 Found (Rev Id = %x)", hm_rev);
24757c478bd9Sstevel@tonic-gate 		hmep->hme_mifpoll_enable = 1;
24767c478bd9Sstevel@tonic-gate 		hmep->hme_frame_enable = 1;
24777c478bd9Sstevel@tonic-gate 		break;
24787c478bd9Sstevel@tonic-gate 
24797c478bd9Sstevel@tonic-gate 	case HME_2P0_REVID:
24807c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
248185025c03Sgd 		    "SBus 2.0 Found (Rev Id = %x)", hm_rev);
24827c478bd9Sstevel@tonic-gate 		break;
24837c478bd9Sstevel@tonic-gate 
24847c478bd9Sstevel@tonic-gate 	case HME_1C0_REVID:
24857c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
248685025c03Sgd 		    "PCI IO 1.0 Found (Rev Id = %x)", hm_rev);
24877c478bd9Sstevel@tonic-gate 		break;
24887c478bd9Sstevel@tonic-gate 
24897c478bd9Sstevel@tonic-gate 	default:
24907c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG3(hmep, SEVERITY_HIGH, DISPLAY_MSG,
249185025c03Sgd 		    "%s (Rev Id = %x) Found",
249285025c03Sgd 		    (hm_rev == HME_2C0_REVID) ? "PCI IO 2.0" : "Sbus", hm_rev);
24937c478bd9Sstevel@tonic-gate 		hmep->hme_mifpoll_enable = 1;
24947c478bd9Sstevel@tonic-gate 		hmep->hme_frame_enable = 1;
24957c478bd9Sstevel@tonic-gate 		hmep->hme_lance_mode_enable = 1;
24967c478bd9Sstevel@tonic-gate 		hmep->hme_rxcv_enable = 1;
24977c478bd9Sstevel@tonic-gate 		break;
24987c478bd9Sstevel@tonic-gate 	}
24997c478bd9Sstevel@tonic-gate }
25007c478bd9Sstevel@tonic-gate 
25017c478bd9Sstevel@tonic-gate /*
25027c478bd9Sstevel@tonic-gate  * Interface exists: make available by filling in network interface
25037c478bd9Sstevel@tonic-gate  * record.  System will initialize the interface when it is ready
25047c478bd9Sstevel@tonic-gate  * to accept packets.
25057c478bd9Sstevel@tonic-gate  */
2506f2cd0f02Sgd int
25077c478bd9Sstevel@tonic-gate hmeattach(dev_info_t *dip, ddi_attach_cmd_t cmd)
25087c478bd9Sstevel@tonic-gate {
25097c478bd9Sstevel@tonic-gate 	struct hme *hmep;
251085025c03Sgd 	mac_register_t *macp = NULL;
25117c478bd9Sstevel@tonic-gate 	int 	regno;
25127c478bd9Sstevel@tonic-gate 	int hm_rev = 0;
25137c478bd9Sstevel@tonic-gate 	int prop_len = sizeof (int);
25147c478bd9Sstevel@tonic-gate 	ddi_acc_handle_t cfg_handle;
25157c478bd9Sstevel@tonic-gate 	struct {
25167c478bd9Sstevel@tonic-gate 		uint16_t vendorid;
25177c478bd9Sstevel@tonic-gate 		uint16_t devid;
25187c478bd9Sstevel@tonic-gate 		uint16_t command;
25197c478bd9Sstevel@tonic-gate 		uint16_t status;
25207c478bd9Sstevel@tonic-gate 		uint8_t revid;
25217c478bd9Sstevel@tonic-gate 		uint8_t j1;
25227c478bd9Sstevel@tonic-gate 		uint16_t j2;
25237c478bd9Sstevel@tonic-gate 	} *cfg_ptr;
25247c478bd9Sstevel@tonic-gate 
25257c478bd9Sstevel@tonic-gate 	switch (cmd) {
25267c478bd9Sstevel@tonic-gate 	case DDI_ATTACH:
25277c478bd9Sstevel@tonic-gate 		break;
25287c478bd9Sstevel@tonic-gate 
25297c478bd9Sstevel@tonic-gate 	case DDI_RESUME:
25307c478bd9Sstevel@tonic-gate 		if ((hmep = ddi_get_driver_private(dip)) == NULL)
253185025c03Sgd 			return (DDI_FAILURE);
25327c478bd9Sstevel@tonic-gate 
25337c478bd9Sstevel@tonic-gate 		hmep->hme_flags &= ~HMESUSPENDED;
25347c478bd9Sstevel@tonic-gate 		hmep->hme_linkcheck = 0;
253585025c03Sgd 
2536228fdff0Sgd 		if (hmep->hme_started)
253785025c03Sgd 			(void) hmeinit(hmep);
25387c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
25397c478bd9Sstevel@tonic-gate 
25407c478bd9Sstevel@tonic-gate 	default:
25417c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
25427c478bd9Sstevel@tonic-gate 	}
25437c478bd9Sstevel@tonic-gate 
25447c478bd9Sstevel@tonic-gate 	/*
25457c478bd9Sstevel@tonic-gate 	 * Allocate soft device data structure
25467c478bd9Sstevel@tonic-gate 	 */
2547*0219346bSGarrett D'Amore 	hmep = kmem_zalloc(sizeof (*hmep), KM_SLEEP);
25487c478bd9Sstevel@tonic-gate 
25497c478bd9Sstevel@tonic-gate 	/*
25507c478bd9Sstevel@tonic-gate 	 * Might as well set up elements of data structure
25517c478bd9Sstevel@tonic-gate 	 */
25527c478bd9Sstevel@tonic-gate 	hmep->dip =		dip;
25537c478bd9Sstevel@tonic-gate 	hmep->instance = 	ddi_get_instance(dip);
25547c478bd9Sstevel@tonic-gate 	hmep->pagesize =	ddi_ptob(dip, (ulong_t)1); /* IOMMU PSize */
25557c478bd9Sstevel@tonic-gate 
25567c478bd9Sstevel@tonic-gate 	/*
25577c478bd9Sstevel@tonic-gate 	 *  Might as well setup the driver private
25587c478bd9Sstevel@tonic-gate 	 * structure as part of the dip.
25597c478bd9Sstevel@tonic-gate 	 */
25607c478bd9Sstevel@tonic-gate 	ddi_set_driver_private(dip, hmep);
25617c478bd9Sstevel@tonic-gate 
25627c478bd9Sstevel@tonic-gate 	/*
25637c478bd9Sstevel@tonic-gate 	 * Reject this device if it's in a slave-only slot.
25647c478bd9Sstevel@tonic-gate 	 */
25657c478bd9Sstevel@tonic-gate 	if (ddi_slaveonly(dip) == DDI_SUCCESS) {
25667c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
2567*0219346bSGarrett D'Amore 		    "Dev not used - dev in slave only slot");
25687c478bd9Sstevel@tonic-gate 		goto error_state;
25697c478bd9Sstevel@tonic-gate 	}
25707c478bd9Sstevel@tonic-gate 
25717c478bd9Sstevel@tonic-gate 	/*
25727c478bd9Sstevel@tonic-gate 	 * Map in the device registers.
25737c478bd9Sstevel@tonic-gate 	 *
25747c478bd9Sstevel@tonic-gate 	 * Reg # 0 is the Global register set
25757c478bd9Sstevel@tonic-gate 	 * Reg # 1 is the ETX register set
25767c478bd9Sstevel@tonic-gate 	 * Reg # 2 is the ERX register set
25777c478bd9Sstevel@tonic-gate 	 * Reg # 3 is the BigMAC register set.
25787c478bd9Sstevel@tonic-gate 	 * Reg # 4 is the MIF register set
25797c478bd9Sstevel@tonic-gate 	 */
25807c478bd9Sstevel@tonic-gate 	if (ddi_dev_nregs(dip, &regno) != (DDI_SUCCESS)) {
25817c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG2(hmep, SEVERITY_HIGH, INIT_MSG,
258285025c03Sgd 		    ddi_nregs_fail_msg, regno);
25837c478bd9Sstevel@tonic-gate 		goto error_state;
25847c478bd9Sstevel@tonic-gate 	}
25857c478bd9Sstevel@tonic-gate 
25867c478bd9Sstevel@tonic-gate 	switch (regno) {
25877c478bd9Sstevel@tonic-gate 	case 5:
25887c478bd9Sstevel@tonic-gate 		hmep->hme_cheerio_mode = 0;
25897c478bd9Sstevel@tonic-gate 		break;
25907c478bd9Sstevel@tonic-gate 	case 2:
25917c478bd9Sstevel@tonic-gate 	case 3: /* for hot swap/plug, there will be 3 entries in "reg" prop */
25927c478bd9Sstevel@tonic-gate 		hmep->hme_cheerio_mode = 1;
25937c478bd9Sstevel@tonic-gate 		break;
25947c478bd9Sstevel@tonic-gate 	default:
259585025c03Sgd 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
259685025c03Sgd 		    bad_num_regs_msg);
25977c478bd9Sstevel@tonic-gate 		goto error_state;
25987c478bd9Sstevel@tonic-gate 	}
25997c478bd9Sstevel@tonic-gate 
26007c478bd9Sstevel@tonic-gate 	/* Initialize device attributes structure */
26017c478bd9Sstevel@tonic-gate 	hmep->hme_dev_attr.devacc_attr_version = DDI_DEVICE_ATTR_V0;
26027c478bd9Sstevel@tonic-gate 
26037c478bd9Sstevel@tonic-gate 	if (hmep->hme_cheerio_mode)
260485025c03Sgd 		hmep->hme_dev_attr.devacc_attr_endian_flags =
260585025c03Sgd 		    DDI_STRUCTURE_LE_ACC;
26067c478bd9Sstevel@tonic-gate 	else
260785025c03Sgd 		hmep->hme_dev_attr.devacc_attr_endian_flags =
260885025c03Sgd 		    DDI_STRUCTURE_BE_ACC;
26097c478bd9Sstevel@tonic-gate 
26107c478bd9Sstevel@tonic-gate 	hmep->hme_dev_attr.devacc_attr_dataorder = DDI_STRICTORDER_ACC;
26117c478bd9Sstevel@tonic-gate 
26127c478bd9Sstevel@tonic-gate 	if (hmep->hme_cheerio_mode) {
26137c478bd9Sstevel@tonic-gate 		uint8_t		oldLT;
26147c478bd9Sstevel@tonic-gate 		uint8_t		newLT = 0;
26157c478bd9Sstevel@tonic-gate 		dev_info_t	*pdip;
26167c478bd9Sstevel@tonic-gate 		const char	*pdrvname;
26177c478bd9Sstevel@tonic-gate 
26187c478bd9Sstevel@tonic-gate 		/*
26197c478bd9Sstevel@tonic-gate 		 * Map the PCI config space
26207c478bd9Sstevel@tonic-gate 		 */
26217c478bd9Sstevel@tonic-gate 		if (pci_config_setup(dip, &hmep->pci_config_handle) !=
262285025c03Sgd 		    DDI_SUCCESS) {
26237c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
262485025c03Sgd 			    "pci_config_setup() failed..");
26257c478bd9Sstevel@tonic-gate 			goto error_state;
26267c478bd9Sstevel@tonic-gate 		}
26277c478bd9Sstevel@tonic-gate 
26287c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 1,
262985025c03Sgd 		    (caddr_t *)&(hmep->hme_globregp), 0, 0,
263085025c03Sgd 		    &hmep->hme_dev_attr, &hmep->hme_globregh)) {
26317c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
263285025c03Sgd 			    mregs_4global_reg_fail_msg);
26337c478bd9Sstevel@tonic-gate 			goto error_unmap;
26347c478bd9Sstevel@tonic-gate 		}
26357c478bd9Sstevel@tonic-gate 		hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
26367c478bd9Sstevel@tonic-gate 		    hmep->hme_mifregh = hmep->hme_globregh;
26377c478bd9Sstevel@tonic-gate 
263885025c03Sgd 		hmep->hme_etxregp =
263985025c03Sgd 		    (void *)(((caddr_t)hmep->hme_globregp) + 0x2000);
264085025c03Sgd 		hmep->hme_erxregp =
264185025c03Sgd 		    (void *)(((caddr_t)hmep->hme_globregp) + 0x4000);
264285025c03Sgd 		hmep->hme_bmacregp =
264385025c03Sgd 		    (void *)(((caddr_t)hmep->hme_globregp) + 0x6000);
264485025c03Sgd 		hmep->hme_mifregp =
264585025c03Sgd 		    (void *)(((caddr_t)hmep->hme_globregp) + 0x7000);
26467c478bd9Sstevel@tonic-gate 
26477c478bd9Sstevel@tonic-gate 		/*
26487c478bd9Sstevel@tonic-gate 		 * Get parent pci bridge info.
26497c478bd9Sstevel@tonic-gate 		 */
26507c478bd9Sstevel@tonic-gate 		pdip = ddi_get_parent(dip);
26517c478bd9Sstevel@tonic-gate 		pdrvname = ddi_driver_name(pdip);
26527c478bd9Sstevel@tonic-gate 
26537c478bd9Sstevel@tonic-gate 		oldLT = pci_config_get8(hmep->pci_config_handle,
265485025c03Sgd 		    PCI_CONF_LATENCY_TIMER);
26557c478bd9Sstevel@tonic-gate 		/*
26567c478bd9Sstevel@tonic-gate 		 * Honor value set in /etc/system
26577c478bd9Sstevel@tonic-gate 		 * "set hme:pci_latency_timer=0xYY"
26587c478bd9Sstevel@tonic-gate 		 */
26597c478bd9Sstevel@tonic-gate 		if (pci_latency_timer)
26607c478bd9Sstevel@tonic-gate 			newLT = pci_latency_timer;
26617c478bd9Sstevel@tonic-gate 		/*
26627c478bd9Sstevel@tonic-gate 		 * Modify LT for simba
26637c478bd9Sstevel@tonic-gate 		 */
26647c478bd9Sstevel@tonic-gate 		else if (strcmp("simba", pdrvname) == 0)
26657c478bd9Sstevel@tonic-gate 			newLT = 0xf0;
26667c478bd9Sstevel@tonic-gate 		/*
26677c478bd9Sstevel@tonic-gate 		 * Ensure minimum cheerio latency timer of 0x50
26687c478bd9Sstevel@tonic-gate 		 * Usually OBP or pci bridge should set this value
26697c478bd9Sstevel@tonic-gate 		 * based on cheerio
26707c478bd9Sstevel@tonic-gate 		 * min_grant * 8(33MHz) = 0x50 = 0xa * 0x8
26717c478bd9Sstevel@tonic-gate 		 * Some system set cheerio LT at 0x40
26727c478bd9Sstevel@tonic-gate 		 */
26737c478bd9Sstevel@tonic-gate 		else if (oldLT < 0x40)
26747c478bd9Sstevel@tonic-gate 			newLT = 0x50;
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 		/*
26777c478bd9Sstevel@tonic-gate 		 * Now program cheerio's pci latency timer with newLT
26787c478bd9Sstevel@tonic-gate 		 */
26797c478bd9Sstevel@tonic-gate 		if (newLT)
26807c478bd9Sstevel@tonic-gate 			pci_config_put8(hmep->pci_config_handle,
268185025c03Sgd 			    PCI_CONF_LATENCY_TIMER, (uchar_t)newLT);
26827c478bd9Sstevel@tonic-gate 	} else { /* Map register sets */
26837c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 0,
268485025c03Sgd 		    (caddr_t *)&(hmep->hme_globregp), 0, 0,
268585025c03Sgd 		    &hmep->hme_dev_attr, &hmep->hme_globregh)) {
26867c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
268785025c03Sgd 			    mregs_4global_reg_fail_msg);
26887c478bd9Sstevel@tonic-gate 			goto error_state;
26897c478bd9Sstevel@tonic-gate 		}
26907c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 1,
269185025c03Sgd 		    (caddr_t *)&(hmep->hme_etxregp), 0, 0,
269285025c03Sgd 		    &hmep->hme_dev_attr, &hmep->hme_etxregh)) {
26937c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
269485025c03Sgd 			    mregs_4etx_reg_fail_msg);
26957c478bd9Sstevel@tonic-gate 			goto error_unmap;
26967c478bd9Sstevel@tonic-gate 		}
26977c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 2,
269885025c03Sgd 		    (caddr_t *)&(hmep->hme_erxregp), 0, 0,
269985025c03Sgd 		    &hmep->hme_dev_attr, &hmep->hme_erxregh)) {
27007c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
270185025c03Sgd 			    mregs_4erx_reg_fail_msg);
27027c478bd9Sstevel@tonic-gate 			goto error_unmap;
27037c478bd9Sstevel@tonic-gate 		}
27047c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 3,
270585025c03Sgd 		    (caddr_t *)&(hmep->hme_bmacregp), 0, 0,
270685025c03Sgd 		    &hmep->hme_dev_attr, &hmep->hme_bmacregh)) {
27077c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
270885025c03Sgd 			    mregs_4bmac_reg_fail_msg);
27097c478bd9Sstevel@tonic-gate 			goto error_unmap;
27107c478bd9Sstevel@tonic-gate 		}
27117c478bd9Sstevel@tonic-gate 
27127c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(dip, 4,
271385025c03Sgd 		    (caddr_t *)&(hmep->hme_mifregp), 0, 0,
271485025c03Sgd 		    &hmep->hme_dev_attr, &hmep->hme_mifregh)) {
27157c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
271685025c03Sgd 			    mregs_4mif_reg_fail_msg);
27177c478bd9Sstevel@tonic-gate 			goto error_unmap;
27187c478bd9Sstevel@tonic-gate 		}
27197c478bd9Sstevel@tonic-gate 	} /* Endif cheerio_mode */
27207c478bd9Sstevel@tonic-gate 
27217c478bd9Sstevel@tonic-gate 	/*
27227c478bd9Sstevel@tonic-gate 	 * Based on the hm-rev, set some capabilities
27237c478bd9Sstevel@tonic-gate 	 * Set up default capabilities for HM 2.0
27247c478bd9Sstevel@tonic-gate 	 */
27257c478bd9Sstevel@tonic-gate 	hmep->hme_mifpoll_enable = 0;
27267c478bd9Sstevel@tonic-gate 	hmep->hme_frame_enable = 0;
27277c478bd9Sstevel@tonic-gate 	hmep->hme_lance_mode_enable = 0;
27287c478bd9Sstevel@tonic-gate 	hmep->hme_rxcv_enable = 0;
27297c478bd9Sstevel@tonic-gate 
27307c478bd9Sstevel@tonic-gate 	/* NEW routine to get the properties */
27317c478bd9Sstevel@tonic-gate 
27327c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, hmep->dip, 0, "hm-rev",
273385025c03Sgd 	    (caddr_t)&hm_rev, &prop_len) == DDI_PROP_SUCCESS) {
27347c478bd9Sstevel@tonic-gate 
27357c478bd9Sstevel@tonic-gate 		hmep->asic_rev = hm_rev;
27367c478bd9Sstevel@tonic-gate 		hmeget_hm_rev_property(hmep);
27377c478bd9Sstevel@tonic-gate 	} else {
27387c478bd9Sstevel@tonic-gate 		/*
27397c478bd9Sstevel@tonic-gate 		 * hm_rev property not found so, this is
27407c478bd9Sstevel@tonic-gate 		 * case of hot insertion of card without interpreting fcode.
27417c478bd9Sstevel@tonic-gate 		 * Get it from revid in config space after mapping it.
27427c478bd9Sstevel@tonic-gate 		 */
27437c478bd9Sstevel@tonic-gate 		if (ddi_regs_map_setup(hmep->dip, 0, (caddr_t *)&cfg_ptr,
274485025c03Sgd 		    0, 0, &hmep->hme_dev_attr, &cfg_handle)) {
27457c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
27467c478bd9Sstevel@tonic-gate 		}
27477c478bd9Sstevel@tonic-gate 		/*
27487c478bd9Sstevel@tonic-gate 		 * Since this is cheerio-based PCI card, we write 0xC in the
27497c478bd9Sstevel@tonic-gate 		 * top 4 bits(4-7) of hm-rev and retain the bottom(0-3) bits
27507c478bd9Sstevel@tonic-gate 		 * for Cheerio version(1.0 or 2.0 = 0xC0 or 0xC1)
27517c478bd9Sstevel@tonic-gate 		 */
27527c478bd9Sstevel@tonic-gate 		hm_rev = ddi_get8(cfg_handle, &cfg_ptr->revid);
27537c478bd9Sstevel@tonic-gate 		hm_rev = HME_1C0_REVID | (hm_rev & HME_REV_VERS_MASK);
27547c478bd9Sstevel@tonic-gate 		hmep->asic_rev = hm_rev;
27557c478bd9Sstevel@tonic-gate 		if (ddi_prop_create(DDI_DEV_T_NONE, dip, DDI_PROP_CANSLEEP,
275685025c03Sgd 		    "hm-rev", (caddr_t)&hm_rev, sizeof (hm_rev)) !=
275785025c03Sgd 		    DDI_SUCCESS) {
27587c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG,
275985025c03Sgd 			    "hmeattach: ddi_prop_create error for hm_rev");
27607c478bd9Sstevel@tonic-gate 		}
27617c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&cfg_handle);
27627c478bd9Sstevel@tonic-gate 
27637c478bd9Sstevel@tonic-gate 		hmeget_hm_rev_property(hmep);
27647c478bd9Sstevel@tonic-gate 
27657c478bd9Sstevel@tonic-gate 		/* get info via VPD */
2766*0219346bSGarrett D'Amore 		if (hmeget_promprops(dip) != DDI_SUCCESS) {
27677c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, AUTOCONFIG_MSG,
276885025c03Sgd 			    "hmeattach: no promprops");
27697c478bd9Sstevel@tonic-gate 		}
27707c478bd9Sstevel@tonic-gate 	}
27717c478bd9Sstevel@tonic-gate 
27727c478bd9Sstevel@tonic-gate 	if (!hme_mifpoll_enable)
27737c478bd9Sstevel@tonic-gate 		hmep->hme_mifpoll_enable = 0;
27747c478bd9Sstevel@tonic-gate 
27757c478bd9Sstevel@tonic-gate 	if (ddi_intr_hilevel(dip, 0)) {
27767c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, NFATAL_ERR_MSG,
277785025c03Sgd 		    " high-level interrupts are not supported");
27787c478bd9Sstevel@tonic-gate 		goto error_unmap;
27797c478bd9Sstevel@tonic-gate 	}
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate 	/*
27827c478bd9Sstevel@tonic-gate 	 * Get intr. block cookie so that mutex locks can be initialized.
27837c478bd9Sstevel@tonic-gate 	 */
27847c478bd9Sstevel@tonic-gate 	if (ddi_get_iblock_cookie(dip, 0, &hmep->hme_cookie) != DDI_SUCCESS)
27857c478bd9Sstevel@tonic-gate 		goto error_unmap;
27867c478bd9Sstevel@tonic-gate 
27877c478bd9Sstevel@tonic-gate 	/*
27887c478bd9Sstevel@tonic-gate 	 * Initialize mutex's for this device.
27897c478bd9Sstevel@tonic-gate 	 */
279085025c03Sgd 	mutex_init(&hmep->hme_xmitlock, NULL, MUTEX_DRIVER, hmep->hme_cookie);
279185025c03Sgd 	mutex_init(&hmep->hme_intrlock, NULL, MUTEX_DRIVER, hmep->hme_cookie);
279285025c03Sgd 	mutex_init(&hmep->hme_linklock, NULL, MUTEX_DRIVER, hmep->hme_cookie);
27937c478bd9Sstevel@tonic-gate 
27947c478bd9Sstevel@tonic-gate 	/*
27957c478bd9Sstevel@tonic-gate 	 * Quiesce the hardware.
27967c478bd9Sstevel@tonic-gate 	 */
27977c478bd9Sstevel@tonic-gate 	(void) hmestop(hmep);
27987c478bd9Sstevel@tonic-gate 
27997c478bd9Sstevel@tonic-gate 	/*
28007c478bd9Sstevel@tonic-gate 	 * Add interrupt to system
28017c478bd9Sstevel@tonic-gate 	 */
28027c478bd9Sstevel@tonic-gate 	if (ddi_add_intr(dip, 0, (ddi_iblock_cookie_t *)NULL,
28037c478bd9Sstevel@tonic-gate 	    (ddi_idevice_cookie_t *)NULL, hmeintr, (caddr_t)hmep)) {
28047c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, CONFIG_MSG,
280585025c03Sgd 		    add_intr_fail_msg);
28067c478bd9Sstevel@tonic-gate 		goto error_mutex;
28077c478bd9Sstevel@tonic-gate 	}
28087c478bd9Sstevel@tonic-gate 
28097c478bd9Sstevel@tonic-gate 	/*
28107c478bd9Sstevel@tonic-gate 	 * Set up the ethernet mac address.
28117c478bd9Sstevel@tonic-gate 	 */
28127c478bd9Sstevel@tonic-gate 	hme_setup_mac_address(hmep, dip);
28137c478bd9Sstevel@tonic-gate 
28147c478bd9Sstevel@tonic-gate 	if (!hmeinit_xfer_params(hmep))
281585025c03Sgd 		goto error_intr;
28167c478bd9Sstevel@tonic-gate 
28177c478bd9Sstevel@tonic-gate 	if (hmeburstsizes(hmep) == DDI_FAILURE) {
28187c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG, burst_size_msg);
281985025c03Sgd 		goto error_intr;
28207c478bd9Sstevel@tonic-gate 	}
28217c478bd9Sstevel@tonic-gate 
2822*0219346bSGarrett D'Amore 	if (hmeallocthings(hmep) != DDI_SUCCESS) {
2823*0219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
2824*0219346bSGarrett D'Amore 		    "resource allocation failed");
2825*0219346bSGarrett D'Amore 		goto error_intr;
2826*0219346bSGarrett D'Amore 	}
2827*0219346bSGarrett D'Amore 
2828*0219346bSGarrett D'Amore 	if (hmeallocbufs(hmep) != DDI_SUCCESS) {
2829*0219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
2830*0219346bSGarrett D'Amore 		    "buffer allocation failed");
2831*0219346bSGarrett D'Amore 		goto error_intr;
2832*0219346bSGarrett D'Amore 	}
28337c478bd9Sstevel@tonic-gate 
28347c478bd9Sstevel@tonic-gate 	hmestatinit(hmep);
283585025c03Sgd 
283685025c03Sgd 	if ((macp = mac_alloc(MAC_VERSION)) == NULL) {
283785025c03Sgd 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, CONFIG_MSG,
283885025c03Sgd 		    "mac_alloc failed");
283985025c03Sgd 		goto error_intr;
284085025c03Sgd 	}
284185025c03Sgd 	macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER;
284285025c03Sgd 	macp->m_driver = hmep;
284385025c03Sgd 	macp->m_dip = dip;
284485025c03Sgd 	macp->m_src_addr = hmep->hme_ouraddr.ether_addr_octet;
284585025c03Sgd 	macp->m_callbacks = &hme_m_callbacks;
284685025c03Sgd 	macp->m_min_sdu = 0;
284785025c03Sgd 	macp->m_max_sdu = ETHERMTU;
2848d62bc4baSyz 	macp->m_margin = VLAN_TAGSZ;
284985025c03Sgd 	if (mac_register(macp, &hmep->hme_mh) != 0) {
285085025c03Sgd 		mac_free(macp);
285185025c03Sgd 		goto error_intr;
285285025c03Sgd 	}
285385025c03Sgd 
285485025c03Sgd 	mac_free(macp);
285585025c03Sgd 
28567c478bd9Sstevel@tonic-gate 	ddi_report_dev(dip);
28577c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
28587c478bd9Sstevel@tonic-gate 
28597c478bd9Sstevel@tonic-gate 	/*
28607c478bd9Sstevel@tonic-gate 	 * Failure Exit
28617c478bd9Sstevel@tonic-gate 	 */
28627c478bd9Sstevel@tonic-gate 
28637c478bd9Sstevel@tonic-gate error_intr:
28647c478bd9Sstevel@tonic-gate 	if (hmep->hme_cookie)
28657c478bd9Sstevel@tonic-gate 		ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0);
28667c478bd9Sstevel@tonic-gate 
28677c478bd9Sstevel@tonic-gate error_mutex:
28687c478bd9Sstevel@tonic-gate 	mutex_destroy(&hmep->hme_xmitlock);
28697c478bd9Sstevel@tonic-gate 	mutex_destroy(&hmep->hme_intrlock);
28707c478bd9Sstevel@tonic-gate 	mutex_destroy(&hmep->hme_linklock);
28717c478bd9Sstevel@tonic-gate 
28727c478bd9Sstevel@tonic-gate error_unmap:
28737c478bd9Sstevel@tonic-gate 	if (hmep->hme_globregh)
287485025c03Sgd 		ddi_regs_map_free(&hmep->hme_globregh);
28757c478bd9Sstevel@tonic-gate 	if (hmep->hme_cheerio_mode == 0) {
28767c478bd9Sstevel@tonic-gate 		if (hmep->hme_etxregh)
287785025c03Sgd 			ddi_regs_map_free(&hmep->hme_etxregh);
28787c478bd9Sstevel@tonic-gate 		if (hmep->hme_erxregh)
287985025c03Sgd 			ddi_regs_map_free(&hmep->hme_erxregh);
28807c478bd9Sstevel@tonic-gate 		if (hmep->hme_bmacregh)
288185025c03Sgd 			ddi_regs_map_free(&hmep->hme_bmacregh);
28827c478bd9Sstevel@tonic-gate 		if (hmep->hme_mifregh)
288385025c03Sgd 			ddi_regs_map_free(&hmep->hme_mifregh);
28847c478bd9Sstevel@tonic-gate 	} else {
28857c478bd9Sstevel@tonic-gate 		if (hmep->pci_config_handle)
28867c478bd9Sstevel@tonic-gate 			(void) pci_config_teardown(&hmep->pci_config_handle);
28877c478bd9Sstevel@tonic-gate 		hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
28887c478bd9Sstevel@tonic-gate 		    hmep->hme_mifregh = hmep->hme_globregh = NULL;
28897c478bd9Sstevel@tonic-gate 	}
28907c478bd9Sstevel@tonic-gate 
28917c478bd9Sstevel@tonic-gate error_state:
2892*0219346bSGarrett D'Amore 	hmefreethings(hmep);
2893*0219346bSGarrett D'Amore 	hmefreebufs(hmep);
2894*0219346bSGarrett D'Amore 
28957c478bd9Sstevel@tonic-gate 	if (hmep) {
28967c478bd9Sstevel@tonic-gate 		kmem_free((caddr_t)hmep, sizeof (*hmep));
28977c478bd9Sstevel@tonic-gate 		ddi_set_driver_private(dip, NULL);
28987c478bd9Sstevel@tonic-gate 	}
28997c478bd9Sstevel@tonic-gate 
29007c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
29017c478bd9Sstevel@tonic-gate }
29027c478bd9Sstevel@tonic-gate 
2903f2cd0f02Sgd int
29047c478bd9Sstevel@tonic-gate hmedetach(dev_info_t *dip, ddi_detach_cmd_t cmd)
29057c478bd9Sstevel@tonic-gate {
290685025c03Sgd 	struct hme *hmep;
29077c478bd9Sstevel@tonic-gate 
29087c478bd9Sstevel@tonic-gate 	if ((hmep = ddi_get_driver_private(dip)) == NULL)
29097c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
29107c478bd9Sstevel@tonic-gate 
29117c478bd9Sstevel@tonic-gate 	switch (cmd) {
29127c478bd9Sstevel@tonic-gate 	case DDI_DETACH:
29137c478bd9Sstevel@tonic-gate 		break;
29147c478bd9Sstevel@tonic-gate 
29157c478bd9Sstevel@tonic-gate 	case DDI_SUSPEND:
29167c478bd9Sstevel@tonic-gate 		hmep->hme_flags |= HMESUSPENDED;
29177c478bd9Sstevel@tonic-gate 		hmeuninit(hmep);
29187c478bd9Sstevel@tonic-gate 		return (DDI_SUCCESS);
29197c478bd9Sstevel@tonic-gate 
29207c478bd9Sstevel@tonic-gate 	default:
292185025c03Sgd 		return (DDI_FAILURE);
292285025c03Sgd 	}
292385025c03Sgd 
292485025c03Sgd 
292585025c03Sgd 	if (mac_unregister(hmep->hme_mh) != 0) {
29267c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
29277c478bd9Sstevel@tonic-gate 	}
29287c478bd9Sstevel@tonic-gate 
29297c478bd9Sstevel@tonic-gate 	/*
29307c478bd9Sstevel@tonic-gate 	 * Make driver quiescent, we don't want to prevent the
29314dd87b61Sgd 	 * detach on failure.  Note that this should be redundant,
29324dd87b61Sgd 	 * since mac_stop should already have called hmeuninit().
29337c478bd9Sstevel@tonic-gate 	 */
29344dd87b61Sgd 	if (!(hmep->hme_flags & HMESUSPENDED)) {
29354dd87b61Sgd 		(void) hmestop(hmep);
29364dd87b61Sgd 	}
29377c478bd9Sstevel@tonic-gate 
29387c478bd9Sstevel@tonic-gate 	/*
29397c478bd9Sstevel@tonic-gate 	 * Remove instance of the intr
29407c478bd9Sstevel@tonic-gate 	 */
29417c478bd9Sstevel@tonic-gate 	ddi_remove_intr(dip, 0, (ddi_iblock_cookie_t)0);
29427c478bd9Sstevel@tonic-gate 
294385025c03Sgd 	/*
294485025c03Sgd 	 * Unregister kstats.
294585025c03Sgd 	 */
294685025c03Sgd 	if (hmep->hme_ksp != NULL)
294785025c03Sgd 		kstat_delete(hmep->hme_ksp);
294885025c03Sgd 	if (hmep->hme_intrstats != NULL)
294985025c03Sgd 		kstat_delete(hmep->hme_intrstats);
295085025c03Sgd 
295185025c03Sgd 	hmep->hme_ksp = NULL;
295285025c03Sgd 	hmep->hme_intrstats = NULL;
295385025c03Sgd 
295485025c03Sgd 	/*
295585025c03Sgd 	 * Stop asynchronous timer events.
295685025c03Sgd 	 */
295785025c03Sgd 	hme_stop_timer(hmep);
295885025c03Sgd 	mutex_exit(&hmep->hme_linklock);
295985025c03Sgd 
29607c478bd9Sstevel@tonic-gate 	/*
29617c478bd9Sstevel@tonic-gate 	 * Destroy all mutexes and data structures allocated during
29627c478bd9Sstevel@tonic-gate 	 * attach time.
296385025c03Sgd 	 *
296485025c03Sgd 	 * Note: at this time we should be the only thread accessing
296585025c03Sgd 	 * the structures for this instance.
29667c478bd9Sstevel@tonic-gate 	 */
29677c478bd9Sstevel@tonic-gate 
29687c478bd9Sstevel@tonic-gate 	if (hmep->hme_globregh)
29697c478bd9Sstevel@tonic-gate 		ddi_regs_map_free(&hmep->hme_globregh);
29707c478bd9Sstevel@tonic-gate 	if (hmep->hme_cheerio_mode == 0) {
29717c478bd9Sstevel@tonic-gate 		if (hmep->hme_etxregh)
297285025c03Sgd 			ddi_regs_map_free(&hmep->hme_etxregh);
29737c478bd9Sstevel@tonic-gate 		if (hmep->hme_erxregh)
297485025c03Sgd 			ddi_regs_map_free(&hmep->hme_erxregh);
29757c478bd9Sstevel@tonic-gate 		if (hmep->hme_bmacregh)
297685025c03Sgd 			ddi_regs_map_free(&hmep->hme_bmacregh);
29777c478bd9Sstevel@tonic-gate 		if (hmep->hme_mifregh)
297885025c03Sgd 			ddi_regs_map_free(&hmep->hme_mifregh);
29797c478bd9Sstevel@tonic-gate 	} else {
29807c478bd9Sstevel@tonic-gate 		if (hmep->pci_config_handle)
29817c478bd9Sstevel@tonic-gate 			(void) pci_config_teardown(&hmep->pci_config_handle);
29827c478bd9Sstevel@tonic-gate 		hmep->hme_etxregh = hmep->hme_erxregh = hmep->hme_bmacregh =
29837c478bd9Sstevel@tonic-gate 		    hmep->hme_mifregh = hmep->hme_globregh = NULL;
29847c478bd9Sstevel@tonic-gate 	}
29857c478bd9Sstevel@tonic-gate 
298685025c03Sgd 	mutex_destroy(&hmep->hme_xmitlock);
298785025c03Sgd 	mutex_destroy(&hmep->hme_intrlock);
298885025c03Sgd 	mutex_destroy(&hmep->hme_linklock);
29897c478bd9Sstevel@tonic-gate 
2990*0219346bSGarrett D'Amore 	hmefreethings(hmep);
299185025c03Sgd 	hmefreebufs(hmep);
29927c478bd9Sstevel@tonic-gate 
299385025c03Sgd 	hme_param_cleanup(hmep);
29947c478bd9Sstevel@tonic-gate 
299585025c03Sgd 	ddi_set_driver_private(dip, NULL);
299685025c03Sgd 	kmem_free(hmep, sizeof (struct hme));
29977c478bd9Sstevel@tonic-gate 
29987c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
29997c478bd9Sstevel@tonic-gate }
30007c478bd9Sstevel@tonic-gate 
3001*0219346bSGarrett D'Amore int
3002*0219346bSGarrett D'Amore hmequiesce(dev_info_t *dip)
3003*0219346bSGarrett D'Amore {
3004*0219346bSGarrett D'Amore 	struct hme *hmep;
3005*0219346bSGarrett D'Amore 
3006*0219346bSGarrett D'Amore 	if ((hmep = ddi_get_driver_private(dip)) == NULL)
3007*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
3008*0219346bSGarrett D'Amore 
3009*0219346bSGarrett D'Amore 	hme_stop_mifpoll(hmep);
3010*0219346bSGarrett D'Amore 	(void) hmestop(hmep);
3011*0219346bSGarrett D'Amore 	return (DDI_SUCCESS);
3012*0219346bSGarrett D'Amore }
3013*0219346bSGarrett D'Amore 
301485025c03Sgd static boolean_t
30157c478bd9Sstevel@tonic-gate hmeinit_xfer_params(struct hme *hmep)
30167c478bd9Sstevel@tonic-gate {
30177c478bd9Sstevel@tonic-gate 	int i;
30187c478bd9Sstevel@tonic-gate 	int hme_ipg1_conf, hme_ipg2_conf;
30197c478bd9Sstevel@tonic-gate 	int hme_use_int_xcvr_conf, hme_pace_count_conf;
30207c478bd9Sstevel@tonic-gate 	int hme_autoneg_conf;
30217c478bd9Sstevel@tonic-gate 	int hme_anar_100T4_conf;
30227c478bd9Sstevel@tonic-gate 	int hme_anar_100fdx_conf, hme_anar_100hdx_conf;
30237c478bd9Sstevel@tonic-gate 	int hme_anar_10fdx_conf, hme_anar_10hdx_conf;
30247c478bd9Sstevel@tonic-gate 	int hme_ipg0_conf, hme_lance_mode_conf;
30257c478bd9Sstevel@tonic-gate 	int prop_len = sizeof (int);
30267c478bd9Sstevel@tonic-gate 	dev_info_t *dip;
30277c478bd9Sstevel@tonic-gate 
30287c478bd9Sstevel@tonic-gate 	dip = hmep->dip;
30297c478bd9Sstevel@tonic-gate 
30307c478bd9Sstevel@tonic-gate 	for (i = 0; i < A_CNT(hme_param_arr); i++)
30317c478bd9Sstevel@tonic-gate 		hmep->hme_param_arr[i] = hme_param_arr[i];
30327c478bd9Sstevel@tonic-gate 
30337c478bd9Sstevel@tonic-gate 	if (!hmep->hme_g_nd && !hme_param_register(hmep, hmep->hme_param_arr,
303485025c03Sgd 	    A_CNT(hme_param_arr))) {
30357c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, NDD_MSG,
303685025c03Sgd 		    param_reg_fail_msg);
30377c478bd9Sstevel@tonic-gate 		return (B_FALSE);
30387c478bd9Sstevel@tonic-gate 	}
30397c478bd9Sstevel@tonic-gate 
30407c478bd9Sstevel@tonic-gate 	/*
30417c478bd9Sstevel@tonic-gate 	 * Set up the start-up values for user-configurable parameters
30427c478bd9Sstevel@tonic-gate 	 * Get the values from the global variables first.
30437c478bd9Sstevel@tonic-gate 	 * Use the MASK to limit the value to allowed maximum.
30447c478bd9Sstevel@tonic-gate 	 */
30457c478bd9Sstevel@tonic-gate 	hme_param_ipg1 = hme_ipg1 & HME_MASK_8BIT;
30467c478bd9Sstevel@tonic-gate 	hme_param_ipg2 = hme_ipg2 & HME_MASK_8BIT;
30477c478bd9Sstevel@tonic-gate 	hme_param_use_intphy = hme_use_int_xcvr & HME_MASK_1BIT;
30487c478bd9Sstevel@tonic-gate 	hme_param_pace_count = hme_pace_size & HME_MASK_8BIT;
30497c478bd9Sstevel@tonic-gate 	hme_param_autoneg = hme_adv_autoneg_cap;
30507c478bd9Sstevel@tonic-gate 	hme_param_anar_100T4 = hme_adv_100T4_cap;
30517c478bd9Sstevel@tonic-gate 	hme_param_anar_100fdx = hme_adv_100fdx_cap;
30527c478bd9Sstevel@tonic-gate 	hme_param_anar_100hdx = hme_adv_100hdx_cap;
30537c478bd9Sstevel@tonic-gate 	hme_param_anar_10fdx = hme_adv_10fdx_cap;
30547c478bd9Sstevel@tonic-gate 	hme_param_anar_10hdx = hme_adv_10hdx_cap;
30557c478bd9Sstevel@tonic-gate 	hme_param_ipg0 = hme_ipg0 & HME_MASK_5BIT;
30567c478bd9Sstevel@tonic-gate 	hme_param_lance_mode = hme_lance_mode & HME_MASK_1BIT;
30577c478bd9Sstevel@tonic-gate 
30587c478bd9Sstevel@tonic-gate 	/*
30597c478bd9Sstevel@tonic-gate 	 * The link speed may be forced to either 10 Mbps or 100 Mbps using the
30607c478bd9Sstevel@tonic-gate 	 * property "transfer-speed". This may be done in OBP by using the
30617c478bd9Sstevel@tonic-gate 	 * command "apply transfer-speed=<speed> <device>". The speed may be
30627c478bd9Sstevel@tonic-gate 	 * either 10 or 100.
30637c478bd9Sstevel@tonic-gate 	 */
30647c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0,
306585025c03Sgd 	    "transfer-speed", (caddr_t)&i, &prop_len) == DDI_PROP_SUCCESS) {
30667c478bd9Sstevel@tonic-gate 		hme_param_autoneg = 0;	/* force speed */
30677c478bd9Sstevel@tonic-gate 		hme_param_anar_100T4 = 0;
30687c478bd9Sstevel@tonic-gate 		hme_param_anar_100fdx = 0;
30697c478bd9Sstevel@tonic-gate 		hme_param_anar_10fdx = 0;
30707c478bd9Sstevel@tonic-gate 		if (i == 10) {
30717c478bd9Sstevel@tonic-gate 			hme_param_anar_10hdx = 1;
30727c478bd9Sstevel@tonic-gate 			hme_param_anar_100hdx = 0;
30737c478bd9Sstevel@tonic-gate 		} else {
30747c478bd9Sstevel@tonic-gate 			hme_param_anar_10hdx = 0;
30757c478bd9Sstevel@tonic-gate 			hme_param_anar_100hdx = 1;
30767c478bd9Sstevel@tonic-gate 		}
30777c478bd9Sstevel@tonic-gate 	}
30787c478bd9Sstevel@tonic-gate 
30797c478bd9Sstevel@tonic-gate 	/*
30807c478bd9Sstevel@tonic-gate 	 * Get the parameter values configured in .conf file.
30817c478bd9Sstevel@tonic-gate 	 */
30827c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg1",
308385025c03Sgd 	    (caddr_t)&hme_ipg1_conf, &prop_len) == DDI_PROP_SUCCESS) {
30847c478bd9Sstevel@tonic-gate 		hme_param_ipg1 = hme_ipg1_conf & HME_MASK_8BIT;
30857c478bd9Sstevel@tonic-gate 	}
30867c478bd9Sstevel@tonic-gate 
30877c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg2",
308885025c03Sgd 	    (caddr_t)&hme_ipg2_conf, &prop_len) == DDI_PROP_SUCCESS) {
30897c478bd9Sstevel@tonic-gate 		hme_param_ipg2 = hme_ipg2_conf & HME_MASK_8BIT;
30907c478bd9Sstevel@tonic-gate 	}
30917c478bd9Sstevel@tonic-gate 
30927c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "use_int_xcvr",
309385025c03Sgd 	    (caddr_t)&hme_use_int_xcvr_conf, &prop_len) == DDI_PROP_SUCCESS) {
30947c478bd9Sstevel@tonic-gate 		hme_param_use_intphy = hme_use_int_xcvr_conf & HME_MASK_1BIT;
30957c478bd9Sstevel@tonic-gate 	}
30967c478bd9Sstevel@tonic-gate 
30977c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "pace_size",
309885025c03Sgd 	    (caddr_t)&hme_pace_count_conf, &prop_len) == DDI_PROP_SUCCESS) {
30997c478bd9Sstevel@tonic-gate 		hme_param_pace_count = hme_pace_count_conf & HME_MASK_8BIT;
31007c478bd9Sstevel@tonic-gate 	}
31017c478bd9Sstevel@tonic-gate 
31027c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "adv_autoneg_cap",
310385025c03Sgd 	    (caddr_t)&hme_autoneg_conf, &prop_len) == DDI_PROP_SUCCESS) {
31047c478bd9Sstevel@tonic-gate 		hme_param_autoneg = hme_autoneg_conf & HME_MASK_1BIT;
31057c478bd9Sstevel@tonic-gate 	}
31067c478bd9Sstevel@tonic-gate 
31077c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "adv_100T4_cap",
310885025c03Sgd 	    (caddr_t)&hme_anar_100T4_conf, &prop_len) == DDI_PROP_SUCCESS) {
31097c478bd9Sstevel@tonic-gate 		hme_param_anar_100T4 = hme_anar_100T4_conf & HME_MASK_1BIT;
31107c478bd9Sstevel@tonic-gate 	}
31117c478bd9Sstevel@tonic-gate 
31127c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "adv_100fdx_cap",
311385025c03Sgd 	    (caddr_t)&hme_anar_100fdx_conf, &prop_len) == DDI_PROP_SUCCESS) {
31147c478bd9Sstevel@tonic-gate 		hme_param_anar_100fdx = hme_anar_100fdx_conf & HME_MASK_1BIT;
31157c478bd9Sstevel@tonic-gate 	}
31167c478bd9Sstevel@tonic-gate 
31177c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "adv_100hdx_cap",
311885025c03Sgd 	    (caddr_t)&hme_anar_100hdx_conf, &prop_len) == DDI_PROP_SUCCESS) {
31197c478bd9Sstevel@tonic-gate 		hme_param_anar_100hdx = hme_anar_100hdx_conf & HME_MASK_1BIT;
31207c478bd9Sstevel@tonic-gate 	}
31217c478bd9Sstevel@tonic-gate 
31227c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "adv_10fdx_cap",
312385025c03Sgd 	    (caddr_t)&hme_anar_10fdx_conf, &prop_len) == DDI_PROP_SUCCESS) {
31247c478bd9Sstevel@tonic-gate 		hme_param_anar_10fdx = hme_anar_10fdx_conf & HME_MASK_1BIT;
31257c478bd9Sstevel@tonic-gate 	}
31267c478bd9Sstevel@tonic-gate 
31277c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "adv_10hdx_cap",
312885025c03Sgd 	    (caddr_t)&hme_anar_10hdx_conf, &prop_len) == DDI_PROP_SUCCESS) {
31297c478bd9Sstevel@tonic-gate 		hme_param_anar_10hdx = hme_anar_10hdx_conf & HME_MASK_1BIT;
31307c478bd9Sstevel@tonic-gate 	}
31317c478bd9Sstevel@tonic-gate 
31327c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "ipg0",
313385025c03Sgd 	    (caddr_t)&hme_ipg0_conf, &prop_len) == DDI_PROP_SUCCESS) {
31347c478bd9Sstevel@tonic-gate 		hme_param_ipg0 = hme_ipg0_conf & HME_MASK_5BIT;
31357c478bd9Sstevel@tonic-gate 	}
31367c478bd9Sstevel@tonic-gate 
31377c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0, "lance_mode",
313885025c03Sgd 	    (caddr_t)&hme_lance_mode_conf, &prop_len) == DDI_PROP_SUCCESS) {
31397c478bd9Sstevel@tonic-gate 		hme_param_lance_mode = hme_lance_mode_conf & HME_MASK_1BIT;
31407c478bd9Sstevel@tonic-gate 	}
31417c478bd9Sstevel@tonic-gate 
31427c478bd9Sstevel@tonic-gate 	if (hme_link_pulse_disabled)
31437c478bd9Sstevel@tonic-gate 		hmep->hme_link_pulse_disabled = 1;
31447c478bd9Sstevel@tonic-gate 	else if (ddi_getlongprop_buf(DDI_DEV_T_ANY, dip, 0,
314585025c03Sgd 	    "link-pulse-disabled", (caddr_t)&i, &prop_len)
314685025c03Sgd 	    == DDI_PROP_SUCCESS) {
31477c478bd9Sstevel@tonic-gate 		hmep->hme_link_pulse_disabled = 1;
31487c478bd9Sstevel@tonic-gate 	}
31497c478bd9Sstevel@tonic-gate 	return (B_TRUE);
31507c478bd9Sstevel@tonic-gate }
31517c478bd9Sstevel@tonic-gate 
31527c478bd9Sstevel@tonic-gate /*
31537c478bd9Sstevel@tonic-gate  * Return 0 upon success, 1 on failure.
31547c478bd9Sstevel@tonic-gate  */
31557c478bd9Sstevel@tonic-gate static uint_t
31567c478bd9Sstevel@tonic-gate hmestop(struct hme *hmep)
31577c478bd9Sstevel@tonic-gate {
31587c478bd9Sstevel@tonic-gate 	/*
31597c478bd9Sstevel@tonic-gate 	 * Disable the Tx dma engine.
31607c478bd9Sstevel@tonic-gate 	 */
31617c478bd9Sstevel@tonic-gate 	PUT_ETXREG(config, (GET_ETXREG(config) & ~HMET_CONFIG_TXDMA_EN));
31627c478bd9Sstevel@tonic-gate 	HMEDELAY(((GET_ETXREG(state_mach) & 0x1f) == 0x1), HMEMAXRSTDELAY);
31637c478bd9Sstevel@tonic-gate 
31647c478bd9Sstevel@tonic-gate 	/*
31657c478bd9Sstevel@tonic-gate 	 * Disable the Rx dma engine.
31667c478bd9Sstevel@tonic-gate 	 */
31677c478bd9Sstevel@tonic-gate 	PUT_ERXREG(config, (GET_ERXREG(config) & ~HMER_CONFIG_RXDMA_EN));
31687c478bd9Sstevel@tonic-gate 	HMEDELAY(((GET_ERXREG(state_mach) & 0x3f) == 0), HMEMAXRSTDELAY);
31697c478bd9Sstevel@tonic-gate 
31707c478bd9Sstevel@tonic-gate 	/*
31717c478bd9Sstevel@tonic-gate 	 * By this time all things should be quiet, so hit the
31727c478bd9Sstevel@tonic-gate 	 * chip with a reset.
31737c478bd9Sstevel@tonic-gate 	 */
31747c478bd9Sstevel@tonic-gate 	PUT_GLOBREG(reset, HMEG_RESET_GLOBAL);
31757c478bd9Sstevel@tonic-gate 
31767c478bd9Sstevel@tonic-gate 	HMEDELAY((GET_GLOBREG(reset) == 0), HMEMAXRSTDELAY);
31777c478bd9Sstevel@tonic-gate 	if (GET_GLOBREG(reset)) {
31787c478bd9Sstevel@tonic-gate 		return (1);
31797c478bd9Sstevel@tonic-gate 	}
31807c478bd9Sstevel@tonic-gate 
31817c478bd9Sstevel@tonic-gate 	CHECK_GLOBREG();
31827c478bd9Sstevel@tonic-gate 	return (0);
31837c478bd9Sstevel@tonic-gate }
31847c478bd9Sstevel@tonic-gate 
31857c478bd9Sstevel@tonic-gate static int
31867c478bd9Sstevel@tonic-gate hmestat_kstat_update(kstat_t *ksp, int rw)
31877c478bd9Sstevel@tonic-gate {
31887c478bd9Sstevel@tonic-gate 	struct hme *hmep;
31897c478bd9Sstevel@tonic-gate 	struct hmekstat *hkp;
31907c478bd9Sstevel@tonic-gate 
31917c478bd9Sstevel@tonic-gate 	hmep = (struct hme *)ksp->ks_private;
31927c478bd9Sstevel@tonic-gate 	hkp = (struct hmekstat *)ksp->ks_data;
31937c478bd9Sstevel@tonic-gate 
319485025c03Sgd 	if (rw != KSTAT_READ)
319585025c03Sgd 		return (EACCES);
319685025c03Sgd 
31977c478bd9Sstevel@tonic-gate 	/*
31987c478bd9Sstevel@tonic-gate 	 * Update all the stats by reading all the counter registers.
31997c478bd9Sstevel@tonic-gate 	 * Counter register stats are not updated till they overflow
32007c478bd9Sstevel@tonic-gate 	 * and interrupt.
32017c478bd9Sstevel@tonic-gate 	 */
32027c478bd9Sstevel@tonic-gate 
32037c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_xmitlock);
32044dd87b61Sgd 	if (hmep->hme_flags & HMERUNNING) {
32057c478bd9Sstevel@tonic-gate 		hmereclaim(hmep);
32064dd87b61Sgd 		hmesavecntrs(hmep);
32074dd87b61Sgd 	}
32087c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_xmitlock);
32097c478bd9Sstevel@tonic-gate 
321085025c03Sgd 	hkp->hk_cvc.value.ul		= hmep->hme_cvc;
321185025c03Sgd 	hkp->hk_lenerr.value.ul		= hmep->hme_lenerr;
321285025c03Sgd 	hkp->hk_buff.value.ul		= hmep->hme_buff;
321385025c03Sgd 	hkp->hk_missed.value.ul		= hmep->hme_missed;
321485025c03Sgd 	hkp->hk_allocbfail.value.ul	= hmep->hme_allocbfail;
321585025c03Sgd 	hkp->hk_babl.value.ul		= hmep->hme_babl;
321685025c03Sgd 	hkp->hk_tmder.value.ul		= hmep->hme_tmder;
321785025c03Sgd 	hkp->hk_txlaterr.value.ul	= hmep->hme_txlaterr;
321885025c03Sgd 	hkp->hk_rxlaterr.value.ul	= hmep->hme_rxlaterr;
321985025c03Sgd 	hkp->hk_slvparerr.value.ul	= hmep->hme_slvparerr;
322085025c03Sgd 	hkp->hk_txparerr.value.ul	= hmep->hme_txparerr;
322185025c03Sgd 	hkp->hk_rxparerr.value.ul	= hmep->hme_rxparerr;
322285025c03Sgd 	hkp->hk_slverrack.value.ul	= hmep->hme_slverrack;
322385025c03Sgd 	hkp->hk_txerrack.value.ul	= hmep->hme_txerrack;
322485025c03Sgd 	hkp->hk_rxerrack.value.ul	= hmep->hme_rxerrack;
322585025c03Sgd 	hkp->hk_txtagerr.value.ul	= hmep->hme_txtagerr;
322685025c03Sgd 	hkp->hk_rxtagerr.value.ul	= hmep->hme_rxtagerr;
322785025c03Sgd 	hkp->hk_eoperr.value.ul		= hmep->hme_eoperr;
322885025c03Sgd 	hkp->hk_notmds.value.ul		= hmep->hme_notmds;
322985025c03Sgd 	hkp->hk_notbufs.value.ul	= hmep->hme_notbufs;
323085025c03Sgd 	hkp->hk_norbufs.value.ul	= hmep->hme_norbufs;
32317c478bd9Sstevel@tonic-gate 
323285025c03Sgd 	/*
323385025c03Sgd 	 * Debug kstats
323485025c03Sgd 	 */
323585025c03Sgd 	hkp->hk_inits.value.ul		= hmep->inits;
323685025c03Sgd 	hkp->hk_phyfail.value.ul	= hmep->phyfail;
32377c478bd9Sstevel@tonic-gate 
323885025c03Sgd 	/*
323985025c03Sgd 	 * xcvr kstats
324085025c03Sgd 	 */
324185025c03Sgd 	hkp->hk_asic_rev.value.ul	= hmep->asic_rev;
32427c478bd9Sstevel@tonic-gate 
32437c478bd9Sstevel@tonic-gate 	return (0);
32447c478bd9Sstevel@tonic-gate }
32457c478bd9Sstevel@tonic-gate 
32467c478bd9Sstevel@tonic-gate static void
32477c478bd9Sstevel@tonic-gate hmestatinit(struct hme *hmep)
32487c478bd9Sstevel@tonic-gate {
32497c478bd9Sstevel@tonic-gate 	struct	kstat	*ksp;
32507c478bd9Sstevel@tonic-gate 	struct	hmekstat	*hkp;
3251f2cd0f02Sgd 	const char *driver;
32527c478bd9Sstevel@tonic-gate 	int	instance;
32537c478bd9Sstevel@tonic-gate 	char	buf[16];
32547c478bd9Sstevel@tonic-gate 
32557c478bd9Sstevel@tonic-gate 	instance = hmep->instance;
3256f2cd0f02Sgd 	driver = ddi_driver_name(hmep->dip);
32577c478bd9Sstevel@tonic-gate 
3258f2cd0f02Sgd 	if ((ksp = kstat_create(driver, instance,
325985025c03Sgd 	    "driver_info", "net", KSTAT_TYPE_NAMED,
32607c478bd9Sstevel@tonic-gate 	    sizeof (struct hmekstat) / sizeof (kstat_named_t), 0)) == NULL) {
32617c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_UNKNOWN, INIT_MSG,
3262*0219346bSGarrett D'Amore 		    "kstat_create failed");
32637c478bd9Sstevel@tonic-gate 		return;
32647c478bd9Sstevel@tonic-gate 	}
32657c478bd9Sstevel@tonic-gate 
3266f2cd0f02Sgd 	(void) snprintf(buf, sizeof (buf), "%sc%d", driver, instance);
3267f2cd0f02Sgd 	hmep->hme_intrstats = kstat_create(driver, instance, buf, "controller",
326885025c03Sgd 	    KSTAT_TYPE_INTR, 1, KSTAT_FLAG_PERSISTENT);
32697c478bd9Sstevel@tonic-gate 	if (hmep->hme_intrstats)
32707c478bd9Sstevel@tonic-gate 		kstat_install(hmep->hme_intrstats);
32717c478bd9Sstevel@tonic-gate 
32727c478bd9Sstevel@tonic-gate 	hmep->hme_ksp = ksp;
32737c478bd9Sstevel@tonic-gate 	hkp = (struct hmekstat *)ksp->ks_data;
32747c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_cvc,			"code_violations",
327585025c03Sgd 	    KSTAT_DATA_ULONG);
32767c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_lenerr,		"len_errors",
327785025c03Sgd 	    KSTAT_DATA_ULONG);
32787c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_buff,			"buff",
327985025c03Sgd 	    KSTAT_DATA_ULONG);
32807c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_missed,		"missed",
328185025c03Sgd 	    KSTAT_DATA_ULONG);
32827c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_nocanput,		"nocanput",
328385025c03Sgd 	    KSTAT_DATA_ULONG);
32847c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_allocbfail,		"allocbfail",
328585025c03Sgd 	    KSTAT_DATA_ULONG);
32867c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_babl,			"babble",
328785025c03Sgd 	    KSTAT_DATA_ULONG);
32887c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_tmder,		"tmd_error",
328985025c03Sgd 	    KSTAT_DATA_ULONG);
32907c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_txlaterr,		"tx_late_error",
329185025c03Sgd 	    KSTAT_DATA_ULONG);
32927c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_rxlaterr,		"rx_late_error",
329385025c03Sgd 	    KSTAT_DATA_ULONG);
32947c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_slvparerr,		"slv_parity_error",
329585025c03Sgd 	    KSTAT_DATA_ULONG);
32967c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_txparerr,		"tx_parity_error",
329785025c03Sgd 	    KSTAT_DATA_ULONG);
32987c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_rxparerr,		"rx_parity_error",
329985025c03Sgd 	    KSTAT_DATA_ULONG);
33007c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_slverrack,		"slv_error_ack",
330185025c03Sgd 	    KSTAT_DATA_ULONG);
33027c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_txerrack,		"tx_error_ack",
330385025c03Sgd 	    KSTAT_DATA_ULONG);
33047c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_rxerrack,		"rx_error_ack",
330585025c03Sgd 	    KSTAT_DATA_ULONG);
33067c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_txtagerr,		"tx_tag_error",
330785025c03Sgd 	    KSTAT_DATA_ULONG);
33087c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_rxtagerr,		"rx_tag_error",
330985025c03Sgd 	    KSTAT_DATA_ULONG);
33107c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_eoperr,		"eop_error",
331185025c03Sgd 	    KSTAT_DATA_ULONG);
33127c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_notmds,		"no_tmds",
331385025c03Sgd 	    KSTAT_DATA_ULONG);
33147c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_notbufs,		"no_tbufs",
331585025c03Sgd 	    KSTAT_DATA_ULONG);
33167c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_norbufs,		"no_rbufs",
331785025c03Sgd 	    KSTAT_DATA_ULONG);
33187c478bd9Sstevel@tonic-gate 
33197c478bd9Sstevel@tonic-gate 	/*
33207c478bd9Sstevel@tonic-gate 	 * Debugging kstats
33217c478bd9Sstevel@tonic-gate 	 */
33227c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_inits,		"inits",
332385025c03Sgd 	    KSTAT_DATA_ULONG);
33247c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_phyfail,		"phy_failures",
332585025c03Sgd 	    KSTAT_DATA_ULONG);
33267c478bd9Sstevel@tonic-gate 
33277c478bd9Sstevel@tonic-gate 	/*
33287c478bd9Sstevel@tonic-gate 	 * I/O bus kstats
33297c478bd9Sstevel@tonic-gate 	 * kstat_named_init(&hkp->hk_pci_speed,		"pci_bus_speed",
33307c478bd9Sstevel@tonic-gate 	 *		KSTAT_DATA_ULONG);
33317c478bd9Sstevel@tonic-gate 	 * kstat_named_init(&hkp->hk_pci_size,		"pci_bus_width",
33327c478bd9Sstevel@tonic-gate 	 *		KSTAT_DATA_ULONG);
33337c478bd9Sstevel@tonic-gate 	 */
33347c478bd9Sstevel@tonic-gate 
33357c478bd9Sstevel@tonic-gate 	/*
33367c478bd9Sstevel@tonic-gate 	 * xcvr kstats
33377c478bd9Sstevel@tonic-gate 	 */
33387c478bd9Sstevel@tonic-gate 	kstat_named_init(&hkp->hk_asic_rev,		"asic_rev",
333985025c03Sgd 	    KSTAT_DATA_ULONG);
33407c478bd9Sstevel@tonic-gate 
33417c478bd9Sstevel@tonic-gate 	ksp->ks_update = hmestat_kstat_update;
33427c478bd9Sstevel@tonic-gate 	ksp->ks_private = (void *) hmep;
33437c478bd9Sstevel@tonic-gate 	kstat_install(ksp);
33447c478bd9Sstevel@tonic-gate }
33457c478bd9Sstevel@tonic-gate 
33467c478bd9Sstevel@tonic-gate static void
334785025c03Sgd hme_m_ioctl(void *arg, queue_t *wq, mblk_t *mp)
33487c478bd9Sstevel@tonic-gate {
334985025c03Sgd 	struct	hme	*hmep = arg;
335085025c03Sgd 	struct	iocblk	*iocp = (void *)mp->b_rptr;
33517c478bd9Sstevel@tonic-gate 	uint32_t old_ipg1, old_ipg2, old_use_int_xcvr, old_autoneg;
33527c478bd9Sstevel@tonic-gate 	uint32_t old_100T4;
33537c478bd9Sstevel@tonic-gate 	uint32_t old_100fdx, old_100hdx, old_10fdx, old_10hdx;
33547c478bd9Sstevel@tonic-gate 	uint32_t old_ipg0, old_lance_mode;
33557c478bd9Sstevel@tonic-gate 
33567c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
33577c478bd9Sstevel@tonic-gate 
33587c478bd9Sstevel@tonic-gate 	case HME_ND_GET:
335985025c03Sgd 
33607c478bd9Sstevel@tonic-gate 		old_autoneg = hme_param_autoneg;
33617c478bd9Sstevel@tonic-gate 		old_100T4 = hme_param_anar_100T4;
33627c478bd9Sstevel@tonic-gate 		old_100fdx = hme_param_anar_100fdx;
33637c478bd9Sstevel@tonic-gate 		old_100hdx = hme_param_anar_100hdx;
33647c478bd9Sstevel@tonic-gate 		old_10fdx = hme_param_anar_10fdx;
33657c478bd9Sstevel@tonic-gate 		old_10hdx = hme_param_anar_10hdx;
33667c478bd9Sstevel@tonic-gate 
33677c478bd9Sstevel@tonic-gate 		hme_param_autoneg = old_autoneg & ~HME_NOTUSR;
33687c478bd9Sstevel@tonic-gate 		hme_param_anar_100T4 = old_100T4 & ~HME_NOTUSR;
33697c478bd9Sstevel@tonic-gate 		hme_param_anar_100fdx = old_100fdx & ~HME_NOTUSR;
33707c478bd9Sstevel@tonic-gate 		hme_param_anar_100hdx = old_100hdx & ~HME_NOTUSR;
33717c478bd9Sstevel@tonic-gate 		hme_param_anar_10fdx = old_10fdx & ~HME_NOTUSR;
33727c478bd9Sstevel@tonic-gate 		hme_param_anar_10hdx = old_10hdx & ~HME_NOTUSR;
33737c478bd9Sstevel@tonic-gate 
33747c478bd9Sstevel@tonic-gate 		if (!hme_nd_getset(wq, hmep->hme_g_nd, mp)) {
33757c478bd9Sstevel@tonic-gate 			hme_param_autoneg = old_autoneg;
33767c478bd9Sstevel@tonic-gate 			hme_param_anar_100T4 = old_100T4;
33777c478bd9Sstevel@tonic-gate 			hme_param_anar_100fdx = old_100fdx;
33787c478bd9Sstevel@tonic-gate 			hme_param_anar_100hdx = old_100hdx;
33797c478bd9Sstevel@tonic-gate 			hme_param_anar_10fdx = old_10fdx;
33807c478bd9Sstevel@tonic-gate 			hme_param_anar_10hdx = old_10hdx;
33817c478bd9Sstevel@tonic-gate 			miocnak(wq, mp, 0, EINVAL);
33827c478bd9Sstevel@tonic-gate 			return;
33837c478bd9Sstevel@tonic-gate 		}
33847c478bd9Sstevel@tonic-gate 		hme_param_autoneg = old_autoneg;
33857c478bd9Sstevel@tonic-gate 		hme_param_anar_100T4 = old_100T4;
33867c478bd9Sstevel@tonic-gate 		hme_param_anar_100fdx = old_100fdx;
33877c478bd9Sstevel@tonic-gate 		hme_param_anar_100hdx = old_100hdx;
33887c478bd9Sstevel@tonic-gate 		hme_param_anar_10fdx = old_10fdx;
33897c478bd9Sstevel@tonic-gate 		hme_param_anar_10hdx = old_10hdx;
33907c478bd9Sstevel@tonic-gate 
33917c478bd9Sstevel@tonic-gate 		qreply(wq, mp);
339285025c03Sgd 		break;
33937c478bd9Sstevel@tonic-gate 
339485025c03Sgd 	case HME_ND_SET:
339585025c03Sgd 		old_ipg0 = hme_param_ipg0;
339685025c03Sgd 		old_lance_mode = hme_param_lance_mode;
339785025c03Sgd 		old_ipg1 = hme_param_ipg1;
339885025c03Sgd 		old_ipg2 = hme_param_ipg2;
339985025c03Sgd 		old_use_int_xcvr = hme_param_use_intphy;
340085025c03Sgd 		old_autoneg = hme_param_autoneg;
340185025c03Sgd 		hme_param_autoneg = 0xff;
34027c478bd9Sstevel@tonic-gate 
340385025c03Sgd 		if (!hme_nd_getset(wq, hmep->hme_g_nd, mp)) {
340485025c03Sgd 			hme_param_autoneg = old_autoneg;
340585025c03Sgd 			miocnak(wq, mp, 0, EINVAL);
340685025c03Sgd 			return;
340785025c03Sgd 		}
34087c478bd9Sstevel@tonic-gate 
340985025c03Sgd 		qreply(wq, mp);
34107c478bd9Sstevel@tonic-gate 
341185025c03Sgd 		if (hme_param_autoneg != 0xff) {
341285025c03Sgd 			hmep->hme_linkcheck = 0;
341385025c03Sgd 			(void) hmeinit(hmep);
341485025c03Sgd 		} else {
341585025c03Sgd 			hme_param_autoneg = old_autoneg;
341685025c03Sgd 			if (old_use_int_xcvr != hme_param_use_intphy) {
341785025c03Sgd 				hmep->hme_linkcheck = 0;
341885025c03Sgd 				(void) hmeinit(hmep);
341985025c03Sgd 			} else if ((old_ipg1 != hme_param_ipg1) ||
342085025c03Sgd 			    (old_ipg2 != hme_param_ipg2) ||
342185025c03Sgd 			    (old_ipg0 != hme_param_ipg0) ||
342285025c03Sgd 			    (old_lance_mode != hme_param_lance_mode)) {
342385025c03Sgd 				(void) hmeinit(hmep);
34247c478bd9Sstevel@tonic-gate 			}
34257c478bd9Sstevel@tonic-gate 		}
34267c478bd9Sstevel@tonic-gate 		break;
34277c478bd9Sstevel@tonic-gate 
34287c478bd9Sstevel@tonic-gate 	default:
342985025c03Sgd 		miocnak(wq, mp, 0, EINVAL);
343085025c03Sgd 		break;
34317c478bd9Sstevel@tonic-gate 	}
34327c478bd9Sstevel@tonic-gate }
34337c478bd9Sstevel@tonic-gate 
343485025c03Sgd /*ARGSUSED*/
343585025c03Sgd static boolean_t
343685025c03Sgd hme_m_getcapab(void *arg, mac_capab_t cap, void *cap_data)
34377c478bd9Sstevel@tonic-gate {
343885025c03Sgd 	switch (cap) {
343985025c03Sgd 	case MAC_CAPAB_HCKSUM:
344085025c03Sgd 		*(uint32_t *)cap_data = HCKSUM_INET_PARTIAL;
344185025c03Sgd 		return (B_TRUE);
344285025c03Sgd 	default:
344385025c03Sgd 		return (B_FALSE);
34447c478bd9Sstevel@tonic-gate 	}
344585025c03Sgd }
34467c478bd9Sstevel@tonic-gate 
344785025c03Sgd static int
344885025c03Sgd hme_m_promisc(void *arg, boolean_t on)
344985025c03Sgd {
345085025c03Sgd 	struct hme *hmep = arg;
34517c478bd9Sstevel@tonic-gate 
345285025c03Sgd 	hmep->hme_promisc = on;
345385025c03Sgd 	(void) hmeinit(hmep);
345485025c03Sgd 	return (0);
345585025c03Sgd }
34567c478bd9Sstevel@tonic-gate 
345785025c03Sgd static int
345885025c03Sgd hme_m_unicst(void *arg, const uint8_t *macaddr)
345985025c03Sgd {
346085025c03Sgd 	struct hme *hmep = arg;
34617c478bd9Sstevel@tonic-gate 
34627c478bd9Sstevel@tonic-gate 	/*
34637c478bd9Sstevel@tonic-gate 	 * Set new interface local address and re-init device.
34647c478bd9Sstevel@tonic-gate 	 * This is destructive to any other streams attached
34657c478bd9Sstevel@tonic-gate 	 * to this device.
34667c478bd9Sstevel@tonic-gate 	 */
346785025c03Sgd 	mutex_enter(&hmep->hme_intrlock);
346885025c03Sgd 	bcopy(macaddr, &hmep->hme_ouraddr, ETHERADDRL);
346985025c03Sgd 	mutex_exit(&hmep->hme_intrlock);
347085025c03Sgd 	(void) hmeinit(hmep);
347185025c03Sgd 	return (0);
34727c478bd9Sstevel@tonic-gate }
34737c478bd9Sstevel@tonic-gate 
347485025c03Sgd static int
347585025c03Sgd hme_m_multicst(void *arg, boolean_t add, const uint8_t *macaddr)
34767c478bd9Sstevel@tonic-gate {
347785025c03Sgd 	struct hme	*hmep = arg;
347885025c03Sgd 	uint32_t	ladrf_bit;
347985025c03Sgd 	boolean_t	doinit = B_FALSE;
34807c478bd9Sstevel@tonic-gate 
34817c478bd9Sstevel@tonic-gate 	/*
348285025c03Sgd 	 * If this address's bit was not already set in the local address
348385025c03Sgd 	 * filter, add it and re-initialize the Hardware.
34847c478bd9Sstevel@tonic-gate 	 */
348585025c03Sgd 	ladrf_bit = hmeladrf_bit(macaddr);
34867c478bd9Sstevel@tonic-gate 
348785025c03Sgd 	mutex_enter(&hmep->hme_intrlock);
348885025c03Sgd 	if (add) {
348985025c03Sgd 		hmep->hme_ladrf_refcnt[ladrf_bit]++;
349085025c03Sgd 		if (hmep->hme_ladrf_refcnt[ladrf_bit] == 1) {
349185025c03Sgd 			hmep->hme_ladrf[ladrf_bit >> 4] |=
349285025c03Sgd 			    1 << (ladrf_bit & 0xf);
349385025c03Sgd 			hmep->hme_multi++;
349485025c03Sgd 			doinit = B_TRUE;
349585025c03Sgd 		}
34967c478bd9Sstevel@tonic-gate 	} else {
349785025c03Sgd 		hmep->hme_ladrf_refcnt[ladrf_bit]--;
349885025c03Sgd 		if (hmep->hme_ladrf_refcnt[ladrf_bit] == 0) {
349985025c03Sgd 			hmep->hme_ladrf[ladrf_bit >> 4] &=
350085025c03Sgd 			    ~(1 << (ladrf_bit & 0xf));
350185025c03Sgd 			doinit = B_TRUE;
35027c478bd9Sstevel@tonic-gate 		}
35037c478bd9Sstevel@tonic-gate 	}
350485025c03Sgd 	mutex_exit(&hmep->hme_intrlock);
35057c478bd9Sstevel@tonic-gate 
3506*0219346bSGarrett D'Amore 	if (doinit) {
350785025c03Sgd 		(void) hmeinit(hmep);
3508*0219346bSGarrett D'Amore 	}
35097c478bd9Sstevel@tonic-gate 
351085025c03Sgd 	return (0);
35117c478bd9Sstevel@tonic-gate }
35127c478bd9Sstevel@tonic-gate 
351385025c03Sgd static int
351485025c03Sgd hme_m_start(void *arg)
35157c478bd9Sstevel@tonic-gate {
351685025c03Sgd 	struct hme *hmep = arg;
35177c478bd9Sstevel@tonic-gate 
3518228fdff0Sgd 	if (hmeinit(hmep) != 0) {
3519228fdff0Sgd 		/* initialization failed -- really want DL_INITFAILED */
3520228fdff0Sgd 		return (EIO);
3521228fdff0Sgd 	} else {
3522228fdff0Sgd 		hmep->hme_started = B_TRUE;
3523228fdff0Sgd 		return (0);
3524228fdff0Sgd 	}
352585025c03Sgd }
35267c478bd9Sstevel@tonic-gate 
352785025c03Sgd static void
352885025c03Sgd hme_m_stop(void *arg)
352985025c03Sgd {
353085025c03Sgd 	struct hme *hmep = arg;
35317c478bd9Sstevel@tonic-gate 
3532228fdff0Sgd 	hmep->hme_started = B_FALSE;
353385025c03Sgd 	hmeuninit(hmep);
353485025c03Sgd }
35357c478bd9Sstevel@tonic-gate 
353685025c03Sgd static int
353785025c03Sgd hme_m_stat(void *arg, uint_t stat, uint64_t *val)
353885025c03Sgd {
353985025c03Sgd 	struct hme	*hmep = arg;
35407c478bd9Sstevel@tonic-gate 
354185025c03Sgd 	mutex_enter(&hmep->hme_xmitlock);
35424dd87b61Sgd 	if (hmep->hme_flags & HMERUNNING) {
354385025c03Sgd 		hmereclaim(hmep);
35444dd87b61Sgd 		hmesavecntrs(hmep);
35454dd87b61Sgd 	}
354685025c03Sgd 	mutex_exit(&hmep->hme_xmitlock);
35477c478bd9Sstevel@tonic-gate 
35487c478bd9Sstevel@tonic-gate 
354985025c03Sgd 	switch (stat) {
355085025c03Sgd 	case MAC_STAT_IFSPEED:
355185025c03Sgd 		*val = hmep->hme_ifspeed * 1000000;
355285025c03Sgd 		break;
355385025c03Sgd 	case MAC_STAT_IPACKETS:
355485025c03Sgd 		*val = hmep->hme_ipackets;
355585025c03Sgd 		break;
355685025c03Sgd 	case MAC_STAT_RBYTES:
355785025c03Sgd 		*val = hmep->hme_rbytes;
355885025c03Sgd 		break;
355985025c03Sgd 	case MAC_STAT_IERRORS:
356085025c03Sgd 		*val = hmep->hme_ierrors;
356185025c03Sgd 		break;
356285025c03Sgd 	case MAC_STAT_OPACKETS:
356385025c03Sgd 		*val = hmep->hme_opackets;
356485025c03Sgd 		break;
356585025c03Sgd 	case MAC_STAT_OBYTES:
356685025c03Sgd 		*val = hmep->hme_obytes;
356785025c03Sgd 		break;
356885025c03Sgd 	case MAC_STAT_OERRORS:
356985025c03Sgd 		*val = hmep->hme_oerrors;
357085025c03Sgd 		break;
357185025c03Sgd 	case MAC_STAT_MULTIRCV:
357285025c03Sgd 		*val = hmep->hme_multircv;
357385025c03Sgd 		break;
357485025c03Sgd 	case MAC_STAT_MULTIXMT:
357585025c03Sgd 		*val = hmep->hme_multixmt;
357685025c03Sgd 		break;
357785025c03Sgd 	case MAC_STAT_BRDCSTRCV:
357885025c03Sgd 		*val = hmep->hme_brdcstrcv;
357985025c03Sgd 		break;
358085025c03Sgd 	case MAC_STAT_BRDCSTXMT:
358185025c03Sgd 		*val = hmep->hme_brdcstxmt;
358285025c03Sgd 		break;
358385025c03Sgd 	case MAC_STAT_UNDERFLOWS:
358485025c03Sgd 		*val = hmep->hme_uflo;
358585025c03Sgd 		break;
358685025c03Sgd 	case MAC_STAT_OVERFLOWS:
358785025c03Sgd 		*val = hmep->hme_oflo;
358885025c03Sgd 		break;
358985025c03Sgd 	case MAC_STAT_COLLISIONS:
359085025c03Sgd 		*val = hmep->hme_coll;
359185025c03Sgd 		break;
359285025c03Sgd 	case MAC_STAT_NORCVBUF:
359385025c03Sgd 		*val = hmep->hme_norcvbuf;
359485025c03Sgd 		break;
359585025c03Sgd 	case MAC_STAT_NOXMTBUF:
359685025c03Sgd 		*val = hmep->hme_noxmtbuf;
359785025c03Sgd 		break;
359885025c03Sgd 	case ETHER_STAT_LINK_DUPLEX:
359985025c03Sgd 		*val = hmep->hme_duplex;
360085025c03Sgd 		break;
360185025c03Sgd 	case ETHER_STAT_ALIGN_ERRORS:
360285025c03Sgd 		*val = hmep->hme_align_errors;
360385025c03Sgd 		break;
360485025c03Sgd 	case ETHER_STAT_FCS_ERRORS:
360585025c03Sgd 		*val = hmep->hme_fcs_errors;
360685025c03Sgd 		break;
360785025c03Sgd 	case ETHER_STAT_EX_COLLISIONS:
360885025c03Sgd 		*val = hmep->hme_excol;
360985025c03Sgd 		break;
361085025c03Sgd 	case ETHER_STAT_DEFER_XMTS:
361185025c03Sgd 		*val = hmep->hme_defer_xmts;
361285025c03Sgd 		break;
361385025c03Sgd 	case ETHER_STAT_SQE_ERRORS:
361485025c03Sgd 		*val = hmep->hme_sqe_errors;
361585025c03Sgd 		break;
361685025c03Sgd 	case ETHER_STAT_FIRST_COLLISIONS:
361785025c03Sgd 		*val = hmep->hme_fstcol;
361885025c03Sgd 		break;
361985025c03Sgd 	case ETHER_STAT_TX_LATE_COLLISIONS:
362085025c03Sgd 		*val = hmep->hme_tlcol;
362185025c03Sgd 		break;
362285025c03Sgd 	case ETHER_STAT_TOOLONG_ERRORS:
362385025c03Sgd 		*val = hmep->hme_toolong_errors;
362485025c03Sgd 		break;
362585025c03Sgd 	case ETHER_STAT_TOOSHORT_ERRORS:
362685025c03Sgd 		*val = hmep->hme_runt;
362785025c03Sgd 		break;
36284dd87b61Sgd 	case ETHER_STAT_CARRIER_ERRORS:
36294dd87b61Sgd 		*val = hmep->hme_carrier_errors;
36304dd87b61Sgd 		break;
363185025c03Sgd 	case ETHER_STAT_XCVR_ADDR:
363285025c03Sgd 		*val = hmep->hme_phyad;
363385025c03Sgd 		break;
363485025c03Sgd 	case ETHER_STAT_XCVR_ID:
363585025c03Sgd 		*val = (hmep->hme_idr1 << 16U) | (hmep->hme_idr2);
363685025c03Sgd 		break;
363785025c03Sgd 	case ETHER_STAT_XCVR_INUSE:
363885025c03Sgd 		switch (hmep->hme_transceiver) {
363985025c03Sgd 		case HME_INTERNAL_TRANSCEIVER:
364085025c03Sgd 			*val = XCVR_100X;
364185025c03Sgd 			break;
364285025c03Sgd 		case HME_NO_TRANSCEIVER:
364385025c03Sgd 			*val = XCVR_NONE;
364485025c03Sgd 			break;
364585025c03Sgd 		default:
364685025c03Sgd 			*val = XCVR_UNDEFINED;
36477c478bd9Sstevel@tonic-gate 			break;
36487c478bd9Sstevel@tonic-gate 		}
364985025c03Sgd 		break;
365085025c03Sgd 	case ETHER_STAT_CAP_100T4:
365185025c03Sgd 		*val = hme_param_bmsr_100T4;
365285025c03Sgd 		break;
365385025c03Sgd 	case ETHER_STAT_ADV_CAP_100T4:
365485025c03Sgd 		*val = hme_param_anar_100T4 & ~HME_NOTUSR;
365585025c03Sgd 		break;
365685025c03Sgd 	case ETHER_STAT_LP_CAP_100T4:
365785025c03Sgd 		*val = hme_param_anlpar_100T4;
365885025c03Sgd 		break;
365985025c03Sgd 	case ETHER_STAT_CAP_100FDX:
366085025c03Sgd 		*val = hme_param_bmsr_100fdx;
366185025c03Sgd 		break;
366285025c03Sgd 	case ETHER_STAT_ADV_CAP_100FDX:
366385025c03Sgd 		*val = hme_param_anar_100fdx & ~HME_NOTUSR;
366485025c03Sgd 		break;
366585025c03Sgd 	case ETHER_STAT_LP_CAP_100FDX:
366685025c03Sgd 		*val = hme_param_anlpar_100fdx;
366785025c03Sgd 		break;
366885025c03Sgd 	case ETHER_STAT_CAP_100HDX:
366985025c03Sgd 		*val = hme_param_bmsr_100hdx;
367085025c03Sgd 		break;
367185025c03Sgd 	case ETHER_STAT_ADV_CAP_100HDX:
367285025c03Sgd 		*val = hme_param_anar_100hdx & ~HME_NOTUSR;
367385025c03Sgd 		break;
367485025c03Sgd 	case ETHER_STAT_LP_CAP_100HDX:
367585025c03Sgd 		*val = hme_param_anlpar_100hdx;
367685025c03Sgd 		break;
367785025c03Sgd 	case ETHER_STAT_CAP_10FDX:
367885025c03Sgd 		*val = hme_param_bmsr_10fdx;
367985025c03Sgd 		break;
368085025c03Sgd 	case ETHER_STAT_ADV_CAP_10FDX:
368185025c03Sgd 		*val = hme_param_anar_10fdx & ~HME_NOTUSR;
368285025c03Sgd 		break;
368385025c03Sgd 	case ETHER_STAT_LP_CAP_10FDX:
368485025c03Sgd 		*val = hme_param_anlpar_10fdx;
368585025c03Sgd 		break;
368685025c03Sgd 	case ETHER_STAT_CAP_10HDX:
368785025c03Sgd 		*val = hme_param_bmsr_10hdx;
368885025c03Sgd 		break;
368985025c03Sgd 	case ETHER_STAT_ADV_CAP_10HDX:
369085025c03Sgd 		*val = hme_param_anar_10hdx & ~HME_NOTUSR;
369185025c03Sgd 		break;
369285025c03Sgd 	case ETHER_STAT_LP_CAP_10HDX:
369385025c03Sgd 		*val = hme_param_anlpar_10hdx;
369485025c03Sgd 		break;
369585025c03Sgd 	case ETHER_STAT_CAP_AUTONEG:
369685025c03Sgd 		*val = hme_param_bmsr_ancap;
369785025c03Sgd 		break;
369885025c03Sgd 	case ETHER_STAT_ADV_CAP_AUTONEG:
369985025c03Sgd 		*val = hme_param_autoneg & ~HME_NOTUSR;
370085025c03Sgd 		break;
370185025c03Sgd 	case ETHER_STAT_LP_CAP_AUTONEG:
370285025c03Sgd 		*val = hme_param_aner_lpancap;
370385025c03Sgd 		break;
370485025c03Sgd 	default:
370585025c03Sgd 		return (EINVAL);
37067c478bd9Sstevel@tonic-gate 	}
370785025c03Sgd 	return (0);
37087c478bd9Sstevel@tonic-gate }
37097c478bd9Sstevel@tonic-gate 
371085025c03Sgd static mblk_t *
371185025c03Sgd hme_m_tx(void *arg, mblk_t *mp)
37127c478bd9Sstevel@tonic-gate {
371385025c03Sgd 	struct hme *hmep = arg;
371485025c03Sgd 	mblk_t *next;
37157c478bd9Sstevel@tonic-gate 
371685025c03Sgd 	while (mp != NULL) {
371785025c03Sgd 		next = mp->b_next;
371885025c03Sgd 		mp->b_next = NULL;
371985025c03Sgd 		if (!hmestart(hmep, mp)) {
372085025c03Sgd 			mp->b_next = next;
372185025c03Sgd 			break;
37227c478bd9Sstevel@tonic-gate 		}
372385025c03Sgd 		mp = next;
37247c478bd9Sstevel@tonic-gate 	}
372585025c03Sgd 	return (mp);
37267c478bd9Sstevel@tonic-gate }
37277c478bd9Sstevel@tonic-gate 
3728eb7b3d20Sgd /*
3729eb7b3d20Sgd  * Software IP checksum, for the edge cases that the
3730eb7b3d20Sgd  * hardware can't handle.  See hmestart for more info.
3731eb7b3d20Sgd  */
3732eb7b3d20Sgd static uint16_t
3733eb7b3d20Sgd hme_cksum(void *data, int len)
3734eb7b3d20Sgd {
3735eb7b3d20Sgd 	uint16_t	*words = data;
3736eb7b3d20Sgd 	int		i, nwords = len / 2;
3737eb7b3d20Sgd 	uint32_t	sum = 0;
3738eb7b3d20Sgd 
3739eb7b3d20Sgd 	/* just add up the words */
3740eb7b3d20Sgd 	for (i = 0; i < nwords; i++) {
3741eb7b3d20Sgd 		sum += *words++;
3742eb7b3d20Sgd 	}
3743eb7b3d20Sgd 
3744eb7b3d20Sgd 	/* pick up residual byte ... assume even half-word allocations */
3745eb7b3d20Sgd 	if (len % 2) {
3746*0219346bSGarrett D'Amore 		sum += (*words & htons(0xff00));
3747eb7b3d20Sgd 	}
3748eb7b3d20Sgd 
3749eb7b3d20Sgd 	sum = (sum >> 16) + (sum & 0xffff);
3750eb7b3d20Sgd 	sum = (sum >> 16) + (sum & 0xffff);
3751eb7b3d20Sgd 
3752eb7b3d20Sgd 	return (~(sum & 0xffff));
3753eb7b3d20Sgd }
3754eb7b3d20Sgd 
375585025c03Sgd static boolean_t
3756*0219346bSGarrett D'Amore hmestart(struct hme *hmep, mblk_t *mp)
37577c478bd9Sstevel@tonic-gate {
3758*0219346bSGarrett D'Amore 	uint32_t	len;
3759*0219346bSGarrett D'Amore 	boolean_t	retval = B_TRUE;
3760*0219346bSGarrett D'Amore 	hmebuf_t	*tbuf;
3761*0219346bSGarrett D'Amore 	uint32_t	txptr;
37627c478bd9Sstevel@tonic-gate 
376385025c03Sgd 	uint32_t	csflags = 0;
376485025c03Sgd 	uint32_t	flags;
376585025c03Sgd 	uint32_t	start_offset;
376685025c03Sgd 	uint32_t	stuff_offset;
37677c478bd9Sstevel@tonic-gate 
376885025c03Sgd 	hcksum_retrieve(mp, NULL, NULL, &start_offset, &stuff_offset,
376985025c03Sgd 	    NULL, NULL, &flags);
37707c478bd9Sstevel@tonic-gate 
377185025c03Sgd 	if (flags & HCK_PARTIALCKSUM) {
377285025c03Sgd 		if (get_ether_type(mp->b_rptr) == ETHERTYPE_VLAN) {
377385025c03Sgd 			start_offset += sizeof (struct ether_header) + 4;
377485025c03Sgd 			stuff_offset += sizeof (struct ether_header) + 4;
377585025c03Sgd 		} else {
377685025c03Sgd 			start_offset += sizeof (struct ether_header);
377785025c03Sgd 			stuff_offset += sizeof (struct ether_header);
37787c478bd9Sstevel@tonic-gate 		}
377985025c03Sgd 		csflags = HMETMD_CSENABL |
378085025c03Sgd 		    (start_offset << HMETMD_CSSTART_SHIFT) |
378185025c03Sgd 		    (stuff_offset << HMETMD_CSSTUFF_SHIFT);
378285025c03Sgd 	}
37837c478bd9Sstevel@tonic-gate 
37847c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_xmitlock);
37857c478bd9Sstevel@tonic-gate 
37864dd87b61Sgd 	if (hmep->hme_flags & HMESUSPENDED) {
37874dd87b61Sgd 		hmep->hme_carrier_errors++;
37884dd87b61Sgd 		hmep->hme_oerrors++;
37894dd87b61Sgd 		goto bad;
37904dd87b61Sgd 	}
37914dd87b61Sgd 
3792*0219346bSGarrett D'Amore 	if (hmep->hme_txindex != hmep->hme_txreclaim) {
3793*0219346bSGarrett D'Amore 		hmereclaim(hmep);
37947c478bd9Sstevel@tonic-gate 	}
3795*0219346bSGarrett D'Amore 	if ((hmep->hme_txindex - HME_TMDMAX) == hmep->hme_txreclaim)
37967c478bd9Sstevel@tonic-gate 		goto notmds;
3797*0219346bSGarrett D'Amore 	txptr = hmep->hme_txindex % HME_TMDMAX;
3798*0219346bSGarrett D'Amore 	tbuf = &hmep->hme_tbuf[txptr];
37997c478bd9Sstevel@tonic-gate 
3800eb7b3d20Sgd 	/*
3801eb7b3d20Sgd 	 * Note that for checksum offload, the hardware cannot
3802eb7b3d20Sgd 	 * generate correct checksums if the packet is smaller than
3803eb7b3d20Sgd 	 * 64-bytes.  In such a case, we bcopy the packet and use
3804eb7b3d20Sgd 	 * a software checksum.
3805eb7b3d20Sgd 	 */
3806eb7b3d20Sgd 
3807*0219346bSGarrett D'Amore 	len = msgsize(mp);
3808*0219346bSGarrett D'Amore 	if (len < 64) {
3809*0219346bSGarrett D'Amore 		/* zero fill the padding */
3810*0219346bSGarrett D'Amore 		bzero(tbuf->kaddr, 64);
38117c478bd9Sstevel@tonic-gate 	}
3812*0219346bSGarrett D'Amore 	mcopymsg(mp, tbuf->kaddr);
38137c478bd9Sstevel@tonic-gate 
3814*0219346bSGarrett D'Amore 	if ((csflags != 0) && (len < 64)) {
3815*0219346bSGarrett D'Amore 		uint16_t sum;
3816*0219346bSGarrett D'Amore 		sum = hme_cksum(tbuf->kaddr + start_offset,
3817*0219346bSGarrett D'Amore 		    len - start_offset);
3818*0219346bSGarrett D'Amore 		bcopy(&sum, tbuf->kaddr + stuff_offset, sizeof (sum));
3819*0219346bSGarrett D'Amore 		csflags = 0;
38207c478bd9Sstevel@tonic-gate 	}
38217c478bd9Sstevel@tonic-gate 
3822*0219346bSGarrett D'Amore 	if (ddi_dma_sync(tbuf->dmah, 0, len, DDI_DMA_SYNC_FORDEV) ==
3823*0219346bSGarrett D'Amore 	    DDI_FAILURE) {
38247c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, DDI_MSG,
382585025c03Sgd 		    "ddi_dma_sync failed");
38267c478bd9Sstevel@tonic-gate 	}
38277c478bd9Sstevel@tonic-gate 
3828*0219346bSGarrett D'Amore 	/*
3829*0219346bSGarrett D'Amore 	 * update MIB II statistics
3830*0219346bSGarrett D'Amore 	 */
3831*0219346bSGarrett D'Amore 	BUMP_OutNUcast(hmep, tbuf->kaddr);
3832*0219346bSGarrett D'Amore 
3833*0219346bSGarrett D'Amore 	PUT_TMD(txptr, tbuf->paddr, len,
3834*0219346bSGarrett D'Amore 	    HMETMD_OWN | HMETMD_SOP | HMETMD_EOP | csflags);
38357c478bd9Sstevel@tonic-gate 
3836*0219346bSGarrett D'Amore 	HMESYNCTMD(txptr, DDI_DMA_SYNC_FORDEV);
3837*0219346bSGarrett D'Amore 	hmep->hme_txindex++;
38387c478bd9Sstevel@tonic-gate 
38397c478bd9Sstevel@tonic-gate 	PUT_ETXREG(txpend, HMET_TXPEND_TDMD);
38407c478bd9Sstevel@tonic-gate 	CHECK_ETXREG();
38417c478bd9Sstevel@tonic-gate 
38427c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_xmitlock);
38437c478bd9Sstevel@tonic-gate 
38447c478bd9Sstevel@tonic-gate 	hmep->hme_starts++;
384585025c03Sgd 	return (B_TRUE);
38467c478bd9Sstevel@tonic-gate 
38477c478bd9Sstevel@tonic-gate bad:
38487c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_xmitlock);
38497c478bd9Sstevel@tonic-gate 	freemsg(mp);
385085025c03Sgd 	return (B_TRUE);
38517c478bd9Sstevel@tonic-gate 
38527c478bd9Sstevel@tonic-gate notmds:
38537c478bd9Sstevel@tonic-gate 	hmep->hme_notmds++;
385485025c03Sgd 	hmep->hme_wantw = B_TRUE;
38557c478bd9Sstevel@tonic-gate 	hmereclaim(hmep);
385685025c03Sgd 	retval = B_FALSE;
38577c478bd9Sstevel@tonic-gate done:
38587c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_xmitlock);
38597c478bd9Sstevel@tonic-gate 
386085025c03Sgd 	return (retval);
38617c478bd9Sstevel@tonic-gate }
38627c478bd9Sstevel@tonic-gate 
38637c478bd9Sstevel@tonic-gate /*
38647c478bd9Sstevel@tonic-gate  * Initialize channel.
38657c478bd9Sstevel@tonic-gate  * Return 0 on success, nonzero on error.
38667c478bd9Sstevel@tonic-gate  *
38677c478bd9Sstevel@tonic-gate  * The recommended sequence for initialization is:
38687c478bd9Sstevel@tonic-gate  * 1. Issue a Global Reset command to the Ethernet Channel.
38697c478bd9Sstevel@tonic-gate  * 2. Poll the Global_Reset bits until the execution of the reset has been
38707c478bd9Sstevel@tonic-gate  *    completed.
38717c478bd9Sstevel@tonic-gate  * 2(a). Use the MIF Frame/Output register to reset the transceiver.
38727c478bd9Sstevel@tonic-gate  *	 Poll Register 0 to till the Resetbit is 0.
38737c478bd9Sstevel@tonic-gate  * 2(b). Use the MIF Frame/Output register to set the PHY in in Normal-Op,
38747c478bd9Sstevel@tonic-gate  *	 100Mbps and Non-Isolated mode. The main point here is to bring the
38757c478bd9Sstevel@tonic-gate  *	 PHY out of Isolate mode so that it can generate the rx_clk and tx_clk
38767c478bd9Sstevel@tonic-gate  *	 to the MII interface so that the Bigmac core can correctly reset
38777c478bd9Sstevel@tonic-gate  *	 upon a software reset.
38787c478bd9Sstevel@tonic-gate  * 2(c).  Issue another Global Reset command to the Ethernet Channel and poll
38797c478bd9Sstevel@tonic-gate  *	  the Global_Reset bits till completion.
38807c478bd9Sstevel@tonic-gate  * 3. Set up all the data structures in the host memory.
38817c478bd9Sstevel@tonic-gate  * 4. Program the TX_MAC registers/counters (excluding the TX_MAC Configuration
38827c478bd9Sstevel@tonic-gate  *    Register).
38837c478bd9Sstevel@tonic-gate  * 5. Program the RX_MAC registers/counters (excluding the RX_MAC Configuration
38847c478bd9Sstevel@tonic-gate  *    Register).
38857c478bd9Sstevel@tonic-gate  * 6. Program the Transmit Descriptor Ring Base Address in the ETX.
38867c478bd9Sstevel@tonic-gate  * 7. Program the Receive Descriptor Ring Base Address in the ERX.
38877c478bd9Sstevel@tonic-gate  * 8. Program the Global Configuration and the Global Interrupt Mask Registers.
38887c478bd9Sstevel@tonic-gate  * 9. Program the ETX Configuration register (enable the Transmit DMA channel).
38897c478bd9Sstevel@tonic-gate  * 10. Program the ERX Configuration register (enable the Receive DMA channel).
38907c478bd9Sstevel@tonic-gate  * 11. Program the XIF Configuration Register (enable the XIF).
38917c478bd9Sstevel@tonic-gate  * 12. Program the RX_MAC Configuration Register (Enable the RX_MAC).
38927c478bd9Sstevel@tonic-gate  * 13. Program the TX_MAC Configuration Register (Enable the TX_MAC).
38937c478bd9Sstevel@tonic-gate  */
38947c478bd9Sstevel@tonic-gate 
38957c478bd9Sstevel@tonic-gate 
38967c478bd9Sstevel@tonic-gate #ifdef FEPS_URUN_BUG
38977c478bd9Sstevel@tonic-gate static int hme_palen = 32;
38987c478bd9Sstevel@tonic-gate #endif
38997c478bd9Sstevel@tonic-gate 
39007c478bd9Sstevel@tonic-gate static int
39017c478bd9Sstevel@tonic-gate hmeinit(struct hme *hmep)
39027c478bd9Sstevel@tonic-gate {
3903*0219346bSGarrett D'Amore 	uint32_t		i;
3904*0219346bSGarrett D'Amore 	int			ret;
39057c478bd9Sstevel@tonic-gate 
390685025c03Sgd 	/*
390785025c03Sgd 	 * Lock sequence:
390885025c03Sgd 	 *	hme_intrlock, hme_xmitlock.
390985025c03Sgd 	 */
391085025c03Sgd 	mutex_enter(&hmep->hme_intrlock);
39117c478bd9Sstevel@tonic-gate 
39127c478bd9Sstevel@tonic-gate 	/*
391385025c03Sgd 	 * Don't touch the hardware if we are suspended.  But don't
391485025c03Sgd 	 * fail either.  Some time later we may be resumed, and then
391585025c03Sgd 	 * we'll be back here to program the device using the settings
391685025c03Sgd 	 * in the soft state.
39177c478bd9Sstevel@tonic-gate 	 */
391885025c03Sgd 	if (hmep->hme_flags & HMESUSPENDED) {
391985025c03Sgd 		mutex_exit(&hmep->hme_intrlock);
392085025c03Sgd 		return (0);
392185025c03Sgd 	}
39227c478bd9Sstevel@tonic-gate 
39237c478bd9Sstevel@tonic-gate 	/*
392485025c03Sgd 	 * This should prevent us from clearing any interrupts that
392585025c03Sgd 	 * may occur by temporarily stopping interrupts from occurring
392685025c03Sgd 	 * for a short time.  We need to update the interrupt mask
392785025c03Sgd 	 * later in this function.
39287c478bd9Sstevel@tonic-gate 	 */
392985025c03Sgd 	PUT_GLOBREG(intmask, ~HMEG_MASK_MIF_INTR);
39307c478bd9Sstevel@tonic-gate 
39317c478bd9Sstevel@tonic-gate 
39327c478bd9Sstevel@tonic-gate 	/*
39337c478bd9Sstevel@tonic-gate 	 * Rearranged the mutex acquisition order to solve the deadlock
39347c478bd9Sstevel@tonic-gate 	 * situation as described in bug ID 4065896.
39357c478bd9Sstevel@tonic-gate 	 */
39367c478bd9Sstevel@tonic-gate 
39377c478bd9Sstevel@tonic-gate 	hme_stop_timer(hmep);	/* acquire hme_linklock */
39387c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_xmitlock);
39397c478bd9Sstevel@tonic-gate 
39407c478bd9Sstevel@tonic-gate 	hmep->hme_flags = 0;
394185025c03Sgd 	hmep->hme_wantw = B_FALSE;
39427c478bd9Sstevel@tonic-gate 	hmep->hme_txhung = 0;
39437c478bd9Sstevel@tonic-gate 
39447c478bd9Sstevel@tonic-gate 	/*
39457c478bd9Sstevel@tonic-gate 	 * Initializing 'hmep->hme_iipackets' to match current
39467c478bd9Sstevel@tonic-gate 	 * number of received packets.
39477c478bd9Sstevel@tonic-gate 	 */
39487c478bd9Sstevel@tonic-gate 	hmep->hme_iipackets = hmep->hme_ipackets;
39497c478bd9Sstevel@tonic-gate 
39507c478bd9Sstevel@tonic-gate 	if (hmep->inits)
39517c478bd9Sstevel@tonic-gate 		hmesavecntrs(hmep);
39527c478bd9Sstevel@tonic-gate 
39537c478bd9Sstevel@tonic-gate 	hme_stop_mifpoll(hmep);
39547c478bd9Sstevel@tonic-gate 
39557c478bd9Sstevel@tonic-gate 	/*
39567c478bd9Sstevel@tonic-gate 	 * Perform Global reset of the Sbus/FEPS ENET channel.
39577c478bd9Sstevel@tonic-gate 	 */
39587c478bd9Sstevel@tonic-gate 	(void) hmestop(hmep);
39597c478bd9Sstevel@tonic-gate 
39607c478bd9Sstevel@tonic-gate 	/*
39617c478bd9Sstevel@tonic-gate 	 * Clear all descriptors.
39627c478bd9Sstevel@tonic-gate 	 */
39637c478bd9Sstevel@tonic-gate 	bzero(hmep->hme_rmdp, HME_RMDMAX * sizeof (struct hme_rmd));
39647c478bd9Sstevel@tonic-gate 	bzero(hmep->hme_tmdp, HME_TMDMAX * sizeof (struct hme_tmd));
39657c478bd9Sstevel@tonic-gate 
39667c478bd9Sstevel@tonic-gate 	/*
39677c478bd9Sstevel@tonic-gate 	 * Hang out receive buffers.
39687c478bd9Sstevel@tonic-gate 	 */
3969*0219346bSGarrett D'Amore 	for (i = 0; i < HME_RMDMAX; i++) {
3970*0219346bSGarrett D'Amore 		PUT_RMD(i, hmep->hme_rbuf[i].paddr);
39717c478bd9Sstevel@tonic-gate 	}
39727c478bd9Sstevel@tonic-gate 
39737c478bd9Sstevel@tonic-gate 	/*
39747c478bd9Sstevel@tonic-gate 	 * DMA sync descriptors.
39757c478bd9Sstevel@tonic-gate 	 */
3976*0219346bSGarrett D'Amore 	(void) ddi_dma_sync(hmep->hme_rmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
3977*0219346bSGarrett D'Amore 	(void) ddi_dma_sync(hmep->hme_tmd_dmah, 0, 0, DDI_DMA_SYNC_FORDEV);
39787c478bd9Sstevel@tonic-gate 
39797c478bd9Sstevel@tonic-gate 	/*
39807c478bd9Sstevel@tonic-gate 	 * Reset RMD and TMD 'walking' pointers.
39817c478bd9Sstevel@tonic-gate 	 */
3982*0219346bSGarrett D'Amore 	hmep->hme_rxindex = 0;
3983*0219346bSGarrett D'Amore 	hmep->hme_txindex = hmep->hme_txreclaim = 0;
39847c478bd9Sstevel@tonic-gate 
39857c478bd9Sstevel@tonic-gate 	/*
39867c478bd9Sstevel@tonic-gate 	 * This is the right place to initialize MIF !!!
39877c478bd9Sstevel@tonic-gate 	 */
39887c478bd9Sstevel@tonic-gate 
39897c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_imask, HME_MIF_INTMASK);	/* mask all interrupts */
39907c478bd9Sstevel@tonic-gate 
39917c478bd9Sstevel@tonic-gate 	if (!hmep->hme_frame_enable)
39927c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) | HME_MIF_CFGBB);
39937c478bd9Sstevel@tonic-gate 	else
39947c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_cfg, GET_MIFREG(mif_cfg) & ~HME_MIF_CFGBB);
39957c478bd9Sstevel@tonic-gate 						/* enable frame mode */
39967c478bd9Sstevel@tonic-gate 
39977c478bd9Sstevel@tonic-gate 	/*
39987c478bd9Sstevel@tonic-gate 	 * Depending on the transceiver detected, select the source
39997c478bd9Sstevel@tonic-gate 	 * of the clocks for the MAC. Without the clocks, TX_MAC does
40007c478bd9Sstevel@tonic-gate 	 * not reset. When the Global Reset is issued to the Sbus/FEPS
40017c478bd9Sstevel@tonic-gate 	 * ASIC, it selects Internal by default.
40027c478bd9Sstevel@tonic-gate 	 */
40037c478bd9Sstevel@tonic-gate 
40047c478bd9Sstevel@tonic-gate 	hme_check_transceiver(hmep);
40057c478bd9Sstevel@tonic-gate 	if (hmep->hme_transceiver == HME_NO_TRANSCEIVER) {
40067c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, XCVR_MSG, no_xcvr_msg);
40077c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER);
40087c478bd9Sstevel@tonic-gate 		goto init_fail;	/* abort initialization */
40097c478bd9Sstevel@tonic-gate 
40107c478bd9Sstevel@tonic-gate 	} else if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER)
40117c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, 0);
40127c478bd9Sstevel@tonic-gate 	else
40137c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, BMAC_XIFC_MIIBUFDIS);
40147c478bd9Sstevel@tonic-gate 				/* Isolate the Int. xcvr */
40157c478bd9Sstevel@tonic-gate 	/*
40167c478bd9Sstevel@tonic-gate 	 * Perform transceiver reset and speed selection only if
40177c478bd9Sstevel@tonic-gate 	 * the link is down.
40187c478bd9Sstevel@tonic-gate 	 */
40197c478bd9Sstevel@tonic-gate 	if (!hmep->hme_linkcheck)
40207c478bd9Sstevel@tonic-gate 		/*
40217c478bd9Sstevel@tonic-gate 		 * Reset the PHY and bring up the link
40227c478bd9Sstevel@tonic-gate 		 * If it fails we will then increment a kstat.
40237c478bd9Sstevel@tonic-gate 		 */
40247c478bd9Sstevel@tonic-gate 		hme_reset_transceiver(hmep);
40257c478bd9Sstevel@tonic-gate 	else {
40267c478bd9Sstevel@tonic-gate 		if (hmep->hme_linkup)
40277c478bd9Sstevel@tonic-gate 			hme_start_mifpoll(hmep);
40287c478bd9Sstevel@tonic-gate 		hme_start_timer(hmep, hme_check_link, HME_LINKCHECK_TIMER);
40297c478bd9Sstevel@tonic-gate 	}
40307c478bd9Sstevel@tonic-gate 	hmep->inits++;
40317c478bd9Sstevel@tonic-gate 
40327c478bd9Sstevel@tonic-gate 	/*
40337c478bd9Sstevel@tonic-gate 	 * Initialize BigMAC registers.
40347c478bd9Sstevel@tonic-gate 	 * First set the tx enable bit in tx config reg to 0 and poll on
40357c478bd9Sstevel@tonic-gate 	 * it till it turns to 0. Same for rx config, hash and address
40367c478bd9Sstevel@tonic-gate 	 * filter reg.
40377c478bd9Sstevel@tonic-gate 	 * Here is the sequence per the spec.
40387c478bd9Sstevel@tonic-gate 	 * MADD2 - MAC Address 2
40397c478bd9Sstevel@tonic-gate 	 * MADD1 - MAC Address 1
40407c478bd9Sstevel@tonic-gate 	 * MADD0 - MAC Address 0
40417c478bd9Sstevel@tonic-gate 	 * HASH3, HASH2, HASH1, HASH0 for group address
40427c478bd9Sstevel@tonic-gate 	 * AFR2, AFR1, AFR0 and AFMR for address filter mask
40437c478bd9Sstevel@tonic-gate 	 * Program RXMIN and RXMAX for packet length if not 802.3
40447c478bd9Sstevel@tonic-gate 	 * RXCFG - Rx config for not stripping CRC
40457c478bd9Sstevel@tonic-gate 	 * XXX Anything else to hme configured in RXCFG
40467c478bd9Sstevel@tonic-gate 	 * IPG1, IPG2, ALIMIT, SLOT, PALEN, PAPAT, TXSFD, JAM, TXMAX, TXMIN
40477c478bd9Sstevel@tonic-gate 	 * if not 802.3 compliant
40487c478bd9Sstevel@tonic-gate 	 * XIF register for speed selection
40497c478bd9Sstevel@tonic-gate 	 * MASK  - Interrupt mask
40507c478bd9Sstevel@tonic-gate 	 * Set bit 0 of TXCFG
40517c478bd9Sstevel@tonic-gate 	 * Set bit 0 of RXCFG
40527c478bd9Sstevel@tonic-gate 	 */
40537c478bd9Sstevel@tonic-gate 
40547c478bd9Sstevel@tonic-gate 	/*
40557c478bd9Sstevel@tonic-gate 	 * Initialize the TX_MAC registers
40567c478bd9Sstevel@tonic-gate 	 * Initialization of jamsize to work around rx crc bug
40577c478bd9Sstevel@tonic-gate 	 */
40587c478bd9Sstevel@tonic-gate 	PUT_MACREG(jam, jamsize);
40597c478bd9Sstevel@tonic-gate 
40607c478bd9Sstevel@tonic-gate #ifdef	FEPS_URUN_BUG
40617c478bd9Sstevel@tonic-gate 	if (hme_urun_fix)
40627c478bd9Sstevel@tonic-gate 		PUT_MACREG(palen, hme_palen);
40637c478bd9Sstevel@tonic-gate #endif
40647c478bd9Sstevel@tonic-gate 
40657c478bd9Sstevel@tonic-gate 	PUT_MACREG(ipg1, hme_param_ipg1);
40667c478bd9Sstevel@tonic-gate 	PUT_MACREG(ipg2, hme_param_ipg2);
40677c478bd9Sstevel@tonic-gate 
40687c478bd9Sstevel@tonic-gate 	PUT_MACREG(rseed,
406985025c03Sgd 	    ((hmep->hme_ouraddr.ether_addr_octet[0] << 8) & 0x3) |
407085025c03Sgd 	    hmep->hme_ouraddr.ether_addr_octet[1]);
40717c478bd9Sstevel@tonic-gate 
40727c478bd9Sstevel@tonic-gate 	/* Initialize the RX_MAC registers */
40737c478bd9Sstevel@tonic-gate 
40747c478bd9Sstevel@tonic-gate 	/*
40757c478bd9Sstevel@tonic-gate 	 * Program BigMAC with local individual ethernet address.
40767c478bd9Sstevel@tonic-gate 	 */
40777c478bd9Sstevel@tonic-gate 	PUT_MACREG(madd2, (hmep->hme_ouraddr.ether_addr_octet[4] << 8) |
407885025c03Sgd 	    hmep->hme_ouraddr.ether_addr_octet[5]);
40797c478bd9Sstevel@tonic-gate 	PUT_MACREG(madd1, (hmep->hme_ouraddr.ether_addr_octet[2] << 8) |
408085025c03Sgd 	    hmep->hme_ouraddr.ether_addr_octet[3]);
40817c478bd9Sstevel@tonic-gate 	PUT_MACREG(madd0, (hmep->hme_ouraddr.ether_addr_octet[0] << 8) |
408285025c03Sgd 	    hmep->hme_ouraddr.ether_addr_octet[1]);
40837c478bd9Sstevel@tonic-gate 
40847c478bd9Sstevel@tonic-gate 	/*
40857c478bd9Sstevel@tonic-gate 	 * Set up multicast address filter by passing all multicast
40867c478bd9Sstevel@tonic-gate 	 * addresses through a crc generator, and then using the
40877c478bd9Sstevel@tonic-gate 	 * low order 6 bits as a index into the 64 bit logical
40887c478bd9Sstevel@tonic-gate 	 * address filter. The high order three bits select the word,
40897c478bd9Sstevel@tonic-gate 	 * while the rest of the bits select the bit within the word.
40907c478bd9Sstevel@tonic-gate 	 */
409185025c03Sgd 	PUT_MACREG(hash0, hmep->hme_ladrf[0]);
409285025c03Sgd 	PUT_MACREG(hash1, hmep->hme_ladrf[1]);
409385025c03Sgd 	PUT_MACREG(hash2, hmep->hme_ladrf[2]);
409485025c03Sgd 	PUT_MACREG(hash3, hmep->hme_ladrf[3]);
40957c478bd9Sstevel@tonic-gate 
40967c478bd9Sstevel@tonic-gate 	/*
409785025c03Sgd 	 * Configure parameters to support VLAN.  (VLAN encapsulation adds
409885025c03Sgd 	 * four bytes.)
40997c478bd9Sstevel@tonic-gate 	 */
410085025c03Sgd 	PUT_MACREG(txmax, ETHERMAX + ETHERFCSL + 4);
410185025c03Sgd 	PUT_MACREG(rxmax, ETHERMAX + ETHERFCSL + 4);
41027c478bd9Sstevel@tonic-gate 
41037c478bd9Sstevel@tonic-gate 	/*
41047c478bd9Sstevel@tonic-gate 	 * Initialize HME Global registers, ETX registers and ERX registers.
41057c478bd9Sstevel@tonic-gate 	 */
41067c478bd9Sstevel@tonic-gate 
4107*0219346bSGarrett D'Amore 	PUT_ETXREG(txring, hmep->hme_tmd_paddr);
4108*0219346bSGarrett D'Amore 	PUT_ERXREG(rxring, hmep->hme_rmd_paddr);
41097c478bd9Sstevel@tonic-gate 
41107c478bd9Sstevel@tonic-gate 	/*
41117c478bd9Sstevel@tonic-gate 	 * ERX registers can be written only if they have even no. of bits set.
41127c478bd9Sstevel@tonic-gate 	 * So, if the value written is not read back, set the lsb and write
41137c478bd9Sstevel@tonic-gate 	 * again.
41147c478bd9Sstevel@tonic-gate 	 * static	int	hme_erx_fix = 1;   : Use the fix for erx bug
41157c478bd9Sstevel@tonic-gate 	 */
41167c478bd9Sstevel@tonic-gate 	{
41177c478bd9Sstevel@tonic-gate 		uint32_t temp;
4118*0219346bSGarrett D'Amore 		temp  = hmep->hme_rmd_paddr;
41197c478bd9Sstevel@tonic-gate 
41207c478bd9Sstevel@tonic-gate 		if (GET_ERXREG(rxring) != temp)
41217c478bd9Sstevel@tonic-gate 			PUT_ERXREG(rxring, (temp | 4));
41227c478bd9Sstevel@tonic-gate 	}
41237c478bd9Sstevel@tonic-gate 
412485025c03Sgd 	PUT_GLOBREG(config, (hmep->hme_config |
412585025c03Sgd 	    (hmep->hme_64bit_xfer << HMEG_CONFIG_64BIT_SHIFT)));
41267c478bd9Sstevel@tonic-gate 
41277c478bd9Sstevel@tonic-gate 	/*
41287c478bd9Sstevel@tonic-gate 	 * Significant performance improvements can be achieved by
41297c478bd9Sstevel@tonic-gate 	 * disabling transmit interrupt. Thus TMD's are reclaimed only
41307c478bd9Sstevel@tonic-gate 	 * when we run out of them in hmestart().
41317c478bd9Sstevel@tonic-gate 	 */
41327c478bd9Sstevel@tonic-gate 	PUT_GLOBREG(intmask,
413385025c03Sgd 	    HMEG_MASK_INTR | HMEG_MASK_TINT | HMEG_MASK_TX_ALL);
41347c478bd9Sstevel@tonic-gate 
41357c478bd9Sstevel@tonic-gate 	PUT_ETXREG(txring_size, ((HME_TMDMAX -1)>> HMET_RINGSZ_SHIFT));
41367c478bd9Sstevel@tonic-gate 	PUT_ETXREG(config, (GET_ETXREG(config) | HMET_CONFIG_TXDMA_EN
413785025c03Sgd 	    | HMET_CONFIG_TXFIFOTH));
41387c478bd9Sstevel@tonic-gate 	/* get the rxring size bits */
41397c478bd9Sstevel@tonic-gate 	switch (HME_RMDMAX) {
41407c478bd9Sstevel@tonic-gate 	case 32:
41417c478bd9Sstevel@tonic-gate 		i = HMER_CONFIG_RXRINGSZ32;
41427c478bd9Sstevel@tonic-gate 		break;
41437c478bd9Sstevel@tonic-gate 	case 64:
41447c478bd9Sstevel@tonic-gate 		i = HMER_CONFIG_RXRINGSZ64;
41457c478bd9Sstevel@tonic-gate 		break;
41467c478bd9Sstevel@tonic-gate 	case 128:
41477c478bd9Sstevel@tonic-gate 		i = HMER_CONFIG_RXRINGSZ128;
41487c478bd9Sstevel@tonic-gate 		break;
41497c478bd9Sstevel@tonic-gate 	case 256:
41507c478bd9Sstevel@tonic-gate 		i = HMER_CONFIG_RXRINGSZ256;
41517c478bd9Sstevel@tonic-gate 		break;
41527c478bd9Sstevel@tonic-gate 	default:
41537c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
415485025c03Sgd 		    unk_rx_ringsz_msg);
41557c478bd9Sstevel@tonic-gate 		goto init_fail;
41567c478bd9Sstevel@tonic-gate 	}
41577c478bd9Sstevel@tonic-gate 	i |= (HME_FSTBYTE_OFFSET << HMER_CONFIG_FBO_SHIFT)
415885025c03Sgd 	    | HMER_CONFIG_RXDMA_EN;
415985025c03Sgd 
416085025c03Sgd 	/* h/w checks start offset in half words */
416185025c03Sgd 	i |= ((sizeof (struct ether_header) / 2) << HMER_RX_CSSTART_SHIFT);
416285025c03Sgd 
41637c478bd9Sstevel@tonic-gate 	PUT_ERXREG(config, i);
41647c478bd9Sstevel@tonic-gate 
41657c478bd9Sstevel@tonic-gate 	/*
41667c478bd9Sstevel@tonic-gate 	 * Bug related to the parity handling in ERX. When erxp-config is
41677c478bd9Sstevel@tonic-gate 	 * read back.
41687c478bd9Sstevel@tonic-gate 	 * Sbus/FEPS drives the parity bit. This value is used while
41697c478bd9Sstevel@tonic-gate 	 * writing again.
41707c478bd9Sstevel@tonic-gate 	 * This fixes the RECV problem in SS5.
41717c478bd9Sstevel@tonic-gate 	 * static	int	hme_erx_fix = 1;   : Use the fix for erx bug
41727c478bd9Sstevel@tonic-gate 	 */
41737c478bd9Sstevel@tonic-gate 	{
41747c478bd9Sstevel@tonic-gate 		uint32_t temp;
41757c478bd9Sstevel@tonic-gate 		temp = GET_ERXREG(config);
41767c478bd9Sstevel@tonic-gate 		PUT_ERXREG(config, i);
41777c478bd9Sstevel@tonic-gate 
41787c478bd9Sstevel@tonic-gate 		if (GET_ERXREG(config) != i)
41797c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG4(hmep, SEVERITY_UNKNOWN, ERX_MSG,
418085025c03Sgd 			    "error:temp = %x erxp->config = %x, should be %x",
418185025c03Sgd 			    temp, GET_ERXREG(config), i);
41827c478bd9Sstevel@tonic-gate 	}
41837c478bd9Sstevel@tonic-gate 
41847c478bd9Sstevel@tonic-gate 	/*
41857c478bd9Sstevel@tonic-gate 	 * Set up the rxconfig, txconfig and seed register without enabling
41867c478bd9Sstevel@tonic-gate 	 * them the former two at this time
41877c478bd9Sstevel@tonic-gate 	 *
41887c478bd9Sstevel@tonic-gate 	 * BigMAC strips the CRC bytes by default. Since this is
41897c478bd9Sstevel@tonic-gate 	 * contrary to other pieces of hardware, this bit needs to
41907c478bd9Sstevel@tonic-gate 	 * enabled to tell BigMAC not to strip the CRC bytes.
41917c478bd9Sstevel@tonic-gate 	 * Do not filter this node's own packets.
41927c478bd9Sstevel@tonic-gate 	 */
41937c478bd9Sstevel@tonic-gate 
41947c478bd9Sstevel@tonic-gate 	if (hme_reject_own) {
41957c478bd9Sstevel@tonic-gate 		PUT_MACREG(rxcfg,
4196228fdff0Sgd 		    ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) |
419785025c03Sgd 		    BMAC_RXCFG_MYOWN | BMAC_RXCFG_HASH));
41987c478bd9Sstevel@tonic-gate 	} else {
41997c478bd9Sstevel@tonic-gate 		PUT_MACREG(rxcfg,
4200228fdff0Sgd 		    ((hmep->hme_promisc ? BMAC_RXCFG_PROMIS : 0) |
420185025c03Sgd 		    BMAC_RXCFG_HASH));
42027c478bd9Sstevel@tonic-gate 	}
42037c478bd9Sstevel@tonic-gate 
42047c478bd9Sstevel@tonic-gate 	drv_usecwait(10);	/* wait after setting Hash Enable bit */
42057c478bd9Sstevel@tonic-gate 
42067c478bd9Sstevel@tonic-gate 	if (hme_ngu_enable)
42077c478bd9Sstevel@tonic-gate 		PUT_MACREG(txcfg, (hmep->hme_fdx ? BMAC_TXCFG_FDX: 0) |
420885025c03Sgd 		    BMAC_TXCFG_NGU);
42097c478bd9Sstevel@tonic-gate 	else
42107c478bd9Sstevel@tonic-gate 		PUT_MACREG(txcfg, (hmep->hme_fdx ? BMAC_TXCFG_FDX: 0));
42117c478bd9Sstevel@tonic-gate 	hmep->hme_macfdx = hmep->hme_fdx;
42127c478bd9Sstevel@tonic-gate 
42137c478bd9Sstevel@tonic-gate 
42147c478bd9Sstevel@tonic-gate 	i = 0;
42157c478bd9Sstevel@tonic-gate 	if ((hme_param_lance_mode) && (hmep->hme_lance_mode_enable))
42167c478bd9Sstevel@tonic-gate 		i = ((hme_param_ipg0 & HME_MASK_5BIT) << BMAC_XIFC_IPG0_SHIFT)
421785025c03Sgd 		    | BMAC_XIFC_LANCE_ENAB;
42187c478bd9Sstevel@tonic-gate 	if (hmep->hme_transceiver == HME_INTERNAL_TRANSCEIVER)
42197c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB));
42207c478bd9Sstevel@tonic-gate 	else
42217c478bd9Sstevel@tonic-gate 		PUT_MACREG(xifc, i | (BMAC_XIFC_ENAB | BMAC_XIFC_MIIBUFDIS));
42227c478bd9Sstevel@tonic-gate 
42237c478bd9Sstevel@tonic-gate 	PUT_MACREG(rxcfg, GET_MACREG(rxcfg) | BMAC_RXCFG_ENAB);
42247c478bd9Sstevel@tonic-gate 	PUT_MACREG(txcfg, GET_MACREG(txcfg) | BMAC_TXCFG_ENAB);
42257c478bd9Sstevel@tonic-gate 
42267c478bd9Sstevel@tonic-gate 	hmep->hme_flags |= (HMERUNNING | HMEINITIALIZED);
42277c478bd9Sstevel@tonic-gate 	/*
42287c478bd9Sstevel@tonic-gate 	 * Update the interrupt mask : this will re-allow interrupts to occur
42297c478bd9Sstevel@tonic-gate 	 */
423085025c03Sgd 	PUT_GLOBREG(intmask, HMEG_MASK_INTR);
423185025c03Sgd 	mac_tx_update(hmep->hme_mh);
42327c478bd9Sstevel@tonic-gate 
42337c478bd9Sstevel@tonic-gate init_fail:
42347c478bd9Sstevel@tonic-gate 	/*
42357c478bd9Sstevel@tonic-gate 	 * Release the locks in reverse order
42367c478bd9Sstevel@tonic-gate 	 */
42377c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_xmitlock);
42387c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_intrlock);
42397c478bd9Sstevel@tonic-gate 
42407c478bd9Sstevel@tonic-gate 	ret = !(hmep->hme_flags & HMERUNNING);
42417c478bd9Sstevel@tonic-gate 	if (ret) {
42427c478bd9Sstevel@tonic-gate 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
424385025c03Sgd 		    init_fail_gen_msg);
42447c478bd9Sstevel@tonic-gate 	}
42457c478bd9Sstevel@tonic-gate 
42467c478bd9Sstevel@tonic-gate 	/*
42477c478bd9Sstevel@tonic-gate 	 * Hardware checks.
42487c478bd9Sstevel@tonic-gate 	 */
42497c478bd9Sstevel@tonic-gate 	CHECK_GLOBREG();
42507c478bd9Sstevel@tonic-gate 	CHECK_MIFREG();
42517c478bd9Sstevel@tonic-gate 	CHECK_MACREG();
42527c478bd9Sstevel@tonic-gate 	CHECK_ERXREG();
42537c478bd9Sstevel@tonic-gate 	CHECK_ETXREG();
42547c478bd9Sstevel@tonic-gate 
42557c478bd9Sstevel@tonic-gate init_exit:
42567c478bd9Sstevel@tonic-gate 	return (ret);
42577c478bd9Sstevel@tonic-gate }
42587c478bd9Sstevel@tonic-gate 
42597c478bd9Sstevel@tonic-gate /*
42607c478bd9Sstevel@tonic-gate  * Calculate the dvma burstsize by setting up a dvma temporarily.  Return
42617c478bd9Sstevel@tonic-gate  * 0 as burstsize upon failure as it signifies no burst size.
42627c478bd9Sstevel@tonic-gate  * Requests for 64-bit transfer setup, if the platform supports it.
42637c478bd9Sstevel@tonic-gate  * NOTE: Do not use ddi_dma_alloc_handle(9f) then ddi_dma_burstsize(9f),
42647c478bd9Sstevel@tonic-gate  * sun4u Ultra-2 incorrectly returns a 32bit transfer.
42657c478bd9Sstevel@tonic-gate  */
42667c478bd9Sstevel@tonic-gate static int
42677c478bd9Sstevel@tonic-gate hmeburstsizes(struct hme *hmep)
42687c478bd9Sstevel@tonic-gate {
42697c478bd9Sstevel@tonic-gate 	int burstsizes;
42707c478bd9Sstevel@tonic-gate 	ddi_dma_handle_t handle;
42717c478bd9Sstevel@tonic-gate 
42727c478bd9Sstevel@tonic-gate 	if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr,
42737c478bd9Sstevel@tonic-gate 	    DDI_DMA_DONTWAIT, NULL, &handle)) {
42747c478bd9Sstevel@tonic-gate 		return (0);
42757c478bd9Sstevel@tonic-gate 	}
42767c478bd9Sstevel@tonic-gate 
42777c478bd9Sstevel@tonic-gate 	hmep->hme_burstsizes = burstsizes = ddi_dma_burstsizes(handle);
42787c478bd9Sstevel@tonic-gate 	ddi_dma_free_handle(&handle);
42797c478bd9Sstevel@tonic-gate 
42807c478bd9Sstevel@tonic-gate 	/*
42817c478bd9Sstevel@tonic-gate 	 * Use user-configurable parameter for enabling 64-bit transfers
42827c478bd9Sstevel@tonic-gate 	 */
42837c478bd9Sstevel@tonic-gate 	burstsizes = (hmep->hme_burstsizes >> 16);
42847c478bd9Sstevel@tonic-gate 	if (burstsizes)
42857c478bd9Sstevel@tonic-gate 		hmep->hme_64bit_xfer = hme_64bit_enable; /* user config value */
42867c478bd9Sstevel@tonic-gate 	else
42877c478bd9Sstevel@tonic-gate 		burstsizes = hmep->hme_burstsizes;
42887c478bd9Sstevel@tonic-gate 
42897c478bd9Sstevel@tonic-gate 	if (hmep->hme_cheerio_mode)
42907c478bd9Sstevel@tonic-gate 		hmep->hme_64bit_xfer = 0; /* Disable for cheerio */
42917c478bd9Sstevel@tonic-gate 
42927c478bd9Sstevel@tonic-gate 	if (burstsizes & 0x40)
42937c478bd9Sstevel@tonic-gate 		hmep->hme_config = HMEG_CONFIG_BURST64;
42947c478bd9Sstevel@tonic-gate 	else if (burstsizes & 0x20)
42957c478bd9Sstevel@tonic-gate 		hmep->hme_config = HMEG_CONFIG_BURST32;
42967c478bd9Sstevel@tonic-gate 	else
42977c478bd9Sstevel@tonic-gate 		hmep->hme_config = HMEG_CONFIG_BURST16;
42987c478bd9Sstevel@tonic-gate 
4299*0219346bSGarrett D'Amore 	return (DDI_SUCCESS);
4300*0219346bSGarrett D'Amore }
4301*0219346bSGarrett D'Amore 
4302*0219346bSGarrett D'Amore static int
4303*0219346bSGarrett D'Amore hmeallocbuf(struct hme *hmep, hmebuf_t *buf, int dir)
4304*0219346bSGarrett D'Amore {
4305*0219346bSGarrett D'Amore 	ddi_dma_cookie_t	dmac;
4306*0219346bSGarrett D'Amore 	size_t			len;
4307*0219346bSGarrett D'Amore 	unsigned		ccnt;
4308*0219346bSGarrett D'Amore 
4309*0219346bSGarrett D'Amore 	if (ddi_dma_alloc_handle(hmep->dip, &hme_dma_attr,
4310*0219346bSGarrett D'Amore 	    DDI_DMA_DONTWAIT, NULL, &buf->dmah) != DDI_SUCCESS) {
4311*0219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
4312*0219346bSGarrett D'Amore 		    "cannot allocate buf dma handle - failed");
4313*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
4314*0219346bSGarrett D'Amore 	}
4315*0219346bSGarrett D'Amore 
4316*0219346bSGarrett D'Amore 	if (ddi_dma_mem_alloc(buf->dmah, ROUNDUP(HMEBUFSIZE, 512),
4317*0219346bSGarrett D'Amore 	    &hme_buf_attr, DDI_DMA_STREAMING, DDI_DMA_DONTWAIT, NULL,
4318*0219346bSGarrett D'Amore 	    &buf->kaddr, &len, &buf->acch) != DDI_SUCCESS) {
4319*0219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
4320*0219346bSGarrett D'Amore 		    "cannot allocate buf memory - failed");
4321*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
4322*0219346bSGarrett D'Amore 	}
4323*0219346bSGarrett D'Amore 
4324*0219346bSGarrett D'Amore 	if (ddi_dma_addr_bind_handle(buf->dmah, NULL, buf->kaddr,
4325*0219346bSGarrett D'Amore 	    len, dir | DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
4326*0219346bSGarrett D'Amore 	    &dmac, &ccnt) != DDI_DMA_MAPPED) {
4327*0219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
4328*0219346bSGarrett D'Amore 		    "cannot map buf for dma - failed");
4329*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
4330*0219346bSGarrett D'Amore 	}
4331*0219346bSGarrett D'Amore 	buf->paddr = dmac.dmac_address;
4332*0219346bSGarrett D'Amore 
4333*0219346bSGarrett D'Amore 	/* apparently they don't handle multiple cookies */
4334*0219346bSGarrett D'Amore 	if (ccnt > 1) {
4335*0219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
4336*0219346bSGarrett D'Amore 		    "too many buf dma cookies");
4337*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
4338*0219346bSGarrett D'Amore 	}
4339*0219346bSGarrett D'Amore 	return (DDI_SUCCESS);
4340*0219346bSGarrett D'Amore }
4341*0219346bSGarrett D'Amore 
4342*0219346bSGarrett D'Amore static int
4343*0219346bSGarrett D'Amore hmeallocbufs(struct hme *hmep)
4344*0219346bSGarrett D'Amore {
4345*0219346bSGarrett D'Amore 	hmep->hme_tbuf = kmem_zalloc(HME_TMDMAX * sizeof (hmebuf_t), KM_SLEEP);
4346*0219346bSGarrett D'Amore 	hmep->hme_rbuf = kmem_zalloc(HME_RMDMAX * sizeof (hmebuf_t), KM_SLEEP);
4347*0219346bSGarrett D'Amore 
4348*0219346bSGarrett D'Amore 	/* Alloc RX buffers. */
4349*0219346bSGarrett D'Amore 	for (int i = 0; i < HME_RMDMAX; i++) {
4350*0219346bSGarrett D'Amore 		if (hmeallocbuf(hmep, &hmep->hme_rbuf[i], DDI_DMA_READ) !=
4351*0219346bSGarrett D'Amore 		    DDI_SUCCESS) {
4352*0219346bSGarrett D'Amore 			return (DDI_FAILURE);
4353*0219346bSGarrett D'Amore 		}
4354*0219346bSGarrett D'Amore 	}
4355*0219346bSGarrett D'Amore 
4356*0219346bSGarrett D'Amore 	/* Alloc TX buffers. */
4357*0219346bSGarrett D'Amore 	for (int i = 0; i < HME_TMDMAX; i++) {
4358*0219346bSGarrett D'Amore 		if (hmeallocbuf(hmep, &hmep->hme_tbuf[i], DDI_DMA_WRITE) !=
4359*0219346bSGarrett D'Amore 		    DDI_SUCCESS) {
4360*0219346bSGarrett D'Amore 			return (DDI_FAILURE);
4361*0219346bSGarrett D'Amore 		}
4362*0219346bSGarrett D'Amore 	}
43637c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
43647c478bd9Sstevel@tonic-gate }
43657c478bd9Sstevel@tonic-gate 
43667c478bd9Sstevel@tonic-gate static void
43677c478bd9Sstevel@tonic-gate hmefreebufs(struct hme *hmep)
43687c478bd9Sstevel@tonic-gate {
43697c478bd9Sstevel@tonic-gate 	int i;
4370*0219346bSGarrett D'Amore 
4371*0219346bSGarrett D'Amore 	if (hmep->hme_rbuf == NULL)
4372*0219346bSGarrett D'Amore 		return;
43737c478bd9Sstevel@tonic-gate 
43747c478bd9Sstevel@tonic-gate 	/*
4375*0219346bSGarrett D'Amore 	 * Free and unload pending xmit and recv buffers.
43767c478bd9Sstevel@tonic-gate 	 * Maintaining the 1-to-1 ordered sequence of
4377*0219346bSGarrett D'Amore 	 * We have written the routine to be idempotent.
43787c478bd9Sstevel@tonic-gate 	 */
43797c478bd9Sstevel@tonic-gate 
43807c478bd9Sstevel@tonic-gate 	for (i = 0; i < HME_TMDMAX; i++) {
4381*0219346bSGarrett D'Amore 		hmebuf_t *tbuf = &hmep->hme_tbuf[i];
4382*0219346bSGarrett D'Amore 		if (tbuf->paddr) {
4383*0219346bSGarrett D'Amore 			(void) ddi_dma_unbind_handle(tbuf->dmah);
4384*0219346bSGarrett D'Amore 		}
4385*0219346bSGarrett D'Amore 		if (tbuf->kaddr) {
4386*0219346bSGarrett D'Amore 			ddi_dma_mem_free(&tbuf->acch);
4387*0219346bSGarrett D'Amore 		}
4388*0219346bSGarrett D'Amore 		if (tbuf->dmah) {
4389*0219346bSGarrett D'Amore 			ddi_dma_free_handle(&tbuf->dmah);
43907c478bd9Sstevel@tonic-gate 		}
43917c478bd9Sstevel@tonic-gate 	}
43927c478bd9Sstevel@tonic-gate 	for (i = 0; i < HME_RMDMAX; i++) {
4393*0219346bSGarrett D'Amore 		hmebuf_t *rbuf = &hmep->hme_rbuf[i];
4394*0219346bSGarrett D'Amore 		if (rbuf->paddr) {
4395*0219346bSGarrett D'Amore 			(void) ddi_dma_unbind_handle(rbuf->dmah);
4396*0219346bSGarrett D'Amore 		}
4397*0219346bSGarrett D'Amore 		if (rbuf->kaddr) {
4398*0219346bSGarrett D'Amore 			ddi_dma_mem_free(&rbuf->acch);
4399*0219346bSGarrett D'Amore 		}
4400*0219346bSGarrett D'Amore 		if (rbuf->dmah) {
4401*0219346bSGarrett D'Amore 			ddi_dma_free_handle(&rbuf->dmah);
44027c478bd9Sstevel@tonic-gate 		}
44037c478bd9Sstevel@tonic-gate 	}
4404*0219346bSGarrett D'Amore 	kmem_free(hmep->hme_rbuf, HME_RMDMAX * sizeof (hmebuf_t));
4405*0219346bSGarrett D'Amore 	kmem_free(hmep->hme_tbuf, HME_TMDMAX * sizeof (hmebuf_t));
44067c478bd9Sstevel@tonic-gate }
44077c478bd9Sstevel@tonic-gate 
44087c478bd9Sstevel@tonic-gate /*
44097c478bd9Sstevel@tonic-gate  * hme_start_mifpoll() - Enables the polling of the BMSR register of the PHY.
44107c478bd9Sstevel@tonic-gate  * After enabling the poll, delay for atleast 62us for one poll to be done.
44117c478bd9Sstevel@tonic-gate  * Then read the MIF status register to auto-clear the MIF status field.
44127c478bd9Sstevel@tonic-gate  * Then program the MIF interrupt mask register to enable interrupts for the
44137c478bd9Sstevel@tonic-gate  * LINK_STATUS and JABBER_DETECT bits.
44147c478bd9Sstevel@tonic-gate  */
44157c478bd9Sstevel@tonic-gate 
44167c478bd9Sstevel@tonic-gate static void
44177c478bd9Sstevel@tonic-gate hme_start_mifpoll(struct hme *hmep)
44187c478bd9Sstevel@tonic-gate {
44197c478bd9Sstevel@tonic-gate 	uint32_t cfg;
44207c478bd9Sstevel@tonic-gate 
44217c478bd9Sstevel@tonic-gate 	if (!hmep->hme_mifpoll_enable)
44227c478bd9Sstevel@tonic-gate 		return;
44237c478bd9Sstevel@tonic-gate 
44247c478bd9Sstevel@tonic-gate 	cfg = (GET_MIFREG(mif_cfg) & ~(HME_MIF_CFGPD | HME_MIF_CFGPR));
44257c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_cfg,
442685025c03Sgd 	    (cfg = (cfg | (hmep->hme_phyad << HME_MIF_CFGPD_SHIFT) |
442785025c03Sgd 	    (HME_PHY_BMSR << HME_MIF_CFGPR_SHIFT) | HME_MIF_CFGPE)));
44287c478bd9Sstevel@tonic-gate 
44297c478bd9Sstevel@tonic-gate 	drv_usecwait(HME_MIF_POLL_DELAY);
44307c478bd9Sstevel@tonic-gate 	hmep->hme_polling_on =		1;
44317c478bd9Sstevel@tonic-gate 	hmep->hme_mifpoll_flag =	0;
44327c478bd9Sstevel@tonic-gate 	hmep->hme_mifpoll_data =	(GET_MIFREG(mif_bsts) >> 16);
44337c478bd9Sstevel@tonic-gate 
44347c478bd9Sstevel@tonic-gate 	/* Do not poll for Jabber Detect for 100 Mbps speed */
44357c478bd9Sstevel@tonic-gate 	if (((hmep->hme_mode == HME_AUTO_SPEED) &&
443685025c03Sgd 	    (hmep->hme_tryspeed == HME_SPEED_100)) ||
443785025c03Sgd 	    ((hmep->hme_mode == HME_FORCE_SPEED) &&
443885025c03Sgd 	    (hmep->hme_forcespeed == HME_SPEED_100)))
44397c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_imask, ((uint16_t)~(PHY_BMSR_LNKSTS)));
44407c478bd9Sstevel@tonic-gate 	else
44417c478bd9Sstevel@tonic-gate 		PUT_MIFREG(mif_imask,
444285025c03Sgd 		    (uint16_t)~(PHY_BMSR_LNKSTS | PHY_BMSR_JABDET));
44437c478bd9Sstevel@tonic-gate 
44447c478bd9Sstevel@tonic-gate 	CHECK_MIFREG();
44457c478bd9Sstevel@tonic-gate }
44467c478bd9Sstevel@tonic-gate 
44477c478bd9Sstevel@tonic-gate static void
44487c478bd9Sstevel@tonic-gate hme_stop_mifpoll(struct hme *hmep)
44497c478bd9Sstevel@tonic-gate {
44507c478bd9Sstevel@tonic-gate 	if ((!hmep->hme_mifpoll_enable) || (!hmep->hme_polling_on))
44517c478bd9Sstevel@tonic-gate 		return;
44527c478bd9Sstevel@tonic-gate 
44537c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_imask, 0xffff);	/* mask interrupts */
44547c478bd9Sstevel@tonic-gate 	PUT_MIFREG(mif_cfg, (GET_MIFREG(mif_cfg) & ~HME_MIF_CFGPE));
44557c478bd9Sstevel@tonic-gate 
44567c478bd9Sstevel@tonic-gate 	hmep->hme_polling_on = 0;
44577c478bd9Sstevel@tonic-gate 	drv_usecwait(HME_MIF_POLL_DELAY);
44587c478bd9Sstevel@tonic-gate 	CHECK_MIFREG();
44597c478bd9Sstevel@tonic-gate }
44607c478bd9Sstevel@tonic-gate 
44617c478bd9Sstevel@tonic-gate /*
44627c478bd9Sstevel@tonic-gate  * Un-initialize (STOP) HME channel.
44637c478bd9Sstevel@tonic-gate  */
44647c478bd9Sstevel@tonic-gate static void
44657c478bd9Sstevel@tonic-gate hmeuninit(struct hme *hmep)
44667c478bd9Sstevel@tonic-gate {
44677c478bd9Sstevel@tonic-gate 	/*
44687c478bd9Sstevel@tonic-gate 	 * Allow up to 'HMEDRAINTIME' for pending xmit's to complete.
44697c478bd9Sstevel@tonic-gate 	 */
4470*0219346bSGarrett D'Amore 	HMEDELAY((hmep->hme_txindex == hmep->hme_txreclaim), HMEDRAINTIME);
44717c478bd9Sstevel@tonic-gate 
44727c478bd9Sstevel@tonic-gate 	hme_stop_timer(hmep);   /* acquire hme_linklock */
44737c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_linklock);
44747c478bd9Sstevel@tonic-gate 
44757c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_intrlock);
44767c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_xmitlock);
44777c478bd9Sstevel@tonic-gate 
44787c478bd9Sstevel@tonic-gate 	hme_stop_mifpoll(hmep);
44797c478bd9Sstevel@tonic-gate 
44807c478bd9Sstevel@tonic-gate 	hmep->hme_flags &= ~HMERUNNING;
44817c478bd9Sstevel@tonic-gate 
44827c478bd9Sstevel@tonic-gate 	(void) hmestop(hmep);
44837c478bd9Sstevel@tonic-gate 
44847c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_xmitlock);
44857c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_intrlock);
44867c478bd9Sstevel@tonic-gate }
44877c478bd9Sstevel@tonic-gate 
44887c478bd9Sstevel@tonic-gate /*
44897c478bd9Sstevel@tonic-gate  * Allocate CONSISTENT memory for rmds and tmds with appropriate alignment and
44907c478bd9Sstevel@tonic-gate  * map it in IO space. Allocate space for transmit and receive ddi_dma_handle
44917c478bd9Sstevel@tonic-gate  * structures to use the DMA interface.
44927c478bd9Sstevel@tonic-gate  */
44937c478bd9Sstevel@tonic-gate static int
44947c478bd9Sstevel@tonic-gate hmeallocthings(struct hme *hmep)
44957c478bd9Sstevel@tonic-gate {
4496*0219346bSGarrett D'Amore 	int			size;
4497*0219346bSGarrett D'Amore 	int			rval;
4498*0219346bSGarrett D'Amore 	size_t			real_len;
4499*0219346bSGarrett D'Amore 	uint_t			cookiec;
4500*0219346bSGarrett D'Amore 	ddi_dma_cookie_t	dmac;
4501*0219346bSGarrett D'Amore 	dev_info_t		*dip = hmep->dip;
45027c478bd9Sstevel@tonic-gate 
45037c478bd9Sstevel@tonic-gate 	/*
45047c478bd9Sstevel@tonic-gate 	 * Allocate the TMD and RMD descriptors and extra for page alignment.
45057c478bd9Sstevel@tonic-gate 	 */
45067c478bd9Sstevel@tonic-gate 
4507*0219346bSGarrett D'Amore 	rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL,
4508*0219346bSGarrett D'Amore 	    &hmep->hme_rmd_dmah);
45097c478bd9Sstevel@tonic-gate 	if (rval != DDI_SUCCESS) {
451085025c03Sgd 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
451185025c03Sgd 		    "cannot allocate rmd handle - failed");
4512*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
45137c478bd9Sstevel@tonic-gate 	}
4514*0219346bSGarrett D'Amore 	size = HME_RMDMAX * sizeof (struct hme_rmd);
4515*0219346bSGarrett D'Amore 	rval = ddi_dma_mem_alloc(hmep->hme_rmd_dmah, size,
4516*0219346bSGarrett D'Amore 	    &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
4517*0219346bSGarrett D'Amore 	    &hmep->hme_rmd_kaddr, &real_len, &hmep->hme_rmd_acch);
45187c478bd9Sstevel@tonic-gate 	if (rval != DDI_SUCCESS) {
451985025c03Sgd 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
4520*0219346bSGarrett D'Amore 		    "cannot allocate rmd dma mem - failed");
4521*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
45227c478bd9Sstevel@tonic-gate 	}
4523*0219346bSGarrett D'Amore 	hmep->hme_rmdp = (void *)(hmep->hme_rmd_kaddr);
4524*0219346bSGarrett D'Amore 	rval = ddi_dma_addr_bind_handle(hmep->hme_rmd_dmah, NULL,
4525*0219346bSGarrett D'Amore 	    hmep->hme_rmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
4526*0219346bSGarrett D'Amore 	    DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec);
45277c478bd9Sstevel@tonic-gate 	if (rval != DDI_DMA_MAPPED) {
452885025c03Sgd 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
4529*0219346bSGarrett D'Amore 		    "cannot allocate rmd dma - failed");
4530*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
45317c478bd9Sstevel@tonic-gate 	}
4532*0219346bSGarrett D'Amore 	hmep->hme_rmd_paddr = dmac.dmac_address;
45337c478bd9Sstevel@tonic-gate 	if (cookiec != 1) {
453485025c03Sgd 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
4535*0219346bSGarrett D'Amore 		    "too many rmd cookies - failed");
4536*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
45377c478bd9Sstevel@tonic-gate 	}
45387c478bd9Sstevel@tonic-gate 
4539*0219346bSGarrett D'Amore 	rval = ddi_dma_alloc_handle(dip, &hme_dma_attr, DDI_DMA_DONTWAIT, NULL,
4540*0219346bSGarrett D'Amore 	    &hmep->hme_tmd_dmah);
4541*0219346bSGarrett D'Amore 	if (rval != DDI_SUCCESS) {
4542*0219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
4543*0219346bSGarrett D'Amore 		    "cannot allocate tmd handle - failed");
4544*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
4545*0219346bSGarrett D'Amore 	}
4546*0219346bSGarrett D'Amore 	size = HME_TMDMAX * sizeof (struct hme_rmd);
4547*0219346bSGarrett D'Amore 	rval = ddi_dma_mem_alloc(hmep->hme_tmd_dmah, size,
4548*0219346bSGarrett D'Amore 	    &hmep->hme_dev_attr, DDI_DMA_CONSISTENT, DDI_DMA_DONTWAIT, NULL,
4549*0219346bSGarrett D'Amore 	    &hmep->hme_tmd_kaddr, &real_len, &hmep->hme_tmd_acch);
4550*0219346bSGarrett D'Amore 	if (rval != DDI_SUCCESS) {
4551*0219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
4552*0219346bSGarrett D'Amore 		    "cannot allocate tmd dma mem - failed");
4553*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
4554*0219346bSGarrett D'Amore 	}
4555*0219346bSGarrett D'Amore 	hmep->hme_tmdp = (void *)(hmep->hme_tmd_kaddr);
4556*0219346bSGarrett D'Amore 	rval = ddi_dma_addr_bind_handle(hmep->hme_tmd_dmah, NULL,
4557*0219346bSGarrett D'Amore 	    hmep->hme_tmd_kaddr, size, DDI_DMA_RDWR | DDI_DMA_CONSISTENT,
4558*0219346bSGarrett D'Amore 	    DDI_DMA_DONTWAIT, NULL, &dmac, &cookiec);
4559*0219346bSGarrett D'Amore 	if (rval != DDI_DMA_MAPPED) {
4560*0219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
4561*0219346bSGarrett D'Amore 		    "cannot allocate tmd dma - failed");
4562*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
4563*0219346bSGarrett D'Amore 	}
4564*0219346bSGarrett D'Amore 	hmep->hme_tmd_paddr = dmac.dmac_address;
4565*0219346bSGarrett D'Amore 	if (cookiec != 1) {
4566*0219346bSGarrett D'Amore 		HME_FAULT_MSG1(hmep, SEVERITY_HIGH, INIT_MSG,
4567*0219346bSGarrett D'Amore 		    "too many tmd cookies - failed");
4568*0219346bSGarrett D'Amore 		return (DDI_FAILURE);
45697c478bd9Sstevel@tonic-gate 	}
45707c478bd9Sstevel@tonic-gate 
4571*0219346bSGarrett D'Amore 	return (DDI_SUCCESS);
45727c478bd9Sstevel@tonic-gate }
45737c478bd9Sstevel@tonic-gate 
4574*0219346bSGarrett D'Amore static void
4575*0219346bSGarrett D'Amore hmefreethings(struct hme *hmep)
4576*0219346bSGarrett D'Amore {
4577*0219346bSGarrett D'Amore 	if (hmep->hme_rmd_paddr) {
4578*0219346bSGarrett D'Amore 		(void) ddi_dma_unbind_handle(hmep->hme_rmd_dmah);
4579*0219346bSGarrett D'Amore 		hmep->hme_rmd_paddr = 0;
4580*0219346bSGarrett D'Amore 	}
4581*0219346bSGarrett D'Amore 	if (hmep->hme_rmd_acch)
4582*0219346bSGarrett D'Amore 		ddi_dma_mem_free(&hmep->hme_rmd_acch);
4583*0219346bSGarrett D'Amore 	if (hmep->hme_rmd_dmah)
4584*0219346bSGarrett D'Amore 		ddi_dma_free_handle(&hmep->hme_rmd_dmah);
4585*0219346bSGarrett D'Amore 
4586*0219346bSGarrett D'Amore 	if (hmep->hme_tmd_paddr) {
4587*0219346bSGarrett D'Amore 		(void) ddi_dma_unbind_handle(hmep->hme_tmd_dmah);
4588*0219346bSGarrett D'Amore 		hmep->hme_tmd_paddr = 0;
4589*0219346bSGarrett D'Amore 	}
4590*0219346bSGarrett D'Amore 	if (hmep->hme_tmd_acch)
4591*0219346bSGarrett D'Amore 		ddi_dma_mem_free(&hmep->hme_tmd_acch);
4592*0219346bSGarrett D'Amore 	if (hmep->hme_tmd_dmah)
4593*0219346bSGarrett D'Amore 		ddi_dma_free_handle(&hmep->hme_tmd_dmah);
4594*0219346bSGarrett D'Amore }
45957c478bd9Sstevel@tonic-gate 
45967c478bd9Sstevel@tonic-gate /*
45977c478bd9Sstevel@tonic-gate  *	First check to see if it our device interrupting.
45987c478bd9Sstevel@tonic-gate  */
45997c478bd9Sstevel@tonic-gate static uint_t
460085025c03Sgd hmeintr(caddr_t arg)
46017c478bd9Sstevel@tonic-gate {
460285025c03Sgd 	struct hme	*hmep = (void *)arg;
46037c478bd9Sstevel@tonic-gate 	uint32_t	hmesbits;
46047c478bd9Sstevel@tonic-gate 	uint32_t	mif_status;
46057c478bd9Sstevel@tonic-gate 	uint32_t	serviced = DDI_INTR_UNCLAIMED;
46067c478bd9Sstevel@tonic-gate 	uint32_t	num_reads = 0;
460785025c03Sgd 	uint32_t	rflags;
460885025c03Sgd 	mblk_t		*mp, *head, **tail;
46097c478bd9Sstevel@tonic-gate 
46107c478bd9Sstevel@tonic-gate 
461185025c03Sgd 	head = NULL;
461285025c03Sgd 	tail = &head;
46137c478bd9Sstevel@tonic-gate 
46147c478bd9Sstevel@tonic-gate 	mutex_enter(&hmep->hme_intrlock);
46157c478bd9Sstevel@tonic-gate 
46167c478bd9Sstevel@tonic-gate 	/*
46177c478bd9Sstevel@tonic-gate 	 * The status register auto-clears on read except for
46187c478bd9Sstevel@tonic-gate 	 * MIF Interrupt bit
46197c478bd9Sstevel@tonic-gate 	 */
46207c478bd9Sstevel@tonic-gate 	hmesbits = GET_GLOBREG(status);
46217c478bd9Sstevel@tonic-gate 	CHECK_GLOBREG();
46227c478bd9Sstevel@tonic-gate 
46237c478bd9Sstevel@tonic-gate 	/*
46247c478bd9Sstevel@tonic-gate 	 * Note: TINT is sometimes enabled in thr hmereclaim()
46257c478bd9Sstevel@tonic-gate 	 */
46267c478bd9Sstevel@tonic-gate 
46277c478bd9Sstevel@tonic-gate 	/*
46287c478bd9Sstevel@tonic-gate 	 * Bugid 1227832 - to handle spurious interrupts on fusion systems.
46297c478bd9Sstevel@tonic-gate 	 * Claim the first interrupt after initialization
46307c478bd9Sstevel@tonic-gate 	 */
46317c478bd9Sstevel@tonic-gate 	if (hmep->hme_flags & HMEINITIALIZED) {
46327c478bd9Sstevel@tonic-gate 		hmep->hme_flags &= ~HMEINITIALIZED;
46337c478bd9Sstevel@tonic-gate 		serviced = DDI_INTR_CLAIMED;
46347c478bd9Sstevel@tonic-gate 	}
46357c478bd9Sstevel@tonic-gate 
46367c478bd9Sstevel@tonic-gate 	if ((hmesbits & (HMEG_STATUS_INTR | HMEG_STATUS_TINT)) == 0) {
46377c478bd9Sstevel@tonic-gate 						/* No interesting interrupt */
46387c478bd9Sstevel@tonic-gate 		if (hmep->hme_intrstats) {
46397c478bd9Sstevel@tonic-gate 			if (serviced == DDI_INTR_UNCLAIMED)
46407c478bd9Sstevel@tonic-gate 				KIOIP->intrs[KSTAT_INTR_SPURIOUS]++;
46417c478bd9Sstevel@tonic-gate 			else
46427c478bd9Sstevel@tonic-gate 				KIOIP->intrs[KSTAT_INTR_HARD]++;
46437c478bd9Sstevel@tonic-gate 		}
46447c478bd9Sstevel@tonic-gate 		mutex_exit(&hmep->hme_intrlock);
46457c478bd9Sstevel@tonic-gate 		return (serviced);
46467c478bd9Sstevel@tonic-gate 	}
46477c478bd9Sstevel@tonic-gate 
46487c478bd9Sstevel@tonic-gate 	serviced = DDI_INTR_CLAIMED;
46497c478bd9Sstevel@tonic-gate 
46507c478bd9Sstevel@tonic-gate 	if (!(hmep->hme_flags & HMERUNNING)) {
46517c478bd9Sstevel@tonic-gate 		if (hmep->hme_intrstats)
46527c478bd9Sstevel@tonic-gate 			KIOIP->intrs[KSTAT_INTR_HARD]++;
46537c478bd9Sstevel@tonic-gate 		mutex_exit(&hmep->hme_intrlock);
46547c478bd9Sstevel@tonic-gate 		hmeuninit(hmep);
46557c478bd9Sstevel@tonic-gate 		return (serviced);
46567c478bd9Sstevel@tonic-gate 	}
46577c478bd9Sstevel@tonic-gate 
46587c478bd9Sstevel@tonic-gate 	if (hmesbits & (HMEG_STATUS_FATAL_ERR | HMEG_STATUS_NONFATAL_ERR)) {
46597c478bd9Sstevel@tonic-gate 		if (hmesbits & HMEG_STATUS_FATAL_ERR) {
46607c478bd9Sstevel@tonic-gate 
46617c478bd9Sstevel@tonic-gate 			if (hmep->hme_intrstats)
46627c478bd9Sstevel@tonic-gate 				KIOIP->intrs[KSTAT_INTR_HARD]++;
46637c478bd9Sstevel@tonic-gate 			hme_fatal_err(hmep, hmesbits);
46647c478bd9Sstevel@tonic-gate 
46657c478bd9Sstevel@tonic-gate 			mutex_exit(&hmep->hme_intrlock);
46667c478bd9Sstevel@tonic-gate 			(void) hmeinit(hmep);
46677c478bd9Sstevel@tonic-gate 			return (serviced);
46687c478bd9Sstevel@tonic-gate 		}
46697c478bd9Sstevel@tonic-gate 		hme_nonfatal_err(hmep, hmesbits);
46707c478bd9Sstevel@tonic-gate 	}
46717c478bd9Sstevel@tonic-gate 
46727c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_MIF_INTR) {
46737c478bd9Sstevel@tonic-gate 		mif_status = (GET_MIFREG(mif_bsts) >> 16);
46747c478bd9Sstevel@tonic-gate 		if (!(mif_status & PHY_BMSR_LNKSTS)) {
46757c478bd9Sstevel@tonic-gate 
46767c478bd9Sstevel@tonic-gate 			if (hmep->hme_intrstats)
46777c478bd9Sstevel@tonic-gate 				KIOIP->intrs[KSTAT_INTR_HARD]++;
46787c478bd9Sstevel@tonic-gate 
46797c478bd9Sstevel@tonic-gate 			hme_stop_mifpoll(hmep);
46807c478bd9Sstevel@tonic-gate 			hmep->hme_mifpoll_flag = 1;
46817c478bd9Sstevel@tonic-gate 			mutex_exit(&hmep->hme_intrlock);
46827c478bd9Sstevel@tonic-gate 			hme_stop_timer(hmep);
46837c478bd9Sstevel@tonic-gate 			hme_start_timer(hmep, hme_check_link, MSECOND(1));
46847c478bd9Sstevel@tonic-gate 			return (serviced);
46857c478bd9Sstevel@tonic-gate 		}
46867c478bd9Sstevel@tonic-gate 		/*
46877c478bd9Sstevel@tonic-gate 		 *
46887c478bd9Sstevel@tonic-gate 		 * BugId 1261889 EscId 50699 ftp hangs @ 10 Mbps
46897c478bd9Sstevel@tonic-gate 		 *
46907c478bd9Sstevel@tonic-gate 		 * Here could be one cause:
46917c478bd9Sstevel@tonic-gate 		 * national PHY sees jabber, goes into "Jabber function",
46927c478bd9Sstevel@tonic-gate 		 * (see section 3.7.6 in PHY specs.), disables transmitter,
46937c478bd9Sstevel@tonic-gate 		 * and waits for internal transmit enable to be de-asserted
46947c478bd9Sstevel@tonic-gate 		 * for at least 750ms (the "unjab" time).  Also, the PHY
46957c478bd9Sstevel@tonic-gate 		 * has asserted COL, the collision detect signal.
46967c478bd9Sstevel@tonic-gate 		 *
46977c478bd9Sstevel@tonic-gate 		 * In the meantime, the Sbus/FEPS, in never-give-up mode,
46987c478bd9Sstevel@tonic-gate 		 * continually retries, backs off 16 times as per spec,
46997c478bd9Sstevel@tonic-gate 		 * and restarts the transmission, so TX_EN is never
47007c478bd9Sstevel@tonic-gate 		 * deasserted long enough, in particular TX_EN is turned
47017c478bd9Sstevel@tonic-gate 		 * on approximately once every 4 microseconds on the
47027c478bd9Sstevel@tonic-gate 		 * average.  PHY and MAC are deadlocked.
47037c478bd9Sstevel@tonic-gate 		 *
47047c478bd9Sstevel@tonic-gate 		 * Here is part of the fix:
47057c478bd9Sstevel@tonic-gate 		 * On seeing the jabber, treat it like a hme_fatal_err
47067c478bd9Sstevel@tonic-gate 		 * and reset both the Sbus/FEPS and the PHY.
47077c478bd9Sstevel@tonic-gate 		 */
47087c478bd9Sstevel@tonic-gate 
47097c478bd9Sstevel@tonic-gate 		if (mif_status & (PHY_BMSR_JABDET)) {
47107c478bd9Sstevel@tonic-gate 
47117c478bd9Sstevel@tonic-gate 			/* national phy only defines this at 10 Mbps */
47127c478bd9Sstevel@tonic-gate 			if (hme_param_speed == 0) { /* 10 Mbps speed ? */
47137c478bd9Sstevel@tonic-gate 				hmep->hme_jab++;
47147c478bd9Sstevel@tonic-gate 
47157c478bd9Sstevel@tonic-gate 				/* treat jabber like a fatal error */
47167c478bd9Sstevel@tonic-gate 				hmep->hme_linkcheck = 0; /* force PHY reset */
47177c478bd9Sstevel@tonic-gate 				mutex_exit(&hmep->hme_intrlock);
47187c478bd9Sstevel@tonic-gate 				(void) hmeinit(hmep);
47197c478bd9Sstevel@tonic-gate 
47207c478bd9Sstevel@tonic-gate 				return (serviced);
47217c478bd9Sstevel@tonic-gate 			}
47227c478bd9Sstevel@tonic-gate 		}
47237c478bd9Sstevel@tonic-gate 		hme_start_mifpoll(hmep);
47247c478bd9Sstevel@tonic-gate 	}
47257c478bd9Sstevel@tonic-gate 
47267c478bd9Sstevel@tonic-gate 	if (hmesbits & (HMEG_STATUS_TX_ALL | HMEG_STATUS_TINT)) {
47277c478bd9Sstevel@tonic-gate 		mutex_enter(&hmep->hme_xmitlock);
47287c478bd9Sstevel@tonic-gate 
47297c478bd9Sstevel@tonic-gate 		hmereclaim(hmep);
47307c478bd9Sstevel@tonic-gate 		mutex_exit(&hmep->hme_xmitlock);
47317c478bd9Sstevel@tonic-gate 	}
47327c478bd9Sstevel@tonic-gate 
47337c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RINT) {
47347c478bd9Sstevel@tonic-gate 
47357c478bd9Sstevel@tonic-gate 		/*
47367c478bd9Sstevel@tonic-gate 		 * This dummy PIO is required to flush the SBus
47377c478bd9Sstevel@tonic-gate 		 * Bridge buffers in QFE.
47387c478bd9Sstevel@tonic-gate 		 */
4739*0219346bSGarrett D'Amore 		(void) GET_GLOBREG(config);
47407c478bd9Sstevel@tonic-gate 
47417c478bd9Sstevel@tonic-gate 		/*
4742*0219346bSGarrett D'Amore 		 * Loop through each RMD no more than once.
47437c478bd9Sstevel@tonic-gate 		 */
4744*0219346bSGarrett D'Amore 		while (num_reads++ < HME_RMDMAX) {
4745*0219346bSGarrett D'Amore 			hmebuf_t *rbuf;
4746*0219346bSGarrett D'Amore 			int rxptr;
4747*0219346bSGarrett D'Amore 
4748*0219346bSGarrett D'Amore 			rxptr = hmep->hme_rxindex % HME_RMDMAX;
4749*0219346bSGarrett D'Amore 			HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORKERNEL);
4750*0219346bSGarrett D'Amore 
4751*0219346bSGarrett D'Amore 			rflags = GET_RMD_FLAGS(rxptr);
4752*0219346bSGarrett D'Amore 			if (rflags & HMERMD_OWN) {
4753*0219346bSGarrett D'Amore 				/*
4754*0219346bSGarrett D'Amore 				 * Chip still owns it.  We're done.
4755*0219346bSGarrett D'Amore 				 */
4756*0219346bSGarrett D'Amore 				break;
4757*0219346bSGarrett D'Amore 			}
475885025c03Sgd 
4759*0219346bSGarrett D'Amore 			/*
4760*0219346bSGarrett D'Amore 			 * Retrieve the packet.
4761*0219346bSGarrett D'Amore 			 */
4762*0219346bSGarrett D'Amore 			rbuf = &hmep->hme_rbuf[rxptr];
4763*0219346bSGarrett D'Amore 			mp = hmeread(hmep, rbuf, rflags);
476485025c03Sgd 
47657c478bd9Sstevel@tonic-gate 			/*
4766*0219346bSGarrett D'Amore 			 * Return ownership of the RMD.
47677c478bd9Sstevel@tonic-gate 			 */
4768*0219346bSGarrett D'Amore 			PUT_RMD(rxptr, rbuf->paddr);
4769*0219346bSGarrett D'Amore 			HMESYNCRMD(rxptr, DDI_DMA_SYNC_FORDEV);
47707c478bd9Sstevel@tonic-gate 
477185025c03Sgd 			if (mp != NULL) {
477285025c03Sgd 				*tail = mp;
477385025c03Sgd 				tail = &mp->b_next;
477485025c03Sgd 			}
477585025c03Sgd 
47767c478bd9Sstevel@tonic-gate 			/*
4777*0219346bSGarrett D'Amore 			 * Advance to the next RMD.
47787c478bd9Sstevel@tonic-gate 			 */
4779*0219346bSGarrett D'Amore 			hmep->hme_rxindex++;
47807c478bd9Sstevel@tonic-gate 		}
47817c478bd9Sstevel@tonic-gate 	}
47827c478bd9Sstevel@tonic-gate 
47837c478bd9Sstevel@tonic-gate 	if (hmep->hme_intrstats)
47847c478bd9Sstevel@tonic-gate 		KIOIP->intrs[KSTAT_INTR_HARD]++;
47857c478bd9Sstevel@tonic-gate 
47867c478bd9Sstevel@tonic-gate 	mutex_exit(&hmep->hme_intrlock);
478785025c03Sgd 
478885025c03Sgd 	if (head != NULL)
478985025c03Sgd 		mac_rx(hmep->hme_mh, NULL, head);
479085025c03Sgd 
47917c478bd9Sstevel@tonic-gate 	return (serviced);
47927c478bd9Sstevel@tonic-gate }
47937c478bd9Sstevel@tonic-gate 
47947c478bd9Sstevel@tonic-gate /*
47957c478bd9Sstevel@tonic-gate  * Transmit completion reclaiming.
47967c478bd9Sstevel@tonic-gate  */
47977c478bd9Sstevel@tonic-gate static void
47987c478bd9Sstevel@tonic-gate hmereclaim(struct hme *hmep)
47997c478bd9Sstevel@tonic-gate {
4800*0219346bSGarrett D'Amore 	boolean_t	reclaimed = B_FALSE;
48017c478bd9Sstevel@tonic-gate 
48027c478bd9Sstevel@tonic-gate 	/*
48037c478bd9Sstevel@tonic-gate 	 * Loop through each TMD.
48047c478bd9Sstevel@tonic-gate 	 */
4805*0219346bSGarrett D'Amore 	while (hmep->hme_txindex > hmep->hme_txreclaim) {
4806*0219346bSGarrett D'Amore 
4807*0219346bSGarrett D'Amore 		int		reclaim;
4808*0219346bSGarrett D'Amore 		uint32_t	flags;
4809*0219346bSGarrett D'Amore 
4810*0219346bSGarrett D'Amore 		reclaim = hmep->hme_txreclaim % HME_TMDMAX;
4811*0219346bSGarrett D'Amore 		HMESYNCTMD(reclaim, DDI_DMA_SYNC_FORKERNEL);
4812*0219346bSGarrett D'Amore 
4813*0219346bSGarrett D'Amore 		flags = GET_TMD_FLAGS(reclaim);
4814*0219346bSGarrett D'Amore 		if (flags & HMETMD_OWN) {
4815*0219346bSGarrett D'Amore 			/*
4816*0219346bSGarrett D'Amore 			 * Chip still owns it.  We're done.
4817*0219346bSGarrett D'Amore 			 */
4818*0219346bSGarrett D'Amore 			break;
4819*0219346bSGarrett D'Amore 		}
48207c478bd9Sstevel@tonic-gate 
48217c478bd9Sstevel@tonic-gate 		/*
4822*0219346bSGarrett D'Amore 		 * Count a chained packet only once.
48237c478bd9Sstevel@tonic-gate 		 */
4824*0219346bSGarrett D'Amore 		if (flags & HMETMD_SOP) {
48257c478bd9Sstevel@tonic-gate 			hmep->hme_opackets++;
48267c478bd9Sstevel@tonic-gate 		}
48277c478bd9Sstevel@tonic-gate 
48287c478bd9Sstevel@tonic-gate 		/*
48297c478bd9Sstevel@tonic-gate 		 * MIB II
48307c478bd9Sstevel@tonic-gate 		 */
4831*0219346bSGarrett D'Amore 		hmep->hme_obytes += flags & HMETMD_BUFSIZE;
48327c478bd9Sstevel@tonic-gate 
4833*0219346bSGarrett D'Amore 		reclaimed = B_TRUE;
4834*0219346bSGarrett D'Amore 		hmep->hme_txreclaim++;
48357c478bd9Sstevel@tonic-gate 	}
48367c478bd9Sstevel@tonic-gate 
4837*0219346bSGarrett D'Amore 	if (reclaimed) {
48387c478bd9Sstevel@tonic-gate 		/*
48397c478bd9Sstevel@tonic-gate 		 * we could reclaim some TMDs so turn off interrupts
48407c478bd9Sstevel@tonic-gate 		 */
48417c478bd9Sstevel@tonic-gate 		if (hmep->hme_wantw) {
48427c478bd9Sstevel@tonic-gate 			PUT_GLOBREG(intmask,
484385025c03Sgd 			    HMEG_MASK_INTR | HMEG_MASK_TINT |
484485025c03Sgd 			    HMEG_MASK_TX_ALL);
484585025c03Sgd 			hmep->hme_wantw = B_FALSE;
484685025c03Sgd 			mac_tx_update(hmep->hme_mh);
48477c478bd9Sstevel@tonic-gate 		}
48487c478bd9Sstevel@tonic-gate 	} else {
48497c478bd9Sstevel@tonic-gate 		/*
48507c478bd9Sstevel@tonic-gate 		 * enable TINTS: so that even if there is no further activity
48517c478bd9Sstevel@tonic-gate 		 * hmereclaim will get called
48527c478bd9Sstevel@tonic-gate 		 */
48537c478bd9Sstevel@tonic-gate 		if (hmep->hme_wantw)
485485025c03Sgd 			PUT_GLOBREG(intmask,
485585025c03Sgd 			    GET_GLOBREG(intmask) & ~HMEG_MASK_TX_ALL);
48567c478bd9Sstevel@tonic-gate 	}
48577c478bd9Sstevel@tonic-gate 	CHECK_GLOBREG();
48587c478bd9Sstevel@tonic-gate }
48597c478bd9Sstevel@tonic-gate 
48607c478bd9Sstevel@tonic-gate /*
48617c478bd9Sstevel@tonic-gate  * Handle interrupts for fatal errors
48627c478bd9Sstevel@tonic-gate  * Need reinitialization of the ENET channel.
48637c478bd9Sstevel@tonic-gate  */
48647c478bd9Sstevel@tonic-gate static void
48657c478bd9Sstevel@tonic-gate hme_fatal_err(struct hme *hmep, uint_t hmesbits)
48667c478bd9Sstevel@tonic-gate {
48677c478bd9Sstevel@tonic-gate 
48687c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_SLV_PAR_ERR) {
48697c478bd9Sstevel@tonic-gate 		hmep->hme_slvparerr++;
48707c478bd9Sstevel@tonic-gate 	}
48717c478bd9Sstevel@tonic-gate 
48727c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_SLV_ERR_ACK) {
48737c478bd9Sstevel@tonic-gate 		hmep->hme_slverrack++;
48747c478bd9Sstevel@tonic-gate 	}
48757c478bd9Sstevel@tonic-gate 
48767c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_TX_TAG_ERR) {
48777c478bd9Sstevel@tonic-gate 		hmep->hme_txtagerr++;
48787c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors++;
48797c478bd9Sstevel@tonic-gate 	}
48807c478bd9Sstevel@tonic-gate 
48817c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_TX_PAR_ERR) {
48827c478bd9Sstevel@tonic-gate 		hmep->hme_txparerr++;
48837c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors++;
48847c478bd9Sstevel@tonic-gate 	}
48857c478bd9Sstevel@tonic-gate 
48867c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_TX_LATE_ERR) {
48877c478bd9Sstevel@tonic-gate 		hmep->hme_txlaterr++;
48887c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors++;
48897c478bd9Sstevel@tonic-gate 	}
48907c478bd9Sstevel@tonic-gate 
48917c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_TX_ERR_ACK) {
48927c478bd9Sstevel@tonic-gate 		hmep->hme_txerrack++;
48937c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors++;
48947c478bd9Sstevel@tonic-gate 	}
48957c478bd9Sstevel@tonic-gate 
48967c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_EOP_ERR) {
48977c478bd9Sstevel@tonic-gate 		hmep->hme_eoperr++;
48987c478bd9Sstevel@tonic-gate 	}
48997c478bd9Sstevel@tonic-gate 
49007c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RX_TAG_ERR) {
49017c478bd9Sstevel@tonic-gate 		hmep->hme_rxtagerr++;
49027c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
49037c478bd9Sstevel@tonic-gate 	}
49047c478bd9Sstevel@tonic-gate 
49057c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RX_PAR_ERR) {
49067c478bd9Sstevel@tonic-gate 		hmep->hme_rxparerr++;
49077c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
49087c478bd9Sstevel@tonic-gate 	}
49097c478bd9Sstevel@tonic-gate 
49107c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RX_LATE_ERR) {
49117c478bd9Sstevel@tonic-gate 		hmep->hme_rxlaterr++;
49127c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
49137c478bd9Sstevel@tonic-gate 	}
49147c478bd9Sstevel@tonic-gate 
49157c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RX_ERR_ACK) {
49167c478bd9Sstevel@tonic-gate 		hmep->hme_rxerrack++;
49177c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
49187c478bd9Sstevel@tonic-gate 	}
49197c478bd9Sstevel@tonic-gate }
49207c478bd9Sstevel@tonic-gate 
49217c478bd9Sstevel@tonic-gate /*
49227c478bd9Sstevel@tonic-gate  * Handle interrupts regarding non-fatal errors.
49237c478bd9Sstevel@tonic-gate  */
49247c478bd9Sstevel@tonic-gate static void
49257c478bd9Sstevel@tonic-gate hme_nonfatal_err(struct hme *hmep, uint_t hmesbits)
49267c478bd9Sstevel@tonic-gate {
49277c478bd9Sstevel@tonic-gate 
49287c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RX_DROP) {
49297c478bd9Sstevel@tonic-gate 		hmep->hme_missed++;
49307c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
49317c478bd9Sstevel@tonic-gate 	}
49327c478bd9Sstevel@tonic-gate 
49337c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_DEFTIMR_EXP) {
49347c478bd9Sstevel@tonic-gate 		hmep->hme_defer_xmts++;
49357c478bd9Sstevel@tonic-gate 	}
49367c478bd9Sstevel@tonic-gate 
49377c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_FSTCOLC_EXP) {
49387c478bd9Sstevel@tonic-gate 		hmep->hme_fstcol += 256;
49397c478bd9Sstevel@tonic-gate 	}
49407c478bd9Sstevel@tonic-gate 
49417c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_LATCOLC_EXP) {
49427c478bd9Sstevel@tonic-gate 		hmep->hme_tlcol += 256;
49437c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors += 256;
49447c478bd9Sstevel@tonic-gate 	}
49457c478bd9Sstevel@tonic-gate 
49467c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_EXCOLC_EXP) {
494785025c03Sgd 		hmep->hme_excol += 256;
49487c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors += 256;
49497c478bd9Sstevel@tonic-gate 	}
49507c478bd9Sstevel@tonic-gate 
49517c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_NRMCOLC_EXP) {
49527c478bd9Sstevel@tonic-gate 		hmep->hme_coll += 256;
49537c478bd9Sstevel@tonic-gate 	}
49547c478bd9Sstevel@tonic-gate 
49557c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_MXPKTSZ_ERR) {
49567c478bd9Sstevel@tonic-gate 		hmep->hme_babl++;
49577c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors++;
49587c478bd9Sstevel@tonic-gate 	}
49597c478bd9Sstevel@tonic-gate 
49607c478bd9Sstevel@tonic-gate 	/*
49617c478bd9Sstevel@tonic-gate 	 * This error is fatal and the board needs to
49627c478bd9Sstevel@tonic-gate 	 * be reinitialized. Comments?
49637c478bd9Sstevel@tonic-gate 	 */
49647c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_TXFIFO_UNDR) {
49657c478bd9Sstevel@tonic-gate 		hmep->hme_uflo++;
49667c478bd9Sstevel@tonic-gate 		hmep->hme_oerrors++;
49677c478bd9Sstevel@tonic-gate 	}
49687c478bd9Sstevel@tonic-gate 
49697c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_SQE_TST_ERR) {
49707c478bd9Sstevel@tonic-gate 		hmep->hme_sqe_errors++;
49717c478bd9Sstevel@tonic-gate 	}
49727c478bd9Sstevel@tonic-gate 
49737c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RCV_CNT_EXP) {
49747c478bd9Sstevel@tonic-gate 		if (hmep->hme_rxcv_enable) {
49757c478bd9Sstevel@tonic-gate 			hmep->hme_cvc += 256;
49767c478bd9Sstevel@tonic-gate 		}
49777c478bd9Sstevel@tonic-gate 	}
49787c478bd9Sstevel@tonic-gate 
49797c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_RXFIFO_OVFL) {
49807c478bd9Sstevel@tonic-gate 		hmep->hme_oflo++;
49817c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
49827c478bd9Sstevel@tonic-gate 	}
49837c478bd9Sstevel@tonic-gate 
49847c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_LEN_CNT_EXP) {
49857c478bd9Sstevel@tonic-gate 		hmep->hme_lenerr += 256;
49867c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors += 256;
49877c478bd9Sstevel@tonic-gate 	}
49887c478bd9Sstevel@tonic-gate 
49897c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_ALN_CNT_EXP) {
49907c478bd9Sstevel@tonic-gate 		hmep->hme_align_errors += 256;
49917c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors += 256;
49927c478bd9Sstevel@tonic-gate 	}
49937c478bd9Sstevel@tonic-gate 
49947c478bd9Sstevel@tonic-gate 	if (hmesbits & HMEG_STATUS_CRC_CNT_EXP) {
49957c478bd9Sstevel@tonic-gate 		hmep->hme_fcs_errors += 256;
49967c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors += 256;
49977c478bd9Sstevel@tonic-gate 	}
49987c478bd9Sstevel@tonic-gate }
49997c478bd9Sstevel@tonic-gate 
500085025c03Sgd static mblk_t *
5001*0219346bSGarrett D'Amore hmeread(struct hme *hmep, hmebuf_t *rbuf, uint32_t rflags)
50027c478bd9Sstevel@tonic-gate {
5003*0219346bSGarrett D'Amore 	mblk_t		*bp;
5004*0219346bSGarrett D'Amore 	uint32_t	len;
5005*0219346bSGarrett D'Amore 	t_uscalar_t	type;
5006*0219346bSGarrett D'Amore 
500785025c03Sgd 	len = (rflags & HMERMD_BUFSIZE) >> HMERMD_BUFSIZE_SHIFT;
50087c478bd9Sstevel@tonic-gate 
50097c478bd9Sstevel@tonic-gate 	/*
50107c478bd9Sstevel@tonic-gate 	 * Check for short packet
50117c478bd9Sstevel@tonic-gate 	 * and check for overflow packet also. The processing is the
50127c478bd9Sstevel@tonic-gate 	 * same for both the cases - reuse the buffer. Update the Buffer
50137c478bd9Sstevel@tonic-gate 	 * overflow counter.
50147c478bd9Sstevel@tonic-gate 	 */
501585025c03Sgd 	if ((len < ETHERMIN) || (rflags & HMERMD_OVFLOW) ||
501685025c03Sgd 	    (len > (ETHERMAX + 4))) {
50177c478bd9Sstevel@tonic-gate 		if (len < ETHERMIN)
50187c478bd9Sstevel@tonic-gate 			hmep->hme_runt++;
50197c478bd9Sstevel@tonic-gate 
50207c478bd9Sstevel@tonic-gate 		else {
50217c478bd9Sstevel@tonic-gate 			hmep->hme_buff++;
50227c478bd9Sstevel@tonic-gate 			hmep->hme_toolong_errors++;
50237c478bd9Sstevel@tonic-gate 		}
50247c478bd9Sstevel@tonic-gate 		hmep->hme_ierrors++;
502585025c03Sgd 		return (NULL);
50267c478bd9Sstevel@tonic-gate 	}
50277c478bd9Sstevel@tonic-gate 
50287c478bd9Sstevel@tonic-gate 	/*
50297c478bd9Sstevel@tonic-gate 	 * Sync the received buffer before looking at it.
50307c478bd9Sstevel@tonic-gate 	 */
50317c478bd9Sstevel@tonic-gate 
5032*0219346bSGarrett D'Amore 	(void) ddi_dma_sync(rbuf->dmah, 0, 0, DDI_DMA_SYNC_FORKERNEL);
50337c478bd9Sstevel@tonic-gate 
50347c478bd9Sstevel@tonic-gate 	/*
50357c478bd9Sstevel@tonic-gate 	 * copy the packet data and then recycle the descriptor.
50367c478bd9Sstevel@tonic-gate 	 */
50377c478bd9Sstevel@tonic-gate 
5038*0219346bSGarrett D'Amore 	if ((bp = allocb(len + HME_FSTBYTE_OFFSET, BPRI_HI)) == NULL) {
50397c478bd9Sstevel@tonic-gate 
50407c478bd9Sstevel@tonic-gate 		hmep->hme_allocbfail++;
50417c478bd9Sstevel@tonic-gate 		hmep->hme_norcvbuf++;
504285025c03Sgd 
504385025c03Sgd 		return (NULL);
50447c478bd9Sstevel@tonic-gate 	}
50457c478bd9Sstevel@tonic-gate 
5046*0219346bSGarrett D'Amore 	bcopy(rbuf->kaddr, bp->b_rptr, len + HME_FSTBYTE_OFFSET);
50477c478bd9Sstevel@tonic-gate 
5048*0219346bSGarrett D'Amore 	hmep->hme_ipackets++;
50497c478bd9Sstevel@tonic-gate 
5050*0219346bSGarrett D'Amore 	/*  Add the First Byte offset to the b_rptr and copy */
5051*0219346bSGarrett D'Amore 	bp->b_rptr += HME_FSTBYTE_OFFSET;
5052*0219346bSGarrett D'Amore 	bp->b_wptr = bp->b_rptr + len;
50537c478bd9Sstevel@tonic-gate 
50547c478bd9Sstevel@tonic-gate 	/*
5055*0219346bSGarrett D'Amore 	 * update MIB II statistics
50567c478bd9Sstevel@tonic-gate 	 */
5057*0219346bSGarrett D'Amore 	BUMP_InNUcast(hmep, bp->b_rptr);
5058*0219346bSGarrett D'Amore 	hmep->hme_rbytes += len;
50597c478bd9Sstevel@tonic-gate 
5060*0219346bSGarrett D'Amore 	type = get_ether_type(bp->b_rptr);
50617c478bd9Sstevel@tonic-gate 
50627c478bd9Sstevel@tonic-gate 	/*
5063*0219346bSGarrett D'Amore 	 * TCP partial checksum in hardware
50647c478bd9Sstevel@tonic-gate 	 */
5065*0219346bSGarrett D'Amore 	if (type == ETHERTYPE_IP || type == ETHERTYPE_IPV6) {
5066*0219346bSGarrett D'Amore 		uint16_t cksum = ~rflags & HMERMD_CKSUM;
5067*0219346bSGarrett D'Amore 		uint_t end = len - sizeof (struct ether_header);
5068*0219346bSGarrett D'Amore 		(void) hcksum_assoc(bp, NULL, NULL, 0,
5069*0219346bSGarrett D'Amore 		    0, end, htons(cksum), HCK_PARTIALCKSUM, 0);
50707c478bd9Sstevel@tonic-gate 	}
50717c478bd9Sstevel@tonic-gate 
507285025c03Sgd 	return (bp);
50737c478bd9Sstevel@tonic-gate }
50747c478bd9Sstevel@tonic-gate 
50757c478bd9Sstevel@tonic-gate /*VARARGS*/
50767c478bd9Sstevel@tonic-gate static void
5077*0219346bSGarrett D'Amore hme_fault_msg(struct hme *hmep, uint_t severity, msg_t type, char *fmt, ...)
50787c478bd9Sstevel@tonic-gate {
50797c478bd9Sstevel@tonic-gate 	char	msg_buffer[255];
50807c478bd9Sstevel@tonic-gate 	va_list	ap;
50817c478bd9Sstevel@tonic-gate 
50827c478bd9Sstevel@tonic-gate 	va_start(ap, fmt);
5083228fdff0Sgd 	(void) vsnprintf(msg_buffer, sizeof (msg_buffer), fmt, ap);
50847c478bd9Sstevel@tonic-gate 
508585025c03Sgd 	if (hmep == NULL) {
50867c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "hme : %s", msg_buffer);
50877c478bd9Sstevel@tonic-gate 
508885025c03Sgd 	} else if (type == DISPLAY_MSG) {
508985025c03Sgd 		cmn_err(CE_CONT, "?%s%d : %s\n", ddi_driver_name(hmep->dip),
509085025c03Sgd 		    hmep->instance, msg_buffer);
509185025c03Sgd 	} else if (severity == SEVERITY_HIGH) {
509285025c03Sgd 		cmn_err(CE_WARN, "%s%d : %s, SEVERITY_HIGH, %s\n",
509385025c03Sgd 		    ddi_driver_name(hmep->dip), hmep->instance,
509485025c03Sgd 		    msg_buffer, msg_string[type]);
509585025c03Sgd 	} else {
509685025c03Sgd 		cmn_err(CE_CONT, "%s%d : %s\n", ddi_driver_name(hmep->dip),
509785025c03Sgd 		    hmep->instance, msg_buffer);
509885025c03Sgd 	}
50997c478bd9Sstevel@tonic-gate 	va_end(ap);
51007c478bd9Sstevel@tonic-gate }
51017c478bd9Sstevel@tonic-gate 
51027c478bd9Sstevel@tonic-gate /*
51037c478bd9Sstevel@tonic-gate  * if this is the first init do not bother to save the
51047c478bd9Sstevel@tonic-gate  * counters. They should be 0, but do not count on it.
51057c478bd9Sstevel@tonic-gate  */
51067c478bd9Sstevel@tonic-gate static void
51077c478bd9Sstevel@tonic-gate hmesavecntrs(struct hme *hmep)
51087c478bd9Sstevel@tonic-gate {
51097c478bd9Sstevel@tonic-gate 	uint32_t fecnt, aecnt, lecnt, rxcv;
51107c478bd9Sstevel@tonic-gate 	uint32_t ltcnt, excnt;
51117c478bd9Sstevel@tonic-gate 
51127c478bd9Sstevel@tonic-gate 	/* XXX What all gets added in ierrors and oerrors? */
51137c478bd9Sstevel@tonic-gate 	fecnt = GET_MACREG(fecnt);
51147c478bd9Sstevel@tonic-gate 	PUT_MACREG(fecnt, 0);
51157c478bd9Sstevel@tonic-gate 
51167c478bd9Sstevel@tonic-gate 	aecnt = GET_MACREG(aecnt);
51177c478bd9Sstevel@tonic-gate 	hmep->hme_align_errors += aecnt;
51187c478bd9Sstevel@tonic-gate 	PUT_MACREG(aecnt, 0);
51197c478bd9Sstevel@tonic-gate 
51207c478bd9Sstevel@tonic-gate 	lecnt = GET_MACREG(lecnt);
51217c478bd9Sstevel@tonic-gate 	hmep->hme_lenerr += lecnt;
51227c478bd9Sstevel@tonic-gate 	PUT_MACREG(lecnt, 0);
51237c478bd9Sstevel@tonic-gate 
51247c478bd9Sstevel@tonic-gate 	rxcv = GET_MACREG(rxcv);
51257c478bd9Sstevel@tonic-gate #ifdef HME_CODEVIOL_BUG
51267c478bd9Sstevel@tonic-gate 	/*
51277c478bd9Sstevel@tonic-gate 	 * Ignore rxcv errors for Sbus/FEPS 2.1 or earlier
51287c478bd9Sstevel@tonic-gate 	 */
51297c478bd9Sstevel@tonic-gate 	if (!hmep->hme_rxcv_enable) {
51307c478bd9Sstevel@tonic-gate 		rxcv = 0;
51317c478bd9Sstevel@tonic-gate 	}
51327c478bd9Sstevel@tonic-gate #endif
51337c478bd9Sstevel@tonic-gate 	hmep->hme_cvc += rxcv;
51347c478bd9Sstevel@tonic-gate 	PUT_MACREG(rxcv, 0);
51357c478bd9Sstevel@tonic-gate 
51367c478bd9Sstevel@tonic-gate 	ltcnt = GET_MACREG(ltcnt);
51377c478bd9Sstevel@tonic-gate 	hmep->hme_tlcol += ltcnt;
51387c478bd9Sstevel@tonic-gate 	PUT_MACREG(ltcnt, 0);
51397c478bd9Sstevel@tonic-gate 
51407c478bd9Sstevel@tonic-gate 	excnt = GET_MACREG(excnt);
514185025c03Sgd 	hmep->hme_excol += excnt;
51427c478bd9Sstevel@tonic-gate 	PUT_MACREG(excnt, 0);
51437c478bd9Sstevel@tonic-gate 
51447c478bd9Sstevel@tonic-gate 	hmep->hme_fcs_errors += fecnt;
51457c478bd9Sstevel@tonic-gate 	hmep->hme_ierrors += (fecnt + aecnt + lecnt);
51467c478bd9Sstevel@tonic-gate 	hmep->hme_oerrors += (ltcnt + excnt);
51477c478bd9Sstevel@tonic-gate 	hmep->hme_coll += (GET_MACREG(nccnt) + ltcnt);
51487c478bd9Sstevel@tonic-gate 
51497c478bd9Sstevel@tonic-gate 	PUT_MACREG(nccnt, 0);
51507c478bd9Sstevel@tonic-gate 	CHECK_MACREG();
51517c478bd9Sstevel@tonic-gate }
51527c478bd9Sstevel@tonic-gate 
51537c478bd9Sstevel@tonic-gate /*
51547c478bd9Sstevel@tonic-gate  * ndd support functions to get/set parameters
51557c478bd9Sstevel@tonic-gate  */
51567c478bd9Sstevel@tonic-gate /* Free the Named Dispatch Table by calling hme_nd_free */
51577c478bd9Sstevel@tonic-gate static void
51587c478bd9Sstevel@tonic-gate hme_param_cleanup(struct hme *hmep)
51597c478bd9Sstevel@tonic-gate {
51607c478bd9Sstevel@tonic-gate 	if (hmep->hme_g_nd)
51617c478bd9Sstevel@tonic-gate 		(void) hme_nd_free(&hmep->hme_g_nd);
51627c478bd9Sstevel@tonic-gate }
51637c478bd9Sstevel@tonic-gate 
51647c478bd9Sstevel@tonic-gate /*
51657c478bd9Sstevel@tonic-gate  * Extracts the value from the hme parameter array and prints the
51667c478bd9Sstevel@tonic-gate  * parameter value. cp points to the required parameter.
51677c478bd9Sstevel@tonic-gate  */
51687c478bd9Sstevel@tonic-gate /* ARGSUSED */
51697c478bd9Sstevel@tonic-gate static int
51707c478bd9Sstevel@tonic-gate hme_param_get(queue_t *q, mblk_t *mp, caddr_t cp)
51717c478bd9Sstevel@tonic-gate {
5172*0219346bSGarrett D'Amore 	hmeparam_t *hmepa = (void *)cp;
51737c478bd9Sstevel@tonic-gate 
51747c478bd9Sstevel@tonic-gate 	(void) mi_mpprintf(mp, "%d", hmepa->hme_param_val);
51757c478bd9Sstevel@tonic-gate 	return (0);
51767c478bd9Sstevel@tonic-gate }
51777c478bd9Sstevel@tonic-gate 
51787c478bd9Sstevel@tonic-gate /*
51797c478bd9Sstevel@tonic-gate  * Register each element of the parameter array with the
51807c478bd9Sstevel@tonic-gate  * named dispatch handler. Each element is loaded using
51817c478bd9Sstevel@tonic-gate  * hme_nd_load()
51827c478bd9Sstevel@tonic-gate  */
51837c478bd9Sstevel@tonic-gate /* ARGSUSED */
51847c478bd9Sstevel@tonic-gate static int
51857c478bd9Sstevel@tonic-gate hme_param_register(struct hme *hmep, hmeparam_t *hmepa, int cnt)
51867c478bd9Sstevel@tonic-gate {
51877c478bd9Sstevel@tonic-gate 	int i;
51887c478bd9Sstevel@tonic-gate 
51897c478bd9Sstevel@tonic-gate 	/* First 4 elements are read-only */
51907c478bd9Sstevel@tonic-gate 	for (i = 0; i < 4; i++, hmepa++)
51917c478bd9Sstevel@tonic-gate 		if (!hme_nd_load(&hmep->hme_g_nd, hmepa->hme_param_name,
519285025c03Sgd 		    (pfi_t)hme_param_get, (pfi_t)0, (caddr_t)hmepa)) {
51937c478bd9Sstevel@tonic-gate 			(void) hme_nd_free(&hmep->hme_g_nd);
51947c478bd9Sstevel@tonic-gate 			return (B_FALSE);
51957c478bd9Sstevel@tonic-gate 		}
51967c478bd9Sstevel@tonic-gate 	/* Next 10 elements are read and write */
51977c478bd9Sstevel@tonic-gate 	for (i = 0; i < 10; i++, hmepa++)
51987c478bd9Sstevel@tonic-gate 		if (hmepa->hme_param_name && hmepa->hme_param_name[0]) {
51997c478bd9Sstevel@tonic-gate 			if (!hme_nd_load(&hmep->hme_g_nd,
520085025c03Sgd 			    hmepa->hme_param_name, (pfi_t)hme_param_get,
520185025c03Sgd 			    (pfi_t)hme_param_set, (caddr_t)hmepa)) {
52027c478bd9Sstevel@tonic-gate 				(void) hme_nd_free(&hmep->hme_g_nd);
52037c478bd9Sstevel@tonic-gate 				return (B_FALSE);
52047c478bd9Sstevel@tonic-gate 
52057c478bd9Sstevel@tonic-gate 			}
52067c478bd9Sstevel@tonic-gate 		}
52077c478bd9Sstevel@tonic-gate 	/* next 12 elements are read-only */
52087c478bd9Sstevel@tonic-gate 	for (i = 0; i < 12; i++, hmepa++)
52097c478bd9Sstevel@tonic-gate 		if (!hme_nd_load(&hmep->hme_g_nd, hmepa->hme_param_name,
521085025c03Sgd 		    (pfi_t)hme_param_get, (pfi_t)0, (caddr_t)hmepa)) {
52117c478bd9Sstevel@tonic-gate 			(void) hme_nd_free(&hmep->hme_g_nd);
52127c478bd9Sstevel@tonic-gate 			return (B_FALSE);
52137c478bd9Sstevel@tonic-gate 		}
52147c478bd9Sstevel@tonic-gate 	/* Next 3  elements are read and write */
52157c478bd9Sstevel@tonic-gate 	for (i = 0; i < 3; i++, hmepa++)
52167c478bd9Sstevel@tonic-gate 		if (hmepa->hme_param_name && hmepa->hme_param_name[0]) {
52177c478bd9Sstevel@tonic-gate 			if (!hme_nd_load(&hmep->hme_g_nd,
521885025c03Sgd 			    hmepa->hme_param_name, (pfi_t)hme_param_get,
521985025c03Sgd 			    (pfi_t)hme_param_set, (caddr_t)hmepa)) {
52207c478bd9Sstevel@tonic-gate 				(void) hme_nd_free(&hmep->hme_g_nd);
52217c478bd9Sstevel@tonic-gate 				return (B_FALSE);
52227c478bd9Sstevel@tonic-gate 			}
52237c478bd9Sstevel@tonic-gate 		}
52247c478bd9Sstevel@tonic-gate 
52257c478bd9Sstevel@tonic-gate 	return (B_TRUE);
52267c478bd9Sstevel@tonic-gate }
52277c478bd9Sstevel@tonic-gate 
52287c478bd9Sstevel@tonic-gate /*
52297c478bd9Sstevel@tonic-gate  * Sets the hme parameter to the value in the hme_param_register using
52307c478bd9Sstevel@tonic-gate  * hme_nd_load().
52317c478bd9Sstevel@tonic-gate  */
52327c478bd9Sstevel@tonic-gate /* ARGSUSED */
52337c478bd9Sstevel@tonic-gate static int
52347c478bd9Sstevel@tonic-gate hme_param_set(queue_t *q, mblk_t *mp, char *value, caddr_t cp)
52357c478bd9Sstevel@tonic-gate {
52367c478bd9Sstevel@tonic-gate 	char *end;
52377c478bd9Sstevel@tonic-gate 	size_t new_value;
5238*0219346bSGarrett D'Amore 	hmeparam_t *hmepa = (void *)cp;
52397c478bd9Sstevel@tonic-gate 
52407c478bd9Sstevel@tonic-gate 	new_value = mi_strtol(value, &end, 10);
52417c478bd9Sstevel@tonic-gate 	if (end == value || new_value < hmepa->hme_param_min ||
524285025c03Sgd 	    new_value > hmepa->hme_param_max) {
52437c478bd9Sstevel@tonic-gate 			return (EINVAL);
52447c478bd9Sstevel@tonic-gate 	}
5245*0219346bSGarrett D'Amore 	hmepa->hme_param_val = (uint32_t)new_value;
52467c478bd9Sstevel@tonic-gate 	return (0);
52477c478bd9Sstevel@tonic-gate 
52487c478bd9Sstevel@tonic-gate }
52497c478bd9Sstevel@tonic-gate 
52507c478bd9Sstevel@tonic-gate /* Free the table pointed to by 'ndp' */
52517c478bd9Sstevel@tonic-gate static void
52527c478bd9Sstevel@tonic-gate hme_nd_free(caddr_t *nd_pparam)
52537c478bd9Sstevel@tonic-gate {
52547c478bd9Sstevel@tonic-gate 	ND	*nd;
52557c478bd9Sstevel@tonic-gate 
5256*0219346bSGarrett D'Amore 	if ((nd = (void *)(*nd_pparam)) != NULL) {
52577c478bd9Sstevel@tonic-gate 		if (nd->nd_tbl)
52587c478bd9Sstevel@tonic-gate 			mi_free((char *)nd->nd_tbl);
52597c478bd9Sstevel@tonic-gate 		mi_free((char *)nd);
52607c478bd9Sstevel@tonic-gate 		*nd_pparam = NULL;
52617c478bd9Sstevel@tonic-gate 	}
52627c478bd9Sstevel@tonic-gate }
52637c478bd9Sstevel@tonic-gate 
52647c478bd9Sstevel@tonic-gate static int
52657c478bd9Sstevel@tonic-gate hme_nd_getset(queue_t *q, caddr_t nd_param, MBLKP mp)
52667c478bd9Sstevel@tonic-gate {
52677c478bd9Sstevel@tonic-gate 	int	err;
52687c478bd9Sstevel@tonic-gate 	IOCP	iocp;
52697c478bd9Sstevel@tonic-gate 	MBLKP	mp1;
52707c478bd9Sstevel@tonic-gate 	ND	*nd;
52717c478bd9Sstevel@tonic-gate 	NDE	*nde;
52727c478bd9Sstevel@tonic-gate 	char	*valp;
52737c478bd9Sstevel@tonic-gate 	size_t	avail;
52747c478bd9Sstevel@tonic-gate 
52757c478bd9Sstevel@tonic-gate 	if (!nd_param)
52767c478bd9Sstevel@tonic-gate 		return (B_FALSE);
52777c478bd9Sstevel@tonic-gate 
5278*0219346bSGarrett D'Amore 	nd = (void *)nd_param;
5279*0219346bSGarrett D'Amore 	iocp = (void *)mp->b_rptr;
52807c478bd9Sstevel@tonic-gate 	if ((iocp->ioc_count == 0) || !(mp1 = mp->b_cont)) {
52817c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_IOCACK;
52827c478bd9Sstevel@tonic-gate 		iocp->ioc_count = 0;
52837c478bd9Sstevel@tonic-gate 		iocp->ioc_error = EINVAL;
52847c478bd9Sstevel@tonic-gate 		return (B_TRUE);
52857c478bd9Sstevel@tonic-gate 	}
52867c478bd9Sstevel@tonic-gate 
52877c478bd9Sstevel@tonic-gate 	/*
52887c478bd9Sstevel@tonic-gate 	 * NOTE - logic throughout nd_xxx assumes single data block for ioctl.
52897c478bd9Sstevel@tonic-gate 	 *	However, existing code sends in some big buffers.
52907c478bd9Sstevel@tonic-gate 	 */
52917c478bd9Sstevel@tonic-gate 	avail = iocp->ioc_count;
52927c478bd9Sstevel@tonic-gate 	if (mp1->b_cont) {
52937c478bd9Sstevel@tonic-gate 		freemsg(mp1->b_cont);
52947c478bd9Sstevel@tonic-gate 		mp1->b_cont = NULL;
52957c478bd9Sstevel@tonic-gate 	}
52967c478bd9Sstevel@tonic-gate 
52977c478bd9Sstevel@tonic-gate 	mp1->b_datap->db_lim[-1] = '\0';	/* Force null termination */
52987c478bd9Sstevel@tonic-gate 	valp = (char *)mp1->b_rptr;
52997c478bd9Sstevel@tonic-gate 	for (nde = nd->nd_tbl; /* */; nde++) {
53007c478bd9Sstevel@tonic-gate 		if (!nde->nde_name)
53017c478bd9Sstevel@tonic-gate 			return (B_FALSE);
53027c478bd9Sstevel@tonic-gate 		if (mi_strcmp(nde->nde_name, valp) == 0)
53037c478bd9Sstevel@tonic-gate 			break;
53047c478bd9Sstevel@tonic-gate 	}
53057c478bd9Sstevel@tonic-gate 
53067c478bd9Sstevel@tonic-gate 	err = EINVAL;
53077c478bd9Sstevel@tonic-gate 	while (*valp++)
53087c478bd9Sstevel@tonic-gate 		;
53097c478bd9Sstevel@tonic-gate 	if (!*valp || valp >= (char *)mp1->b_wptr)
53107c478bd9Sstevel@tonic-gate 		valp = NULL;
53117c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
53127c478bd9Sstevel@tonic-gate 	case ND_GET:
53137c478bd9Sstevel@tonic-gate /*
53147c478bd9Sstevel@tonic-gate  * (temporary) hack: "*valp" is size of user buffer for copyout. If result
53157c478bd9Sstevel@tonic-gate  * of action routine is too big, free excess and return ioc_rval as buffer
53167c478bd9Sstevel@tonic-gate  * size needed.  Return as many mblocks as will fit, free the rest.  For
53177c478bd9Sstevel@tonic-gate  * backward compatibility, assume size of original ioctl buffer if "*valp"
53187c478bd9Sstevel@tonic-gate  * bad or not given.
53197c478bd9Sstevel@tonic-gate  */
53207c478bd9Sstevel@tonic-gate 		if (valp)
53217c478bd9Sstevel@tonic-gate 			avail = mi_strtol(valp, (char **)0, 10);
53227c478bd9Sstevel@tonic-gate 		/* We overwrite the name/value with the reply data */
53237c478bd9Sstevel@tonic-gate 		{
53247c478bd9Sstevel@tonic-gate 			mblk_t *mp2 = mp1;
53257c478bd9Sstevel@tonic-gate 
53267c478bd9Sstevel@tonic-gate 			while (mp2) {
53277c478bd9Sstevel@tonic-gate 				mp2->b_wptr = mp2->b_rptr;
53287c478bd9Sstevel@tonic-gate 				mp2 = mp2->b_cont;
53297c478bd9Sstevel@tonic-gate 			}
53307c478bd9Sstevel@tonic-gate 		}
53317c478bd9Sstevel@tonic-gate 		err = (*nde->nde_get_pfi)(q, mp1, nde->nde_data, iocp->ioc_cr);
53327c478bd9Sstevel@tonic-gate 		if (!err) {
53337c478bd9Sstevel@tonic-gate 			size_t	size_out;
53347c478bd9Sstevel@tonic-gate 			ssize_t	excess;
53357c478bd9Sstevel@tonic-gate 
53367c478bd9Sstevel@tonic-gate 			iocp->ioc_rval = 0;
53377c478bd9Sstevel@tonic-gate 
53387c478bd9Sstevel@tonic-gate 			/* Tack on the null */
53397c478bd9Sstevel@tonic-gate 			(void) mi_mpprintf_putc((char *)mp1, '\0');
53407c478bd9Sstevel@tonic-gate 			size_out = msgdsize(mp1);
53417c478bd9Sstevel@tonic-gate 			excess = size_out - avail;
53427c478bd9Sstevel@tonic-gate 			if (excess > 0) {
53437c478bd9Sstevel@tonic-gate 				iocp->ioc_rval = (int)size_out;
53447c478bd9Sstevel@tonic-gate 				size_out -= excess;
53457c478bd9Sstevel@tonic-gate 				(void) adjmsg(mp1, -(excess + 1));
53467c478bd9Sstevel@tonic-gate 				(void) mi_mpprintf_putc((char *)mp1, '\0');
53477c478bd9Sstevel@tonic-gate 			}
53487c478bd9Sstevel@tonic-gate 			iocp->ioc_count = size_out;
53497c478bd9Sstevel@tonic-gate 		}
53507c478bd9Sstevel@tonic-gate 		break;
53517c478bd9Sstevel@tonic-gate 
53527c478bd9Sstevel@tonic-gate 	case ND_SET:
53537c478bd9Sstevel@tonic-gate 		if (valp) {
53547c478bd9Sstevel@tonic-gate 			if ((iocp->ioc_cr != NULL) &&
53557c478bd9Sstevel@tonic-gate 			    ((err = secpolicy_net_config(iocp->ioc_cr, B_FALSE))
53567c478bd9Sstevel@tonic-gate 			    == 0)) {
53577c478bd9Sstevel@tonic-gate 				err = (*nde->nde_set_pfi)(q, mp1, valp,
53587c478bd9Sstevel@tonic-gate 				    nde->nde_data, iocp->ioc_cr);
53597c478bd9Sstevel@tonic-gate 			}
53607c478bd9Sstevel@tonic-gate 			iocp->ioc_count = 0;
53617c478bd9Sstevel@tonic-gate 			freemsg(mp1);
53627c478bd9Sstevel@tonic-gate 			mp->b_cont = NULL;
53637c478bd9Sstevel@tonic-gate 		}
53647c478bd9Sstevel@tonic-gate 		break;
53657c478bd9Sstevel@tonic-gate 
53667c478bd9Sstevel@tonic-gate 	default:
53677c478bd9Sstevel@tonic-gate 		break;
53687c478bd9Sstevel@tonic-gate 	}
53697c478bd9Sstevel@tonic-gate 
53707c478bd9Sstevel@tonic-gate 	iocp->ioc_error = err;
53717c478bd9Sstevel@tonic-gate 	mp->b_datap->db_type = M_IOCACK;
53727c478bd9Sstevel@tonic-gate 	return (B_TRUE);
53737c478bd9Sstevel@tonic-gate }
53747c478bd9Sstevel@tonic-gate 
53757c478bd9Sstevel@tonic-gate /*
53767c478bd9Sstevel@tonic-gate  * Load 'name' into the named dispatch table pointed to by 'ndp'.
53777c478bd9Sstevel@tonic-gate  * 'ndp' should be the address of a char pointer cell.  If the table
53787c478bd9Sstevel@tonic-gate  * does not exist (*ndp == 0), a new table is allocated and 'ndp'
53797c478bd9Sstevel@tonic-gate  * is stuffed.  If there is not enough space in the table for a new
53807c478bd9Sstevel@tonic-gate  * entry, more space is allocated.
53817c478bd9Sstevel@tonic-gate  */
53827c478bd9Sstevel@tonic-gate static boolean_t
53837c478bd9Sstevel@tonic-gate hme_nd_load(caddr_t *nd_pparam, char *name, pfi_t get_pfi,
53847c478bd9Sstevel@tonic-gate     pfi_t set_pfi, caddr_t data)
53857c478bd9Sstevel@tonic-gate {
53867c478bd9Sstevel@tonic-gate 	ND	*nd;
53877c478bd9Sstevel@tonic-gate 	NDE	*nde;
53887c478bd9Sstevel@tonic-gate 
53897c478bd9Sstevel@tonic-gate 	if (!nd_pparam)
53907c478bd9Sstevel@tonic-gate 		return (B_FALSE);
53917c478bd9Sstevel@tonic-gate 
5392*0219346bSGarrett D'Amore 	if ((nd = (void *)(*nd_pparam)) == NULL) {
5393*0219346bSGarrett D'Amore 		if ((nd = (void *)mi_alloc(sizeof (ND), BPRI_MED)) == NULL)
53947c478bd9Sstevel@tonic-gate 			return (B_FALSE);
53957c478bd9Sstevel@tonic-gate 		bzero(nd, sizeof (ND));
53967c478bd9Sstevel@tonic-gate 		*nd_pparam = (caddr_t)nd;
53977c478bd9Sstevel@tonic-gate 	}
53987c478bd9Sstevel@tonic-gate 
53997c478bd9Sstevel@tonic-gate 	if (nd->nd_tbl) {
54007c478bd9Sstevel@tonic-gate 		for (nde = nd->nd_tbl; nde->nde_name; nde++) {
54017c478bd9Sstevel@tonic-gate 			if (mi_strcmp(name, nde->nde_name) == 0)
54027c478bd9Sstevel@tonic-gate 				goto fill_it;
54037c478bd9Sstevel@tonic-gate 		}
54047c478bd9Sstevel@tonic-gate 	}
54057c478bd9Sstevel@tonic-gate 
54067c478bd9Sstevel@tonic-gate 	if (nd->nd_free_count <= 1) {
54077c478bd9Sstevel@tonic-gate 		if ((nde = (NDE *)mi_alloc(nd->nd_size +
54087c478bd9Sstevel@tonic-gate 		    NDE_ALLOC_SIZE, BPRI_MED)) == NULL)
54097c478bd9Sstevel@tonic-gate 			return (B_FALSE);
54107c478bd9Sstevel@tonic-gate 		bzero(nde, nd->nd_size + NDE_ALLOC_SIZE);
54117c478bd9Sstevel@tonic-gate 		nd->nd_free_count += NDE_ALLOC_COUNT;
54127c478bd9Sstevel@tonic-gate 		if (nd->nd_tbl) {
54137c478bd9Sstevel@tonic-gate 			bcopy(nd->nd_tbl, nde, nd->nd_size);
54147c478bd9Sstevel@tonic-gate 			mi_free((char *)nd->nd_tbl);
54157c478bd9Sstevel@tonic-gate 		} else {
54167c478bd9Sstevel@tonic-gate 			nd->nd_free_count--;
54177c478bd9Sstevel@tonic-gate 			nde->nde_name = "?";
54187c478bd9Sstevel@tonic-gate 			nde->nde_get_pfi = nd_get_names;
54197c478bd9Sstevel@tonic-gate 			nde->nde_set_pfi = nd_set_default;
54207c478bd9Sstevel@tonic-gate 		}
54217c478bd9Sstevel@tonic-gate 		nde->nde_data = (caddr_t)nd;
54227c478bd9Sstevel@tonic-gate 		nd->nd_tbl = nde;
54237c478bd9Sstevel@tonic-gate 		nd->nd_size += NDE_ALLOC_SIZE;
54247c478bd9Sstevel@tonic-gate 	}
54257c478bd9Sstevel@tonic-gate 
54267c478bd9Sstevel@tonic-gate 	for (nde = nd->nd_tbl; nde->nde_name; nde++)
54277c478bd9Sstevel@tonic-gate 		;
54287c478bd9Sstevel@tonic-gate 	nd->nd_free_count--;
54297c478bd9Sstevel@tonic-gate fill_it:
54307c478bd9Sstevel@tonic-gate 	nde->nde_name = name;
54317c478bd9Sstevel@tonic-gate 	nde->nde_get_pfi = get_pfi ? get_pfi : nd_get_default;
54327c478bd9Sstevel@tonic-gate 	nde->nde_set_pfi = set_pfi ? set_pfi : nd_set_default;
54337c478bd9Sstevel@tonic-gate 	nde->nde_data = data;
54347c478bd9Sstevel@tonic-gate 	return (B_TRUE);
54357c478bd9Sstevel@tonic-gate }
54367c478bd9Sstevel@tonic-gate 
54377c478bd9Sstevel@tonic-gate /*
54387c478bd9Sstevel@tonic-gate  * To set up the mac address for the network interface:
54397c478bd9Sstevel@tonic-gate  * The adapter card may support a local mac address which is published
54407c478bd9Sstevel@tonic-gate  * in a device node property "local-mac-address". This mac address is
54417c478bd9Sstevel@tonic-gate  * treated as the factory-installed mac address for DLPI interface.
54427c478bd9Sstevel@tonic-gate  * If the adapter firmware has used the device for diskless boot
54437c478bd9Sstevel@tonic-gate  * operation it publishes a property called "mac-address" for use by
54447c478bd9Sstevel@tonic-gate  * inetboot and the device driver.
54457c478bd9Sstevel@tonic-gate  * If "mac-address" is not found, the system options property
54467c478bd9Sstevel@tonic-gate  * "local-mac-address" is used to select the mac-address. If this option
54477c478bd9Sstevel@tonic-gate  * is set to "true", and "local-mac-address" has been found, then
54487c478bd9Sstevel@tonic-gate  * local-mac-address is used; otherwise the system mac address is used
54497c478bd9Sstevel@tonic-gate  * by calling the "localetheraddr()" function.
54507c478bd9Sstevel@tonic-gate  */
54517c478bd9Sstevel@tonic-gate static void
54527c478bd9Sstevel@tonic-gate hme_setup_mac_address(struct hme *hmep, dev_info_t *dip)
54537c478bd9Sstevel@tonic-gate {
54547c478bd9Sstevel@tonic-gate 	char	*prop;
54557c478bd9Sstevel@tonic-gate 	int	prop_len = sizeof (int);
54567c478bd9Sstevel@tonic-gate 
54577c478bd9Sstevel@tonic-gate 	hmep->hme_addrflags = 0;
54587c478bd9Sstevel@tonic-gate 
54597c478bd9Sstevel@tonic-gate 	/*
54607c478bd9Sstevel@tonic-gate 	 * Check if it is an adapter with its own local mac address
54617c478bd9Sstevel@tonic-gate 	 * If it is present, save it as the "factory-address"
54627c478bd9Sstevel@tonic-gate 	 * for this adapter.
54637c478bd9Sstevel@tonic-gate 	 */
546485025c03Sgd 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
546585025c03Sgd 	    "local-mac-address",
546685025c03Sgd 	    (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) {
54677c478bd9Sstevel@tonic-gate 		if (prop_len == ETHERADDRL) {
54687c478bd9Sstevel@tonic-gate 			hmep->hme_addrflags = HME_FACTADDR_PRESENT;
54697c478bd9Sstevel@tonic-gate 			ether_bcopy(prop, &hmep->hme_factaddr);
54707c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG2(hmep, SEVERITY_NONE, DISPLAY_MSG,
5471*0219346bSGarrett D'Amore 			    "Local Ethernet address = %s",
547285025c03Sgd 			    ether_sprintf(&hmep->hme_factaddr));
54737c478bd9Sstevel@tonic-gate 		}
54747c478bd9Sstevel@tonic-gate 		kmem_free(prop, prop_len);
54757c478bd9Sstevel@tonic-gate 	}
54767c478bd9Sstevel@tonic-gate 
54777c478bd9Sstevel@tonic-gate 	/*
54787c478bd9Sstevel@tonic-gate 	 * Check if the adapter has published "mac-address" property.
54797c478bd9Sstevel@tonic-gate 	 * If it is present, use it as the mac address for this device.
54807c478bd9Sstevel@tonic-gate 	 */
548185025c03Sgd 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, DDI_PROP_DONTPASS,
548285025c03Sgd 	    "mac-address", (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) {
54837c478bd9Sstevel@tonic-gate 		if (prop_len >= ETHERADDRL) {
54847c478bd9Sstevel@tonic-gate 			ether_bcopy(prop, &hmep->hme_ouraddr);
54857c478bd9Sstevel@tonic-gate 			kmem_free(prop, prop_len);
54867c478bd9Sstevel@tonic-gate 			return;
54877c478bd9Sstevel@tonic-gate 		}
54887c478bd9Sstevel@tonic-gate 		kmem_free(prop, prop_len);
54897c478bd9Sstevel@tonic-gate 	}
54907c478bd9Sstevel@tonic-gate 
5491*0219346bSGarrett D'Amore #ifdef	__sparc
5492*0219346bSGarrett D'Amore 	/*
5493*0219346bSGarrett D'Amore 	 * On sparc, we might be able to use the mac address from the
5494*0219346bSGarrett D'Amore 	 * system.  However, on all other systems, we need to use the
5495*0219346bSGarrett D'Amore 	 * address from the PROM.
5496*0219346bSGarrett D'Amore 	 */
54977c478bd9Sstevel@tonic-gate 	if (ddi_getlongprop(DDI_DEV_T_ANY, dip, 0, "local-mac-address?",
549885025c03Sgd 	    (caddr_t)&prop, &prop_len) == DDI_PROP_SUCCESS) {
54997c478bd9Sstevel@tonic-gate 		if ((strncmp("true", prop, prop_len) == 0) &&
550085025c03Sgd 		    (hmep->hme_addrflags & HME_FACTADDR_PRESENT)) {
55017c478bd9Sstevel@tonic-gate 			hmep->hme_addrflags |= HME_FACTADDR_USE;
55027c478bd9Sstevel@tonic-gate 			ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr);
55037c478bd9Sstevel@tonic-gate 			kmem_free(prop, prop_len);
55047c478bd9Sstevel@tonic-gate 			HME_FAULT_MSG1(hmep, SEVERITY_NONE, DISPLAY_MSG,
5505*0219346bSGarrett D'Amore 			    "Using local MAC address");
55067c478bd9Sstevel@tonic-gate 			return;
55077c478bd9Sstevel@tonic-gate 		}
55087c478bd9Sstevel@tonic-gate 		kmem_free(prop, prop_len);
55097c478bd9Sstevel@tonic-gate 	}
55107c478bd9Sstevel@tonic-gate 
55117c478bd9Sstevel@tonic-gate 	/*
55127c478bd9Sstevel@tonic-gate 	 * Get the system ethernet address.
55137c478bd9Sstevel@tonic-gate 	 */
55147c478bd9Sstevel@tonic-gate 	(void) localetheraddr((struct ether_addr *)NULL, &hmep->hme_ouraddr);
5515*0219346bSGarrett D'Amore #else
5516*0219346bSGarrett D'Amore 	ether_bcopy(&hmep->hme_factaddr, &hmep->hme_ouraddr);
5517*0219346bSGarrett D'Amore #endif
55187c478bd9Sstevel@tonic-gate }
55197c478bd9Sstevel@tonic-gate 
55207c478bd9Sstevel@tonic-gate /* ARGSUSED */
55217c478bd9Sstevel@tonic-gate static void
55227c478bd9Sstevel@tonic-gate hme_check_acc_handle(char *file, uint_t line, struct hme *hmep,
55237c478bd9Sstevel@tonic-gate     ddi_acc_handle_t handle)
55247c478bd9Sstevel@tonic-gate {
55257c478bd9Sstevel@tonic-gate }
5526