xref: /onnv-gate/usr/src/uts/common/io/gld.c (revision 2163:7ec44efa9cdb)
10Sstevel@tonic-gate /*
20Sstevel@tonic-gate  * CDDL HEADER START
30Sstevel@tonic-gate  *
40Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
51521Syz147064  * Common Development and Distribution License (the "License").
61521Syz147064  * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate  *
80Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate  * See the License for the specific language governing permissions
110Sstevel@tonic-gate  * and limitations under the License.
120Sstevel@tonic-gate  *
130Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate  *
190Sstevel@tonic-gate  * CDDL HEADER END
200Sstevel@tonic-gate  */
210Sstevel@tonic-gate /*
221521Syz147064  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
230Sstevel@tonic-gate  * Use is subject to license terms.
240Sstevel@tonic-gate  */
250Sstevel@tonic-gate 
260Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
270Sstevel@tonic-gate 
280Sstevel@tonic-gate /*
290Sstevel@tonic-gate  * gld - Generic LAN Driver Version 2, PSARC/1997/382
300Sstevel@tonic-gate  *
310Sstevel@tonic-gate  * This is a utility module that provides generic facilities for
320Sstevel@tonic-gate  * LAN	drivers.  The DLPI protocol and most STREAMS interfaces
330Sstevel@tonic-gate  * are handled here.
340Sstevel@tonic-gate  *
350Sstevel@tonic-gate  * It no longer provides compatibility with drivers
360Sstevel@tonic-gate  * implemented according to the GLD v0 documentation published
370Sstevel@tonic-gate  * in 1993. (See PSARC 2003/728)
380Sstevel@tonic-gate  */
390Sstevel@tonic-gate 
400Sstevel@tonic-gate 
410Sstevel@tonic-gate #include <sys/types.h>
420Sstevel@tonic-gate #include <sys/errno.h>
430Sstevel@tonic-gate #include <sys/stropts.h>
440Sstevel@tonic-gate #include <sys/stream.h>
450Sstevel@tonic-gate #include <sys/kmem.h>
460Sstevel@tonic-gate #include <sys/stat.h>
470Sstevel@tonic-gate #include <sys/modctl.h>
480Sstevel@tonic-gate #include <sys/kstat.h>
490Sstevel@tonic-gate #include <sys/debug.h>
500Sstevel@tonic-gate #include <sys/note.h>
510Sstevel@tonic-gate #include <sys/sysmacros.h>
520Sstevel@tonic-gate 
530Sstevel@tonic-gate #include <sys/byteorder.h>
540Sstevel@tonic-gate #include <sys/strsun.h>
550Sstevel@tonic-gate #include <sys/strsubr.h>
560Sstevel@tonic-gate #include <sys/dlpi.h>
570Sstevel@tonic-gate #include <sys/pattr.h>
580Sstevel@tonic-gate #include <sys/ethernet.h>
590Sstevel@tonic-gate #include <sys/ib/clients/ibd/ibd.h>
600Sstevel@tonic-gate #include <sys/policy.h>
610Sstevel@tonic-gate #include <sys/atomic.h>
620Sstevel@tonic-gate 
630Sstevel@tonic-gate #include <sys/multidata.h>
640Sstevel@tonic-gate #include <sys/gld.h>
650Sstevel@tonic-gate #include <sys/gldpriv.h>
660Sstevel@tonic-gate 
670Sstevel@tonic-gate #include <sys/ddi.h>
680Sstevel@tonic-gate #include <sys/sunddi.h>
690Sstevel@tonic-gate 
700Sstevel@tonic-gate /*
710Sstevel@tonic-gate  * Macro to atomically increment counters of type uint32_t, uint64_t
720Sstevel@tonic-gate  * and ulong_t.
730Sstevel@tonic-gate  */
740Sstevel@tonic-gate #define	BUMP(stat, delta)	do {				\
750Sstevel@tonic-gate 	_NOTE(CONSTANTCONDITION)				\
760Sstevel@tonic-gate 	if (sizeof (stat) == sizeof (uint32_t))	{		\
770Sstevel@tonic-gate 		atomic_add_32((uint32_t *)&stat, delta);	\
780Sstevel@tonic-gate 	_NOTE(CONSTANTCONDITION)				\
790Sstevel@tonic-gate 	} else if (sizeof (stat) == sizeof (uint64_t)) {	\
800Sstevel@tonic-gate 		atomic_add_64((uint64_t *)&stat, delta);	\
810Sstevel@tonic-gate 	}							\
820Sstevel@tonic-gate 	_NOTE(CONSTANTCONDITION)				\
830Sstevel@tonic-gate } while (0)
840Sstevel@tonic-gate 
850Sstevel@tonic-gate #define	UPDATE_STATS(vlan, pktinfo, number)	{		\
860Sstevel@tonic-gate 	if ((pktinfo).isBroadcast)				\
870Sstevel@tonic-gate 		(vlan)->gldv_stats->glds_brdcstxmt += (number);	\
880Sstevel@tonic-gate 	else if ((pktinfo).isMulticast)				\
890Sstevel@tonic-gate 		(vlan)->gldv_stats->glds_multixmt += (number);	\
900Sstevel@tonic-gate 	(vlan)->gldv_stats->glds_bytexmt64 += (pktinfo).pktLen;	\
910Sstevel@tonic-gate 	(vlan)->gldv_stats->glds_pktxmt64 += (number);		\
920Sstevel@tonic-gate }
930Sstevel@tonic-gate 
940Sstevel@tonic-gate #ifdef GLD_DEBUG
950Sstevel@tonic-gate int gld_debug = GLDERRS;
960Sstevel@tonic-gate #endif
970Sstevel@tonic-gate 
980Sstevel@tonic-gate /* called from gld_register */
990Sstevel@tonic-gate static int gld_initstats(gld_mac_info_t *);
1000Sstevel@tonic-gate 
1010Sstevel@tonic-gate /* called from kstat mechanism, and from wsrv's get_statistics */
1020Sstevel@tonic-gate static int gld_update_kstat(kstat_t *, int);
1030Sstevel@tonic-gate 
1040Sstevel@tonic-gate /* statistics for additional vlans */
1050Sstevel@tonic-gate static int gld_init_vlan_stats(gld_vlan_t *);
1060Sstevel@tonic-gate static int gld_update_vlan_kstat(kstat_t *, int);
1070Sstevel@tonic-gate 
1080Sstevel@tonic-gate /* called from gld_getinfo */
1090Sstevel@tonic-gate static dev_info_t *gld_finddevinfo(dev_t);
1100Sstevel@tonic-gate 
1110Sstevel@tonic-gate /* called from wput, wsrv, unidata, and v0_sched to send a packet */
1120Sstevel@tonic-gate /* also from the source routing stuff for sending RDE protocol packets */
1130Sstevel@tonic-gate static int gld_start(queue_t *, mblk_t *, int, uint32_t);
1140Sstevel@tonic-gate static int gld_start_mdt(queue_t *, mblk_t *, int);
1150Sstevel@tonic-gate 
1160Sstevel@tonic-gate /* called from gld_start[_mdt] to loopback packet(s) in promiscuous mode */
1170Sstevel@tonic-gate static void gld_precv(gld_mac_info_t *, gld_vlan_t *, mblk_t *);
1180Sstevel@tonic-gate static void gld_precv_mdt(gld_mac_info_t *, gld_vlan_t *, mblk_t *,
1190Sstevel@tonic-gate     pdesc_t *, pktinfo_t *);
1200Sstevel@tonic-gate 
1210Sstevel@tonic-gate /* receive group: called from gld_recv and gld_precv* with maclock held */
1220Sstevel@tonic-gate static void gld_sendup(gld_mac_info_t *, gld_vlan_t *, pktinfo_t *, mblk_t *,
1230Sstevel@tonic-gate     int (*)());
1240Sstevel@tonic-gate static int gld_accept(gld_t *, pktinfo_t *);
1250Sstevel@tonic-gate static int gld_mcmatch(gld_t *, pktinfo_t *);
1260Sstevel@tonic-gate static int gld_multicast(unsigned char *, gld_t *);
1270Sstevel@tonic-gate static int gld_paccept(gld_t *, pktinfo_t *);
1280Sstevel@tonic-gate static void gld_passon(gld_t *, mblk_t *, pktinfo_t *,
1290Sstevel@tonic-gate     void (*)(queue_t *, mblk_t *));
1300Sstevel@tonic-gate static mblk_t *gld_addudind(gld_t *, mblk_t *, pktinfo_t *);
1310Sstevel@tonic-gate 
1320Sstevel@tonic-gate /* wsrv group: called from wsrv, single threaded per queue */
1330Sstevel@tonic-gate static int gld_ioctl(queue_t *, mblk_t *);
1340Sstevel@tonic-gate static void gld_fastpath(gld_t *, queue_t *, mblk_t *);
1350Sstevel@tonic-gate static int gld_cmds(queue_t *, mblk_t *);
1360Sstevel@tonic-gate static mblk_t *gld_bindack(queue_t *, mblk_t *);
1370Sstevel@tonic-gate static int gld_notify_req(queue_t *, mblk_t *);
1380Sstevel@tonic-gate static int gld_udqos(queue_t *, mblk_t *);
1390Sstevel@tonic-gate static int gld_bind(queue_t *, mblk_t *);
1400Sstevel@tonic-gate static int gld_unbind(queue_t *, mblk_t *);
1410Sstevel@tonic-gate static int gld_inforeq(queue_t *, mblk_t *);
1420Sstevel@tonic-gate static int gld_unitdata(queue_t *, mblk_t *);
1430Sstevel@tonic-gate static int gldattach(queue_t *, mblk_t *);
1440Sstevel@tonic-gate static int gldunattach(queue_t *, mblk_t *);
1450Sstevel@tonic-gate static int gld_enable_multi(queue_t *, mblk_t *);
1460Sstevel@tonic-gate static int gld_disable_multi(queue_t *, mblk_t *);
1470Sstevel@tonic-gate static void gld_send_disable_multi(gld_mac_info_t *, gld_mcast_t *);
1480Sstevel@tonic-gate static int gld_promisc(queue_t *, mblk_t *, t_uscalar_t, boolean_t);
1490Sstevel@tonic-gate static int gld_physaddr(queue_t *, mblk_t *);
1500Sstevel@tonic-gate static int gld_setaddr(queue_t *, mblk_t *);
1510Sstevel@tonic-gate static int gld_get_statistics(queue_t *, mblk_t *);
1520Sstevel@tonic-gate static int gld_cap(queue_t *, mblk_t *);
1530Sstevel@tonic-gate static int gld_cap_ack(queue_t *, mblk_t *);
1540Sstevel@tonic-gate static int gld_cap_enable(queue_t *, mblk_t *);
1550Sstevel@tonic-gate 
1560Sstevel@tonic-gate /* misc utilities, some requiring various mutexes held */
1570Sstevel@tonic-gate static int gld_start_mac(gld_mac_info_t *);
1580Sstevel@tonic-gate static void gld_stop_mac(gld_mac_info_t *);
1590Sstevel@tonic-gate static void gld_set_ipq(gld_t *);
1600Sstevel@tonic-gate static void gld_flushqueue(queue_t *);
1610Sstevel@tonic-gate static glddev_t *gld_devlookup(int);
1620Sstevel@tonic-gate static int gld_findminor(glddev_t *);
1630Sstevel@tonic-gate static void gldinsque(void *, void *);
1640Sstevel@tonic-gate static void gldremque(void *);
1650Sstevel@tonic-gate void gld_bitrevcopy(caddr_t, caddr_t, size_t);
1660Sstevel@tonic-gate void gld_bitreverse(uchar_t *, size_t);
1670Sstevel@tonic-gate char *gld_macaddr_sprintf(char *, unsigned char *, int);
1680Sstevel@tonic-gate static gld_vlan_t *gld_add_vlan(gld_mac_info_t *, uint32_t vid);
1690Sstevel@tonic-gate static void gld_rem_vlan(gld_vlan_t *);
1700Sstevel@tonic-gate gld_vlan_t *gld_find_vlan(gld_mac_info_t *, uint32_t);
1710Sstevel@tonic-gate gld_vlan_t *gld_get_vlan(gld_mac_info_t *, uint32_t);
1720Sstevel@tonic-gate 
1730Sstevel@tonic-gate #ifdef GLD_DEBUG
1740Sstevel@tonic-gate static void gld_check_assertions(void);
1750Sstevel@tonic-gate extern void gld_sr_dump(gld_mac_info_t *);
1760Sstevel@tonic-gate #endif
1770Sstevel@tonic-gate 
1780Sstevel@tonic-gate /*
1790Sstevel@tonic-gate  * Allocate and zero-out "number" structures each of type "structure" in
1800Sstevel@tonic-gate  * kernel memory.
1810Sstevel@tonic-gate  */
1820Sstevel@tonic-gate #define	GETSTRUCT(structure, number)   \
1830Sstevel@tonic-gate 	(kmem_zalloc((uint_t)(sizeof (structure) * (number)), KM_NOSLEEP))
1840Sstevel@tonic-gate 
1850Sstevel@tonic-gate #define	abs(a) ((a) < 0 ? -(a) : a)
1860Sstevel@tonic-gate 
1870Sstevel@tonic-gate uint32_t gld_global_options = GLD_OPT_NO_ETHRXSNAP;
1880Sstevel@tonic-gate 
1890Sstevel@tonic-gate /*
1900Sstevel@tonic-gate  * VLANs are only supported on ethernet devices that manipulate VLAN headers
1910Sstevel@tonic-gate  * themselves.
1920Sstevel@tonic-gate  */
1930Sstevel@tonic-gate #define	VLAN_CAPABLE(macinfo) \
1940Sstevel@tonic-gate 	((macinfo)->gldm_type == DL_ETHER && \
1950Sstevel@tonic-gate 	(macinfo)->gldm_send_tagged != NULL)
1960Sstevel@tonic-gate 
1970Sstevel@tonic-gate /*
1980Sstevel@tonic-gate  * The set of notifications generatable by GLD itself, the additional
1990Sstevel@tonic-gate  * set that can be generated if the MAC driver provide the link-state
2000Sstevel@tonic-gate  * tracking callback capability, and the set supported by the GLD
2010Sstevel@tonic-gate  * notification code below.
2020Sstevel@tonic-gate  *
2030Sstevel@tonic-gate  * PLEASE keep these in sync with what the code actually does!
2040Sstevel@tonic-gate  */
2050Sstevel@tonic-gate static const uint32_t gld_internal_notes =	DL_NOTE_PROMISC_ON_PHYS |
2060Sstevel@tonic-gate 						DL_NOTE_PROMISC_OFF_PHYS |
2070Sstevel@tonic-gate 						DL_NOTE_PHYS_ADDR;
2080Sstevel@tonic-gate static const uint32_t gld_linkstate_notes =	DL_NOTE_LINK_DOWN |
2090Sstevel@tonic-gate 						DL_NOTE_LINK_UP |
2100Sstevel@tonic-gate 						DL_NOTE_SPEED;
2110Sstevel@tonic-gate static const uint32_t gld_supported_notes =	DL_NOTE_PROMISC_ON_PHYS |
2120Sstevel@tonic-gate 						DL_NOTE_PROMISC_OFF_PHYS |
2130Sstevel@tonic-gate 						DL_NOTE_PHYS_ADDR |
2140Sstevel@tonic-gate 						DL_NOTE_LINK_DOWN |
2150Sstevel@tonic-gate 						DL_NOTE_LINK_UP |
2160Sstevel@tonic-gate 						DL_NOTE_SPEED;
2170Sstevel@tonic-gate 
2180Sstevel@tonic-gate /* Media must correspond to #defines in gld.h */
2190Sstevel@tonic-gate static char *gld_media[] = {
2200Sstevel@tonic-gate 	"unknown",	/* GLDM_UNKNOWN - driver cannot determine media */
2210Sstevel@tonic-gate 	"aui",		/* GLDM_AUI */
2220Sstevel@tonic-gate 	"bnc",		/* GLDM_BNC */
2230Sstevel@tonic-gate 	"twpair",	/* GLDM_TP */
2240Sstevel@tonic-gate 	"fiber",	/* GLDM_FIBER */
2250Sstevel@tonic-gate 	"100baseT",	/* GLDM_100BT */
2260Sstevel@tonic-gate 	"100vgAnyLan",	/* GLDM_VGANYLAN */
2270Sstevel@tonic-gate 	"10baseT",	/* GLDM_10BT */
2280Sstevel@tonic-gate 	"ring4",	/* GLDM_RING4 */
2290Sstevel@tonic-gate 	"ring16",	/* GLDM_RING16 */
2300Sstevel@tonic-gate 	"PHY/MII",	/* GLDM_PHYMII */
2310Sstevel@tonic-gate 	"100baseTX",	/* GLDM_100BTX */
2320Sstevel@tonic-gate 	"100baseT4",	/* GLDM_100BT4 */
2330Sstevel@tonic-gate 	"unknown",	/* skip */
2340Sstevel@tonic-gate 	"ipib",		/* GLDM_IB */
2350Sstevel@tonic-gate };
2360Sstevel@tonic-gate 
2370Sstevel@tonic-gate /* Must correspond to #defines in gld.h */
2380Sstevel@tonic-gate static char *gld_duplex[] = {
2390Sstevel@tonic-gate 	"unknown",	/* GLD_DUPLEX_UNKNOWN - not known or not applicable */
2400Sstevel@tonic-gate 	"half",		/* GLD_DUPLEX_HALF */
2410Sstevel@tonic-gate 	"full"		/* GLD_DUPLEX_FULL */
2420Sstevel@tonic-gate };
2430Sstevel@tonic-gate 
2440Sstevel@tonic-gate extern int gld_interpret_ether(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
2450Sstevel@tonic-gate extern int gld_interpret_fddi(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
2460Sstevel@tonic-gate extern int gld_interpret_tr(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
2470Sstevel@tonic-gate extern int gld_interpret_ib(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
2480Sstevel@tonic-gate extern void gld_interpret_mdt_ib(gld_mac_info_t *, mblk_t *, pdescinfo_t *,
2490Sstevel@tonic-gate     pktinfo_t *, int);
2500Sstevel@tonic-gate 
2510Sstevel@tonic-gate extern mblk_t *gld_fastpath_ether(gld_t *, mblk_t *);
2520Sstevel@tonic-gate extern mblk_t *gld_fastpath_fddi(gld_t *, mblk_t *);
2530Sstevel@tonic-gate extern mblk_t *gld_fastpath_tr(gld_t *, mblk_t *);
2540Sstevel@tonic-gate extern mblk_t *gld_fastpath_ib(gld_t *, mblk_t *);
2550Sstevel@tonic-gate 
2560Sstevel@tonic-gate extern mblk_t *gld_unitdata_ether(gld_t *, mblk_t *);
2570Sstevel@tonic-gate extern mblk_t *gld_unitdata_fddi(gld_t *, mblk_t *);
2580Sstevel@tonic-gate extern mblk_t *gld_unitdata_tr(gld_t *, mblk_t *);
2590Sstevel@tonic-gate extern mblk_t *gld_unitdata_ib(gld_t *, mblk_t *);
2600Sstevel@tonic-gate 
2610Sstevel@tonic-gate extern void gld_init_ether(gld_mac_info_t *);
2620Sstevel@tonic-gate extern void gld_init_fddi(gld_mac_info_t *);
2630Sstevel@tonic-gate extern void gld_init_tr(gld_mac_info_t *);
2640Sstevel@tonic-gate extern void gld_init_ib(gld_mac_info_t *);
2650Sstevel@tonic-gate 
2660Sstevel@tonic-gate extern void gld_uninit_ether(gld_mac_info_t *);
2670Sstevel@tonic-gate extern void gld_uninit_fddi(gld_mac_info_t *);
2680Sstevel@tonic-gate extern void gld_uninit_tr(gld_mac_info_t *);
2690Sstevel@tonic-gate extern void gld_uninit_ib(gld_mac_info_t *);
2700Sstevel@tonic-gate 
2710Sstevel@tonic-gate /*
2720Sstevel@tonic-gate  * Interface types currently supported by GLD.
2730Sstevel@tonic-gate  * If you add new types, you must check all "XXX" strings in the GLD source
2740Sstevel@tonic-gate  * for implementation issues that may affect the support of your new type.
2750Sstevel@tonic-gate  * In particular, any type with gldm_addrlen > 6, or gldm_saplen != -2, will
2760Sstevel@tonic-gate  * require generalizing this GLD source to handle the new cases.  In other
2770Sstevel@tonic-gate  * words there are assumptions built into the code in a few places that must
2780Sstevel@tonic-gate  * be fixed.  Be sure to turn on DEBUG/ASSERT code when testing a new type.
2790Sstevel@tonic-gate  */
2800Sstevel@tonic-gate static gld_interface_t interfaces[] = {
2810Sstevel@tonic-gate 
2820Sstevel@tonic-gate 	/* Ethernet Bus */
2830Sstevel@tonic-gate 	{
2840Sstevel@tonic-gate 		DL_ETHER,
2850Sstevel@tonic-gate 		(uint_t)-1,
2860Sstevel@tonic-gate 		sizeof (struct ether_mac_frm),
2870Sstevel@tonic-gate 		gld_interpret_ether,
2880Sstevel@tonic-gate 		NULL,
2890Sstevel@tonic-gate 		gld_fastpath_ether,
2900Sstevel@tonic-gate 		gld_unitdata_ether,
2910Sstevel@tonic-gate 		gld_init_ether,
2920Sstevel@tonic-gate 		gld_uninit_ether,
2930Sstevel@tonic-gate 		"ether"
2940Sstevel@tonic-gate 	},
2950Sstevel@tonic-gate 
2960Sstevel@tonic-gate 	/* Fiber Distributed data interface */
2970Sstevel@tonic-gate 	{
2980Sstevel@tonic-gate 		DL_FDDI,
2990Sstevel@tonic-gate 		4352,
3000Sstevel@tonic-gate 		sizeof (struct fddi_mac_frm),
3010Sstevel@tonic-gate 		gld_interpret_fddi,
3020Sstevel@tonic-gate 		NULL,
3030Sstevel@tonic-gate 		gld_fastpath_fddi,
3040Sstevel@tonic-gate 		gld_unitdata_fddi,
3050Sstevel@tonic-gate 		gld_init_fddi,
3060Sstevel@tonic-gate 		gld_uninit_fddi,
3070Sstevel@tonic-gate 		"fddi"
3080Sstevel@tonic-gate 	},
3090Sstevel@tonic-gate 
3100Sstevel@tonic-gate 	/* Token Ring interface */
3110Sstevel@tonic-gate 	{
3120Sstevel@tonic-gate 		DL_TPR,
3130Sstevel@tonic-gate 		17914,
3140Sstevel@tonic-gate 		-1,			/* variable header size */
3150Sstevel@tonic-gate 		gld_interpret_tr,
3160Sstevel@tonic-gate 		NULL,
3170Sstevel@tonic-gate 		gld_fastpath_tr,
3180Sstevel@tonic-gate 		gld_unitdata_tr,
3190Sstevel@tonic-gate 		gld_init_tr,
3200Sstevel@tonic-gate 		gld_uninit_tr,
3210Sstevel@tonic-gate 		"tpr"
3220Sstevel@tonic-gate 	},
3230Sstevel@tonic-gate 
3240Sstevel@tonic-gate 	/* Infiniband */
3250Sstevel@tonic-gate 	{
3260Sstevel@tonic-gate 		DL_IB,
3270Sstevel@tonic-gate 		4092,
3280Sstevel@tonic-gate 		sizeof (struct ipoib_header),
3290Sstevel@tonic-gate 		gld_interpret_ib,
3300Sstevel@tonic-gate 		gld_interpret_mdt_ib,
3310Sstevel@tonic-gate 		gld_fastpath_ib,
3320Sstevel@tonic-gate 		gld_unitdata_ib,
3330Sstevel@tonic-gate 		gld_init_ib,
3340Sstevel@tonic-gate 		gld_uninit_ib,
3350Sstevel@tonic-gate 		"ipib"
3360Sstevel@tonic-gate 	},
3370Sstevel@tonic-gate };
3380Sstevel@tonic-gate 
3390Sstevel@tonic-gate /*
3400Sstevel@tonic-gate  * bit reversal lookup table.
3410Sstevel@tonic-gate  */
3420Sstevel@tonic-gate static	uchar_t bit_rev[] = {
3430Sstevel@tonic-gate 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0,
3440Sstevel@tonic-gate 	0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
3450Sstevel@tonic-gate 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4,
3460Sstevel@tonic-gate 	0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
3470Sstevel@tonic-gate 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc,
3480Sstevel@tonic-gate 	0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
3490Sstevel@tonic-gate 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca,
3500Sstevel@tonic-gate 	0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
3510Sstevel@tonic-gate 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6,
3520Sstevel@tonic-gate 	0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
3530Sstevel@tonic-gate 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1,
3540Sstevel@tonic-gate 	0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
3550Sstevel@tonic-gate 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
3560Sstevel@tonic-gate 	0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
3570Sstevel@tonic-gate 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd,
3580Sstevel@tonic-gate 	0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
3590Sstevel@tonic-gate 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3,
3600Sstevel@tonic-gate 	0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
3610Sstevel@tonic-gate 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7,
3620Sstevel@tonic-gate 	0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
3630Sstevel@tonic-gate 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf,
3640Sstevel@tonic-gate 	0x3f, 0xbf, 0x7f, 0xff,
3650Sstevel@tonic-gate };
3660Sstevel@tonic-gate 
3670Sstevel@tonic-gate /*
3680Sstevel@tonic-gate  * User priorities, mapped from b_band.
3690Sstevel@tonic-gate  */
3700Sstevel@tonic-gate static uint32_t user_priority[] = {
3710Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3720Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3730Sstevel@tonic-gate 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3740Sstevel@tonic-gate 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3750Sstevel@tonic-gate 	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3760Sstevel@tonic-gate 	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3770Sstevel@tonic-gate 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3780Sstevel@tonic-gate 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3790Sstevel@tonic-gate 	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3800Sstevel@tonic-gate 	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3810Sstevel@tonic-gate 	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3820Sstevel@tonic-gate 	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3830Sstevel@tonic-gate 	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
3840Sstevel@tonic-gate 	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
3850Sstevel@tonic-gate 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3860Sstevel@tonic-gate 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
3870Sstevel@tonic-gate };
3880Sstevel@tonic-gate 
3890Sstevel@tonic-gate #define	UPRI(gld, band)	((band != 0) ? user_priority[(band)] : (gld)->gld_upri)
3900Sstevel@tonic-gate 
3910Sstevel@tonic-gate static struct glddevice gld_device_list;  /* Per-system root of GLD tables */
3920Sstevel@tonic-gate 
3930Sstevel@tonic-gate /*
3940Sstevel@tonic-gate  * Module linkage information for the kernel.
3950Sstevel@tonic-gate  */
3960Sstevel@tonic-gate 
3970Sstevel@tonic-gate static struct modldrv modlmisc = {
3980Sstevel@tonic-gate 	&mod_miscops,		/* Type of module - a utility provider */
3990Sstevel@tonic-gate 	"Generic LAN Driver (" GLD_VERSION_STRING ") %I%"
4000Sstevel@tonic-gate #ifdef GLD_DEBUG
4010Sstevel@tonic-gate 	" DEBUG"
4020Sstevel@tonic-gate #endif
4030Sstevel@tonic-gate };
4040Sstevel@tonic-gate 
4050Sstevel@tonic-gate static struct modlinkage modlinkage = {
4060Sstevel@tonic-gate 	MODREV_1, &modlmisc, NULL
4070Sstevel@tonic-gate };
4080Sstevel@tonic-gate 
4090Sstevel@tonic-gate int
4100Sstevel@tonic-gate _init(void)
4110Sstevel@tonic-gate {
4120Sstevel@tonic-gate 	int e;
4130Sstevel@tonic-gate 
4140Sstevel@tonic-gate 	/* initialize gld_device_list mutex */
4150Sstevel@tonic-gate 	mutex_init(&gld_device_list.gld_devlock, NULL, MUTEX_DRIVER, NULL);
4160Sstevel@tonic-gate 
4170Sstevel@tonic-gate 	/* initialize device driver (per-major) list */
4180Sstevel@tonic-gate 	gld_device_list.gld_next =
4190Sstevel@tonic-gate 	    gld_device_list.gld_prev = &gld_device_list;
4200Sstevel@tonic-gate 
4210Sstevel@tonic-gate 	if ((e = mod_install(&modlinkage)) != 0)
4220Sstevel@tonic-gate 		mutex_destroy(&gld_device_list.gld_devlock);
4230Sstevel@tonic-gate 
4240Sstevel@tonic-gate 	return (e);
4250Sstevel@tonic-gate }
4260Sstevel@tonic-gate 
4270Sstevel@tonic-gate int
4280Sstevel@tonic-gate _fini(void)
4290Sstevel@tonic-gate {
4300Sstevel@tonic-gate 	int e;
4310Sstevel@tonic-gate 
4320Sstevel@tonic-gate 	if ((e = mod_remove(&modlinkage)) != 0)
4330Sstevel@tonic-gate 		return (e);
4340Sstevel@tonic-gate 
4350Sstevel@tonic-gate 	ASSERT(gld_device_list.gld_next ==
4360Sstevel@tonic-gate 	    (glddev_t *)&gld_device_list.gld_next);
4370Sstevel@tonic-gate 	ASSERT(gld_device_list.gld_prev ==
4380Sstevel@tonic-gate 	    (glddev_t *)&gld_device_list.gld_next);
4390Sstevel@tonic-gate 	mutex_destroy(&gld_device_list.gld_devlock);
4400Sstevel@tonic-gate 
4410Sstevel@tonic-gate 	return (e);
4420Sstevel@tonic-gate }
4430Sstevel@tonic-gate 
4440Sstevel@tonic-gate int
4450Sstevel@tonic-gate _info(struct modinfo *modinfop)
4460Sstevel@tonic-gate {
4470Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
4480Sstevel@tonic-gate }
4490Sstevel@tonic-gate 
4500Sstevel@tonic-gate /*
4510Sstevel@tonic-gate  * GLD service routines
4520Sstevel@tonic-gate  */
4530Sstevel@tonic-gate 
4540Sstevel@tonic-gate /* So this gld binary maybe can be forward compatible with future v2 drivers */
4550Sstevel@tonic-gate #define	GLD_MAC_RESERVED (16 * sizeof (caddr_t))
4560Sstevel@tonic-gate 
4570Sstevel@tonic-gate /*ARGSUSED*/
4580Sstevel@tonic-gate gld_mac_info_t *
4590Sstevel@tonic-gate gld_mac_alloc(dev_info_t *devinfo)
4600Sstevel@tonic-gate {
4610Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
4620Sstevel@tonic-gate 
4630Sstevel@tonic-gate 	macinfo = kmem_zalloc(sizeof (gld_mac_info_t) + GLD_MAC_RESERVED,
4640Sstevel@tonic-gate 	    KM_SLEEP);
4650Sstevel@tonic-gate 
4660Sstevel@tonic-gate 	/*
4670Sstevel@tonic-gate 	 * The setting of gldm_driver_version will not be documented or allowed
4680Sstevel@tonic-gate 	 * until a future release.
4690Sstevel@tonic-gate 	 */
4700Sstevel@tonic-gate 	macinfo->gldm_driver_version = GLD_VERSION_200;
4710Sstevel@tonic-gate 
4720Sstevel@tonic-gate 	/*
4730Sstevel@tonic-gate 	 * GLD's version.  This also is undocumented for now, but will be
4740Sstevel@tonic-gate 	 * available if needed in the future.
4750Sstevel@tonic-gate 	 */
4760Sstevel@tonic-gate 	macinfo->gldm_GLD_version = GLD_VERSION;
4770Sstevel@tonic-gate 
4780Sstevel@tonic-gate 	return (macinfo);
4790Sstevel@tonic-gate }
4800Sstevel@tonic-gate 
4810Sstevel@tonic-gate /*
4820Sstevel@tonic-gate  * gld_mac_free must be called after the driver has removed interrupts
4830Sstevel@tonic-gate  * and completely stopped calling gld_recv() and gld_sched().  At that
4840Sstevel@tonic-gate  * point the interrupt routine is guaranteed by the system to have been
4850Sstevel@tonic-gate  * exited and the maclock is no longer needed.  Of course, it is
4860Sstevel@tonic-gate  * expected (required) that (assuming gld_register() succeeded),
4870Sstevel@tonic-gate  * gld_unregister() was called before gld_mac_free().
4880Sstevel@tonic-gate  */
4890Sstevel@tonic-gate void
4900Sstevel@tonic-gate gld_mac_free(gld_mac_info_t *macinfo)
4910Sstevel@tonic-gate {
4920Sstevel@tonic-gate 	ASSERT(macinfo);
4930Sstevel@tonic-gate 	ASSERT(macinfo->gldm_GLD_version == GLD_VERSION);
4940Sstevel@tonic-gate 
4950Sstevel@tonic-gate 	/*
4960Sstevel@tonic-gate 	 * Assert that if we made it through gld_register, then we must
4970Sstevel@tonic-gate 	 * have unregistered.
4980Sstevel@tonic-gate 	 */
4990Sstevel@tonic-gate 	ASSERT(!GLDM_LOCK_INITED(macinfo) ||
5000Sstevel@tonic-gate 	    (macinfo->gldm_GLD_flags & GLD_UNREGISTERED));
5010Sstevel@tonic-gate 
5020Sstevel@tonic-gate 	GLDM_LOCK_DESTROY(macinfo);
5030Sstevel@tonic-gate 
5040Sstevel@tonic-gate 	kmem_free(macinfo, sizeof (gld_mac_info_t) + GLD_MAC_RESERVED);
5050Sstevel@tonic-gate }
5060Sstevel@tonic-gate 
5070Sstevel@tonic-gate /*
5080Sstevel@tonic-gate  * gld_register -- called once per device instance (PPA)
5090Sstevel@tonic-gate  *
5100Sstevel@tonic-gate  * During its attach routine, a real device driver will register with GLD
5110Sstevel@tonic-gate  * so that later opens and dl_attach_reqs will work.  The arguments are the
5120Sstevel@tonic-gate  * devinfo pointer, the device name, and a macinfo structure describing the
5130Sstevel@tonic-gate  * physical device instance.
5140Sstevel@tonic-gate  */
5150Sstevel@tonic-gate int
5160Sstevel@tonic-gate gld_register(dev_info_t *devinfo, char *devname, gld_mac_info_t *macinfo)
5170Sstevel@tonic-gate {
5180Sstevel@tonic-gate 	int mediatype;
5190Sstevel@tonic-gate 	int major = ddi_name_to_major(devname), i;
5200Sstevel@tonic-gate 	glddev_t *glddev;
5210Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
5220Sstevel@tonic-gate 	char minordev[32];
5230Sstevel@tonic-gate 	char pbuf[3*GLD_MAX_ADDRLEN];
5240Sstevel@tonic-gate 	gld_interface_t *ifp;
5250Sstevel@tonic-gate 
5260Sstevel@tonic-gate 	ASSERT(devinfo != NULL);
5270Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
5280Sstevel@tonic-gate 
5290Sstevel@tonic-gate 	if (macinfo->gldm_driver_version != GLD_VERSION)
5300Sstevel@tonic-gate 		return (DDI_FAILURE);
5310Sstevel@tonic-gate 
5320Sstevel@tonic-gate 	mediatype = macinfo->gldm_type;
5330Sstevel@tonic-gate 
5340Sstevel@tonic-gate 	/*
5350Sstevel@tonic-gate 	 * Entry points should be ready for us.
5360Sstevel@tonic-gate 	 * ioctl is optional.
5370Sstevel@tonic-gate 	 * set_multicast and get_stats are optional in v0.
5380Sstevel@tonic-gate 	 * intr is only required if you add an interrupt.
5390Sstevel@tonic-gate 	 */
5400Sstevel@tonic-gate 	ASSERT(macinfo->gldm_reset != NULL);
5410Sstevel@tonic-gate 	ASSERT(macinfo->gldm_start != NULL);
5420Sstevel@tonic-gate 	ASSERT(macinfo->gldm_stop != NULL);
5430Sstevel@tonic-gate 	ASSERT(macinfo->gldm_set_mac_addr != NULL);
5440Sstevel@tonic-gate 	ASSERT(macinfo->gldm_set_promiscuous != NULL);
5450Sstevel@tonic-gate 	ASSERT(macinfo->gldm_send != NULL);
5460Sstevel@tonic-gate 
5470Sstevel@tonic-gate 	ASSERT(macinfo->gldm_maxpkt >= macinfo->gldm_minpkt);
5480Sstevel@tonic-gate 	ASSERT(macinfo->gldm_GLD_version == GLD_VERSION);
5490Sstevel@tonic-gate 	ASSERT(macinfo->gldm_broadcast_addr != NULL);
5500Sstevel@tonic-gate 	ASSERT(macinfo->gldm_vendor_addr != NULL);
5510Sstevel@tonic-gate 	ASSERT(macinfo->gldm_ident != NULL);
5520Sstevel@tonic-gate 
5530Sstevel@tonic-gate 	if (macinfo->gldm_addrlen > GLD_MAX_ADDRLEN) {
5540Sstevel@tonic-gate 		cmn_err(CE_WARN, "GLD: %s driver gldm_addrlen %d > %d not sup"
5550Sstevel@tonic-gate 		    "ported", devname, macinfo->gldm_addrlen, GLD_MAX_ADDRLEN);
5560Sstevel@tonic-gate 		return (DDI_FAILURE);
5570Sstevel@tonic-gate 	}
5580Sstevel@tonic-gate 
5590Sstevel@tonic-gate 	/*
5600Sstevel@tonic-gate 	 * GLD only functions properly with saplen == -2
5610Sstevel@tonic-gate 	 */
5620Sstevel@tonic-gate 	if (macinfo->gldm_saplen != -2) {
5630Sstevel@tonic-gate 		cmn_err(CE_WARN, "GLD: %s driver gldm_saplen %d != -2 "
5640Sstevel@tonic-gate 		    "not supported", devname, macinfo->gldm_saplen);
5650Sstevel@tonic-gate 		return (DDI_FAILURE);
5660Sstevel@tonic-gate 	}
5670Sstevel@tonic-gate 
5680Sstevel@tonic-gate 	/* see gld_rsrv() */
5690Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_NONE, devinfo, 0, "fast_recv", 0))
5700Sstevel@tonic-gate 		macinfo->gldm_options |= GLDOPT_FAST_RECV;
5710Sstevel@tonic-gate 
5720Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
5730Sstevel@tonic-gate 	glddev = gld_devlookup(major);
5740Sstevel@tonic-gate 
5750Sstevel@tonic-gate 	/*
5760Sstevel@tonic-gate 	 *  Allocate per-driver (major) data structure if necessary
5770Sstevel@tonic-gate 	 */
5780Sstevel@tonic-gate 	if (glddev == NULL) {
5790Sstevel@tonic-gate 		/* first occurrence of this device name (major number) */
5800Sstevel@tonic-gate 		glddev = GETSTRUCT(glddev_t, 1);
5810Sstevel@tonic-gate 		if (glddev == NULL) {
5820Sstevel@tonic-gate 			mutex_exit(&gld_device_list.gld_devlock);
5830Sstevel@tonic-gate 			return (DDI_FAILURE);
5840Sstevel@tonic-gate 		}
5850Sstevel@tonic-gate 		(void) strncpy(glddev->gld_name, devname,
5860Sstevel@tonic-gate 		    sizeof (glddev->gld_name) - 1);
5870Sstevel@tonic-gate 		glddev->gld_major = major;
5880Sstevel@tonic-gate 		glddev->gld_nextminor = GLD_MIN_CLONE_MINOR;
5890Sstevel@tonic-gate 		glddev->gld_mac_next = glddev->gld_mac_prev =
5900Sstevel@tonic-gate 			(gld_mac_info_t *)&glddev->gld_mac_next;
5910Sstevel@tonic-gate 		glddev->gld_str_next = glddev->gld_str_prev =
5920Sstevel@tonic-gate 			(gld_t *)&glddev->gld_str_next;
5930Sstevel@tonic-gate 		mutex_init(&glddev->gld_devlock, NULL, MUTEX_DRIVER, NULL);
5940Sstevel@tonic-gate 
5950Sstevel@tonic-gate 		/* allow increase of number of supported multicast addrs */
5960Sstevel@tonic-gate 		glddev->gld_multisize = ddi_getprop(DDI_DEV_T_NONE,
5970Sstevel@tonic-gate 		    devinfo, 0, "multisize", GLD_MAX_MULTICAST);
5980Sstevel@tonic-gate 
5990Sstevel@tonic-gate 		/*
6000Sstevel@tonic-gate 		 * Optionally restrict DLPI provider style
6010Sstevel@tonic-gate 		 *
6020Sstevel@tonic-gate 		 * -1 - don't create style 1 nodes
6030Sstevel@tonic-gate 		 * -2 - don't create style 2 nodes
6040Sstevel@tonic-gate 		 */
6050Sstevel@tonic-gate 		glddev->gld_styles = ddi_getprop(DDI_DEV_T_NONE, devinfo, 0,
6060Sstevel@tonic-gate 		    "gld-provider-styles", 0);
6070Sstevel@tonic-gate 
6080Sstevel@tonic-gate 		/* Stuff that's needed before any PPA gets attached */
6090Sstevel@tonic-gate 		glddev->gld_type = macinfo->gldm_type;
6100Sstevel@tonic-gate 		glddev->gld_minsdu = macinfo->gldm_minpkt;
6110Sstevel@tonic-gate 		glddev->gld_saplen = macinfo->gldm_saplen;
6120Sstevel@tonic-gate 		glddev->gld_addrlen = macinfo->gldm_addrlen;
6130Sstevel@tonic-gate 		glddev->gld_broadcast = kmem_zalloc(macinfo->gldm_addrlen,
6140Sstevel@tonic-gate 		    KM_SLEEP);
6150Sstevel@tonic-gate 		bcopy(macinfo->gldm_broadcast_addr,
6160Sstevel@tonic-gate 		    glddev->gld_broadcast, macinfo->gldm_addrlen);
6170Sstevel@tonic-gate 		glddev->gld_maxsdu = macinfo->gldm_maxpkt;
6180Sstevel@tonic-gate 		gldinsque(glddev, gld_device_list.gld_prev);
6190Sstevel@tonic-gate 	}
6200Sstevel@tonic-gate 	glddev->gld_ndevice++;
6210Sstevel@tonic-gate 	/* Now glddev can't go away until we unregister this mac (or fail) */
6220Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
6230Sstevel@tonic-gate 
6240Sstevel@tonic-gate 	/*
6250Sstevel@tonic-gate 	 *  Per-instance initialization
6260Sstevel@tonic-gate 	 */
6270Sstevel@tonic-gate 
6280Sstevel@tonic-gate 	/*
6290Sstevel@tonic-gate 	 * Initialize per-mac structure that is private to GLD.
6300Sstevel@tonic-gate 	 * Set up interface pointer. These are device class specific pointers
6310Sstevel@tonic-gate 	 * used to handle FDDI/TR/ETHER/IPoIB specific packets.
6320Sstevel@tonic-gate 	 */
6330Sstevel@tonic-gate 	for (i = 0; i < sizeof (interfaces)/sizeof (*interfaces); i++) {
6340Sstevel@tonic-gate 		if (mediatype != interfaces[i].mac_type)
6350Sstevel@tonic-gate 			continue;
6360Sstevel@tonic-gate 
6370Sstevel@tonic-gate 		macinfo->gldm_mac_pvt = kmem_zalloc(sizeof (gld_mac_pvt_t),
6380Sstevel@tonic-gate 		    KM_SLEEP);
6390Sstevel@tonic-gate 		((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep = ifp =
6400Sstevel@tonic-gate 		    &interfaces[i];
6410Sstevel@tonic-gate 		break;
6420Sstevel@tonic-gate 	}
6430Sstevel@tonic-gate 
6440Sstevel@tonic-gate 	if (ifp == NULL) {
6450Sstevel@tonic-gate 		cmn_err(CE_WARN, "GLD: this version does not support %s driver "
6460Sstevel@tonic-gate 		    "of type %d", devname, mediatype);
6470Sstevel@tonic-gate 		goto failure;
6480Sstevel@tonic-gate 	}
6490Sstevel@tonic-gate 
6500Sstevel@tonic-gate 	/*
6510Sstevel@tonic-gate 	 * Driver can only register MTU within legal media range.
6520Sstevel@tonic-gate 	 */
6530Sstevel@tonic-gate 	if (macinfo->gldm_maxpkt > ifp->mtu_size) {
6540Sstevel@tonic-gate 		cmn_err(CE_WARN, "GLD: oversize MTU is specified by driver %s",
6550Sstevel@tonic-gate 		    devname);
6560Sstevel@tonic-gate 		goto failure;
6570Sstevel@tonic-gate 	}
6580Sstevel@tonic-gate 
6590Sstevel@tonic-gate 	/*
6600Sstevel@tonic-gate 	 * For now, only Infiniband drivers can use MDT. Do not add
6610Sstevel@tonic-gate 	 * support for Ethernet, FDDI or TR.
6620Sstevel@tonic-gate 	 */
6630Sstevel@tonic-gate 	if (macinfo->gldm_mdt_pre != NULL) {
6640Sstevel@tonic-gate 		if (mediatype != DL_IB) {
6650Sstevel@tonic-gate 			cmn_err(CE_WARN, "GLD: MDT not supported for %s "
6660Sstevel@tonic-gate 			    "driver of type %d", devname, mediatype);
6670Sstevel@tonic-gate 			goto failure;
6680Sstevel@tonic-gate 		}
6690Sstevel@tonic-gate 
6700Sstevel@tonic-gate 		/*
6710Sstevel@tonic-gate 		 * Validate entry points.
6720Sstevel@tonic-gate 		 */
6730Sstevel@tonic-gate 		if ((macinfo->gldm_mdt_send == NULL) ||
6740Sstevel@tonic-gate 		    (macinfo->gldm_mdt_post == NULL)) {
6750Sstevel@tonic-gate 			cmn_err(CE_WARN, "GLD: invalid MDT entry points for "
6760Sstevel@tonic-gate 			    "%s driver of type %d", devname, mediatype);
6770Sstevel@tonic-gate 			goto failure;
6780Sstevel@tonic-gate 		}
6790Sstevel@tonic-gate 		macinfo->gldm_options |= GLDOPT_MDT;
6800Sstevel@tonic-gate 	}
6810Sstevel@tonic-gate 
6820Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
6830Sstevel@tonic-gate 	mac_pvt->major_dev = glddev;
6840Sstevel@tonic-gate 
6850Sstevel@tonic-gate 	mac_pvt->curr_macaddr = kmem_zalloc(macinfo->gldm_addrlen, KM_SLEEP);
6860Sstevel@tonic-gate 	/*
6870Sstevel@tonic-gate 	 * XXX Do bit-reversed devices store gldm_vendor in canonical
6880Sstevel@tonic-gate 	 * format or in wire format?  Also gldm_broadcast.  For now
6890Sstevel@tonic-gate 	 * we are assuming canonical, but I'm not sure that makes the
6900Sstevel@tonic-gate 	 * most sense for ease of driver implementation.
6910Sstevel@tonic-gate 	 */
6920Sstevel@tonic-gate 	bcopy(macinfo->gldm_vendor_addr, mac_pvt->curr_macaddr,
6930Sstevel@tonic-gate 	    macinfo->gldm_addrlen);
6940Sstevel@tonic-gate 	mac_pvt->statistics = kmem_zalloc(sizeof (struct gld_stats), KM_SLEEP);
6950Sstevel@tonic-gate 
6960Sstevel@tonic-gate 	/*
6970Sstevel@tonic-gate 	 * The available set of notifications is those generatable by GLD
6980Sstevel@tonic-gate 	 * itself, plus those corresponding to the capabilities of the MAC
6990Sstevel@tonic-gate 	 * driver, intersected with those supported by gld_notify_ind() above.
7000Sstevel@tonic-gate 	 */
7010Sstevel@tonic-gate 	mac_pvt->notifications = gld_internal_notes;
7020Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_LINKSTATE)
7030Sstevel@tonic-gate 		mac_pvt->notifications |= gld_linkstate_notes;
7040Sstevel@tonic-gate 	mac_pvt->notifications &= gld_supported_notes;
7050Sstevel@tonic-gate 
7060Sstevel@tonic-gate 	GLDM_LOCK_INIT(macinfo);
7070Sstevel@tonic-gate 
7080Sstevel@tonic-gate 	ddi_set_driver_private(devinfo, macinfo);
7090Sstevel@tonic-gate 
7100Sstevel@tonic-gate 	/*
7110Sstevel@tonic-gate 	 * Now atomically get a PPA and put ourselves on the mac list.
7120Sstevel@tonic-gate 	 */
7130Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
7140Sstevel@tonic-gate 
7150Sstevel@tonic-gate #ifdef DEBUG
7160Sstevel@tonic-gate 	if (macinfo->gldm_ppa != ddi_get_instance(devinfo))
7170Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d instance != ppa %d",
7180Sstevel@tonic-gate 		    ddi_driver_name(devinfo), ddi_get_instance(devinfo),
7190Sstevel@tonic-gate 		    macinfo->gldm_ppa);
7200Sstevel@tonic-gate #endif
7210Sstevel@tonic-gate 
7220Sstevel@tonic-gate 	/*
7230Sstevel@tonic-gate 	 * Create style 2 node (gated by gld-provider-styles property).
7240Sstevel@tonic-gate 	 *
7250Sstevel@tonic-gate 	 * NOTE: When the CLONE_DEV flag is specified to
7260Sstevel@tonic-gate 	 *	 ddi_create_minor_node() the minor number argument is
7270Sstevel@tonic-gate 	 *	 immaterial. Opens of that node will go via the clone
7280Sstevel@tonic-gate 	 *	 driver and gld_open() will always be passed a dev_t with
7290Sstevel@tonic-gate 	 *	 minor of zero.
7300Sstevel@tonic-gate 	 */
7310Sstevel@tonic-gate 	if (glddev->gld_styles != -2) {
7320Sstevel@tonic-gate 		if (ddi_create_minor_node(devinfo, glddev->gld_name, S_IFCHR,
7330Sstevel@tonic-gate 		    0, DDI_NT_NET, CLONE_DEV) == DDI_FAILURE) {
7340Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
7350Sstevel@tonic-gate 			goto late_failure;
7360Sstevel@tonic-gate 		}
7370Sstevel@tonic-gate 	}
7380Sstevel@tonic-gate 
7390Sstevel@tonic-gate 	/*
7400Sstevel@tonic-gate 	 * Create style 1 node (gated by gld-provider-styles property)
7410Sstevel@tonic-gate 	 */
7420Sstevel@tonic-gate 	if (glddev->gld_styles != -1) {
7430Sstevel@tonic-gate 		(void) sprintf(minordev, "%s%d", glddev->gld_name,
7440Sstevel@tonic-gate 		    macinfo->gldm_ppa);
7450Sstevel@tonic-gate 		if (ddi_create_minor_node(devinfo, minordev, S_IFCHR,
7460Sstevel@tonic-gate 		    GLD_STYLE1_PPA_TO_MINOR(macinfo->gldm_ppa), DDI_NT_NET,
7470Sstevel@tonic-gate 		    0) != DDI_SUCCESS) {
7480Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
7490Sstevel@tonic-gate 			goto late_failure;
7500Sstevel@tonic-gate 		}
7510Sstevel@tonic-gate 	}
7520Sstevel@tonic-gate 
7530Sstevel@tonic-gate 	/* add ourselves to this major device's linked list of instances */
7540Sstevel@tonic-gate 	gldinsque(macinfo, glddev->gld_mac_prev);
7550Sstevel@tonic-gate 
7560Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
7570Sstevel@tonic-gate 
7580Sstevel@tonic-gate 	/*
7590Sstevel@tonic-gate 	 * Unfortunately we need the ppa before we call gld_initstats();
7600Sstevel@tonic-gate 	 * otherwise we would like to do this just above the mutex_enter
7610Sstevel@tonic-gate 	 * above.  In which case we could have set MAC_READY inside the
7620Sstevel@tonic-gate 	 * mutex and we wouldn't have needed to check it in open and
7630Sstevel@tonic-gate 	 * DL_ATTACH.  We wouldn't like to do the initstats/kstat_create
7640Sstevel@tonic-gate 	 * inside the mutex because it might get taken in our kstat_update
7650Sstevel@tonic-gate 	 * routine and cause a deadlock with kstat_chain_lock.
7660Sstevel@tonic-gate 	 */
7670Sstevel@tonic-gate 
7680Sstevel@tonic-gate 	/* gld_initstats() calls (*ifp->init)() */
7690Sstevel@tonic-gate 	if (gld_initstats(macinfo) != GLD_SUCCESS) {
7700Sstevel@tonic-gate 		mutex_enter(&glddev->gld_devlock);
7710Sstevel@tonic-gate 		gldremque(macinfo);
7720Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
7730Sstevel@tonic-gate 		goto late_failure;
7740Sstevel@tonic-gate 	}
7750Sstevel@tonic-gate 
7760Sstevel@tonic-gate 	/*
7770Sstevel@tonic-gate 	 * Need to indicate we are NOW ready to process interrupts;
7780Sstevel@tonic-gate 	 * any interrupt before this is set is for someone else.
7790Sstevel@tonic-gate 	 * This flag is also now used to tell open, et. al. that this
7800Sstevel@tonic-gate 	 * mac is now fully ready and available for use.
7810Sstevel@tonic-gate 	 */
7820Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
7830Sstevel@tonic-gate 	macinfo->gldm_GLD_flags |= GLD_MAC_READY;
7840Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
7850Sstevel@tonic-gate 
7860Sstevel@tonic-gate 	/* log local ethernet address -- XXX not DDI compliant */
7870Sstevel@tonic-gate 	if (macinfo->gldm_addrlen == sizeof (struct ether_addr))
7880Sstevel@tonic-gate 		(void) localetheraddr(
7890Sstevel@tonic-gate 		    (struct ether_addr *)macinfo->gldm_vendor_addr, NULL);
7900Sstevel@tonic-gate 
7910Sstevel@tonic-gate 	/* now put announcement into the message buffer */
7920Sstevel@tonic-gate 	cmn_err(CE_CONT, "!%s%d: %s: type \"%s\" mac address %s\n",
7930Sstevel@tonic-gate 	    glddev->gld_name,
7940Sstevel@tonic-gate 	    macinfo->gldm_ppa, macinfo->gldm_ident,
7950Sstevel@tonic-gate 	    mac_pvt->interfacep->mac_string,
7960Sstevel@tonic-gate 	    gld_macaddr_sprintf(pbuf, macinfo->gldm_vendor_addr,
7970Sstevel@tonic-gate 	    macinfo->gldm_addrlen));
7980Sstevel@tonic-gate 
7990Sstevel@tonic-gate 	ddi_report_dev(devinfo);
8000Sstevel@tonic-gate 	return (DDI_SUCCESS);
8010Sstevel@tonic-gate 
8020Sstevel@tonic-gate late_failure:
8030Sstevel@tonic-gate 	ddi_remove_minor_node(devinfo, NULL);
8040Sstevel@tonic-gate 	GLDM_LOCK_DESTROY(macinfo);
8050Sstevel@tonic-gate 	if (mac_pvt->curr_macaddr != NULL)
8060Sstevel@tonic-gate 	    kmem_free(mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
8070Sstevel@tonic-gate 	if (mac_pvt->statistics != NULL)
8080Sstevel@tonic-gate 	    kmem_free(mac_pvt->statistics, sizeof (struct gld_stats));
8090Sstevel@tonic-gate 	kmem_free(macinfo->gldm_mac_pvt, sizeof (gld_mac_pvt_t));
8100Sstevel@tonic-gate 	macinfo->gldm_mac_pvt = NULL;
8110Sstevel@tonic-gate 
8120Sstevel@tonic-gate failure:
8130Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
8140Sstevel@tonic-gate 	glddev->gld_ndevice--;
8150Sstevel@tonic-gate 	/*
8160Sstevel@tonic-gate 	 * Note that just because this goes to zero here does not necessarily
8170Sstevel@tonic-gate 	 * mean that we were the one who added the glddev above.  It's
8180Sstevel@tonic-gate 	 * possible that the first mac unattached while were were in here
8190Sstevel@tonic-gate 	 * failing to attach the second mac.  But we're now the last.
8200Sstevel@tonic-gate 	 */
8210Sstevel@tonic-gate 	if (glddev->gld_ndevice == 0) {
8220Sstevel@tonic-gate 		/* There should be no macinfos left */
8230Sstevel@tonic-gate 		ASSERT(glddev->gld_mac_next ==
8240Sstevel@tonic-gate 		    (gld_mac_info_t *)&glddev->gld_mac_next);
8250Sstevel@tonic-gate 		ASSERT(glddev->gld_mac_prev ==
8260Sstevel@tonic-gate 		    (gld_mac_info_t *)&glddev->gld_mac_next);
8270Sstevel@tonic-gate 
8280Sstevel@tonic-gate 		/*
8290Sstevel@tonic-gate 		 * There should be no DL_UNATTACHED streams: the system
8300Sstevel@tonic-gate 		 * should not have detached the "first" devinfo which has
8310Sstevel@tonic-gate 		 * all the open style 2 streams.
8320Sstevel@tonic-gate 		 *
8330Sstevel@tonic-gate 		 * XXX This is not clear.  See gld_getinfo and Bug 1165519
8340Sstevel@tonic-gate 		 */
8350Sstevel@tonic-gate 		ASSERT(glddev->gld_str_next == (gld_t *)&glddev->gld_str_next);
8360Sstevel@tonic-gate 		ASSERT(glddev->gld_str_prev == (gld_t *)&glddev->gld_str_next);
8370Sstevel@tonic-gate 
8380Sstevel@tonic-gate 		gldremque(glddev);
8390Sstevel@tonic-gate 		mutex_destroy(&glddev->gld_devlock);
8400Sstevel@tonic-gate 		if (glddev->gld_broadcast != NULL)
8410Sstevel@tonic-gate 			kmem_free(glddev->gld_broadcast, glddev->gld_addrlen);
8420Sstevel@tonic-gate 		kmem_free(glddev, sizeof (glddev_t));
8430Sstevel@tonic-gate 	}
8440Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
8450Sstevel@tonic-gate 
8460Sstevel@tonic-gate 	return (DDI_FAILURE);
8470Sstevel@tonic-gate }
8480Sstevel@tonic-gate 
8490Sstevel@tonic-gate /*
8500Sstevel@tonic-gate  * gld_unregister (macinfo)
8510Sstevel@tonic-gate  * remove the macinfo structure from local structures
8520Sstevel@tonic-gate  * this is cleanup for a driver to be unloaded
8530Sstevel@tonic-gate  */
8540Sstevel@tonic-gate int
8550Sstevel@tonic-gate gld_unregister(gld_mac_info_t *macinfo)
8560Sstevel@tonic-gate {
8570Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
8580Sstevel@tonic-gate 	glddev_t *glddev = mac_pvt->major_dev;
8590Sstevel@tonic-gate 	gld_interface_t *ifp;
8600Sstevel@tonic-gate 	int multisize = sizeof (gld_mcast_t) * glddev->gld_multisize;
8610Sstevel@tonic-gate 
8620Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
8630Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
8640Sstevel@tonic-gate 
8650Sstevel@tonic-gate 	if (mac_pvt->nvlan > 0) {
8660Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
8670Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
8680Sstevel@tonic-gate 		return (DDI_FAILURE);
8690Sstevel@tonic-gate 	}
8700Sstevel@tonic-gate 
8710Sstevel@tonic-gate #ifdef	GLD_DEBUG
8720Sstevel@tonic-gate 	{
8730Sstevel@tonic-gate 		int i;
8740Sstevel@tonic-gate 
8750Sstevel@tonic-gate 		for (i = 0; i < VLAN_HASHSZ; i++) {
8760Sstevel@tonic-gate 			if ((mac_pvt->vlan_hash[i] != NULL))
8770Sstevel@tonic-gate 				cmn_err(CE_PANIC,
8780Sstevel@tonic-gate 				    "%s, line %d: "
8790Sstevel@tonic-gate 				    "mac_pvt->vlan_hash[%d] != NULL",
8800Sstevel@tonic-gate 				    __FILE__, __LINE__, i);
8810Sstevel@tonic-gate 		}
8820Sstevel@tonic-gate 	}
8830Sstevel@tonic-gate #endif
8840Sstevel@tonic-gate 
8850Sstevel@tonic-gate 	/* Delete this mac */
8860Sstevel@tonic-gate 	gldremque(macinfo);
8870Sstevel@tonic-gate 
8880Sstevel@tonic-gate 	/* Disallow further entries to gld_recv() and gld_sched() */
8890Sstevel@tonic-gate 	macinfo->gldm_GLD_flags |= GLD_UNREGISTERED;
8900Sstevel@tonic-gate 
8910Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
8920Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
8930Sstevel@tonic-gate 
8940Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
8950Sstevel@tonic-gate 	(*ifp->uninit)(macinfo);
8960Sstevel@tonic-gate 
8970Sstevel@tonic-gate 	ASSERT(mac_pvt->kstatp);
8980Sstevel@tonic-gate 	kstat_delete(mac_pvt->kstatp);
8990Sstevel@tonic-gate 
9000Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_INITED(macinfo));
9010Sstevel@tonic-gate 	kmem_free(mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
9020Sstevel@tonic-gate 	kmem_free(mac_pvt->statistics, sizeof (struct gld_stats));
9030Sstevel@tonic-gate 
9040Sstevel@tonic-gate 	if (mac_pvt->mcast_table != NULL)
9050Sstevel@tonic-gate 		kmem_free(mac_pvt->mcast_table, multisize);
9060Sstevel@tonic-gate 	kmem_free(macinfo->gldm_mac_pvt, sizeof (gld_mac_pvt_t));
9070Sstevel@tonic-gate 	macinfo->gldm_mac_pvt = (caddr_t)NULL;
9080Sstevel@tonic-gate 
9090Sstevel@tonic-gate 	/* We now have one fewer instance for this major device */
9100Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
9110Sstevel@tonic-gate 	glddev->gld_ndevice--;
9120Sstevel@tonic-gate 	if (glddev->gld_ndevice == 0) {
9130Sstevel@tonic-gate 		/* There should be no macinfos left */
9140Sstevel@tonic-gate 		ASSERT(glddev->gld_mac_next ==
9150Sstevel@tonic-gate 		    (gld_mac_info_t *)&glddev->gld_mac_next);
9160Sstevel@tonic-gate 		ASSERT(glddev->gld_mac_prev ==
9170Sstevel@tonic-gate 		    (gld_mac_info_t *)&glddev->gld_mac_next);
9180Sstevel@tonic-gate 
9190Sstevel@tonic-gate 		/*
9200Sstevel@tonic-gate 		 * There should be no DL_UNATTACHED streams: the system
9210Sstevel@tonic-gate 		 * should not have detached the "first" devinfo which has
9220Sstevel@tonic-gate 		 * all the open style 2 streams.
9230Sstevel@tonic-gate 		 *
9240Sstevel@tonic-gate 		 * XXX This is not clear.  See gld_getinfo and Bug 1165519
9250Sstevel@tonic-gate 		 */
9260Sstevel@tonic-gate 		ASSERT(glddev->gld_str_next == (gld_t *)&glddev->gld_str_next);
9270Sstevel@tonic-gate 		ASSERT(glddev->gld_str_prev == (gld_t *)&glddev->gld_str_next);
9280Sstevel@tonic-gate 
9290Sstevel@tonic-gate 		ddi_remove_minor_node(macinfo->gldm_devinfo, NULL);
9300Sstevel@tonic-gate 		gldremque(glddev);
9310Sstevel@tonic-gate 		mutex_destroy(&glddev->gld_devlock);
9320Sstevel@tonic-gate 		if (glddev->gld_broadcast != NULL)
9330Sstevel@tonic-gate 			kmem_free(glddev->gld_broadcast, glddev->gld_addrlen);
9340Sstevel@tonic-gate 		kmem_free(glddev, sizeof (glddev_t));
9350Sstevel@tonic-gate 	}
9360Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
9370Sstevel@tonic-gate 
9380Sstevel@tonic-gate 	return (DDI_SUCCESS);
9390Sstevel@tonic-gate }
9400Sstevel@tonic-gate 
9410Sstevel@tonic-gate /*
9420Sstevel@tonic-gate  * gld_initstats
9430Sstevel@tonic-gate  * called from gld_register
9440Sstevel@tonic-gate  */
9450Sstevel@tonic-gate static int
9460Sstevel@tonic-gate gld_initstats(gld_mac_info_t *macinfo)
9470Sstevel@tonic-gate {
9480Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
9490Sstevel@tonic-gate 	struct gldkstats *sp;
9500Sstevel@tonic-gate 	glddev_t *glddev;
9510Sstevel@tonic-gate 	kstat_t *ksp;
9520Sstevel@tonic-gate 	gld_interface_t *ifp;
9530Sstevel@tonic-gate 
9540Sstevel@tonic-gate 	glddev = mac_pvt->major_dev;
9550Sstevel@tonic-gate 
9560Sstevel@tonic-gate 	if ((ksp = kstat_create(glddev->gld_name, macinfo->gldm_ppa,
9570Sstevel@tonic-gate 	    NULL, "net", KSTAT_TYPE_NAMED,
9580Sstevel@tonic-gate 	    sizeof (struct gldkstats) / sizeof (kstat_named_t), 0)) == NULL) {
9590Sstevel@tonic-gate 		cmn_err(CE_WARN,
9600Sstevel@tonic-gate 		    "GLD: failed to create kstat structure for %s%d",
9610Sstevel@tonic-gate 		    glddev->gld_name, macinfo->gldm_ppa);
9620Sstevel@tonic-gate 		return (GLD_FAILURE);
9630Sstevel@tonic-gate 	}
9640Sstevel@tonic-gate 	mac_pvt->kstatp = ksp;
9650Sstevel@tonic-gate 
9660Sstevel@tonic-gate 	ksp->ks_update = gld_update_kstat;
9670Sstevel@tonic-gate 	ksp->ks_private = (void *)macinfo;
9680Sstevel@tonic-gate 
9690Sstevel@tonic-gate 	sp = ksp->ks_data;
9700Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktrcv, "ipackets", KSTAT_DATA_UINT32);
9710Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktxmt, "opackets", KSTAT_DATA_UINT32);
9720Sstevel@tonic-gate 	kstat_named_init(&sp->glds_errrcv, "ierrors", KSTAT_DATA_ULONG);
9730Sstevel@tonic-gate 	kstat_named_init(&sp->glds_errxmt, "oerrors", KSTAT_DATA_ULONG);
9740Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytexmt, "obytes", KSTAT_DATA_UINT32);
9750Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytercv, "rbytes", KSTAT_DATA_UINT32);
9760Sstevel@tonic-gate 	kstat_named_init(&sp->glds_multixmt, "multixmt", KSTAT_DATA_ULONG);
9770Sstevel@tonic-gate 	kstat_named_init(&sp->glds_multircv, "multircv", KSTAT_DATA_ULONG);
9780Sstevel@tonic-gate 	kstat_named_init(&sp->glds_brdcstxmt, "brdcstxmt", KSTAT_DATA_ULONG);
9790Sstevel@tonic-gate 	kstat_named_init(&sp->glds_brdcstrcv, "brdcstrcv", KSTAT_DATA_ULONG);
9800Sstevel@tonic-gate 	kstat_named_init(&sp->glds_blocked, "blocked", KSTAT_DATA_ULONG);
9810Sstevel@tonic-gate 	kstat_named_init(&sp->glds_noxmtbuf, "noxmtbuf", KSTAT_DATA_ULONG);
9820Sstevel@tonic-gate 	kstat_named_init(&sp->glds_norcvbuf, "norcvbuf", KSTAT_DATA_ULONG);
9830Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtretry, "xmtretry", KSTAT_DATA_ULONG);
9840Sstevel@tonic-gate 	kstat_named_init(&sp->glds_intr, "intr", KSTAT_DATA_ULONG);
9850Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktrcv64, "ipackets64", KSTAT_DATA_UINT64);
9860Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktxmt64, "opackets64", KSTAT_DATA_UINT64);
9870Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytexmt64, "obytes64", KSTAT_DATA_UINT64);
9880Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytercv64, "rbytes64", KSTAT_DATA_UINT64);
9890Sstevel@tonic-gate 	kstat_named_init(&sp->glds_unknowns, "unknowns", KSTAT_DATA_ULONG);
9900Sstevel@tonic-gate 	kstat_named_init(&sp->glds_speed, "ifspeed", KSTAT_DATA_UINT64);
9910Sstevel@tonic-gate 	kstat_named_init(&sp->glds_media, "media", KSTAT_DATA_CHAR);
9920Sstevel@tonic-gate 	kstat_named_init(&sp->glds_prom, "promisc", KSTAT_DATA_CHAR);
9930Sstevel@tonic-gate 
9940Sstevel@tonic-gate 	kstat_named_init(&sp->glds_overflow, "oflo", KSTAT_DATA_ULONG);
9950Sstevel@tonic-gate 	kstat_named_init(&sp->glds_underflow, "uflo", KSTAT_DATA_ULONG);
9960Sstevel@tonic-gate 	kstat_named_init(&sp->glds_missed, "missed", KSTAT_DATA_ULONG);
9970Sstevel@tonic-gate 
9980Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtbadinterp, "xmt_badinterp",
9990Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
10000Sstevel@tonic-gate 	kstat_named_init(&sp->glds_rcvbadinterp, "rcv_badinterp",
10010Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
10020Sstevel@tonic-gate 
10030Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
10040Sstevel@tonic-gate 
10050Sstevel@tonic-gate 	(*ifp->init)(macinfo);
10060Sstevel@tonic-gate 
10070Sstevel@tonic-gate 	kstat_install(ksp);
10080Sstevel@tonic-gate 
10090Sstevel@tonic-gate 	return (GLD_SUCCESS);
10100Sstevel@tonic-gate }
10110Sstevel@tonic-gate 
10120Sstevel@tonic-gate /* called from kstat mechanism, and from wsrv's get_statistics_req */
10130Sstevel@tonic-gate static int
10140Sstevel@tonic-gate gld_update_kstat(kstat_t *ksp, int rw)
10150Sstevel@tonic-gate {
10160Sstevel@tonic-gate 	gld_mac_info_t	*macinfo;
10170Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt;
10180Sstevel@tonic-gate 	struct gldkstats *gsp;
10190Sstevel@tonic-gate 	struct gld_stats *stats;
10200Sstevel@tonic-gate 
10210Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
10220Sstevel@tonic-gate 		return (EACCES);
10230Sstevel@tonic-gate 
10240Sstevel@tonic-gate 	macinfo = (gld_mac_info_t *)ksp->ks_private;
10250Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
10260Sstevel@tonic-gate 
10270Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
10280Sstevel@tonic-gate 
10290Sstevel@tonic-gate 	if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY)) {
10300Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
10310Sstevel@tonic-gate 		return (EIO);	/* this one's not ready yet */
10320Sstevel@tonic-gate 	}
10330Sstevel@tonic-gate 
10340Sstevel@tonic-gate 	if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
10350Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
10360Sstevel@tonic-gate 		return (EIO);	/* this one's not ready any more */
10370Sstevel@tonic-gate 	}
10380Sstevel@tonic-gate 
10390Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
10400Sstevel@tonic-gate 	gsp = mac_pvt->kstatp->ks_data;
10410Sstevel@tonic-gate 	ASSERT(gsp);
10420Sstevel@tonic-gate 	stats = mac_pvt->statistics;
10430Sstevel@tonic-gate 
10440Sstevel@tonic-gate 	if (macinfo->gldm_get_stats)
10450Sstevel@tonic-gate 		(void) (*macinfo->gldm_get_stats)(macinfo, stats);
10460Sstevel@tonic-gate 
10470Sstevel@tonic-gate 	gsp->glds_pktxmt.value.ui32 = stats->glds_pktxmt64 & 0xffffffff;
10480Sstevel@tonic-gate 	gsp->glds_bytexmt.value.ui32 = stats->glds_bytexmt64 & 0xffffffff;
10490Sstevel@tonic-gate 	gsp->glds_multixmt.value.ul = stats->glds_multixmt;
10500Sstevel@tonic-gate 	gsp->glds_brdcstxmt.value.ul = stats->glds_brdcstxmt;
10510Sstevel@tonic-gate 	gsp->glds_noxmtbuf.value.ul = stats->glds_noxmtbuf;	/* 0 for now */
10520Sstevel@tonic-gate 	gsp->glds_xmtretry.value.ul = stats->glds_xmtretry;
10530Sstevel@tonic-gate 
10540Sstevel@tonic-gate 	gsp->glds_pktxmt64.value.ui64 = stats->glds_pktxmt64;
10550Sstevel@tonic-gate 	gsp->glds_bytexmt64.value.ui64 = stats->glds_bytexmt64;
10560Sstevel@tonic-gate 	gsp->glds_xmtbadinterp.value.ui32 = stats->glds_xmtbadinterp;
10570Sstevel@tonic-gate 
10580Sstevel@tonic-gate 	gsp->glds_pktrcv.value.ui32 = stats->glds_pktrcv64 & 0xffffffff;
10590Sstevel@tonic-gate 	gsp->glds_errxmt.value.ul = stats->glds_errxmt;
10600Sstevel@tonic-gate 	gsp->glds_errrcv.value.ul = stats->glds_errrcv;
10610Sstevel@tonic-gate 	gsp->glds_bytercv.value.ui32 = stats->glds_bytercv64 & 0xffffffff;
10620Sstevel@tonic-gate 	gsp->glds_multircv.value.ul = stats->glds_multircv;
10630Sstevel@tonic-gate 	gsp->glds_brdcstrcv.value.ul = stats->glds_brdcstrcv;
10640Sstevel@tonic-gate 	gsp->glds_blocked.value.ul = stats->glds_blocked;
10650Sstevel@tonic-gate 	gsp->glds_overflow.value.ul = stats->glds_overflow;
10660Sstevel@tonic-gate 	gsp->glds_underflow.value.ul = stats->glds_underflow;
10670Sstevel@tonic-gate 	gsp->glds_missed.value.ul = stats->glds_missed;
10680Sstevel@tonic-gate 	gsp->glds_norcvbuf.value.ul = stats->glds_norcvbuf +
10690Sstevel@tonic-gate 	    stats->glds_gldnorcvbuf;
10700Sstevel@tonic-gate 	gsp->glds_intr.value.ul = stats->glds_intr;
10710Sstevel@tonic-gate 
10720Sstevel@tonic-gate 	gsp->glds_speed.value.ui64 = stats->glds_speed;
10730Sstevel@tonic-gate 	gsp->glds_unknowns.value.ul = stats->glds_unknowns;
10740Sstevel@tonic-gate 	gsp->glds_pktrcv64.value.ui64 = stats->glds_pktrcv64;
10750Sstevel@tonic-gate 	gsp->glds_bytercv64.value.ui64 = stats->glds_bytercv64;
10760Sstevel@tonic-gate 	gsp->glds_rcvbadinterp.value.ui32 = stats->glds_rcvbadinterp;
10770Sstevel@tonic-gate 
10780Sstevel@tonic-gate 	if (mac_pvt->nprom)
10790Sstevel@tonic-gate 		(void) strcpy(gsp->glds_prom.value.c, "phys");
10800Sstevel@tonic-gate 	else if (mac_pvt->nprom_multi)
10810Sstevel@tonic-gate 		(void) strcpy(gsp->glds_prom.value.c, "multi");
10820Sstevel@tonic-gate 	else
10830Sstevel@tonic-gate 		(void) strcpy(gsp->glds_prom.value.c, "off");
10840Sstevel@tonic-gate 
10850Sstevel@tonic-gate 	(void) strcpy(gsp->glds_media.value.c, gld_media[
10860Sstevel@tonic-gate 	    stats->glds_media < sizeof (gld_media) / sizeof (gld_media[0])
10870Sstevel@tonic-gate 	    ? stats->glds_media : 0]);
10880Sstevel@tonic-gate 
10890Sstevel@tonic-gate 	switch (macinfo->gldm_type) {
10900Sstevel@tonic-gate 	case DL_ETHER:
10910Sstevel@tonic-gate 		gsp->glds_frame.value.ul = stats->glds_frame;
10920Sstevel@tonic-gate 		gsp->glds_crc.value.ul = stats->glds_crc;
10930Sstevel@tonic-gate 		gsp->glds_collisions.value.ul = stats->glds_collisions;
10940Sstevel@tonic-gate 		gsp->glds_excoll.value.ul = stats->glds_excoll;
10950Sstevel@tonic-gate 		gsp->glds_defer.value.ul = stats->glds_defer;
10960Sstevel@tonic-gate 		gsp->glds_short.value.ul = stats->glds_short;
10970Sstevel@tonic-gate 		gsp->glds_xmtlatecoll.value.ul = stats->glds_xmtlatecoll;
10980Sstevel@tonic-gate 		gsp->glds_nocarrier.value.ul = stats->glds_nocarrier;
10990Sstevel@tonic-gate 		gsp->glds_dot3_first_coll.value.ui32 =
11000Sstevel@tonic-gate 		    stats->glds_dot3_first_coll;
11010Sstevel@tonic-gate 		gsp->glds_dot3_multi_coll.value.ui32 =
11020Sstevel@tonic-gate 		    stats->glds_dot3_multi_coll;
11030Sstevel@tonic-gate 		gsp->glds_dot3_sqe_error.value.ui32 =
11040Sstevel@tonic-gate 		    stats->glds_dot3_sqe_error;
11050Sstevel@tonic-gate 		gsp->glds_dot3_mac_xmt_error.value.ui32 =
11060Sstevel@tonic-gate 		    stats->glds_dot3_mac_xmt_error;
11070Sstevel@tonic-gate 		gsp->glds_dot3_mac_rcv_error.value.ui32 =
11080Sstevel@tonic-gate 		    stats->glds_dot3_mac_rcv_error;
11090Sstevel@tonic-gate 		gsp->glds_dot3_frame_too_long.value.ui32 =
11100Sstevel@tonic-gate 		    stats->glds_dot3_frame_too_long;
11110Sstevel@tonic-gate 		(void) strcpy(gsp->glds_duplex.value.c, gld_duplex[
11120Sstevel@tonic-gate 		    stats->glds_duplex <
11130Sstevel@tonic-gate 		    sizeof (gld_duplex) / sizeof (gld_duplex[0]) ?
11140Sstevel@tonic-gate 		    stats->glds_duplex : 0]);
11150Sstevel@tonic-gate 		break;
11160Sstevel@tonic-gate 	case DL_TPR:
11170Sstevel@tonic-gate 		gsp->glds_dot5_line_error.value.ui32 =
11180Sstevel@tonic-gate 		    stats->glds_dot5_line_error;
11190Sstevel@tonic-gate 		gsp->glds_dot5_burst_error.value.ui32 =
11200Sstevel@tonic-gate 		    stats->glds_dot5_burst_error;
11210Sstevel@tonic-gate 		gsp->glds_dot5_signal_loss.value.ui32 =
11220Sstevel@tonic-gate 		    stats->glds_dot5_signal_loss;
11230Sstevel@tonic-gate 		gsp->glds_dot5_ace_error.value.ui32 =
11240Sstevel@tonic-gate 		    stats->glds_dot5_ace_error;
11250Sstevel@tonic-gate 		gsp->glds_dot5_internal_error.value.ui32 =
11260Sstevel@tonic-gate 		    stats->glds_dot5_internal_error;
11270Sstevel@tonic-gate 		gsp->glds_dot5_lost_frame_error.value.ui32 =
11280Sstevel@tonic-gate 		    stats->glds_dot5_lost_frame_error;
11290Sstevel@tonic-gate 		gsp->glds_dot5_frame_copied_error.value.ui32 =
11300Sstevel@tonic-gate 		    stats->glds_dot5_frame_copied_error;
11310Sstevel@tonic-gate 		gsp->glds_dot5_token_error.value.ui32 =
11320Sstevel@tonic-gate 		    stats->glds_dot5_token_error;
11330Sstevel@tonic-gate 		gsp->glds_dot5_freq_error.value.ui32 =
11340Sstevel@tonic-gate 		    stats->glds_dot5_freq_error;
11350Sstevel@tonic-gate 		break;
11360Sstevel@tonic-gate 	case DL_FDDI:
11370Sstevel@tonic-gate 		gsp->glds_fddi_mac_error.value.ui32 =
11380Sstevel@tonic-gate 		    stats->glds_fddi_mac_error;
11390Sstevel@tonic-gate 		gsp->glds_fddi_mac_lost.value.ui32 =
11400Sstevel@tonic-gate 		    stats->glds_fddi_mac_lost;
11410Sstevel@tonic-gate 		gsp->glds_fddi_mac_token.value.ui32 =
11420Sstevel@tonic-gate 		    stats->glds_fddi_mac_token;
11430Sstevel@tonic-gate 		gsp->glds_fddi_mac_tvx_expired.value.ui32 =
11440Sstevel@tonic-gate 		    stats->glds_fddi_mac_tvx_expired;
11450Sstevel@tonic-gate 		gsp->glds_fddi_mac_late.value.ui32 =
11460Sstevel@tonic-gate 		    stats->glds_fddi_mac_late;
11470Sstevel@tonic-gate 		gsp->glds_fddi_mac_ring_op.value.ui32 =
11480Sstevel@tonic-gate 		    stats->glds_fddi_mac_ring_op;
11490Sstevel@tonic-gate 		break;
11500Sstevel@tonic-gate 	case DL_IB:
11510Sstevel@tonic-gate 		break;
11520Sstevel@tonic-gate 	default:
11530Sstevel@tonic-gate 		break;
11540Sstevel@tonic-gate 	}
11550Sstevel@tonic-gate 
11560Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
11570Sstevel@tonic-gate 
11580Sstevel@tonic-gate #ifdef GLD_DEBUG
11590Sstevel@tonic-gate 	gld_check_assertions();
11600Sstevel@tonic-gate 	if (gld_debug & GLDRDE)
11610Sstevel@tonic-gate 		gld_sr_dump(macinfo);
11620Sstevel@tonic-gate #endif
11630Sstevel@tonic-gate 
11640Sstevel@tonic-gate 	return (0);
11650Sstevel@tonic-gate }
11660Sstevel@tonic-gate 
11670Sstevel@tonic-gate static int
11680Sstevel@tonic-gate gld_init_vlan_stats(gld_vlan_t *vlan)
11690Sstevel@tonic-gate {
11700Sstevel@tonic-gate 	gld_mac_info_t *mac = vlan->gldv_mac;
11710Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)mac->gldm_mac_pvt;
11720Sstevel@tonic-gate 	struct gldkstats *sp;
11730Sstevel@tonic-gate 	glddev_t *glddev;
11740Sstevel@tonic-gate 	kstat_t *ksp;
11750Sstevel@tonic-gate 	char *name;
11760Sstevel@tonic-gate 	int instance;
11770Sstevel@tonic-gate 
11780Sstevel@tonic-gate 	glddev = mac_pvt->major_dev;
11790Sstevel@tonic-gate 	name = glddev->gld_name;
11800Sstevel@tonic-gate 	instance = (vlan->gldv_id * GLD_VLAN_SCALE) + mac->gldm_ppa;
11810Sstevel@tonic-gate 
11820Sstevel@tonic-gate 	if ((ksp = kstat_create(name, instance,
11830Sstevel@tonic-gate 	    NULL, "net", KSTAT_TYPE_NAMED,
11840Sstevel@tonic-gate 	    sizeof (struct gldkstats) / sizeof (kstat_named_t), 0)) == NULL) {
11850Sstevel@tonic-gate 		cmn_err(CE_WARN,
11860Sstevel@tonic-gate 		    "GLD: failed to create kstat structure for %s%d",
11870Sstevel@tonic-gate 		    name, instance);
11880Sstevel@tonic-gate 		return (GLD_FAILURE);
11890Sstevel@tonic-gate 	}
11900Sstevel@tonic-gate 
11910Sstevel@tonic-gate 	vlan->gldv_kstatp = ksp;
11920Sstevel@tonic-gate 
11930Sstevel@tonic-gate 	ksp->ks_update = gld_update_vlan_kstat;
11940Sstevel@tonic-gate 	ksp->ks_private = (void *)vlan;
11950Sstevel@tonic-gate 
11960Sstevel@tonic-gate 	sp = ksp->ks_data;
11970Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktrcv, "ipackets", KSTAT_DATA_UINT32);
11980Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktxmt, "opackets", KSTAT_DATA_UINT32);
11990Sstevel@tonic-gate 	kstat_named_init(&sp->glds_errrcv, "ierrors", KSTAT_DATA_ULONG);
12000Sstevel@tonic-gate 	kstat_named_init(&sp->glds_errxmt, "oerrors", KSTAT_DATA_ULONG);
12010Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytexmt, "obytes", KSTAT_DATA_UINT32);
12020Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytercv, "rbytes", KSTAT_DATA_UINT32);
12030Sstevel@tonic-gate 	kstat_named_init(&sp->glds_multixmt, "multixmt", KSTAT_DATA_ULONG);
12040Sstevel@tonic-gate 	kstat_named_init(&sp->glds_multircv, "multircv", KSTAT_DATA_ULONG);
12050Sstevel@tonic-gate 	kstat_named_init(&sp->glds_brdcstxmt, "brdcstxmt", KSTAT_DATA_ULONG);
12060Sstevel@tonic-gate 	kstat_named_init(&sp->glds_brdcstrcv, "brdcstrcv", KSTAT_DATA_ULONG);
12070Sstevel@tonic-gate 	kstat_named_init(&sp->glds_blocked, "blocked", KSTAT_DATA_ULONG);
12080Sstevel@tonic-gate 	kstat_named_init(&sp->glds_noxmtbuf, "noxmtbuf", KSTAT_DATA_ULONG);
12090Sstevel@tonic-gate 	kstat_named_init(&sp->glds_norcvbuf, "norcvbuf", KSTAT_DATA_ULONG);
12100Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtretry, "xmtretry", KSTAT_DATA_ULONG);
12110Sstevel@tonic-gate 	kstat_named_init(&sp->glds_intr, "intr", KSTAT_DATA_ULONG);
12120Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktrcv64, "ipackets64", KSTAT_DATA_UINT64);
12130Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktxmt64, "opackets64", KSTAT_DATA_UINT64);
12140Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytexmt64, "obytes64", KSTAT_DATA_UINT64);
12150Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytercv64, "rbytes64", KSTAT_DATA_UINT64);
12160Sstevel@tonic-gate 	kstat_named_init(&sp->glds_unknowns, "unknowns", KSTAT_DATA_ULONG);
12170Sstevel@tonic-gate 	kstat_named_init(&sp->glds_speed, "ifspeed", KSTAT_DATA_UINT64);
12180Sstevel@tonic-gate 	kstat_named_init(&sp->glds_media, "media", KSTAT_DATA_CHAR);
12190Sstevel@tonic-gate 	kstat_named_init(&sp->glds_prom, "promisc", KSTAT_DATA_CHAR);
12200Sstevel@tonic-gate 
12210Sstevel@tonic-gate 	kstat_named_init(&sp->glds_overflow, "oflo", KSTAT_DATA_ULONG);
12220Sstevel@tonic-gate 	kstat_named_init(&sp->glds_underflow, "uflo", KSTAT_DATA_ULONG);
12230Sstevel@tonic-gate 	kstat_named_init(&sp->glds_missed, "missed", KSTAT_DATA_ULONG);
12240Sstevel@tonic-gate 
12250Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtbadinterp, "xmt_badinterp",
12260Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
12270Sstevel@tonic-gate 	kstat_named_init(&sp->glds_rcvbadinterp, "rcv_badinterp",
12280Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
12290Sstevel@tonic-gate 
12300Sstevel@tonic-gate 	kstat_install(ksp);
12310Sstevel@tonic-gate 	return (GLD_SUCCESS);
12320Sstevel@tonic-gate }
12330Sstevel@tonic-gate 
12340Sstevel@tonic-gate static int
12350Sstevel@tonic-gate gld_update_vlan_kstat(kstat_t *ksp, int rw)
12360Sstevel@tonic-gate {
12370Sstevel@tonic-gate 	gld_vlan_t	*vlan;
12380Sstevel@tonic-gate 	gld_mac_info_t	*macinfo;
12390Sstevel@tonic-gate 	struct gldkstats *gsp;
12400Sstevel@tonic-gate 	struct gld_stats *stats;
1241*2163Syz147064 	gld_mac_pvt_t *mac_pvt;
1242*2163Syz147064 	uint32_t media;
12430Sstevel@tonic-gate 
12440Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
12450Sstevel@tonic-gate 		return (EACCES);
12460Sstevel@tonic-gate 
12470Sstevel@tonic-gate 	vlan = (gld_vlan_t *)ksp->ks_private;
12480Sstevel@tonic-gate 	ASSERT(vlan != NULL);
12490Sstevel@tonic-gate 
12500Sstevel@tonic-gate 	macinfo = vlan->gldv_mac;
12510Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
12520Sstevel@tonic-gate 
1253*2163Syz147064 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
1254*2163Syz147064 
12550Sstevel@tonic-gate 	gsp = vlan->gldv_kstatp->ks_data;
12560Sstevel@tonic-gate 	ASSERT(gsp);
12570Sstevel@tonic-gate 	stats = vlan->gldv_stats;
12580Sstevel@tonic-gate 
12590Sstevel@tonic-gate 	gsp->glds_pktxmt.value.ui32 = stats->glds_pktxmt64 & 0xffffffff;
12600Sstevel@tonic-gate 	gsp->glds_bytexmt.value.ui32 = stats->glds_bytexmt64 & 0xffffffff;
12610Sstevel@tonic-gate 	gsp->glds_errxmt.value.ul = stats->glds_errxmt;
12620Sstevel@tonic-gate 	gsp->glds_multixmt.value.ul = stats->glds_multixmt;
12630Sstevel@tonic-gate 	gsp->glds_brdcstxmt.value.ul = stats->glds_brdcstxmt;
12640Sstevel@tonic-gate 	gsp->glds_noxmtbuf.value.ul = stats->glds_noxmtbuf;
12650Sstevel@tonic-gate 	gsp->glds_xmtretry.value.ul = stats->glds_xmtretry;
12660Sstevel@tonic-gate 	gsp->glds_pktxmt64.value.ui64 = stats->glds_pktxmt64;
12670Sstevel@tonic-gate 	gsp->glds_bytexmt64.value.ui64 = stats->glds_bytexmt64;
12680Sstevel@tonic-gate 
12690Sstevel@tonic-gate 	gsp->glds_pktrcv.value.ui32 = stats->glds_pktrcv64 & 0xffffffff;
12700Sstevel@tonic-gate 	gsp->glds_bytercv.value.ui32 = stats->glds_bytercv64 & 0xffffffff;
12710Sstevel@tonic-gate 	gsp->glds_errrcv.value.ul = stats->glds_errrcv;
12720Sstevel@tonic-gate 	gsp->glds_multircv.value.ul = stats->glds_multircv;
12730Sstevel@tonic-gate 	gsp->glds_brdcstrcv.value.ul = stats->glds_brdcstrcv;
12740Sstevel@tonic-gate 	gsp->glds_blocked.value.ul = stats->glds_blocked;
12750Sstevel@tonic-gate 	gsp->glds_pktrcv64.value.ui64 = stats->glds_pktrcv64;
12760Sstevel@tonic-gate 	gsp->glds_bytercv64.value.ui64 = stats->glds_bytercv64;
1277*2163Syz147064 	gsp->glds_unknowns.value.ul = stats->glds_unknowns;
1278*2163Syz147064 	gsp->glds_xmtbadinterp.value.ui32 = stats->glds_xmtbadinterp;
1279*2163Syz147064 	gsp->glds_rcvbadinterp.value.ui32 = stats->glds_rcvbadinterp;
1280*2163Syz147064 
1281*2163Syz147064 	gsp->glds_speed.value.ui64 = mac_pvt->statistics->glds_speed;
1282*2163Syz147064 	media = mac_pvt->statistics->glds_media;
1283*2163Syz147064 	(void) strcpy(gsp->glds_media.value.c,
1284*2163Syz147064 	    gld_media[media < sizeof (gld_media) / sizeof (gld_media[0]) ?
1285*2163Syz147064 	    media : 0]);
12860Sstevel@tonic-gate 
12870Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
12880Sstevel@tonic-gate 	return (0);
12890Sstevel@tonic-gate }
12900Sstevel@tonic-gate 
12910Sstevel@tonic-gate /*
12920Sstevel@tonic-gate  * The device dependent driver specifies gld_getinfo as its getinfo routine.
12930Sstevel@tonic-gate  */
12940Sstevel@tonic-gate /*ARGSUSED*/
12950Sstevel@tonic-gate int
12960Sstevel@tonic-gate gld_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
12970Sstevel@tonic-gate {
12980Sstevel@tonic-gate 	dev_info_t	*devinfo;
12990Sstevel@tonic-gate 	minor_t		minor = getminor((dev_t)arg);
13000Sstevel@tonic-gate 	int		rc = DDI_FAILURE;
13010Sstevel@tonic-gate 
13020Sstevel@tonic-gate 	switch (cmd) {
13030Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
13040Sstevel@tonic-gate 		if ((devinfo = gld_finddevinfo((dev_t)arg)) != NULL) {
13050Sstevel@tonic-gate 			*(dev_info_t **)resultp = devinfo;
13060Sstevel@tonic-gate 			rc = DDI_SUCCESS;
13070Sstevel@tonic-gate 		}
13080Sstevel@tonic-gate 		break;
13090Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
13100Sstevel@tonic-gate 		/* Need static mapping for deferred attach */
13110Sstevel@tonic-gate 		if (minor == GLD_USE_STYLE2) {
13120Sstevel@tonic-gate 			/*
13130Sstevel@tonic-gate 			 * Style 2:  this minor number does not correspond to
13140Sstevel@tonic-gate 			 * any particular instance number.
13150Sstevel@tonic-gate 			 */
13160Sstevel@tonic-gate 			rc = DDI_FAILURE;
13170Sstevel@tonic-gate 		} else if (minor <= GLD_MAX_STYLE1_MINOR) {
13180Sstevel@tonic-gate 			/* Style 1:  calculate the PPA from the minor */
13191717Swesolows 			*resultp = (void *)(uintptr_t)
13201717Swesolows 			    GLD_STYLE1_MINOR_TO_PPA(minor);
13210Sstevel@tonic-gate 			rc = DDI_SUCCESS;
13220Sstevel@tonic-gate 		} else {
13230Sstevel@tonic-gate 			/* Clone:  look for it.  Not a static mapping */
13240Sstevel@tonic-gate 			if ((devinfo = gld_finddevinfo((dev_t)arg)) != NULL) {
13251717Swesolows 				*resultp = (void *)(uintptr_t)
13261717Swesolows 				    ddi_get_instance(devinfo);
13270Sstevel@tonic-gate 				rc = DDI_SUCCESS;
13280Sstevel@tonic-gate 			}
13290Sstevel@tonic-gate 		}
13300Sstevel@tonic-gate 		break;
13310Sstevel@tonic-gate 	}
13320Sstevel@tonic-gate 
13330Sstevel@tonic-gate 	return (rc);
13340Sstevel@tonic-gate }
13350Sstevel@tonic-gate 
13360Sstevel@tonic-gate /* called from gld_getinfo */
13370Sstevel@tonic-gate dev_info_t *
13380Sstevel@tonic-gate gld_finddevinfo(dev_t dev)
13390Sstevel@tonic-gate {
13400Sstevel@tonic-gate 	minor_t		minor = getminor(dev);
13410Sstevel@tonic-gate 	glddev_t	*device;
13420Sstevel@tonic-gate 	gld_mac_info_t	*mac;
13430Sstevel@tonic-gate 	gld_vlan_t	*vlan;
13440Sstevel@tonic-gate 	gld_t		*str;
13450Sstevel@tonic-gate 	dev_info_t	*devinfo = NULL;
13460Sstevel@tonic-gate 	int		i;
13470Sstevel@tonic-gate 
13480Sstevel@tonic-gate 	if (minor == GLD_USE_STYLE2) {
13490Sstevel@tonic-gate 		/*
13500Sstevel@tonic-gate 		 * Style 2:  this minor number does not correspond to
13510Sstevel@tonic-gate 		 * any particular instance number.
13520Sstevel@tonic-gate 		 *
13530Sstevel@tonic-gate 		 * XXX We don't know what to say.  See Bug 1165519.
13540Sstevel@tonic-gate 		 */
13550Sstevel@tonic-gate 		return (NULL);
13560Sstevel@tonic-gate 	}
13570Sstevel@tonic-gate 
13580Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);	/* hold the device */
13590Sstevel@tonic-gate 
13600Sstevel@tonic-gate 	device = gld_devlookup(getmajor(dev));
13610Sstevel@tonic-gate 	if (device == NULL) {
13620Sstevel@tonic-gate 		/* There are no attached instances of this device */
13630Sstevel@tonic-gate 		mutex_exit(&gld_device_list.gld_devlock);
13640Sstevel@tonic-gate 		return (NULL);
13650Sstevel@tonic-gate 	}
13660Sstevel@tonic-gate 
13670Sstevel@tonic-gate 	/*
13680Sstevel@tonic-gate 	 * Search all attached macs and streams.
13690Sstevel@tonic-gate 	 *
13700Sstevel@tonic-gate 	 * XXX We don't bother checking the DL_UNATTACHED streams since
13710Sstevel@tonic-gate 	 * we don't know what devinfo we should report back even if we
13720Sstevel@tonic-gate 	 * found the minor.  Maybe we should associate streams that are
13730Sstevel@tonic-gate 	 * not currently attached to a PPA with the "first" devinfo node
13740Sstevel@tonic-gate 	 * of the major device to attach -- the one that created the
13750Sstevel@tonic-gate 	 * minor node for the generic device.
13760Sstevel@tonic-gate 	 */
13770Sstevel@tonic-gate 	mutex_enter(&device->gld_devlock);
13780Sstevel@tonic-gate 
13790Sstevel@tonic-gate 	for (mac = device->gld_mac_next;
13800Sstevel@tonic-gate 	    mac != (gld_mac_info_t *)&device->gld_mac_next;
13810Sstevel@tonic-gate 	    mac = mac->gldm_next) {
13820Sstevel@tonic-gate 		gld_mac_pvt_t *pvt = (gld_mac_pvt_t *)mac->gldm_mac_pvt;
13830Sstevel@tonic-gate 
13840Sstevel@tonic-gate 		if (!(mac->gldm_GLD_flags & GLD_MAC_READY))
13850Sstevel@tonic-gate 			continue;	/* this one's not ready yet */
13860Sstevel@tonic-gate 		if (minor <= GLD_MAX_STYLE1_MINOR) {
13870Sstevel@tonic-gate 			/* Style 1 -- look for the corresponding PPA */
13880Sstevel@tonic-gate 			if (minor == GLD_STYLE1_PPA_TO_MINOR(mac->gldm_ppa)) {
13890Sstevel@tonic-gate 				devinfo = mac->gldm_devinfo;
13900Sstevel@tonic-gate 				goto out;	/* found it! */
13910Sstevel@tonic-gate 			} else
13920Sstevel@tonic-gate 				continue;	/* not this PPA */
13930Sstevel@tonic-gate 		}
13940Sstevel@tonic-gate 
13950Sstevel@tonic-gate 		/* We are looking for a clone */
13960Sstevel@tonic-gate 		for (i = 0; i < VLAN_HASHSZ; i++) {
13970Sstevel@tonic-gate 			for (vlan = pvt->vlan_hash[i];
13980Sstevel@tonic-gate 			    vlan != NULL; vlan = vlan->gldv_next) {
13990Sstevel@tonic-gate 				for (str = vlan->gldv_str_next;
14000Sstevel@tonic-gate 				    str != (gld_t *)&vlan->gldv_str_next;
14010Sstevel@tonic-gate 				    str = str->gld_next) {
14020Sstevel@tonic-gate 					ASSERT(str->gld_mac_info == mac);
14030Sstevel@tonic-gate 					if (minor == str->gld_minor) {
14040Sstevel@tonic-gate 						devinfo = mac->gldm_devinfo;
14050Sstevel@tonic-gate 						goto out;
14060Sstevel@tonic-gate 					}
14070Sstevel@tonic-gate 				}
14080Sstevel@tonic-gate 			}
14090Sstevel@tonic-gate 		}
14100Sstevel@tonic-gate 	}
14110Sstevel@tonic-gate out:
14120Sstevel@tonic-gate 	mutex_exit(&device->gld_devlock);
14130Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
14140Sstevel@tonic-gate 	return (devinfo);
14150Sstevel@tonic-gate }
14160Sstevel@tonic-gate 
14170Sstevel@tonic-gate /*
14180Sstevel@tonic-gate  * STREAMS open routine.  The device dependent driver specifies this as its
14190Sstevel@tonic-gate  * open entry point.
14200Sstevel@tonic-gate  */
14210Sstevel@tonic-gate /*ARGSUSED2*/
14220Sstevel@tonic-gate int
14230Sstevel@tonic-gate gld_open(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *cred)
14240Sstevel@tonic-gate {
14250Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
14260Sstevel@tonic-gate 	gld_t *gld;
14270Sstevel@tonic-gate 	glddev_t *glddev;
14280Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
14290Sstevel@tonic-gate 	minor_t minor = getminor(*dev);
14300Sstevel@tonic-gate 	gld_vlan_t *vlan;
14310Sstevel@tonic-gate 	t_uscalar_t ppa;
14320Sstevel@tonic-gate 
14330Sstevel@tonic-gate 	ASSERT(q != NULL);
14340Sstevel@tonic-gate 
14350Sstevel@tonic-gate 	if (minor > GLD_MAX_STYLE1_MINOR)
14360Sstevel@tonic-gate 		return (ENXIO);
14370Sstevel@tonic-gate 
14380Sstevel@tonic-gate 	ASSERT(q->q_ptr == NULL);	/* Clone device gives us a fresh Q */
14390Sstevel@tonic-gate 
14400Sstevel@tonic-gate 	/* Find our per-major glddev_t structure */
14410Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
14420Sstevel@tonic-gate 	glddev = gld_devlookup(getmajor(*dev));
14430Sstevel@tonic-gate 
14440Sstevel@tonic-gate 	/*
14450Sstevel@tonic-gate 	 * This glddev will hang around since detach (and therefore
14460Sstevel@tonic-gate 	 * gld_unregister) can't run while we're here in the open routine.
14470Sstevel@tonic-gate 	 */
14480Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
14490Sstevel@tonic-gate 
14500Sstevel@tonic-gate 	if (glddev == NULL)
14510Sstevel@tonic-gate 		return (ENXIO);
14520Sstevel@tonic-gate 
14530Sstevel@tonic-gate #ifdef GLD_DEBUG
14540Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
14550Sstevel@tonic-gate 		if (minor == GLD_USE_STYLE2)
14560Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_open(%p, Style 2)", (void *)q);
14570Sstevel@tonic-gate 		else
14580Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_open(%p, Style 1, minor = %d)",
14590Sstevel@tonic-gate 			    (void *)q, minor);
14600Sstevel@tonic-gate 	}
14610Sstevel@tonic-gate #endif
14620Sstevel@tonic-gate 
14630Sstevel@tonic-gate 	/*
14640Sstevel@tonic-gate 	 * get a per-stream structure and link things together so we
14650Sstevel@tonic-gate 	 * can easily find them later.
14660Sstevel@tonic-gate 	 */
14670Sstevel@tonic-gate 	gld = kmem_zalloc(sizeof (gld_t), KM_SLEEP);
14680Sstevel@tonic-gate 
14690Sstevel@tonic-gate 	/*
14700Sstevel@tonic-gate 	 * fill in the structure and state info
14710Sstevel@tonic-gate 	 */
14720Sstevel@tonic-gate 	gld->gld_qptr = q;
14730Sstevel@tonic-gate 	gld->gld_device = glddev;
14740Sstevel@tonic-gate 	gld->gld_state = DL_UNATTACHED;
14750Sstevel@tonic-gate 
14760Sstevel@tonic-gate 	/*
14770Sstevel@tonic-gate 	 * we must atomically find a free minor number and add the stream
14780Sstevel@tonic-gate 	 * to a list, because gld_findminor has to traverse the lists to
14790Sstevel@tonic-gate 	 * determine which minor numbers are free.
14800Sstevel@tonic-gate 	 */
14810Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
14820Sstevel@tonic-gate 
14830Sstevel@tonic-gate 	/* find a free minor device number for the clone */
14840Sstevel@tonic-gate 	gld->gld_minor = gld_findminor(glddev);
14850Sstevel@tonic-gate 	if (gld->gld_minor == 0) {
14860Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
14870Sstevel@tonic-gate 		kmem_free(gld, sizeof (gld_t));
14880Sstevel@tonic-gate 		return (ENOSR);
14890Sstevel@tonic-gate 	}
14900Sstevel@tonic-gate 
14910Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
14920Sstevel@tonic-gate 	if (gld_debug & GLDPROT)
14930Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_open() gld ptr: %p minor: %d",
14940Sstevel@tonic-gate 		    (void *)gld, gld->gld_minor);
14950Sstevel@tonic-gate #endif
14960Sstevel@tonic-gate 
14970Sstevel@tonic-gate 	if (minor == GLD_USE_STYLE2) {
14980Sstevel@tonic-gate 		gld->gld_style = DL_STYLE2;
14990Sstevel@tonic-gate 		*dev = makedevice(getmajor(*dev), gld->gld_minor);
15000Sstevel@tonic-gate 		WR(q)->q_ptr = q->q_ptr = (caddr_t)gld;
15010Sstevel@tonic-gate 		gldinsque(gld, glddev->gld_str_prev);
15020Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
15030Sstevel@tonic-gate 		if (gld_debug & GLDPROT)
15040Sstevel@tonic-gate 			cmn_err(CE_NOTE, "GLDstruct added to device list");
15050Sstevel@tonic-gate #endif
15060Sstevel@tonic-gate 		(void) qassociate(q, -1);
15070Sstevel@tonic-gate 		goto done;
15080Sstevel@tonic-gate 	}
15090Sstevel@tonic-gate 
15100Sstevel@tonic-gate 	gld->gld_style = DL_STYLE1;
15110Sstevel@tonic-gate 
15120Sstevel@tonic-gate 	/* the PPA is actually 1 less than the minordev */
15130Sstevel@tonic-gate 	ppa = GLD_STYLE1_MINOR_TO_PPA(minor);
15140Sstevel@tonic-gate 
15150Sstevel@tonic-gate 	for (macinfo = glddev->gld_mac_next;
15160Sstevel@tonic-gate 	    macinfo != (gld_mac_info_t *)(&glddev->gld_mac_next);
15170Sstevel@tonic-gate 	    macinfo = macinfo->gldm_next) {
15180Sstevel@tonic-gate 		ASSERT(macinfo != NULL);
15190Sstevel@tonic-gate 		if (macinfo->gldm_ppa != ppa)
15200Sstevel@tonic-gate 			continue;
15210Sstevel@tonic-gate 
15220Sstevel@tonic-gate 		if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY))
15230Sstevel@tonic-gate 			continue;	/* this one's not ready yet */
15240Sstevel@tonic-gate 
15250Sstevel@tonic-gate 		/*
15260Sstevel@tonic-gate 		 * we found the correct PPA
15270Sstevel@tonic-gate 		 */
15280Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
15290Sstevel@tonic-gate 
15300Sstevel@tonic-gate 		gld->gld_mac_info = macinfo;
15310Sstevel@tonic-gate 
15320Sstevel@tonic-gate 		if (macinfo->gldm_send_tagged != NULL)
15330Sstevel@tonic-gate 			gld->gld_send = macinfo->gldm_send_tagged;
15340Sstevel@tonic-gate 		else
15350Sstevel@tonic-gate 			gld->gld_send = macinfo->gldm_send;
15360Sstevel@tonic-gate 
15370Sstevel@tonic-gate 		/* now ready for action */
15380Sstevel@tonic-gate 		gld->gld_state = DL_UNBOUND;
15390Sstevel@tonic-gate 
15400Sstevel@tonic-gate 		if ((vlan = gld_get_vlan(macinfo, VLAN_VID_NONE)) == NULL) {
15410Sstevel@tonic-gate 			GLDM_UNLOCK(macinfo);
15420Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
15430Sstevel@tonic-gate 			kmem_free(gld, sizeof (gld_t));
15440Sstevel@tonic-gate 			return (EIO);
15450Sstevel@tonic-gate 		}
15460Sstevel@tonic-gate 
15470Sstevel@tonic-gate 		mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
15480Sstevel@tonic-gate 		if (!mac_pvt->started) {
15490Sstevel@tonic-gate 			if (gld_start_mac(macinfo) != GLD_SUCCESS) {
15501521Syz147064 				gld_rem_vlan(vlan);
15510Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
15520Sstevel@tonic-gate 				mutex_exit(&glddev->gld_devlock);
15530Sstevel@tonic-gate 				kmem_free(gld, sizeof (gld_t));
15540Sstevel@tonic-gate 				return (EIO);
15550Sstevel@tonic-gate 			}
15560Sstevel@tonic-gate 		}
15570Sstevel@tonic-gate 
15580Sstevel@tonic-gate 		gld->gld_vlan = vlan;
15590Sstevel@tonic-gate 		vlan->gldv_nstreams++;
15600Sstevel@tonic-gate 		gldinsque(gld, vlan->gldv_str_prev);
15610Sstevel@tonic-gate 		*dev = makedevice(getmajor(*dev), gld->gld_minor);
15620Sstevel@tonic-gate 		WR(q)->q_ptr = q->q_ptr = (caddr_t)gld;
15630Sstevel@tonic-gate 
15640Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
15650Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
15660Sstevel@tonic-gate 		if (gld_debug & GLDPROT)
15670Sstevel@tonic-gate 			cmn_err(CE_NOTE,
15680Sstevel@tonic-gate 			    "GLDstruct added to instance list");
15690Sstevel@tonic-gate #endif
15700Sstevel@tonic-gate 		break;
15710Sstevel@tonic-gate 	}
15720Sstevel@tonic-gate 
15730Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED) {
15740Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
15750Sstevel@tonic-gate 		kmem_free(gld, sizeof (gld_t));
15760Sstevel@tonic-gate 		return (ENXIO);
15770Sstevel@tonic-gate 	}
15780Sstevel@tonic-gate 
15790Sstevel@tonic-gate done:
15800Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
15810Sstevel@tonic-gate 	noenable(WR(q));	/* We'll do the qenables manually */
15820Sstevel@tonic-gate 	qprocson(q);		/* start the queues running */
15830Sstevel@tonic-gate 	qenable(WR(q));
15840Sstevel@tonic-gate 	return (0);
15850Sstevel@tonic-gate }
15860Sstevel@tonic-gate 
15870Sstevel@tonic-gate /*
15880Sstevel@tonic-gate  * normal stream close call checks current status and cleans up
15890Sstevel@tonic-gate  * data structures that were dynamically allocated
15900Sstevel@tonic-gate  */
15910Sstevel@tonic-gate /*ARGSUSED1*/
15920Sstevel@tonic-gate int
15930Sstevel@tonic-gate gld_close(queue_t *q, int flag, cred_t *cred)
15940Sstevel@tonic-gate {
15950Sstevel@tonic-gate 	gld_t	*gld = (gld_t *)q->q_ptr;
15960Sstevel@tonic-gate 	glddev_t *glddev = gld->gld_device;
15970Sstevel@tonic-gate 
15980Sstevel@tonic-gate 	ASSERT(q);
15990Sstevel@tonic-gate 	ASSERT(gld);
16000Sstevel@tonic-gate 
16010Sstevel@tonic-gate #ifdef GLD_DEBUG
16020Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
16030Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_close(%p, Style %d)",
16040Sstevel@tonic-gate 		    (void *)q, (gld->gld_style & 0x1) + 1);
16050Sstevel@tonic-gate 	}
16060Sstevel@tonic-gate #endif
16070Sstevel@tonic-gate 
16080Sstevel@tonic-gate 	/* Hold all device streams lists still while we check for a macinfo */
16090Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
16100Sstevel@tonic-gate 
16110Sstevel@tonic-gate 	if (gld->gld_mac_info != NULL) {
16120Sstevel@tonic-gate 		/* If there's a macinfo, block recv while we change state */
16130Sstevel@tonic-gate 		GLDM_LOCK(gld->gld_mac_info, RW_WRITER);
16140Sstevel@tonic-gate 		gld->gld_flags |= GLD_STR_CLOSING; /* no more rcv putnexts */
16150Sstevel@tonic-gate 		GLDM_UNLOCK(gld->gld_mac_info);
16160Sstevel@tonic-gate 	} else {
16170Sstevel@tonic-gate 		/* no mac DL_ATTACHED right now */
16180Sstevel@tonic-gate 		gld->gld_flags |= GLD_STR_CLOSING;
16190Sstevel@tonic-gate 	}
16200Sstevel@tonic-gate 
16210Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
16220Sstevel@tonic-gate 
16230Sstevel@tonic-gate 	/*
16240Sstevel@tonic-gate 	 * qprocsoff before we call gld_unbind/gldunattach, so that
16250Sstevel@tonic-gate 	 * we know wsrv isn't in there trying to undo what we're doing.
16260Sstevel@tonic-gate 	 */
16270Sstevel@tonic-gate 	qprocsoff(q);
16280Sstevel@tonic-gate 
16290Sstevel@tonic-gate 	ASSERT(gld->gld_wput_count == 0);
16300Sstevel@tonic-gate 	gld->gld_wput_count = 0;	/* just in case */
16310Sstevel@tonic-gate 
16320Sstevel@tonic-gate 	if (gld->gld_state == DL_IDLE) {
16330Sstevel@tonic-gate 		/* Need to unbind */
16340Sstevel@tonic-gate 		ASSERT(gld->gld_mac_info != NULL);
16350Sstevel@tonic-gate 		(void) gld_unbind(WR(q), NULL);
16360Sstevel@tonic-gate 	}
16370Sstevel@tonic-gate 
16380Sstevel@tonic-gate 	if (gld->gld_state == DL_UNBOUND) {
16390Sstevel@tonic-gate 		/*
16400Sstevel@tonic-gate 		 * Need to unattach
16410Sstevel@tonic-gate 		 * For style 2 stream, gldunattach also
16420Sstevel@tonic-gate 		 * associate queue with NULL dip
16430Sstevel@tonic-gate 		 */
16440Sstevel@tonic-gate 		ASSERT(gld->gld_mac_info != NULL);
16450Sstevel@tonic-gate 		(void) gldunattach(WR(q), NULL);
16460Sstevel@tonic-gate 	}
16470Sstevel@tonic-gate 
16480Sstevel@tonic-gate 	/* disassociate the stream from the device */
16490Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = NULL;
16500Sstevel@tonic-gate 
16510Sstevel@tonic-gate 	/*
16520Sstevel@tonic-gate 	 * Since we unattached above (if necessary), we know that we're
16530Sstevel@tonic-gate 	 * on the per-major list of unattached streams, rather than a
16540Sstevel@tonic-gate 	 * per-PPA list.  So we know we should hold the devlock.
16550Sstevel@tonic-gate 	 */
16560Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
16570Sstevel@tonic-gate 	gldremque(gld);			/* remove from Style 2 list */
16580Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
16590Sstevel@tonic-gate 
16600Sstevel@tonic-gate 	kmem_free(gld, sizeof (gld_t));
16610Sstevel@tonic-gate 
16620Sstevel@tonic-gate 	return (0);
16630Sstevel@tonic-gate }
16640Sstevel@tonic-gate 
16650Sstevel@tonic-gate /*
16660Sstevel@tonic-gate  * gld_rsrv (q)
16670Sstevel@tonic-gate  *	simple read service procedure
16680Sstevel@tonic-gate  *	purpose is to avoid the time it takes for packets
16690Sstevel@tonic-gate  *	to move through IP so we can get them off the board
16700Sstevel@tonic-gate  *	as fast as possible due to limited PC resources.
16710Sstevel@tonic-gate  *
16720Sstevel@tonic-gate  *	This is not normally used in the current implementation.  It
16730Sstevel@tonic-gate  *	can be selected with the undocumented property "fast_recv".
16740Sstevel@tonic-gate  *	If that property is set, gld_recv will send the packet
16750Sstevel@tonic-gate  *	upstream with a putq() rather than a putnext(), thus causing
16760Sstevel@tonic-gate  *	this routine to be scheduled.
16770Sstevel@tonic-gate  */
16780Sstevel@tonic-gate int
16790Sstevel@tonic-gate gld_rsrv(queue_t *q)
16800Sstevel@tonic-gate {
16810Sstevel@tonic-gate 	mblk_t *mp;
16820Sstevel@tonic-gate 
16830Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
16840Sstevel@tonic-gate 		if (canputnext(q)) {
16850Sstevel@tonic-gate 			putnext(q, mp);
16860Sstevel@tonic-gate 		} else {
16870Sstevel@tonic-gate 			freemsg(mp);
16880Sstevel@tonic-gate 		}
16890Sstevel@tonic-gate 	}
16900Sstevel@tonic-gate 	return (0);
16910Sstevel@tonic-gate }
16920Sstevel@tonic-gate 
16930Sstevel@tonic-gate /*
16940Sstevel@tonic-gate  * gld_wput (q, mp)
16950Sstevel@tonic-gate  * general gld stream write put routine. Receives fastpath data from upper
16960Sstevel@tonic-gate  * modules and processes it immediately.  ioctl and M_PROTO/M_PCPROTO are
16970Sstevel@tonic-gate  * queued for later processing by the service procedure.
16980Sstevel@tonic-gate  */
16990Sstevel@tonic-gate 
17000Sstevel@tonic-gate int
17010Sstevel@tonic-gate gld_wput(queue_t *q, mblk_t *mp)
17020Sstevel@tonic-gate {
17030Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)(q->q_ptr);
17040Sstevel@tonic-gate 	int	rc;
17050Sstevel@tonic-gate 	boolean_t multidata = B_TRUE;
17060Sstevel@tonic-gate 
17070Sstevel@tonic-gate #ifdef GLD_DEBUG
17080Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
17090Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_wput(%p %p): type %x",
17100Sstevel@tonic-gate 		    (void *)q, (void *)mp, DB_TYPE(mp));
17110Sstevel@tonic-gate #endif
17120Sstevel@tonic-gate 	switch (DB_TYPE(mp)) {
17130Sstevel@tonic-gate 
17140Sstevel@tonic-gate 	case M_DATA:
17150Sstevel@tonic-gate 		/* fast data / raw support */
17160Sstevel@tonic-gate 		/* we must be DL_ATTACHED and DL_BOUND to do this */
17170Sstevel@tonic-gate 		/* Tricky to access memory without taking the mutex */
17180Sstevel@tonic-gate 		if ((gld->gld_flags & (GLD_RAW | GLD_FAST)) == 0 ||
17190Sstevel@tonic-gate 		    gld->gld_state != DL_IDLE) {
17200Sstevel@tonic-gate 			merror(q, mp, EPROTO);
17210Sstevel@tonic-gate 			break;
17220Sstevel@tonic-gate 		}
17230Sstevel@tonic-gate 		multidata = B_FALSE;
17240Sstevel@tonic-gate 		/* LINTED: E_CASE_FALLTHRU */
17250Sstevel@tonic-gate 	case M_MULTIDATA:
17260Sstevel@tonic-gate 		/* Only call gld_start() directly if nothing queued ahead */
17270Sstevel@tonic-gate 		/* No guarantees about ordering with different threads */
17280Sstevel@tonic-gate 		if (q->q_first)
17290Sstevel@tonic-gate 			goto use_wsrv;
17300Sstevel@tonic-gate 
17310Sstevel@tonic-gate 		/*
17320Sstevel@tonic-gate 		 * This can happen if wsrv has taken off the last mblk but
17330Sstevel@tonic-gate 		 * is still processing it.
17340Sstevel@tonic-gate 		 */
17350Sstevel@tonic-gate 		membar_consumer();
17360Sstevel@tonic-gate 		if (gld->gld_in_wsrv)
17370Sstevel@tonic-gate 			goto use_wsrv;
17380Sstevel@tonic-gate 
17390Sstevel@tonic-gate 		/*
17400Sstevel@tonic-gate 		 * Keep a count of current wput calls to start.
17410Sstevel@tonic-gate 		 * Nonzero count delays any attempted DL_UNBIND.
17420Sstevel@tonic-gate 		 * See comments above gld_start().
17430Sstevel@tonic-gate 		 */
17440Sstevel@tonic-gate 		atomic_add_32((uint32_t *)&gld->gld_wput_count, 1);
17450Sstevel@tonic-gate 		membar_enter();
17460Sstevel@tonic-gate 
17470Sstevel@tonic-gate 		/* Recheck state now wput_count is set to prevent DL_UNBIND */
17480Sstevel@tonic-gate 		/* If this Q is in process of DL_UNBIND, don't call start */
17490Sstevel@tonic-gate 		if (gld->gld_state != DL_IDLE || gld->gld_in_unbind) {
17500Sstevel@tonic-gate 			/* Extremely unlikely */
17510Sstevel@tonic-gate 			atomic_add_32((uint32_t *)&gld->gld_wput_count, -1);
17520Sstevel@tonic-gate 			goto use_wsrv;
17530Sstevel@tonic-gate 		}
17540Sstevel@tonic-gate 
17550Sstevel@tonic-gate 		rc = (multidata) ? gld_start_mdt(q, mp, GLD_WPUT) :
17560Sstevel@tonic-gate 		    gld_start(q, mp, GLD_WPUT, UPRI(gld, mp->b_band));
17570Sstevel@tonic-gate 
17580Sstevel@tonic-gate 		/* Allow DL_UNBIND again */
17590Sstevel@tonic-gate 		membar_exit();
17600Sstevel@tonic-gate 		atomic_add_32((uint32_t *)&gld->gld_wput_count, -1);
17610Sstevel@tonic-gate 
17620Sstevel@tonic-gate 		if (rc == GLD_NORESOURCES)
17630Sstevel@tonic-gate 			qenable(q);
17640Sstevel@tonic-gate 		break;	/*  Done with this packet */
17650Sstevel@tonic-gate 
17660Sstevel@tonic-gate use_wsrv:
17670Sstevel@tonic-gate 		/* Q not empty, in DL_DETACH, or start gave NORESOURCES */
17680Sstevel@tonic-gate 		(void) putq(q, mp);
17690Sstevel@tonic-gate 		qenable(q);
17700Sstevel@tonic-gate 		break;
17710Sstevel@tonic-gate 
17720Sstevel@tonic-gate 	case M_IOCTL:
17730Sstevel@tonic-gate 		/* ioctl relies on wsrv single threading per queue */
17740Sstevel@tonic-gate 		(void) putq(q, mp);
17750Sstevel@tonic-gate 		qenable(q);
17760Sstevel@tonic-gate 		break;
17770Sstevel@tonic-gate 
17780Sstevel@tonic-gate 	case M_CTL:
17790Sstevel@tonic-gate 		(void) putq(q, mp);
17800Sstevel@tonic-gate 		qenable(q);
17810Sstevel@tonic-gate 		break;
17820Sstevel@tonic-gate 
17830Sstevel@tonic-gate 	case M_FLUSH:		/* canonical flush handling */
17840Sstevel@tonic-gate 		/* XXX Should these be FLUSHALL? */
17850Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
17860Sstevel@tonic-gate 			flushq(q, 0);
17870Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
17880Sstevel@tonic-gate 			flushq(RD(q), 0);
17890Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;
17900Sstevel@tonic-gate 			qreply(q, mp);
17910Sstevel@tonic-gate 		} else
17920Sstevel@tonic-gate 			freemsg(mp);
17930Sstevel@tonic-gate 		break;
17940Sstevel@tonic-gate 
17950Sstevel@tonic-gate 	case M_PROTO:
17960Sstevel@tonic-gate 	case M_PCPROTO:
17970Sstevel@tonic-gate 		/* these rely on wsrv single threading per queue */
17980Sstevel@tonic-gate 		(void) putq(q, mp);
17990Sstevel@tonic-gate 		qenable(q);
18000Sstevel@tonic-gate 		break;
18010Sstevel@tonic-gate 
18020Sstevel@tonic-gate 	default:
18030Sstevel@tonic-gate #ifdef GLD_DEBUG
18040Sstevel@tonic-gate 		if (gld_debug & GLDETRACE)
18050Sstevel@tonic-gate 			cmn_err(CE_WARN,
18060Sstevel@tonic-gate 			    "gld: Unexpected packet type from queue: 0x%x",
18070Sstevel@tonic-gate 			    DB_TYPE(mp));
18080Sstevel@tonic-gate #endif
18090Sstevel@tonic-gate 		freemsg(mp);
18100Sstevel@tonic-gate 	}
18110Sstevel@tonic-gate 	return (0);
18120Sstevel@tonic-gate }
18130Sstevel@tonic-gate 
18140Sstevel@tonic-gate /*
18150Sstevel@tonic-gate  * gld_wsrv - Incoming messages are processed according to the DLPI protocol
18160Sstevel@tonic-gate  * specification.
18170Sstevel@tonic-gate  *
18180Sstevel@tonic-gate  * wsrv is single-threaded per Q.  We make use of this to avoid taking the
18190Sstevel@tonic-gate  * lock for reading data items that are only ever written by us.
18200Sstevel@tonic-gate  */
18210Sstevel@tonic-gate 
18220Sstevel@tonic-gate int
18230Sstevel@tonic-gate gld_wsrv(queue_t *q)
18240Sstevel@tonic-gate {
18250Sstevel@tonic-gate 	mblk_t *mp;
18260Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
18270Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
18280Sstevel@tonic-gate 	union DL_primitives *prim;
18290Sstevel@tonic-gate 	int err;
18300Sstevel@tonic-gate 	boolean_t multidata;
18310Sstevel@tonic-gate 
18320Sstevel@tonic-gate #ifdef GLD_DEBUG
18330Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
18340Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_wsrv(%p)", (void *)q);
18350Sstevel@tonic-gate #endif
18360Sstevel@tonic-gate 
18370Sstevel@tonic-gate 	ASSERT(!gld->gld_in_wsrv);
18380Sstevel@tonic-gate 
18390Sstevel@tonic-gate 	gld->gld_xwait = B_FALSE; /* We are now going to process this Q */
18400Sstevel@tonic-gate 
18410Sstevel@tonic-gate 	if (q->q_first == NULL)
18420Sstevel@tonic-gate 		return (0);
18430Sstevel@tonic-gate 
18440Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
18450Sstevel@tonic-gate 
18460Sstevel@tonic-gate 	/*
18470Sstevel@tonic-gate 	 * Help wput avoid a call to gld_start if there might be a message
18480Sstevel@tonic-gate 	 * previously queued by that thread being processed here.
18490Sstevel@tonic-gate 	 */
18500Sstevel@tonic-gate 	gld->gld_in_wsrv = B_TRUE;
18510Sstevel@tonic-gate 	membar_enter();
18520Sstevel@tonic-gate 
18530Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
18540Sstevel@tonic-gate 		switch (DB_TYPE(mp)) {
18550Sstevel@tonic-gate 		case M_DATA:
18560Sstevel@tonic-gate 		case M_MULTIDATA:
18570Sstevel@tonic-gate 			multidata = (DB_TYPE(mp) == M_MULTIDATA);
18580Sstevel@tonic-gate 
18590Sstevel@tonic-gate 			/*
18600Sstevel@tonic-gate 			 * retry of a previously processed UNITDATA_REQ
18610Sstevel@tonic-gate 			 * or is a RAW or FAST message from above.
18620Sstevel@tonic-gate 			 */
18630Sstevel@tonic-gate 			if (macinfo == NULL) {
18640Sstevel@tonic-gate 				/* No longer attached to a PPA, drop packet */
18650Sstevel@tonic-gate 				freemsg(mp);
18660Sstevel@tonic-gate 				break;
18670Sstevel@tonic-gate 			}
18680Sstevel@tonic-gate 
18690Sstevel@tonic-gate 			gld->gld_sched_ran = B_FALSE;
18700Sstevel@tonic-gate 			membar_enter();
18710Sstevel@tonic-gate 			err = (multidata) ? gld_start_mdt(q, mp, GLD_WSRV) :
18720Sstevel@tonic-gate 			    gld_start(q, mp, GLD_WSRV, UPRI(gld, mp->b_band));
18730Sstevel@tonic-gate 			if (err == GLD_NORESOURCES) {
18740Sstevel@tonic-gate 				/* gld_sched will qenable us later */
18750Sstevel@tonic-gate 				gld->gld_xwait = B_TRUE; /* want qenable */
18760Sstevel@tonic-gate 				membar_enter();
18770Sstevel@tonic-gate 				/*
18780Sstevel@tonic-gate 				 * v2:  we're not holding the lock; it's
18790Sstevel@tonic-gate 				 * possible that the driver could have already
18800Sstevel@tonic-gate 				 * called gld_sched (following up on its
18810Sstevel@tonic-gate 				 * return of GLD_NORESOURCES), before we got a
18820Sstevel@tonic-gate 				 * chance to do the putbq() and set gld_xwait.
18830Sstevel@tonic-gate 				 * So if we saw a call to gld_sched that
18840Sstevel@tonic-gate 				 * examined this queue, since our call to
18850Sstevel@tonic-gate 				 * gld_start() above, then it's possible we've
18860Sstevel@tonic-gate 				 * already seen the only call to gld_sched()
18870Sstevel@tonic-gate 				 * we're ever going to see.  So we better retry
18880Sstevel@tonic-gate 				 * transmitting this packet right now.
18890Sstevel@tonic-gate 				 */
18900Sstevel@tonic-gate 				if (gld->gld_sched_ran) {
18910Sstevel@tonic-gate #ifdef GLD_DEBUG
18920Sstevel@tonic-gate 					if (gld_debug & GLDTRACE)
18930Sstevel@tonic-gate 						cmn_err(CE_NOTE, "gld_wsrv: "
18940Sstevel@tonic-gate 						    "sched was called");
18950Sstevel@tonic-gate #endif
18960Sstevel@tonic-gate 					break;	/* try again right now */
18970Sstevel@tonic-gate 				}
18980Sstevel@tonic-gate 				gld->gld_in_wsrv = B_FALSE;
18990Sstevel@tonic-gate 				return (0);
19000Sstevel@tonic-gate 			}
19010Sstevel@tonic-gate 			break;
19020Sstevel@tonic-gate 
19030Sstevel@tonic-gate 		case M_IOCTL:
19040Sstevel@tonic-gate 			(void) gld_ioctl(q, mp);
19050Sstevel@tonic-gate 			break;
19060Sstevel@tonic-gate 
19070Sstevel@tonic-gate 		case M_CTL:
19080Sstevel@tonic-gate 			if (macinfo == NULL) {
19090Sstevel@tonic-gate 				freemsg(mp);
19100Sstevel@tonic-gate 				break;
19110Sstevel@tonic-gate 			}
19120Sstevel@tonic-gate 
19130Sstevel@tonic-gate 			if (macinfo->gldm_mctl != NULL) {
19140Sstevel@tonic-gate 				GLDM_LOCK(macinfo, RW_WRITER);
19150Sstevel@tonic-gate 				(void) (*macinfo->gldm_mctl) (macinfo, q, mp);
19160Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
19170Sstevel@tonic-gate 			} else {
19180Sstevel@tonic-gate 				/* This driver doesn't recognize, just drop */
19190Sstevel@tonic-gate 				freemsg(mp);
19200Sstevel@tonic-gate 			}
19210Sstevel@tonic-gate 			break;
19220Sstevel@tonic-gate 
19230Sstevel@tonic-gate 		case M_PROTO:	/* Will be an DLPI message of some type */
19240Sstevel@tonic-gate 		case M_PCPROTO:
19250Sstevel@tonic-gate 			if ((err = gld_cmds(q, mp)) != GLDE_OK) {
19260Sstevel@tonic-gate 				if (err == GLDE_RETRY) {
19270Sstevel@tonic-gate 					gld->gld_in_wsrv = B_FALSE;
19280Sstevel@tonic-gate 					return (0); /* quit while we're ahead */
19290Sstevel@tonic-gate 				}
19300Sstevel@tonic-gate 				prim = (union DL_primitives *)mp->b_rptr;
19310Sstevel@tonic-gate 				dlerrorack(q, mp, prim->dl_primitive, err, 0);
19320Sstevel@tonic-gate 			}
19330Sstevel@tonic-gate 			break;
19340Sstevel@tonic-gate 
19350Sstevel@tonic-gate 		default:
19360Sstevel@tonic-gate 			/* This should never happen */
19370Sstevel@tonic-gate #ifdef GLD_DEBUG
19380Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
19390Sstevel@tonic-gate 				cmn_err(CE_WARN,
19400Sstevel@tonic-gate 				    "gld_wsrv: db_type(%x) not supported",
19410Sstevel@tonic-gate 				    mp->b_datap->db_type);
19420Sstevel@tonic-gate #endif
19430Sstevel@tonic-gate 			freemsg(mp);	/* unknown types are discarded */
19440Sstevel@tonic-gate 			break;
19450Sstevel@tonic-gate 		}
19460Sstevel@tonic-gate 	}
19470Sstevel@tonic-gate 
19480Sstevel@tonic-gate 	membar_exit();
19490Sstevel@tonic-gate 	gld->gld_in_wsrv = B_FALSE;
19500Sstevel@tonic-gate 	return (0);
19510Sstevel@tonic-gate }
19520Sstevel@tonic-gate 
19530Sstevel@tonic-gate /*
19540Sstevel@tonic-gate  * gld_start() can get called from gld_wput(), gld_wsrv(), or gld_unitdata().
19550Sstevel@tonic-gate  *
19560Sstevel@tonic-gate  * We only come directly from wput() in the GLD_FAST (fastpath) or RAW case.
19570Sstevel@tonic-gate  *
19580Sstevel@tonic-gate  * In particular, we must avoid calling gld_precv*() if we came from wput().
19590Sstevel@tonic-gate  * gld_precv*() is where we, on the transmit side, loop back our outgoing
19600Sstevel@tonic-gate  * packets to the receive side if we are in physical promiscuous mode.
19610Sstevel@tonic-gate  * Since the receive side holds a lock across its call to the upstream
19620Sstevel@tonic-gate  * putnext, and that upstream module could well have looped back to our
19630Sstevel@tonic-gate  * wput() routine on the same thread, we cannot call gld_precv* from here
19640Sstevel@tonic-gate  * for fear of causing a recursive lock entry in our receive code.
19650Sstevel@tonic-gate  *
19660Sstevel@tonic-gate  * There is a problem here when coming from gld_wput().  While wput
19670Sstevel@tonic-gate  * only comes here if the queue is attached to a PPA and bound to a SAP
19680Sstevel@tonic-gate  * and there are no messages on the queue ahead of the M_DATA that could
19690Sstevel@tonic-gate  * change that, it is theoretically possible that another thread could
19700Sstevel@tonic-gate  * now wput a DL_UNBIND and a DL_DETACH message, and the wsrv() routine
19710Sstevel@tonic-gate  * could wake up and process them, before we finish processing this
19720Sstevel@tonic-gate  * send of the M_DATA.  This can only possibly happen on a Style 2 RAW or
19730Sstevel@tonic-gate  * FAST (fastpath) stream:  non RAW/FAST streams always go through wsrv(),
19740Sstevel@tonic-gate  * and Style 1 streams only DL_DETACH in the close routine, where
19750Sstevel@tonic-gate  * qprocsoff() protects us.  If this happens we could end up calling
19760Sstevel@tonic-gate  * gldm_send() after we have detached the stream and possibly called
19770Sstevel@tonic-gate  * gldm_stop().  Worse, once the number of attached streams goes to zero,
19780Sstevel@tonic-gate  * detach/unregister could be called, and the macinfo could go away entirely.
19790Sstevel@tonic-gate  *
19800Sstevel@tonic-gate  * No one has ever seen this happen.
19810Sstevel@tonic-gate  *
19820Sstevel@tonic-gate  * It is some trouble to fix this, and we would rather not add any mutex
19830Sstevel@tonic-gate  * logic into the wput() routine, which is supposed to be a "fast"
19840Sstevel@tonic-gate  * path.
19850Sstevel@tonic-gate  *
19860Sstevel@tonic-gate  * What I've done is use an atomic counter to keep a count of the number
19870Sstevel@tonic-gate  * of threads currently calling gld_start() from wput() on this stream.
19880Sstevel@tonic-gate  * If DL_DETACH sees this as nonzero, it putbqs the request back onto
19890Sstevel@tonic-gate  * the queue and qenables, hoping to have better luck next time.  Since
19900Sstevel@tonic-gate  * people shouldn't be trying to send after they've asked to DL_DETACH,
19910Sstevel@tonic-gate  * hopefully very soon all the wput=>start threads should have returned
19920Sstevel@tonic-gate  * and the DL_DETACH will succeed.  It's hard to test this since the odds
19930Sstevel@tonic-gate  * of the failure even trying to happen are so small.  I probably could
19940Sstevel@tonic-gate  * have ignored the whole issue and never been the worse for it.
19950Sstevel@tonic-gate  */
19960Sstevel@tonic-gate static int
19970Sstevel@tonic-gate gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri)
19980Sstevel@tonic-gate {
19990Sstevel@tonic-gate 	mblk_t *nmp;
20000Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
20010Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
20020Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
20030Sstevel@tonic-gate 	int rc;
20040Sstevel@tonic-gate 	gld_interface_t *ifp;
20050Sstevel@tonic-gate 	pktinfo_t pktinfo;
20060Sstevel@tonic-gate 	uint32_t vtag;
20070Sstevel@tonic-gate 	gld_vlan_t *vlan;
20080Sstevel@tonic-gate 
20090Sstevel@tonic-gate 	ASSERT(DB_TYPE(mp) == M_DATA);
20100Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
20110Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
20120Sstevel@tonic-gate 	ifp = mac_pvt->interfacep;
20130Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
20140Sstevel@tonic-gate 
20150Sstevel@tonic-gate 	if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_TX) != 0) {
20160Sstevel@tonic-gate 		freemsg(mp);
20170Sstevel@tonic-gate #ifdef GLD_DEBUG
20180Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
20190Sstevel@tonic-gate 			cmn_err(CE_WARN,
20200Sstevel@tonic-gate 			    "gld_start: failed to interpret outbound packet");
20210Sstevel@tonic-gate #endif
20220Sstevel@tonic-gate 		vlan->gldv_stats->glds_xmtbadinterp++;
20230Sstevel@tonic-gate 		return (GLD_BADARG);
20240Sstevel@tonic-gate 	}
20250Sstevel@tonic-gate 
20260Sstevel@tonic-gate 	/*
20270Sstevel@tonic-gate 	 * We're not holding the lock for this check.  If the promiscuous
20280Sstevel@tonic-gate 	 * state is in flux it doesn't matter much if we get this wrong.
20290Sstevel@tonic-gate 	 */
20300Sstevel@tonic-gate 	if (mac_pvt->nprom > 0) {
20310Sstevel@tonic-gate 		/*
20320Sstevel@tonic-gate 		 * We want to loopback to the receive side, but to avoid
20330Sstevel@tonic-gate 		 * recursive lock entry:  if we came from wput(), which
20340Sstevel@tonic-gate 		 * could have looped back via IP from our own receive
20350Sstevel@tonic-gate 		 * interrupt thread, we decline this request.  wput()
20360Sstevel@tonic-gate 		 * will then queue the packet for wsrv().  This means
20370Sstevel@tonic-gate 		 * that when snoop is running we don't get the advantage
20380Sstevel@tonic-gate 		 * of the wput() multithreaded direct entry to the
20390Sstevel@tonic-gate 		 * driver's send routine.
20400Sstevel@tonic-gate 		 */
20410Sstevel@tonic-gate 		if (caller == GLD_WPUT) {
20420Sstevel@tonic-gate 			(void) putbq(q, mp);
20430Sstevel@tonic-gate 			return (GLD_NORESOURCES);
20440Sstevel@tonic-gate 		}
20450Sstevel@tonic-gate 		if (macinfo->gldm_capabilities & GLD_CAP_ZEROCOPY)
20460Sstevel@tonic-gate 			nmp = dupmsg_noloan(mp);
20470Sstevel@tonic-gate 		else
20480Sstevel@tonic-gate 			nmp = dupmsg(mp);
20490Sstevel@tonic-gate 	} else
20500Sstevel@tonic-gate 		nmp = NULL;		/* we need no loopback */
20510Sstevel@tonic-gate 
20520Sstevel@tonic-gate 	vtag = GLD_MK_VTAG(vlan->gldv_ptag, upri);
20530Sstevel@tonic-gate 	if (ifp->hdr_size > 0 &&
20540Sstevel@tonic-gate 	    pktinfo.pktLen > ifp->hdr_size + (vtag == 0 ? 0 : VTAG_SIZE) +
20550Sstevel@tonic-gate 	    macinfo->gldm_maxpkt) {
20560Sstevel@tonic-gate 		freemsg(mp);	/* discard oversized outbound packet */
20570Sstevel@tonic-gate 		if (nmp)
20580Sstevel@tonic-gate 			freemsg(nmp);	/* free the duped message */
20590Sstevel@tonic-gate #ifdef GLD_DEBUG
20600Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
20610Sstevel@tonic-gate 			cmn_err(CE_WARN,
20620Sstevel@tonic-gate 			    "gld_start: oversize outbound packet, size %d,"
20630Sstevel@tonic-gate 			    "max %d", pktinfo.pktLen,
20640Sstevel@tonic-gate 			    ifp->hdr_size + macinfo->gldm_maxpkt);
20650Sstevel@tonic-gate #endif
20660Sstevel@tonic-gate 		vlan->gldv_stats->glds_xmtbadinterp++;
20670Sstevel@tonic-gate 		return (GLD_BADARG);
20680Sstevel@tonic-gate 	}
20690Sstevel@tonic-gate 
20700Sstevel@tonic-gate 	rc = (*gld->gld_send)(macinfo, mp, vtag);
20710Sstevel@tonic-gate 
20720Sstevel@tonic-gate 	if (rc != GLD_SUCCESS) {
20730Sstevel@tonic-gate 		if (rc == GLD_NORESOURCES) {
20740Sstevel@tonic-gate 			vlan->gldv_stats->glds_xmtretry++;
20750Sstevel@tonic-gate 			(void) putbq(q, mp);
20760Sstevel@tonic-gate 		} else {
20770Sstevel@tonic-gate 			/* transmit error; drop the packet */
20780Sstevel@tonic-gate 			freemsg(mp);
20790Sstevel@tonic-gate 			/* We're supposed to count failed attempts as well */
20800Sstevel@tonic-gate 			UPDATE_STATS(vlan, pktinfo, 1);
20810Sstevel@tonic-gate #ifdef GLD_DEBUG
20820Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
20830Sstevel@tonic-gate 				cmn_err(CE_WARN,
20840Sstevel@tonic-gate 				    "gld_start: gldm_send failed %d", rc);
20850Sstevel@tonic-gate #endif
20860Sstevel@tonic-gate 		}
20870Sstevel@tonic-gate 		if (nmp)
20880Sstevel@tonic-gate 			freemsg(nmp);	/* free the dupped message */
20890Sstevel@tonic-gate 		return (rc);
20900Sstevel@tonic-gate 	}
20910Sstevel@tonic-gate 
20920Sstevel@tonic-gate 	UPDATE_STATS(vlan, pktinfo, 1);
20930Sstevel@tonic-gate 
20940Sstevel@tonic-gate 	/*
20950Sstevel@tonic-gate 	 * Loopback case. The message needs to be returned back on
20960Sstevel@tonic-gate 	 * the read side. This would silently fail if the dumpmsg fails
20970Sstevel@tonic-gate 	 * above. This is probably OK, if there is no memory to dup the
20980Sstevel@tonic-gate 	 * block, then there isn't much we could do anyway.
20990Sstevel@tonic-gate 	 */
21000Sstevel@tonic-gate 	if (nmp) {
21010Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
21020Sstevel@tonic-gate 		gld_precv(macinfo, vlan, nmp);
21030Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
21040Sstevel@tonic-gate 	}
21050Sstevel@tonic-gate 
21060Sstevel@tonic-gate 	return (GLD_SUCCESS);
21070Sstevel@tonic-gate }
21080Sstevel@tonic-gate 
21090Sstevel@tonic-gate /*
21100Sstevel@tonic-gate  * With MDT V.2 a single message mp can have one header area and multiple
21110Sstevel@tonic-gate  * payload areas. A packet is described by dl_pkt_info, and each packet can
21120Sstevel@tonic-gate  * span multiple payload areas (currently with TCP, each packet will have one
21130Sstevel@tonic-gate  * header and at the most two payload areas). MACs might have a limit on the
21140Sstevel@tonic-gate  * number of payload segments (i.e. per packet scatter-gather limit), and
21150Sstevel@tonic-gate  * MDT V.2 has a way of specifying that with mdt_span_limit; the MAC driver
21160Sstevel@tonic-gate  * might also have a limit on the total number of payloads in a message, and
21170Sstevel@tonic-gate  * that is specified by mdt_max_pld.
21180Sstevel@tonic-gate  */
21190Sstevel@tonic-gate static int
21200Sstevel@tonic-gate gld_start_mdt(queue_t *q, mblk_t *mp, int caller)
21210Sstevel@tonic-gate {
21220Sstevel@tonic-gate 	mblk_t *nextmp;
21230Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
21240Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
21250Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
21260Sstevel@tonic-gate 	int numpacks, mdtpacks;
21270Sstevel@tonic-gate 	gld_interface_t *ifp = mac_pvt->interfacep;
21280Sstevel@tonic-gate 	pktinfo_t pktinfo;
21290Sstevel@tonic-gate 	gld_vlan_t *vlan = (gld_vlan_t *)gld->gld_vlan;
21300Sstevel@tonic-gate 	boolean_t doloop = B_FALSE;
21310Sstevel@tonic-gate 	multidata_t *dlmdp;
21320Sstevel@tonic-gate 	pdescinfo_t pinfo;
21330Sstevel@tonic-gate 	pdesc_t *dl_pkt;
21340Sstevel@tonic-gate 	void *cookie;
21350Sstevel@tonic-gate 	uint_t totLen = 0;
21360Sstevel@tonic-gate 
21370Sstevel@tonic-gate 	ASSERT(DB_TYPE(mp) == M_MULTIDATA);
21380Sstevel@tonic-gate 
21390Sstevel@tonic-gate 	/*
21400Sstevel@tonic-gate 	 * We're not holding the lock for this check.  If the promiscuous
21410Sstevel@tonic-gate 	 * state is in flux it doesn't matter much if we get this wrong.
21420Sstevel@tonic-gate 	 */
21430Sstevel@tonic-gate 	if (mac_pvt->nprom > 0) {
21440Sstevel@tonic-gate 		/*
21450Sstevel@tonic-gate 		 * We want to loopback to the receive side, but to avoid
21460Sstevel@tonic-gate 		 * recursive lock entry:  if we came from wput(), which
21470Sstevel@tonic-gate 		 * could have looped back via IP from our own receive
21480Sstevel@tonic-gate 		 * interrupt thread, we decline this request.  wput()
21490Sstevel@tonic-gate 		 * will then queue the packet for wsrv().  This means
21500Sstevel@tonic-gate 		 * that when snoop is running we don't get the advantage
21510Sstevel@tonic-gate 		 * of the wput() multithreaded direct entry to the
21520Sstevel@tonic-gate 		 * driver's send routine.
21530Sstevel@tonic-gate 		 */
21540Sstevel@tonic-gate 		if (caller == GLD_WPUT) {
21550Sstevel@tonic-gate 			(void) putbq(q, mp);
21560Sstevel@tonic-gate 			return (GLD_NORESOURCES);
21570Sstevel@tonic-gate 		}
21580Sstevel@tonic-gate 		doloop = B_TRUE;
21590Sstevel@tonic-gate 
21600Sstevel@tonic-gate 		/*
21610Sstevel@tonic-gate 		 * unlike the M_DATA case, we don't have to call
21620Sstevel@tonic-gate 		 * dupmsg_noloan here because mmd_transform
21630Sstevel@tonic-gate 		 * (called by gld_precv_mdt) will make a copy of
21640Sstevel@tonic-gate 		 * each dblk.
21650Sstevel@tonic-gate 		 */
21660Sstevel@tonic-gate 	}
21670Sstevel@tonic-gate 
21680Sstevel@tonic-gate 	while (mp != NULL) {
21690Sstevel@tonic-gate 		/*
21700Sstevel@tonic-gate 		 * The lower layer driver only gets a single multidata
21710Sstevel@tonic-gate 		 * message; this also makes it easier to handle noresources.
21720Sstevel@tonic-gate 		 */
21730Sstevel@tonic-gate 		nextmp = mp->b_cont;
21740Sstevel@tonic-gate 		mp->b_cont = NULL;
21750Sstevel@tonic-gate 
21760Sstevel@tonic-gate 		/*
21770Sstevel@tonic-gate 		 * Get number of packets in this message; if nothing
21780Sstevel@tonic-gate 		 * to transmit, go to next message.
21790Sstevel@tonic-gate 		 */
21800Sstevel@tonic-gate 		dlmdp = mmd_getmultidata(mp);
21810Sstevel@tonic-gate 		if ((mdtpacks = (int)mmd_getcnt(dlmdp, NULL, NULL)) == 0) {
21820Sstevel@tonic-gate 			freemsg(mp);
21830Sstevel@tonic-gate 			mp = nextmp;
21840Sstevel@tonic-gate 			continue;
21850Sstevel@tonic-gate 		}
21860Sstevel@tonic-gate 
21870Sstevel@tonic-gate 		/*
21880Sstevel@tonic-gate 		 * Run interpreter to populate media specific pktinfo fields.
21890Sstevel@tonic-gate 		 * This collects per MDT message information like sap,
21900Sstevel@tonic-gate 		 * broad/multicast etc.
21910Sstevel@tonic-gate 		 */
21920Sstevel@tonic-gate 		(void) (*ifp->interpreter_mdt)(macinfo, mp, NULL, &pktinfo,
21930Sstevel@tonic-gate 		    GLD_MDT_TX);
21940Sstevel@tonic-gate 
21950Sstevel@tonic-gate 		numpacks = (*macinfo->gldm_mdt_pre)(macinfo, mp, &cookie);
21960Sstevel@tonic-gate 
21970Sstevel@tonic-gate 		if (numpacks > 0) {
21980Sstevel@tonic-gate 			/*
21990Sstevel@tonic-gate 			 * Driver indicates it can transmit at least 1, and
22000Sstevel@tonic-gate 			 * possibly all, packets in MDT message.
22010Sstevel@tonic-gate 			 */
22020Sstevel@tonic-gate 			int count = numpacks;
22030Sstevel@tonic-gate 
22040Sstevel@tonic-gate 			for (dl_pkt = mmd_getfirstpdesc(dlmdp, &pinfo);
22050Sstevel@tonic-gate 			    (dl_pkt != NULL);
22060Sstevel@tonic-gate 			    dl_pkt = mmd_getnextpdesc(dl_pkt, &pinfo)) {
22070Sstevel@tonic-gate 				/*
22080Sstevel@tonic-gate 				 * Format this packet by adding link header and
22090Sstevel@tonic-gate 				 * adjusting pdescinfo to include it; get
22100Sstevel@tonic-gate 				 * packet length.
22110Sstevel@tonic-gate 				 */
22120Sstevel@tonic-gate 				(void) (*ifp->interpreter_mdt)(macinfo, NULL,
22130Sstevel@tonic-gate 				    &pinfo, &pktinfo, GLD_MDT_TXPKT);
22140Sstevel@tonic-gate 
22150Sstevel@tonic-gate 				totLen += pktinfo.pktLen;
22160Sstevel@tonic-gate 
22170Sstevel@tonic-gate 				/*
22180Sstevel@tonic-gate 				 * Loop back packet before handing to the
22190Sstevel@tonic-gate 				 * driver.
22200Sstevel@tonic-gate 				 */
22210Sstevel@tonic-gate 				if (doloop &&
22220Sstevel@tonic-gate 				    mmd_adjpdesc(dl_pkt, &pinfo) != NULL) {
22230Sstevel@tonic-gate 					GLDM_LOCK(macinfo, RW_WRITER);
22240Sstevel@tonic-gate 					gld_precv_mdt(macinfo, vlan, mp,
22250Sstevel@tonic-gate 					    dl_pkt, &pktinfo);
22260Sstevel@tonic-gate 					GLDM_UNLOCK(macinfo);
22270Sstevel@tonic-gate 				}
22280Sstevel@tonic-gate 
22290Sstevel@tonic-gate 				/*
22300Sstevel@tonic-gate 				 * And send off to driver.
22310Sstevel@tonic-gate 				 */
22320Sstevel@tonic-gate 				(*macinfo->gldm_mdt_send)(macinfo, cookie,
22330Sstevel@tonic-gate 				    &pinfo);
22340Sstevel@tonic-gate 
22350Sstevel@tonic-gate 				/*
22360Sstevel@tonic-gate 				 * Be careful not to invoke getnextpdesc if we
22370Sstevel@tonic-gate 				 * already sent the last packet, since driver
22380Sstevel@tonic-gate 				 * might have posted it to hardware causing a
22390Sstevel@tonic-gate 				 * completion and freemsg() so the MDT data
22400Sstevel@tonic-gate 				 * structures might not be valid anymore.
22410Sstevel@tonic-gate 				 */
22420Sstevel@tonic-gate 				if (--count == 0)
22430Sstevel@tonic-gate 					break;
22440Sstevel@tonic-gate 			}
22450Sstevel@tonic-gate 			(*macinfo->gldm_mdt_post)(macinfo, mp, cookie);
22460Sstevel@tonic-gate 			pktinfo.pktLen = totLen;
22470Sstevel@tonic-gate 			UPDATE_STATS(vlan, pktinfo, numpacks);
22480Sstevel@tonic-gate 
22490Sstevel@tonic-gate 			/*
22500Sstevel@tonic-gate 			 * In the noresources case (when driver indicates it
22510Sstevel@tonic-gate 			 * can not transmit all packets in the MDT message),
22520Sstevel@tonic-gate 			 * adjust to skip the first few packets on retrial.
22530Sstevel@tonic-gate 			 */
22540Sstevel@tonic-gate 			if (numpacks != mdtpacks) {
22550Sstevel@tonic-gate 				/*
22560Sstevel@tonic-gate 				 * Release already processed packet descriptors.
22570Sstevel@tonic-gate 				 */
22580Sstevel@tonic-gate 				for (count = 0; count < numpacks; count++) {
22590Sstevel@tonic-gate 					dl_pkt = mmd_getfirstpdesc(dlmdp,
22600Sstevel@tonic-gate 					    &pinfo);
22610Sstevel@tonic-gate 					mmd_rempdesc(dl_pkt);
22620Sstevel@tonic-gate 				}
22630Sstevel@tonic-gate 				vlan->gldv_stats->glds_xmtretry++;
22640Sstevel@tonic-gate 				mp->b_cont = nextmp;
22650Sstevel@tonic-gate 				(void) putbq(q, mp);
22660Sstevel@tonic-gate 				return (GLD_NORESOURCES);
22670Sstevel@tonic-gate 			}
22680Sstevel@tonic-gate 		} else if (numpacks == 0) {
22690Sstevel@tonic-gate 			/*
22700Sstevel@tonic-gate 			 * Driver indicates it can not transmit any packets
22710Sstevel@tonic-gate 			 * currently and will request retrial later.
22720Sstevel@tonic-gate 			 */
22730Sstevel@tonic-gate 			vlan->gldv_stats->glds_xmtretry++;
22740Sstevel@tonic-gate 			mp->b_cont = nextmp;
22750Sstevel@tonic-gate 			(void) putbq(q, mp);
22760Sstevel@tonic-gate 			return (GLD_NORESOURCES);
22770Sstevel@tonic-gate 		} else {
22780Sstevel@tonic-gate 			ASSERT(numpacks == -1);
22790Sstevel@tonic-gate 			/*
22800Sstevel@tonic-gate 			 * We're supposed to count failed attempts as well.
22810Sstevel@tonic-gate 			 */
22820Sstevel@tonic-gate 			dl_pkt = mmd_getfirstpdesc(dlmdp, &pinfo);
22830Sstevel@tonic-gate 			while (dl_pkt != NULL) {
22840Sstevel@tonic-gate 				/*
22850Sstevel@tonic-gate 				 * Call interpreter to determine total packet
22860Sstevel@tonic-gate 				 * bytes that are being dropped.
22870Sstevel@tonic-gate 				 */
22880Sstevel@tonic-gate 				(void) (*ifp->interpreter_mdt)(macinfo, NULL,
22890Sstevel@tonic-gate 				    &pinfo, &pktinfo, GLD_MDT_TXPKT);
22900Sstevel@tonic-gate 
22910Sstevel@tonic-gate 				totLen += pktinfo.pktLen;
22920Sstevel@tonic-gate 
22930Sstevel@tonic-gate 				dl_pkt = mmd_getnextpdesc(dl_pkt, &pinfo);
22940Sstevel@tonic-gate 			}
22950Sstevel@tonic-gate 			pktinfo.pktLen = totLen;
22960Sstevel@tonic-gate 			UPDATE_STATS(vlan, pktinfo, mdtpacks);
22970Sstevel@tonic-gate 
22980Sstevel@tonic-gate 			/*
22990Sstevel@tonic-gate 			 * Transmit error; drop the message, move on
23000Sstevel@tonic-gate 			 * to the next one.
23010Sstevel@tonic-gate 			 */
23020Sstevel@tonic-gate 			freemsg(mp);
23030Sstevel@tonic-gate 		}
23040Sstevel@tonic-gate 
23050Sstevel@tonic-gate 		/*
23060Sstevel@tonic-gate 		 * Process the next multidata block, if there is one.
23070Sstevel@tonic-gate 		 */
23080Sstevel@tonic-gate 		mp = nextmp;
23090Sstevel@tonic-gate 	}
23100Sstevel@tonic-gate 
23110Sstevel@tonic-gate 	return (GLD_SUCCESS);
23120Sstevel@tonic-gate }
23130Sstevel@tonic-gate 
23140Sstevel@tonic-gate /*
23150Sstevel@tonic-gate  * gld_intr (macinfo)
23160Sstevel@tonic-gate  */
23170Sstevel@tonic-gate uint_t
23180Sstevel@tonic-gate gld_intr(gld_mac_info_t *macinfo)
23190Sstevel@tonic-gate {
23200Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
23210Sstevel@tonic-gate 
23220Sstevel@tonic-gate 	if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY))
23230Sstevel@tonic-gate 		return (DDI_INTR_UNCLAIMED);
23240Sstevel@tonic-gate 
23250Sstevel@tonic-gate 	return ((*macinfo->gldm_intr)(macinfo));
23260Sstevel@tonic-gate }
23270Sstevel@tonic-gate 
23280Sstevel@tonic-gate /*
23290Sstevel@tonic-gate  * gld_sched (macinfo)
23300Sstevel@tonic-gate  *
23310Sstevel@tonic-gate  * This routine scans the streams that refer to a specific macinfo
23320Sstevel@tonic-gate  * structure and causes the STREAMS scheduler to try to run them if
23330Sstevel@tonic-gate  * they are marked as waiting for the transmit buffer.
23340Sstevel@tonic-gate  */
23350Sstevel@tonic-gate void
23360Sstevel@tonic-gate gld_sched(gld_mac_info_t *macinfo)
23370Sstevel@tonic-gate {
23380Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
23390Sstevel@tonic-gate 	gld_t *gld;
23400Sstevel@tonic-gate 	gld_vlan_t *vlan;
23410Sstevel@tonic-gate 	int i;
23420Sstevel@tonic-gate 
23430Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
23440Sstevel@tonic-gate 
23450Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
23460Sstevel@tonic-gate 
23470Sstevel@tonic-gate 	if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
23480Sstevel@tonic-gate 		/* We're probably being called from a leftover interrupt */
23490Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
23500Sstevel@tonic-gate 		return;
23510Sstevel@tonic-gate 	}
23520Sstevel@tonic-gate 
23530Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
23540Sstevel@tonic-gate 
23550Sstevel@tonic-gate 	for (i = 0; i < VLAN_HASHSZ; i++) {
23560Sstevel@tonic-gate 		for (vlan = mac_pvt->vlan_hash[i];
23570Sstevel@tonic-gate 		    vlan != NULL; vlan = vlan->gldv_next) {
23580Sstevel@tonic-gate 			for (gld = vlan->gldv_str_next;
23590Sstevel@tonic-gate 			    gld != (gld_t *)&vlan->gldv_str_next;
23600Sstevel@tonic-gate 			    gld = gld->gld_next) {
23610Sstevel@tonic-gate 				ASSERT(gld->gld_mac_info == macinfo);
23620Sstevel@tonic-gate 				gld->gld_sched_ran = B_TRUE;
23630Sstevel@tonic-gate 				membar_enter();
23640Sstevel@tonic-gate 				if (gld->gld_xwait) {
23650Sstevel@tonic-gate 					gld->gld_xwait = B_FALSE;
23660Sstevel@tonic-gate 					qenable(WR(gld->gld_qptr));
23670Sstevel@tonic-gate 				}
23680Sstevel@tonic-gate 			}
23690Sstevel@tonic-gate 		}
23700Sstevel@tonic-gate 	}
23710Sstevel@tonic-gate 
23720Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
23730Sstevel@tonic-gate }
23740Sstevel@tonic-gate 
23750Sstevel@tonic-gate /*
23760Sstevel@tonic-gate  * gld_precv (macinfo, mp)
23770Sstevel@tonic-gate  * called from gld_start to loopback a packet when in promiscuous mode
23780Sstevel@tonic-gate  */
23790Sstevel@tonic-gate static void
23800Sstevel@tonic-gate gld_precv(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp)
23810Sstevel@tonic-gate {
23820Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
23830Sstevel@tonic-gate 	gld_interface_t *ifp;
23840Sstevel@tonic-gate 	pktinfo_t pktinfo;
23850Sstevel@tonic-gate 
23860Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
23870Sstevel@tonic-gate 
23880Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
23890Sstevel@tonic-gate 	ifp = mac_pvt->interfacep;
23900Sstevel@tonic-gate 
23910Sstevel@tonic-gate 	/*
23920Sstevel@tonic-gate 	 * call the media specific packet interpreter routine
23930Sstevel@tonic-gate 	 */
23940Sstevel@tonic-gate 	if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RXLOOP) != 0) {
23950Sstevel@tonic-gate 		freemsg(mp);
23960Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_rcvbadinterp, 1);
23970Sstevel@tonic-gate #ifdef GLD_DEBUG
23980Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
23990Sstevel@tonic-gate 			cmn_err(CE_WARN,
24000Sstevel@tonic-gate 			    "gld_precv: interpreter failed");
24010Sstevel@tonic-gate #endif
24020Sstevel@tonic-gate 		return;
24030Sstevel@tonic-gate 	}
24040Sstevel@tonic-gate 
24050Sstevel@tonic-gate 	gld_sendup(macinfo, vlan, &pktinfo, mp, gld_paccept);
24060Sstevel@tonic-gate }
24070Sstevel@tonic-gate 
24080Sstevel@tonic-gate /*
24090Sstevel@tonic-gate  * called from gld_start_mdt to loopback packet(s) when in promiscuous mode
24100Sstevel@tonic-gate  */
24110Sstevel@tonic-gate static void
24120Sstevel@tonic-gate gld_precv_mdt(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp,
24130Sstevel@tonic-gate     pdesc_t *dl_pkt, pktinfo_t *pktinfo)
24140Sstevel@tonic-gate {
24150Sstevel@tonic-gate 	mblk_t *adjmp;
24160Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
24170Sstevel@tonic-gate 	gld_interface_t *ifp = mac_pvt->interfacep;
24180Sstevel@tonic-gate 
24190Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
24200Sstevel@tonic-gate 
24210Sstevel@tonic-gate 	/*
24220Sstevel@tonic-gate 	 * Get source/destination.
24230Sstevel@tonic-gate 	 */
24240Sstevel@tonic-gate 	(void) (*ifp->interpreter_mdt)(macinfo, mp, NULL, pktinfo,
24250Sstevel@tonic-gate 	    GLD_MDT_RXLOOP);
24260Sstevel@tonic-gate 	if ((adjmp = mmd_transform(dl_pkt)) != NULL)
24270Sstevel@tonic-gate 		gld_sendup(macinfo, vlan, pktinfo, adjmp, gld_paccept);
24280Sstevel@tonic-gate }
24290Sstevel@tonic-gate 
24300Sstevel@tonic-gate /*
24310Sstevel@tonic-gate  * gld_recv (macinfo, mp)
24320Sstevel@tonic-gate  * called with an mac-level packet in a mblock; take the maclock,
24330Sstevel@tonic-gate  * try the ip4q and ip6q hack, and otherwise call gld_sendup.
24340Sstevel@tonic-gate  *
24350Sstevel@tonic-gate  * V0 drivers already are holding the mutex when they call us.
24360Sstevel@tonic-gate  */
24370Sstevel@tonic-gate void
24380Sstevel@tonic-gate gld_recv(gld_mac_info_t *macinfo, mblk_t *mp)
24390Sstevel@tonic-gate {
24400Sstevel@tonic-gate 	gld_recv_tagged(macinfo, mp, VLAN_VTAG_NONE);
24410Sstevel@tonic-gate }
24420Sstevel@tonic-gate 
24430Sstevel@tonic-gate void
24440Sstevel@tonic-gate gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
24450Sstevel@tonic-gate {
24460Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
24470Sstevel@tonic-gate 	char pbuf[3*GLD_MAX_ADDRLEN];
24480Sstevel@tonic-gate 	pktinfo_t pktinfo;
24490Sstevel@tonic-gate 	gld_interface_t *ifp;
24500Sstevel@tonic-gate 	queue_t *ipq = NULL;
24510Sstevel@tonic-gate 	gld_vlan_t *vlan;
24520Sstevel@tonic-gate 	uint32_t vid;
24530Sstevel@tonic-gate 
24540Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
24550Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_ref);
24560Sstevel@tonic-gate 
24570Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_READER);
24580Sstevel@tonic-gate 
24590Sstevel@tonic-gate 	if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
24600Sstevel@tonic-gate 		/* We're probably being called from a leftover interrupt */
24610Sstevel@tonic-gate 		freemsg(mp);
24620Sstevel@tonic-gate 		goto done;
24630Sstevel@tonic-gate 	}
24640Sstevel@tonic-gate 
24650Sstevel@tonic-gate 	vid = GLD_VTAG_VID(vtag);
24660Sstevel@tonic-gate 	if ((vlan = gld_find_vlan(macinfo, vid)) == NULL) {
24670Sstevel@tonic-gate 		freemsg(mp);
24680Sstevel@tonic-gate 		goto done;
24690Sstevel@tonic-gate 	}
24700Sstevel@tonic-gate 
24710Sstevel@tonic-gate 	/*
24720Sstevel@tonic-gate 	 * Check whether underlying media code supports the IPQ hack,
24730Sstevel@tonic-gate 	 * and if so, whether the interpreter can quickly parse the
24740Sstevel@tonic-gate 	 * packet to get some relevant parameters.
24750Sstevel@tonic-gate 	 */
24760Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
24770Sstevel@tonic-gate 	ifp = mac_pvt->interfacep;
24780Sstevel@tonic-gate 	if (((*ifp->interpreter)(macinfo, mp, &pktinfo,
24790Sstevel@tonic-gate 	    GLD_RXQUICK) == 0) && (vlan->gldv_ipq_flags == 0)) {
24800Sstevel@tonic-gate 		switch (pktinfo.ethertype) {
24810Sstevel@tonic-gate 		case ETHERTYPE_IP:
24820Sstevel@tonic-gate 			ipq = vlan->gldv_ipq;
24830Sstevel@tonic-gate 			break;
24840Sstevel@tonic-gate 		case ETHERTYPE_IPV6:
24850Sstevel@tonic-gate 			ipq = vlan->gldv_ipv6q;
24860Sstevel@tonic-gate 			break;
24870Sstevel@tonic-gate 		}
24880Sstevel@tonic-gate 	}
24890Sstevel@tonic-gate 
24900Sstevel@tonic-gate 	BUMP(vlan->gldv_stats->glds_bytercv64, pktinfo.pktLen);
24910Sstevel@tonic-gate 	BUMP(vlan->gldv_stats->glds_pktrcv64, 1);
24920Sstevel@tonic-gate 
24930Sstevel@tonic-gate 	/*
24940Sstevel@tonic-gate 	 * Special case for IP; we can simply do the putnext here, if:
24950Sstevel@tonic-gate 	 * o ipq != NULL, and therefore:
24960Sstevel@tonic-gate 	 * - the device type supports IPQ (ethernet and IPoIB);
24970Sstevel@tonic-gate 	 * - the interpreter could quickly parse the packet;
24980Sstevel@tonic-gate 	 * - there are no PROMISC_SAP streams (on this VLAN);
24990Sstevel@tonic-gate 	 * - there is one, and only one, IP stream bound (to this VLAN);
25000Sstevel@tonic-gate 	 * - that stream is a "fastpath" stream;
25010Sstevel@tonic-gate 	 * - the packet is of type ETHERTYPE_IP or ETHERTYPE_IPV6
25020Sstevel@tonic-gate 	 *
25030Sstevel@tonic-gate 	 * o the packet is specifically for me, and therefore:
25040Sstevel@tonic-gate 	 * - the packet is not multicast or broadcast (fastpath only
25050Sstevel@tonic-gate 	 *   wants unicast packets).
25060Sstevel@tonic-gate 	 *
25070Sstevel@tonic-gate 	 * o the stream is not asserting flow control.
25080Sstevel@tonic-gate 	 */
25090Sstevel@tonic-gate 	if (ipq != NULL &&
25100Sstevel@tonic-gate 	    pktinfo.isForMe &&
25110Sstevel@tonic-gate 	    canputnext(ipq)) {
25120Sstevel@tonic-gate 		/*
25130Sstevel@tonic-gate 		 * Skip the mac header. We know there is no LLC1/SNAP header
25140Sstevel@tonic-gate 		 * in this packet
25150Sstevel@tonic-gate 		 */
25160Sstevel@tonic-gate 		mp->b_rptr += pktinfo.macLen;
25170Sstevel@tonic-gate 		putnext(ipq, mp);
25180Sstevel@tonic-gate 		goto done;
25190Sstevel@tonic-gate 	}
25200Sstevel@tonic-gate 
25210Sstevel@tonic-gate 	/*
25220Sstevel@tonic-gate 	 * call the media specific packet interpreter routine
25230Sstevel@tonic-gate 	 */
25240Sstevel@tonic-gate 	if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RX) != 0) {
25250Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_rcvbadinterp, 1);
25260Sstevel@tonic-gate #ifdef GLD_DEBUG
25270Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
25280Sstevel@tonic-gate 			cmn_err(CE_WARN,
25290Sstevel@tonic-gate 			    "gld_recv_tagged: interpreter failed");
25300Sstevel@tonic-gate #endif
25310Sstevel@tonic-gate 		freemsg(mp);
25320Sstevel@tonic-gate 		goto done;
25330Sstevel@tonic-gate 	}
25340Sstevel@tonic-gate 
25350Sstevel@tonic-gate 	/*
25360Sstevel@tonic-gate 	 * This is safe even if vtag is VLAN_VTAG_NONE
25370Sstevel@tonic-gate 	 */
25380Sstevel@tonic-gate 
25390Sstevel@tonic-gate 	pktinfo.vid = vid;
25400Sstevel@tonic-gate 	pktinfo.cfi = GLD_VTAG_CFI(vtag);
25410Sstevel@tonic-gate #ifdef GLD_DEBUG
25420Sstevel@tonic-gate 	if (pktinfo.cfi != VLAN_CFI_ETHER)
25430Sstevel@tonic-gate 		cmn_err(CE_WARN, "gld_recv_tagged: non-ETHER CFI");
25440Sstevel@tonic-gate #endif
25450Sstevel@tonic-gate 	pktinfo.user_pri = GLD_VTAG_PRI(vtag);
25460Sstevel@tonic-gate 
25470Sstevel@tonic-gate #ifdef GLD_DEBUG
25480Sstevel@tonic-gate 	if ((gld_debug & GLDRECV) &&
25490Sstevel@tonic-gate 	    (!(gld_debug & GLDNOBR) ||
25500Sstevel@tonic-gate 	    (!pktinfo.isBroadcast && !pktinfo.isMulticast))) {
25510Sstevel@tonic-gate 		char pbuf2[3*GLD_MAX_ADDRLEN];
25520Sstevel@tonic-gate 
25530Sstevel@tonic-gate 		cmn_err(CE_CONT, "gld_recv_tagged: machdr=<%s -> %s>\n",
25540Sstevel@tonic-gate 		    gld_macaddr_sprintf(pbuf, pktinfo.shost,
25550Sstevel@tonic-gate 		    macinfo->gldm_addrlen), gld_macaddr_sprintf(pbuf2,
25560Sstevel@tonic-gate 		    pktinfo.dhost, macinfo->gldm_addrlen));
25570Sstevel@tonic-gate 		cmn_err(CE_CONT, "gld_recv_tagged: VlanId %d UserPri %d\n",
25580Sstevel@tonic-gate 		    pktinfo.vid,
25590Sstevel@tonic-gate 		    pktinfo.user_pri);
25600Sstevel@tonic-gate 		cmn_err(CE_CONT, "gld_recv_tagged: ethertype: %4x Len: %4d "
25610Sstevel@tonic-gate 		    "Hdr: %d,%d isMulticast: %s\n",
25620Sstevel@tonic-gate 		    pktinfo.ethertype,
25630Sstevel@tonic-gate 		    pktinfo.pktLen,
25640Sstevel@tonic-gate 		    pktinfo.macLen,
25650Sstevel@tonic-gate 		    pktinfo.hdrLen,
25660Sstevel@tonic-gate 		    pktinfo.isMulticast ? "Y" : "N");
25670Sstevel@tonic-gate 	}
25680Sstevel@tonic-gate #endif
25690Sstevel@tonic-gate 
25700Sstevel@tonic-gate 	gld_sendup(macinfo, vlan, &pktinfo, mp, gld_accept);
25710Sstevel@tonic-gate 
25720Sstevel@tonic-gate done:
25730Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
25740Sstevel@tonic-gate }
25750Sstevel@tonic-gate 
25760Sstevel@tonic-gate /* =================================================================== */
25770Sstevel@tonic-gate /* receive group: called from gld_recv and gld_precv* with maclock held */
25780Sstevel@tonic-gate /* =================================================================== */
25790Sstevel@tonic-gate 
25800Sstevel@tonic-gate /*
25810Sstevel@tonic-gate  * gld_sendup (macinfo, mp)
25820Sstevel@tonic-gate  * called with an ethernet packet in a mblock; must decide whether
25830Sstevel@tonic-gate  * packet is for us and which streams to queue it to.
25840Sstevel@tonic-gate  */
25850Sstevel@tonic-gate static void
25860Sstevel@tonic-gate gld_sendup(gld_mac_info_t *macinfo, gld_vlan_t *vlan, pktinfo_t *pktinfo,
25870Sstevel@tonic-gate     mblk_t *mp, int (*acceptfunc)())
25880Sstevel@tonic-gate {
25890Sstevel@tonic-gate 	gld_t *gld;
25900Sstevel@tonic-gate 	gld_t *fgld = NULL;
25910Sstevel@tonic-gate 	mblk_t *nmp;
25920Sstevel@tonic-gate 	void (*send)(queue_t *qp, mblk_t *mp);
25930Sstevel@tonic-gate 	int (*cansend)(queue_t *qp);
25940Sstevel@tonic-gate 
25950Sstevel@tonic-gate #ifdef GLD_DEBUG
25960Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
25970Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_sendup(%p, %p)", (void *)mp,
25980Sstevel@tonic-gate 		    (void *)macinfo);
25990Sstevel@tonic-gate #endif
26000Sstevel@tonic-gate 
26010Sstevel@tonic-gate 	ASSERT(mp != NULL);
26020Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
26030Sstevel@tonic-gate 	ASSERT(vlan != NULL);
26040Sstevel@tonic-gate 	ASSERT(pktinfo != NULL);
26050Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(macinfo));
26060Sstevel@tonic-gate 
26070Sstevel@tonic-gate 	/*
26080Sstevel@tonic-gate 	 * The "fast" in "GLDOPT_FAST_RECV" refers to the speed at which
26090Sstevel@tonic-gate 	 * gld_recv returns to the caller's interrupt routine.  The total
26100Sstevel@tonic-gate 	 * network throughput would normally be lower when selecting this
26110Sstevel@tonic-gate 	 * option, because we putq the messages and process them later,
26120Sstevel@tonic-gate 	 * instead of sending them with putnext now.  Some time critical
26130Sstevel@tonic-gate 	 * device might need this, so it's here but undocumented.
26140Sstevel@tonic-gate 	 */
26150Sstevel@tonic-gate 	if (macinfo->gldm_options & GLDOPT_FAST_RECV) {
26160Sstevel@tonic-gate 		send = (void (*)(queue_t *, mblk_t *))putq;
26170Sstevel@tonic-gate 		cansend = canput;
26180Sstevel@tonic-gate 	} else {
26190Sstevel@tonic-gate 		send = (void (*)(queue_t *, mblk_t *))putnext;
26200Sstevel@tonic-gate 		cansend = canputnext;
26210Sstevel@tonic-gate 	}
26220Sstevel@tonic-gate 
26230Sstevel@tonic-gate 	/*
26240Sstevel@tonic-gate 	 * Search all the streams attached to this macinfo looking for
26250Sstevel@tonic-gate 	 * those eligible to receive the present packet.
26260Sstevel@tonic-gate 	 */
26270Sstevel@tonic-gate 	for (gld = vlan->gldv_str_next;
26280Sstevel@tonic-gate 	    gld != (gld_t *)&vlan->gldv_str_next; gld = gld->gld_next) {
26290Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
26300Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_sendup: SAP: %4x QPTR: %p QSTATE: %s",
26310Sstevel@tonic-gate 		    gld->gld_sap, (void *)gld->gld_qptr,
26320Sstevel@tonic-gate 		    gld->gld_state == DL_IDLE ? "IDLE": "NOT IDLE");
26330Sstevel@tonic-gate #endif
26340Sstevel@tonic-gate 		ASSERT(gld->gld_qptr != NULL);
26350Sstevel@tonic-gate 		ASSERT(gld->gld_state == DL_IDLE ||
26360Sstevel@tonic-gate 		    gld->gld_state == DL_UNBOUND);
26370Sstevel@tonic-gate 		ASSERT(gld->gld_mac_info == macinfo);
26380Sstevel@tonic-gate 		ASSERT(gld->gld_vlan == vlan);
26390Sstevel@tonic-gate 
26400Sstevel@tonic-gate 		if (gld->gld_state != DL_IDLE)
26410Sstevel@tonic-gate 			continue;	/* not eligible to receive */
26420Sstevel@tonic-gate 		if (gld->gld_flags & GLD_STR_CLOSING)
26430Sstevel@tonic-gate 			continue;	/* not eligible to receive */
26440Sstevel@tonic-gate 
26450Sstevel@tonic-gate #ifdef GLD_DEBUG
26460Sstevel@tonic-gate 		if ((gld_debug & GLDRECV) &&
26470Sstevel@tonic-gate 		    (!(gld_debug & GLDNOBR) ||
26480Sstevel@tonic-gate 		    (!pktinfo->isBroadcast && !pktinfo->isMulticast)))
26490Sstevel@tonic-gate 			cmn_err(CE_NOTE,
26500Sstevel@tonic-gate 			    "gld_sendup: queue sap: %4x promis: %s %s %s",
26510Sstevel@tonic-gate 			    gld->gld_sap,
26520Sstevel@tonic-gate 			    gld->gld_flags & GLD_PROM_PHYS ? "phys " : "     ",
26530Sstevel@tonic-gate 			    gld->gld_flags & GLD_PROM_SAP  ? "sap  " : "     ",
26540Sstevel@tonic-gate 			    gld->gld_flags & GLD_PROM_MULT ? "multi" : "     ");
26550Sstevel@tonic-gate #endif
26560Sstevel@tonic-gate 
26570Sstevel@tonic-gate 		/*
26580Sstevel@tonic-gate 		 * The accept function differs depending on whether this is
26590Sstevel@tonic-gate 		 * a packet that we received from the wire or a loopback.
26600Sstevel@tonic-gate 		 */
26610Sstevel@tonic-gate 		if ((*acceptfunc)(gld, pktinfo)) {
26620Sstevel@tonic-gate 			/* sap matches */
26630Sstevel@tonic-gate 			pktinfo->wasAccepted = 1;	/* known protocol */
26640Sstevel@tonic-gate 
26650Sstevel@tonic-gate 			if (!(*cansend)(gld->gld_qptr)) {
26660Sstevel@tonic-gate 				/*
26670Sstevel@tonic-gate 				 * Upper stream is not accepting messages, i.e.
26680Sstevel@tonic-gate 				 * it is flow controlled, therefore we will
26690Sstevel@tonic-gate 				 * forgo sending the message up this stream.
26700Sstevel@tonic-gate 				 */
26710Sstevel@tonic-gate #ifdef GLD_DEBUG
26720Sstevel@tonic-gate 				if (gld_debug & GLDETRACE)
26730Sstevel@tonic-gate 					cmn_err(CE_WARN,
26740Sstevel@tonic-gate 					    "gld_sendup: canput failed");
26750Sstevel@tonic-gate #endif
26760Sstevel@tonic-gate 				BUMP(vlan->gldv_stats->glds_blocked, 1);
26770Sstevel@tonic-gate 				qenable(gld->gld_qptr);
26780Sstevel@tonic-gate 				continue;
26790Sstevel@tonic-gate 			}
26800Sstevel@tonic-gate 
26810Sstevel@tonic-gate 			/*
26820Sstevel@tonic-gate 			 * we are trying to avoid an extra dumpmsg() here.
26830Sstevel@tonic-gate 			 * If this is the first eligible queue, remember the
26840Sstevel@tonic-gate 			 * queue and send up the message after the loop.
26850Sstevel@tonic-gate 			 */
26860Sstevel@tonic-gate 			if (!fgld) {
26870Sstevel@tonic-gate 				fgld = gld;
26880Sstevel@tonic-gate 				continue;
26890Sstevel@tonic-gate 			}
26900Sstevel@tonic-gate 
26910Sstevel@tonic-gate 			/* duplicate the packet for this stream */
26920Sstevel@tonic-gate 			nmp = dupmsg(mp);
26930Sstevel@tonic-gate 			if (nmp == NULL) {
26940Sstevel@tonic-gate 				BUMP(vlan->gldv_stats->glds_gldnorcvbuf, 1);
26950Sstevel@tonic-gate #ifdef GLD_DEBUG
26960Sstevel@tonic-gate 				if (gld_debug & GLDERRS)
26970Sstevel@tonic-gate 					cmn_err(CE_WARN,
26980Sstevel@tonic-gate 					    "gld_sendup: dupmsg failed");
26990Sstevel@tonic-gate #endif
27000Sstevel@tonic-gate 				break;	/* couldn't get resources; drop it */
27010Sstevel@tonic-gate 			}
27020Sstevel@tonic-gate 			/* pass the message up the stream */
27030Sstevel@tonic-gate 			gld_passon(gld, nmp, pktinfo, send);
27040Sstevel@tonic-gate 		}
27050Sstevel@tonic-gate 	}
27060Sstevel@tonic-gate 
27070Sstevel@tonic-gate 	ASSERT(mp);
27080Sstevel@tonic-gate 	/* send the original dup of the packet up the first stream found */
27090Sstevel@tonic-gate 	if (fgld)
27100Sstevel@tonic-gate 		gld_passon(fgld, mp, pktinfo, send);
27110Sstevel@tonic-gate 	else
27120Sstevel@tonic-gate 		freemsg(mp);	/* no streams matched */
27130Sstevel@tonic-gate 
27140Sstevel@tonic-gate 	/* We do not count looped back packets */
27150Sstevel@tonic-gate 	if (acceptfunc == gld_paccept)
27160Sstevel@tonic-gate 		return;		/* transmit loopback case */
27170Sstevel@tonic-gate 
27180Sstevel@tonic-gate 	if (pktinfo->isBroadcast)
27190Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_brdcstrcv, 1);
27200Sstevel@tonic-gate 	else if (pktinfo->isMulticast)
27210Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_multircv, 1);
27220Sstevel@tonic-gate 
27230Sstevel@tonic-gate 	/* No stream accepted this packet */
27240Sstevel@tonic-gate 	if (!pktinfo->wasAccepted)
27250Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_unknowns, 1);
27260Sstevel@tonic-gate }
27270Sstevel@tonic-gate 
27280Sstevel@tonic-gate /*
27290Sstevel@tonic-gate  * A packet matches a stream if:
27300Sstevel@tonic-gate  *     the stream accepts EtherType encoded packets and the type matches
27310Sstevel@tonic-gate  *  or the stream accepts LLC packets and the packet is an LLC packet
27320Sstevel@tonic-gate  */
27330Sstevel@tonic-gate #define	MATCH(stream, pktinfo) \
27340Sstevel@tonic-gate 	((stream->gld_ethertype && stream->gld_sap == pktinfo->ethertype) || \
27350Sstevel@tonic-gate 	(!stream->gld_ethertype && pktinfo->isLLC))
27360Sstevel@tonic-gate 
27370Sstevel@tonic-gate /*
27380Sstevel@tonic-gate  * This function validates a packet for sending up a particular
27390Sstevel@tonic-gate  * stream. The message header has been parsed and its characteristic
27400Sstevel@tonic-gate  * are recorded in the pktinfo data structure. The streams stack info
27410Sstevel@tonic-gate  * are presented in gld data structures.
27420Sstevel@tonic-gate  */
27430Sstevel@tonic-gate static int
27440Sstevel@tonic-gate gld_accept(gld_t *gld, pktinfo_t *pktinfo)
27450Sstevel@tonic-gate {
27460Sstevel@tonic-gate 	/*
27470Sstevel@tonic-gate 	 * if there is no match do not bother checking further.
27480Sstevel@tonic-gate 	 */
27490Sstevel@tonic-gate 	if (!MATCH(gld, pktinfo) && !(gld->gld_flags & GLD_PROM_SAP))
27500Sstevel@tonic-gate 		return (0);
27510Sstevel@tonic-gate 
27520Sstevel@tonic-gate 	/*
27530Sstevel@tonic-gate 	 * We don't accept any packet from the hardware if we originated it.
27540Sstevel@tonic-gate 	 * (Contrast gld_paccept, the send-loopback accept function.)
27550Sstevel@tonic-gate 	 */
27560Sstevel@tonic-gate 	if (pktinfo->isLooped)
27570Sstevel@tonic-gate 		return (0);
27580Sstevel@tonic-gate 
27590Sstevel@tonic-gate 	/*
27600Sstevel@tonic-gate 	 * If the packet is broadcast or sent to us directly we will accept it.
27610Sstevel@tonic-gate 	 * Also we will accept multicast packets requested by the stream.
27620Sstevel@tonic-gate 	 */
27630Sstevel@tonic-gate 	if (pktinfo->isForMe || pktinfo->isBroadcast ||
27640Sstevel@tonic-gate 	    gld_mcmatch(gld, pktinfo))
27650Sstevel@tonic-gate 		return (1);
27660Sstevel@tonic-gate 
27670Sstevel@tonic-gate 	/*
27680Sstevel@tonic-gate 	 * Finally, accept anything else if we're in promiscuous mode
27690Sstevel@tonic-gate 	 */
27700Sstevel@tonic-gate 	if (gld->gld_flags & GLD_PROM_PHYS)
27710Sstevel@tonic-gate 		return (1);
27720Sstevel@tonic-gate 
27730Sstevel@tonic-gate 	return (0);
27740Sstevel@tonic-gate }
27750Sstevel@tonic-gate 
27760Sstevel@tonic-gate /*
27770Sstevel@tonic-gate  * Return TRUE if the given multicast address is one
27780Sstevel@tonic-gate  * of those that this particular Stream is interested in.
27790Sstevel@tonic-gate  */
27800Sstevel@tonic-gate static int
27810Sstevel@tonic-gate gld_mcmatch(gld_t *gld, pktinfo_t *pktinfo)
27820Sstevel@tonic-gate {
27830Sstevel@tonic-gate 	/*
27840Sstevel@tonic-gate 	 * Return FALSE if not a multicast address.
27850Sstevel@tonic-gate 	 */
27860Sstevel@tonic-gate 	if (!pktinfo->isMulticast)
27870Sstevel@tonic-gate 		return (0);
27880Sstevel@tonic-gate 
27890Sstevel@tonic-gate 	/*
27900Sstevel@tonic-gate 	 * Check if all multicasts have been enabled for this Stream
27910Sstevel@tonic-gate 	 */
27920Sstevel@tonic-gate 	if (gld->gld_flags & GLD_PROM_MULT)
27930Sstevel@tonic-gate 		return (1);
27940Sstevel@tonic-gate 
27950Sstevel@tonic-gate 	/*
27960Sstevel@tonic-gate 	 * Return FALSE if no multicast addresses enabled for this Stream.
27970Sstevel@tonic-gate 	 */
27980Sstevel@tonic-gate 	if (!gld->gld_mcast)
27990Sstevel@tonic-gate 		return (0);
28000Sstevel@tonic-gate 
28010Sstevel@tonic-gate 	/*
28020Sstevel@tonic-gate 	 * Otherwise, look for it in the table.
28030Sstevel@tonic-gate 	 */
28040Sstevel@tonic-gate 	return (gld_multicast(pktinfo->dhost, gld));
28050Sstevel@tonic-gate }
28060Sstevel@tonic-gate 
28070Sstevel@tonic-gate /*
28080Sstevel@tonic-gate  * gld_multicast determines if the address is a multicast address for
28090Sstevel@tonic-gate  * this stream.
28100Sstevel@tonic-gate  */
28110Sstevel@tonic-gate static int
28120Sstevel@tonic-gate gld_multicast(unsigned char *macaddr, gld_t *gld)
28130Sstevel@tonic-gate {
28140Sstevel@tonic-gate 	int i;
28150Sstevel@tonic-gate 
28160Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(gld->gld_mac_info));
28170Sstevel@tonic-gate 
28180Sstevel@tonic-gate 	if (!gld->gld_mcast)
28190Sstevel@tonic-gate 		return (0);
28200Sstevel@tonic-gate 
28210Sstevel@tonic-gate 	for (i = 0; i < gld->gld_multicnt; i++) {
28220Sstevel@tonic-gate 		if (gld->gld_mcast[i]) {
28230Sstevel@tonic-gate 			ASSERT(gld->gld_mcast[i]->gldm_refcnt);
28240Sstevel@tonic-gate 			if (mac_eq(gld->gld_mcast[i]->gldm_addr, macaddr,
28250Sstevel@tonic-gate 			    gld->gld_mac_info->gldm_addrlen))
28260Sstevel@tonic-gate 				return (1);
28270Sstevel@tonic-gate 		}
28280Sstevel@tonic-gate 	}
28290Sstevel@tonic-gate 
28300Sstevel@tonic-gate 	return (0);
28310Sstevel@tonic-gate }
28320Sstevel@tonic-gate 
28330Sstevel@tonic-gate /*
28340Sstevel@tonic-gate  * accept function for looped back packets
28350Sstevel@tonic-gate  */
28360Sstevel@tonic-gate static int
28370Sstevel@tonic-gate gld_paccept(gld_t *gld, pktinfo_t *pktinfo)
28380Sstevel@tonic-gate {
28390Sstevel@tonic-gate 	return (gld->gld_flags & GLD_PROM_PHYS &&
28400Sstevel@tonic-gate 	    (MATCH(gld, pktinfo) || gld->gld_flags & GLD_PROM_SAP));
28410Sstevel@tonic-gate }
28420Sstevel@tonic-gate 
28430Sstevel@tonic-gate static void
28440Sstevel@tonic-gate gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo,
28450Sstevel@tonic-gate 	void (*send)(queue_t *qp, mblk_t *mp))
28460Sstevel@tonic-gate {
28470Sstevel@tonic-gate 	int skiplen;
28480Sstevel@tonic-gate 
28490Sstevel@tonic-gate #ifdef GLD_DEBUG
28500Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
28510Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_passon(%p, %p, %p)", (void *)gld,
28520Sstevel@tonic-gate 		    (void *)mp, (void *)pktinfo);
28530Sstevel@tonic-gate 
28540Sstevel@tonic-gate 	if ((gld_debug & GLDRECV) && (!(gld_debug & GLDNOBR) ||
28550Sstevel@tonic-gate 	    (!pktinfo->isBroadcast && !pktinfo->isMulticast)))
28560Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_passon: q: %p mblk: %p minor: %d sap: %x",
28570Sstevel@tonic-gate 		    (void *)gld->gld_qptr->q_next, (void *)mp, gld->gld_minor,
28580Sstevel@tonic-gate 		    gld->gld_sap);
28590Sstevel@tonic-gate #endif
28600Sstevel@tonic-gate 
28610Sstevel@tonic-gate 	/*
28620Sstevel@tonic-gate 	 * Figure out how much of the packet header to throw away.
28630Sstevel@tonic-gate 	 *
28640Sstevel@tonic-gate 	 * RAW streams expect to see the whole packet.
28650Sstevel@tonic-gate 	 *
28660Sstevel@tonic-gate 	 * Other streams expect to see the packet with the MAC header
28670Sstevel@tonic-gate 	 * removed.
28680Sstevel@tonic-gate 	 *
28690Sstevel@tonic-gate 	 * Normal DLPI (non RAW/FAST) streams also want the
28700Sstevel@tonic-gate 	 * DL_UNITDATA_IND M_PROTO message block prepended to the M_DATA.
28710Sstevel@tonic-gate 	 */
28720Sstevel@tonic-gate 	if (gld->gld_flags & GLD_RAW) {
28730Sstevel@tonic-gate 		skiplen = 0;
28740Sstevel@tonic-gate 	} else {
28750Sstevel@tonic-gate 		skiplen = pktinfo->macLen;		/* skip mac header */
28760Sstevel@tonic-gate 		if (gld->gld_ethertype)
28770Sstevel@tonic-gate 			skiplen += pktinfo->hdrLen;	/* skip any extra */
28780Sstevel@tonic-gate 	}
28790Sstevel@tonic-gate 
28800Sstevel@tonic-gate 	if (skiplen >= pktinfo->pktLen) {
28810Sstevel@tonic-gate 		/*
28820Sstevel@tonic-gate 		 * If the interpreter did its job right, then it cannot be
28830Sstevel@tonic-gate 		 * asking us to skip more bytes than are in the packet!
28840Sstevel@tonic-gate 		 * However, there could be zero data bytes left after the
28850Sstevel@tonic-gate 		 * amount to skip.  DLPI specifies that passed M_DATA blocks
28860Sstevel@tonic-gate 		 * should contain at least one byte of data, so if we have
28870Sstevel@tonic-gate 		 * none we just drop it.
28880Sstevel@tonic-gate 		 */
28890Sstevel@tonic-gate 		ASSERT(!(skiplen > pktinfo->pktLen));
28900Sstevel@tonic-gate 		freemsg(mp);
28910Sstevel@tonic-gate 		return;
28920Sstevel@tonic-gate 	}
28930Sstevel@tonic-gate 
28940Sstevel@tonic-gate 	/*
28950Sstevel@tonic-gate 	 * Skip over the header(s), taking care to possibly handle message
28960Sstevel@tonic-gate 	 * fragments shorter than the amount we need to skip.  Hopefully
28970Sstevel@tonic-gate 	 * the driver will put the entire packet, or at least the entire
28980Sstevel@tonic-gate 	 * header, into a single message block.  But we handle it if not.
28990Sstevel@tonic-gate 	 */
29000Sstevel@tonic-gate 	while (skiplen >= MBLKL(mp)) {
29010Sstevel@tonic-gate 		mblk_t *tmp = mp;
29020Sstevel@tonic-gate 		skiplen -= MBLKL(mp);
29030Sstevel@tonic-gate 		mp = mp->b_cont;
29040Sstevel@tonic-gate 		ASSERT(mp != NULL);	/* because skiplen < pktinfo->pktLen */
29050Sstevel@tonic-gate 		freeb(tmp);
29060Sstevel@tonic-gate 	}
29070Sstevel@tonic-gate 	mp->b_rptr += skiplen;
29080Sstevel@tonic-gate 
29090Sstevel@tonic-gate 	/* Add M_PROTO if necessary, and pass upstream */
29100Sstevel@tonic-gate 	if (((gld->gld_flags & GLD_FAST) && !pktinfo->isMulticast &&
29110Sstevel@tonic-gate 	    !pktinfo->isBroadcast) || (gld->gld_flags & GLD_RAW)) {
29120Sstevel@tonic-gate 		/* RAW/FAST: just send up the M_DATA */
29130Sstevel@tonic-gate 		(*send)(gld->gld_qptr, mp);
29140Sstevel@tonic-gate 	} else {
29150Sstevel@tonic-gate 		/* everybody else wants to see a unitdata_ind structure */
29160Sstevel@tonic-gate 		mp = gld_addudind(gld, mp, pktinfo);
29170Sstevel@tonic-gate 		if (mp)
29180Sstevel@tonic-gate 			(*send)(gld->gld_qptr, mp);
29190Sstevel@tonic-gate 		/* if it failed, gld_addudind already bumped statistic */
29200Sstevel@tonic-gate 	}
29210Sstevel@tonic-gate }
29220Sstevel@tonic-gate 
29230Sstevel@tonic-gate /*
29240Sstevel@tonic-gate  * gld_addudind(gld, mp, pktinfo)
29250Sstevel@tonic-gate  * format a DL_UNITDATA_IND message to be sent upstream to the user
29260Sstevel@tonic-gate  */
29270Sstevel@tonic-gate static mblk_t *
29280Sstevel@tonic-gate gld_addudind(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo)
29290Sstevel@tonic-gate {
29300Sstevel@tonic-gate 	gld_mac_info_t		*macinfo = gld->gld_mac_info;
29310Sstevel@tonic-gate 	gld_vlan_t		*vlan = (gld_vlan_t *)gld->gld_vlan;
29320Sstevel@tonic-gate 	dl_unitdata_ind_t	*dludindp;
29330Sstevel@tonic-gate 	mblk_t			*nmp;
29340Sstevel@tonic-gate 	int			size;
29350Sstevel@tonic-gate 	int			type;
29360Sstevel@tonic-gate 
29370Sstevel@tonic-gate #ifdef GLD_DEBUG
29380Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
29390Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_addudind(%p, %p, %p)", (void *)gld,
29400Sstevel@tonic-gate 		    (void *)mp, (void *)pktinfo);
29410Sstevel@tonic-gate #endif
29420Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
29430Sstevel@tonic-gate 
29440Sstevel@tonic-gate 	/*
29450Sstevel@tonic-gate 	 * Allocate the DL_UNITDATA_IND M_PROTO header, if allocation fails
29460Sstevel@tonic-gate 	 * might as well discard since we can't go further
29470Sstevel@tonic-gate 	 */
29480Sstevel@tonic-gate 	size = sizeof (dl_unitdata_ind_t) +
29490Sstevel@tonic-gate 	    2 * (macinfo->gldm_addrlen + abs(macinfo->gldm_saplen));
29500Sstevel@tonic-gate 	if ((nmp = allocb(size, BPRI_MED)) == NULL) {
29510Sstevel@tonic-gate 		freemsg(mp);
29520Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_gldnorcvbuf, 1);
29530Sstevel@tonic-gate #ifdef GLD_DEBUG
29540Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
29550Sstevel@tonic-gate 			cmn_err(CE_WARN,
29560Sstevel@tonic-gate 			    "gld_addudind: allocb failed");
29570Sstevel@tonic-gate #endif
29580Sstevel@tonic-gate 		return ((mblk_t *)NULL);
29590Sstevel@tonic-gate 	}
29600Sstevel@tonic-gate 	DB_TYPE(nmp) = M_PROTO;
29610Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_datap->db_lim - size;
29620Sstevel@tonic-gate 
29630Sstevel@tonic-gate 	type = (gld->gld_ethertype) ? pktinfo->ethertype : 0;
29640Sstevel@tonic-gate 
29650Sstevel@tonic-gate 	/*
29660Sstevel@tonic-gate 	 * now setup the DL_UNITDATA_IND header
29670Sstevel@tonic-gate 	 *
29680Sstevel@tonic-gate 	 * XXX This looks broken if the saps aren't two bytes.
29690Sstevel@tonic-gate 	 */
29700Sstevel@tonic-gate 	dludindp = (dl_unitdata_ind_t *)nmp->b_rptr;
29710Sstevel@tonic-gate 	dludindp->dl_primitive = DL_UNITDATA_IND;
29720Sstevel@tonic-gate 	dludindp->dl_src_addr_length =
29730Sstevel@tonic-gate 	    dludindp->dl_dest_addr_length = macinfo->gldm_addrlen +
29740Sstevel@tonic-gate 					abs(macinfo->gldm_saplen);
29750Sstevel@tonic-gate 	dludindp->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
29760Sstevel@tonic-gate 	dludindp->dl_src_addr_offset = dludindp->dl_dest_addr_offset +
29770Sstevel@tonic-gate 					dludindp->dl_dest_addr_length;
29780Sstevel@tonic-gate 
29790Sstevel@tonic-gate 	dludindp->dl_group_address = (pktinfo->isMulticast ||
29800Sstevel@tonic-gate 					pktinfo->isBroadcast);
29810Sstevel@tonic-gate 
29820Sstevel@tonic-gate 	nmp->b_wptr = nmp->b_rptr + dludindp->dl_dest_addr_offset;
29830Sstevel@tonic-gate 
29840Sstevel@tonic-gate 	mac_copy(pktinfo->dhost, nmp->b_wptr, macinfo->gldm_addrlen);
29850Sstevel@tonic-gate 	nmp->b_wptr += macinfo->gldm_addrlen;
29860Sstevel@tonic-gate 
29870Sstevel@tonic-gate 	ASSERT(macinfo->gldm_saplen == -2);	/* XXX following code assumes */
29880Sstevel@tonic-gate 	*(ushort_t *)(nmp->b_wptr) = type;
29890Sstevel@tonic-gate 	nmp->b_wptr += abs(macinfo->gldm_saplen);
29900Sstevel@tonic-gate 
29910Sstevel@tonic-gate 	ASSERT(nmp->b_wptr == nmp->b_rptr + dludindp->dl_src_addr_offset);
29920Sstevel@tonic-gate 
29930Sstevel@tonic-gate 	mac_copy(pktinfo->shost, nmp->b_wptr, macinfo->gldm_addrlen);
29940Sstevel@tonic-gate 	nmp->b_wptr += macinfo->gldm_addrlen;
29950Sstevel@tonic-gate 
29960Sstevel@tonic-gate 	*(ushort_t *)(nmp->b_wptr) = type;
29970Sstevel@tonic-gate 	nmp->b_wptr += abs(macinfo->gldm_saplen);
29980Sstevel@tonic-gate 
29990Sstevel@tonic-gate 	if (pktinfo->nosource)
30000Sstevel@tonic-gate 		dludindp->dl_src_addr_offset = dludindp->dl_src_addr_length = 0;
30010Sstevel@tonic-gate 	linkb(nmp, mp);
30020Sstevel@tonic-gate 	return (nmp);
30030Sstevel@tonic-gate }
30040Sstevel@tonic-gate 
30050Sstevel@tonic-gate /* ======================================================= */
30060Sstevel@tonic-gate /* wsrv group: called from wsrv, single threaded per queue */
30070Sstevel@tonic-gate /* ======================================================= */
30080Sstevel@tonic-gate 
30090Sstevel@tonic-gate /*
30100Sstevel@tonic-gate  * We go to some trouble to avoid taking the same lock during normal
30110Sstevel@tonic-gate  * transmit processing as we do during normal receive processing.
30120Sstevel@tonic-gate  *
30130Sstevel@tonic-gate  * Elements of the per-instance macinfo and per-stream gld_t structures
30140Sstevel@tonic-gate  * are for the most part protected by the GLDM_LOCK rwlock/mutex.
30150Sstevel@tonic-gate  * (Elements of the gld_mac_pvt_t structure are considered part of the
30160Sstevel@tonic-gate  * macinfo structure for purposes of this discussion).
30170Sstevel@tonic-gate  *
30180Sstevel@tonic-gate  * However, it is more complicated than that:
30190Sstevel@tonic-gate  *
30200Sstevel@tonic-gate  *	Elements of the macinfo structure that are set before the macinfo
30210Sstevel@tonic-gate  *	structure is added to its device list by gld_register(), and never
30220Sstevel@tonic-gate  *	thereafter modified, are accessed without requiring taking the lock.
30230Sstevel@tonic-gate  *	A similar rule applies to those elements of the gld_t structure that
30240Sstevel@tonic-gate  *	are written by gld_open() before the stream is added to any list.
30250Sstevel@tonic-gate  *
30260Sstevel@tonic-gate  *	Most other elements of the macinfo structure may only be read or
30270Sstevel@tonic-gate  *	written while holding the maclock.
30280Sstevel@tonic-gate  *
30290Sstevel@tonic-gate  *	Most writable elements of the gld_t structure are written only
30300Sstevel@tonic-gate  *	within the single-threaded domain of wsrv() and subsidiaries.
30310Sstevel@tonic-gate  *	(This domain includes open/close while qprocs are not on.)
30320Sstevel@tonic-gate  *	The maclock need not be taken while within that domain
30330Sstevel@tonic-gate  *	simply to read those elements.  Writing to them, even within
30340Sstevel@tonic-gate  *	that domain, or reading from it outside that domain, requires
30350Sstevel@tonic-gate  *	holding the maclock.  Exception:  if the stream is not
30360Sstevel@tonic-gate  *	presently attached to a PPA, there is no associated macinfo,
30370Sstevel@tonic-gate  *	and no maclock need be taken.
30380Sstevel@tonic-gate  *
30390Sstevel@tonic-gate  *	The curr_macaddr element of the mac private structure is also
30400Sstevel@tonic-gate  *      protected by the GLDM_LOCK rwlock/mutex, like most other members
30410Sstevel@tonic-gate  *      of that structure. However, there are a few instances in the
30420Sstevel@tonic-gate  *      transmit path where we choose to forgo lock protection when
30430Sstevel@tonic-gate  *      reading this variable. This is to avoid lock contention between
30440Sstevel@tonic-gate  *      threads executing the DL_UNITDATA_REQ case and receive threads.
30450Sstevel@tonic-gate  *      In doing so we will take a small risk or a few corrupted packets
30460Sstevel@tonic-gate  *      during the short an rare times when someone is changing the interface's
30470Sstevel@tonic-gate  *      physical address. We consider the small cost in this rare case to be
30480Sstevel@tonic-gate  *      worth the benefit of reduced lock contention under normal operating
30490Sstevel@tonic-gate  *      conditions. The risk/cost is small because:
30500Sstevel@tonic-gate  *          1. there is no guarantee at this layer of uncorrupted delivery.
30510Sstevel@tonic-gate  *          2. the physaddr doesn't change very often - no performance hit.
30520Sstevel@tonic-gate  *          3. if the physaddr changes, other stuff is going to be screwed
30530Sstevel@tonic-gate  *             up for a while anyway, while other sites refigure ARP, etc.,
30540Sstevel@tonic-gate  *             so losing a couple of packets is the least of our worries.
30550Sstevel@tonic-gate  *
30560Sstevel@tonic-gate  *	The list of streams associated with a macinfo is protected by
30570Sstevel@tonic-gate  *	two locks:  the per-macinfo maclock, and the per-major-device
30580Sstevel@tonic-gate  *	gld_devlock.  Both must be held to modify the list, but either
30590Sstevel@tonic-gate  *	may be held to protect the list during reading/traversing.  This
30600Sstevel@tonic-gate  *	allows independent locking for multiple instances in the receive
30610Sstevel@tonic-gate  *	path (using macinfo), while facilitating routines that must search
30620Sstevel@tonic-gate  *	the entire set of streams associated with a major device, such as
30630Sstevel@tonic-gate  *	gld_findminor(), gld_finddevinfo(), close().  The "nstreams"
30640Sstevel@tonic-gate  *	macinfo	element, and the gld_mac_info gld_t element, are similarly
30650Sstevel@tonic-gate  *	protected, since they change at exactly the same time macinfo
30660Sstevel@tonic-gate  *	streams list does.
30670Sstevel@tonic-gate  *
30680Sstevel@tonic-gate  *	The list of macinfo structures associated with a major device
30690Sstevel@tonic-gate  *	structure is protected by the gld_devlock, as is the per-major
30700Sstevel@tonic-gate  *	list of Style 2 streams in the DL_UNATTACHED state.
30710Sstevel@tonic-gate  *
30720Sstevel@tonic-gate  *	The list of major devices is kept on a module-global list
30730Sstevel@tonic-gate  *	gld_device_list, which has its own lock to protect the list.
30740Sstevel@tonic-gate  *
30750Sstevel@tonic-gate  *	When it is necessary to hold more than one lock at a time, they
30760Sstevel@tonic-gate  *	are acquired in this "outside in" order:
30770Sstevel@tonic-gate  *		gld_device_list.gld_devlock
30780Sstevel@tonic-gate  *		glddev->gld_devlock
30790Sstevel@tonic-gate  *		GLDM_LOCK(macinfo)
30800Sstevel@tonic-gate  *
30810Sstevel@tonic-gate  *	Finally, there are some "volatile" elements of the gld_t structure
30820Sstevel@tonic-gate  *	used for synchronization between various routines that don't share
30830Sstevel@tonic-gate  *	the same mutexes.  See the routines for details.  These are:
30840Sstevel@tonic-gate  *		gld_xwait	between gld_wsrv() and gld_sched()
30850Sstevel@tonic-gate  *		gld_sched_ran	between gld_wsrv() and gld_sched()
30860Sstevel@tonic-gate  *		gld_in_unbind	between gld_wput() and wsrv's gld_unbind()
30870Sstevel@tonic-gate  *		gld_wput_count	between gld_wput() and wsrv's gld_unbind()
30880Sstevel@tonic-gate  *		gld_in_wsrv	between gld_wput() and gld_wsrv()
30890Sstevel@tonic-gate  *				(used in conjunction with q->q_first)
30900Sstevel@tonic-gate  */
30910Sstevel@tonic-gate 
30920Sstevel@tonic-gate /*
30930Sstevel@tonic-gate  * gld_ioctl (q, mp)
30940Sstevel@tonic-gate  * handles all ioctl requests passed downstream. This routine is
30950Sstevel@tonic-gate  * passed a pointer to the message block with the ioctl request in it, and a
30960Sstevel@tonic-gate  * pointer to the queue so it can respond to the ioctl request with an ack.
30970Sstevel@tonic-gate  */
30980Sstevel@tonic-gate int
30990Sstevel@tonic-gate gld_ioctl(queue_t *q, mblk_t *mp)
31000Sstevel@tonic-gate {
31010Sstevel@tonic-gate 	struct iocblk *iocp;
31020Sstevel@tonic-gate 	gld_t *gld;
31030Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
31040Sstevel@tonic-gate 
31050Sstevel@tonic-gate #ifdef GLD_DEBUG
31060Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
31070Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_ioctl(%p %p)", (void *)q, (void *)mp);
31080Sstevel@tonic-gate #endif
31090Sstevel@tonic-gate 	gld = (gld_t *)q->q_ptr;
31100Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
31110Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
31120Sstevel@tonic-gate 	case DLIOCRAW:		/* raw M_DATA mode */
31130Sstevel@tonic-gate 		gld->gld_flags |= GLD_RAW;
31140Sstevel@tonic-gate 		DB_TYPE(mp) = M_IOCACK;
31150Sstevel@tonic-gate 		qreply(q, mp);
31160Sstevel@tonic-gate 		break;
31170Sstevel@tonic-gate 
31180Sstevel@tonic-gate 	case DL_IOC_HDR_INFO:	/* fastpath */
31190Sstevel@tonic-gate 		if (gld_global_options & GLD_OPT_NO_FASTPATH) {
31200Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
31210Sstevel@tonic-gate 			break;
31220Sstevel@tonic-gate 		}
31230Sstevel@tonic-gate 		gld_fastpath(gld, q, mp);
31240Sstevel@tonic-gate 		break;
31250Sstevel@tonic-gate 
31260Sstevel@tonic-gate 	default:
31270Sstevel@tonic-gate 		macinfo	 = gld->gld_mac_info;
31280Sstevel@tonic-gate 		if (macinfo == NULL || macinfo->gldm_ioctl == NULL) {
31290Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
31300Sstevel@tonic-gate 			break;
31310Sstevel@tonic-gate 		}
31320Sstevel@tonic-gate 
31330Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
31340Sstevel@tonic-gate 		(void) (*macinfo->gldm_ioctl) (macinfo, q, mp);
31350Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
31360Sstevel@tonic-gate 		break;
31370Sstevel@tonic-gate 	}
31380Sstevel@tonic-gate 	return (0);
31390Sstevel@tonic-gate }
31400Sstevel@tonic-gate 
31410Sstevel@tonic-gate /*
31420Sstevel@tonic-gate  * Since the rules for "fastpath" mode don't seem to be documented
31430Sstevel@tonic-gate  * anywhere, I will describe GLD's rules for fastpath users here:
31440Sstevel@tonic-gate  *
31450Sstevel@tonic-gate  * Once in this mode you remain there until close.
31460Sstevel@tonic-gate  * If you unbind/rebind you should get a new header using DL_IOC_HDR_INFO.
31470Sstevel@tonic-gate  * You must be bound (DL_IDLE) to transmit.
31480Sstevel@tonic-gate  * There are other rules not listed above.
31490Sstevel@tonic-gate  */
31500Sstevel@tonic-gate static void
31510Sstevel@tonic-gate gld_fastpath(gld_t *gld, queue_t *q, mblk_t *mp)
31520Sstevel@tonic-gate {
31530Sstevel@tonic-gate 	gld_interface_t *ifp;
31540Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
31550Sstevel@tonic-gate 	dl_unitdata_req_t *dludp;
31560Sstevel@tonic-gate 	mblk_t *nmp;
31570Sstevel@tonic-gate 	t_scalar_t off, len;
31580Sstevel@tonic-gate 	uint_t maclen;
31590Sstevel@tonic-gate 	int error;
31600Sstevel@tonic-gate 	gld_vlan_t *vlan;
31610Sstevel@tonic-gate 
31620Sstevel@tonic-gate 	if (gld->gld_state != DL_IDLE) {
31630Sstevel@tonic-gate 		miocnak(q, mp, 0, EINVAL);
31640Sstevel@tonic-gate 		return;
31650Sstevel@tonic-gate 	}
31660Sstevel@tonic-gate 
31670Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
31680Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
31690Sstevel@tonic-gate 	maclen = macinfo->gldm_addrlen + abs(macinfo->gldm_saplen);
31700Sstevel@tonic-gate 
31710Sstevel@tonic-gate 	error = miocpullup(mp, sizeof (dl_unitdata_req_t) + maclen);
31720Sstevel@tonic-gate 	if (error != 0) {
31730Sstevel@tonic-gate 		miocnak(q, mp, 0, error);
31740Sstevel@tonic-gate 		return;
31750Sstevel@tonic-gate 	}
31760Sstevel@tonic-gate 
31770Sstevel@tonic-gate 	dludp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
31780Sstevel@tonic-gate 	off = dludp->dl_dest_addr_offset;
31790Sstevel@tonic-gate 	len = dludp->dl_dest_addr_length;
31800Sstevel@tonic-gate 	if (dludp->dl_primitive != DL_UNITDATA_REQ ||
31810Sstevel@tonic-gate 	    !MBLKIN(mp->b_cont, off, len) || len != maclen) {
31820Sstevel@tonic-gate 		miocnak(q, mp, 0, EINVAL);
31830Sstevel@tonic-gate 		return;
31840Sstevel@tonic-gate 	}
31850Sstevel@tonic-gate 
31860Sstevel@tonic-gate 	/*
31870Sstevel@tonic-gate 	 * We take his fastpath request as a declaration that he will accept
31880Sstevel@tonic-gate 	 * M_DATA messages from us, whether or not we are willing to accept
31890Sstevel@tonic-gate 	 * them from him.  This allows us to have fastpath in one direction
31900Sstevel@tonic-gate 	 * (flow upstream) even on media with Source Routing, where we are
31910Sstevel@tonic-gate 	 * unable to provide a fixed MAC header to be prepended to downstream
31920Sstevel@tonic-gate 	 * flowing packets.  So we set GLD_FAST whether or not we decide to
31930Sstevel@tonic-gate 	 * allow him to send M_DATA down to us.
31940Sstevel@tonic-gate 	 */
31950Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
31960Sstevel@tonic-gate 	gld->gld_flags |= GLD_FAST;
31970Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
31980Sstevel@tonic-gate 	vlan->gldv_ipq_flags &= ~IPQ_DISABLED;
31990Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
32000Sstevel@tonic-gate 
32010Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
32020Sstevel@tonic-gate 
32030Sstevel@tonic-gate 	/* This will fail for Source Routing media */
32040Sstevel@tonic-gate 	/* Also on Ethernet on 802.2 SAPs */
32050Sstevel@tonic-gate 	if ((nmp = (*ifp->mkfastpath)(gld, mp)) == NULL) {
32060Sstevel@tonic-gate 		miocnak(q, mp, 0, ENOMEM);
32070Sstevel@tonic-gate 		return;
32080Sstevel@tonic-gate 	}
32090Sstevel@tonic-gate 
32100Sstevel@tonic-gate 	/*
32110Sstevel@tonic-gate 	 * Link new mblk in after the "request" mblks.
32120Sstevel@tonic-gate 	 */
32130Sstevel@tonic-gate 	linkb(mp, nmp);
32140Sstevel@tonic-gate 	miocack(q, mp, msgdsize(mp->b_cont), 0);
32150Sstevel@tonic-gate }
32160Sstevel@tonic-gate 
32170Sstevel@tonic-gate /*
32180Sstevel@tonic-gate  * gld_cmds (q, mp)
32190Sstevel@tonic-gate  *	process the DL commands as defined in dlpi.h
32200Sstevel@tonic-gate  *	note that the primitives return status which is passed back
32210Sstevel@tonic-gate  *	to the service procedure.  If the value is GLDE_RETRY, then
32220Sstevel@tonic-gate  *	it is assumed that processing must stop and the primitive has
32230Sstevel@tonic-gate  *	been put back onto the queue.  If the value is any other error,
32240Sstevel@tonic-gate  *	then an error ack is generated by the service procedure.
32250Sstevel@tonic-gate  */
32260Sstevel@tonic-gate static int
32270Sstevel@tonic-gate gld_cmds(queue_t *q, mblk_t *mp)
32280Sstevel@tonic-gate {
32290Sstevel@tonic-gate 	union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr;
32300Sstevel@tonic-gate 	gld_t *gld = (gld_t *)(q->q_ptr);
32310Sstevel@tonic-gate 	int result = DL_BADPRIM;
32320Sstevel@tonic-gate 	int mblkl = MBLKL(mp);
32330Sstevel@tonic-gate 	t_uscalar_t dlreq;
32340Sstevel@tonic-gate 
32350Sstevel@tonic-gate 	/* Make sure we have at least dlp->dl_primitive */
32360Sstevel@tonic-gate 	if (mblkl < sizeof (dlp->dl_primitive))
32370Sstevel@tonic-gate 		return (DL_BADPRIM);
32380Sstevel@tonic-gate 
32390Sstevel@tonic-gate 	dlreq = dlp->dl_primitive;
32400Sstevel@tonic-gate #ifdef	GLD_DEBUG
32410Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
32420Sstevel@tonic-gate 		cmn_err(CE_NOTE,
32430Sstevel@tonic-gate 		    "gld_cmds(%p, %p):dlp=%p, dlp->dl_primitive=%d",
32440Sstevel@tonic-gate 		    (void *)q, (void *)mp, (void *)dlp, dlreq);
32450Sstevel@tonic-gate #endif
32460Sstevel@tonic-gate 
32470Sstevel@tonic-gate 	switch (dlreq) {
32480Sstevel@tonic-gate 	case DL_UDQOS_REQ:
32490Sstevel@tonic-gate 		if (mblkl < DL_UDQOS_REQ_SIZE)
32500Sstevel@tonic-gate 			break;
32510Sstevel@tonic-gate 		result = gld_udqos(q, mp);
32520Sstevel@tonic-gate 		break;
32530Sstevel@tonic-gate 
32540Sstevel@tonic-gate 	case DL_BIND_REQ:
32550Sstevel@tonic-gate 		if (mblkl < DL_BIND_REQ_SIZE)
32560Sstevel@tonic-gate 			break;
32570Sstevel@tonic-gate 		result = gld_bind(q, mp);
32580Sstevel@tonic-gate 		break;
32590Sstevel@tonic-gate 
32600Sstevel@tonic-gate 	case DL_UNBIND_REQ:
32610Sstevel@tonic-gate 		if (mblkl < DL_UNBIND_REQ_SIZE)
32620Sstevel@tonic-gate 			break;
32630Sstevel@tonic-gate 		result = gld_unbind(q, mp);
32640Sstevel@tonic-gate 		break;
32650Sstevel@tonic-gate 
32660Sstevel@tonic-gate 	case DL_UNITDATA_REQ:
32670Sstevel@tonic-gate 		if (mblkl < DL_UNITDATA_REQ_SIZE)
32680Sstevel@tonic-gate 			break;
32690Sstevel@tonic-gate 		result = gld_unitdata(q, mp);
32700Sstevel@tonic-gate 		break;
32710Sstevel@tonic-gate 
32720Sstevel@tonic-gate 	case DL_INFO_REQ:
32730Sstevel@tonic-gate 		if (mblkl < DL_INFO_REQ_SIZE)
32740Sstevel@tonic-gate 			break;
32750Sstevel@tonic-gate 		result = gld_inforeq(q, mp);
32760Sstevel@tonic-gate 		break;
32770Sstevel@tonic-gate 
32780Sstevel@tonic-gate 	case DL_ATTACH_REQ:
32790Sstevel@tonic-gate 		if (mblkl < DL_ATTACH_REQ_SIZE)
32800Sstevel@tonic-gate 			break;
32810Sstevel@tonic-gate 		if (gld->gld_style == DL_STYLE2)
32820Sstevel@tonic-gate 			result = gldattach(q, mp);
32830Sstevel@tonic-gate 		else
32840Sstevel@tonic-gate 			result = DL_NOTSUPPORTED;
32850Sstevel@tonic-gate 		break;
32860Sstevel@tonic-gate 
32870Sstevel@tonic-gate 	case DL_DETACH_REQ:
32880Sstevel@tonic-gate 		if (mblkl < DL_DETACH_REQ_SIZE)
32890Sstevel@tonic-gate 			break;
32900Sstevel@tonic-gate 		if (gld->gld_style == DL_STYLE2)
32910Sstevel@tonic-gate 			result = gldunattach(q, mp);
32920Sstevel@tonic-gate 		else
32930Sstevel@tonic-gate 			result = DL_NOTSUPPORTED;
32940Sstevel@tonic-gate 		break;
32950Sstevel@tonic-gate 
32960Sstevel@tonic-gate 	case DL_ENABMULTI_REQ:
32970Sstevel@tonic-gate 		if (mblkl < DL_ENABMULTI_REQ_SIZE)
32980Sstevel@tonic-gate 			break;
32990Sstevel@tonic-gate 		result = gld_enable_multi(q, mp);
33000Sstevel@tonic-gate 		break;
33010Sstevel@tonic-gate 
33020Sstevel@tonic-gate 	case DL_DISABMULTI_REQ:
33030Sstevel@tonic-gate 		if (mblkl < DL_DISABMULTI_REQ_SIZE)
33040Sstevel@tonic-gate 			break;
33050Sstevel@tonic-gate 		result = gld_disable_multi(q, mp);
33060Sstevel@tonic-gate 		break;
33070Sstevel@tonic-gate 
33080Sstevel@tonic-gate 	case DL_PHYS_ADDR_REQ:
33090Sstevel@tonic-gate 		if (mblkl < DL_PHYS_ADDR_REQ_SIZE)
33100Sstevel@tonic-gate 			break;
33110Sstevel@tonic-gate 		result = gld_physaddr(q, mp);
33120Sstevel@tonic-gate 		break;
33130Sstevel@tonic-gate 
33140Sstevel@tonic-gate 	case DL_SET_PHYS_ADDR_REQ:
33150Sstevel@tonic-gate 		if (mblkl < DL_SET_PHYS_ADDR_REQ_SIZE)
33160Sstevel@tonic-gate 			break;
33170Sstevel@tonic-gate 		result = gld_setaddr(q, mp);
33180Sstevel@tonic-gate 		break;
33190Sstevel@tonic-gate 
33200Sstevel@tonic-gate 	case DL_PROMISCON_REQ:
33210Sstevel@tonic-gate 		if (mblkl < DL_PROMISCON_REQ_SIZE)
33220Sstevel@tonic-gate 			break;
33230Sstevel@tonic-gate 		result = gld_promisc(q, mp, dlreq, B_TRUE);
33240Sstevel@tonic-gate 		break;
33250Sstevel@tonic-gate 
33260Sstevel@tonic-gate 	case DL_PROMISCOFF_REQ:
33270Sstevel@tonic-gate 		if (mblkl < DL_PROMISCOFF_REQ_SIZE)
33280Sstevel@tonic-gate 			break;
33290Sstevel@tonic-gate 		result = gld_promisc(q, mp, dlreq, B_FALSE);
33300Sstevel@tonic-gate 		break;
33310Sstevel@tonic-gate 
33320Sstevel@tonic-gate 	case DL_GET_STATISTICS_REQ:
33330Sstevel@tonic-gate 		if (mblkl < DL_GET_STATISTICS_REQ_SIZE)
33340Sstevel@tonic-gate 			break;
33350Sstevel@tonic-gate 		result = gld_get_statistics(q, mp);
33360Sstevel@tonic-gate 		break;
33370Sstevel@tonic-gate 
33380Sstevel@tonic-gate 	case DL_CAPABILITY_REQ:
33390Sstevel@tonic-gate 		if (mblkl < DL_CAPABILITY_REQ_SIZE)
33400Sstevel@tonic-gate 			break;
33410Sstevel@tonic-gate 		result = gld_cap(q, mp);
33420Sstevel@tonic-gate 		break;
33430Sstevel@tonic-gate 
33440Sstevel@tonic-gate 	case DL_NOTIFY_REQ:
33450Sstevel@tonic-gate 		if (mblkl < DL_NOTIFY_REQ_SIZE)
33460Sstevel@tonic-gate 			break;
33470Sstevel@tonic-gate 		result = gld_notify_req(q, mp);
33480Sstevel@tonic-gate 		break;
33490Sstevel@tonic-gate 
33500Sstevel@tonic-gate 	case DL_XID_REQ:
33510Sstevel@tonic-gate 	case DL_XID_RES:
33520Sstevel@tonic-gate 	case DL_TEST_REQ:
33530Sstevel@tonic-gate 	case DL_TEST_RES:
33540Sstevel@tonic-gate 	case DL_CONTROL_REQ:
335556Smeem 	case DL_PASSIVE_REQ:
33560Sstevel@tonic-gate 		result = DL_NOTSUPPORTED;
33570Sstevel@tonic-gate 		break;
33580Sstevel@tonic-gate 
33590Sstevel@tonic-gate 	default:
33600Sstevel@tonic-gate #ifdef	GLD_DEBUG
33610Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
33620Sstevel@tonic-gate 			cmn_err(CE_WARN,
33630Sstevel@tonic-gate 			    "gld_cmds: unknown M_PROTO message: %d",
33640Sstevel@tonic-gate 			    dlreq);
33650Sstevel@tonic-gate #endif
33660Sstevel@tonic-gate 		result = DL_BADPRIM;
33670Sstevel@tonic-gate 	}
33680Sstevel@tonic-gate 
33690Sstevel@tonic-gate 	return (result);
33700Sstevel@tonic-gate }
33710Sstevel@tonic-gate 
33720Sstevel@tonic-gate static int
33730Sstevel@tonic-gate gld_cap(queue_t *q, mblk_t *mp)
33740Sstevel@tonic-gate {
33750Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
33760Sstevel@tonic-gate 	dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr;
33770Sstevel@tonic-gate 
33780Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
33790Sstevel@tonic-gate 		return (DL_OUTSTATE);
33800Sstevel@tonic-gate 
33810Sstevel@tonic-gate 	if (dlp->dl_sub_length == 0)
33820Sstevel@tonic-gate 		return (gld_cap_ack(q, mp));
33830Sstevel@tonic-gate 
33840Sstevel@tonic-gate 	return (gld_cap_enable(q, mp));
33850Sstevel@tonic-gate }
33860Sstevel@tonic-gate 
33870Sstevel@tonic-gate static int
33880Sstevel@tonic-gate gld_cap_ack(queue_t *q, mblk_t *mp)
33890Sstevel@tonic-gate {
33900Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
33910Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
33920Sstevel@tonic-gate 	gld_interface_t *ifp;
33930Sstevel@tonic-gate 	dl_capability_ack_t *dlap;
33940Sstevel@tonic-gate 	dl_capability_sub_t *dlsp;
33950Sstevel@tonic-gate 	size_t size = sizeof (dl_capability_ack_t);
33960Sstevel@tonic-gate 	size_t subsize = 0;
33970Sstevel@tonic-gate 
33980Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
33990Sstevel@tonic-gate 
34000Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_ANY)
34010Sstevel@tonic-gate 		subsize += sizeof (dl_capability_sub_t) +
34020Sstevel@tonic-gate 		    sizeof (dl_capab_hcksum_t);
34030Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_ZEROCOPY)
34040Sstevel@tonic-gate 		subsize += sizeof (dl_capability_sub_t) +
34050Sstevel@tonic-gate 		    sizeof (dl_capab_zerocopy_t);
34060Sstevel@tonic-gate 	if (macinfo->gldm_options & GLDOPT_MDT)
34070Sstevel@tonic-gate 		subsize += (sizeof (dl_capability_sub_t) +
34080Sstevel@tonic-gate 		    sizeof (dl_capab_mdt_t));
34090Sstevel@tonic-gate 
34100Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, size + subsize, M_PROTO,
34110Sstevel@tonic-gate 	    DL_CAPABILITY_ACK)) == NULL)
34120Sstevel@tonic-gate 		return (GLDE_OK);
34130Sstevel@tonic-gate 
34140Sstevel@tonic-gate 	dlap = (dl_capability_ack_t *)mp->b_rptr;
34150Sstevel@tonic-gate 	dlap->dl_sub_offset = 0;
34160Sstevel@tonic-gate 	if ((dlap->dl_sub_length = subsize) != 0)
34170Sstevel@tonic-gate 		dlap->dl_sub_offset = sizeof (dl_capability_ack_t);
34180Sstevel@tonic-gate 	dlsp = (dl_capability_sub_t *)&dlap[1];
34190Sstevel@tonic-gate 
34200Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_ANY) {
34210Sstevel@tonic-gate 		dl_capab_hcksum_t *dlhp = (dl_capab_hcksum_t *)&dlsp[1];
34220Sstevel@tonic-gate 
34230Sstevel@tonic-gate 		dlsp->dl_cap = DL_CAPAB_HCKSUM;
34240Sstevel@tonic-gate 		dlsp->dl_length = sizeof (dl_capab_hcksum_t);
34250Sstevel@tonic-gate 
34260Sstevel@tonic-gate 		dlhp->hcksum_version = HCKSUM_VERSION_1;
34270Sstevel@tonic-gate 
34280Sstevel@tonic-gate 		dlhp->hcksum_txflags = 0;
34290Sstevel@tonic-gate 		if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_PARTIAL)
34300Sstevel@tonic-gate 			dlhp->hcksum_txflags |= HCKSUM_INET_PARTIAL;
34310Sstevel@tonic-gate 		if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_FULL_V4)
34320Sstevel@tonic-gate 			dlhp->hcksum_txflags |= HCKSUM_INET_FULL_V4;
3433741Smasputra 		if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_FULL_V6)
3434741Smasputra 			dlhp->hcksum_txflags |= HCKSUM_INET_FULL_V6;
34350Sstevel@tonic-gate 		if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_IPHDR)
34360Sstevel@tonic-gate 			dlhp->hcksum_txflags |= HCKSUM_IPHDRCKSUM;
34370Sstevel@tonic-gate 
34380Sstevel@tonic-gate 		dlcapabsetqid(&(dlhp->hcksum_mid), RD(q));
34390Sstevel@tonic-gate 		dlsp = (dl_capability_sub_t *)&dlhp[1];
34400Sstevel@tonic-gate 	}
34410Sstevel@tonic-gate 
34420Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_ZEROCOPY) {
34430Sstevel@tonic-gate 		dl_capab_zerocopy_t *dlzp = (dl_capab_zerocopy_t *)&dlsp[1];
34440Sstevel@tonic-gate 
34450Sstevel@tonic-gate 		dlsp->dl_cap = DL_CAPAB_ZEROCOPY;
34460Sstevel@tonic-gate 		dlsp->dl_length = sizeof (dl_capab_zerocopy_t);
34470Sstevel@tonic-gate 		dlzp->zerocopy_version = ZEROCOPY_VERSION_1;
34480Sstevel@tonic-gate 		dlzp->zerocopy_flags = DL_CAPAB_VMSAFE_MEM;
34490Sstevel@tonic-gate 
34500Sstevel@tonic-gate 		dlcapabsetqid(&(dlzp->zerocopy_mid), RD(q));
34510Sstevel@tonic-gate 		dlsp = (dl_capability_sub_t *)&dlzp[1];
34520Sstevel@tonic-gate 	}
34530Sstevel@tonic-gate 
34540Sstevel@tonic-gate 	if (macinfo->gldm_options & GLDOPT_MDT) {
34550Sstevel@tonic-gate 		dl_capab_mdt_t *dlmp = (dl_capab_mdt_t *)&dlsp[1];
34560Sstevel@tonic-gate 
34570Sstevel@tonic-gate 		dlsp->dl_cap = DL_CAPAB_MDT;
34580Sstevel@tonic-gate 		dlsp->dl_length = sizeof (dl_capab_mdt_t);
34590Sstevel@tonic-gate 
34600Sstevel@tonic-gate 		dlmp->mdt_version = MDT_VERSION_2;
34610Sstevel@tonic-gate 		dlmp->mdt_max_pld = macinfo->gldm_mdt_segs;
34620Sstevel@tonic-gate 		dlmp->mdt_span_limit = macinfo->gldm_mdt_sgl;
34630Sstevel@tonic-gate 		dlcapabsetqid(&dlmp->mdt_mid, OTHERQ(q));
34640Sstevel@tonic-gate 		dlmp->mdt_flags = DL_CAPAB_MDT_ENABLE;
34650Sstevel@tonic-gate 		dlmp->mdt_hdr_head = ifp->hdr_size;
34660Sstevel@tonic-gate 		dlmp->mdt_hdr_tail = 0;
34670Sstevel@tonic-gate 	}
34680Sstevel@tonic-gate 
34690Sstevel@tonic-gate 	qreply(q, mp);
34700Sstevel@tonic-gate 	return (GLDE_OK);
34710Sstevel@tonic-gate }
34720Sstevel@tonic-gate 
34730Sstevel@tonic-gate static int
34740Sstevel@tonic-gate gld_cap_enable(queue_t *q, mblk_t *mp)
34750Sstevel@tonic-gate {
34760Sstevel@tonic-gate 	dl_capability_req_t *dlp;
34770Sstevel@tonic-gate 	dl_capability_sub_t *dlsp;
34780Sstevel@tonic-gate 	dl_capab_hcksum_t *dlhp;
34790Sstevel@tonic-gate 	offset_t off;
34800Sstevel@tonic-gate 	size_t len;
34810Sstevel@tonic-gate 	size_t size;
34820Sstevel@tonic-gate 	offset_t end;
34830Sstevel@tonic-gate 
34840Sstevel@tonic-gate 	dlp = (dl_capability_req_t *)mp->b_rptr;
34850Sstevel@tonic-gate 	dlp->dl_primitive = DL_CAPABILITY_ACK;
34860Sstevel@tonic-gate 
34870Sstevel@tonic-gate 	off = dlp->dl_sub_offset;
34880Sstevel@tonic-gate 	len = dlp->dl_sub_length;
34890Sstevel@tonic-gate 
34900Sstevel@tonic-gate 	if (!MBLKIN(mp, off, len))
34910Sstevel@tonic-gate 		return (DL_BADPRIM);
34920Sstevel@tonic-gate 
34930Sstevel@tonic-gate 	end = off + len;
34940Sstevel@tonic-gate 	while (off < end) {
34950Sstevel@tonic-gate 		dlsp = (dl_capability_sub_t *)(mp->b_rptr + off);
34960Sstevel@tonic-gate 		size = sizeof (dl_capability_sub_t) + dlsp->dl_length;
34970Sstevel@tonic-gate 		if (off + size > end)
34980Sstevel@tonic-gate 			return (DL_BADPRIM);
34990Sstevel@tonic-gate 
35000Sstevel@tonic-gate 		switch (dlsp->dl_cap) {
35010Sstevel@tonic-gate 		case DL_CAPAB_HCKSUM:
35020Sstevel@tonic-gate 			dlhp = (dl_capab_hcksum_t *)&dlsp[1];
35030Sstevel@tonic-gate 			/* nothing useful we can do with the contents */
35040Sstevel@tonic-gate 			dlcapabsetqid(&(dlhp->hcksum_mid), RD(q));
35050Sstevel@tonic-gate 			break;
35060Sstevel@tonic-gate 		default:
35070Sstevel@tonic-gate 			break;
35080Sstevel@tonic-gate 		}
35090Sstevel@tonic-gate 
35100Sstevel@tonic-gate 		off += size;
35110Sstevel@tonic-gate 	}
35120Sstevel@tonic-gate 
35130Sstevel@tonic-gate 	qreply(q, mp);
35140Sstevel@tonic-gate 	return (GLDE_OK);
35150Sstevel@tonic-gate }
35160Sstevel@tonic-gate 
35170Sstevel@tonic-gate /*
35180Sstevel@tonic-gate  * Send a copy of the DL_NOTIFY_IND message <mp> to each stream that has
35190Sstevel@tonic-gate  * requested the specific <notification> that the message carries AND is
35200Sstevel@tonic-gate  * eligible and ready to receive the notification immediately.
35210Sstevel@tonic-gate  *
35220Sstevel@tonic-gate  * This routine ignores flow control. Notifications will be sent regardless.
35230Sstevel@tonic-gate  *
35240Sstevel@tonic-gate  * In all cases, the original message passed in is freed at the end of
35250Sstevel@tonic-gate  * the routine.
35260Sstevel@tonic-gate  */
35270Sstevel@tonic-gate static void
35280Sstevel@tonic-gate gld_notify_qs(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t notification)
35290Sstevel@tonic-gate {
35300Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
35310Sstevel@tonic-gate 	gld_vlan_t *vlan;
35320Sstevel@tonic-gate 	gld_t *gld;
35330Sstevel@tonic-gate 	mblk_t *nmp;
35340Sstevel@tonic-gate 	int i;
35350Sstevel@tonic-gate 
35360Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
35370Sstevel@tonic-gate 
35380Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
35390Sstevel@tonic-gate 
35400Sstevel@tonic-gate 	/*
35410Sstevel@tonic-gate 	 * Search all the streams attached to this macinfo looking
35420Sstevel@tonic-gate 	 * for those eligible to receive the present notification.
35430Sstevel@tonic-gate 	 */
35440Sstevel@tonic-gate 	for (i = 0; i < VLAN_HASHSZ; i++) {
35450Sstevel@tonic-gate 		for (vlan = mac_pvt->vlan_hash[i];
35460Sstevel@tonic-gate 		    vlan != NULL; vlan = vlan->gldv_next) {
35470Sstevel@tonic-gate 			for (gld = vlan->gldv_str_next;
35480Sstevel@tonic-gate 			    gld != (gld_t *)&vlan->gldv_str_next;
35490Sstevel@tonic-gate 			    gld = gld->gld_next) {
35500Sstevel@tonic-gate 				ASSERT(gld->gld_qptr != NULL);
35510Sstevel@tonic-gate 				ASSERT(gld->gld_state == DL_IDLE ||
35520Sstevel@tonic-gate 				    gld->gld_state == DL_UNBOUND);
35530Sstevel@tonic-gate 				ASSERT(gld->gld_mac_info == macinfo);
35540Sstevel@tonic-gate 
35550Sstevel@tonic-gate 				if (gld->gld_flags & GLD_STR_CLOSING)
35560Sstevel@tonic-gate 					continue; /* not eligible - skip */
35570Sstevel@tonic-gate 				if (!(notification & gld->gld_notifications))
35580Sstevel@tonic-gate 					continue; /* not wanted - skip */
35590Sstevel@tonic-gate 				if ((nmp = dupmsg(mp)) == NULL)
35600Sstevel@tonic-gate 					continue; /* can't copy - skip */
35610Sstevel@tonic-gate 
35620Sstevel@tonic-gate 				/*
35630Sstevel@tonic-gate 				 * All OK; send dup'd notification up this
35640Sstevel@tonic-gate 				 * stream
35650Sstevel@tonic-gate 				 */
35660Sstevel@tonic-gate 				qreply(WR(gld->gld_qptr), nmp);
35670Sstevel@tonic-gate 			}
35680Sstevel@tonic-gate 		}
35690Sstevel@tonic-gate 	}
35700Sstevel@tonic-gate 
35710Sstevel@tonic-gate 	/*
35720Sstevel@tonic-gate 	 * Drop the original message block now
35730Sstevel@tonic-gate 	 */
35740Sstevel@tonic-gate 	freemsg(mp);
35750Sstevel@tonic-gate }
35760Sstevel@tonic-gate 
35770Sstevel@tonic-gate /*
35780Sstevel@tonic-gate  * For each (understood) bit in the <notifications> argument, contruct
35790Sstevel@tonic-gate  * a DL_NOTIFY_IND message and send it to the specified <q>, or to all
35800Sstevel@tonic-gate  * eligible queues if <q> is NULL.
35810Sstevel@tonic-gate  */
35820Sstevel@tonic-gate static void
35830Sstevel@tonic-gate gld_notify_ind(gld_mac_info_t *macinfo, uint32_t notifications, queue_t *q)
35840Sstevel@tonic-gate {
35850Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
35860Sstevel@tonic-gate 	dl_notify_ind_t *dlnip;
35870Sstevel@tonic-gate 	struct gld_stats *stats;
35880Sstevel@tonic-gate 	mblk_t *mp;
35890Sstevel@tonic-gate 	size_t size;
35900Sstevel@tonic-gate 	uint32_t bit;
35910Sstevel@tonic-gate 
35920Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
35930Sstevel@tonic-gate 
35940Sstevel@tonic-gate 	/*
35950Sstevel@tonic-gate 	 * The following cases shouldn't happen, but just in case the
35960Sstevel@tonic-gate 	 * MAC driver calls gld_linkstate() at an inappropriate time, we
35970Sstevel@tonic-gate 	 * check anyway ...
35980Sstevel@tonic-gate 	 */
35990Sstevel@tonic-gate 	if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY)) {
36000Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
36010Sstevel@tonic-gate 		return;				/* not ready yet	*/
36020Sstevel@tonic-gate 	}
36030Sstevel@tonic-gate 
36040Sstevel@tonic-gate 	if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
36050Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
36060Sstevel@tonic-gate 		return;				/* not ready anymore	*/
36070Sstevel@tonic-gate 	}
36080Sstevel@tonic-gate 
36090Sstevel@tonic-gate 	/*
36100Sstevel@tonic-gate 	 * Make sure the kstats are up to date, 'cos we use some of
36110Sstevel@tonic-gate 	 * the kstat values below, specifically the link speed ...
36120Sstevel@tonic-gate 	 */
36130Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
36140Sstevel@tonic-gate 	stats = mac_pvt->statistics;
36150Sstevel@tonic-gate 	if (macinfo->gldm_get_stats)
36160Sstevel@tonic-gate 		(void) (*macinfo->gldm_get_stats)(macinfo, stats);
36170Sstevel@tonic-gate 
36180Sstevel@tonic-gate 	for (bit = 1; notifications != 0; bit <<= 1) {
36190Sstevel@tonic-gate 		if ((notifications & bit) == 0)
36200Sstevel@tonic-gate 			continue;
36210Sstevel@tonic-gate 		notifications &= ~bit;
36220Sstevel@tonic-gate 
36230Sstevel@tonic-gate 		size = DL_NOTIFY_IND_SIZE;
36240Sstevel@tonic-gate 		if (bit == DL_NOTE_PHYS_ADDR)
36250Sstevel@tonic-gate 			size += macinfo->gldm_addrlen;
36260Sstevel@tonic-gate 		if ((mp = allocb(size, BPRI_MED)) == NULL)
36270Sstevel@tonic-gate 			continue;
36280Sstevel@tonic-gate 
36290Sstevel@tonic-gate 		mp->b_datap->db_type = M_PROTO;
36300Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + size;
36310Sstevel@tonic-gate 		dlnip = (dl_notify_ind_t *)mp->b_rptr;
36320Sstevel@tonic-gate 		dlnip->dl_primitive = DL_NOTIFY_IND;
36330Sstevel@tonic-gate 		dlnip->dl_notification = 0;
36340Sstevel@tonic-gate 		dlnip->dl_data = 0;
36350Sstevel@tonic-gate 		dlnip->dl_addr_length = 0;
36360Sstevel@tonic-gate 		dlnip->dl_addr_offset = 0;
36370Sstevel@tonic-gate 
36380Sstevel@tonic-gate 		switch (bit) {
36390Sstevel@tonic-gate 		case DL_NOTE_PROMISC_ON_PHYS:
36400Sstevel@tonic-gate 		case DL_NOTE_PROMISC_OFF_PHYS:
36410Sstevel@tonic-gate 			if (mac_pvt->nprom != 0)
36420Sstevel@tonic-gate 				dlnip->dl_notification = bit;
36430Sstevel@tonic-gate 			break;
36440Sstevel@tonic-gate 
36450Sstevel@tonic-gate 		case DL_NOTE_LINK_DOWN:
36460Sstevel@tonic-gate 			if (macinfo->gldm_linkstate == GLD_LINKSTATE_DOWN)
36470Sstevel@tonic-gate 				dlnip->dl_notification = bit;
36480Sstevel@tonic-gate 			break;
36490Sstevel@tonic-gate 
36500Sstevel@tonic-gate 		case DL_NOTE_LINK_UP:
36510Sstevel@tonic-gate 			if (macinfo->gldm_linkstate == GLD_LINKSTATE_UP)
36520Sstevel@tonic-gate 				dlnip->dl_notification = bit;
36530Sstevel@tonic-gate 			break;
36540Sstevel@tonic-gate 
36550Sstevel@tonic-gate 		case DL_NOTE_SPEED:
36560Sstevel@tonic-gate 			/*
36570Sstevel@tonic-gate 			 * Conversion required here:
36580Sstevel@tonic-gate 			 *	GLD keeps the speed in bit/s in a uint64
36590Sstevel@tonic-gate 			 *	DLPI wants it in kb/s in a uint32
36600Sstevel@tonic-gate 			 * Fortunately this is still big enough for 10Gb/s!
36610Sstevel@tonic-gate 			 */
36620Sstevel@tonic-gate 			dlnip->dl_notification = bit;
36630Sstevel@tonic-gate 			dlnip->dl_data = stats->glds_speed/1000ULL;
36640Sstevel@tonic-gate 			break;
36650Sstevel@tonic-gate 
36660Sstevel@tonic-gate 		case DL_NOTE_PHYS_ADDR:
36670Sstevel@tonic-gate 			dlnip->dl_notification = bit;
36680Sstevel@tonic-gate 			dlnip->dl_data = DL_CURR_PHYS_ADDR;
36690Sstevel@tonic-gate 			dlnip->dl_addr_offset = sizeof (dl_notify_ind_t);
36700Sstevel@tonic-gate 			dlnip->dl_addr_length = macinfo->gldm_addrlen +
36710Sstevel@tonic-gate 			    abs(macinfo->gldm_saplen);
36720Sstevel@tonic-gate 			mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
36730Sstevel@tonic-gate 			mac_copy(mac_pvt->curr_macaddr,
36740Sstevel@tonic-gate 			    mp->b_rptr + sizeof (dl_notify_ind_t),
36750Sstevel@tonic-gate 			    macinfo->gldm_addrlen);
36760Sstevel@tonic-gate 			break;
36770Sstevel@tonic-gate 
36780Sstevel@tonic-gate 		default:
36790Sstevel@tonic-gate 			break;
36800Sstevel@tonic-gate 		}
36810Sstevel@tonic-gate 
36820Sstevel@tonic-gate 		if (dlnip->dl_notification == 0)
36830Sstevel@tonic-gate 			freemsg(mp);
36840Sstevel@tonic-gate 		else if (q != NULL)
36850Sstevel@tonic-gate 			qreply(q, mp);
36860Sstevel@tonic-gate 		else
36870Sstevel@tonic-gate 			gld_notify_qs(macinfo, mp, bit);
36880Sstevel@tonic-gate 	}
36890Sstevel@tonic-gate 
36900Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
36910Sstevel@tonic-gate }
36920Sstevel@tonic-gate 
36930Sstevel@tonic-gate /*
36940Sstevel@tonic-gate  * gld_notify_req - handle a DL_NOTIFY_REQ message
36950Sstevel@tonic-gate  */
36960Sstevel@tonic-gate static int
36970Sstevel@tonic-gate gld_notify_req(queue_t *q, mblk_t *mp)
36980Sstevel@tonic-gate {
36990Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
37000Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
37010Sstevel@tonic-gate 	gld_mac_pvt_t *pvt;
37020Sstevel@tonic-gate 	dl_notify_req_t *dlnrp;
37030Sstevel@tonic-gate 	dl_notify_ack_t *dlnap;
37040Sstevel@tonic-gate 
37050Sstevel@tonic-gate 	ASSERT(gld != NULL);
37060Sstevel@tonic-gate 	ASSERT(gld->gld_qptr == RD(q));
37070Sstevel@tonic-gate 
37080Sstevel@tonic-gate 	dlnrp = (dl_notify_req_t *)mp->b_rptr;
37090Sstevel@tonic-gate 
37100Sstevel@tonic-gate #ifdef GLD_DEBUG
37110Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
37120Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_notify_req(%p %p)",
37130Sstevel@tonic-gate 			(void *)q, (void *)mp);
37140Sstevel@tonic-gate #endif
37150Sstevel@tonic-gate 
37160Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED) {
37170Sstevel@tonic-gate #ifdef GLD_DEBUG
37180Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
37190Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_notify_req: wrong state (%d)",
37200Sstevel@tonic-gate 				gld->gld_state);
37210Sstevel@tonic-gate #endif
37220Sstevel@tonic-gate 		return (DL_OUTSTATE);
37230Sstevel@tonic-gate 	}
37240Sstevel@tonic-gate 
37250Sstevel@tonic-gate 	/*
37260Sstevel@tonic-gate 	 * Remember what notifications are required by this stream
37270Sstevel@tonic-gate 	 */
37280Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
37290Sstevel@tonic-gate 	pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
37300Sstevel@tonic-gate 
37310Sstevel@tonic-gate 	gld->gld_notifications = dlnrp->dl_notifications & pvt->notifications;
37320Sstevel@tonic-gate 
37330Sstevel@tonic-gate 	/*
37340Sstevel@tonic-gate 	 * The return DL_NOTIFY_ACK carries the bitset of notifications
37350Sstevel@tonic-gate 	 * that this driver can provide, independently of which ones have
37360Sstevel@tonic-gate 	 * previously been or are now being requested.
37370Sstevel@tonic-gate 	 */
37380Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, sizeof (dl_notify_ack_t), M_PCPROTO,
37390Sstevel@tonic-gate 	    DL_NOTIFY_ACK)) == NULL)
37400Sstevel@tonic-gate 		return (DL_SYSERR);
37410Sstevel@tonic-gate 
37420Sstevel@tonic-gate 	dlnap = (dl_notify_ack_t *)mp->b_rptr;
37430Sstevel@tonic-gate 	dlnap->dl_notifications = pvt->notifications;
37440Sstevel@tonic-gate 	qreply(q, mp);
37450Sstevel@tonic-gate 
37460Sstevel@tonic-gate 	/*
37470Sstevel@tonic-gate 	 * A side effect of a DL_NOTIFY_REQ is that after the DL_NOTIFY_ACK
37480Sstevel@tonic-gate 	 * reply, the the requestor gets zero or more DL_NOTIFY_IND messages
37490Sstevel@tonic-gate 	 * that provide the current status.
37500Sstevel@tonic-gate 	 */
37510Sstevel@tonic-gate 	gld_notify_ind(macinfo, gld->gld_notifications, q);
37520Sstevel@tonic-gate 
37530Sstevel@tonic-gate 	return (GLDE_OK);
37540Sstevel@tonic-gate }
37550Sstevel@tonic-gate 
37560Sstevel@tonic-gate /*
37570Sstevel@tonic-gate  * gld_linkstate()
37580Sstevel@tonic-gate  *	Called by driver to tell GLD the state of the physical link.
37590Sstevel@tonic-gate  *	As a side effect, sends a DL_NOTE_LINK_UP or DL_NOTE_LINK_DOWN
37600Sstevel@tonic-gate  *	notification to each client that has previously requested such
37610Sstevel@tonic-gate  *	notifications
37620Sstevel@tonic-gate  */
37630Sstevel@tonic-gate void
37640Sstevel@tonic-gate gld_linkstate(gld_mac_info_t *macinfo, int32_t newstate)
37650Sstevel@tonic-gate {
37660Sstevel@tonic-gate 	uint32_t notification;
37670Sstevel@tonic-gate 
37680Sstevel@tonic-gate 	switch (newstate) {
37690Sstevel@tonic-gate 	default:
37700Sstevel@tonic-gate 		return;
37710Sstevel@tonic-gate 
37720Sstevel@tonic-gate 	case GLD_LINKSTATE_DOWN:
37730Sstevel@tonic-gate 		notification = DL_NOTE_LINK_DOWN;
37740Sstevel@tonic-gate 		break;
37750Sstevel@tonic-gate 
37760Sstevel@tonic-gate 	case GLD_LINKSTATE_UP:
37770Sstevel@tonic-gate 		notification = DL_NOTE_LINK_UP | DL_NOTE_SPEED;
37780Sstevel@tonic-gate 		break;
37790Sstevel@tonic-gate 
37800Sstevel@tonic-gate 	case GLD_LINKSTATE_UNKNOWN:
37810Sstevel@tonic-gate 		notification = 0;
37820Sstevel@tonic-gate 		break;
37830Sstevel@tonic-gate 	}
37840Sstevel@tonic-gate 
37850Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
37860Sstevel@tonic-gate 	if (macinfo->gldm_linkstate == newstate)
37870Sstevel@tonic-gate 		notification = 0;
37880Sstevel@tonic-gate 	else
37890Sstevel@tonic-gate 		macinfo->gldm_linkstate = newstate;
37900Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
37910Sstevel@tonic-gate 
37920Sstevel@tonic-gate 	if (notification)
37930Sstevel@tonic-gate 		gld_notify_ind(macinfo, notification, NULL);
37940Sstevel@tonic-gate }
37950Sstevel@tonic-gate 
37960Sstevel@tonic-gate /*
37970Sstevel@tonic-gate  * gld_udqos - set the current QoS parameters (priority only at the moment).
37980Sstevel@tonic-gate  */
37990Sstevel@tonic-gate static int
38000Sstevel@tonic-gate gld_udqos(queue_t *q, mblk_t *mp)
38010Sstevel@tonic-gate {
38020Sstevel@tonic-gate 	dl_udqos_req_t *dlp;
38030Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
38040Sstevel@tonic-gate 	int off;
38050Sstevel@tonic-gate 	int len;
38060Sstevel@tonic-gate 	dl_qos_cl_sel1_t *selp;
38070Sstevel@tonic-gate 
38080Sstevel@tonic-gate 	ASSERT(gld);
38090Sstevel@tonic-gate 	ASSERT(gld->gld_qptr == RD(q));
38100Sstevel@tonic-gate 
38110Sstevel@tonic-gate #ifdef GLD_DEBUG
38120Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
38130Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_udqos(%p %p)", (void *)q, (void *)mp);
38140Sstevel@tonic-gate #endif
38150Sstevel@tonic-gate 
38160Sstevel@tonic-gate 	if (gld->gld_state != DL_IDLE) {
38170Sstevel@tonic-gate #ifdef GLD_DEBUG
38180Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
38190Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_udqos: wrong state (%d)",
38200Sstevel@tonic-gate 			    gld->gld_state);
38210Sstevel@tonic-gate #endif
38220Sstevel@tonic-gate 		return (DL_OUTSTATE);
38230Sstevel@tonic-gate 	}
38240Sstevel@tonic-gate 
38250Sstevel@tonic-gate 	dlp = (dl_udqos_req_t *)mp->b_rptr;
38260Sstevel@tonic-gate 	off = dlp->dl_qos_offset;
38270Sstevel@tonic-gate 	len = dlp->dl_qos_length;
38280Sstevel@tonic-gate 
38290Sstevel@tonic-gate 	if (len != sizeof (dl_qos_cl_sel1_t) || !MBLKIN(mp, off, len))
38300Sstevel@tonic-gate 		return (DL_BADQOSTYPE);
38310Sstevel@tonic-gate 
38320Sstevel@tonic-gate 	selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off);
38330Sstevel@tonic-gate 	if (selp->dl_qos_type != DL_QOS_CL_SEL1)
38340Sstevel@tonic-gate 		return (DL_BADQOSTYPE);
38350Sstevel@tonic-gate 
38360Sstevel@tonic-gate 	if (selp->dl_trans_delay != 0 &&
38370Sstevel@tonic-gate 	    selp->dl_trans_delay != DL_QOS_DONT_CARE)
38380Sstevel@tonic-gate 		return (DL_BADQOSPARAM);
38390Sstevel@tonic-gate 	if (selp->dl_protection != 0 &&
38400Sstevel@tonic-gate 	    selp->dl_protection != DL_QOS_DONT_CARE)
38410Sstevel@tonic-gate 		return (DL_BADQOSPARAM);
38420Sstevel@tonic-gate 	if (selp->dl_residual_error != 0 &&
38430Sstevel@tonic-gate 	    selp->dl_residual_error != DL_QOS_DONT_CARE)
38440Sstevel@tonic-gate 		return (DL_BADQOSPARAM);
38450Sstevel@tonic-gate 	if (selp->dl_priority < 0 || selp->dl_priority > 7)
38460Sstevel@tonic-gate 		return (DL_BADQOSPARAM);
38470Sstevel@tonic-gate 
38480Sstevel@tonic-gate 	gld->gld_upri = selp->dl_priority;
38490Sstevel@tonic-gate 
38500Sstevel@tonic-gate 	dlokack(q, mp, DL_UDQOS_REQ);
38510Sstevel@tonic-gate 	return (GLDE_OK);
38520Sstevel@tonic-gate }
38530Sstevel@tonic-gate 
38540Sstevel@tonic-gate static mblk_t *
38550Sstevel@tonic-gate gld_bindack(queue_t *q, mblk_t *mp)
38560Sstevel@tonic-gate {
38570Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
38580Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
38590Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
38600Sstevel@tonic-gate 	dl_bind_ack_t *dlp;
38610Sstevel@tonic-gate 	size_t size;
38620Sstevel@tonic-gate 	t_uscalar_t addrlen;
38630Sstevel@tonic-gate 	uchar_t *sapp;
38640Sstevel@tonic-gate 
38650Sstevel@tonic-gate 	addrlen = macinfo->gldm_addrlen + abs(macinfo->gldm_saplen);
38660Sstevel@tonic-gate 	size = sizeof (dl_bind_ack_t) + addrlen;
38670Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, size, M_PCPROTO, DL_BIND_ACK)) == NULL)
38680Sstevel@tonic-gate 		return (NULL);
38690Sstevel@tonic-gate 
38700Sstevel@tonic-gate 	dlp = (dl_bind_ack_t *)mp->b_rptr;
38710Sstevel@tonic-gate 	dlp->dl_sap = gld->gld_sap;
38720Sstevel@tonic-gate 	dlp->dl_addr_length = addrlen;
38730Sstevel@tonic-gate 	dlp->dl_addr_offset = sizeof (dl_bind_ack_t);
38740Sstevel@tonic-gate 	dlp->dl_max_conind = 0;
38750Sstevel@tonic-gate 	dlp->dl_xidtest_flg = 0;
38760Sstevel@tonic-gate 
38770Sstevel@tonic-gate 	mac_copy(mac_pvt->curr_macaddr, (uchar_t *)&dlp[1],
38780Sstevel@tonic-gate 	    macinfo->gldm_addrlen);
38790Sstevel@tonic-gate 	sapp = mp->b_rptr + dlp->dl_addr_offset + macinfo->gldm_addrlen;
38800Sstevel@tonic-gate 	*(ushort_t *)sapp = gld->gld_sap;
38810Sstevel@tonic-gate 
38820Sstevel@tonic-gate 	return (mp);
38830Sstevel@tonic-gate }
38840Sstevel@tonic-gate 
38850Sstevel@tonic-gate /*
38860Sstevel@tonic-gate  * gld_bind - determine if a SAP is already allocated and whether it is legal
38870Sstevel@tonic-gate  * to do the bind at this time
38880Sstevel@tonic-gate  */
38890Sstevel@tonic-gate static int
38900Sstevel@tonic-gate gld_bind(queue_t *q, mblk_t *mp)
38910Sstevel@tonic-gate {
38920Sstevel@tonic-gate 	ulong_t	sap;
38930Sstevel@tonic-gate 	dl_bind_req_t *dlp;
38940Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
38950Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
38960Sstevel@tonic-gate 
38970Sstevel@tonic-gate 	ASSERT(gld);
38980Sstevel@tonic-gate 	ASSERT(gld->gld_qptr == RD(q));
38990Sstevel@tonic-gate 
39000Sstevel@tonic-gate #ifdef GLD_DEBUG
39010Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
39020Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_bind(%p %p)", (void *)q, (void *)mp);
39030Sstevel@tonic-gate #endif
39040Sstevel@tonic-gate 
39050Sstevel@tonic-gate 	dlp = (dl_bind_req_t *)mp->b_rptr;
39060Sstevel@tonic-gate 	sap = dlp->dl_sap;
39070Sstevel@tonic-gate 
39080Sstevel@tonic-gate #ifdef GLD_DEBUG
39090Sstevel@tonic-gate 	if (gld_debug & GLDPROT)
39100Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_bind: lsap=%lx", sap);
39110Sstevel@tonic-gate #endif
39120Sstevel@tonic-gate 
39130Sstevel@tonic-gate 	if (gld->gld_state != DL_UNBOUND) {
39140Sstevel@tonic-gate #ifdef GLD_DEBUG
39150Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
39160Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_bind: bound or not attached (%d)",
39170Sstevel@tonic-gate 				gld->gld_state);
39180Sstevel@tonic-gate #endif
39190Sstevel@tonic-gate 		return (DL_OUTSTATE);
39200Sstevel@tonic-gate 	}
39210Sstevel@tonic-gate 	ASSERT(macinfo);
39220Sstevel@tonic-gate 
39230Sstevel@tonic-gate 	if (dlp->dl_service_mode != DL_CLDLS) {
39240Sstevel@tonic-gate 		return (DL_UNSUPPORTED);
39250Sstevel@tonic-gate 	}
39260Sstevel@tonic-gate 	if (dlp->dl_xidtest_flg & (DL_AUTO_XID | DL_AUTO_TEST)) {
39270Sstevel@tonic-gate 		return (DL_NOAUTO);
39280Sstevel@tonic-gate 	}
39290Sstevel@tonic-gate 
39300Sstevel@tonic-gate 	/*
39310Sstevel@tonic-gate 	 * Check sap validity and decide whether this stream accepts
39320Sstevel@tonic-gate 	 * IEEE 802.2 (LLC) packets.
39330Sstevel@tonic-gate 	 */
39340Sstevel@tonic-gate 	if (sap > ETHERTYPE_MAX)
39350Sstevel@tonic-gate 		return (DL_BADSAP);
39360Sstevel@tonic-gate 
39370Sstevel@tonic-gate 	/*
39380Sstevel@tonic-gate 	 * Decide whether the SAP value selects EtherType encoding/decoding.
39390Sstevel@tonic-gate 	 * For compatibility with monolithic ethernet drivers, the range of
39400Sstevel@tonic-gate 	 * SAP values is different for DL_ETHER media.
39410Sstevel@tonic-gate 	 */
39420Sstevel@tonic-gate 	switch (macinfo->gldm_type) {
39430Sstevel@tonic-gate 	case DL_ETHER:
39440Sstevel@tonic-gate 		gld->gld_ethertype = (sap > ETHERMTU);
39450Sstevel@tonic-gate 		break;
39460Sstevel@tonic-gate 	default:
39470Sstevel@tonic-gate 		gld->gld_ethertype = (sap > GLD_MAX_802_SAP);
39480Sstevel@tonic-gate 		break;
39490Sstevel@tonic-gate 	}
39500Sstevel@tonic-gate 
39510Sstevel@tonic-gate 	/* if we get to here, then the SAP is legal enough */
39520Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
39530Sstevel@tonic-gate 	gld->gld_state = DL_IDLE;	/* bound and ready */
39540Sstevel@tonic-gate 	gld->gld_sap = sap;
39550Sstevel@tonic-gate 	gld_set_ipq(gld);
39560Sstevel@tonic-gate 
39570Sstevel@tonic-gate #ifdef GLD_DEBUG
39580Sstevel@tonic-gate 	if (gld_debug & GLDPROT)
39590Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_bind: ok - sap = %d", gld->gld_sap);
39600Sstevel@tonic-gate #endif
39610Sstevel@tonic-gate 
39620Sstevel@tonic-gate 	/* ACK the BIND */
39630Sstevel@tonic-gate 	mp = gld_bindack(q, mp);
39640Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
39650Sstevel@tonic-gate 
39660Sstevel@tonic-gate 	if (mp != NULL) {
39670Sstevel@tonic-gate 		qreply(q, mp);
39680Sstevel@tonic-gate 		return (GLDE_OK);
39690Sstevel@tonic-gate 	}
39700Sstevel@tonic-gate 
39710Sstevel@tonic-gate 	return (DL_SYSERR);
39720Sstevel@tonic-gate }
39730Sstevel@tonic-gate 
39740Sstevel@tonic-gate /*
39750Sstevel@tonic-gate  * gld_unbind - perform an unbind of an LSAP or ether type on the stream.
39760Sstevel@tonic-gate  * The stream is still open and can be re-bound.
39770Sstevel@tonic-gate  */
39780Sstevel@tonic-gate static int
39790Sstevel@tonic-gate gld_unbind(queue_t *q, mblk_t *mp)
39800Sstevel@tonic-gate {
39810Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
39820Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
39830Sstevel@tonic-gate 
39840Sstevel@tonic-gate 	ASSERT(gld);
39850Sstevel@tonic-gate 
39860Sstevel@tonic-gate #ifdef GLD_DEBUG
39870Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
39880Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_unbind(%p %p)", (void *)q, (void *)mp);
39890Sstevel@tonic-gate #endif
39900Sstevel@tonic-gate 
39910Sstevel@tonic-gate 	if (gld->gld_state != DL_IDLE) {
39920Sstevel@tonic-gate #ifdef GLD_DEBUG
39930Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
39940Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unbind: wrong state (%d)",
39950Sstevel@tonic-gate 				gld->gld_state);
39960Sstevel@tonic-gate #endif
39970Sstevel@tonic-gate 		return (DL_OUTSTATE);
39980Sstevel@tonic-gate 	}
39990Sstevel@tonic-gate 	ASSERT(macinfo);
40000Sstevel@tonic-gate 
40010Sstevel@tonic-gate 	/*
40020Sstevel@tonic-gate 	 * Avoid unbinding (DL_UNBIND_REQ) while FAST/RAW is inside wput.
40030Sstevel@tonic-gate 	 * See comments above gld_start().
40040Sstevel@tonic-gate 	 */
40050Sstevel@tonic-gate 	gld->gld_in_unbind = B_TRUE;	/* disallow wput=>start */
40060Sstevel@tonic-gate 	membar_enter();
40070Sstevel@tonic-gate 	if (gld->gld_wput_count != 0) {
40080Sstevel@tonic-gate 		gld->gld_in_unbind = B_FALSE;
40090Sstevel@tonic-gate 		ASSERT(mp);		/* we didn't come from close */
40100Sstevel@tonic-gate #ifdef GLD_DEBUG
40110Sstevel@tonic-gate 		if (gld_debug & GLDETRACE)
40120Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unbind: defer for wput");
40130Sstevel@tonic-gate #endif
40140Sstevel@tonic-gate 		(void) putbq(q, mp);
40150Sstevel@tonic-gate 		qenable(q);		/* try again soon */
40160Sstevel@tonic-gate 		return (GLDE_RETRY);
40170Sstevel@tonic-gate 	}
40180Sstevel@tonic-gate 
40190Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
40200Sstevel@tonic-gate 	gld->gld_state = DL_UNBOUND;
40210Sstevel@tonic-gate 	gld->gld_sap = 0;
40220Sstevel@tonic-gate 	gld_set_ipq(gld);
40230Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
40240Sstevel@tonic-gate 
40250Sstevel@tonic-gate 	membar_exit();
40260Sstevel@tonic-gate 	gld->gld_in_unbind = B_FALSE;
40270Sstevel@tonic-gate 
40280Sstevel@tonic-gate 	/* mp is NULL if we came from close */
40290Sstevel@tonic-gate 	if (mp) {
40300Sstevel@tonic-gate 		gld_flushqueue(q);	/* flush the queues */
40310Sstevel@tonic-gate 		dlokack(q, mp, DL_UNBIND_REQ);
40320Sstevel@tonic-gate 	}
40330Sstevel@tonic-gate 	return (GLDE_OK);
40340Sstevel@tonic-gate }
40350Sstevel@tonic-gate 
40360Sstevel@tonic-gate /*
40370Sstevel@tonic-gate  * gld_inforeq - generate the response to an info request
40380Sstevel@tonic-gate  */
40390Sstevel@tonic-gate static int
40400Sstevel@tonic-gate gld_inforeq(queue_t *q, mblk_t *mp)
40410Sstevel@tonic-gate {
40420Sstevel@tonic-gate 	gld_t		*gld;
40430Sstevel@tonic-gate 	dl_info_ack_t	*dlp;
40440Sstevel@tonic-gate 	int		bufsize;
40450Sstevel@tonic-gate 	glddev_t	*glddev;
40460Sstevel@tonic-gate 	gld_mac_info_t	*macinfo;
40470Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt;
40480Sstevel@tonic-gate 	int		sel_offset = 0;
40490Sstevel@tonic-gate 	int		range_offset = 0;
40500Sstevel@tonic-gate 	int		addr_offset;
40510Sstevel@tonic-gate 	int		addr_length;
40520Sstevel@tonic-gate 	int		sap_length;
40530Sstevel@tonic-gate 	int		brdcst_offset;
40540Sstevel@tonic-gate 	int		brdcst_length;
40550Sstevel@tonic-gate 	gld_vlan_t	*vlan;
40560Sstevel@tonic-gate 	uchar_t		*sapp;
40570Sstevel@tonic-gate 
40580Sstevel@tonic-gate #ifdef GLD_DEBUG
40590Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
40600Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_inforeq(%p %p)", (void *)q, (void *)mp);
40610Sstevel@tonic-gate #endif
40620Sstevel@tonic-gate 	gld = (gld_t *)q->q_ptr;
40630Sstevel@tonic-gate 	ASSERT(gld);
40640Sstevel@tonic-gate 	glddev = gld->gld_device;
40650Sstevel@tonic-gate 	ASSERT(glddev);
40660Sstevel@tonic-gate 
40670Sstevel@tonic-gate 	if (gld->gld_state == DL_IDLE || gld->gld_state == DL_UNBOUND) {
40680Sstevel@tonic-gate 		macinfo = gld->gld_mac_info;
40690Sstevel@tonic-gate 		ASSERT(macinfo != NULL);
40700Sstevel@tonic-gate 
40710Sstevel@tonic-gate 		mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
40720Sstevel@tonic-gate 
40730Sstevel@tonic-gate 		addr_length = macinfo->gldm_addrlen;
40740Sstevel@tonic-gate 		sap_length = macinfo->gldm_saplen;
40750Sstevel@tonic-gate 		brdcst_length = macinfo->gldm_addrlen;
40760Sstevel@tonic-gate 	} else {
40770Sstevel@tonic-gate 		addr_length = glddev->gld_addrlen;
40780Sstevel@tonic-gate 		sap_length = glddev->gld_saplen;
40790Sstevel@tonic-gate 		brdcst_length = glddev->gld_addrlen;
40800Sstevel@tonic-gate 	}
40810Sstevel@tonic-gate 
40820Sstevel@tonic-gate 	bufsize = sizeof (dl_info_ack_t);
40830Sstevel@tonic-gate 
40840Sstevel@tonic-gate 	addr_offset = bufsize;
40850Sstevel@tonic-gate 	bufsize += addr_length;
40860Sstevel@tonic-gate 	bufsize += abs(sap_length);
40870Sstevel@tonic-gate 
40880Sstevel@tonic-gate 	brdcst_offset = bufsize;
40890Sstevel@tonic-gate 	bufsize += brdcst_length;
40900Sstevel@tonic-gate 
40910Sstevel@tonic-gate 	if ((vlan = (gld_vlan_t *)gld->gld_vlan) != NULL &&
40920Sstevel@tonic-gate 	    vlan->gldv_id != VLAN_VID_NONE) {
40930Sstevel@tonic-gate 		sel_offset = P2ROUNDUP(bufsize, sizeof (int64_t));
40940Sstevel@tonic-gate 		bufsize = sel_offset + sizeof (dl_qos_cl_sel1_t);
40950Sstevel@tonic-gate 
40960Sstevel@tonic-gate 		range_offset = P2ROUNDUP(bufsize, sizeof (int64_t));
40970Sstevel@tonic-gate 		bufsize = range_offset + sizeof (dl_qos_cl_range1_t);
40980Sstevel@tonic-gate 	}
40990Sstevel@tonic-gate 
41000Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, bufsize, M_PCPROTO, DL_INFO_ACK)) == NULL)
41010Sstevel@tonic-gate 		return (GLDE_OK);	/* nothing more to be done */
41020Sstevel@tonic-gate 
41030Sstevel@tonic-gate 	bzero(mp->b_rptr, bufsize);
41040Sstevel@tonic-gate 
41050Sstevel@tonic-gate 	dlp = (dl_info_ack_t *)mp->b_rptr;
41060Sstevel@tonic-gate 	dlp->dl_primitive = DL_INFO_ACK;
41070Sstevel@tonic-gate 	dlp->dl_version = DL_VERSION_2;
41080Sstevel@tonic-gate 	dlp->dl_service_mode = DL_CLDLS;
41090Sstevel@tonic-gate 	dlp->dl_current_state = gld->gld_state;
41100Sstevel@tonic-gate 	dlp->dl_provider_style = gld->gld_style;
41110Sstevel@tonic-gate 
41120Sstevel@tonic-gate 	if (sel_offset != 0) {
41130Sstevel@tonic-gate 		dl_qos_cl_sel1_t	*selp;
41140Sstevel@tonic-gate 		dl_qos_cl_range1_t	*rangep;
41150Sstevel@tonic-gate 
41160Sstevel@tonic-gate 		ASSERT(range_offset != 0);
41170Sstevel@tonic-gate 
41180Sstevel@tonic-gate 		dlp->dl_qos_offset = sel_offset;
41190Sstevel@tonic-gate 		dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t);
41200Sstevel@tonic-gate 		dlp->dl_qos_range_offset = range_offset;
41210Sstevel@tonic-gate 		dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t);
41220Sstevel@tonic-gate 
41230Sstevel@tonic-gate 		selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + sel_offset);
41240Sstevel@tonic-gate 		selp->dl_qos_type = DL_QOS_CL_SEL1;
41250Sstevel@tonic-gate 		selp->dl_priority = gld->gld_upri;
41260Sstevel@tonic-gate 
41270Sstevel@tonic-gate 		rangep = (dl_qos_cl_range1_t *)(mp->b_rptr + range_offset);
41280Sstevel@tonic-gate 		rangep->dl_qos_type = DL_QOS_CL_RANGE1;
41290Sstevel@tonic-gate 		rangep->dl_priority.dl_min = 0;
41300Sstevel@tonic-gate 		rangep->dl_priority.dl_max = 7;
41310Sstevel@tonic-gate 	}
41320Sstevel@tonic-gate 
41330Sstevel@tonic-gate 	if (gld->gld_state == DL_IDLE || gld->gld_state == DL_UNBOUND) {
41340Sstevel@tonic-gate 		dlp->dl_min_sdu = macinfo->gldm_minpkt;
41350Sstevel@tonic-gate 		dlp->dl_max_sdu = macinfo->gldm_maxpkt;
41360Sstevel@tonic-gate 		dlp->dl_mac_type = macinfo->gldm_type;
41370Sstevel@tonic-gate 		dlp->dl_addr_length = addr_length + abs(sap_length);
41380Sstevel@tonic-gate 		dlp->dl_sap_length = sap_length;
41390Sstevel@tonic-gate 
41400Sstevel@tonic-gate 		if (gld->gld_state == DL_IDLE) {
41410Sstevel@tonic-gate 			/*
41420Sstevel@tonic-gate 			 * If we are bound to a non-LLC SAP on any medium
41430Sstevel@tonic-gate 			 * other than Ethernet, then we need room for a
41440Sstevel@tonic-gate 			 * SNAP header.  So we have to adjust the MTU size
41450Sstevel@tonic-gate 			 * accordingly.  XXX I suppose this should be done
41460Sstevel@tonic-gate 			 * in gldutil.c, but it seems likely that this will
41470Sstevel@tonic-gate 			 * always be true for everything GLD supports but
41480Sstevel@tonic-gate 			 * Ethernet.  Check this if you add another medium.
41490Sstevel@tonic-gate 			 */
41500Sstevel@tonic-gate 			if ((macinfo->gldm_type == DL_TPR ||
41510Sstevel@tonic-gate 			    macinfo->gldm_type == DL_FDDI) &&
41520Sstevel@tonic-gate 			    gld->gld_ethertype)
41530Sstevel@tonic-gate 				dlp->dl_max_sdu -= LLC_SNAP_HDR_LEN;
41540Sstevel@tonic-gate 
41550Sstevel@tonic-gate 			/* copy macaddr and sap */
41560Sstevel@tonic-gate 			dlp->dl_addr_offset = addr_offset;
41570Sstevel@tonic-gate 
41580Sstevel@tonic-gate 			mac_copy(mac_pvt->curr_macaddr, mp->b_rptr +
41590Sstevel@tonic-gate 			    addr_offset, macinfo->gldm_addrlen);
41600Sstevel@tonic-gate 			sapp = mp->b_rptr + addr_offset +
41610Sstevel@tonic-gate 			    macinfo->gldm_addrlen;
41620Sstevel@tonic-gate 			*(ushort_t *)sapp = gld->gld_sap;
41630Sstevel@tonic-gate 		} else {
41640Sstevel@tonic-gate 			dlp->dl_addr_offset = 0;
41650Sstevel@tonic-gate 		}
41660Sstevel@tonic-gate 
41670Sstevel@tonic-gate 		/* copy broadcast addr */
41680Sstevel@tonic-gate 		dlp->dl_brdcst_addr_length = macinfo->gldm_addrlen;
41690Sstevel@tonic-gate 		dlp->dl_brdcst_addr_offset = brdcst_offset;
41700Sstevel@tonic-gate 		mac_copy((caddr_t)macinfo->gldm_broadcast_addr,
41710Sstevel@tonic-gate 		    mp->b_rptr + brdcst_offset, brdcst_length);
41720Sstevel@tonic-gate 	} else {
41730Sstevel@tonic-gate 		/*
41740Sstevel@tonic-gate 		 * No PPA is attached.
41750Sstevel@tonic-gate 		 * The best we can do is use the values provided
41760Sstevel@tonic-gate 		 * by the first mac that called gld_register.
41770Sstevel@tonic-gate 		 */
41780Sstevel@tonic-gate 		dlp->dl_min_sdu = glddev->gld_minsdu;
41790Sstevel@tonic-gate 		dlp->dl_max_sdu = glddev->gld_maxsdu;
41800Sstevel@tonic-gate 		dlp->dl_mac_type = glddev->gld_type;
41810Sstevel@tonic-gate 		dlp->dl_addr_length = addr_length + abs(sap_length);
41820Sstevel@tonic-gate 		dlp->dl_sap_length = sap_length;
41830Sstevel@tonic-gate 		dlp->dl_addr_offset = 0;
41840Sstevel@tonic-gate 		dlp->dl_brdcst_addr_offset = brdcst_offset;
41850Sstevel@tonic-gate 		dlp->dl_brdcst_addr_length = brdcst_length;
41860Sstevel@tonic-gate 		mac_copy((caddr_t)glddev->gld_broadcast,
41870Sstevel@tonic-gate 		    mp->b_rptr + brdcst_offset, brdcst_length);
41880Sstevel@tonic-gate 	}
41890Sstevel@tonic-gate 	qreply(q, mp);
41900Sstevel@tonic-gate 	return (GLDE_OK);
41910Sstevel@tonic-gate }
41920Sstevel@tonic-gate 
41930Sstevel@tonic-gate /*
41940Sstevel@tonic-gate  * gld_unitdata (q, mp)
41950Sstevel@tonic-gate  * send a datagram.  Destination address/lsap is in M_PROTO
41960Sstevel@tonic-gate  * message (first mblock), data is in remainder of message.
41970Sstevel@tonic-gate  *
41980Sstevel@tonic-gate  */
41990Sstevel@tonic-gate static int
42000Sstevel@tonic-gate gld_unitdata(queue_t *q, mblk_t *mp)
42010Sstevel@tonic-gate {
42020Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
42030Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
42040Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
42050Sstevel@tonic-gate 	size_t	msglen;
42060Sstevel@tonic-gate 	mblk_t	*nmp;
42070Sstevel@tonic-gate 	gld_interface_t *ifp;
42080Sstevel@tonic-gate 	uint32_t start;
42090Sstevel@tonic-gate 	uint32_t stuff;
42100Sstevel@tonic-gate 	uint32_t end;
42110Sstevel@tonic-gate 	uint32_t value;
42120Sstevel@tonic-gate 	uint32_t flags;
42130Sstevel@tonic-gate 	uint32_t upri;
42140Sstevel@tonic-gate 
42150Sstevel@tonic-gate #ifdef GLD_DEBUG
42160Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
42170Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_unitdata(%p %p)", (void *)q, (void *)mp);
42180Sstevel@tonic-gate #endif
42190Sstevel@tonic-gate 
42200Sstevel@tonic-gate 	if (gld->gld_state != DL_IDLE) {
42210Sstevel@tonic-gate #ifdef GLD_DEBUG
42220Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
42230Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unitdata: wrong state (%d)",
42240Sstevel@tonic-gate 				gld->gld_state);
42250Sstevel@tonic-gate #endif
42260Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
42270Sstevel@tonic-gate 		    dlp->dl_dest_addr_length, DL_OUTSTATE, 0);
42280Sstevel@tonic-gate 		return (GLDE_OK);
42290Sstevel@tonic-gate 	}
42300Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
42310Sstevel@tonic-gate 
42320Sstevel@tonic-gate 	if (!MBLKIN(mp, dlp->dl_dest_addr_offset, dlp->dl_dest_addr_length) ||
42330Sstevel@tonic-gate 	    dlp->dl_dest_addr_length !=
42340Sstevel@tonic-gate 	    macinfo->gldm_addrlen + abs(macinfo->gldm_saplen)) {
42350Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
42360Sstevel@tonic-gate 		    dlp->dl_dest_addr_length, DL_BADADDR, 0);
42370Sstevel@tonic-gate 		return (GLDE_OK);
42380Sstevel@tonic-gate 	}
42390Sstevel@tonic-gate 
42400Sstevel@tonic-gate 	upri = dlp->dl_priority.dl_max;
42410Sstevel@tonic-gate 
42420Sstevel@tonic-gate 	msglen = msgdsize(mp);
42430Sstevel@tonic-gate 	if (msglen == 0 || msglen > macinfo->gldm_maxpkt) {
42440Sstevel@tonic-gate #ifdef GLD_DEBUG
42450Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
42460Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unitdata: bad msglen (%d)",
42470Sstevel@tonic-gate 				(int)msglen);
42480Sstevel@tonic-gate #endif
42490Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
42500Sstevel@tonic-gate 		    dlp->dl_dest_addr_length, DL_BADDATA, 0);
42510Sstevel@tonic-gate 		return (GLDE_OK);
42520Sstevel@tonic-gate 	}
42530Sstevel@tonic-gate 
42540Sstevel@tonic-gate 	ASSERT(mp->b_cont != NULL);	/* because msgdsize(mp) is nonzero */
42550Sstevel@tonic-gate 
42560Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
42570Sstevel@tonic-gate 
42580Sstevel@tonic-gate 	/* grab any checksum information that may be present */
42590Sstevel@tonic-gate 	hcksum_retrieve(mp->b_cont, NULL, NULL, &start, &stuff, &end,
42600Sstevel@tonic-gate 	    &value, &flags);
42610Sstevel@tonic-gate 
42620Sstevel@tonic-gate 	/*
42630Sstevel@tonic-gate 	 * Prepend a valid header for transmission
42640Sstevel@tonic-gate 	 */
42650Sstevel@tonic-gate 	if ((nmp = (*ifp->mkunitdata)(gld, mp)) == NULL) {
42660Sstevel@tonic-gate #ifdef GLD_DEBUG
42670Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
42680Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unitdata: mkunitdata failed.");
42690Sstevel@tonic-gate #endif
42700Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
42710Sstevel@tonic-gate 		    dlp->dl_dest_addr_length, DL_SYSERR, ENOSR);
42720Sstevel@tonic-gate 		return (GLDE_OK);
42730Sstevel@tonic-gate 	}
42740Sstevel@tonic-gate 
42750Sstevel@tonic-gate 	/* apply any checksum information to the first block in the chain */
42760Sstevel@tonic-gate 	(void) hcksum_assoc(nmp, NULL, NULL, start, stuff, end, value,
42770Sstevel@tonic-gate 	    flags, 0);
42780Sstevel@tonic-gate 
42790Sstevel@tonic-gate 	if (gld_start(q, nmp, GLD_WSRV, upri) == GLD_NORESOURCES) {
42800Sstevel@tonic-gate 		qenable(q);
42810Sstevel@tonic-gate 		return (GLDE_RETRY);
42820Sstevel@tonic-gate 	}
42830Sstevel@tonic-gate 
42840Sstevel@tonic-gate 	return (GLDE_OK);
42850Sstevel@tonic-gate }
42860Sstevel@tonic-gate 
42870Sstevel@tonic-gate /*
42880Sstevel@tonic-gate  * gldattach(q, mp)
42890Sstevel@tonic-gate  * DLPI DL_ATTACH_REQ
42900Sstevel@tonic-gate  * this attaches the stream to a PPA
42910Sstevel@tonic-gate  */
42920Sstevel@tonic-gate static int
42930Sstevel@tonic-gate gldattach(queue_t *q, mblk_t *mp)
42940Sstevel@tonic-gate {
42950Sstevel@tonic-gate 	dl_attach_req_t *at;
42960Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
42970Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
42980Sstevel@tonic-gate 	glddev_t *glddev;
42990Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
43000Sstevel@tonic-gate 	uint32_t ppa;
43010Sstevel@tonic-gate 	uint32_t vid;
43020Sstevel@tonic-gate 	gld_vlan_t *vlan;
43030Sstevel@tonic-gate 
43040Sstevel@tonic-gate 	at = (dl_attach_req_t *)mp->b_rptr;
43050Sstevel@tonic-gate 
43060Sstevel@tonic-gate 	if (gld->gld_state != DL_UNATTACHED)
43070Sstevel@tonic-gate 		return (DL_OUTSTATE);
43080Sstevel@tonic-gate 
43090Sstevel@tonic-gate 	ASSERT(!gld->gld_mac_info);
43100Sstevel@tonic-gate 
43110Sstevel@tonic-gate 	ppa = at->dl_ppa % GLD_VLAN_SCALE;	/* 0 .. 999	*/
43120Sstevel@tonic-gate 	vid = at->dl_ppa / GLD_VLAN_SCALE;	/* 0 .. 4094	*/
43130Sstevel@tonic-gate 	if (vid > VLAN_VID_MAX)
43140Sstevel@tonic-gate 		return (DL_BADPPA);
43150Sstevel@tonic-gate 
43160Sstevel@tonic-gate 	glddev = gld->gld_device;
43170Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
43180Sstevel@tonic-gate 	for (macinfo = glddev->gld_mac_next;
43190Sstevel@tonic-gate 	    macinfo != (gld_mac_info_t *)&glddev->gld_mac_next;
43200Sstevel@tonic-gate 	    macinfo = macinfo->gldm_next) {
43210Sstevel@tonic-gate 		int inst;
43220Sstevel@tonic-gate 
43230Sstevel@tonic-gate 		ASSERT(macinfo != NULL);
43240Sstevel@tonic-gate 		if (macinfo->gldm_ppa != ppa)
43250Sstevel@tonic-gate 			continue;
43260Sstevel@tonic-gate 
43270Sstevel@tonic-gate 		if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY))
43280Sstevel@tonic-gate 			continue;	/* this one's not ready yet */
43290Sstevel@tonic-gate 
43300Sstevel@tonic-gate 		/*
43310Sstevel@tonic-gate 		 * VLAN sanity check
43320Sstevel@tonic-gate 		 */
43330Sstevel@tonic-gate 		if (vid != VLAN_VID_NONE && !VLAN_CAPABLE(macinfo)) {
43340Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
43350Sstevel@tonic-gate 			return (DL_BADPPA);
43360Sstevel@tonic-gate 		}
43370Sstevel@tonic-gate 
43380Sstevel@tonic-gate 		/*
43390Sstevel@tonic-gate 		 * We found the correct PPA, hold the instance
43400Sstevel@tonic-gate 		 */
43410Sstevel@tonic-gate 		inst = ddi_get_instance(macinfo->gldm_devinfo);
43420Sstevel@tonic-gate 		if (inst == -1 || qassociate(q, inst) != 0) {
43430Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
43440Sstevel@tonic-gate 			return (DL_BADPPA);
43450Sstevel@tonic-gate 		}
43460Sstevel@tonic-gate 
43470Sstevel@tonic-gate 		/* Take the stream off the per-driver-class list */
43480Sstevel@tonic-gate 		gldremque(gld);
43490Sstevel@tonic-gate 
43500Sstevel@tonic-gate 		/*
43510Sstevel@tonic-gate 		 * We must hold the lock to prevent multiple calls
43520Sstevel@tonic-gate 		 * to the reset and start routines.
43530Sstevel@tonic-gate 		 */
43540Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
43550Sstevel@tonic-gate 
43560Sstevel@tonic-gate 		gld->gld_mac_info = macinfo;
43570Sstevel@tonic-gate 
43580Sstevel@tonic-gate 		if (macinfo->gldm_send_tagged != NULL)
43590Sstevel@tonic-gate 			gld->gld_send = macinfo->gldm_send_tagged;
43600Sstevel@tonic-gate 		else
43610Sstevel@tonic-gate 			gld->gld_send = macinfo->gldm_send;
43620Sstevel@tonic-gate 
43630Sstevel@tonic-gate 		if ((vlan = gld_get_vlan(macinfo, vid)) == NULL) {
43640Sstevel@tonic-gate 			GLDM_UNLOCK(macinfo);
43650Sstevel@tonic-gate 			gldinsque(gld, glddev->gld_str_prev);
43660Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
43670Sstevel@tonic-gate 			(void) qassociate(q, -1);
43680Sstevel@tonic-gate 			return (DL_BADPPA);
43690Sstevel@tonic-gate 		}
43700Sstevel@tonic-gate 
43710Sstevel@tonic-gate 		mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
43720Sstevel@tonic-gate 		if (!mac_pvt->started) {
43730Sstevel@tonic-gate 			if (gld_start_mac(macinfo) != GLD_SUCCESS) {
43740Sstevel@tonic-gate 				gld_rem_vlan(vlan);
43750Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
43760Sstevel@tonic-gate 				gldinsque(gld, glddev->gld_str_prev);
43770Sstevel@tonic-gate 				mutex_exit(&glddev->gld_devlock);
43780Sstevel@tonic-gate 				dlerrorack(q, mp, DL_ATTACH_REQ, DL_SYSERR,
43790Sstevel@tonic-gate 				    EIO);
43800Sstevel@tonic-gate 				(void) qassociate(q, -1);
43810Sstevel@tonic-gate 				return (GLDE_OK);
43820Sstevel@tonic-gate 			}
43830Sstevel@tonic-gate 		}
43840Sstevel@tonic-gate 
43850Sstevel@tonic-gate 		gld->gld_vlan = vlan;
43860Sstevel@tonic-gate 		vlan->gldv_nstreams++;
43870Sstevel@tonic-gate 		gldinsque(gld, vlan->gldv_str_prev);
43880Sstevel@tonic-gate 		gld->gld_state = DL_UNBOUND;
43890Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
43900Sstevel@tonic-gate 
43910Sstevel@tonic-gate #ifdef GLD_DEBUG
43920Sstevel@tonic-gate 		if (gld_debug & GLDPROT) {
43930Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gldattach(%p, %p, PPA = %d)",
43940Sstevel@tonic-gate 			    (void *)q, (void *)mp, macinfo->gldm_ppa);
43950Sstevel@tonic-gate 		}
43960Sstevel@tonic-gate #endif
43970Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
43980Sstevel@tonic-gate 		dlokack(q, mp, DL_ATTACH_REQ);
43990Sstevel@tonic-gate 		return (GLDE_OK);
44000Sstevel@tonic-gate 	}
44010Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
44020Sstevel@tonic-gate 	return (DL_BADPPA);
44030Sstevel@tonic-gate }
44040Sstevel@tonic-gate 
44050Sstevel@tonic-gate /*
44060Sstevel@tonic-gate  * gldunattach(q, mp)
44070Sstevel@tonic-gate  * DLPI DL_DETACH_REQ
44080Sstevel@tonic-gate  * detaches the mac layer from the stream
44090Sstevel@tonic-gate  */
44100Sstevel@tonic-gate int
44110Sstevel@tonic-gate gldunattach(queue_t *q, mblk_t *mp)
44120Sstevel@tonic-gate {
44130Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
44140Sstevel@tonic-gate 	glddev_t *glddev = gld->gld_device;
44150Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
44160Sstevel@tonic-gate 	int	state = gld->gld_state;
44170Sstevel@tonic-gate 	int	i;
44180Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
44190Sstevel@tonic-gate 	gld_vlan_t *vlan;
44200Sstevel@tonic-gate 	boolean_t phys_off;
44210Sstevel@tonic-gate 	boolean_t mult_off;
44220Sstevel@tonic-gate 	int op = GLD_MAC_PROMISC_NOOP;
44230Sstevel@tonic-gate 
44240Sstevel@tonic-gate 	if (state != DL_UNBOUND)
44250Sstevel@tonic-gate 		return (DL_OUTSTATE);
44260Sstevel@tonic-gate 
44270Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
44280Sstevel@tonic-gate 	ASSERT(gld->gld_sap == 0);
44290Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
44300Sstevel@tonic-gate 
44310Sstevel@tonic-gate #ifdef GLD_DEBUG
44320Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
44330Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gldunattach(%p, %p, PPA = %d)",
44340Sstevel@tonic-gate 		    (void *)q, (void *)mp, macinfo->gldm_ppa);
44350Sstevel@tonic-gate 	}
44360Sstevel@tonic-gate #endif
44370Sstevel@tonic-gate 
44380Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
44390Sstevel@tonic-gate 
44400Sstevel@tonic-gate 	if (gld->gld_mcast) {
44410Sstevel@tonic-gate 		for (i = 0; i < gld->gld_multicnt; i++) {
44420Sstevel@tonic-gate 			gld_mcast_t *mcast;
44430Sstevel@tonic-gate 
44440Sstevel@tonic-gate 			if ((mcast = gld->gld_mcast[i]) != NULL) {
44450Sstevel@tonic-gate 				ASSERT(mcast->gldm_refcnt);
44460Sstevel@tonic-gate 				gld_send_disable_multi(macinfo, mcast);
44470Sstevel@tonic-gate 			}
44480Sstevel@tonic-gate 		}
44490Sstevel@tonic-gate 		kmem_free(gld->gld_mcast,
44500Sstevel@tonic-gate 		    sizeof (gld_mcast_t *) * gld->gld_multicnt);
44510Sstevel@tonic-gate 		gld->gld_mcast = NULL;
44520Sstevel@tonic-gate 		gld->gld_multicnt = 0;
44530Sstevel@tonic-gate 	}
44540Sstevel@tonic-gate 
44550Sstevel@tonic-gate 	/* decide if we need to turn off any promiscuity */
44560Sstevel@tonic-gate 	phys_off = (gld->gld_flags & GLD_PROM_PHYS &&
44570Sstevel@tonic-gate 	    --mac_pvt->nprom == 0);
44580Sstevel@tonic-gate 	mult_off = (gld->gld_flags & GLD_PROM_MULT &&
44590Sstevel@tonic-gate 	    --mac_pvt->nprom_multi == 0);
44600Sstevel@tonic-gate 
44610Sstevel@tonic-gate 	gld->gld_flags &= ~(GLD_PROM_PHYS | GLD_PROM_SAP | GLD_PROM_MULT);
44620Sstevel@tonic-gate 
44630Sstevel@tonic-gate 	if (phys_off) {
44640Sstevel@tonic-gate 		op = (mac_pvt->nprom_multi == 0) ? GLD_MAC_PROMISC_NONE :
44650Sstevel@tonic-gate 		    GLD_MAC_PROMISC_MULTI;
44660Sstevel@tonic-gate 	} else if (mult_off) {
44670Sstevel@tonic-gate 		op = (mac_pvt->nprom == 0) ? GLD_MAC_PROMISC_NONE :
44680Sstevel@tonic-gate 		    GLD_MAC_PROMISC_NOOP;	/* phys overrides multi */
44690Sstevel@tonic-gate 	}
44700Sstevel@tonic-gate 
44710Sstevel@tonic-gate 	if (op != GLD_MAC_PROMISC_NOOP)
44720Sstevel@tonic-gate 		(void) (*macinfo->gldm_set_promiscuous)(macinfo, op);
44730Sstevel@tonic-gate 
44740Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
44750Sstevel@tonic-gate 
44760Sstevel@tonic-gate 	if (phys_off)
44770Sstevel@tonic-gate 		gld_notify_ind(macinfo, DL_NOTE_PROMISC_OFF_PHYS, NULL);
44780Sstevel@tonic-gate 
44790Sstevel@tonic-gate 	/*
44800Sstevel@tonic-gate 	 * We need to hold both locks when modifying the mac stream list
44810Sstevel@tonic-gate 	 * to protect findminor as well as everyone else.
44820Sstevel@tonic-gate 	 */
44830Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
44840Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
44850Sstevel@tonic-gate 
44860Sstevel@tonic-gate 	/* disassociate this stream with its vlan and underlying mac */
44870Sstevel@tonic-gate 	gldremque(gld);
44880Sstevel@tonic-gate 
44890Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
44900Sstevel@tonic-gate 	if (--vlan->gldv_nstreams == 0) {
44910Sstevel@tonic-gate 		gld_rem_vlan(vlan);
44920Sstevel@tonic-gate 		gld->gld_vlan = NULL;
44930Sstevel@tonic-gate 	}
44940Sstevel@tonic-gate 
44950Sstevel@tonic-gate 	gld->gld_mac_info = NULL;
44960Sstevel@tonic-gate 	gld->gld_state = DL_UNATTACHED;
44970Sstevel@tonic-gate 
44980Sstevel@tonic-gate 	/* cleanup mac layer if last vlan */
44990Sstevel@tonic-gate 	if (mac_pvt->nvlan == 0) {
45000Sstevel@tonic-gate 		gld_stop_mac(macinfo);
45010Sstevel@tonic-gate 		macinfo->gldm_GLD_flags &= ~GLD_INTR_WAIT;
45020Sstevel@tonic-gate 	}
45030Sstevel@tonic-gate 
45040Sstevel@tonic-gate 	/* make sure no references to this gld for gld_v0_sched */
45050Sstevel@tonic-gate 	if (mac_pvt->last_sched == gld)
45060Sstevel@tonic-gate 		mac_pvt->last_sched = NULL;
45070Sstevel@tonic-gate 
45080Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
45090Sstevel@tonic-gate 
45100Sstevel@tonic-gate 	/* put the stream on the unattached Style 2 list */
45110Sstevel@tonic-gate 	gldinsque(gld, glddev->gld_str_prev);
45120Sstevel@tonic-gate 
45130Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
45140Sstevel@tonic-gate 
45150Sstevel@tonic-gate 	/* There will be no mp if we were called from close */
45160Sstevel@tonic-gate 	if (mp) {
45170Sstevel@tonic-gate 		dlokack(q, mp, DL_DETACH_REQ);
45180Sstevel@tonic-gate 	}
45190Sstevel@tonic-gate 	if (gld->gld_style == DL_STYLE2)
45200Sstevel@tonic-gate 		(void) qassociate(q, -1);
45210Sstevel@tonic-gate 	return (GLDE_OK);
45220Sstevel@tonic-gate }
45230Sstevel@tonic-gate 
45240Sstevel@tonic-gate /*
45250Sstevel@tonic-gate  * gld_enable_multi (q, mp)
45260Sstevel@tonic-gate  * Enables multicast address on the stream.  If the mac layer
45270Sstevel@tonic-gate  * isn't enabled for this address, enable at that level as well.
45280Sstevel@tonic-gate  */
45290Sstevel@tonic-gate static int
45300Sstevel@tonic-gate gld_enable_multi(queue_t *q, mblk_t *mp)
45310Sstevel@tonic-gate {
45320Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
45330Sstevel@tonic-gate 	glddev_t *glddev;
45340Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
45350Sstevel@tonic-gate 	unsigned char *maddr;
45360Sstevel@tonic-gate 	dl_enabmulti_req_t *multi;
45370Sstevel@tonic-gate 	gld_mcast_t *mcast;
45380Sstevel@tonic-gate 	int	i, rc;
45390Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
45400Sstevel@tonic-gate 
45410Sstevel@tonic-gate #ifdef GLD_DEBUG
45420Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
45430Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_enable_multi(%p, %p)", (void *)q,
45440Sstevel@tonic-gate 		    (void *)mp);
45450Sstevel@tonic-gate 	}
45460Sstevel@tonic-gate #endif
45470Sstevel@tonic-gate 
45480Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
45490Sstevel@tonic-gate 		return (DL_OUTSTATE);
45500Sstevel@tonic-gate 
45510Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
45520Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
45530Sstevel@tonic-gate 
45540Sstevel@tonic-gate 	if (macinfo->gldm_set_multicast == NULL) {
45550Sstevel@tonic-gate 		return (DL_UNSUPPORTED);
45560Sstevel@tonic-gate 	}
45570Sstevel@tonic-gate 
45580Sstevel@tonic-gate 	multi = (dl_enabmulti_req_t *)mp->b_rptr;
45590Sstevel@tonic-gate 
45600Sstevel@tonic-gate 	if (!MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length) ||
45610Sstevel@tonic-gate 	    multi->dl_addr_length != macinfo->gldm_addrlen)
45620Sstevel@tonic-gate 		return (DL_BADADDR);
45630Sstevel@tonic-gate 
45640Sstevel@tonic-gate 	/* request appears to be valid */
45650Sstevel@tonic-gate 
45660Sstevel@tonic-gate 	glddev = mac_pvt->major_dev;
45670Sstevel@tonic-gate 	ASSERT(glddev == gld->gld_device);
45680Sstevel@tonic-gate 
45690Sstevel@tonic-gate 	maddr = mp->b_rptr + multi->dl_addr_offset;
45700Sstevel@tonic-gate 
45710Sstevel@tonic-gate 	/*
45720Sstevel@tonic-gate 	 * The multicast addresses live in a per-device table, along
45730Sstevel@tonic-gate 	 * with a reference count.  Each stream has a table that
45740Sstevel@tonic-gate 	 * points to entries in the device table, with the reference
45750Sstevel@tonic-gate 	 * count reflecting the number of streams pointing at it.  If
45760Sstevel@tonic-gate 	 * this multicast address is already in the per-device table,
45770Sstevel@tonic-gate 	 * all we have to do is point at it.
45780Sstevel@tonic-gate 	 */
45790Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
45800Sstevel@tonic-gate 
45810Sstevel@tonic-gate 	/* does this address appear in current table? */
45820Sstevel@tonic-gate 	if (gld->gld_mcast == NULL) {
45830Sstevel@tonic-gate 		/* no mcast addresses -- allocate table */
45840Sstevel@tonic-gate 		gld->gld_mcast = GETSTRUCT(gld_mcast_t *,
45850Sstevel@tonic-gate 					    glddev->gld_multisize);
45860Sstevel@tonic-gate 		if (gld->gld_mcast == NULL) {
45870Sstevel@tonic-gate 			GLDM_UNLOCK(macinfo);
45880Sstevel@tonic-gate 			dlerrorack(q, mp, DL_ENABMULTI_REQ, DL_SYSERR, ENOSR);
45890Sstevel@tonic-gate 			return (GLDE_OK);
45900Sstevel@tonic-gate 		}
45910Sstevel@tonic-gate 		gld->gld_multicnt = glddev->gld_multisize;
45920Sstevel@tonic-gate 	} else {
45930Sstevel@tonic-gate 		for (i = 0; i < gld->gld_multicnt; i++) {
45940Sstevel@tonic-gate 			if (gld->gld_mcast[i] &&
45950Sstevel@tonic-gate 			    mac_eq(gld->gld_mcast[i]->gldm_addr,
45960Sstevel@tonic-gate 				maddr, macinfo->gldm_addrlen)) {
45970Sstevel@tonic-gate 				/* this is a match -- just succeed */
45980Sstevel@tonic-gate 				ASSERT(gld->gld_mcast[i]->gldm_refcnt);
45990Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
46000Sstevel@tonic-gate 				dlokack(q, mp, DL_ENABMULTI_REQ);
46010Sstevel@tonic-gate 				return (GLDE_OK);
46020Sstevel@tonic-gate 			}
46030Sstevel@tonic-gate 		}
46040Sstevel@tonic-gate 	}
46050Sstevel@tonic-gate 
46060Sstevel@tonic-gate 	/*
46070Sstevel@tonic-gate 	 * it wasn't in the stream so check to see if the mac layer has it
46080Sstevel@tonic-gate 	 */
46090Sstevel@tonic-gate 	mcast = NULL;
46100Sstevel@tonic-gate 	if (mac_pvt->mcast_table == NULL) {
46110Sstevel@tonic-gate 		mac_pvt->mcast_table = GETSTRUCT(gld_mcast_t,
46120Sstevel@tonic-gate 						glddev->gld_multisize);
46130Sstevel@tonic-gate 		if (mac_pvt->mcast_table == NULL) {
46140Sstevel@tonic-gate 			GLDM_UNLOCK(macinfo);
46150Sstevel@tonic-gate 			dlerrorack(q, mp, DL_ENABMULTI_REQ, DL_SYSERR, ENOSR);
46160Sstevel@tonic-gate 			return (GLDE_OK);
46170Sstevel@tonic-gate 		}
46180Sstevel@tonic-gate 	} else {
46190Sstevel@tonic-gate 		for (i = 0; i < glddev->gld_multisize; i++) {
46200Sstevel@tonic-gate 			if (mac_pvt->mcast_table[i].gldm_refcnt &&
46210Sstevel@tonic-gate 			    mac_eq(mac_pvt->mcast_table[i].gldm_addr,
46220Sstevel@tonic-gate 			    maddr, macinfo->gldm_addrlen)) {
46230Sstevel@tonic-gate 				mcast = &mac_pvt->mcast_table[i];
46240Sstevel@tonic-gate 				break;
46250Sstevel@tonic-gate 			}
46260Sstevel@tonic-gate 		}
46270Sstevel@tonic-gate 	}
46280Sstevel@tonic-gate 	if (mcast == NULL) {
46290Sstevel@tonic-gate 		/* not in mac layer -- find an empty mac slot to fill in */
46300Sstevel@tonic-gate 		for (i = 0; i < glddev->gld_multisize; i++) {
46310Sstevel@tonic-gate 			if (mac_pvt->mcast_table[i].gldm_refcnt == 0) {
46320Sstevel@tonic-gate 				mcast = &mac_pvt->mcast_table[i];
46330Sstevel@tonic-gate 				mac_copy(maddr, mcast->gldm_addr,
46340Sstevel@tonic-gate 				    macinfo->gldm_addrlen);
46350Sstevel@tonic-gate 				break;
46360Sstevel@tonic-gate 			}
46370Sstevel@tonic-gate 		}
46380Sstevel@tonic-gate 	}
46390Sstevel@tonic-gate 	if (mcast == NULL) {
46400Sstevel@tonic-gate 		/* couldn't get a mac layer slot */
46410Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
46420Sstevel@tonic-gate 		return (DL_TOOMANY);
46430Sstevel@tonic-gate 	}
46440Sstevel@tonic-gate 
46450Sstevel@tonic-gate 	/* now we have a mac layer slot in mcast -- get a stream slot */
46460Sstevel@tonic-gate 	for (i = 0; i < gld->gld_multicnt; i++) {
46470Sstevel@tonic-gate 		if (gld->gld_mcast[i] != NULL)
46480Sstevel@tonic-gate 			continue;
46490Sstevel@tonic-gate 		/* found an empty slot */
46500Sstevel@tonic-gate 		if (!mcast->gldm_refcnt) {
46510Sstevel@tonic-gate 			/* set mcast in hardware */
46520Sstevel@tonic-gate 			unsigned char cmaddr[GLD_MAX_ADDRLEN];
46530Sstevel@tonic-gate 
46540Sstevel@tonic-gate 			ASSERT(sizeof (cmaddr) >= macinfo->gldm_addrlen);
46550Sstevel@tonic-gate 			cmac_copy(maddr, cmaddr,
46560Sstevel@tonic-gate 			    macinfo->gldm_addrlen, macinfo);
46570Sstevel@tonic-gate 
46580Sstevel@tonic-gate 			rc = (*macinfo->gldm_set_multicast)
46590Sstevel@tonic-gate 			    (macinfo, cmaddr, GLD_MULTI_ENABLE);
46600Sstevel@tonic-gate 			if (rc == GLD_NOTSUPPORTED) {
46610Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
46620Sstevel@tonic-gate 				return (DL_NOTSUPPORTED);
46630Sstevel@tonic-gate 			} else if (rc == GLD_NORESOURCES) {
46640Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
46650Sstevel@tonic-gate 				return (DL_TOOMANY);
46660Sstevel@tonic-gate 			} else if (rc == GLD_BADARG) {
46670Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
46680Sstevel@tonic-gate 				return (DL_BADADDR);
46690Sstevel@tonic-gate 			} else if (rc == GLD_RETRY) {
46700Sstevel@tonic-gate 				/*
46710Sstevel@tonic-gate 				 * The putbq and gld_xwait must be
46720Sstevel@tonic-gate 				 * within the lock to prevent races
46730Sstevel@tonic-gate 				 * with gld_sched.
46740Sstevel@tonic-gate 				 */
46750Sstevel@tonic-gate 				(void) putbq(q, mp);
46760Sstevel@tonic-gate 				gld->gld_xwait = B_TRUE;
46770Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
46780Sstevel@tonic-gate 				return (GLDE_RETRY);
46790Sstevel@tonic-gate 			} else if (rc != GLD_SUCCESS) {
46800Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
46810Sstevel@tonic-gate 				dlerrorack(q, mp, DL_ENABMULTI_REQ,
46820Sstevel@tonic-gate 				    DL_SYSERR, EIO);
46830Sstevel@tonic-gate 				return (GLDE_OK);
46840Sstevel@tonic-gate 			}
46850Sstevel@tonic-gate 		}
46860Sstevel@tonic-gate 		gld->gld_mcast[i] = mcast;
46870Sstevel@tonic-gate 		mcast->gldm_refcnt++;
46880Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
46890Sstevel@tonic-gate 		dlokack(q, mp, DL_ENABMULTI_REQ);
46900Sstevel@tonic-gate 		return (GLDE_OK);
46910Sstevel@tonic-gate 	}
46920Sstevel@tonic-gate 
46930Sstevel@tonic-gate 	/* couldn't get a stream slot */
46940Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
46950Sstevel@tonic-gate 	return (DL_TOOMANY);
46960Sstevel@tonic-gate }
46970Sstevel@tonic-gate 
46980Sstevel@tonic-gate 
46990Sstevel@tonic-gate /*
47000Sstevel@tonic-gate  * gld_disable_multi (q, mp)
47010Sstevel@tonic-gate  * Disable the multicast address on the stream.  If last
47020Sstevel@tonic-gate  * reference for the mac layer, disable there as well.
47030Sstevel@tonic-gate  */
47040Sstevel@tonic-gate static int
47050Sstevel@tonic-gate gld_disable_multi(queue_t *q, mblk_t *mp)
47060Sstevel@tonic-gate {
47070Sstevel@tonic-gate 	gld_t  *gld;
47080Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
47090Sstevel@tonic-gate 	unsigned char *maddr;
47100Sstevel@tonic-gate 	dl_disabmulti_req_t *multi;
47110Sstevel@tonic-gate 	int i;
47120Sstevel@tonic-gate 	gld_mcast_t *mcast;
47130Sstevel@tonic-gate 
47140Sstevel@tonic-gate #ifdef GLD_DEBUG
47150Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
47160Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_disable_multi(%p, %p)", (void *)q,
47170Sstevel@tonic-gate 		    (void *)mp);
47180Sstevel@tonic-gate 	}
47190Sstevel@tonic-gate #endif
47200Sstevel@tonic-gate 
47210Sstevel@tonic-gate 	gld = (gld_t *)q->q_ptr;
47220Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
47230Sstevel@tonic-gate 		return (DL_OUTSTATE);
47240Sstevel@tonic-gate 
47250Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
47260Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
47270Sstevel@tonic-gate 	if (macinfo->gldm_set_multicast == NULL) {
47280Sstevel@tonic-gate 		return (DL_UNSUPPORTED);
47290Sstevel@tonic-gate 	}
47300Sstevel@tonic-gate 
47310Sstevel@tonic-gate 	multi = (dl_disabmulti_req_t *)mp->b_rptr;
47320Sstevel@tonic-gate 
47330Sstevel@tonic-gate 	if (!MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length) ||
47340Sstevel@tonic-gate 	    multi->dl_addr_length != macinfo->gldm_addrlen)
47350Sstevel@tonic-gate 		return (DL_BADADDR);
47360Sstevel@tonic-gate 
47370Sstevel@tonic-gate 	maddr = mp->b_rptr + multi->dl_addr_offset;
47380Sstevel@tonic-gate 
47390Sstevel@tonic-gate 	/* request appears to be valid */
47400Sstevel@tonic-gate 	/* does this address appear in current table? */
47410Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
47420Sstevel@tonic-gate 	if (gld->gld_mcast != NULL) {
47430Sstevel@tonic-gate 		for (i = 0; i < gld->gld_multicnt; i++)
47440Sstevel@tonic-gate 			if (((mcast = gld->gld_mcast[i]) != NULL) &&
47450Sstevel@tonic-gate 			    mac_eq(mcast->gldm_addr,
47460Sstevel@tonic-gate 			    maddr, macinfo->gldm_addrlen)) {
47470Sstevel@tonic-gate 				ASSERT(mcast->gldm_refcnt);
47480Sstevel@tonic-gate 				gld_send_disable_multi(macinfo, mcast);
47490Sstevel@tonic-gate 				gld->gld_mcast[i] = NULL;
47500Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
47510Sstevel@tonic-gate 				dlokack(q, mp, DL_DISABMULTI_REQ);
47520Sstevel@tonic-gate 				return (GLDE_OK);
47530Sstevel@tonic-gate 			}
47540Sstevel@tonic-gate 	}
47550Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
47560Sstevel@tonic-gate 	return (DL_NOTENAB); /* not an enabled address */
47570Sstevel@tonic-gate }
47580Sstevel@tonic-gate 
47590Sstevel@tonic-gate /*
47600Sstevel@tonic-gate  * gld_send_disable_multi(macinfo, mcast)
47610Sstevel@tonic-gate  * this function is used to disable a multicast address if the reference
47620Sstevel@tonic-gate  * count goes to zero. The disable request will then be forwarded to the
47630Sstevel@tonic-gate  * lower stream.
47640Sstevel@tonic-gate  */
47650Sstevel@tonic-gate static void
47660Sstevel@tonic-gate gld_send_disable_multi(gld_mac_info_t *macinfo, gld_mcast_t *mcast)
47670Sstevel@tonic-gate {
47680Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
47690Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
47700Sstevel@tonic-gate 	ASSERT(mcast != NULL);
47710Sstevel@tonic-gate 	ASSERT(mcast->gldm_refcnt);
47720Sstevel@tonic-gate 
47730Sstevel@tonic-gate 	if (!mcast->gldm_refcnt) {
47740Sstevel@tonic-gate 		return;			/* "cannot happen" */
47750Sstevel@tonic-gate 	}
47760Sstevel@tonic-gate 
47770Sstevel@tonic-gate 	if (--mcast->gldm_refcnt > 0) {
47780Sstevel@tonic-gate 		return;
47790Sstevel@tonic-gate 	}
47800Sstevel@tonic-gate 
47810Sstevel@tonic-gate 	/*
47820Sstevel@tonic-gate 	 * This must be converted from canonical form to device form.
47830Sstevel@tonic-gate 	 * The refcnt is now zero so we can trash the data.
47840Sstevel@tonic-gate 	 */
47850Sstevel@tonic-gate 	if (macinfo->gldm_options & GLDOPT_CANONICAL_ADDR)
47860Sstevel@tonic-gate 		gld_bitreverse(mcast->gldm_addr, macinfo->gldm_addrlen);
47870Sstevel@tonic-gate 
47880Sstevel@tonic-gate 	/* XXX Ought to check for GLD_NORESOURCES or GLD_FAILURE */
47890Sstevel@tonic-gate 	(void) (*macinfo->gldm_set_multicast)
47900Sstevel@tonic-gate 	    (macinfo, mcast->gldm_addr, GLD_MULTI_DISABLE);
47910Sstevel@tonic-gate }
47920Sstevel@tonic-gate 
47930Sstevel@tonic-gate /*
47940Sstevel@tonic-gate  * gld_promisc (q, mp, req, on)
47950Sstevel@tonic-gate  *	enable or disable the use of promiscuous mode with the hardware
47960Sstevel@tonic-gate  */
47970Sstevel@tonic-gate static int
47980Sstevel@tonic-gate gld_promisc(queue_t *q, mblk_t *mp, t_uscalar_t req, boolean_t on)
47990Sstevel@tonic-gate {
48000Sstevel@tonic-gate 	gld_t *gld;
48010Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
48020Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
48030Sstevel@tonic-gate 	gld_vlan_t *vlan;
48040Sstevel@tonic-gate 	union DL_primitives *prim;
48050Sstevel@tonic-gate 	int macrc = GLD_SUCCESS;
48060Sstevel@tonic-gate 	int dlerr = GLDE_OK;
48070Sstevel@tonic-gate 	int op = GLD_MAC_PROMISC_NOOP;
48080Sstevel@tonic-gate 
48090Sstevel@tonic-gate #ifdef GLD_DEBUG
48100Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
48110Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_promisc(%p, %p, %d, %d)",
48120Sstevel@tonic-gate 		    (void *)q, (void *)mp, req, on);
48130Sstevel@tonic-gate #endif
48140Sstevel@tonic-gate 
48150Sstevel@tonic-gate 	ASSERT(mp != NULL);
48160Sstevel@tonic-gate 	prim = (union DL_primitives *)mp->b_rptr;
48170Sstevel@tonic-gate 
48180Sstevel@tonic-gate 	/* XXX I think spec allows promisc in unattached state */
48190Sstevel@tonic-gate 	gld = (gld_t *)q->q_ptr;
48200Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
48210Sstevel@tonic-gate 		return (DL_OUTSTATE);
48220Sstevel@tonic-gate 
48230Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
48240Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
48250Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
48260Sstevel@tonic-gate 
48270Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
48280Sstevel@tonic-gate 	ASSERT(vlan != NULL);
48290Sstevel@tonic-gate 
48300Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
48310Sstevel@tonic-gate 
48320Sstevel@tonic-gate 	/*
48330Sstevel@tonic-gate 	 * Work out what request (if any) has to be made to the MAC layer
48340Sstevel@tonic-gate 	 */
48350Sstevel@tonic-gate 	if (on) {
48360Sstevel@tonic-gate 		switch (prim->promiscon_req.dl_level) {
48370Sstevel@tonic-gate 		default:
48380Sstevel@tonic-gate 			dlerr = DL_UNSUPPORTED;	/* this is an error */
48390Sstevel@tonic-gate 			break;
48400Sstevel@tonic-gate 
48410Sstevel@tonic-gate 		case DL_PROMISC_PHYS:
48420Sstevel@tonic-gate 			if (mac_pvt->nprom == 0)
48430Sstevel@tonic-gate 				op = GLD_MAC_PROMISC_PHYS;
48440Sstevel@tonic-gate 			break;
48450Sstevel@tonic-gate 
48460Sstevel@tonic-gate 		case DL_PROMISC_MULTI:
48470Sstevel@tonic-gate 			if (mac_pvt->nprom_multi == 0)
48480Sstevel@tonic-gate 				if (mac_pvt->nprom == 0)
48490Sstevel@tonic-gate 					op = GLD_MAC_PROMISC_MULTI;
48500Sstevel@tonic-gate 			break;
48510Sstevel@tonic-gate 
48520Sstevel@tonic-gate 		case DL_PROMISC_SAP:
48530Sstevel@tonic-gate 			/* We can do this without reference to the MAC */
48540Sstevel@tonic-gate 			break;
48550Sstevel@tonic-gate 		}
48560Sstevel@tonic-gate 	} else {
48570Sstevel@tonic-gate 		switch (prim->promiscoff_req.dl_level) {
48580Sstevel@tonic-gate 		default:
48590Sstevel@tonic-gate 			dlerr = DL_UNSUPPORTED;	/* this is an error */
48600Sstevel@tonic-gate 			break;
48610Sstevel@tonic-gate 
48620Sstevel@tonic-gate 		case DL_PROMISC_PHYS:
48630Sstevel@tonic-gate 			if (!(gld->gld_flags & GLD_PROM_PHYS))
48640Sstevel@tonic-gate 				dlerr = DL_NOTENAB;
48650Sstevel@tonic-gate 			else if (mac_pvt->nprom == 1)
48660Sstevel@tonic-gate 				if (mac_pvt->nprom_multi)
48670Sstevel@tonic-gate 					op = GLD_MAC_PROMISC_MULTI;
48680Sstevel@tonic-gate 				else
48690Sstevel@tonic-gate 					op = GLD_MAC_PROMISC_NONE;
48700Sstevel@tonic-gate 			break;
48710Sstevel@tonic-gate 
48720Sstevel@tonic-gate 		case DL_PROMISC_MULTI:
48730Sstevel@tonic-gate 			if (!(gld->gld_flags & GLD_PROM_MULT))
48740Sstevel@tonic-gate 				dlerr = DL_NOTENAB;
48750Sstevel@tonic-gate 			else if (mac_pvt->nprom_multi == 1)
48760Sstevel@tonic-gate 				if (mac_pvt->nprom == 0)
48770Sstevel@tonic-gate 					op = GLD_MAC_PROMISC_NONE;
48780Sstevel@tonic-gate 			break;
48790Sstevel@tonic-gate 
48800Sstevel@tonic-gate 		case DL_PROMISC_SAP:
48810Sstevel@tonic-gate 			if (!(gld->gld_flags & GLD_PROM_SAP))
48820Sstevel@tonic-gate 				dlerr = DL_NOTENAB;
48830Sstevel@tonic-gate 
48840Sstevel@tonic-gate 			/* We can do this without reference to the MAC */
48850Sstevel@tonic-gate 			break;
48860Sstevel@tonic-gate 		}
48870Sstevel@tonic-gate 	}
48880Sstevel@tonic-gate 
48890Sstevel@tonic-gate 	/*
48900Sstevel@tonic-gate 	 * The request was invalid in some way so no need to continue.
48910Sstevel@tonic-gate 	 */
48920Sstevel@tonic-gate 	if (dlerr != GLDE_OK) {
48930Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
48940Sstevel@tonic-gate 		return (dlerr);
48950Sstevel@tonic-gate 	}
48960Sstevel@tonic-gate 
48970Sstevel@tonic-gate 	/*
48980Sstevel@tonic-gate 	 * Issue the request to the MAC layer, if required
48990Sstevel@tonic-gate 	 */
49000Sstevel@tonic-gate 	if (op != GLD_MAC_PROMISC_NOOP) {
49010Sstevel@tonic-gate 		macrc = (*macinfo->gldm_set_promiscuous)(macinfo, op);
49020Sstevel@tonic-gate 	}
49030Sstevel@tonic-gate 
49040Sstevel@tonic-gate 	/*
49050Sstevel@tonic-gate 	 * On success, update the appropriate flags & refcounts
49060Sstevel@tonic-gate 	 */
49070Sstevel@tonic-gate 	if (macrc == GLD_SUCCESS) {
49080Sstevel@tonic-gate 		if (on) {
49090Sstevel@tonic-gate 			switch (prim->promiscon_req.dl_level) {
49100Sstevel@tonic-gate 			case DL_PROMISC_PHYS:
49110Sstevel@tonic-gate 				mac_pvt->nprom++;
49120Sstevel@tonic-gate 				gld->gld_flags |= GLD_PROM_PHYS;
49130Sstevel@tonic-gate 				break;
49140Sstevel@tonic-gate 
49150Sstevel@tonic-gate 			case DL_PROMISC_MULTI:
49160Sstevel@tonic-gate 				mac_pvt->nprom_multi++;
49170Sstevel@tonic-gate 				gld->gld_flags |= GLD_PROM_MULT;
49180Sstevel@tonic-gate 				break;
49190Sstevel@tonic-gate 
49200Sstevel@tonic-gate 			case DL_PROMISC_SAP:
49210Sstevel@tonic-gate 				gld->gld_flags |= GLD_PROM_SAP;
49220Sstevel@tonic-gate 				break;
49230Sstevel@tonic-gate 
49240Sstevel@tonic-gate 			default:
49250Sstevel@tonic-gate 				break;
49260Sstevel@tonic-gate 			}
49270Sstevel@tonic-gate 		} else {
49280Sstevel@tonic-gate 			switch (prim->promiscoff_req.dl_level) {
49290Sstevel@tonic-gate 			case DL_PROMISC_PHYS:
49300Sstevel@tonic-gate 				mac_pvt->nprom--;
49310Sstevel@tonic-gate 				gld->gld_flags &= ~GLD_PROM_PHYS;
49320Sstevel@tonic-gate 				break;
49330Sstevel@tonic-gate 
49340Sstevel@tonic-gate 			case DL_PROMISC_MULTI:
49350Sstevel@tonic-gate 				mac_pvt->nprom_multi--;
49360Sstevel@tonic-gate 				gld->gld_flags &= ~GLD_PROM_MULT;
49370Sstevel@tonic-gate 				break;
49380Sstevel@tonic-gate 
49390Sstevel@tonic-gate 			case DL_PROMISC_SAP:
49400Sstevel@tonic-gate 				gld->gld_flags &= ~GLD_PROM_SAP;
49410Sstevel@tonic-gate 				break;
49420Sstevel@tonic-gate 
49430Sstevel@tonic-gate 			default:
49440Sstevel@tonic-gate 				break;
49450Sstevel@tonic-gate 			}
49460Sstevel@tonic-gate 		}
49470Sstevel@tonic-gate 	} else if (macrc == GLD_RETRY) {
49480Sstevel@tonic-gate 		/*
49490Sstevel@tonic-gate 		 * The putbq and gld_xwait must be within the lock to
49500Sstevel@tonic-gate 		 * prevent races with gld_sched.
49510Sstevel@tonic-gate 		 */
49520Sstevel@tonic-gate 		(void) putbq(q, mp);
49530Sstevel@tonic-gate 		gld->gld_xwait = B_TRUE;
49540Sstevel@tonic-gate 	}
49550Sstevel@tonic-gate 
49560Sstevel@tonic-gate 	/*
49570Sstevel@tonic-gate 	 * Update VLAN IPQ status -- it may have changed
49580Sstevel@tonic-gate 	 */
49590Sstevel@tonic-gate 	if (gld->gld_flags & (GLD_PROM_SAP | GLD_PROM_MULT | GLD_PROM_PHYS))
49600Sstevel@tonic-gate 		vlan->gldv_ipq_flags |= IPQ_FORBIDDEN;
49610Sstevel@tonic-gate 	else
49620Sstevel@tonic-gate 		vlan->gldv_ipq_flags &= ~IPQ_FORBIDDEN;
49630Sstevel@tonic-gate 
49640Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
49650Sstevel@tonic-gate 
49660Sstevel@tonic-gate 	/*
49670Sstevel@tonic-gate 	 * Finally, decide how to reply.
49680Sstevel@tonic-gate 	 *
49690Sstevel@tonic-gate 	 * If <macrc> is not GLD_SUCCESS, the request was put to the MAC
49700Sstevel@tonic-gate 	 * layer but failed.  In such cases, we can return a DL_* error
49710Sstevel@tonic-gate 	 * code and let the caller send an error-ack reply upstream, or
49720Sstevel@tonic-gate 	 * we can send a reply here and then return GLDE_OK so that the
49730Sstevel@tonic-gate 	 * caller doesn't also respond.
49740Sstevel@tonic-gate 	 *
49750Sstevel@tonic-gate 	 * If physical-promiscuous mode was (successfully) switched on or
49760Sstevel@tonic-gate 	 * off, send a notification (DL_NOTIFY_IND) to anyone interested.
49770Sstevel@tonic-gate 	 */
49780Sstevel@tonic-gate 	switch (macrc) {
49790Sstevel@tonic-gate 	case GLD_NOTSUPPORTED:
49800Sstevel@tonic-gate 		return (DL_NOTSUPPORTED);
49810Sstevel@tonic-gate 
49820Sstevel@tonic-gate 	case GLD_NORESOURCES:
49830Sstevel@tonic-gate 		dlerrorack(q, mp, req, DL_SYSERR, ENOSR);
49840Sstevel@tonic-gate 		return (GLDE_OK);
49850Sstevel@tonic-gate 
49860Sstevel@tonic-gate 	case GLD_RETRY:
49870Sstevel@tonic-gate 		return (GLDE_RETRY);
49880Sstevel@tonic-gate 
49890Sstevel@tonic-gate 	default:
49900Sstevel@tonic-gate 		dlerrorack(q, mp, req, DL_SYSERR, EIO);
49910Sstevel@tonic-gate 		return (GLDE_OK);
49920Sstevel@tonic-gate 
49930Sstevel@tonic-gate 	case GLD_SUCCESS:
49940Sstevel@tonic-gate 		dlokack(q, mp, req);
49950Sstevel@tonic-gate 		break;
49960Sstevel@tonic-gate 	}
49970Sstevel@tonic-gate 
49980Sstevel@tonic-gate 	switch (op) {
49990Sstevel@tonic-gate 	case GLD_MAC_PROMISC_NOOP:
50000Sstevel@tonic-gate 		break;
50010Sstevel@tonic-gate 
50020Sstevel@tonic-gate 	case GLD_MAC_PROMISC_PHYS:
50030Sstevel@tonic-gate 		gld_notify_ind(macinfo, DL_NOTE_PROMISC_ON_PHYS, NULL);
50040Sstevel@tonic-gate 		break;
50050Sstevel@tonic-gate 
50060Sstevel@tonic-gate 	default:
50070Sstevel@tonic-gate 		gld_notify_ind(macinfo, DL_NOTE_PROMISC_OFF_PHYS, NULL);
50080Sstevel@tonic-gate 		break;
50090Sstevel@tonic-gate 	}
50100Sstevel@tonic-gate 
50110Sstevel@tonic-gate 	return (GLDE_OK);
50120Sstevel@tonic-gate }
50130Sstevel@tonic-gate 
50140Sstevel@tonic-gate /*
50150Sstevel@tonic-gate  * gld_physaddr()
50160Sstevel@tonic-gate  *	get the current or factory physical address value
50170Sstevel@tonic-gate  */
50180Sstevel@tonic-gate static int
50190Sstevel@tonic-gate gld_physaddr(queue_t *q, mblk_t *mp)
50200Sstevel@tonic-gate {
50210Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
50220Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
50230Sstevel@tonic-gate 	union DL_primitives *prim = (union DL_primitives *)mp->b_rptr;
50240Sstevel@tonic-gate 	unsigned char addr[GLD_MAX_ADDRLEN];
50250Sstevel@tonic-gate 
50260Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
50270Sstevel@tonic-gate 		return (DL_OUTSTATE);
50280Sstevel@tonic-gate 
50290Sstevel@tonic-gate 	macinfo = (gld_mac_info_t *)gld->gld_mac_info;
50300Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
50310Sstevel@tonic-gate 	ASSERT(macinfo->gldm_addrlen <= GLD_MAX_ADDRLEN);
50320Sstevel@tonic-gate 
50330Sstevel@tonic-gate 	switch (prim->physaddr_req.dl_addr_type) {
50340Sstevel@tonic-gate 	case DL_FACT_PHYS_ADDR:
50350Sstevel@tonic-gate 		mac_copy((caddr_t)macinfo->gldm_vendor_addr,
50360Sstevel@tonic-gate 		    (caddr_t)addr, macinfo->gldm_addrlen);
50370Sstevel@tonic-gate 		break;
50380Sstevel@tonic-gate 	case DL_CURR_PHYS_ADDR:
50390Sstevel@tonic-gate 		/* make a copy so we don't hold the lock across qreply */
50400Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
50410Sstevel@tonic-gate 		mac_copy((caddr_t)
50420Sstevel@tonic-gate 		    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
50430Sstevel@tonic-gate 		    (caddr_t)addr, macinfo->gldm_addrlen);
50440Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
50450Sstevel@tonic-gate 		break;
50460Sstevel@tonic-gate 	default:
50470Sstevel@tonic-gate 		return (DL_BADPRIM);
50480Sstevel@tonic-gate 	}
50490Sstevel@tonic-gate 	dlphysaddrack(q, mp, (caddr_t)addr, macinfo->gldm_addrlen);
50500Sstevel@tonic-gate 	return (GLDE_OK);
50510Sstevel@tonic-gate }
50520Sstevel@tonic-gate 
50530Sstevel@tonic-gate /*
50540Sstevel@tonic-gate  * gld_setaddr()
50550Sstevel@tonic-gate  *	change the hardware's physical address to a user specified value
50560Sstevel@tonic-gate  */
50570Sstevel@tonic-gate static int
50580Sstevel@tonic-gate gld_setaddr(queue_t *q, mblk_t *mp)
50590Sstevel@tonic-gate {
50600Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
50610Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
50620Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
50630Sstevel@tonic-gate 	union DL_primitives *prim = (union DL_primitives *)mp->b_rptr;
50640Sstevel@tonic-gate 	unsigned char *addr;
50650Sstevel@tonic-gate 	unsigned char cmaddr[GLD_MAX_ADDRLEN];
50660Sstevel@tonic-gate 	int rc;
50670Sstevel@tonic-gate 	gld_vlan_t *vlan;
50680Sstevel@tonic-gate 
50690Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
50700Sstevel@tonic-gate 		return (DL_OUTSTATE);
50710Sstevel@tonic-gate 
50720Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
50730Sstevel@tonic-gate 	ASSERT(vlan != NULL);
50740Sstevel@tonic-gate 
50750Sstevel@tonic-gate 	if (vlan->gldv_id != VLAN_VID_NONE)
50760Sstevel@tonic-gate 		return (DL_NOTSUPPORTED);
50770Sstevel@tonic-gate 
50780Sstevel@tonic-gate 	macinfo = (gld_mac_info_t *)gld->gld_mac_info;
50790Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
50800Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
50810Sstevel@tonic-gate 
50820Sstevel@tonic-gate 	if (!MBLKIN(mp, prim->set_physaddr_req.dl_addr_offset,
50830Sstevel@tonic-gate 	    prim->set_physaddr_req.dl_addr_length) ||
50840Sstevel@tonic-gate 	    prim->set_physaddr_req.dl_addr_length != macinfo->gldm_addrlen)
50850Sstevel@tonic-gate 		return (DL_BADADDR);
50860Sstevel@tonic-gate 
50870Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
50880Sstevel@tonic-gate 
50890Sstevel@tonic-gate 	/* now do the set at the hardware level */
50900Sstevel@tonic-gate 	addr = mp->b_rptr + prim->set_physaddr_req.dl_addr_offset;
50910Sstevel@tonic-gate 	ASSERT(sizeof (cmaddr) >= macinfo->gldm_addrlen);
50920Sstevel@tonic-gate 	cmac_copy(addr, cmaddr, macinfo->gldm_addrlen, macinfo);
50930Sstevel@tonic-gate 
50940Sstevel@tonic-gate 	rc = (*macinfo->gldm_set_mac_addr)(macinfo, cmaddr);
50950Sstevel@tonic-gate 	if (rc == GLD_SUCCESS)
50960Sstevel@tonic-gate 		mac_copy(addr, mac_pvt->curr_macaddr,
50970Sstevel@tonic-gate 		    macinfo->gldm_addrlen);
50980Sstevel@tonic-gate 
50990Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
51000Sstevel@tonic-gate 
51010Sstevel@tonic-gate 	switch (rc) {
51020Sstevel@tonic-gate 	case GLD_SUCCESS:
51030Sstevel@tonic-gate 		break;
51040Sstevel@tonic-gate 	case GLD_NOTSUPPORTED:
51050Sstevel@tonic-gate 		return (DL_NOTSUPPORTED);
51060Sstevel@tonic-gate 	case GLD_BADARG:
51070Sstevel@tonic-gate 		return (DL_BADADDR);
51080Sstevel@tonic-gate 	case GLD_NORESOURCES:
51090Sstevel@tonic-gate 		dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, DL_SYSERR, ENOSR);
51100Sstevel@tonic-gate 		return (GLDE_OK);
51110Sstevel@tonic-gate 	default:
51120Sstevel@tonic-gate 		dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, DL_SYSERR, EIO);
51130Sstevel@tonic-gate 		return (GLDE_OK);
51140Sstevel@tonic-gate 	}
51150Sstevel@tonic-gate 
51160Sstevel@tonic-gate 	gld_notify_ind(macinfo, DL_NOTE_PHYS_ADDR, NULL);
51170Sstevel@tonic-gate 
51180Sstevel@tonic-gate 	dlokack(q, mp, DL_SET_PHYS_ADDR_REQ);
51190Sstevel@tonic-gate 	return (GLDE_OK);
51200Sstevel@tonic-gate }
51210Sstevel@tonic-gate 
51220Sstevel@tonic-gate int
51230Sstevel@tonic-gate gld_get_statistics(queue_t *q, mblk_t *mp)
51240Sstevel@tonic-gate {
51250Sstevel@tonic-gate 	dl_get_statistics_ack_t *dlsp;
51260Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
51270Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
51280Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
51290Sstevel@tonic-gate 
51300Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
51310Sstevel@tonic-gate 		return (DL_OUTSTATE);
51320Sstevel@tonic-gate 
51330Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
51340Sstevel@tonic-gate 
51350Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
51360Sstevel@tonic-gate 	(void) gld_update_kstat(mac_pvt->kstatp, KSTAT_READ);
51370Sstevel@tonic-gate 
51380Sstevel@tonic-gate 	mp = mexchange(q, mp, DL_GET_STATISTICS_ACK_SIZE +
51390Sstevel@tonic-gate 	    sizeof (struct gldkstats), M_PCPROTO, DL_GET_STATISTICS_ACK);
51400Sstevel@tonic-gate 
51410Sstevel@tonic-gate 	if (mp == NULL)
51420Sstevel@tonic-gate 		return (GLDE_OK);	/* mexchange already sent merror */
51430Sstevel@tonic-gate 
51440Sstevel@tonic-gate 	dlsp = (dl_get_statistics_ack_t *)mp->b_rptr;
51450Sstevel@tonic-gate 	dlsp->dl_primitive = DL_GET_STATISTICS_ACK;
51460Sstevel@tonic-gate 	dlsp->dl_stat_length = sizeof (struct gldkstats);
51470Sstevel@tonic-gate 	dlsp->dl_stat_offset = DL_GET_STATISTICS_ACK_SIZE;
51480Sstevel@tonic-gate 
51490Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
51500Sstevel@tonic-gate 	bcopy(mac_pvt->kstatp->ks_data,
51510Sstevel@tonic-gate 	    (mp->b_rptr + DL_GET_STATISTICS_ACK_SIZE),
51520Sstevel@tonic-gate 	    sizeof (struct gldkstats));
51530Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
51540Sstevel@tonic-gate 
51550Sstevel@tonic-gate 	qreply(q, mp);
51560Sstevel@tonic-gate 	return (GLDE_OK);
51570Sstevel@tonic-gate }
51580Sstevel@tonic-gate 
51590Sstevel@tonic-gate /* =================================================== */
51600Sstevel@tonic-gate /* misc utilities, some requiring various mutexes held */
51610Sstevel@tonic-gate /* =================================================== */
51620Sstevel@tonic-gate 
51630Sstevel@tonic-gate /*
51640Sstevel@tonic-gate  * Initialize and start the driver.
51650Sstevel@tonic-gate  */
51660Sstevel@tonic-gate static int
51670Sstevel@tonic-gate gld_start_mac(gld_mac_info_t *macinfo)
51680Sstevel@tonic-gate {
51690Sstevel@tonic-gate 	int	rc;
51700Sstevel@tonic-gate 	unsigned char cmaddr[GLD_MAX_ADDRLEN];
51710Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
51720Sstevel@tonic-gate 
51730Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
51740Sstevel@tonic-gate 	ASSERT(!mac_pvt->started);
51750Sstevel@tonic-gate 
51760Sstevel@tonic-gate 	rc = (*macinfo->gldm_reset)(macinfo);
51770Sstevel@tonic-gate 	if (rc != GLD_SUCCESS)
51780Sstevel@tonic-gate 		return (GLD_FAILURE);
51790Sstevel@tonic-gate 
51800Sstevel@tonic-gate 	/* set the addr after we reset the device */
51810Sstevel@tonic-gate 	ASSERT(sizeof (cmaddr) >= macinfo->gldm_addrlen);
51820Sstevel@tonic-gate 	cmac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)
51830Sstevel@tonic-gate 	    ->curr_macaddr, cmaddr, macinfo->gldm_addrlen, macinfo);
51840Sstevel@tonic-gate 
51850Sstevel@tonic-gate 	rc = (*macinfo->gldm_set_mac_addr)(macinfo, cmaddr);
51860Sstevel@tonic-gate 	ASSERT(rc != GLD_BADARG);  /* this address was good before */
51870Sstevel@tonic-gate 	if (rc != GLD_SUCCESS && rc != GLD_NOTSUPPORTED)
51880Sstevel@tonic-gate 		return (GLD_FAILURE);
51890Sstevel@tonic-gate 
51900Sstevel@tonic-gate 	rc = (*macinfo->gldm_start)(macinfo);
51910Sstevel@tonic-gate 	if (rc != GLD_SUCCESS)
51920Sstevel@tonic-gate 		return (GLD_FAILURE);
51930Sstevel@tonic-gate 
51940Sstevel@tonic-gate 	mac_pvt->started = B_TRUE;
51950Sstevel@tonic-gate 	return (GLD_SUCCESS);
51960Sstevel@tonic-gate }
51970Sstevel@tonic-gate 
51980Sstevel@tonic-gate /*
51990Sstevel@tonic-gate  * Stop the driver.
52000Sstevel@tonic-gate  */
52010Sstevel@tonic-gate static void
52020Sstevel@tonic-gate gld_stop_mac(gld_mac_info_t *macinfo)
52030Sstevel@tonic-gate {
52040Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
52050Sstevel@tonic-gate 
52060Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
52070Sstevel@tonic-gate 	ASSERT(mac_pvt->started);
52080Sstevel@tonic-gate 
52090Sstevel@tonic-gate 	(void) (*macinfo->gldm_stop)(macinfo);
52100Sstevel@tonic-gate 
52110Sstevel@tonic-gate 	mac_pvt->started = B_FALSE;
52120Sstevel@tonic-gate }
52130Sstevel@tonic-gate 
52140Sstevel@tonic-gate 
52150Sstevel@tonic-gate /*
52160Sstevel@tonic-gate  * gld_set_ipq will set a pointer to the queue which is bound to the
52170Sstevel@tonic-gate  * IP sap if:
52180Sstevel@tonic-gate  * o the device type is ethernet or IPoIB.
52190Sstevel@tonic-gate  * o there is no stream in SAP promiscuous mode.
52200Sstevel@tonic-gate  * o there is exactly one stream bound to the IP sap.
52210Sstevel@tonic-gate  * o the stream is in "fastpath" mode.
52220Sstevel@tonic-gate  */
52230Sstevel@tonic-gate static void
52240Sstevel@tonic-gate gld_set_ipq(gld_t *gld)
52250Sstevel@tonic-gate {
52260Sstevel@tonic-gate 	gld_vlan_t	*vlan;
52270Sstevel@tonic-gate 	gld_mac_info_t	*macinfo = gld->gld_mac_info;
52280Sstevel@tonic-gate 	gld_t		*ip_gld = NULL;
52290Sstevel@tonic-gate 	uint_t		ipq_candidates = 0;
52300Sstevel@tonic-gate 	gld_t		*ipv6_gld = NULL;
52310Sstevel@tonic-gate 	uint_t		ipv6q_candidates = 0;
52320Sstevel@tonic-gate 
52330Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
52340Sstevel@tonic-gate 
52350Sstevel@tonic-gate 	/* The ipq code in gld_recv() is intimate with ethernet/IPoIB */
52360Sstevel@tonic-gate 	if (((macinfo->gldm_type != DL_ETHER) &&
52370Sstevel@tonic-gate 	    (macinfo->gldm_type != DL_IB)) ||
52380Sstevel@tonic-gate 	    (gld_global_options & GLD_OPT_NO_IPQ))
52390Sstevel@tonic-gate 		return;
52400Sstevel@tonic-gate 
52410Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
52420Sstevel@tonic-gate 	ASSERT(vlan != NULL);
52430Sstevel@tonic-gate 
52440Sstevel@tonic-gate 	/* clear down any previously defined ipqs */
52450Sstevel@tonic-gate 	vlan->gldv_ipq = NULL;
52460Sstevel@tonic-gate 	vlan->gldv_ipv6q = NULL;
52470Sstevel@tonic-gate 
52480Sstevel@tonic-gate 	/* Try to find a single stream eligible to receive IP packets */
52490Sstevel@tonic-gate 	for (gld = vlan->gldv_str_next;
52500Sstevel@tonic-gate 	    gld != (gld_t *)&vlan->gldv_str_next; gld = gld->gld_next) {
52510Sstevel@tonic-gate 		if (gld->gld_state != DL_IDLE)
52520Sstevel@tonic-gate 			continue;	/* not eligible to receive */
52530Sstevel@tonic-gate 		if (gld->gld_flags & GLD_STR_CLOSING)
52540Sstevel@tonic-gate 			continue;	/* not eligible to receive */
52550Sstevel@tonic-gate 
52560Sstevel@tonic-gate 		if (gld->gld_sap == ETHERTYPE_IP) {
52570Sstevel@tonic-gate 			ip_gld = gld;
52580Sstevel@tonic-gate 			ipq_candidates++;
52590Sstevel@tonic-gate 		}
52600Sstevel@tonic-gate 
52610Sstevel@tonic-gate 		if (gld->gld_sap == ETHERTYPE_IPV6) {
52620Sstevel@tonic-gate 			ipv6_gld = gld;
52630Sstevel@tonic-gate 			ipv6q_candidates++;
52640Sstevel@tonic-gate 		}
52650Sstevel@tonic-gate 	}
52660Sstevel@tonic-gate 
52670Sstevel@tonic-gate 	if (ipq_candidates == 1) {
52680Sstevel@tonic-gate 		ASSERT(ip_gld != NULL);
52690Sstevel@tonic-gate 
52700Sstevel@tonic-gate 		if (ip_gld->gld_flags & GLD_FAST)	/* eligible for ipq */
52710Sstevel@tonic-gate 			vlan->gldv_ipq = ip_gld->gld_qptr;
52720Sstevel@tonic-gate 	}
52730Sstevel@tonic-gate 
52740Sstevel@tonic-gate 	if (ipv6q_candidates == 1) {
52750Sstevel@tonic-gate 		ASSERT(ipv6_gld != NULL);
52760Sstevel@tonic-gate 
52770Sstevel@tonic-gate 		if (ipv6_gld->gld_flags & GLD_FAST)	/* eligible for ipq */
52780Sstevel@tonic-gate 			vlan->gldv_ipv6q = ipv6_gld->gld_qptr;
52790Sstevel@tonic-gate 	}
52800Sstevel@tonic-gate }
52810Sstevel@tonic-gate 
52820Sstevel@tonic-gate /*
52830Sstevel@tonic-gate  * gld_flushqueue (q)
52840Sstevel@tonic-gate  *	used by DLPI primitives that require flushing the queues.
52850Sstevel@tonic-gate  *	essentially, this is DL_UNBIND_REQ.
52860Sstevel@tonic-gate  */
52870Sstevel@tonic-gate static void
52880Sstevel@tonic-gate gld_flushqueue(queue_t *q)
52890Sstevel@tonic-gate {
52900Sstevel@tonic-gate 	/* flush all data in both queues */
52910Sstevel@tonic-gate 	/* XXX Should these be FLUSHALL? */
52920Sstevel@tonic-gate 	flushq(q, FLUSHDATA);
52930Sstevel@tonic-gate 	flushq(WR(q), FLUSHDATA);
52940Sstevel@tonic-gate 	/* flush all the queues upstream */
52950Sstevel@tonic-gate 	(void) putctl1(q, M_FLUSH, FLUSHRW);
52960Sstevel@tonic-gate }
52970Sstevel@tonic-gate 
52980Sstevel@tonic-gate /*
52990Sstevel@tonic-gate  * gld_devlookup (major)
53000Sstevel@tonic-gate  * search the device table for the device with specified
53010Sstevel@tonic-gate  * major number and return a pointer to it if it exists
53020Sstevel@tonic-gate  */
53030Sstevel@tonic-gate static glddev_t *
53040Sstevel@tonic-gate gld_devlookup(int major)
53050Sstevel@tonic-gate {
53060Sstevel@tonic-gate 	struct glddevice *dev;
53070Sstevel@tonic-gate 
53080Sstevel@tonic-gate 	ASSERT(mutex_owned(&gld_device_list.gld_devlock));
53090Sstevel@tonic-gate 
53100Sstevel@tonic-gate 	for (dev = gld_device_list.gld_next;
53110Sstevel@tonic-gate 	    dev != &gld_device_list;
53120Sstevel@tonic-gate 	    dev = dev->gld_next) {
53130Sstevel@tonic-gate 		ASSERT(dev);
53140Sstevel@tonic-gate 		if (dev->gld_major == major)
53150Sstevel@tonic-gate 			return (dev);
53160Sstevel@tonic-gate 	}
53170Sstevel@tonic-gate 	return (NULL);
53180Sstevel@tonic-gate }
53190Sstevel@tonic-gate 
53200Sstevel@tonic-gate /*
53210Sstevel@tonic-gate  * gld_findminor(device)
53220Sstevel@tonic-gate  * Returns a minor number currently unused by any stream in the current
53230Sstevel@tonic-gate  * device class (major) list.
53240Sstevel@tonic-gate  */
53250Sstevel@tonic-gate static int
53260Sstevel@tonic-gate gld_findminor(glddev_t *device)
53270Sstevel@tonic-gate {
53280Sstevel@tonic-gate 	gld_t		*next;
53290Sstevel@tonic-gate 	gld_mac_info_t	*nextmac;
53300Sstevel@tonic-gate 	gld_vlan_t	*nextvlan;
53310Sstevel@tonic-gate 	int		minor;
53320Sstevel@tonic-gate 	int		i;
53330Sstevel@tonic-gate 
53340Sstevel@tonic-gate 	ASSERT(mutex_owned(&device->gld_devlock));
53350Sstevel@tonic-gate 
53360Sstevel@tonic-gate 	/* The fast way */
53370Sstevel@tonic-gate 	if (device->gld_nextminor >= GLD_MIN_CLONE_MINOR &&
53380Sstevel@tonic-gate 	    device->gld_nextminor <= GLD_MAX_CLONE_MINOR)
53390Sstevel@tonic-gate 		return (device->gld_nextminor++);
53400Sstevel@tonic-gate 
53410Sstevel@tonic-gate 	/* The steady way */
53420Sstevel@tonic-gate 	for (minor = GLD_MIN_CLONE_MINOR; minor <= GLD_MAX_CLONE_MINOR;
53430Sstevel@tonic-gate 	    minor++) {
53440Sstevel@tonic-gate 		/* Search all unattached streams */
53450Sstevel@tonic-gate 		for (next = device->gld_str_next;
53460Sstevel@tonic-gate 		    next != (gld_t *)&device->gld_str_next;
53470Sstevel@tonic-gate 		    next = next->gld_next) {
53480Sstevel@tonic-gate 			if (minor == next->gld_minor)
53490Sstevel@tonic-gate 				goto nextminor;
53500Sstevel@tonic-gate 		}
53510Sstevel@tonic-gate 		/* Search all attached streams; we don't need maclock because */
53520Sstevel@tonic-gate 		/* mac stream list is protected by devlock as well as maclock */
53530Sstevel@tonic-gate 		for (nextmac = device->gld_mac_next;
53540Sstevel@tonic-gate 		    nextmac != (gld_mac_info_t *)&device->gld_mac_next;
53550Sstevel@tonic-gate 		    nextmac = nextmac->gldm_next) {
53560Sstevel@tonic-gate 			gld_mac_pvt_t *pvt =
53570Sstevel@tonic-gate 			    (gld_mac_pvt_t *)nextmac->gldm_mac_pvt;
53580Sstevel@tonic-gate 
53590Sstevel@tonic-gate 			if (!(nextmac->gldm_GLD_flags & GLD_MAC_READY))
53600Sstevel@tonic-gate 				continue;	/* this one's not ready yet */
53610Sstevel@tonic-gate 
53620Sstevel@tonic-gate 			for (i = 0; i < VLAN_HASHSZ; i++) {
53630Sstevel@tonic-gate 				for (nextvlan = pvt->vlan_hash[i];
53640Sstevel@tonic-gate 				    nextvlan != NULL;
53650Sstevel@tonic-gate 				    nextvlan = nextvlan->gldv_next) {
53660Sstevel@tonic-gate 					for (next = nextvlan->gldv_str_next;
53670Sstevel@tonic-gate 					    next !=
53680Sstevel@tonic-gate 					    (gld_t *)&nextvlan->gldv_str_next;
53690Sstevel@tonic-gate 					    next = next->gld_next) {
53700Sstevel@tonic-gate 						if (minor == next->gld_minor)
53710Sstevel@tonic-gate 							goto nextminor;
53720Sstevel@tonic-gate 					}
53730Sstevel@tonic-gate 				}
53740Sstevel@tonic-gate 			}
53750Sstevel@tonic-gate 		}
53760Sstevel@tonic-gate 
53770Sstevel@tonic-gate 		return (minor);
53780Sstevel@tonic-gate nextminor:
53790Sstevel@tonic-gate 		/* don't need to do anything */
53800Sstevel@tonic-gate 		;
53810Sstevel@tonic-gate 	}
53820Sstevel@tonic-gate 	cmn_err(CE_WARN, "GLD ran out of minor numbers for %s",
53830Sstevel@tonic-gate 		device->gld_name);
53840Sstevel@tonic-gate 	return (0);
53850Sstevel@tonic-gate }
53860Sstevel@tonic-gate 
53870Sstevel@tonic-gate /*
53880Sstevel@tonic-gate  * version of insque/remque for use by this driver
53890Sstevel@tonic-gate  */
53900Sstevel@tonic-gate struct qelem {
53910Sstevel@tonic-gate 	struct qelem *q_forw;
53920Sstevel@tonic-gate 	struct qelem *q_back;
53930Sstevel@tonic-gate 	/* rest of structure */
53940Sstevel@tonic-gate };
53950Sstevel@tonic-gate 
53960Sstevel@tonic-gate static void
53970Sstevel@tonic-gate gldinsque(void *elem, void *pred)
53980Sstevel@tonic-gate {
53990Sstevel@tonic-gate 	struct qelem *pelem = elem;
54000Sstevel@tonic-gate 	struct qelem *ppred = pred;
54010Sstevel@tonic-gate 	struct qelem *pnext = ppred->q_forw;
54020Sstevel@tonic-gate 
54030Sstevel@tonic-gate 	pelem->q_forw = pnext;
54040Sstevel@tonic-gate 	pelem->q_back = ppred;
54050Sstevel@tonic-gate 	ppred->q_forw = pelem;
54060Sstevel@tonic-gate 	pnext->q_back = pelem;
54070Sstevel@tonic-gate }
54080Sstevel@tonic-gate 
54090Sstevel@tonic-gate static void
54100Sstevel@tonic-gate gldremque(void *arg)
54110Sstevel@tonic-gate {
54120Sstevel@tonic-gate 	struct qelem *pelem = arg;
54130Sstevel@tonic-gate 	struct qelem *elem = arg;
54140Sstevel@tonic-gate 
54150Sstevel@tonic-gate 	pelem->q_forw->q_back = pelem->q_back;
54160Sstevel@tonic-gate 	pelem->q_back->q_forw = pelem->q_forw;
54170Sstevel@tonic-gate 	elem->q_back = elem->q_forw = NULL;
54180Sstevel@tonic-gate }
54190Sstevel@tonic-gate 
54200Sstevel@tonic-gate static gld_vlan_t *
54210Sstevel@tonic-gate gld_add_vlan(gld_mac_info_t *macinfo, uint32_t vid)
54220Sstevel@tonic-gate {
54230Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
54240Sstevel@tonic-gate 	gld_vlan_t	**pp;
54250Sstevel@tonic-gate 	gld_vlan_t	*p;
54260Sstevel@tonic-gate 
54270Sstevel@tonic-gate 	pp = &(mac_pvt->vlan_hash[vid % VLAN_HASHSZ]);
54280Sstevel@tonic-gate 	while ((p = *pp) != NULL) {
54290Sstevel@tonic-gate 		ASSERT(p->gldv_id != vid);
54300Sstevel@tonic-gate 		pp = &(p->gldv_next);
54310Sstevel@tonic-gate 	}
54320Sstevel@tonic-gate 
54330Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (gld_vlan_t), KM_NOSLEEP)) == NULL)
54340Sstevel@tonic-gate 		return (NULL);
54350Sstevel@tonic-gate 
54360Sstevel@tonic-gate 	p->gldv_mac = macinfo;
54370Sstevel@tonic-gate 	p->gldv_id = vid;
54380Sstevel@tonic-gate 
54390Sstevel@tonic-gate 	if (vid == VLAN_VID_NONE) {
54400Sstevel@tonic-gate 		p->gldv_ptag = VLAN_VTAG_NONE;
54410Sstevel@tonic-gate 		p->gldv_stats = mac_pvt->statistics;
54420Sstevel@tonic-gate 		p->gldv_kstatp = NULL;
54430Sstevel@tonic-gate 	} else {
54440Sstevel@tonic-gate 		p->gldv_ptag = GLD_MK_PTAG(VLAN_CFI_ETHER, vid);
54450Sstevel@tonic-gate 		p->gldv_stats = kmem_zalloc(sizeof (struct gld_stats),
54460Sstevel@tonic-gate 		    KM_SLEEP);
54470Sstevel@tonic-gate 
54480Sstevel@tonic-gate 		if (gld_init_vlan_stats(p) != GLD_SUCCESS) {
54490Sstevel@tonic-gate 			kmem_free(p->gldv_stats, sizeof (struct gld_stats));
54500Sstevel@tonic-gate 			kmem_free(p, sizeof (gld_vlan_t));
54510Sstevel@tonic-gate 			return (NULL);
54520Sstevel@tonic-gate 		}
54530Sstevel@tonic-gate 	}
54540Sstevel@tonic-gate 
54550Sstevel@tonic-gate 	p->gldv_str_next = p->gldv_str_prev = (gld_t *)&p->gldv_str_next;
54560Sstevel@tonic-gate 	mac_pvt->nvlan++;
54570Sstevel@tonic-gate 	*pp = p;
54580Sstevel@tonic-gate 
54590Sstevel@tonic-gate 	return (p);
54600Sstevel@tonic-gate }
54610Sstevel@tonic-gate 
54620Sstevel@tonic-gate static void
54630Sstevel@tonic-gate gld_rem_vlan(gld_vlan_t *vlan)
54640Sstevel@tonic-gate {
54650Sstevel@tonic-gate 	gld_mac_info_t	*macinfo = vlan->gldv_mac;
54660Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
54670Sstevel@tonic-gate 	gld_vlan_t	**pp;
54680Sstevel@tonic-gate 	gld_vlan_t	*p;
54690Sstevel@tonic-gate 
54700Sstevel@tonic-gate 	pp = &(mac_pvt->vlan_hash[vlan->gldv_id % VLAN_HASHSZ]);
54710Sstevel@tonic-gate 	while ((p = *pp) != NULL) {
54720Sstevel@tonic-gate 		if (p->gldv_id == vlan->gldv_id)
54730Sstevel@tonic-gate 			break;
54740Sstevel@tonic-gate 		pp = &(p->gldv_next);
54750Sstevel@tonic-gate 	}
54760Sstevel@tonic-gate 	ASSERT(p != NULL);
54770Sstevel@tonic-gate 
54780Sstevel@tonic-gate 	*pp = p->gldv_next;
54790Sstevel@tonic-gate 	mac_pvt->nvlan--;
54800Sstevel@tonic-gate 	if (p->gldv_id != VLAN_VID_NONE) {
54810Sstevel@tonic-gate 		ASSERT(p->gldv_kstatp != NULL);
54820Sstevel@tonic-gate 		kstat_delete(p->gldv_kstatp);
54830Sstevel@tonic-gate 		kmem_free(p->gldv_stats, sizeof (struct gld_stats));
54840Sstevel@tonic-gate 	}
54850Sstevel@tonic-gate 	kmem_free(p, sizeof (gld_vlan_t));
54860Sstevel@tonic-gate }
54870Sstevel@tonic-gate 
54880Sstevel@tonic-gate gld_vlan_t *
54890Sstevel@tonic-gate gld_find_vlan(gld_mac_info_t *macinfo, uint32_t vid)
54900Sstevel@tonic-gate {
54910Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
54920Sstevel@tonic-gate 	gld_vlan_t	*p;
54930Sstevel@tonic-gate 
54940Sstevel@tonic-gate 	p = mac_pvt->vlan_hash[vid % VLAN_HASHSZ];
54950Sstevel@tonic-gate 	while (p != NULL) {
54960Sstevel@tonic-gate 		if (p->gldv_id == vid)
54970Sstevel@tonic-gate 			return (p);
54980Sstevel@tonic-gate 		p = p->gldv_next;
54990Sstevel@tonic-gate 	}
55000Sstevel@tonic-gate 	return (NULL);
55010Sstevel@tonic-gate }
55020Sstevel@tonic-gate 
55030Sstevel@tonic-gate gld_vlan_t *
55040Sstevel@tonic-gate gld_get_vlan(gld_mac_info_t *macinfo, uint32_t vid)
55050Sstevel@tonic-gate {
55060Sstevel@tonic-gate 	gld_vlan_t	*vlan;
55070Sstevel@tonic-gate 
55080Sstevel@tonic-gate 	if ((vlan = gld_find_vlan(macinfo, vid)) == NULL)
55090Sstevel@tonic-gate 		vlan = gld_add_vlan(macinfo, vid);
55100Sstevel@tonic-gate 
55110Sstevel@tonic-gate 	return (vlan);
55120Sstevel@tonic-gate }
55130Sstevel@tonic-gate 
55140Sstevel@tonic-gate /*
55150Sstevel@tonic-gate  * gld_bitrevcopy()
55160Sstevel@tonic-gate  * This is essentially bcopy, with the ability to bit reverse the
55170Sstevel@tonic-gate  * the source bytes. The MAC addresses bytes as transmitted by FDDI
55180Sstevel@tonic-gate  * interfaces are bit reversed.
55190Sstevel@tonic-gate  */
55200Sstevel@tonic-gate void
55210Sstevel@tonic-gate gld_bitrevcopy(caddr_t src, caddr_t target, size_t n)
55220Sstevel@tonic-gate {
55230Sstevel@tonic-gate 	while (n--)
55240Sstevel@tonic-gate 		*target++ = bit_rev[(uchar_t)*src++];
55250Sstevel@tonic-gate }
55260Sstevel@tonic-gate 
55270Sstevel@tonic-gate /*
55280Sstevel@tonic-gate  * gld_bitreverse()
55290Sstevel@tonic-gate  * Convert the bit order by swaping all the bits, using a
55300Sstevel@tonic-gate  * lookup table.
55310Sstevel@tonic-gate  */
55320Sstevel@tonic-gate void
55330Sstevel@tonic-gate gld_bitreverse(uchar_t *rptr, size_t n)
55340Sstevel@tonic-gate {
55350Sstevel@tonic-gate 	while (n--) {
55360Sstevel@tonic-gate 		*rptr = bit_rev[*rptr];
55370Sstevel@tonic-gate 		rptr++;
55380Sstevel@tonic-gate 	}
55390Sstevel@tonic-gate }
55400Sstevel@tonic-gate 
55410Sstevel@tonic-gate char *
55420Sstevel@tonic-gate gld_macaddr_sprintf(char *etherbuf, unsigned char *ap, int len)
55430Sstevel@tonic-gate {
55440Sstevel@tonic-gate 	int i;
55450Sstevel@tonic-gate 	char *cp = etherbuf;
55460Sstevel@tonic-gate 	static char digits[] = "0123456789abcdef";
55470Sstevel@tonic-gate 
55480Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
55490Sstevel@tonic-gate 		*cp++ = digits[*ap >> 4];
55500Sstevel@tonic-gate 		*cp++ = digits[*ap++ & 0xf];
55510Sstevel@tonic-gate 		*cp++ = ':';
55520Sstevel@tonic-gate 	}
55530Sstevel@tonic-gate 	*--cp = 0;
55540Sstevel@tonic-gate 	return (etherbuf);
55550Sstevel@tonic-gate }
55560Sstevel@tonic-gate 
55570Sstevel@tonic-gate #ifdef GLD_DEBUG
55580Sstevel@tonic-gate static void
55590Sstevel@tonic-gate gld_check_assertions()
55600Sstevel@tonic-gate {
55610Sstevel@tonic-gate 	glddev_t	*dev;
55620Sstevel@tonic-gate 	gld_mac_info_t	*mac;
55630Sstevel@tonic-gate 	gld_t		*str;
55640Sstevel@tonic-gate 	gld_vlan_t	*vlan;
55650Sstevel@tonic-gate 	int		i;
55660Sstevel@tonic-gate 
55670Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
55680Sstevel@tonic-gate 
55690Sstevel@tonic-gate 	for (dev = gld_device_list.gld_next;
55700Sstevel@tonic-gate 	    dev != (glddev_t *)&gld_device_list.gld_next;
55710Sstevel@tonic-gate 	    dev = dev->gld_next) {
55720Sstevel@tonic-gate 		mutex_enter(&dev->gld_devlock);
55730Sstevel@tonic-gate 		ASSERT(dev->gld_broadcast != NULL);
55740Sstevel@tonic-gate 		for (str = dev->gld_str_next;
55750Sstevel@tonic-gate 		    str != (gld_t *)&dev->gld_str_next;
55760Sstevel@tonic-gate 		    str = str->gld_next) {
55770Sstevel@tonic-gate 			ASSERT(str->gld_device == dev);
55780Sstevel@tonic-gate 			ASSERT(str->gld_mac_info == NULL);
55790Sstevel@tonic-gate 			ASSERT(str->gld_qptr != NULL);
55800Sstevel@tonic-gate 			ASSERT(str->gld_minor >= GLD_MIN_CLONE_MINOR);
55810Sstevel@tonic-gate 			ASSERT(str->gld_multicnt == 0);
55820Sstevel@tonic-gate 			ASSERT(str->gld_mcast == NULL);
55830Sstevel@tonic-gate 			ASSERT(!(str->gld_flags &
55840Sstevel@tonic-gate 			    (GLD_PROM_PHYS|GLD_PROM_MULT|GLD_PROM_SAP)));
55850Sstevel@tonic-gate 			ASSERT(str->gld_sap == 0);
55860Sstevel@tonic-gate 			ASSERT(str->gld_state == DL_UNATTACHED);
55870Sstevel@tonic-gate 		}
55880Sstevel@tonic-gate 		for (mac = dev->gld_mac_next;
55890Sstevel@tonic-gate 		    mac != (gld_mac_info_t *)&dev->gld_mac_next;
55900Sstevel@tonic-gate 		    mac = mac->gldm_next) {
55910Sstevel@tonic-gate 			int nvlan = 0;
55920Sstevel@tonic-gate 			gld_mac_pvt_t *pvt = (gld_mac_pvt_t *)mac->gldm_mac_pvt;
55930Sstevel@tonic-gate 
55940Sstevel@tonic-gate 			if (!(mac->gldm_GLD_flags & GLD_MAC_READY))
55950Sstevel@tonic-gate 				continue;	/* this one's not ready yet */
55960Sstevel@tonic-gate 
55970Sstevel@tonic-gate 			GLDM_LOCK(mac, RW_WRITER);
55980Sstevel@tonic-gate 			ASSERT(mac->gldm_devinfo != NULL);
55990Sstevel@tonic-gate 			ASSERT(mac->gldm_mac_pvt != NULL);
56000Sstevel@tonic-gate 			ASSERT(pvt->interfacep != NULL);
56010Sstevel@tonic-gate 			ASSERT(pvt->kstatp != NULL);
56020Sstevel@tonic-gate 			ASSERT(pvt->statistics != NULL);
56030Sstevel@tonic-gate 			ASSERT(pvt->major_dev == dev);
56040Sstevel@tonic-gate 
56050Sstevel@tonic-gate 			for (i = 0; i < VLAN_HASHSZ; i++) {
56060Sstevel@tonic-gate 				for (vlan = pvt->vlan_hash[i];
56070Sstevel@tonic-gate 				    vlan != NULL; vlan = vlan->gldv_next) {
56080Sstevel@tonic-gate 					int nstr = 0;
56090Sstevel@tonic-gate 
56100Sstevel@tonic-gate 					ASSERT(vlan->gldv_mac == mac);
56110Sstevel@tonic-gate 
56120Sstevel@tonic-gate 					for (str = vlan->gldv_str_next;
56130Sstevel@tonic-gate 					    str !=
56140Sstevel@tonic-gate 					    (gld_t *)&vlan->gldv_str_next;
56150Sstevel@tonic-gate 					    str = str->gld_next) {
56160Sstevel@tonic-gate 						ASSERT(str->gld_device == dev);
56170Sstevel@tonic-gate 						ASSERT(str->gld_mac_info ==
56180Sstevel@tonic-gate 						    mac);
56190Sstevel@tonic-gate 						ASSERT(str->gld_qptr != NULL);
56200Sstevel@tonic-gate 						ASSERT(str->gld_minor >=
56210Sstevel@tonic-gate 						    GLD_MIN_CLONE_MINOR);
56220Sstevel@tonic-gate 						ASSERT(
56230Sstevel@tonic-gate 						    str->gld_multicnt == 0 ||
56240Sstevel@tonic-gate 						    str->gld_mcast);
56250Sstevel@tonic-gate 						nstr++;
56260Sstevel@tonic-gate 					}
56270Sstevel@tonic-gate 					ASSERT(vlan->gldv_nstreams == nstr);
56280Sstevel@tonic-gate 					nvlan++;
56290Sstevel@tonic-gate 				}
56300Sstevel@tonic-gate 			}
56310Sstevel@tonic-gate 			ASSERT(pvt->nvlan == nvlan);
56320Sstevel@tonic-gate 			GLDM_UNLOCK(mac);
56330Sstevel@tonic-gate 		}
56340Sstevel@tonic-gate 		mutex_exit(&dev->gld_devlock);
56350Sstevel@tonic-gate 	}
56360Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
56370Sstevel@tonic-gate }
56380Sstevel@tonic-gate #endif
5639