xref: /titanic_53/usr/src/uts/common/io/gld.c (revision 0ef0bcfb1f92ed00145c158e6103d7e875f756df)
17c478bd9Sstevel@tonic-gate /*
27c478bd9Sstevel@tonic-gate  * CDDL HEADER START
37c478bd9Sstevel@tonic-gate  *
47c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*0ef0bcfbSyz147064  * Common Development and Distribution License (the "License").
6*0ef0bcfbSyz147064  * You may not use this file except in compliance with the License.
77c478bd9Sstevel@tonic-gate  *
87c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
97c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
107c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
117c478bd9Sstevel@tonic-gate  * and limitations under the License.
127c478bd9Sstevel@tonic-gate  *
137c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
147c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
157c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
167c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
177c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
187c478bd9Sstevel@tonic-gate  *
197c478bd9Sstevel@tonic-gate  * CDDL HEADER END
207c478bd9Sstevel@tonic-gate  */
217c478bd9Sstevel@tonic-gate /*
22*0ef0bcfbSyz147064  * Copyright 2006 Sun Microsystems, Inc.  All rights reserved.
237c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
247c478bd9Sstevel@tonic-gate  */
257c478bd9Sstevel@tonic-gate 
267c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
277c478bd9Sstevel@tonic-gate 
287c478bd9Sstevel@tonic-gate /*
297c478bd9Sstevel@tonic-gate  * gld - Generic LAN Driver Version 2, PSARC/1997/382
307c478bd9Sstevel@tonic-gate  *
317c478bd9Sstevel@tonic-gate  * This is a utility module that provides generic facilities for
327c478bd9Sstevel@tonic-gate  * LAN	drivers.  The DLPI protocol and most STREAMS interfaces
337c478bd9Sstevel@tonic-gate  * are handled here.
347c478bd9Sstevel@tonic-gate  *
357c478bd9Sstevel@tonic-gate  * It no longer provides compatibility with drivers
367c478bd9Sstevel@tonic-gate  * implemented according to the GLD v0 documentation published
377c478bd9Sstevel@tonic-gate  * in 1993. (See PSARC 2003/728)
387c478bd9Sstevel@tonic-gate  */
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate 
417c478bd9Sstevel@tonic-gate #include <sys/types.h>
427c478bd9Sstevel@tonic-gate #include <sys/errno.h>
437c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
447c478bd9Sstevel@tonic-gate #include <sys/stream.h>
457c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
467c478bd9Sstevel@tonic-gate #include <sys/stat.h>
477c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
487c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
497c478bd9Sstevel@tonic-gate #include <sys/debug.h>
507c478bd9Sstevel@tonic-gate #include <sys/note.h>
517c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
527c478bd9Sstevel@tonic-gate 
537c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
547c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
557c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
567c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
577c478bd9Sstevel@tonic-gate #include <sys/pattr.h>
587c478bd9Sstevel@tonic-gate #include <sys/ethernet.h>
597c478bd9Sstevel@tonic-gate #include <sys/ib/clients/ibd/ibd.h>
607c478bd9Sstevel@tonic-gate #include <sys/policy.h>
617c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
627c478bd9Sstevel@tonic-gate 
637c478bd9Sstevel@tonic-gate #include <sys/multidata.h>
647c478bd9Sstevel@tonic-gate #include <sys/gld.h>
657c478bd9Sstevel@tonic-gate #include <sys/gldpriv.h>
667c478bd9Sstevel@tonic-gate 
677c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
687c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
697c478bd9Sstevel@tonic-gate 
707c478bd9Sstevel@tonic-gate /*
717c478bd9Sstevel@tonic-gate  * Macro to atomically increment counters of type uint32_t, uint64_t
727c478bd9Sstevel@tonic-gate  * and ulong_t.
737c478bd9Sstevel@tonic-gate  */
747c478bd9Sstevel@tonic-gate #define	BUMP(stat, delta)	do {				\
757c478bd9Sstevel@tonic-gate 	_NOTE(CONSTANTCONDITION)				\
767c478bd9Sstevel@tonic-gate 	if (sizeof (stat) == sizeof (uint32_t))	{		\
777c478bd9Sstevel@tonic-gate 		atomic_add_32((uint32_t *)&stat, delta);	\
787c478bd9Sstevel@tonic-gate 	_NOTE(CONSTANTCONDITION)				\
797c478bd9Sstevel@tonic-gate 	} else if (sizeof (stat) == sizeof (uint64_t)) {	\
807c478bd9Sstevel@tonic-gate 		atomic_add_64((uint64_t *)&stat, delta);	\
817c478bd9Sstevel@tonic-gate 	}							\
827c478bd9Sstevel@tonic-gate 	_NOTE(CONSTANTCONDITION)				\
837c478bd9Sstevel@tonic-gate } while (0)
847c478bd9Sstevel@tonic-gate 
857c478bd9Sstevel@tonic-gate #define	UPDATE_STATS(vlan, pktinfo, number)	{		\
867c478bd9Sstevel@tonic-gate 	if ((pktinfo).isBroadcast)				\
877c478bd9Sstevel@tonic-gate 		(vlan)->gldv_stats->glds_brdcstxmt += (number);	\
887c478bd9Sstevel@tonic-gate 	else if ((pktinfo).isMulticast)				\
897c478bd9Sstevel@tonic-gate 		(vlan)->gldv_stats->glds_multixmt += (number);	\
907c478bd9Sstevel@tonic-gate 	(vlan)->gldv_stats->glds_bytexmt64 += (pktinfo).pktLen;	\
917c478bd9Sstevel@tonic-gate 	(vlan)->gldv_stats->glds_pktxmt64 += (number);		\
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
957c478bd9Sstevel@tonic-gate int gld_debug = GLDERRS;
967c478bd9Sstevel@tonic-gate #endif
977c478bd9Sstevel@tonic-gate 
987c478bd9Sstevel@tonic-gate /* called from gld_register */
997c478bd9Sstevel@tonic-gate static int gld_initstats(gld_mac_info_t *);
1007c478bd9Sstevel@tonic-gate 
1017c478bd9Sstevel@tonic-gate /* called from kstat mechanism, and from wsrv's get_statistics */
1027c478bd9Sstevel@tonic-gate static int gld_update_kstat(kstat_t *, int);
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /* statistics for additional vlans */
1057c478bd9Sstevel@tonic-gate static int gld_init_vlan_stats(gld_vlan_t *);
1067c478bd9Sstevel@tonic-gate static int gld_update_vlan_kstat(kstat_t *, int);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate /* called from gld_getinfo */
1097c478bd9Sstevel@tonic-gate static dev_info_t *gld_finddevinfo(dev_t);
1107c478bd9Sstevel@tonic-gate 
1117c478bd9Sstevel@tonic-gate /* called from wput, wsrv, unidata, and v0_sched to send a packet */
1127c478bd9Sstevel@tonic-gate /* also from the source routing stuff for sending RDE protocol packets */
1137c478bd9Sstevel@tonic-gate static int gld_start(queue_t *, mblk_t *, int, uint32_t);
1147c478bd9Sstevel@tonic-gate static int gld_start_mdt(queue_t *, mblk_t *, int);
1157c478bd9Sstevel@tonic-gate 
1167c478bd9Sstevel@tonic-gate /* called from gld_start[_mdt] to loopback packet(s) in promiscuous mode */
1177c478bd9Sstevel@tonic-gate static void gld_precv(gld_mac_info_t *, gld_vlan_t *, mblk_t *);
1187c478bd9Sstevel@tonic-gate static void gld_precv_mdt(gld_mac_info_t *, gld_vlan_t *, mblk_t *,
1197c478bd9Sstevel@tonic-gate     pdesc_t *, pktinfo_t *);
1207c478bd9Sstevel@tonic-gate 
1217c478bd9Sstevel@tonic-gate /* receive group: called from gld_recv and gld_precv* with maclock held */
1227c478bd9Sstevel@tonic-gate static void gld_sendup(gld_mac_info_t *, gld_vlan_t *, pktinfo_t *, mblk_t *,
1237c478bd9Sstevel@tonic-gate     int (*)());
1247c478bd9Sstevel@tonic-gate static int gld_accept(gld_t *, pktinfo_t *);
1257c478bd9Sstevel@tonic-gate static int gld_mcmatch(gld_t *, pktinfo_t *);
1267c478bd9Sstevel@tonic-gate static int gld_multicast(unsigned char *, gld_t *);
1277c478bd9Sstevel@tonic-gate static int gld_paccept(gld_t *, pktinfo_t *);
1287c478bd9Sstevel@tonic-gate static void gld_passon(gld_t *, mblk_t *, pktinfo_t *,
1297c478bd9Sstevel@tonic-gate     void (*)(queue_t *, mblk_t *));
1307c478bd9Sstevel@tonic-gate static mblk_t *gld_addudind(gld_t *, mblk_t *, pktinfo_t *);
1317c478bd9Sstevel@tonic-gate 
1327c478bd9Sstevel@tonic-gate /* wsrv group: called from wsrv, single threaded per queue */
1337c478bd9Sstevel@tonic-gate static int gld_ioctl(queue_t *, mblk_t *);
1347c478bd9Sstevel@tonic-gate static void gld_fastpath(gld_t *, queue_t *, mblk_t *);
1357c478bd9Sstevel@tonic-gate static int gld_cmds(queue_t *, mblk_t *);
1367c478bd9Sstevel@tonic-gate static mblk_t *gld_bindack(queue_t *, mblk_t *);
1377c478bd9Sstevel@tonic-gate static int gld_notify_req(queue_t *, mblk_t *);
1387c478bd9Sstevel@tonic-gate static int gld_udqos(queue_t *, mblk_t *);
1397c478bd9Sstevel@tonic-gate static int gld_bind(queue_t *, mblk_t *);
1407c478bd9Sstevel@tonic-gate static int gld_unbind(queue_t *, mblk_t *);
1417c478bd9Sstevel@tonic-gate static int gld_inforeq(queue_t *, mblk_t *);
1427c478bd9Sstevel@tonic-gate static int gld_unitdata(queue_t *, mblk_t *);
1437c478bd9Sstevel@tonic-gate static int gldattach(queue_t *, mblk_t *);
1447c478bd9Sstevel@tonic-gate static int gldunattach(queue_t *, mblk_t *);
1457c478bd9Sstevel@tonic-gate static int gld_enable_multi(queue_t *, mblk_t *);
1467c478bd9Sstevel@tonic-gate static int gld_disable_multi(queue_t *, mblk_t *);
1477c478bd9Sstevel@tonic-gate static void gld_send_disable_multi(gld_mac_info_t *, gld_mcast_t *);
1487c478bd9Sstevel@tonic-gate static int gld_promisc(queue_t *, mblk_t *, t_uscalar_t, boolean_t);
1497c478bd9Sstevel@tonic-gate static int gld_physaddr(queue_t *, mblk_t *);
1507c478bd9Sstevel@tonic-gate static int gld_setaddr(queue_t *, mblk_t *);
1517c478bd9Sstevel@tonic-gate static int gld_get_statistics(queue_t *, mblk_t *);
1527c478bd9Sstevel@tonic-gate static int gld_cap(queue_t *, mblk_t *);
1537c478bd9Sstevel@tonic-gate static int gld_cap_ack(queue_t *, mblk_t *);
1547c478bd9Sstevel@tonic-gate static int gld_cap_enable(queue_t *, mblk_t *);
1557c478bd9Sstevel@tonic-gate 
1567c478bd9Sstevel@tonic-gate /* misc utilities, some requiring various mutexes held */
1577c478bd9Sstevel@tonic-gate static int gld_start_mac(gld_mac_info_t *);
1587c478bd9Sstevel@tonic-gate static void gld_stop_mac(gld_mac_info_t *);
1597c478bd9Sstevel@tonic-gate static void gld_set_ipq(gld_t *);
1607c478bd9Sstevel@tonic-gate static void gld_flushqueue(queue_t *);
1617c478bd9Sstevel@tonic-gate static glddev_t *gld_devlookup(int);
1627c478bd9Sstevel@tonic-gate static int gld_findminor(glddev_t *);
1637c478bd9Sstevel@tonic-gate static void gldinsque(void *, void *);
1647c478bd9Sstevel@tonic-gate static void gldremque(void *);
1657c478bd9Sstevel@tonic-gate void gld_bitrevcopy(caddr_t, caddr_t, size_t);
1667c478bd9Sstevel@tonic-gate void gld_bitreverse(uchar_t *, size_t);
1677c478bd9Sstevel@tonic-gate char *gld_macaddr_sprintf(char *, unsigned char *, int);
1687c478bd9Sstevel@tonic-gate static gld_vlan_t *gld_add_vlan(gld_mac_info_t *, uint32_t vid);
1697c478bd9Sstevel@tonic-gate static void gld_rem_vlan(gld_vlan_t *);
1707c478bd9Sstevel@tonic-gate gld_vlan_t *gld_find_vlan(gld_mac_info_t *, uint32_t);
1717c478bd9Sstevel@tonic-gate gld_vlan_t *gld_get_vlan(gld_mac_info_t *, uint32_t);
1727c478bd9Sstevel@tonic-gate 
1737c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1747c478bd9Sstevel@tonic-gate static void gld_check_assertions(void);
1757c478bd9Sstevel@tonic-gate extern void gld_sr_dump(gld_mac_info_t *);
1767c478bd9Sstevel@tonic-gate #endif
1777c478bd9Sstevel@tonic-gate 
1787c478bd9Sstevel@tonic-gate /*
1797c478bd9Sstevel@tonic-gate  * Allocate and zero-out "number" structures each of type "structure" in
1807c478bd9Sstevel@tonic-gate  * kernel memory.
1817c478bd9Sstevel@tonic-gate  */
1827c478bd9Sstevel@tonic-gate #define	GETSTRUCT(structure, number)   \
1837c478bd9Sstevel@tonic-gate 	(kmem_zalloc((uint_t)(sizeof (structure) * (number)), KM_NOSLEEP))
1847c478bd9Sstevel@tonic-gate 
1857c478bd9Sstevel@tonic-gate #define	abs(a) ((a) < 0 ? -(a) : a)
1867c478bd9Sstevel@tonic-gate 
1877c478bd9Sstevel@tonic-gate uint32_t gld_global_options = GLD_OPT_NO_ETHRXSNAP;
1887c478bd9Sstevel@tonic-gate 
1897c478bd9Sstevel@tonic-gate /*
1907c478bd9Sstevel@tonic-gate  * VLANs are only supported on ethernet devices that manipulate VLAN headers
1917c478bd9Sstevel@tonic-gate  * themselves.
1927c478bd9Sstevel@tonic-gate  */
1937c478bd9Sstevel@tonic-gate #define	VLAN_CAPABLE(macinfo) \
1947c478bd9Sstevel@tonic-gate 	((macinfo)->gldm_type == DL_ETHER && \
1957c478bd9Sstevel@tonic-gate 	(macinfo)->gldm_send_tagged != NULL)
1967c478bd9Sstevel@tonic-gate 
1977c478bd9Sstevel@tonic-gate /*
1987c478bd9Sstevel@tonic-gate  * The set of notifications generatable by GLD itself, the additional
1997c478bd9Sstevel@tonic-gate  * set that can be generated if the MAC driver provide the link-state
2007c478bd9Sstevel@tonic-gate  * tracking callback capability, and the set supported by the GLD
2017c478bd9Sstevel@tonic-gate  * notification code below.
2027c478bd9Sstevel@tonic-gate  *
2037c478bd9Sstevel@tonic-gate  * PLEASE keep these in sync with what the code actually does!
2047c478bd9Sstevel@tonic-gate  */
2057c478bd9Sstevel@tonic-gate static const uint32_t gld_internal_notes =	DL_NOTE_PROMISC_ON_PHYS |
2067c478bd9Sstevel@tonic-gate 						DL_NOTE_PROMISC_OFF_PHYS |
2077c478bd9Sstevel@tonic-gate 						DL_NOTE_PHYS_ADDR;
2087c478bd9Sstevel@tonic-gate static const uint32_t gld_linkstate_notes =	DL_NOTE_LINK_DOWN |
2097c478bd9Sstevel@tonic-gate 						DL_NOTE_LINK_UP |
2107c478bd9Sstevel@tonic-gate 						DL_NOTE_SPEED;
2117c478bd9Sstevel@tonic-gate static const uint32_t gld_supported_notes =	DL_NOTE_PROMISC_ON_PHYS |
2127c478bd9Sstevel@tonic-gate 						DL_NOTE_PROMISC_OFF_PHYS |
2137c478bd9Sstevel@tonic-gate 						DL_NOTE_PHYS_ADDR |
2147c478bd9Sstevel@tonic-gate 						DL_NOTE_LINK_DOWN |
2157c478bd9Sstevel@tonic-gate 						DL_NOTE_LINK_UP |
2167c478bd9Sstevel@tonic-gate 						DL_NOTE_SPEED;
2177c478bd9Sstevel@tonic-gate 
2187c478bd9Sstevel@tonic-gate /* Media must correspond to #defines in gld.h */
2197c478bd9Sstevel@tonic-gate static char *gld_media[] = {
2207c478bd9Sstevel@tonic-gate 	"unknown",	/* GLDM_UNKNOWN - driver cannot determine media */
2217c478bd9Sstevel@tonic-gate 	"aui",		/* GLDM_AUI */
2227c478bd9Sstevel@tonic-gate 	"bnc",		/* GLDM_BNC */
2237c478bd9Sstevel@tonic-gate 	"twpair",	/* GLDM_TP */
2247c478bd9Sstevel@tonic-gate 	"fiber",	/* GLDM_FIBER */
2257c478bd9Sstevel@tonic-gate 	"100baseT",	/* GLDM_100BT */
2267c478bd9Sstevel@tonic-gate 	"100vgAnyLan",	/* GLDM_VGANYLAN */
2277c478bd9Sstevel@tonic-gate 	"10baseT",	/* GLDM_10BT */
2287c478bd9Sstevel@tonic-gate 	"ring4",	/* GLDM_RING4 */
2297c478bd9Sstevel@tonic-gate 	"ring16",	/* GLDM_RING16 */
2307c478bd9Sstevel@tonic-gate 	"PHY/MII",	/* GLDM_PHYMII */
2317c478bd9Sstevel@tonic-gate 	"100baseTX",	/* GLDM_100BTX */
2327c478bd9Sstevel@tonic-gate 	"100baseT4",	/* GLDM_100BT4 */
2337c478bd9Sstevel@tonic-gate 	"unknown",	/* skip */
2347c478bd9Sstevel@tonic-gate 	"ipib",		/* GLDM_IB */
2357c478bd9Sstevel@tonic-gate };
2367c478bd9Sstevel@tonic-gate 
2377c478bd9Sstevel@tonic-gate /* Must correspond to #defines in gld.h */
2387c478bd9Sstevel@tonic-gate static char *gld_duplex[] = {
2397c478bd9Sstevel@tonic-gate 	"unknown",	/* GLD_DUPLEX_UNKNOWN - not known or not applicable */
2407c478bd9Sstevel@tonic-gate 	"half",		/* GLD_DUPLEX_HALF */
2417c478bd9Sstevel@tonic-gate 	"full"		/* GLD_DUPLEX_FULL */
2427c478bd9Sstevel@tonic-gate };
2437c478bd9Sstevel@tonic-gate 
2447c478bd9Sstevel@tonic-gate extern int gld_interpret_ether(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
2457c478bd9Sstevel@tonic-gate extern int gld_interpret_fddi(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
2467c478bd9Sstevel@tonic-gate extern int gld_interpret_tr(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
2477c478bd9Sstevel@tonic-gate extern int gld_interpret_ib(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
2487c478bd9Sstevel@tonic-gate extern void gld_interpret_mdt_ib(gld_mac_info_t *, mblk_t *, pdescinfo_t *,
2497c478bd9Sstevel@tonic-gate     pktinfo_t *, int);
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate extern mblk_t *gld_fastpath_ether(gld_t *, mblk_t *);
2527c478bd9Sstevel@tonic-gate extern mblk_t *gld_fastpath_fddi(gld_t *, mblk_t *);
2537c478bd9Sstevel@tonic-gate extern mblk_t *gld_fastpath_tr(gld_t *, mblk_t *);
2547c478bd9Sstevel@tonic-gate extern mblk_t *gld_fastpath_ib(gld_t *, mblk_t *);
2557c478bd9Sstevel@tonic-gate 
2567c478bd9Sstevel@tonic-gate extern mblk_t *gld_unitdata_ether(gld_t *, mblk_t *);
2577c478bd9Sstevel@tonic-gate extern mblk_t *gld_unitdata_fddi(gld_t *, mblk_t *);
2587c478bd9Sstevel@tonic-gate extern mblk_t *gld_unitdata_tr(gld_t *, mblk_t *);
2597c478bd9Sstevel@tonic-gate extern mblk_t *gld_unitdata_ib(gld_t *, mblk_t *);
2607c478bd9Sstevel@tonic-gate 
2617c478bd9Sstevel@tonic-gate extern void gld_init_ether(gld_mac_info_t *);
2627c478bd9Sstevel@tonic-gate extern void gld_init_fddi(gld_mac_info_t *);
2637c478bd9Sstevel@tonic-gate extern void gld_init_tr(gld_mac_info_t *);
2647c478bd9Sstevel@tonic-gate extern void gld_init_ib(gld_mac_info_t *);
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate extern void gld_uninit_ether(gld_mac_info_t *);
2677c478bd9Sstevel@tonic-gate extern void gld_uninit_fddi(gld_mac_info_t *);
2687c478bd9Sstevel@tonic-gate extern void gld_uninit_tr(gld_mac_info_t *);
2697c478bd9Sstevel@tonic-gate extern void gld_uninit_ib(gld_mac_info_t *);
2707c478bd9Sstevel@tonic-gate 
2717c478bd9Sstevel@tonic-gate /*
2727c478bd9Sstevel@tonic-gate  * Interface types currently supported by GLD.
2737c478bd9Sstevel@tonic-gate  * If you add new types, you must check all "XXX" strings in the GLD source
2747c478bd9Sstevel@tonic-gate  * for implementation issues that may affect the support of your new type.
2757c478bd9Sstevel@tonic-gate  * In particular, any type with gldm_addrlen > 6, or gldm_saplen != -2, will
2767c478bd9Sstevel@tonic-gate  * require generalizing this GLD source to handle the new cases.  In other
2777c478bd9Sstevel@tonic-gate  * words there are assumptions built into the code in a few places that must
2787c478bd9Sstevel@tonic-gate  * be fixed.  Be sure to turn on DEBUG/ASSERT code when testing a new type.
2797c478bd9Sstevel@tonic-gate  */
2807c478bd9Sstevel@tonic-gate static gld_interface_t interfaces[] = {
2817c478bd9Sstevel@tonic-gate 
2827c478bd9Sstevel@tonic-gate 	/* Ethernet Bus */
2837c478bd9Sstevel@tonic-gate 	{
2847c478bd9Sstevel@tonic-gate 		DL_ETHER,
2857c478bd9Sstevel@tonic-gate 		(uint_t)-1,
2867c478bd9Sstevel@tonic-gate 		sizeof (struct ether_mac_frm),
2877c478bd9Sstevel@tonic-gate 		gld_interpret_ether,
2887c478bd9Sstevel@tonic-gate 		NULL,
2897c478bd9Sstevel@tonic-gate 		gld_fastpath_ether,
2907c478bd9Sstevel@tonic-gate 		gld_unitdata_ether,
2917c478bd9Sstevel@tonic-gate 		gld_init_ether,
2927c478bd9Sstevel@tonic-gate 		gld_uninit_ether,
2937c478bd9Sstevel@tonic-gate 		"ether"
2947c478bd9Sstevel@tonic-gate 	},
2957c478bd9Sstevel@tonic-gate 
2967c478bd9Sstevel@tonic-gate 	/* Fiber Distributed data interface */
2977c478bd9Sstevel@tonic-gate 	{
2987c478bd9Sstevel@tonic-gate 		DL_FDDI,
2997c478bd9Sstevel@tonic-gate 		4352,
3007c478bd9Sstevel@tonic-gate 		sizeof (struct fddi_mac_frm),
3017c478bd9Sstevel@tonic-gate 		gld_interpret_fddi,
3027c478bd9Sstevel@tonic-gate 		NULL,
3037c478bd9Sstevel@tonic-gate 		gld_fastpath_fddi,
3047c478bd9Sstevel@tonic-gate 		gld_unitdata_fddi,
3057c478bd9Sstevel@tonic-gate 		gld_init_fddi,
3067c478bd9Sstevel@tonic-gate 		gld_uninit_fddi,
3077c478bd9Sstevel@tonic-gate 		"fddi"
3087c478bd9Sstevel@tonic-gate 	},
3097c478bd9Sstevel@tonic-gate 
3107c478bd9Sstevel@tonic-gate 	/* Token Ring interface */
3117c478bd9Sstevel@tonic-gate 	{
3127c478bd9Sstevel@tonic-gate 		DL_TPR,
3137c478bd9Sstevel@tonic-gate 		17914,
3147c478bd9Sstevel@tonic-gate 		-1,			/* variable header size */
3157c478bd9Sstevel@tonic-gate 		gld_interpret_tr,
3167c478bd9Sstevel@tonic-gate 		NULL,
3177c478bd9Sstevel@tonic-gate 		gld_fastpath_tr,
3187c478bd9Sstevel@tonic-gate 		gld_unitdata_tr,
3197c478bd9Sstevel@tonic-gate 		gld_init_tr,
3207c478bd9Sstevel@tonic-gate 		gld_uninit_tr,
3217c478bd9Sstevel@tonic-gate 		"tpr"
3227c478bd9Sstevel@tonic-gate 	},
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	/* Infiniband */
3257c478bd9Sstevel@tonic-gate 	{
3267c478bd9Sstevel@tonic-gate 		DL_IB,
3277c478bd9Sstevel@tonic-gate 		4092,
3287c478bd9Sstevel@tonic-gate 		sizeof (struct ipoib_header),
3297c478bd9Sstevel@tonic-gate 		gld_interpret_ib,
3307c478bd9Sstevel@tonic-gate 		gld_interpret_mdt_ib,
3317c478bd9Sstevel@tonic-gate 		gld_fastpath_ib,
3327c478bd9Sstevel@tonic-gate 		gld_unitdata_ib,
3337c478bd9Sstevel@tonic-gate 		gld_init_ib,
3347c478bd9Sstevel@tonic-gate 		gld_uninit_ib,
3357c478bd9Sstevel@tonic-gate 		"ipib"
3367c478bd9Sstevel@tonic-gate 	},
3377c478bd9Sstevel@tonic-gate };
3387c478bd9Sstevel@tonic-gate 
3397c478bd9Sstevel@tonic-gate /*
3407c478bd9Sstevel@tonic-gate  * bit reversal lookup table.
3417c478bd9Sstevel@tonic-gate  */
3427c478bd9Sstevel@tonic-gate static	uchar_t bit_rev[] = {
3437c478bd9Sstevel@tonic-gate 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0,
3447c478bd9Sstevel@tonic-gate 	0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
3457c478bd9Sstevel@tonic-gate 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4,
3467c478bd9Sstevel@tonic-gate 	0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
3477c478bd9Sstevel@tonic-gate 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc,
3487c478bd9Sstevel@tonic-gate 	0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
3497c478bd9Sstevel@tonic-gate 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca,
3507c478bd9Sstevel@tonic-gate 	0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
3517c478bd9Sstevel@tonic-gate 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6,
3527c478bd9Sstevel@tonic-gate 	0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
3537c478bd9Sstevel@tonic-gate 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1,
3547c478bd9Sstevel@tonic-gate 	0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
3557c478bd9Sstevel@tonic-gate 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
3567c478bd9Sstevel@tonic-gate 	0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
3577c478bd9Sstevel@tonic-gate 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd,
3587c478bd9Sstevel@tonic-gate 	0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
3597c478bd9Sstevel@tonic-gate 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3,
3607c478bd9Sstevel@tonic-gate 	0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
3617c478bd9Sstevel@tonic-gate 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7,
3627c478bd9Sstevel@tonic-gate 	0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
3637c478bd9Sstevel@tonic-gate 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf,
3647c478bd9Sstevel@tonic-gate 	0x3f, 0xbf, 0x7f, 0xff,
3657c478bd9Sstevel@tonic-gate };
3667c478bd9Sstevel@tonic-gate 
3677c478bd9Sstevel@tonic-gate /*
3687c478bd9Sstevel@tonic-gate  * User priorities, mapped from b_band.
3697c478bd9Sstevel@tonic-gate  */
3707c478bd9Sstevel@tonic-gate static uint32_t user_priority[] = {
3717c478bd9Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3727c478bd9Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3737c478bd9Sstevel@tonic-gate 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3747c478bd9Sstevel@tonic-gate 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3757c478bd9Sstevel@tonic-gate 	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3767c478bd9Sstevel@tonic-gate 	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3777c478bd9Sstevel@tonic-gate 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3787c478bd9Sstevel@tonic-gate 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3797c478bd9Sstevel@tonic-gate 	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3807c478bd9Sstevel@tonic-gate 	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3817c478bd9Sstevel@tonic-gate 	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3827c478bd9Sstevel@tonic-gate 	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3837c478bd9Sstevel@tonic-gate 	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
3847c478bd9Sstevel@tonic-gate 	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
3857c478bd9Sstevel@tonic-gate 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3867c478bd9Sstevel@tonic-gate 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
3877c478bd9Sstevel@tonic-gate };
3887c478bd9Sstevel@tonic-gate 
3897c478bd9Sstevel@tonic-gate #define	UPRI(gld, band)	((band != 0) ? user_priority[(band)] : (gld)->gld_upri)
3907c478bd9Sstevel@tonic-gate 
3917c478bd9Sstevel@tonic-gate static struct glddevice gld_device_list;  /* Per-system root of GLD tables */
3927c478bd9Sstevel@tonic-gate 
3937c478bd9Sstevel@tonic-gate /*
3947c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
3957c478bd9Sstevel@tonic-gate  */
3967c478bd9Sstevel@tonic-gate 
3977c478bd9Sstevel@tonic-gate static struct modldrv modlmisc = {
3987c478bd9Sstevel@tonic-gate 	&mod_miscops,		/* Type of module - a utility provider */
3997c478bd9Sstevel@tonic-gate 	"Generic LAN Driver (" GLD_VERSION_STRING ") %I%"
4007c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
4017c478bd9Sstevel@tonic-gate 	" DEBUG"
4027c478bd9Sstevel@tonic-gate #endif
4037c478bd9Sstevel@tonic-gate };
4047c478bd9Sstevel@tonic-gate 
4057c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
4067c478bd9Sstevel@tonic-gate 	MODREV_1, &modlmisc, NULL
4077c478bd9Sstevel@tonic-gate };
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate int
4107c478bd9Sstevel@tonic-gate _init(void)
4117c478bd9Sstevel@tonic-gate {
4127c478bd9Sstevel@tonic-gate 	int e;
4137c478bd9Sstevel@tonic-gate 
4147c478bd9Sstevel@tonic-gate 	/* initialize gld_device_list mutex */
4157c478bd9Sstevel@tonic-gate 	mutex_init(&gld_device_list.gld_devlock, NULL, MUTEX_DRIVER, NULL);
4167c478bd9Sstevel@tonic-gate 
4177c478bd9Sstevel@tonic-gate 	/* initialize device driver (per-major) list */
4187c478bd9Sstevel@tonic-gate 	gld_device_list.gld_next =
4197c478bd9Sstevel@tonic-gate 	    gld_device_list.gld_prev = &gld_device_list;
4207c478bd9Sstevel@tonic-gate 
4217c478bd9Sstevel@tonic-gate 	if ((e = mod_install(&modlinkage)) != 0)
4227c478bd9Sstevel@tonic-gate 		mutex_destroy(&gld_device_list.gld_devlock);
4237c478bd9Sstevel@tonic-gate 
4247c478bd9Sstevel@tonic-gate 	return (e);
4257c478bd9Sstevel@tonic-gate }
4267c478bd9Sstevel@tonic-gate 
4277c478bd9Sstevel@tonic-gate int
4287c478bd9Sstevel@tonic-gate _fini(void)
4297c478bd9Sstevel@tonic-gate {
4307c478bd9Sstevel@tonic-gate 	int e;
4317c478bd9Sstevel@tonic-gate 
4327c478bd9Sstevel@tonic-gate 	if ((e = mod_remove(&modlinkage)) != 0)
4337c478bd9Sstevel@tonic-gate 		return (e);
4347c478bd9Sstevel@tonic-gate 
4357c478bd9Sstevel@tonic-gate 	ASSERT(gld_device_list.gld_next ==
4367c478bd9Sstevel@tonic-gate 	    (glddev_t *)&gld_device_list.gld_next);
4377c478bd9Sstevel@tonic-gate 	ASSERT(gld_device_list.gld_prev ==
4387c478bd9Sstevel@tonic-gate 	    (glddev_t *)&gld_device_list.gld_next);
4397c478bd9Sstevel@tonic-gate 	mutex_destroy(&gld_device_list.gld_devlock);
4407c478bd9Sstevel@tonic-gate 
4417c478bd9Sstevel@tonic-gate 	return (e);
4427c478bd9Sstevel@tonic-gate }
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate int
4457c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
4467c478bd9Sstevel@tonic-gate {
4477c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
4487c478bd9Sstevel@tonic-gate }
4497c478bd9Sstevel@tonic-gate 
4507c478bd9Sstevel@tonic-gate /*
4517c478bd9Sstevel@tonic-gate  * GLD service routines
4527c478bd9Sstevel@tonic-gate  */
4537c478bd9Sstevel@tonic-gate 
4547c478bd9Sstevel@tonic-gate /* So this gld binary maybe can be forward compatible with future v2 drivers */
4557c478bd9Sstevel@tonic-gate #define	GLD_MAC_RESERVED (16 * sizeof (caddr_t))
4567c478bd9Sstevel@tonic-gate 
4577c478bd9Sstevel@tonic-gate /*ARGSUSED*/
4587c478bd9Sstevel@tonic-gate gld_mac_info_t *
4597c478bd9Sstevel@tonic-gate gld_mac_alloc(dev_info_t *devinfo)
4607c478bd9Sstevel@tonic-gate {
4617c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
4627c478bd9Sstevel@tonic-gate 
4637c478bd9Sstevel@tonic-gate 	macinfo = kmem_zalloc(sizeof (gld_mac_info_t) + GLD_MAC_RESERVED,
4647c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
4657c478bd9Sstevel@tonic-gate 
4667c478bd9Sstevel@tonic-gate 	/*
4677c478bd9Sstevel@tonic-gate 	 * The setting of gldm_driver_version will not be documented or allowed
4687c478bd9Sstevel@tonic-gate 	 * until a future release.
4697c478bd9Sstevel@tonic-gate 	 */
4707c478bd9Sstevel@tonic-gate 	macinfo->gldm_driver_version = GLD_VERSION_200;
4717c478bd9Sstevel@tonic-gate 
4727c478bd9Sstevel@tonic-gate 	/*
4737c478bd9Sstevel@tonic-gate 	 * GLD's version.  This also is undocumented for now, but will be
4747c478bd9Sstevel@tonic-gate 	 * available if needed in the future.
4757c478bd9Sstevel@tonic-gate 	 */
4767c478bd9Sstevel@tonic-gate 	macinfo->gldm_GLD_version = GLD_VERSION;
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate 	return (macinfo);
4797c478bd9Sstevel@tonic-gate }
4807c478bd9Sstevel@tonic-gate 
4817c478bd9Sstevel@tonic-gate /*
4827c478bd9Sstevel@tonic-gate  * gld_mac_free must be called after the driver has removed interrupts
4837c478bd9Sstevel@tonic-gate  * and completely stopped calling gld_recv() and gld_sched().  At that
4847c478bd9Sstevel@tonic-gate  * point the interrupt routine is guaranteed by the system to have been
4857c478bd9Sstevel@tonic-gate  * exited and the maclock is no longer needed.  Of course, it is
4867c478bd9Sstevel@tonic-gate  * expected (required) that (assuming gld_register() succeeded),
4877c478bd9Sstevel@tonic-gate  * gld_unregister() was called before gld_mac_free().
4887c478bd9Sstevel@tonic-gate  */
4897c478bd9Sstevel@tonic-gate void
4907c478bd9Sstevel@tonic-gate gld_mac_free(gld_mac_info_t *macinfo)
4917c478bd9Sstevel@tonic-gate {
4927c478bd9Sstevel@tonic-gate 	ASSERT(macinfo);
4937c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_GLD_version == GLD_VERSION);
4947c478bd9Sstevel@tonic-gate 
4957c478bd9Sstevel@tonic-gate 	/*
4967c478bd9Sstevel@tonic-gate 	 * Assert that if we made it through gld_register, then we must
4977c478bd9Sstevel@tonic-gate 	 * have unregistered.
4987c478bd9Sstevel@tonic-gate 	 */
4997c478bd9Sstevel@tonic-gate 	ASSERT(!GLDM_LOCK_INITED(macinfo) ||
5007c478bd9Sstevel@tonic-gate 	    (macinfo->gldm_GLD_flags & GLD_UNREGISTERED));
5017c478bd9Sstevel@tonic-gate 
5027c478bd9Sstevel@tonic-gate 	GLDM_LOCK_DESTROY(macinfo);
5037c478bd9Sstevel@tonic-gate 
5047c478bd9Sstevel@tonic-gate 	kmem_free(macinfo, sizeof (gld_mac_info_t) + GLD_MAC_RESERVED);
5057c478bd9Sstevel@tonic-gate }
5067c478bd9Sstevel@tonic-gate 
5077c478bd9Sstevel@tonic-gate /*
5087c478bd9Sstevel@tonic-gate  * gld_register -- called once per device instance (PPA)
5097c478bd9Sstevel@tonic-gate  *
5107c478bd9Sstevel@tonic-gate  * During its attach routine, a real device driver will register with GLD
5117c478bd9Sstevel@tonic-gate  * so that later opens and dl_attach_reqs will work.  The arguments are the
5127c478bd9Sstevel@tonic-gate  * devinfo pointer, the device name, and a macinfo structure describing the
5137c478bd9Sstevel@tonic-gate  * physical device instance.
5147c478bd9Sstevel@tonic-gate  */
5157c478bd9Sstevel@tonic-gate int
5167c478bd9Sstevel@tonic-gate gld_register(dev_info_t *devinfo, char *devname, gld_mac_info_t *macinfo)
5177c478bd9Sstevel@tonic-gate {
5187c478bd9Sstevel@tonic-gate 	int mediatype;
5197c478bd9Sstevel@tonic-gate 	int major = ddi_name_to_major(devname), i;
5207c478bd9Sstevel@tonic-gate 	glddev_t *glddev;
5217c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
5227c478bd9Sstevel@tonic-gate 	char minordev[32];
5237c478bd9Sstevel@tonic-gate 	char pbuf[3*GLD_MAX_ADDRLEN];
5247c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
5257c478bd9Sstevel@tonic-gate 
5267c478bd9Sstevel@tonic-gate 	ASSERT(devinfo != NULL);
5277c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
5287c478bd9Sstevel@tonic-gate 
5297c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_driver_version != GLD_VERSION)
5307c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5317c478bd9Sstevel@tonic-gate 
5327c478bd9Sstevel@tonic-gate 	mediatype = macinfo->gldm_type;
5337c478bd9Sstevel@tonic-gate 
5347c478bd9Sstevel@tonic-gate 	/*
5357c478bd9Sstevel@tonic-gate 	 * Entry points should be ready for us.
5367c478bd9Sstevel@tonic-gate 	 * ioctl is optional.
5377c478bd9Sstevel@tonic-gate 	 * set_multicast and get_stats are optional in v0.
5387c478bd9Sstevel@tonic-gate 	 * intr is only required if you add an interrupt.
5397c478bd9Sstevel@tonic-gate 	 */
5407c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_reset != NULL);
5417c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_start != NULL);
5427c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_stop != NULL);
5437c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_set_mac_addr != NULL);
5447c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_set_promiscuous != NULL);
5457c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_send != NULL);
5467c478bd9Sstevel@tonic-gate 
5477c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_maxpkt >= macinfo->gldm_minpkt);
5487c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_GLD_version == GLD_VERSION);
5497c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_broadcast_addr != NULL);
5507c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_vendor_addr != NULL);
5517c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_ident != NULL);
5527c478bd9Sstevel@tonic-gate 
5537c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_addrlen > GLD_MAX_ADDRLEN) {
5547c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "GLD: %s driver gldm_addrlen %d > %d not sup"
5557c478bd9Sstevel@tonic-gate 		    "ported", devname, macinfo->gldm_addrlen, GLD_MAX_ADDRLEN);
5567c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5577c478bd9Sstevel@tonic-gate 	}
5587c478bd9Sstevel@tonic-gate 
5597c478bd9Sstevel@tonic-gate 	/*
5607c478bd9Sstevel@tonic-gate 	 * GLD only functions properly with saplen == -2
5617c478bd9Sstevel@tonic-gate 	 */
5627c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_saplen != -2) {
5637c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "GLD: %s driver gldm_saplen %d != -2 "
5647c478bd9Sstevel@tonic-gate 		    "not supported", devname, macinfo->gldm_saplen);
5657c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
5667c478bd9Sstevel@tonic-gate 	}
5677c478bd9Sstevel@tonic-gate 
5687c478bd9Sstevel@tonic-gate 	/* see gld_rsrv() */
5697c478bd9Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_NONE, devinfo, 0, "fast_recv", 0))
5707c478bd9Sstevel@tonic-gate 		macinfo->gldm_options |= GLDOPT_FAST_RECV;
5717c478bd9Sstevel@tonic-gate 
5727c478bd9Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
5737c478bd9Sstevel@tonic-gate 	glddev = gld_devlookup(major);
5747c478bd9Sstevel@tonic-gate 
5757c478bd9Sstevel@tonic-gate 	/*
5767c478bd9Sstevel@tonic-gate 	 *  Allocate per-driver (major) data structure if necessary
5777c478bd9Sstevel@tonic-gate 	 */
5787c478bd9Sstevel@tonic-gate 	if (glddev == NULL) {
5797c478bd9Sstevel@tonic-gate 		/* first occurrence of this device name (major number) */
5807c478bd9Sstevel@tonic-gate 		glddev = GETSTRUCT(glddev_t, 1);
5817c478bd9Sstevel@tonic-gate 		if (glddev == NULL) {
5827c478bd9Sstevel@tonic-gate 			mutex_exit(&gld_device_list.gld_devlock);
5837c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
5847c478bd9Sstevel@tonic-gate 		}
5857c478bd9Sstevel@tonic-gate 		(void) strncpy(glddev->gld_name, devname,
5867c478bd9Sstevel@tonic-gate 		    sizeof (glddev->gld_name) - 1);
5877c478bd9Sstevel@tonic-gate 		glddev->gld_major = major;
5887c478bd9Sstevel@tonic-gate 		glddev->gld_nextminor = GLD_MIN_CLONE_MINOR;
5897c478bd9Sstevel@tonic-gate 		glddev->gld_mac_next = glddev->gld_mac_prev =
5907c478bd9Sstevel@tonic-gate 			(gld_mac_info_t *)&glddev->gld_mac_next;
5917c478bd9Sstevel@tonic-gate 		glddev->gld_str_next = glddev->gld_str_prev =
5927c478bd9Sstevel@tonic-gate 			(gld_t *)&glddev->gld_str_next;
5937c478bd9Sstevel@tonic-gate 		mutex_init(&glddev->gld_devlock, NULL, MUTEX_DRIVER, NULL);
5947c478bd9Sstevel@tonic-gate 
5957c478bd9Sstevel@tonic-gate 		/* allow increase of number of supported multicast addrs */
5967c478bd9Sstevel@tonic-gate 		glddev->gld_multisize = ddi_getprop(DDI_DEV_T_NONE,
5977c478bd9Sstevel@tonic-gate 		    devinfo, 0, "multisize", GLD_MAX_MULTICAST);
5987c478bd9Sstevel@tonic-gate 
5997c478bd9Sstevel@tonic-gate 		/*
6007c478bd9Sstevel@tonic-gate 		 * Optionally restrict DLPI provider style
6017c478bd9Sstevel@tonic-gate 		 *
6027c478bd9Sstevel@tonic-gate 		 * -1 - don't create style 1 nodes
6037c478bd9Sstevel@tonic-gate 		 * -2 - don't create style 2 nodes
6047c478bd9Sstevel@tonic-gate 		 */
6057c478bd9Sstevel@tonic-gate 		glddev->gld_styles = ddi_getprop(DDI_DEV_T_NONE, devinfo, 0,
6067c478bd9Sstevel@tonic-gate 		    "gld-provider-styles", 0);
6077c478bd9Sstevel@tonic-gate 
6087c478bd9Sstevel@tonic-gate 		/* Stuff that's needed before any PPA gets attached */
6097c478bd9Sstevel@tonic-gate 		glddev->gld_type = macinfo->gldm_type;
6107c478bd9Sstevel@tonic-gate 		glddev->gld_minsdu = macinfo->gldm_minpkt;
6117c478bd9Sstevel@tonic-gate 		glddev->gld_saplen = macinfo->gldm_saplen;
6127c478bd9Sstevel@tonic-gate 		glddev->gld_addrlen = macinfo->gldm_addrlen;
6137c478bd9Sstevel@tonic-gate 		glddev->gld_broadcast = kmem_zalloc(macinfo->gldm_addrlen,
6147c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
6157c478bd9Sstevel@tonic-gate 		bcopy(macinfo->gldm_broadcast_addr,
6167c478bd9Sstevel@tonic-gate 		    glddev->gld_broadcast, macinfo->gldm_addrlen);
6177c478bd9Sstevel@tonic-gate 		glddev->gld_maxsdu = macinfo->gldm_maxpkt;
6187c478bd9Sstevel@tonic-gate 		gldinsque(glddev, gld_device_list.gld_prev);
6197c478bd9Sstevel@tonic-gate 	}
6207c478bd9Sstevel@tonic-gate 	glddev->gld_ndevice++;
6217c478bd9Sstevel@tonic-gate 	/* Now glddev can't go away until we unregister this mac (or fail) */
6227c478bd9Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
6237c478bd9Sstevel@tonic-gate 
6247c478bd9Sstevel@tonic-gate 	/*
6257c478bd9Sstevel@tonic-gate 	 *  Per-instance initialization
6267c478bd9Sstevel@tonic-gate 	 */
6277c478bd9Sstevel@tonic-gate 
6287c478bd9Sstevel@tonic-gate 	/*
6297c478bd9Sstevel@tonic-gate 	 * Initialize per-mac structure that is private to GLD.
6307c478bd9Sstevel@tonic-gate 	 * Set up interface pointer. These are device class specific pointers
6317c478bd9Sstevel@tonic-gate 	 * used to handle FDDI/TR/ETHER/IPoIB specific packets.
6327c478bd9Sstevel@tonic-gate 	 */
6337c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (interfaces)/sizeof (*interfaces); i++) {
6347c478bd9Sstevel@tonic-gate 		if (mediatype != interfaces[i].mac_type)
6357c478bd9Sstevel@tonic-gate 			continue;
6367c478bd9Sstevel@tonic-gate 
6377c478bd9Sstevel@tonic-gate 		macinfo->gldm_mac_pvt = kmem_zalloc(sizeof (gld_mac_pvt_t),
6387c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
6397c478bd9Sstevel@tonic-gate 		((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep = ifp =
6407c478bd9Sstevel@tonic-gate 		    &interfaces[i];
6417c478bd9Sstevel@tonic-gate 		break;
6427c478bd9Sstevel@tonic-gate 	}
6437c478bd9Sstevel@tonic-gate 
6447c478bd9Sstevel@tonic-gate 	if (ifp == NULL) {
6457c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "GLD: this version does not support %s driver "
6467c478bd9Sstevel@tonic-gate 		    "of type %d", devname, mediatype);
6477c478bd9Sstevel@tonic-gate 		goto failure;
6487c478bd9Sstevel@tonic-gate 	}
6497c478bd9Sstevel@tonic-gate 
6507c478bd9Sstevel@tonic-gate 	/*
6517c478bd9Sstevel@tonic-gate 	 * Driver can only register MTU within legal media range.
6527c478bd9Sstevel@tonic-gate 	 */
6537c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_maxpkt > ifp->mtu_size) {
6547c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "GLD: oversize MTU is specified by driver %s",
6557c478bd9Sstevel@tonic-gate 		    devname);
6567c478bd9Sstevel@tonic-gate 		goto failure;
6577c478bd9Sstevel@tonic-gate 	}
6587c478bd9Sstevel@tonic-gate 
6597c478bd9Sstevel@tonic-gate 	/*
6607c478bd9Sstevel@tonic-gate 	 * For now, only Infiniband drivers can use MDT. Do not add
6617c478bd9Sstevel@tonic-gate 	 * support for Ethernet, FDDI or TR.
6627c478bd9Sstevel@tonic-gate 	 */
6637c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_mdt_pre != NULL) {
6647c478bd9Sstevel@tonic-gate 		if (mediatype != DL_IB) {
6657c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "GLD: MDT not supported for %s "
6667c478bd9Sstevel@tonic-gate 			    "driver of type %d", devname, mediatype);
6677c478bd9Sstevel@tonic-gate 			goto failure;
6687c478bd9Sstevel@tonic-gate 		}
6697c478bd9Sstevel@tonic-gate 
6707c478bd9Sstevel@tonic-gate 		/*
6717c478bd9Sstevel@tonic-gate 		 * Validate entry points.
6727c478bd9Sstevel@tonic-gate 		 */
6737c478bd9Sstevel@tonic-gate 		if ((macinfo->gldm_mdt_send == NULL) ||
6747c478bd9Sstevel@tonic-gate 		    (macinfo->gldm_mdt_post == NULL)) {
6757c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "GLD: invalid MDT entry points for "
6767c478bd9Sstevel@tonic-gate 			    "%s driver of type %d", devname, mediatype);
6777c478bd9Sstevel@tonic-gate 			goto failure;
6787c478bd9Sstevel@tonic-gate 		}
6797c478bd9Sstevel@tonic-gate 		macinfo->gldm_options |= GLDOPT_MDT;
6807c478bd9Sstevel@tonic-gate 	}
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
6837c478bd9Sstevel@tonic-gate 	mac_pvt->major_dev = glddev;
6847c478bd9Sstevel@tonic-gate 
6857c478bd9Sstevel@tonic-gate 	mac_pvt->curr_macaddr = kmem_zalloc(macinfo->gldm_addrlen, KM_SLEEP);
6867c478bd9Sstevel@tonic-gate 	/*
6877c478bd9Sstevel@tonic-gate 	 * XXX Do bit-reversed devices store gldm_vendor in canonical
6887c478bd9Sstevel@tonic-gate 	 * format or in wire format?  Also gldm_broadcast.  For now
6897c478bd9Sstevel@tonic-gate 	 * we are assuming canonical, but I'm not sure that makes the
6907c478bd9Sstevel@tonic-gate 	 * most sense for ease of driver implementation.
6917c478bd9Sstevel@tonic-gate 	 */
6927c478bd9Sstevel@tonic-gate 	bcopy(macinfo->gldm_vendor_addr, mac_pvt->curr_macaddr,
6937c478bd9Sstevel@tonic-gate 	    macinfo->gldm_addrlen);
6947c478bd9Sstevel@tonic-gate 	mac_pvt->statistics = kmem_zalloc(sizeof (struct gld_stats), KM_SLEEP);
6957c478bd9Sstevel@tonic-gate 
6967c478bd9Sstevel@tonic-gate 	/*
6977c478bd9Sstevel@tonic-gate 	 * The available set of notifications is those generatable by GLD
6987c478bd9Sstevel@tonic-gate 	 * itself, plus those corresponding to the capabilities of the MAC
6997c478bd9Sstevel@tonic-gate 	 * driver, intersected with those supported by gld_notify_ind() above.
7007c478bd9Sstevel@tonic-gate 	 */
7017c478bd9Sstevel@tonic-gate 	mac_pvt->notifications = gld_internal_notes;
7027c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_LINKSTATE)
7037c478bd9Sstevel@tonic-gate 		mac_pvt->notifications |= gld_linkstate_notes;
7047c478bd9Sstevel@tonic-gate 	mac_pvt->notifications &= gld_supported_notes;
7057c478bd9Sstevel@tonic-gate 
7067c478bd9Sstevel@tonic-gate 	GLDM_LOCK_INIT(macinfo);
7077c478bd9Sstevel@tonic-gate 
7087c478bd9Sstevel@tonic-gate 	ddi_set_driver_private(devinfo, macinfo);
7097c478bd9Sstevel@tonic-gate 
7107c478bd9Sstevel@tonic-gate 	/*
7117c478bd9Sstevel@tonic-gate 	 * Now atomically get a PPA and put ourselves on the mac list.
7127c478bd9Sstevel@tonic-gate 	 */
7137c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
7147c478bd9Sstevel@tonic-gate 
7157c478bd9Sstevel@tonic-gate #ifdef DEBUG
7167c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_ppa != ddi_get_instance(devinfo))
7177c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d instance != ppa %d",
7187c478bd9Sstevel@tonic-gate 		    ddi_driver_name(devinfo), ddi_get_instance(devinfo),
7197c478bd9Sstevel@tonic-gate 		    macinfo->gldm_ppa);
7207c478bd9Sstevel@tonic-gate #endif
7217c478bd9Sstevel@tonic-gate 
7227c478bd9Sstevel@tonic-gate 	/*
7237c478bd9Sstevel@tonic-gate 	 * Create style 2 node (gated by gld-provider-styles property).
7247c478bd9Sstevel@tonic-gate 	 *
7257c478bd9Sstevel@tonic-gate 	 * NOTE: When the CLONE_DEV flag is specified to
7267c478bd9Sstevel@tonic-gate 	 *	 ddi_create_minor_node() the minor number argument is
7277c478bd9Sstevel@tonic-gate 	 *	 immaterial. Opens of that node will go via the clone
7287c478bd9Sstevel@tonic-gate 	 *	 driver and gld_open() will always be passed a dev_t with
7297c478bd9Sstevel@tonic-gate 	 *	 minor of zero.
7307c478bd9Sstevel@tonic-gate 	 */
7317c478bd9Sstevel@tonic-gate 	if (glddev->gld_styles != -2) {
7327c478bd9Sstevel@tonic-gate 		if (ddi_create_minor_node(devinfo, glddev->gld_name, S_IFCHR,
7337c478bd9Sstevel@tonic-gate 		    0, DDI_NT_NET, CLONE_DEV) == DDI_FAILURE) {
7347c478bd9Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
7357c478bd9Sstevel@tonic-gate 			goto late_failure;
7367c478bd9Sstevel@tonic-gate 		}
7377c478bd9Sstevel@tonic-gate 	}
7387c478bd9Sstevel@tonic-gate 
7397c478bd9Sstevel@tonic-gate 	/*
7407c478bd9Sstevel@tonic-gate 	 * Create style 1 node (gated by gld-provider-styles property)
7417c478bd9Sstevel@tonic-gate 	 */
7427c478bd9Sstevel@tonic-gate 	if (glddev->gld_styles != -1) {
7437c478bd9Sstevel@tonic-gate 		(void) sprintf(minordev, "%s%d", glddev->gld_name,
7447c478bd9Sstevel@tonic-gate 		    macinfo->gldm_ppa);
7457c478bd9Sstevel@tonic-gate 		if (ddi_create_minor_node(devinfo, minordev, S_IFCHR,
7467c478bd9Sstevel@tonic-gate 		    GLD_STYLE1_PPA_TO_MINOR(macinfo->gldm_ppa), DDI_NT_NET,
7477c478bd9Sstevel@tonic-gate 		    0) != DDI_SUCCESS) {
7487c478bd9Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
7497c478bd9Sstevel@tonic-gate 			goto late_failure;
7507c478bd9Sstevel@tonic-gate 		}
7517c478bd9Sstevel@tonic-gate 	}
7527c478bd9Sstevel@tonic-gate 
7537c478bd9Sstevel@tonic-gate 	/* add ourselves to this major device's linked list of instances */
7547c478bd9Sstevel@tonic-gate 	gldinsque(macinfo, glddev->gld_mac_prev);
7557c478bd9Sstevel@tonic-gate 
7567c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
7577c478bd9Sstevel@tonic-gate 
7587c478bd9Sstevel@tonic-gate 	/*
7597c478bd9Sstevel@tonic-gate 	 * Unfortunately we need the ppa before we call gld_initstats();
7607c478bd9Sstevel@tonic-gate 	 * otherwise we would like to do this just above the mutex_enter
7617c478bd9Sstevel@tonic-gate 	 * above.  In which case we could have set MAC_READY inside the
7627c478bd9Sstevel@tonic-gate 	 * mutex and we wouldn't have needed to check it in open and
7637c478bd9Sstevel@tonic-gate 	 * DL_ATTACH.  We wouldn't like to do the initstats/kstat_create
7647c478bd9Sstevel@tonic-gate 	 * inside the mutex because it might get taken in our kstat_update
7657c478bd9Sstevel@tonic-gate 	 * routine and cause a deadlock with kstat_chain_lock.
7667c478bd9Sstevel@tonic-gate 	 */
7677c478bd9Sstevel@tonic-gate 
7687c478bd9Sstevel@tonic-gate 	/* gld_initstats() calls (*ifp->init)() */
7697c478bd9Sstevel@tonic-gate 	if (gld_initstats(macinfo) != GLD_SUCCESS) {
7707c478bd9Sstevel@tonic-gate 		mutex_enter(&glddev->gld_devlock);
7717c478bd9Sstevel@tonic-gate 		gldremque(macinfo);
7727c478bd9Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
7737c478bd9Sstevel@tonic-gate 		goto late_failure;
7747c478bd9Sstevel@tonic-gate 	}
7757c478bd9Sstevel@tonic-gate 
7767c478bd9Sstevel@tonic-gate 	/*
7777c478bd9Sstevel@tonic-gate 	 * Need to indicate we are NOW ready to process interrupts;
7787c478bd9Sstevel@tonic-gate 	 * any interrupt before this is set is for someone else.
7797c478bd9Sstevel@tonic-gate 	 * This flag is also now used to tell open, et. al. that this
7807c478bd9Sstevel@tonic-gate 	 * mac is now fully ready and available for use.
7817c478bd9Sstevel@tonic-gate 	 */
7827c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
7837c478bd9Sstevel@tonic-gate 	macinfo->gldm_GLD_flags |= GLD_MAC_READY;
7847c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
7857c478bd9Sstevel@tonic-gate 
7867c478bd9Sstevel@tonic-gate 	/* log local ethernet address -- XXX not DDI compliant */
7877c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_addrlen == sizeof (struct ether_addr))
7887c478bd9Sstevel@tonic-gate 		(void) localetheraddr(
7897c478bd9Sstevel@tonic-gate 		    (struct ether_addr *)macinfo->gldm_vendor_addr, NULL);
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 	/* now put announcement into the message buffer */
7927c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "!%s%d: %s: type \"%s\" mac address %s\n",
7937c478bd9Sstevel@tonic-gate 	    glddev->gld_name,
7947c478bd9Sstevel@tonic-gate 	    macinfo->gldm_ppa, macinfo->gldm_ident,
7957c478bd9Sstevel@tonic-gate 	    mac_pvt->interfacep->mac_string,
7967c478bd9Sstevel@tonic-gate 	    gld_macaddr_sprintf(pbuf, macinfo->gldm_vendor_addr,
7977c478bd9Sstevel@tonic-gate 	    macinfo->gldm_addrlen));
7987c478bd9Sstevel@tonic-gate 
7997c478bd9Sstevel@tonic-gate 	ddi_report_dev(devinfo);
8007c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
8017c478bd9Sstevel@tonic-gate 
8027c478bd9Sstevel@tonic-gate late_failure:
8037c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(devinfo, NULL);
8047c478bd9Sstevel@tonic-gate 	GLDM_LOCK_DESTROY(macinfo);
8057c478bd9Sstevel@tonic-gate 	if (mac_pvt->curr_macaddr != NULL)
8067c478bd9Sstevel@tonic-gate 	    kmem_free(mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
8077c478bd9Sstevel@tonic-gate 	if (mac_pvt->statistics != NULL)
8087c478bd9Sstevel@tonic-gate 	    kmem_free(mac_pvt->statistics, sizeof (struct gld_stats));
8097c478bd9Sstevel@tonic-gate 	kmem_free(macinfo->gldm_mac_pvt, sizeof (gld_mac_pvt_t));
8107c478bd9Sstevel@tonic-gate 	macinfo->gldm_mac_pvt = NULL;
8117c478bd9Sstevel@tonic-gate 
8127c478bd9Sstevel@tonic-gate failure:
8137c478bd9Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
8147c478bd9Sstevel@tonic-gate 	glddev->gld_ndevice--;
8157c478bd9Sstevel@tonic-gate 	/*
8167c478bd9Sstevel@tonic-gate 	 * Note that just because this goes to zero here does not necessarily
8177c478bd9Sstevel@tonic-gate 	 * mean that we were the one who added the glddev above.  It's
8187c478bd9Sstevel@tonic-gate 	 * possible that the first mac unattached while were were in here
8197c478bd9Sstevel@tonic-gate 	 * failing to attach the second mac.  But we're now the last.
8207c478bd9Sstevel@tonic-gate 	 */
8217c478bd9Sstevel@tonic-gate 	if (glddev->gld_ndevice == 0) {
8227c478bd9Sstevel@tonic-gate 		/* There should be no macinfos left */
8237c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_mac_next ==
8247c478bd9Sstevel@tonic-gate 		    (gld_mac_info_t *)&glddev->gld_mac_next);
8257c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_mac_prev ==
8267c478bd9Sstevel@tonic-gate 		    (gld_mac_info_t *)&glddev->gld_mac_next);
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 		/*
8297c478bd9Sstevel@tonic-gate 		 * There should be no DL_UNATTACHED streams: the system
8307c478bd9Sstevel@tonic-gate 		 * should not have detached the "first" devinfo which has
8317c478bd9Sstevel@tonic-gate 		 * all the open style 2 streams.
8327c478bd9Sstevel@tonic-gate 		 *
8337c478bd9Sstevel@tonic-gate 		 * XXX This is not clear.  See gld_getinfo and Bug 1165519
8347c478bd9Sstevel@tonic-gate 		 */
8357c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_str_next == (gld_t *)&glddev->gld_str_next);
8367c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_str_prev == (gld_t *)&glddev->gld_str_next);
8377c478bd9Sstevel@tonic-gate 
8387c478bd9Sstevel@tonic-gate 		gldremque(glddev);
8397c478bd9Sstevel@tonic-gate 		mutex_destroy(&glddev->gld_devlock);
8407c478bd9Sstevel@tonic-gate 		if (glddev->gld_broadcast != NULL)
8417c478bd9Sstevel@tonic-gate 			kmem_free(glddev->gld_broadcast, glddev->gld_addrlen);
8427c478bd9Sstevel@tonic-gate 		kmem_free(glddev, sizeof (glddev_t));
8437c478bd9Sstevel@tonic-gate 	}
8447c478bd9Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
8457c478bd9Sstevel@tonic-gate 
8467c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
8477c478bd9Sstevel@tonic-gate }
8487c478bd9Sstevel@tonic-gate 
8497c478bd9Sstevel@tonic-gate /*
8507c478bd9Sstevel@tonic-gate  * gld_unregister (macinfo)
8517c478bd9Sstevel@tonic-gate  * remove the macinfo structure from local structures
8527c478bd9Sstevel@tonic-gate  * this is cleanup for a driver to be unloaded
8537c478bd9Sstevel@tonic-gate  */
8547c478bd9Sstevel@tonic-gate int
8557c478bd9Sstevel@tonic-gate gld_unregister(gld_mac_info_t *macinfo)
8567c478bd9Sstevel@tonic-gate {
8577c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
8587c478bd9Sstevel@tonic-gate 	glddev_t *glddev = mac_pvt->major_dev;
8597c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
8607c478bd9Sstevel@tonic-gate 	int multisize = sizeof (gld_mcast_t) * glddev->gld_multisize;
8617c478bd9Sstevel@tonic-gate 
8627c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
8637c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
8647c478bd9Sstevel@tonic-gate 
8657c478bd9Sstevel@tonic-gate 	if (mac_pvt->nvlan > 0) {
8667c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
8677c478bd9Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
8687c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
8697c478bd9Sstevel@tonic-gate 	}
8707c478bd9Sstevel@tonic-gate 
8717c478bd9Sstevel@tonic-gate #ifdef	GLD_DEBUG
8727c478bd9Sstevel@tonic-gate 	{
8737c478bd9Sstevel@tonic-gate 		int i;
8747c478bd9Sstevel@tonic-gate 
8757c478bd9Sstevel@tonic-gate 		for (i = 0; i < VLAN_HASHSZ; i++) {
8767c478bd9Sstevel@tonic-gate 			if ((mac_pvt->vlan_hash[i] != NULL))
8777c478bd9Sstevel@tonic-gate 				cmn_err(CE_PANIC,
8787c478bd9Sstevel@tonic-gate 				    "%s, line %d: "
8797c478bd9Sstevel@tonic-gate 				    "mac_pvt->vlan_hash[%d] != NULL",
8807c478bd9Sstevel@tonic-gate 				    __FILE__, __LINE__, i);
8817c478bd9Sstevel@tonic-gate 		}
8827c478bd9Sstevel@tonic-gate 	}
8837c478bd9Sstevel@tonic-gate #endif
8847c478bd9Sstevel@tonic-gate 
8857c478bd9Sstevel@tonic-gate 	/* Delete this mac */
8867c478bd9Sstevel@tonic-gate 	gldremque(macinfo);
8877c478bd9Sstevel@tonic-gate 
8887c478bd9Sstevel@tonic-gate 	/* Disallow further entries to gld_recv() and gld_sched() */
8897c478bd9Sstevel@tonic-gate 	macinfo->gldm_GLD_flags |= GLD_UNREGISTERED;
8907c478bd9Sstevel@tonic-gate 
8917c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
8927c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
8937c478bd9Sstevel@tonic-gate 
8947c478bd9Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
8957c478bd9Sstevel@tonic-gate 	(*ifp->uninit)(macinfo);
8967c478bd9Sstevel@tonic-gate 
8977c478bd9Sstevel@tonic-gate 	ASSERT(mac_pvt->kstatp);
8987c478bd9Sstevel@tonic-gate 	kstat_delete(mac_pvt->kstatp);
8997c478bd9Sstevel@tonic-gate 
9007c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_INITED(macinfo));
9017c478bd9Sstevel@tonic-gate 	kmem_free(mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
9027c478bd9Sstevel@tonic-gate 	kmem_free(mac_pvt->statistics, sizeof (struct gld_stats));
9037c478bd9Sstevel@tonic-gate 
9047c478bd9Sstevel@tonic-gate 	if (mac_pvt->mcast_table != NULL)
9057c478bd9Sstevel@tonic-gate 		kmem_free(mac_pvt->mcast_table, multisize);
9067c478bd9Sstevel@tonic-gate 	kmem_free(macinfo->gldm_mac_pvt, sizeof (gld_mac_pvt_t));
9077c478bd9Sstevel@tonic-gate 	macinfo->gldm_mac_pvt = (caddr_t)NULL;
9087c478bd9Sstevel@tonic-gate 
9097c478bd9Sstevel@tonic-gate 	/* We now have one fewer instance for this major device */
9107c478bd9Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
9117c478bd9Sstevel@tonic-gate 	glddev->gld_ndevice--;
9127c478bd9Sstevel@tonic-gate 	if (glddev->gld_ndevice == 0) {
9137c478bd9Sstevel@tonic-gate 		/* There should be no macinfos left */
9147c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_mac_next ==
9157c478bd9Sstevel@tonic-gate 		    (gld_mac_info_t *)&glddev->gld_mac_next);
9167c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_mac_prev ==
9177c478bd9Sstevel@tonic-gate 		    (gld_mac_info_t *)&glddev->gld_mac_next);
9187c478bd9Sstevel@tonic-gate 
9197c478bd9Sstevel@tonic-gate 		/*
9207c478bd9Sstevel@tonic-gate 		 * There should be no DL_UNATTACHED streams: the system
9217c478bd9Sstevel@tonic-gate 		 * should not have detached the "first" devinfo which has
9227c478bd9Sstevel@tonic-gate 		 * all the open style 2 streams.
9237c478bd9Sstevel@tonic-gate 		 *
9247c478bd9Sstevel@tonic-gate 		 * XXX This is not clear.  See gld_getinfo and Bug 1165519
9257c478bd9Sstevel@tonic-gate 		 */
9267c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_str_next == (gld_t *)&glddev->gld_str_next);
9277c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_str_prev == (gld_t *)&glddev->gld_str_next);
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(macinfo->gldm_devinfo, NULL);
9307c478bd9Sstevel@tonic-gate 		gldremque(glddev);
9317c478bd9Sstevel@tonic-gate 		mutex_destroy(&glddev->gld_devlock);
9327c478bd9Sstevel@tonic-gate 		if (glddev->gld_broadcast != NULL)
9337c478bd9Sstevel@tonic-gate 			kmem_free(glddev->gld_broadcast, glddev->gld_addrlen);
9347c478bd9Sstevel@tonic-gate 		kmem_free(glddev, sizeof (glddev_t));
9357c478bd9Sstevel@tonic-gate 	}
9367c478bd9Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
9377c478bd9Sstevel@tonic-gate 
9387c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
9397c478bd9Sstevel@tonic-gate }
9407c478bd9Sstevel@tonic-gate 
9417c478bd9Sstevel@tonic-gate /*
9427c478bd9Sstevel@tonic-gate  * gld_initstats
9437c478bd9Sstevel@tonic-gate  * called from gld_register
9447c478bd9Sstevel@tonic-gate  */
9457c478bd9Sstevel@tonic-gate static int
9467c478bd9Sstevel@tonic-gate gld_initstats(gld_mac_info_t *macinfo)
9477c478bd9Sstevel@tonic-gate {
9487c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
9497c478bd9Sstevel@tonic-gate 	struct gldkstats *sp;
9507c478bd9Sstevel@tonic-gate 	glddev_t *glddev;
9517c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
9527c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
9537c478bd9Sstevel@tonic-gate 
9547c478bd9Sstevel@tonic-gate 	glddev = mac_pvt->major_dev;
9557c478bd9Sstevel@tonic-gate 
9567c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_create(glddev->gld_name, macinfo->gldm_ppa,
9577c478bd9Sstevel@tonic-gate 	    NULL, "net", KSTAT_TYPE_NAMED,
9587c478bd9Sstevel@tonic-gate 	    sizeof (struct gldkstats) / sizeof (kstat_named_t), 0)) == NULL) {
9597c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
9607c478bd9Sstevel@tonic-gate 		    "GLD: failed to create kstat structure for %s%d",
9617c478bd9Sstevel@tonic-gate 		    glddev->gld_name, macinfo->gldm_ppa);
9627c478bd9Sstevel@tonic-gate 		return (GLD_FAILURE);
9637c478bd9Sstevel@tonic-gate 	}
9647c478bd9Sstevel@tonic-gate 	mac_pvt->kstatp = ksp;
9657c478bd9Sstevel@tonic-gate 
9667c478bd9Sstevel@tonic-gate 	ksp->ks_update = gld_update_kstat;
9677c478bd9Sstevel@tonic-gate 	ksp->ks_private = (void *)macinfo;
9687c478bd9Sstevel@tonic-gate 
9697c478bd9Sstevel@tonic-gate 	sp = ksp->ks_data;
9707c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktrcv, "ipackets", KSTAT_DATA_UINT32);
9717c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktxmt, "opackets", KSTAT_DATA_UINT32);
9727c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_errrcv, "ierrors", KSTAT_DATA_ULONG);
9737c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_errxmt, "oerrors", KSTAT_DATA_ULONG);
9747c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytexmt, "obytes", KSTAT_DATA_UINT32);
9757c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytercv, "rbytes", KSTAT_DATA_UINT32);
9767c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_multixmt, "multixmt", KSTAT_DATA_ULONG);
9777c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_multircv, "multircv", KSTAT_DATA_ULONG);
9787c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_brdcstxmt, "brdcstxmt", KSTAT_DATA_ULONG);
9797c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_brdcstrcv, "brdcstrcv", KSTAT_DATA_ULONG);
9807c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_blocked, "blocked", KSTAT_DATA_ULONG);
9817c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_noxmtbuf, "noxmtbuf", KSTAT_DATA_ULONG);
9827c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_norcvbuf, "norcvbuf", KSTAT_DATA_ULONG);
9837c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtretry, "xmtretry", KSTAT_DATA_ULONG);
9847c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_intr, "intr", KSTAT_DATA_ULONG);
9857c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktrcv64, "ipackets64", KSTAT_DATA_UINT64);
9867c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktxmt64, "opackets64", KSTAT_DATA_UINT64);
9877c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytexmt64, "obytes64", KSTAT_DATA_UINT64);
9887c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytercv64, "rbytes64", KSTAT_DATA_UINT64);
9897c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_unknowns, "unknowns", KSTAT_DATA_ULONG);
9907c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_speed, "ifspeed", KSTAT_DATA_UINT64);
9917c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_media, "media", KSTAT_DATA_CHAR);
9927c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_prom, "promisc", KSTAT_DATA_CHAR);
9937c478bd9Sstevel@tonic-gate 
9947c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_overflow, "oflo", KSTAT_DATA_ULONG);
9957c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_underflow, "uflo", KSTAT_DATA_ULONG);
9967c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_missed, "missed", KSTAT_DATA_ULONG);
9977c478bd9Sstevel@tonic-gate 
9987c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtbadinterp, "xmt_badinterp",
9997c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
10007c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_rcvbadinterp, "rcv_badinterp",
10017c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
10027c478bd9Sstevel@tonic-gate 
10037c478bd9Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
10047c478bd9Sstevel@tonic-gate 
10057c478bd9Sstevel@tonic-gate 	(*ifp->init)(macinfo);
10067c478bd9Sstevel@tonic-gate 
10077c478bd9Sstevel@tonic-gate 	kstat_install(ksp);
10087c478bd9Sstevel@tonic-gate 
10097c478bd9Sstevel@tonic-gate 	return (GLD_SUCCESS);
10107c478bd9Sstevel@tonic-gate }
10117c478bd9Sstevel@tonic-gate 
10127c478bd9Sstevel@tonic-gate /* called from kstat mechanism, and from wsrv's get_statistics_req */
10137c478bd9Sstevel@tonic-gate static int
10147c478bd9Sstevel@tonic-gate gld_update_kstat(kstat_t *ksp, int rw)
10157c478bd9Sstevel@tonic-gate {
10167c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*macinfo;
10177c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt;
10187c478bd9Sstevel@tonic-gate 	struct gldkstats *gsp;
10197c478bd9Sstevel@tonic-gate 	struct gld_stats *stats;
10207c478bd9Sstevel@tonic-gate 
10217c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
10227c478bd9Sstevel@tonic-gate 		return (EACCES);
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 	macinfo = (gld_mac_info_t *)ksp->ks_private;
10257c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
10267c478bd9Sstevel@tonic-gate 
10277c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
10287c478bd9Sstevel@tonic-gate 
10297c478bd9Sstevel@tonic-gate 	if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY)) {
10307c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
10317c478bd9Sstevel@tonic-gate 		return (EIO);	/* this one's not ready yet */
10327c478bd9Sstevel@tonic-gate 	}
10337c478bd9Sstevel@tonic-gate 
10347c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
10357c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
10367c478bd9Sstevel@tonic-gate 		return (EIO);	/* this one's not ready any more */
10377c478bd9Sstevel@tonic-gate 	}
10387c478bd9Sstevel@tonic-gate 
10397c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
10407c478bd9Sstevel@tonic-gate 	gsp = mac_pvt->kstatp->ks_data;
10417c478bd9Sstevel@tonic-gate 	ASSERT(gsp);
10427c478bd9Sstevel@tonic-gate 	stats = mac_pvt->statistics;
10437c478bd9Sstevel@tonic-gate 
10447c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_get_stats)
10457c478bd9Sstevel@tonic-gate 		(void) (*macinfo->gldm_get_stats)(macinfo, stats);
10467c478bd9Sstevel@tonic-gate 
10477c478bd9Sstevel@tonic-gate 	gsp->glds_pktxmt.value.ui32 = stats->glds_pktxmt64 & 0xffffffff;
10487c478bd9Sstevel@tonic-gate 	gsp->glds_bytexmt.value.ui32 = stats->glds_bytexmt64 & 0xffffffff;
10497c478bd9Sstevel@tonic-gate 	gsp->glds_multixmt.value.ul = stats->glds_multixmt;
10507c478bd9Sstevel@tonic-gate 	gsp->glds_brdcstxmt.value.ul = stats->glds_brdcstxmt;
10517c478bd9Sstevel@tonic-gate 	gsp->glds_noxmtbuf.value.ul = stats->glds_noxmtbuf;	/* 0 for now */
10527c478bd9Sstevel@tonic-gate 	gsp->glds_xmtretry.value.ul = stats->glds_xmtretry;
10537c478bd9Sstevel@tonic-gate 
10547c478bd9Sstevel@tonic-gate 	gsp->glds_pktxmt64.value.ui64 = stats->glds_pktxmt64;
10557c478bd9Sstevel@tonic-gate 	gsp->glds_bytexmt64.value.ui64 = stats->glds_bytexmt64;
10567c478bd9Sstevel@tonic-gate 	gsp->glds_xmtbadinterp.value.ui32 = stats->glds_xmtbadinterp;
10577c478bd9Sstevel@tonic-gate 
10587c478bd9Sstevel@tonic-gate 	gsp->glds_pktrcv.value.ui32 = stats->glds_pktrcv64 & 0xffffffff;
10597c478bd9Sstevel@tonic-gate 	gsp->glds_errxmt.value.ul = stats->glds_errxmt;
10607c478bd9Sstevel@tonic-gate 	gsp->glds_errrcv.value.ul = stats->glds_errrcv;
10617c478bd9Sstevel@tonic-gate 	gsp->glds_bytercv.value.ui32 = stats->glds_bytercv64 & 0xffffffff;
10627c478bd9Sstevel@tonic-gate 	gsp->glds_multircv.value.ul = stats->glds_multircv;
10637c478bd9Sstevel@tonic-gate 	gsp->glds_brdcstrcv.value.ul = stats->glds_brdcstrcv;
10647c478bd9Sstevel@tonic-gate 	gsp->glds_blocked.value.ul = stats->glds_blocked;
10657c478bd9Sstevel@tonic-gate 	gsp->glds_overflow.value.ul = stats->glds_overflow;
10667c478bd9Sstevel@tonic-gate 	gsp->glds_underflow.value.ul = stats->glds_underflow;
10677c478bd9Sstevel@tonic-gate 	gsp->glds_missed.value.ul = stats->glds_missed;
10687c478bd9Sstevel@tonic-gate 	gsp->glds_norcvbuf.value.ul = stats->glds_norcvbuf +
10697c478bd9Sstevel@tonic-gate 	    stats->glds_gldnorcvbuf;
10707c478bd9Sstevel@tonic-gate 	gsp->glds_intr.value.ul = stats->glds_intr;
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 	gsp->glds_speed.value.ui64 = stats->glds_speed;
10737c478bd9Sstevel@tonic-gate 	gsp->glds_unknowns.value.ul = stats->glds_unknowns;
10747c478bd9Sstevel@tonic-gate 	gsp->glds_pktrcv64.value.ui64 = stats->glds_pktrcv64;
10757c478bd9Sstevel@tonic-gate 	gsp->glds_bytercv64.value.ui64 = stats->glds_bytercv64;
10767c478bd9Sstevel@tonic-gate 	gsp->glds_rcvbadinterp.value.ui32 = stats->glds_rcvbadinterp;
10777c478bd9Sstevel@tonic-gate 
10787c478bd9Sstevel@tonic-gate 	if (mac_pvt->nprom)
10797c478bd9Sstevel@tonic-gate 		(void) strcpy(gsp->glds_prom.value.c, "phys");
10807c478bd9Sstevel@tonic-gate 	else if (mac_pvt->nprom_multi)
10817c478bd9Sstevel@tonic-gate 		(void) strcpy(gsp->glds_prom.value.c, "multi");
10827c478bd9Sstevel@tonic-gate 	else
10837c478bd9Sstevel@tonic-gate 		(void) strcpy(gsp->glds_prom.value.c, "off");
10847c478bd9Sstevel@tonic-gate 
10857c478bd9Sstevel@tonic-gate 	(void) strcpy(gsp->glds_media.value.c, gld_media[
10867c478bd9Sstevel@tonic-gate 	    stats->glds_media < sizeof (gld_media) / sizeof (gld_media[0])
10877c478bd9Sstevel@tonic-gate 	    ? stats->glds_media : 0]);
10887c478bd9Sstevel@tonic-gate 
10897c478bd9Sstevel@tonic-gate 	switch (macinfo->gldm_type) {
10907c478bd9Sstevel@tonic-gate 	case DL_ETHER:
10917c478bd9Sstevel@tonic-gate 		gsp->glds_frame.value.ul = stats->glds_frame;
10927c478bd9Sstevel@tonic-gate 		gsp->glds_crc.value.ul = stats->glds_crc;
10937c478bd9Sstevel@tonic-gate 		gsp->glds_collisions.value.ul = stats->glds_collisions;
10947c478bd9Sstevel@tonic-gate 		gsp->glds_excoll.value.ul = stats->glds_excoll;
10957c478bd9Sstevel@tonic-gate 		gsp->glds_defer.value.ul = stats->glds_defer;
10967c478bd9Sstevel@tonic-gate 		gsp->glds_short.value.ul = stats->glds_short;
10977c478bd9Sstevel@tonic-gate 		gsp->glds_xmtlatecoll.value.ul = stats->glds_xmtlatecoll;
10987c478bd9Sstevel@tonic-gate 		gsp->glds_nocarrier.value.ul = stats->glds_nocarrier;
10997c478bd9Sstevel@tonic-gate 		gsp->glds_dot3_first_coll.value.ui32 =
11007c478bd9Sstevel@tonic-gate 		    stats->glds_dot3_first_coll;
11017c478bd9Sstevel@tonic-gate 		gsp->glds_dot3_multi_coll.value.ui32 =
11027c478bd9Sstevel@tonic-gate 		    stats->glds_dot3_multi_coll;
11037c478bd9Sstevel@tonic-gate 		gsp->glds_dot3_sqe_error.value.ui32 =
11047c478bd9Sstevel@tonic-gate 		    stats->glds_dot3_sqe_error;
11057c478bd9Sstevel@tonic-gate 		gsp->glds_dot3_mac_xmt_error.value.ui32 =
11067c478bd9Sstevel@tonic-gate 		    stats->glds_dot3_mac_xmt_error;
11077c478bd9Sstevel@tonic-gate 		gsp->glds_dot3_mac_rcv_error.value.ui32 =
11087c478bd9Sstevel@tonic-gate 		    stats->glds_dot3_mac_rcv_error;
11097c478bd9Sstevel@tonic-gate 		gsp->glds_dot3_frame_too_long.value.ui32 =
11107c478bd9Sstevel@tonic-gate 		    stats->glds_dot3_frame_too_long;
11117c478bd9Sstevel@tonic-gate 		(void) strcpy(gsp->glds_duplex.value.c, gld_duplex[
11127c478bd9Sstevel@tonic-gate 		    stats->glds_duplex <
11137c478bd9Sstevel@tonic-gate 		    sizeof (gld_duplex) / sizeof (gld_duplex[0]) ?
11147c478bd9Sstevel@tonic-gate 		    stats->glds_duplex : 0]);
11157c478bd9Sstevel@tonic-gate 		break;
11167c478bd9Sstevel@tonic-gate 	case DL_TPR:
11177c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_line_error.value.ui32 =
11187c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_line_error;
11197c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_burst_error.value.ui32 =
11207c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_burst_error;
11217c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_signal_loss.value.ui32 =
11227c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_signal_loss;
11237c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_ace_error.value.ui32 =
11247c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_ace_error;
11257c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_internal_error.value.ui32 =
11267c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_internal_error;
11277c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_lost_frame_error.value.ui32 =
11287c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_lost_frame_error;
11297c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_frame_copied_error.value.ui32 =
11307c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_frame_copied_error;
11317c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_token_error.value.ui32 =
11327c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_token_error;
11337c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_freq_error.value.ui32 =
11347c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_freq_error;
11357c478bd9Sstevel@tonic-gate 		break;
11367c478bd9Sstevel@tonic-gate 	case DL_FDDI:
11377c478bd9Sstevel@tonic-gate 		gsp->glds_fddi_mac_error.value.ui32 =
11387c478bd9Sstevel@tonic-gate 		    stats->glds_fddi_mac_error;
11397c478bd9Sstevel@tonic-gate 		gsp->glds_fddi_mac_lost.value.ui32 =
11407c478bd9Sstevel@tonic-gate 		    stats->glds_fddi_mac_lost;
11417c478bd9Sstevel@tonic-gate 		gsp->glds_fddi_mac_token.value.ui32 =
11427c478bd9Sstevel@tonic-gate 		    stats->glds_fddi_mac_token;
11437c478bd9Sstevel@tonic-gate 		gsp->glds_fddi_mac_tvx_expired.value.ui32 =
11447c478bd9Sstevel@tonic-gate 		    stats->glds_fddi_mac_tvx_expired;
11457c478bd9Sstevel@tonic-gate 		gsp->glds_fddi_mac_late.value.ui32 =
11467c478bd9Sstevel@tonic-gate 		    stats->glds_fddi_mac_late;
11477c478bd9Sstevel@tonic-gate 		gsp->glds_fddi_mac_ring_op.value.ui32 =
11487c478bd9Sstevel@tonic-gate 		    stats->glds_fddi_mac_ring_op;
11497c478bd9Sstevel@tonic-gate 		break;
11507c478bd9Sstevel@tonic-gate 	case DL_IB:
11517c478bd9Sstevel@tonic-gate 		break;
11527c478bd9Sstevel@tonic-gate 	default:
11537c478bd9Sstevel@tonic-gate 		break;
11547c478bd9Sstevel@tonic-gate 	}
11557c478bd9Sstevel@tonic-gate 
11567c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
11577c478bd9Sstevel@tonic-gate 
11587c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
11597c478bd9Sstevel@tonic-gate 	gld_check_assertions();
11607c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDRDE)
11617c478bd9Sstevel@tonic-gate 		gld_sr_dump(macinfo);
11627c478bd9Sstevel@tonic-gate #endif
11637c478bd9Sstevel@tonic-gate 
11647c478bd9Sstevel@tonic-gate 	return (0);
11657c478bd9Sstevel@tonic-gate }
11667c478bd9Sstevel@tonic-gate 
11677c478bd9Sstevel@tonic-gate static int
11687c478bd9Sstevel@tonic-gate gld_init_vlan_stats(gld_vlan_t *vlan)
11697c478bd9Sstevel@tonic-gate {
11707c478bd9Sstevel@tonic-gate 	gld_mac_info_t *mac = vlan->gldv_mac;
11717c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)mac->gldm_mac_pvt;
11727c478bd9Sstevel@tonic-gate 	struct gldkstats *sp;
11737c478bd9Sstevel@tonic-gate 	glddev_t *glddev;
11747c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
11757c478bd9Sstevel@tonic-gate 	char *name;
11767c478bd9Sstevel@tonic-gate 	int instance;
11777c478bd9Sstevel@tonic-gate 
11787c478bd9Sstevel@tonic-gate 	glddev = mac_pvt->major_dev;
11797c478bd9Sstevel@tonic-gate 	name = glddev->gld_name;
11807c478bd9Sstevel@tonic-gate 	instance = (vlan->gldv_id * GLD_VLAN_SCALE) + mac->gldm_ppa;
11817c478bd9Sstevel@tonic-gate 
11827c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_create(name, instance,
11837c478bd9Sstevel@tonic-gate 	    NULL, "net", KSTAT_TYPE_NAMED,
11847c478bd9Sstevel@tonic-gate 	    sizeof (struct gldkstats) / sizeof (kstat_named_t), 0)) == NULL) {
11857c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
11867c478bd9Sstevel@tonic-gate 		    "GLD: failed to create kstat structure for %s%d",
11877c478bd9Sstevel@tonic-gate 		    name, instance);
11887c478bd9Sstevel@tonic-gate 		return (GLD_FAILURE);
11897c478bd9Sstevel@tonic-gate 	}
11907c478bd9Sstevel@tonic-gate 
11917c478bd9Sstevel@tonic-gate 	vlan->gldv_kstatp = ksp;
11927c478bd9Sstevel@tonic-gate 
11937c478bd9Sstevel@tonic-gate 	ksp->ks_update = gld_update_vlan_kstat;
11947c478bd9Sstevel@tonic-gate 	ksp->ks_private = (void *)vlan;
11957c478bd9Sstevel@tonic-gate 
11967c478bd9Sstevel@tonic-gate 	sp = ksp->ks_data;
11977c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktrcv, "ipackets", KSTAT_DATA_UINT32);
11987c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktxmt, "opackets", KSTAT_DATA_UINT32);
11997c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_errrcv, "ierrors", KSTAT_DATA_ULONG);
12007c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_errxmt, "oerrors", KSTAT_DATA_ULONG);
12017c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytexmt, "obytes", KSTAT_DATA_UINT32);
12027c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytercv, "rbytes", KSTAT_DATA_UINT32);
12037c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_multixmt, "multixmt", KSTAT_DATA_ULONG);
12047c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_multircv, "multircv", KSTAT_DATA_ULONG);
12057c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_brdcstxmt, "brdcstxmt", KSTAT_DATA_ULONG);
12067c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_brdcstrcv, "brdcstrcv", KSTAT_DATA_ULONG);
12077c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_blocked, "blocked", KSTAT_DATA_ULONG);
12087c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_noxmtbuf, "noxmtbuf", KSTAT_DATA_ULONG);
12097c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_norcvbuf, "norcvbuf", KSTAT_DATA_ULONG);
12107c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtretry, "xmtretry", KSTAT_DATA_ULONG);
12117c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_intr, "intr", KSTAT_DATA_ULONG);
12127c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktrcv64, "ipackets64", KSTAT_DATA_UINT64);
12137c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktxmt64, "opackets64", KSTAT_DATA_UINT64);
12147c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytexmt64, "obytes64", KSTAT_DATA_UINT64);
12157c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytercv64, "rbytes64", KSTAT_DATA_UINT64);
12167c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_unknowns, "unknowns", KSTAT_DATA_ULONG);
12177c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_speed, "ifspeed", KSTAT_DATA_UINT64);
12187c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_media, "media", KSTAT_DATA_CHAR);
12197c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_prom, "promisc", KSTAT_DATA_CHAR);
12207c478bd9Sstevel@tonic-gate 
12217c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_overflow, "oflo", KSTAT_DATA_ULONG);
12227c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_underflow, "uflo", KSTAT_DATA_ULONG);
12237c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_missed, "missed", KSTAT_DATA_ULONG);
12247c478bd9Sstevel@tonic-gate 
12257c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtbadinterp, "xmt_badinterp",
12267c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
12277c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_rcvbadinterp, "rcv_badinterp",
12287c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
12297c478bd9Sstevel@tonic-gate 
12307c478bd9Sstevel@tonic-gate 	kstat_install(ksp);
12317c478bd9Sstevel@tonic-gate 	return (GLD_SUCCESS);
12327c478bd9Sstevel@tonic-gate }
12337c478bd9Sstevel@tonic-gate 
12347c478bd9Sstevel@tonic-gate static int
12357c478bd9Sstevel@tonic-gate gld_update_vlan_kstat(kstat_t *ksp, int rw)
12367c478bd9Sstevel@tonic-gate {
12377c478bd9Sstevel@tonic-gate 	gld_vlan_t	*vlan;
12387c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*macinfo;
12397c478bd9Sstevel@tonic-gate 	struct gldkstats *gsp;
12407c478bd9Sstevel@tonic-gate 	struct gld_stats *stats;
12417c478bd9Sstevel@tonic-gate 
12427c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
12437c478bd9Sstevel@tonic-gate 		return (EACCES);
12447c478bd9Sstevel@tonic-gate 
12457c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)ksp->ks_private;
12467c478bd9Sstevel@tonic-gate 	ASSERT(vlan != NULL);
12477c478bd9Sstevel@tonic-gate 
12487c478bd9Sstevel@tonic-gate 	macinfo = vlan->gldv_mac;
12497c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
12507c478bd9Sstevel@tonic-gate 
12517c478bd9Sstevel@tonic-gate 	gsp = vlan->gldv_kstatp->ks_data;
12527c478bd9Sstevel@tonic-gate 	ASSERT(gsp);
12537c478bd9Sstevel@tonic-gate 	stats = vlan->gldv_stats;
12547c478bd9Sstevel@tonic-gate 
12557c478bd9Sstevel@tonic-gate 	gsp->glds_pktxmt.value.ui32 = stats->glds_pktxmt64 & 0xffffffff;
12567c478bd9Sstevel@tonic-gate 	gsp->glds_bytexmt.value.ui32 = stats->glds_bytexmt64 & 0xffffffff;
12577c478bd9Sstevel@tonic-gate 	gsp->glds_errxmt.value.ul = stats->glds_errxmt;
12587c478bd9Sstevel@tonic-gate 	gsp->glds_multixmt.value.ul = stats->glds_multixmt;
12597c478bd9Sstevel@tonic-gate 	gsp->glds_brdcstxmt.value.ul = stats->glds_brdcstxmt;
12607c478bd9Sstevel@tonic-gate 	gsp->glds_noxmtbuf.value.ul = stats->glds_noxmtbuf;
12617c478bd9Sstevel@tonic-gate 	gsp->glds_xmtretry.value.ul = stats->glds_xmtretry;
12627c478bd9Sstevel@tonic-gate 	gsp->glds_pktxmt64.value.ui64 = stats->glds_pktxmt64;
12637c478bd9Sstevel@tonic-gate 	gsp->glds_bytexmt64.value.ui64 = stats->glds_bytexmt64;
12647c478bd9Sstevel@tonic-gate 
12657c478bd9Sstevel@tonic-gate 	gsp->glds_pktrcv.value.ui32 = stats->glds_pktrcv64 & 0xffffffff;
12667c478bd9Sstevel@tonic-gate 	gsp->glds_bytercv.value.ui32 = stats->glds_bytercv64 & 0xffffffff;
12677c478bd9Sstevel@tonic-gate 	gsp->glds_errrcv.value.ul = stats->glds_errrcv;
12687c478bd9Sstevel@tonic-gate 	gsp->glds_multircv.value.ul = stats->glds_multircv;
12697c478bd9Sstevel@tonic-gate 	gsp->glds_brdcstrcv.value.ul = stats->glds_brdcstrcv;
12707c478bd9Sstevel@tonic-gate 	gsp->glds_blocked.value.ul = stats->glds_blocked;
12717c478bd9Sstevel@tonic-gate 	gsp->glds_pktrcv64.value.ui64 = stats->glds_pktrcv64;
12727c478bd9Sstevel@tonic-gate 	gsp->glds_bytercv64.value.ui64 = stats->glds_bytercv64;
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
12757c478bd9Sstevel@tonic-gate 	return (0);
12767c478bd9Sstevel@tonic-gate }
12777c478bd9Sstevel@tonic-gate 
12787c478bd9Sstevel@tonic-gate /*
12797c478bd9Sstevel@tonic-gate  * The device dependent driver specifies gld_getinfo as its getinfo routine.
12807c478bd9Sstevel@tonic-gate  */
12817c478bd9Sstevel@tonic-gate /*ARGSUSED*/
12827c478bd9Sstevel@tonic-gate int
12837c478bd9Sstevel@tonic-gate gld_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
12847c478bd9Sstevel@tonic-gate {
12857c478bd9Sstevel@tonic-gate 	dev_info_t	*devinfo;
12867c478bd9Sstevel@tonic-gate 	minor_t		minor = getminor((dev_t)arg);
12877c478bd9Sstevel@tonic-gate 	int		rc = DDI_FAILURE;
12887c478bd9Sstevel@tonic-gate 
12897c478bd9Sstevel@tonic-gate 	switch (cmd) {
12907c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
12917c478bd9Sstevel@tonic-gate 		if ((devinfo = gld_finddevinfo((dev_t)arg)) != NULL) {
12927c478bd9Sstevel@tonic-gate 			*(dev_info_t **)resultp = devinfo;
12937c478bd9Sstevel@tonic-gate 			rc = DDI_SUCCESS;
12947c478bd9Sstevel@tonic-gate 		}
12957c478bd9Sstevel@tonic-gate 		break;
12967c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
12977c478bd9Sstevel@tonic-gate 		/* Need static mapping for deferred attach */
12987c478bd9Sstevel@tonic-gate 		if (minor == GLD_USE_STYLE2) {
12997c478bd9Sstevel@tonic-gate 			/*
13007c478bd9Sstevel@tonic-gate 			 * Style 2:  this minor number does not correspond to
13017c478bd9Sstevel@tonic-gate 			 * any particular instance number.
13027c478bd9Sstevel@tonic-gate 			 */
13037c478bd9Sstevel@tonic-gate 			rc = DDI_FAILURE;
13047c478bd9Sstevel@tonic-gate 		} else if (minor <= GLD_MAX_STYLE1_MINOR) {
13057c478bd9Sstevel@tonic-gate 			/* Style 1:  calculate the PPA from the minor */
1306*0ef0bcfbSyz147064 			*resultp = (void *)GLD_STYLE1_MINOR_TO_PPA(minor);
13077c478bd9Sstevel@tonic-gate 			rc = DDI_SUCCESS;
13087c478bd9Sstevel@tonic-gate 		} else {
13097c478bd9Sstevel@tonic-gate 			/* Clone:  look for it.  Not a static mapping */
13107c478bd9Sstevel@tonic-gate 			if ((devinfo = gld_finddevinfo((dev_t)arg)) != NULL) {
1311*0ef0bcfbSyz147064 				*resultp = (void *)ddi_get_instance(devinfo);
13127c478bd9Sstevel@tonic-gate 				rc = DDI_SUCCESS;
13137c478bd9Sstevel@tonic-gate 			}
13147c478bd9Sstevel@tonic-gate 		}
13157c478bd9Sstevel@tonic-gate 		break;
13167c478bd9Sstevel@tonic-gate 	}
13177c478bd9Sstevel@tonic-gate 
13187c478bd9Sstevel@tonic-gate 	return (rc);
13197c478bd9Sstevel@tonic-gate }
13207c478bd9Sstevel@tonic-gate 
13217c478bd9Sstevel@tonic-gate /* called from gld_getinfo */
13227c478bd9Sstevel@tonic-gate dev_info_t *
13237c478bd9Sstevel@tonic-gate gld_finddevinfo(dev_t dev)
13247c478bd9Sstevel@tonic-gate {
13257c478bd9Sstevel@tonic-gate 	minor_t		minor = getminor(dev);
13267c478bd9Sstevel@tonic-gate 	glddev_t	*device;
13277c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*mac;
13287c478bd9Sstevel@tonic-gate 	gld_vlan_t	*vlan;
13297c478bd9Sstevel@tonic-gate 	gld_t		*str;
13307c478bd9Sstevel@tonic-gate 	dev_info_t	*devinfo = NULL;
13317c478bd9Sstevel@tonic-gate 	int		i;
13327c478bd9Sstevel@tonic-gate 
13337c478bd9Sstevel@tonic-gate 	if (minor == GLD_USE_STYLE2) {
13347c478bd9Sstevel@tonic-gate 		/*
13357c478bd9Sstevel@tonic-gate 		 * Style 2:  this minor number does not correspond to
13367c478bd9Sstevel@tonic-gate 		 * any particular instance number.
13377c478bd9Sstevel@tonic-gate 		 *
13387c478bd9Sstevel@tonic-gate 		 * XXX We don't know what to say.  See Bug 1165519.
13397c478bd9Sstevel@tonic-gate 		 */
13407c478bd9Sstevel@tonic-gate 		return (NULL);
13417c478bd9Sstevel@tonic-gate 	}
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);	/* hold the device */
13447c478bd9Sstevel@tonic-gate 
13457c478bd9Sstevel@tonic-gate 	device = gld_devlookup(getmajor(dev));
13467c478bd9Sstevel@tonic-gate 	if (device == NULL) {
13477c478bd9Sstevel@tonic-gate 		/* There are no attached instances of this device */
13487c478bd9Sstevel@tonic-gate 		mutex_exit(&gld_device_list.gld_devlock);
13497c478bd9Sstevel@tonic-gate 		return (NULL);
13507c478bd9Sstevel@tonic-gate 	}
13517c478bd9Sstevel@tonic-gate 
13527c478bd9Sstevel@tonic-gate 	/*
13537c478bd9Sstevel@tonic-gate 	 * Search all attached macs and streams.
13547c478bd9Sstevel@tonic-gate 	 *
13557c478bd9Sstevel@tonic-gate 	 * XXX We don't bother checking the DL_UNATTACHED streams since
13567c478bd9Sstevel@tonic-gate 	 * we don't know what devinfo we should report back even if we
13577c478bd9Sstevel@tonic-gate 	 * found the minor.  Maybe we should associate streams that are
13587c478bd9Sstevel@tonic-gate 	 * not currently attached to a PPA with the "first" devinfo node
13597c478bd9Sstevel@tonic-gate 	 * of the major device to attach -- the one that created the
13607c478bd9Sstevel@tonic-gate 	 * minor node for the generic device.
13617c478bd9Sstevel@tonic-gate 	 */
13627c478bd9Sstevel@tonic-gate 	mutex_enter(&device->gld_devlock);
13637c478bd9Sstevel@tonic-gate 
13647c478bd9Sstevel@tonic-gate 	for (mac = device->gld_mac_next;
13657c478bd9Sstevel@tonic-gate 	    mac != (gld_mac_info_t *)&device->gld_mac_next;
13667c478bd9Sstevel@tonic-gate 	    mac = mac->gldm_next) {
13677c478bd9Sstevel@tonic-gate 		gld_mac_pvt_t *pvt = (gld_mac_pvt_t *)mac->gldm_mac_pvt;
13687c478bd9Sstevel@tonic-gate 
13697c478bd9Sstevel@tonic-gate 		if (!(mac->gldm_GLD_flags & GLD_MAC_READY))
13707c478bd9Sstevel@tonic-gate 			continue;	/* this one's not ready yet */
13717c478bd9Sstevel@tonic-gate 		if (minor <= GLD_MAX_STYLE1_MINOR) {
13727c478bd9Sstevel@tonic-gate 			/* Style 1 -- look for the corresponding PPA */
13737c478bd9Sstevel@tonic-gate 			if (minor == GLD_STYLE1_PPA_TO_MINOR(mac->gldm_ppa)) {
13747c478bd9Sstevel@tonic-gate 				devinfo = mac->gldm_devinfo;
13757c478bd9Sstevel@tonic-gate 				goto out;	/* found it! */
13767c478bd9Sstevel@tonic-gate 			} else
13777c478bd9Sstevel@tonic-gate 				continue;	/* not this PPA */
13787c478bd9Sstevel@tonic-gate 		}
13797c478bd9Sstevel@tonic-gate 
13807c478bd9Sstevel@tonic-gate 		/* We are looking for a clone */
13817c478bd9Sstevel@tonic-gate 		for (i = 0; i < VLAN_HASHSZ; i++) {
13827c478bd9Sstevel@tonic-gate 			for (vlan = pvt->vlan_hash[i];
13837c478bd9Sstevel@tonic-gate 			    vlan != NULL; vlan = vlan->gldv_next) {
13847c478bd9Sstevel@tonic-gate 				for (str = vlan->gldv_str_next;
13857c478bd9Sstevel@tonic-gate 				    str != (gld_t *)&vlan->gldv_str_next;
13867c478bd9Sstevel@tonic-gate 				    str = str->gld_next) {
13877c478bd9Sstevel@tonic-gate 					ASSERT(str->gld_mac_info == mac);
13887c478bd9Sstevel@tonic-gate 					if (minor == str->gld_minor) {
13897c478bd9Sstevel@tonic-gate 						devinfo = mac->gldm_devinfo;
13907c478bd9Sstevel@tonic-gate 						goto out;
13917c478bd9Sstevel@tonic-gate 					}
13927c478bd9Sstevel@tonic-gate 				}
13937c478bd9Sstevel@tonic-gate 			}
13947c478bd9Sstevel@tonic-gate 		}
13957c478bd9Sstevel@tonic-gate 	}
13967c478bd9Sstevel@tonic-gate out:
13977c478bd9Sstevel@tonic-gate 	mutex_exit(&device->gld_devlock);
13987c478bd9Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
13997c478bd9Sstevel@tonic-gate 	return (devinfo);
14007c478bd9Sstevel@tonic-gate }
14017c478bd9Sstevel@tonic-gate 
14027c478bd9Sstevel@tonic-gate /*
14037c478bd9Sstevel@tonic-gate  * STREAMS open routine.  The device dependent driver specifies this as its
14047c478bd9Sstevel@tonic-gate  * open entry point.
14057c478bd9Sstevel@tonic-gate  */
14067c478bd9Sstevel@tonic-gate /*ARGSUSED2*/
14077c478bd9Sstevel@tonic-gate int
14087c478bd9Sstevel@tonic-gate gld_open(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *cred)
14097c478bd9Sstevel@tonic-gate {
14107c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
14117c478bd9Sstevel@tonic-gate 	gld_t *gld;
14127c478bd9Sstevel@tonic-gate 	glddev_t *glddev;
14137c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
14147c478bd9Sstevel@tonic-gate 	minor_t minor = getminor(*dev);
14157c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
14167c478bd9Sstevel@tonic-gate 	t_uscalar_t ppa;
14177c478bd9Sstevel@tonic-gate 
14187c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 	if (minor > GLD_MAX_STYLE1_MINOR)
14217c478bd9Sstevel@tonic-gate 		return (ENXIO);
14227c478bd9Sstevel@tonic-gate 
14237c478bd9Sstevel@tonic-gate 	ASSERT(q->q_ptr == NULL);	/* Clone device gives us a fresh Q */
14247c478bd9Sstevel@tonic-gate 
14257c478bd9Sstevel@tonic-gate 	/* Find our per-major glddev_t structure */
14267c478bd9Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
14277c478bd9Sstevel@tonic-gate 	glddev = gld_devlookup(getmajor(*dev));
14287c478bd9Sstevel@tonic-gate 
14297c478bd9Sstevel@tonic-gate 	/*
14307c478bd9Sstevel@tonic-gate 	 * This glddev will hang around since detach (and therefore
14317c478bd9Sstevel@tonic-gate 	 * gld_unregister) can't run while we're here in the open routine.
14327c478bd9Sstevel@tonic-gate 	 */
14337c478bd9Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
14347c478bd9Sstevel@tonic-gate 
14357c478bd9Sstevel@tonic-gate 	if (glddev == NULL)
14367c478bd9Sstevel@tonic-gate 		return (ENXIO);
14377c478bd9Sstevel@tonic-gate 
14387c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
14397c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
14407c478bd9Sstevel@tonic-gate 		if (minor == GLD_USE_STYLE2)
14417c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_open(%p, Style 2)", (void *)q);
14427c478bd9Sstevel@tonic-gate 		else
14437c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_open(%p, Style 1, minor = %d)",
14447c478bd9Sstevel@tonic-gate 			    (void *)q, minor);
14457c478bd9Sstevel@tonic-gate 	}
14467c478bd9Sstevel@tonic-gate #endif
14477c478bd9Sstevel@tonic-gate 
14487c478bd9Sstevel@tonic-gate 	/*
14497c478bd9Sstevel@tonic-gate 	 * get a per-stream structure and link things together so we
14507c478bd9Sstevel@tonic-gate 	 * can easily find them later.
14517c478bd9Sstevel@tonic-gate 	 */
14527c478bd9Sstevel@tonic-gate 	gld = kmem_zalloc(sizeof (gld_t), KM_SLEEP);
14537c478bd9Sstevel@tonic-gate 
14547c478bd9Sstevel@tonic-gate 	/*
14557c478bd9Sstevel@tonic-gate 	 * fill in the structure and state info
14567c478bd9Sstevel@tonic-gate 	 */
14577c478bd9Sstevel@tonic-gate 	gld->gld_qptr = q;
14587c478bd9Sstevel@tonic-gate 	gld->gld_device = glddev;
14597c478bd9Sstevel@tonic-gate 	gld->gld_state = DL_UNATTACHED;
14607c478bd9Sstevel@tonic-gate 
14617c478bd9Sstevel@tonic-gate 	/*
14627c478bd9Sstevel@tonic-gate 	 * we must atomically find a free minor number and add the stream
14637c478bd9Sstevel@tonic-gate 	 * to a list, because gld_findminor has to traverse the lists to
14647c478bd9Sstevel@tonic-gate 	 * determine which minor numbers are free.
14657c478bd9Sstevel@tonic-gate 	 */
14667c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
14677c478bd9Sstevel@tonic-gate 
14687c478bd9Sstevel@tonic-gate 	/* find a free minor device number for the clone */
14697c478bd9Sstevel@tonic-gate 	gld->gld_minor = gld_findminor(glddev);
14707c478bd9Sstevel@tonic-gate 	if (gld->gld_minor == 0) {
14717c478bd9Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
14727c478bd9Sstevel@tonic-gate 		kmem_free(gld, sizeof (gld_t));
14737c478bd9Sstevel@tonic-gate 		return (ENOSR);
14747c478bd9Sstevel@tonic-gate 	}
14757c478bd9Sstevel@tonic-gate 
14767c478bd9Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
14777c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT)
14787c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_open() gld ptr: %p minor: %d",
14797c478bd9Sstevel@tonic-gate 		    (void *)gld, gld->gld_minor);
14807c478bd9Sstevel@tonic-gate #endif
14817c478bd9Sstevel@tonic-gate 
14827c478bd9Sstevel@tonic-gate 	if (minor == GLD_USE_STYLE2) {
14837c478bd9Sstevel@tonic-gate 		gld->gld_style = DL_STYLE2;
14847c478bd9Sstevel@tonic-gate 		*dev = makedevice(getmajor(*dev), gld->gld_minor);
14857c478bd9Sstevel@tonic-gate 		WR(q)->q_ptr = q->q_ptr = (caddr_t)gld;
14867c478bd9Sstevel@tonic-gate 		gldinsque(gld, glddev->gld_str_prev);
14877c478bd9Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
14887c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDPROT)
14897c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "GLDstruct added to device list");
14907c478bd9Sstevel@tonic-gate #endif
14917c478bd9Sstevel@tonic-gate 		(void) qassociate(q, -1);
14927c478bd9Sstevel@tonic-gate 		goto done;
14937c478bd9Sstevel@tonic-gate 	}
14947c478bd9Sstevel@tonic-gate 
14957c478bd9Sstevel@tonic-gate 	gld->gld_style = DL_STYLE1;
14967c478bd9Sstevel@tonic-gate 
14977c478bd9Sstevel@tonic-gate 	/* the PPA is actually 1 less than the minordev */
14987c478bd9Sstevel@tonic-gate 	ppa = GLD_STYLE1_MINOR_TO_PPA(minor);
14997c478bd9Sstevel@tonic-gate 
15007c478bd9Sstevel@tonic-gate 	for (macinfo = glddev->gld_mac_next;
15017c478bd9Sstevel@tonic-gate 	    macinfo != (gld_mac_info_t *)(&glddev->gld_mac_next);
15027c478bd9Sstevel@tonic-gate 	    macinfo = macinfo->gldm_next) {
15037c478bd9Sstevel@tonic-gate 		ASSERT(macinfo != NULL);
15047c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_ppa != ppa)
15057c478bd9Sstevel@tonic-gate 			continue;
15067c478bd9Sstevel@tonic-gate 
15077c478bd9Sstevel@tonic-gate 		if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY))
15087c478bd9Sstevel@tonic-gate 			continue;	/* this one's not ready yet */
15097c478bd9Sstevel@tonic-gate 
15107c478bd9Sstevel@tonic-gate 		/*
15117c478bd9Sstevel@tonic-gate 		 * we found the correct PPA
15127c478bd9Sstevel@tonic-gate 		 */
15137c478bd9Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
15147c478bd9Sstevel@tonic-gate 
15157c478bd9Sstevel@tonic-gate 		gld->gld_mac_info = macinfo;
15167c478bd9Sstevel@tonic-gate 
15177c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_send_tagged != NULL)
15187c478bd9Sstevel@tonic-gate 			gld->gld_send = macinfo->gldm_send_tagged;
15197c478bd9Sstevel@tonic-gate 		else
15207c478bd9Sstevel@tonic-gate 			gld->gld_send = macinfo->gldm_send;
15217c478bd9Sstevel@tonic-gate 
15227c478bd9Sstevel@tonic-gate 		/* now ready for action */
15237c478bd9Sstevel@tonic-gate 		gld->gld_state = DL_UNBOUND;
15247c478bd9Sstevel@tonic-gate 
15257c478bd9Sstevel@tonic-gate 		if ((vlan = gld_get_vlan(macinfo, VLAN_VID_NONE)) == NULL) {
15267c478bd9Sstevel@tonic-gate 			GLDM_UNLOCK(macinfo);
15277c478bd9Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
15287c478bd9Sstevel@tonic-gate 			kmem_free(gld, sizeof (gld_t));
15297c478bd9Sstevel@tonic-gate 			return (EIO);
15307c478bd9Sstevel@tonic-gate 		}
15317c478bd9Sstevel@tonic-gate 
15327c478bd9Sstevel@tonic-gate 		mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
15337c478bd9Sstevel@tonic-gate 		if (!mac_pvt->started) {
15347c478bd9Sstevel@tonic-gate 			if (gld_start_mac(macinfo) != GLD_SUCCESS) {
1535*0ef0bcfbSyz147064 				gld_rem_vlan(vlan);
15367c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
15377c478bd9Sstevel@tonic-gate 				mutex_exit(&glddev->gld_devlock);
15387c478bd9Sstevel@tonic-gate 				kmem_free(gld, sizeof (gld_t));
15397c478bd9Sstevel@tonic-gate 				return (EIO);
15407c478bd9Sstevel@tonic-gate 			}
15417c478bd9Sstevel@tonic-gate 		}
15427c478bd9Sstevel@tonic-gate 
15437c478bd9Sstevel@tonic-gate 		gld->gld_vlan = vlan;
15447c478bd9Sstevel@tonic-gate 		vlan->gldv_nstreams++;
15457c478bd9Sstevel@tonic-gate 		gldinsque(gld, vlan->gldv_str_prev);
15467c478bd9Sstevel@tonic-gate 		*dev = makedevice(getmajor(*dev), gld->gld_minor);
15477c478bd9Sstevel@tonic-gate 		WR(q)->q_ptr = q->q_ptr = (caddr_t)gld;
15487c478bd9Sstevel@tonic-gate 
15497c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
15507c478bd9Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
15517c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDPROT)
15527c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
15537c478bd9Sstevel@tonic-gate 			    "GLDstruct added to instance list");
15547c478bd9Sstevel@tonic-gate #endif
15557c478bd9Sstevel@tonic-gate 		break;
15567c478bd9Sstevel@tonic-gate 	}
15577c478bd9Sstevel@tonic-gate 
15587c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED) {
15597c478bd9Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
15607c478bd9Sstevel@tonic-gate 		kmem_free(gld, sizeof (gld_t));
15617c478bd9Sstevel@tonic-gate 		return (ENXIO);
15627c478bd9Sstevel@tonic-gate 	}
15637c478bd9Sstevel@tonic-gate 
15647c478bd9Sstevel@tonic-gate done:
15657c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
15667c478bd9Sstevel@tonic-gate 	noenable(WR(q));	/* We'll do the qenables manually */
15677c478bd9Sstevel@tonic-gate 	qprocson(q);		/* start the queues running */
15687c478bd9Sstevel@tonic-gate 	qenable(WR(q));
15697c478bd9Sstevel@tonic-gate 	return (0);
15707c478bd9Sstevel@tonic-gate }
15717c478bd9Sstevel@tonic-gate 
15727c478bd9Sstevel@tonic-gate /*
15737c478bd9Sstevel@tonic-gate  * normal stream close call checks current status and cleans up
15747c478bd9Sstevel@tonic-gate  * data structures that were dynamically allocated
15757c478bd9Sstevel@tonic-gate  */
15767c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
15777c478bd9Sstevel@tonic-gate int
15787c478bd9Sstevel@tonic-gate gld_close(queue_t *q, int flag, cred_t *cred)
15797c478bd9Sstevel@tonic-gate {
15807c478bd9Sstevel@tonic-gate 	gld_t	*gld = (gld_t *)q->q_ptr;
15817c478bd9Sstevel@tonic-gate 	glddev_t *glddev = gld->gld_device;
15827c478bd9Sstevel@tonic-gate 
15837c478bd9Sstevel@tonic-gate 	ASSERT(q);
15847c478bd9Sstevel@tonic-gate 	ASSERT(gld);
15857c478bd9Sstevel@tonic-gate 
15867c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
15877c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
15887c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_close(%p, Style %d)",
15897c478bd9Sstevel@tonic-gate 		    (void *)q, (gld->gld_style & 0x1) + 1);
15907c478bd9Sstevel@tonic-gate 	}
15917c478bd9Sstevel@tonic-gate #endif
15927c478bd9Sstevel@tonic-gate 
15937c478bd9Sstevel@tonic-gate 	/* Hold all device streams lists still while we check for a macinfo */
15947c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
15957c478bd9Sstevel@tonic-gate 
15967c478bd9Sstevel@tonic-gate 	if (gld->gld_mac_info != NULL) {
15977c478bd9Sstevel@tonic-gate 		/* If there's a macinfo, block recv while we change state */
15987c478bd9Sstevel@tonic-gate 		GLDM_LOCK(gld->gld_mac_info, RW_WRITER);
15997c478bd9Sstevel@tonic-gate 		gld->gld_flags |= GLD_STR_CLOSING; /* no more rcv putnexts */
16007c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(gld->gld_mac_info);
16017c478bd9Sstevel@tonic-gate 	} else {
16027c478bd9Sstevel@tonic-gate 		/* no mac DL_ATTACHED right now */
16037c478bd9Sstevel@tonic-gate 		gld->gld_flags |= GLD_STR_CLOSING;
16047c478bd9Sstevel@tonic-gate 	}
16057c478bd9Sstevel@tonic-gate 
16067c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
16077c478bd9Sstevel@tonic-gate 
16087c478bd9Sstevel@tonic-gate 	/*
16097c478bd9Sstevel@tonic-gate 	 * qprocsoff before we call gld_unbind/gldunattach, so that
16107c478bd9Sstevel@tonic-gate 	 * we know wsrv isn't in there trying to undo what we're doing.
16117c478bd9Sstevel@tonic-gate 	 */
16127c478bd9Sstevel@tonic-gate 	qprocsoff(q);
16137c478bd9Sstevel@tonic-gate 
16147c478bd9Sstevel@tonic-gate 	ASSERT(gld->gld_wput_count == 0);
16157c478bd9Sstevel@tonic-gate 	gld->gld_wput_count = 0;	/* just in case */
16167c478bd9Sstevel@tonic-gate 
16177c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_IDLE) {
16187c478bd9Sstevel@tonic-gate 		/* Need to unbind */
16197c478bd9Sstevel@tonic-gate 		ASSERT(gld->gld_mac_info != NULL);
16207c478bd9Sstevel@tonic-gate 		(void) gld_unbind(WR(q), NULL);
16217c478bd9Sstevel@tonic-gate 	}
16227c478bd9Sstevel@tonic-gate 
16237c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNBOUND) {
16247c478bd9Sstevel@tonic-gate 		/*
16257c478bd9Sstevel@tonic-gate 		 * Need to unattach
16267c478bd9Sstevel@tonic-gate 		 * For style 2 stream, gldunattach also
16277c478bd9Sstevel@tonic-gate 		 * associate queue with NULL dip
16287c478bd9Sstevel@tonic-gate 		 */
16297c478bd9Sstevel@tonic-gate 		ASSERT(gld->gld_mac_info != NULL);
16307c478bd9Sstevel@tonic-gate 		(void) gldunattach(WR(q), NULL);
16317c478bd9Sstevel@tonic-gate 	}
16327c478bd9Sstevel@tonic-gate 
16337c478bd9Sstevel@tonic-gate 	/* disassociate the stream from the device */
16347c478bd9Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = NULL;
16357c478bd9Sstevel@tonic-gate 
16367c478bd9Sstevel@tonic-gate 	/*
16377c478bd9Sstevel@tonic-gate 	 * Since we unattached above (if necessary), we know that we're
16387c478bd9Sstevel@tonic-gate 	 * on the per-major list of unattached streams, rather than a
16397c478bd9Sstevel@tonic-gate 	 * per-PPA list.  So we know we should hold the devlock.
16407c478bd9Sstevel@tonic-gate 	 */
16417c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
16427c478bd9Sstevel@tonic-gate 	gldremque(gld);			/* remove from Style 2 list */
16437c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate 	kmem_free(gld, sizeof (gld_t));
16467c478bd9Sstevel@tonic-gate 
16477c478bd9Sstevel@tonic-gate 	return (0);
16487c478bd9Sstevel@tonic-gate }
16497c478bd9Sstevel@tonic-gate 
16507c478bd9Sstevel@tonic-gate /*
16517c478bd9Sstevel@tonic-gate  * gld_rsrv (q)
16527c478bd9Sstevel@tonic-gate  *	simple read service procedure
16537c478bd9Sstevel@tonic-gate  *	purpose is to avoid the time it takes for packets
16547c478bd9Sstevel@tonic-gate  *	to move through IP so we can get them off the board
16557c478bd9Sstevel@tonic-gate  *	as fast as possible due to limited PC resources.
16567c478bd9Sstevel@tonic-gate  *
16577c478bd9Sstevel@tonic-gate  *	This is not normally used in the current implementation.  It
16587c478bd9Sstevel@tonic-gate  *	can be selected with the undocumented property "fast_recv".
16597c478bd9Sstevel@tonic-gate  *	If that property is set, gld_recv will send the packet
16607c478bd9Sstevel@tonic-gate  *	upstream with a putq() rather than a putnext(), thus causing
16617c478bd9Sstevel@tonic-gate  *	this routine to be scheduled.
16627c478bd9Sstevel@tonic-gate  */
16637c478bd9Sstevel@tonic-gate int
16647c478bd9Sstevel@tonic-gate gld_rsrv(queue_t *q)
16657c478bd9Sstevel@tonic-gate {
16667c478bd9Sstevel@tonic-gate 	mblk_t *mp;
16677c478bd9Sstevel@tonic-gate 
16687c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
16697c478bd9Sstevel@tonic-gate 		if (canputnext(q)) {
16707c478bd9Sstevel@tonic-gate 			putnext(q, mp);
16717c478bd9Sstevel@tonic-gate 		} else {
16727c478bd9Sstevel@tonic-gate 			freemsg(mp);
16737c478bd9Sstevel@tonic-gate 		}
16747c478bd9Sstevel@tonic-gate 	}
16757c478bd9Sstevel@tonic-gate 	return (0);
16767c478bd9Sstevel@tonic-gate }
16777c478bd9Sstevel@tonic-gate 
16787c478bd9Sstevel@tonic-gate /*
16797c478bd9Sstevel@tonic-gate  * gld_wput (q, mp)
16807c478bd9Sstevel@tonic-gate  * general gld stream write put routine. Receives fastpath data from upper
16817c478bd9Sstevel@tonic-gate  * modules and processes it immediately.  ioctl and M_PROTO/M_PCPROTO are
16827c478bd9Sstevel@tonic-gate  * queued for later processing by the service procedure.
16837c478bd9Sstevel@tonic-gate  */
16847c478bd9Sstevel@tonic-gate 
16857c478bd9Sstevel@tonic-gate int
16867c478bd9Sstevel@tonic-gate gld_wput(queue_t *q, mblk_t *mp)
16877c478bd9Sstevel@tonic-gate {
16887c478bd9Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)(q->q_ptr);
16897c478bd9Sstevel@tonic-gate 	int	rc;
16907c478bd9Sstevel@tonic-gate 	boolean_t multidata = B_TRUE;
16917c478bd9Sstevel@tonic-gate 
16927c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
16937c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
16947c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_wput(%p %p): type %x",
16957c478bd9Sstevel@tonic-gate 		    (void *)q, (void *)mp, DB_TYPE(mp));
16967c478bd9Sstevel@tonic-gate #endif
16977c478bd9Sstevel@tonic-gate 	switch (DB_TYPE(mp)) {
16987c478bd9Sstevel@tonic-gate 
16997c478bd9Sstevel@tonic-gate 	case M_DATA:
17007c478bd9Sstevel@tonic-gate 		/* fast data / raw support */
17017c478bd9Sstevel@tonic-gate 		/* we must be DL_ATTACHED and DL_BOUND to do this */
17027c478bd9Sstevel@tonic-gate 		/* Tricky to access memory without taking the mutex */
17037c478bd9Sstevel@tonic-gate 		if ((gld->gld_flags & (GLD_RAW | GLD_FAST)) == 0 ||
17047c478bd9Sstevel@tonic-gate 		    gld->gld_state != DL_IDLE) {
17057c478bd9Sstevel@tonic-gate 			merror(q, mp, EPROTO);
17067c478bd9Sstevel@tonic-gate 			break;
17077c478bd9Sstevel@tonic-gate 		}
17087c478bd9Sstevel@tonic-gate 		multidata = B_FALSE;
17097c478bd9Sstevel@tonic-gate 		/* LINTED: E_CASE_FALLTHRU */
17107c478bd9Sstevel@tonic-gate 	case M_MULTIDATA:
17117c478bd9Sstevel@tonic-gate 		/* Only call gld_start() directly if nothing queued ahead */
17127c478bd9Sstevel@tonic-gate 		/* No guarantees about ordering with different threads */
17137c478bd9Sstevel@tonic-gate 		if (q->q_first)
17147c478bd9Sstevel@tonic-gate 			goto use_wsrv;
17157c478bd9Sstevel@tonic-gate 
17167c478bd9Sstevel@tonic-gate 		/*
17177c478bd9Sstevel@tonic-gate 		 * This can happen if wsrv has taken off the last mblk but
17187c478bd9Sstevel@tonic-gate 		 * is still processing it.
17197c478bd9Sstevel@tonic-gate 		 */
17207c478bd9Sstevel@tonic-gate 		membar_consumer();
17217c478bd9Sstevel@tonic-gate 		if (gld->gld_in_wsrv)
17227c478bd9Sstevel@tonic-gate 			goto use_wsrv;
17237c478bd9Sstevel@tonic-gate 
17247c478bd9Sstevel@tonic-gate 		/*
17257c478bd9Sstevel@tonic-gate 		 * Keep a count of current wput calls to start.
17267c478bd9Sstevel@tonic-gate 		 * Nonzero count delays any attempted DL_UNBIND.
17277c478bd9Sstevel@tonic-gate 		 * See comments above gld_start().
17287c478bd9Sstevel@tonic-gate 		 */
17297c478bd9Sstevel@tonic-gate 		atomic_add_32((uint32_t *)&gld->gld_wput_count, 1);
17307c478bd9Sstevel@tonic-gate 		membar_enter();
17317c478bd9Sstevel@tonic-gate 
17327c478bd9Sstevel@tonic-gate 		/* Recheck state now wput_count is set to prevent DL_UNBIND */
17337c478bd9Sstevel@tonic-gate 		/* If this Q is in process of DL_UNBIND, don't call start */
17347c478bd9Sstevel@tonic-gate 		if (gld->gld_state != DL_IDLE || gld->gld_in_unbind) {
17357c478bd9Sstevel@tonic-gate 			/* Extremely unlikely */
17367c478bd9Sstevel@tonic-gate 			atomic_add_32((uint32_t *)&gld->gld_wput_count, -1);
17377c478bd9Sstevel@tonic-gate 			goto use_wsrv;
17387c478bd9Sstevel@tonic-gate 		}
17397c478bd9Sstevel@tonic-gate 
17407c478bd9Sstevel@tonic-gate 		rc = (multidata) ? gld_start_mdt(q, mp, GLD_WPUT) :
17417c478bd9Sstevel@tonic-gate 		    gld_start(q, mp, GLD_WPUT, UPRI(gld, mp->b_band));
17427c478bd9Sstevel@tonic-gate 
17437c478bd9Sstevel@tonic-gate 		/* Allow DL_UNBIND again */
17447c478bd9Sstevel@tonic-gate 		membar_exit();
17457c478bd9Sstevel@tonic-gate 		atomic_add_32((uint32_t *)&gld->gld_wput_count, -1);
17467c478bd9Sstevel@tonic-gate 
17477c478bd9Sstevel@tonic-gate 		if (rc == GLD_NORESOURCES)
17487c478bd9Sstevel@tonic-gate 			qenable(q);
17497c478bd9Sstevel@tonic-gate 		break;	/*  Done with this packet */
17507c478bd9Sstevel@tonic-gate 
17517c478bd9Sstevel@tonic-gate use_wsrv:
17527c478bd9Sstevel@tonic-gate 		/* Q not empty, in DL_DETACH, or start gave NORESOURCES */
17537c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
17547c478bd9Sstevel@tonic-gate 		qenable(q);
17557c478bd9Sstevel@tonic-gate 		break;
17567c478bd9Sstevel@tonic-gate 
17577c478bd9Sstevel@tonic-gate 	case M_IOCTL:
17587c478bd9Sstevel@tonic-gate 		/* ioctl relies on wsrv single threading per queue */
17597c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
17607c478bd9Sstevel@tonic-gate 		qenable(q);
17617c478bd9Sstevel@tonic-gate 		break;
17627c478bd9Sstevel@tonic-gate 
17637c478bd9Sstevel@tonic-gate 	case M_CTL:
17647c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
17657c478bd9Sstevel@tonic-gate 		qenable(q);
17667c478bd9Sstevel@tonic-gate 		break;
17677c478bd9Sstevel@tonic-gate 
17687c478bd9Sstevel@tonic-gate 	case M_FLUSH:		/* canonical flush handling */
17697c478bd9Sstevel@tonic-gate 		/* XXX Should these be FLUSHALL? */
17707c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
17717c478bd9Sstevel@tonic-gate 			flushq(q, 0);
17727c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
17737c478bd9Sstevel@tonic-gate 			flushq(RD(q), 0);
17747c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;
17757c478bd9Sstevel@tonic-gate 			qreply(q, mp);
17767c478bd9Sstevel@tonic-gate 		} else
17777c478bd9Sstevel@tonic-gate 			freemsg(mp);
17787c478bd9Sstevel@tonic-gate 		break;
17797c478bd9Sstevel@tonic-gate 
17807c478bd9Sstevel@tonic-gate 	case M_PROTO:
17817c478bd9Sstevel@tonic-gate 	case M_PCPROTO:
17827c478bd9Sstevel@tonic-gate 		/* these rely on wsrv single threading per queue */
17837c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
17847c478bd9Sstevel@tonic-gate 		qenable(q);
17857c478bd9Sstevel@tonic-gate 		break;
17867c478bd9Sstevel@tonic-gate 
17877c478bd9Sstevel@tonic-gate 	default:
17887c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
17897c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDETRACE)
17907c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
17917c478bd9Sstevel@tonic-gate 			    "gld: Unexpected packet type from queue: 0x%x",
17927c478bd9Sstevel@tonic-gate 			    DB_TYPE(mp));
17937c478bd9Sstevel@tonic-gate #endif
17947c478bd9Sstevel@tonic-gate 		freemsg(mp);
17957c478bd9Sstevel@tonic-gate 	}
17967c478bd9Sstevel@tonic-gate 	return (0);
17977c478bd9Sstevel@tonic-gate }
17987c478bd9Sstevel@tonic-gate 
17997c478bd9Sstevel@tonic-gate /*
18007c478bd9Sstevel@tonic-gate  * gld_wsrv - Incoming messages are processed according to the DLPI protocol
18017c478bd9Sstevel@tonic-gate  * specification.
18027c478bd9Sstevel@tonic-gate  *
18037c478bd9Sstevel@tonic-gate  * wsrv is single-threaded per Q.  We make use of this to avoid taking the
18047c478bd9Sstevel@tonic-gate  * lock for reading data items that are only ever written by us.
18057c478bd9Sstevel@tonic-gate  */
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate int
18087c478bd9Sstevel@tonic-gate gld_wsrv(queue_t *q)
18097c478bd9Sstevel@tonic-gate {
18107c478bd9Sstevel@tonic-gate 	mblk_t *mp;
18117c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
18127c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
18137c478bd9Sstevel@tonic-gate 	union DL_primitives *prim;
18147c478bd9Sstevel@tonic-gate 	int err;
18157c478bd9Sstevel@tonic-gate 	boolean_t multidata;
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
18187c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
18197c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_wsrv(%p)", (void *)q);
18207c478bd9Sstevel@tonic-gate #endif
18217c478bd9Sstevel@tonic-gate 
18227c478bd9Sstevel@tonic-gate 	ASSERT(!gld->gld_in_wsrv);
18237c478bd9Sstevel@tonic-gate 
18247c478bd9Sstevel@tonic-gate 	gld->gld_xwait = B_FALSE; /* We are now going to process this Q */
18257c478bd9Sstevel@tonic-gate 
18267c478bd9Sstevel@tonic-gate 	if (q->q_first == NULL)
18277c478bd9Sstevel@tonic-gate 		return (0);
18287c478bd9Sstevel@tonic-gate 
18297c478bd9Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	/*
18327c478bd9Sstevel@tonic-gate 	 * Help wput avoid a call to gld_start if there might be a message
18337c478bd9Sstevel@tonic-gate 	 * previously queued by that thread being processed here.
18347c478bd9Sstevel@tonic-gate 	 */
18357c478bd9Sstevel@tonic-gate 	gld->gld_in_wsrv = B_TRUE;
18367c478bd9Sstevel@tonic-gate 	membar_enter();
18377c478bd9Sstevel@tonic-gate 
18387c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
18397c478bd9Sstevel@tonic-gate 		switch (DB_TYPE(mp)) {
18407c478bd9Sstevel@tonic-gate 		case M_DATA:
18417c478bd9Sstevel@tonic-gate 		case M_MULTIDATA:
18427c478bd9Sstevel@tonic-gate 			multidata = (DB_TYPE(mp) == M_MULTIDATA);
18437c478bd9Sstevel@tonic-gate 
18447c478bd9Sstevel@tonic-gate 			/*
18457c478bd9Sstevel@tonic-gate 			 * retry of a previously processed UNITDATA_REQ
18467c478bd9Sstevel@tonic-gate 			 * or is a RAW or FAST message from above.
18477c478bd9Sstevel@tonic-gate 			 */
18487c478bd9Sstevel@tonic-gate 			if (macinfo == NULL) {
18497c478bd9Sstevel@tonic-gate 				/* No longer attached to a PPA, drop packet */
18507c478bd9Sstevel@tonic-gate 				freemsg(mp);
18517c478bd9Sstevel@tonic-gate 				break;
18527c478bd9Sstevel@tonic-gate 			}
18537c478bd9Sstevel@tonic-gate 
18547c478bd9Sstevel@tonic-gate 			gld->gld_sched_ran = B_FALSE;
18557c478bd9Sstevel@tonic-gate 			membar_enter();
18567c478bd9Sstevel@tonic-gate 			err = (multidata) ? gld_start_mdt(q, mp, GLD_WSRV) :
18577c478bd9Sstevel@tonic-gate 			    gld_start(q, mp, GLD_WSRV, UPRI(gld, mp->b_band));
18587c478bd9Sstevel@tonic-gate 			if (err == GLD_NORESOURCES) {
18597c478bd9Sstevel@tonic-gate 				/* gld_sched will qenable us later */
18607c478bd9Sstevel@tonic-gate 				gld->gld_xwait = B_TRUE; /* want qenable */
18617c478bd9Sstevel@tonic-gate 				membar_enter();
18627c478bd9Sstevel@tonic-gate 				/*
18637c478bd9Sstevel@tonic-gate 				 * v2:  we're not holding the lock; it's
18647c478bd9Sstevel@tonic-gate 				 * possible that the driver could have already
18657c478bd9Sstevel@tonic-gate 				 * called gld_sched (following up on its
18667c478bd9Sstevel@tonic-gate 				 * return of GLD_NORESOURCES), before we got a
18677c478bd9Sstevel@tonic-gate 				 * chance to do the putbq() and set gld_xwait.
18687c478bd9Sstevel@tonic-gate 				 * So if we saw a call to gld_sched that
18697c478bd9Sstevel@tonic-gate 				 * examined this queue, since our call to
18707c478bd9Sstevel@tonic-gate 				 * gld_start() above, then it's possible we've
18717c478bd9Sstevel@tonic-gate 				 * already seen the only call to gld_sched()
18727c478bd9Sstevel@tonic-gate 				 * we're ever going to see.  So we better retry
18737c478bd9Sstevel@tonic-gate 				 * transmitting this packet right now.
18747c478bd9Sstevel@tonic-gate 				 */
18757c478bd9Sstevel@tonic-gate 				if (gld->gld_sched_ran) {
18767c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
18777c478bd9Sstevel@tonic-gate 					if (gld_debug & GLDTRACE)
18787c478bd9Sstevel@tonic-gate 						cmn_err(CE_NOTE, "gld_wsrv: "
18797c478bd9Sstevel@tonic-gate 						    "sched was called");
18807c478bd9Sstevel@tonic-gate #endif
18817c478bd9Sstevel@tonic-gate 					break;	/* try again right now */
18827c478bd9Sstevel@tonic-gate 				}
18837c478bd9Sstevel@tonic-gate 				gld->gld_in_wsrv = B_FALSE;
18847c478bd9Sstevel@tonic-gate 				return (0);
18857c478bd9Sstevel@tonic-gate 			}
18867c478bd9Sstevel@tonic-gate 			break;
18877c478bd9Sstevel@tonic-gate 
18887c478bd9Sstevel@tonic-gate 		case M_IOCTL:
18897c478bd9Sstevel@tonic-gate 			(void) gld_ioctl(q, mp);
18907c478bd9Sstevel@tonic-gate 			break;
18917c478bd9Sstevel@tonic-gate 
18927c478bd9Sstevel@tonic-gate 		case M_CTL:
18937c478bd9Sstevel@tonic-gate 			if (macinfo == NULL) {
18947c478bd9Sstevel@tonic-gate 				freemsg(mp);
18957c478bd9Sstevel@tonic-gate 				break;
18967c478bd9Sstevel@tonic-gate 			}
18977c478bd9Sstevel@tonic-gate 
18987c478bd9Sstevel@tonic-gate 			if (macinfo->gldm_mctl != NULL) {
18997c478bd9Sstevel@tonic-gate 				GLDM_LOCK(macinfo, RW_WRITER);
19007c478bd9Sstevel@tonic-gate 				(void) (*macinfo->gldm_mctl) (macinfo, q, mp);
19017c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
19027c478bd9Sstevel@tonic-gate 			} else {
19037c478bd9Sstevel@tonic-gate 				/* This driver doesn't recognize, just drop */
19047c478bd9Sstevel@tonic-gate 				freemsg(mp);
19057c478bd9Sstevel@tonic-gate 			}
19067c478bd9Sstevel@tonic-gate 			break;
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate 		case M_PROTO:	/* Will be an DLPI message of some type */
19097c478bd9Sstevel@tonic-gate 		case M_PCPROTO:
19107c478bd9Sstevel@tonic-gate 			if ((err = gld_cmds(q, mp)) != GLDE_OK) {
19117c478bd9Sstevel@tonic-gate 				if (err == GLDE_RETRY) {
19127c478bd9Sstevel@tonic-gate 					gld->gld_in_wsrv = B_FALSE;
19137c478bd9Sstevel@tonic-gate 					return (0); /* quit while we're ahead */
19147c478bd9Sstevel@tonic-gate 				}
19157c478bd9Sstevel@tonic-gate 				prim = (union DL_primitives *)mp->b_rptr;
19167c478bd9Sstevel@tonic-gate 				dlerrorack(q, mp, prim->dl_primitive, err, 0);
19177c478bd9Sstevel@tonic-gate 			}
19187c478bd9Sstevel@tonic-gate 			break;
19197c478bd9Sstevel@tonic-gate 
19207c478bd9Sstevel@tonic-gate 		default:
19217c478bd9Sstevel@tonic-gate 			/* This should never happen */
19227c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
19237c478bd9Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
19247c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
19257c478bd9Sstevel@tonic-gate 				    "gld_wsrv: db_type(%x) not supported",
19267c478bd9Sstevel@tonic-gate 				    mp->b_datap->db_type);
19277c478bd9Sstevel@tonic-gate #endif
19287c478bd9Sstevel@tonic-gate 			freemsg(mp);	/* unknown types are discarded */
19297c478bd9Sstevel@tonic-gate 			break;
19307c478bd9Sstevel@tonic-gate 		}
19317c478bd9Sstevel@tonic-gate 	}
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate 	membar_exit();
19347c478bd9Sstevel@tonic-gate 	gld->gld_in_wsrv = B_FALSE;
19357c478bd9Sstevel@tonic-gate 	return (0);
19367c478bd9Sstevel@tonic-gate }
19377c478bd9Sstevel@tonic-gate 
19387c478bd9Sstevel@tonic-gate /*
19397c478bd9Sstevel@tonic-gate  * gld_start() can get called from gld_wput(), gld_wsrv(), or gld_unitdata().
19407c478bd9Sstevel@tonic-gate  *
19417c478bd9Sstevel@tonic-gate  * We only come directly from wput() in the GLD_FAST (fastpath) or RAW case.
19427c478bd9Sstevel@tonic-gate  *
19437c478bd9Sstevel@tonic-gate  * In particular, we must avoid calling gld_precv*() if we came from wput().
19447c478bd9Sstevel@tonic-gate  * gld_precv*() is where we, on the transmit side, loop back our outgoing
19457c478bd9Sstevel@tonic-gate  * packets to the receive side if we are in physical promiscuous mode.
19467c478bd9Sstevel@tonic-gate  * Since the receive side holds a lock across its call to the upstream
19477c478bd9Sstevel@tonic-gate  * putnext, and that upstream module could well have looped back to our
19487c478bd9Sstevel@tonic-gate  * wput() routine on the same thread, we cannot call gld_precv* from here
19497c478bd9Sstevel@tonic-gate  * for fear of causing a recursive lock entry in our receive code.
19507c478bd9Sstevel@tonic-gate  *
19517c478bd9Sstevel@tonic-gate  * There is a problem here when coming from gld_wput().  While wput
19527c478bd9Sstevel@tonic-gate  * only comes here if the queue is attached to a PPA and bound to a SAP
19537c478bd9Sstevel@tonic-gate  * and there are no messages on the queue ahead of the M_DATA that could
19547c478bd9Sstevel@tonic-gate  * change that, it is theoretically possible that another thread could
19557c478bd9Sstevel@tonic-gate  * now wput a DL_UNBIND and a DL_DETACH message, and the wsrv() routine
19567c478bd9Sstevel@tonic-gate  * could wake up and process them, before we finish processing this
19577c478bd9Sstevel@tonic-gate  * send of the M_DATA.  This can only possibly happen on a Style 2 RAW or
19587c478bd9Sstevel@tonic-gate  * FAST (fastpath) stream:  non RAW/FAST streams always go through wsrv(),
19597c478bd9Sstevel@tonic-gate  * and Style 1 streams only DL_DETACH in the close routine, where
19607c478bd9Sstevel@tonic-gate  * qprocsoff() protects us.  If this happens we could end up calling
19617c478bd9Sstevel@tonic-gate  * gldm_send() after we have detached the stream and possibly called
19627c478bd9Sstevel@tonic-gate  * gldm_stop().  Worse, once the number of attached streams goes to zero,
19637c478bd9Sstevel@tonic-gate  * detach/unregister could be called, and the macinfo could go away entirely.
19647c478bd9Sstevel@tonic-gate  *
19657c478bd9Sstevel@tonic-gate  * No one has ever seen this happen.
19667c478bd9Sstevel@tonic-gate  *
19677c478bd9Sstevel@tonic-gate  * It is some trouble to fix this, and we would rather not add any mutex
19687c478bd9Sstevel@tonic-gate  * logic into the wput() routine, which is supposed to be a "fast"
19697c478bd9Sstevel@tonic-gate  * path.
19707c478bd9Sstevel@tonic-gate  *
19717c478bd9Sstevel@tonic-gate  * What I've done is use an atomic counter to keep a count of the number
19727c478bd9Sstevel@tonic-gate  * of threads currently calling gld_start() from wput() on this stream.
19737c478bd9Sstevel@tonic-gate  * If DL_DETACH sees this as nonzero, it putbqs the request back onto
19747c478bd9Sstevel@tonic-gate  * the queue and qenables, hoping to have better luck next time.  Since
19757c478bd9Sstevel@tonic-gate  * people shouldn't be trying to send after they've asked to DL_DETACH,
19767c478bd9Sstevel@tonic-gate  * hopefully very soon all the wput=>start threads should have returned
19777c478bd9Sstevel@tonic-gate  * and the DL_DETACH will succeed.  It's hard to test this since the odds
19787c478bd9Sstevel@tonic-gate  * of the failure even trying to happen are so small.  I probably could
19797c478bd9Sstevel@tonic-gate  * have ignored the whole issue and never been the worse for it.
19807c478bd9Sstevel@tonic-gate  */
19817c478bd9Sstevel@tonic-gate static int
19827c478bd9Sstevel@tonic-gate gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri)
19837c478bd9Sstevel@tonic-gate {
19847c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
19857c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
19867c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
19877c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
19887c478bd9Sstevel@tonic-gate 	int rc;
19897c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
19907c478bd9Sstevel@tonic-gate 	pktinfo_t pktinfo;
19917c478bd9Sstevel@tonic-gate 	uint32_t vtag;
19927c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
19937c478bd9Sstevel@tonic-gate 
19947c478bd9Sstevel@tonic-gate 	ASSERT(DB_TYPE(mp) == M_DATA);
19957c478bd9Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
19967c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
19977c478bd9Sstevel@tonic-gate 	ifp = mac_pvt->interfacep;
19987c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
19997c478bd9Sstevel@tonic-gate 
20007c478bd9Sstevel@tonic-gate 	if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_TX) != 0) {
20017c478bd9Sstevel@tonic-gate 		freemsg(mp);
20027c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
20037c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
20047c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
20057c478bd9Sstevel@tonic-gate 			    "gld_start: failed to interpret outbound packet");
20067c478bd9Sstevel@tonic-gate #endif
20077c478bd9Sstevel@tonic-gate 		vlan->gldv_stats->glds_xmtbadinterp++;
20087c478bd9Sstevel@tonic-gate 		return (GLD_BADARG);
20097c478bd9Sstevel@tonic-gate 	}
20107c478bd9Sstevel@tonic-gate 
20117c478bd9Sstevel@tonic-gate 	/*
20127c478bd9Sstevel@tonic-gate 	 * We're not holding the lock for this check.  If the promiscuous
20137c478bd9Sstevel@tonic-gate 	 * state is in flux it doesn't matter much if we get this wrong.
20147c478bd9Sstevel@tonic-gate 	 */
20157c478bd9Sstevel@tonic-gate 	if (mac_pvt->nprom > 0) {
20167c478bd9Sstevel@tonic-gate 		/*
20177c478bd9Sstevel@tonic-gate 		 * We want to loopback to the receive side, but to avoid
20187c478bd9Sstevel@tonic-gate 		 * recursive lock entry:  if we came from wput(), which
20197c478bd9Sstevel@tonic-gate 		 * could have looped back via IP from our own receive
20207c478bd9Sstevel@tonic-gate 		 * interrupt thread, we decline this request.  wput()
20217c478bd9Sstevel@tonic-gate 		 * will then queue the packet for wsrv().  This means
20227c478bd9Sstevel@tonic-gate 		 * that when snoop is running we don't get the advantage
20237c478bd9Sstevel@tonic-gate 		 * of the wput() multithreaded direct entry to the
20247c478bd9Sstevel@tonic-gate 		 * driver's send routine.
20257c478bd9Sstevel@tonic-gate 		 */
20267c478bd9Sstevel@tonic-gate 		if (caller == GLD_WPUT) {
20277c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
20287c478bd9Sstevel@tonic-gate 			return (GLD_NORESOURCES);
20297c478bd9Sstevel@tonic-gate 		}
20307c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_capabilities & GLD_CAP_ZEROCOPY)
20317c478bd9Sstevel@tonic-gate 			nmp = dupmsg_noloan(mp);
20327c478bd9Sstevel@tonic-gate 		else
20337c478bd9Sstevel@tonic-gate 			nmp = dupmsg(mp);
20347c478bd9Sstevel@tonic-gate 	} else
20357c478bd9Sstevel@tonic-gate 		nmp = NULL;		/* we need no loopback */
20367c478bd9Sstevel@tonic-gate 
20377c478bd9Sstevel@tonic-gate 	vtag = GLD_MK_VTAG(vlan->gldv_ptag, upri);
20387c478bd9Sstevel@tonic-gate 	if (ifp->hdr_size > 0 &&
20397c478bd9Sstevel@tonic-gate 	    pktinfo.pktLen > ifp->hdr_size + (vtag == 0 ? 0 : VTAG_SIZE) +
20407c478bd9Sstevel@tonic-gate 	    macinfo->gldm_maxpkt) {
20417c478bd9Sstevel@tonic-gate 		freemsg(mp);	/* discard oversized outbound packet */
20427c478bd9Sstevel@tonic-gate 		if (nmp)
20437c478bd9Sstevel@tonic-gate 			freemsg(nmp);	/* free the duped message */
20447c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
20457c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
20467c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
20477c478bd9Sstevel@tonic-gate 			    "gld_start: oversize outbound packet, size %d,"
20487c478bd9Sstevel@tonic-gate 			    "max %d", pktinfo.pktLen,
20497c478bd9Sstevel@tonic-gate 			    ifp->hdr_size + macinfo->gldm_maxpkt);
20507c478bd9Sstevel@tonic-gate #endif
20517c478bd9Sstevel@tonic-gate 		vlan->gldv_stats->glds_xmtbadinterp++;
20527c478bd9Sstevel@tonic-gate 		return (GLD_BADARG);
20537c478bd9Sstevel@tonic-gate 	}
20547c478bd9Sstevel@tonic-gate 
20557c478bd9Sstevel@tonic-gate 	rc = (*gld->gld_send)(macinfo, mp, vtag);
20567c478bd9Sstevel@tonic-gate 
20577c478bd9Sstevel@tonic-gate 	if (rc != GLD_SUCCESS) {
20587c478bd9Sstevel@tonic-gate 		if (rc == GLD_NORESOURCES) {
20597c478bd9Sstevel@tonic-gate 			vlan->gldv_stats->glds_xmtretry++;
20607c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
20617c478bd9Sstevel@tonic-gate 		} else {
20627c478bd9Sstevel@tonic-gate 			/* transmit error; drop the packet */
20637c478bd9Sstevel@tonic-gate 			freemsg(mp);
20647c478bd9Sstevel@tonic-gate 			/* We're supposed to count failed attempts as well */
20657c478bd9Sstevel@tonic-gate 			UPDATE_STATS(vlan, pktinfo, 1);
20667c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
20677c478bd9Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
20687c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
20697c478bd9Sstevel@tonic-gate 				    "gld_start: gldm_send failed %d", rc);
20707c478bd9Sstevel@tonic-gate #endif
20717c478bd9Sstevel@tonic-gate 		}
20727c478bd9Sstevel@tonic-gate 		if (nmp)
20737c478bd9Sstevel@tonic-gate 			freemsg(nmp);	/* free the dupped message */
20747c478bd9Sstevel@tonic-gate 		return (rc);
20757c478bd9Sstevel@tonic-gate 	}
20767c478bd9Sstevel@tonic-gate 
20777c478bd9Sstevel@tonic-gate 	UPDATE_STATS(vlan, pktinfo, 1);
20787c478bd9Sstevel@tonic-gate 
20797c478bd9Sstevel@tonic-gate 	/*
20807c478bd9Sstevel@tonic-gate 	 * Loopback case. The message needs to be returned back on
20817c478bd9Sstevel@tonic-gate 	 * the read side. This would silently fail if the dumpmsg fails
20827c478bd9Sstevel@tonic-gate 	 * above. This is probably OK, if there is no memory to dup the
20837c478bd9Sstevel@tonic-gate 	 * block, then there isn't much we could do anyway.
20847c478bd9Sstevel@tonic-gate 	 */
20857c478bd9Sstevel@tonic-gate 	if (nmp) {
20867c478bd9Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
20877c478bd9Sstevel@tonic-gate 		gld_precv(macinfo, vlan, nmp);
20887c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
20897c478bd9Sstevel@tonic-gate 	}
20907c478bd9Sstevel@tonic-gate 
20917c478bd9Sstevel@tonic-gate 	return (GLD_SUCCESS);
20927c478bd9Sstevel@tonic-gate }
20937c478bd9Sstevel@tonic-gate 
20947c478bd9Sstevel@tonic-gate /*
20957c478bd9Sstevel@tonic-gate  * With MDT V.2 a single message mp can have one header area and multiple
20967c478bd9Sstevel@tonic-gate  * payload areas. A packet is described by dl_pkt_info, and each packet can
20977c478bd9Sstevel@tonic-gate  * span multiple payload areas (currently with TCP, each packet will have one
20987c478bd9Sstevel@tonic-gate  * header and at the most two payload areas). MACs might have a limit on the
20997c478bd9Sstevel@tonic-gate  * number of payload segments (i.e. per packet scatter-gather limit), and
21007c478bd9Sstevel@tonic-gate  * MDT V.2 has a way of specifying that with mdt_span_limit; the MAC driver
21017c478bd9Sstevel@tonic-gate  * might also have a limit on the total number of payloads in a message, and
21027c478bd9Sstevel@tonic-gate  * that is specified by mdt_max_pld.
21037c478bd9Sstevel@tonic-gate  */
21047c478bd9Sstevel@tonic-gate static int
21057c478bd9Sstevel@tonic-gate gld_start_mdt(queue_t *q, mblk_t *mp, int caller)
21067c478bd9Sstevel@tonic-gate {
21077c478bd9Sstevel@tonic-gate 	mblk_t *nextmp;
21087c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
21097c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
21107c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
21117c478bd9Sstevel@tonic-gate 	int numpacks, mdtpacks;
21127c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp = mac_pvt->interfacep;
21137c478bd9Sstevel@tonic-gate 	pktinfo_t pktinfo;
21147c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan = (gld_vlan_t *)gld->gld_vlan;
21157c478bd9Sstevel@tonic-gate 	boolean_t doloop = B_FALSE;
21167c478bd9Sstevel@tonic-gate 	multidata_t *dlmdp;
21177c478bd9Sstevel@tonic-gate 	pdescinfo_t pinfo;
21187c478bd9Sstevel@tonic-gate 	pdesc_t *dl_pkt;
21197c478bd9Sstevel@tonic-gate 	void *cookie;
21207c478bd9Sstevel@tonic-gate 	uint_t totLen = 0;
21217c478bd9Sstevel@tonic-gate 
21227c478bd9Sstevel@tonic-gate 	ASSERT(DB_TYPE(mp) == M_MULTIDATA);
21237c478bd9Sstevel@tonic-gate 
21247c478bd9Sstevel@tonic-gate 	/*
21257c478bd9Sstevel@tonic-gate 	 * We're not holding the lock for this check.  If the promiscuous
21267c478bd9Sstevel@tonic-gate 	 * state is in flux it doesn't matter much if we get this wrong.
21277c478bd9Sstevel@tonic-gate 	 */
21287c478bd9Sstevel@tonic-gate 	if (mac_pvt->nprom > 0) {
21297c478bd9Sstevel@tonic-gate 		/*
21307c478bd9Sstevel@tonic-gate 		 * We want to loopback to the receive side, but to avoid
21317c478bd9Sstevel@tonic-gate 		 * recursive lock entry:  if we came from wput(), which
21327c478bd9Sstevel@tonic-gate 		 * could have looped back via IP from our own receive
21337c478bd9Sstevel@tonic-gate 		 * interrupt thread, we decline this request.  wput()
21347c478bd9Sstevel@tonic-gate 		 * will then queue the packet for wsrv().  This means
21357c478bd9Sstevel@tonic-gate 		 * that when snoop is running we don't get the advantage
21367c478bd9Sstevel@tonic-gate 		 * of the wput() multithreaded direct entry to the
21377c478bd9Sstevel@tonic-gate 		 * driver's send routine.
21387c478bd9Sstevel@tonic-gate 		 */
21397c478bd9Sstevel@tonic-gate 		if (caller == GLD_WPUT) {
21407c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
21417c478bd9Sstevel@tonic-gate 			return (GLD_NORESOURCES);
21427c478bd9Sstevel@tonic-gate 		}
21437c478bd9Sstevel@tonic-gate 		doloop = B_TRUE;
21447c478bd9Sstevel@tonic-gate 
21457c478bd9Sstevel@tonic-gate 		/*
21467c478bd9Sstevel@tonic-gate 		 * unlike the M_DATA case, we don't have to call
21477c478bd9Sstevel@tonic-gate 		 * dupmsg_noloan here because mmd_transform
21487c478bd9Sstevel@tonic-gate 		 * (called by gld_precv_mdt) will make a copy of
21497c478bd9Sstevel@tonic-gate 		 * each dblk.
21507c478bd9Sstevel@tonic-gate 		 */
21517c478bd9Sstevel@tonic-gate 	}
21527c478bd9Sstevel@tonic-gate 
21537c478bd9Sstevel@tonic-gate 	while (mp != NULL) {
21547c478bd9Sstevel@tonic-gate 		/*
21557c478bd9Sstevel@tonic-gate 		 * The lower layer driver only gets a single multidata
21567c478bd9Sstevel@tonic-gate 		 * message; this also makes it easier to handle noresources.
21577c478bd9Sstevel@tonic-gate 		 */
21587c478bd9Sstevel@tonic-gate 		nextmp = mp->b_cont;
21597c478bd9Sstevel@tonic-gate 		mp->b_cont = NULL;
21607c478bd9Sstevel@tonic-gate 
21617c478bd9Sstevel@tonic-gate 		/*
21627c478bd9Sstevel@tonic-gate 		 * Get number of packets in this message; if nothing
21637c478bd9Sstevel@tonic-gate 		 * to transmit, go to next message.
21647c478bd9Sstevel@tonic-gate 		 */
21657c478bd9Sstevel@tonic-gate 		dlmdp = mmd_getmultidata(mp);
21667c478bd9Sstevel@tonic-gate 		if ((mdtpacks = (int)mmd_getcnt(dlmdp, NULL, NULL)) == 0) {
21677c478bd9Sstevel@tonic-gate 			freemsg(mp);
21687c478bd9Sstevel@tonic-gate 			mp = nextmp;
21697c478bd9Sstevel@tonic-gate 			continue;
21707c478bd9Sstevel@tonic-gate 		}
21717c478bd9Sstevel@tonic-gate 
21727c478bd9Sstevel@tonic-gate 		/*
21737c478bd9Sstevel@tonic-gate 		 * Run interpreter to populate media specific pktinfo fields.
21747c478bd9Sstevel@tonic-gate 		 * This collects per MDT message information like sap,
21757c478bd9Sstevel@tonic-gate 		 * broad/multicast etc.
21767c478bd9Sstevel@tonic-gate 		 */
21777c478bd9Sstevel@tonic-gate 		(void) (*ifp->interpreter_mdt)(macinfo, mp, NULL, &pktinfo,
21787c478bd9Sstevel@tonic-gate 		    GLD_MDT_TX);
21797c478bd9Sstevel@tonic-gate 
21807c478bd9Sstevel@tonic-gate 		numpacks = (*macinfo->gldm_mdt_pre)(macinfo, mp, &cookie);
21817c478bd9Sstevel@tonic-gate 
21827c478bd9Sstevel@tonic-gate 		if (numpacks > 0) {
21837c478bd9Sstevel@tonic-gate 			/*
21847c478bd9Sstevel@tonic-gate 			 * Driver indicates it can transmit at least 1, and
21857c478bd9Sstevel@tonic-gate 			 * possibly all, packets in MDT message.
21867c478bd9Sstevel@tonic-gate 			 */
21877c478bd9Sstevel@tonic-gate 			int count = numpacks;
21887c478bd9Sstevel@tonic-gate 
21897c478bd9Sstevel@tonic-gate 			for (dl_pkt = mmd_getfirstpdesc(dlmdp, &pinfo);
21907c478bd9Sstevel@tonic-gate 			    (dl_pkt != NULL);
21917c478bd9Sstevel@tonic-gate 			    dl_pkt = mmd_getnextpdesc(dl_pkt, &pinfo)) {
21927c478bd9Sstevel@tonic-gate 				/*
21937c478bd9Sstevel@tonic-gate 				 * Format this packet by adding link header and
21947c478bd9Sstevel@tonic-gate 				 * adjusting pdescinfo to include it; get
21957c478bd9Sstevel@tonic-gate 				 * packet length.
21967c478bd9Sstevel@tonic-gate 				 */
21977c478bd9Sstevel@tonic-gate 				(void) (*ifp->interpreter_mdt)(macinfo, NULL,
21987c478bd9Sstevel@tonic-gate 				    &pinfo, &pktinfo, GLD_MDT_TXPKT);
21997c478bd9Sstevel@tonic-gate 
22007c478bd9Sstevel@tonic-gate 				totLen += pktinfo.pktLen;
22017c478bd9Sstevel@tonic-gate 
22027c478bd9Sstevel@tonic-gate 				/*
22037c478bd9Sstevel@tonic-gate 				 * Loop back packet before handing to the
22047c478bd9Sstevel@tonic-gate 				 * driver.
22057c478bd9Sstevel@tonic-gate 				 */
22067c478bd9Sstevel@tonic-gate 				if (doloop &&
22077c478bd9Sstevel@tonic-gate 				    mmd_adjpdesc(dl_pkt, &pinfo) != NULL) {
22087c478bd9Sstevel@tonic-gate 					GLDM_LOCK(macinfo, RW_WRITER);
22097c478bd9Sstevel@tonic-gate 					gld_precv_mdt(macinfo, vlan, mp,
22107c478bd9Sstevel@tonic-gate 					    dl_pkt, &pktinfo);
22117c478bd9Sstevel@tonic-gate 					GLDM_UNLOCK(macinfo);
22127c478bd9Sstevel@tonic-gate 				}
22137c478bd9Sstevel@tonic-gate 
22147c478bd9Sstevel@tonic-gate 				/*
22157c478bd9Sstevel@tonic-gate 				 * And send off to driver.
22167c478bd9Sstevel@tonic-gate 				 */
22177c478bd9Sstevel@tonic-gate 				(*macinfo->gldm_mdt_send)(macinfo, cookie,
22187c478bd9Sstevel@tonic-gate 				    &pinfo);
22197c478bd9Sstevel@tonic-gate 
22207c478bd9Sstevel@tonic-gate 				/*
22217c478bd9Sstevel@tonic-gate 				 * Be careful not to invoke getnextpdesc if we
22227c478bd9Sstevel@tonic-gate 				 * already sent the last packet, since driver
22237c478bd9Sstevel@tonic-gate 				 * might have posted it to hardware causing a
22247c478bd9Sstevel@tonic-gate 				 * completion and freemsg() so the MDT data
22257c478bd9Sstevel@tonic-gate 				 * structures might not be valid anymore.
22267c478bd9Sstevel@tonic-gate 				 */
22277c478bd9Sstevel@tonic-gate 				if (--count == 0)
22287c478bd9Sstevel@tonic-gate 					break;
22297c478bd9Sstevel@tonic-gate 			}
22307c478bd9Sstevel@tonic-gate 			(*macinfo->gldm_mdt_post)(macinfo, mp, cookie);
22317c478bd9Sstevel@tonic-gate 			pktinfo.pktLen = totLen;
22327c478bd9Sstevel@tonic-gate 			UPDATE_STATS(vlan, pktinfo, numpacks);
22337c478bd9Sstevel@tonic-gate 
22347c478bd9Sstevel@tonic-gate 			/*
22357c478bd9Sstevel@tonic-gate 			 * In the noresources case (when driver indicates it
22367c478bd9Sstevel@tonic-gate 			 * can not transmit all packets in the MDT message),
22377c478bd9Sstevel@tonic-gate 			 * adjust to skip the first few packets on retrial.
22387c478bd9Sstevel@tonic-gate 			 */
22397c478bd9Sstevel@tonic-gate 			if (numpacks != mdtpacks) {
22407c478bd9Sstevel@tonic-gate 				/*
22417c478bd9Sstevel@tonic-gate 				 * Release already processed packet descriptors.
22427c478bd9Sstevel@tonic-gate 				 */
22437c478bd9Sstevel@tonic-gate 				for (count = 0; count < numpacks; count++) {
22447c478bd9Sstevel@tonic-gate 					dl_pkt = mmd_getfirstpdesc(dlmdp,
22457c478bd9Sstevel@tonic-gate 					    &pinfo);
22467c478bd9Sstevel@tonic-gate 					mmd_rempdesc(dl_pkt);
22477c478bd9Sstevel@tonic-gate 				}
22487c478bd9Sstevel@tonic-gate 				vlan->gldv_stats->glds_xmtretry++;
22497c478bd9Sstevel@tonic-gate 				mp->b_cont = nextmp;
22507c478bd9Sstevel@tonic-gate 				(void) putbq(q, mp);
22517c478bd9Sstevel@tonic-gate 				return (GLD_NORESOURCES);
22527c478bd9Sstevel@tonic-gate 			}
22537c478bd9Sstevel@tonic-gate 		} else if (numpacks == 0) {
22547c478bd9Sstevel@tonic-gate 			/*
22557c478bd9Sstevel@tonic-gate 			 * Driver indicates it can not transmit any packets
22567c478bd9Sstevel@tonic-gate 			 * currently and will request retrial later.
22577c478bd9Sstevel@tonic-gate 			 */
22587c478bd9Sstevel@tonic-gate 			vlan->gldv_stats->glds_xmtretry++;
22597c478bd9Sstevel@tonic-gate 			mp->b_cont = nextmp;
22607c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
22617c478bd9Sstevel@tonic-gate 			return (GLD_NORESOURCES);
22627c478bd9Sstevel@tonic-gate 		} else {
22637c478bd9Sstevel@tonic-gate 			ASSERT(numpacks == -1);
22647c478bd9Sstevel@tonic-gate 			/*
22657c478bd9Sstevel@tonic-gate 			 * We're supposed to count failed attempts as well.
22667c478bd9Sstevel@tonic-gate 			 */
22677c478bd9Sstevel@tonic-gate 			dl_pkt = mmd_getfirstpdesc(dlmdp, &pinfo);
22687c478bd9Sstevel@tonic-gate 			while (dl_pkt != NULL) {
22697c478bd9Sstevel@tonic-gate 				/*
22707c478bd9Sstevel@tonic-gate 				 * Call interpreter to determine total packet
22717c478bd9Sstevel@tonic-gate 				 * bytes that are being dropped.
22727c478bd9Sstevel@tonic-gate 				 */
22737c478bd9Sstevel@tonic-gate 				(void) (*ifp->interpreter_mdt)(macinfo, NULL,
22747c478bd9Sstevel@tonic-gate 				    &pinfo, &pktinfo, GLD_MDT_TXPKT);
22757c478bd9Sstevel@tonic-gate 
22767c478bd9Sstevel@tonic-gate 				totLen += pktinfo.pktLen;
22777c478bd9Sstevel@tonic-gate 
22787c478bd9Sstevel@tonic-gate 				dl_pkt = mmd_getnextpdesc(dl_pkt, &pinfo);
22797c478bd9Sstevel@tonic-gate 			}
22807c478bd9Sstevel@tonic-gate 			pktinfo.pktLen = totLen;
22817c478bd9Sstevel@tonic-gate 			UPDATE_STATS(vlan, pktinfo, mdtpacks);
22827c478bd9Sstevel@tonic-gate 
22837c478bd9Sstevel@tonic-gate 			/*
22847c478bd9Sstevel@tonic-gate 			 * Transmit error; drop the message, move on
22857c478bd9Sstevel@tonic-gate 			 * to the next one.
22867c478bd9Sstevel@tonic-gate 			 */
22877c478bd9Sstevel@tonic-gate 			freemsg(mp);
22887c478bd9Sstevel@tonic-gate 		}
22897c478bd9Sstevel@tonic-gate 
22907c478bd9Sstevel@tonic-gate 		/*
22917c478bd9Sstevel@tonic-gate 		 * Process the next multidata block, if there is one.
22927c478bd9Sstevel@tonic-gate 		 */
22937c478bd9Sstevel@tonic-gate 		mp = nextmp;
22947c478bd9Sstevel@tonic-gate 	}
22957c478bd9Sstevel@tonic-gate 
22967c478bd9Sstevel@tonic-gate 	return (GLD_SUCCESS);
22977c478bd9Sstevel@tonic-gate }
22987c478bd9Sstevel@tonic-gate 
22997c478bd9Sstevel@tonic-gate /*
23007c478bd9Sstevel@tonic-gate  * gld_intr (macinfo)
23017c478bd9Sstevel@tonic-gate  */
23027c478bd9Sstevel@tonic-gate uint_t
23037c478bd9Sstevel@tonic-gate gld_intr(gld_mac_info_t *macinfo)
23047c478bd9Sstevel@tonic-gate {
23057c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
23067c478bd9Sstevel@tonic-gate 
23077c478bd9Sstevel@tonic-gate 	if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY))
23087c478bd9Sstevel@tonic-gate 		return (DDI_INTR_UNCLAIMED);
23097c478bd9Sstevel@tonic-gate 
23107c478bd9Sstevel@tonic-gate 	return ((*macinfo->gldm_intr)(macinfo));
23117c478bd9Sstevel@tonic-gate }
23127c478bd9Sstevel@tonic-gate 
23137c478bd9Sstevel@tonic-gate /*
23147c478bd9Sstevel@tonic-gate  * gld_sched (macinfo)
23157c478bd9Sstevel@tonic-gate  *
23167c478bd9Sstevel@tonic-gate  * This routine scans the streams that refer to a specific macinfo
23177c478bd9Sstevel@tonic-gate  * structure and causes the STREAMS scheduler to try to run them if
23187c478bd9Sstevel@tonic-gate  * they are marked as waiting for the transmit buffer.
23197c478bd9Sstevel@tonic-gate  */
23207c478bd9Sstevel@tonic-gate void
23217c478bd9Sstevel@tonic-gate gld_sched(gld_mac_info_t *macinfo)
23227c478bd9Sstevel@tonic-gate {
23237c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
23247c478bd9Sstevel@tonic-gate 	gld_t *gld;
23257c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
23267c478bd9Sstevel@tonic-gate 	int i;
23277c478bd9Sstevel@tonic-gate 
23287c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
23297c478bd9Sstevel@tonic-gate 
23307c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
23317c478bd9Sstevel@tonic-gate 
23327c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
23337c478bd9Sstevel@tonic-gate 		/* We're probably being called from a leftover interrupt */
23347c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
23357c478bd9Sstevel@tonic-gate 		return;
23367c478bd9Sstevel@tonic-gate 	}
23377c478bd9Sstevel@tonic-gate 
23387c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
23397c478bd9Sstevel@tonic-gate 
23407c478bd9Sstevel@tonic-gate 	for (i = 0; i < VLAN_HASHSZ; i++) {
23417c478bd9Sstevel@tonic-gate 		for (vlan = mac_pvt->vlan_hash[i];
23427c478bd9Sstevel@tonic-gate 		    vlan != NULL; vlan = vlan->gldv_next) {
23437c478bd9Sstevel@tonic-gate 			for (gld = vlan->gldv_str_next;
23447c478bd9Sstevel@tonic-gate 			    gld != (gld_t *)&vlan->gldv_str_next;
23457c478bd9Sstevel@tonic-gate 			    gld = gld->gld_next) {
23467c478bd9Sstevel@tonic-gate 				ASSERT(gld->gld_mac_info == macinfo);
23477c478bd9Sstevel@tonic-gate 				gld->gld_sched_ran = B_TRUE;
23487c478bd9Sstevel@tonic-gate 				membar_enter();
23497c478bd9Sstevel@tonic-gate 				if (gld->gld_xwait) {
23507c478bd9Sstevel@tonic-gate 					gld->gld_xwait = B_FALSE;
23517c478bd9Sstevel@tonic-gate 					qenable(WR(gld->gld_qptr));
23527c478bd9Sstevel@tonic-gate 				}
23537c478bd9Sstevel@tonic-gate 			}
23547c478bd9Sstevel@tonic-gate 		}
23557c478bd9Sstevel@tonic-gate 	}
23567c478bd9Sstevel@tonic-gate 
23577c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
23587c478bd9Sstevel@tonic-gate }
23597c478bd9Sstevel@tonic-gate 
23607c478bd9Sstevel@tonic-gate /*
23617c478bd9Sstevel@tonic-gate  * gld_precv (macinfo, mp)
23627c478bd9Sstevel@tonic-gate  * called from gld_start to loopback a packet when in promiscuous mode
23637c478bd9Sstevel@tonic-gate  */
23647c478bd9Sstevel@tonic-gate static void
23657c478bd9Sstevel@tonic-gate gld_precv(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp)
23667c478bd9Sstevel@tonic-gate {
23677c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
23687c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
23697c478bd9Sstevel@tonic-gate 	pktinfo_t pktinfo;
23707c478bd9Sstevel@tonic-gate 
23717c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
23727c478bd9Sstevel@tonic-gate 
23737c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
23747c478bd9Sstevel@tonic-gate 	ifp = mac_pvt->interfacep;
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate 	/*
23777c478bd9Sstevel@tonic-gate 	 * call the media specific packet interpreter routine
23787c478bd9Sstevel@tonic-gate 	 */
23797c478bd9Sstevel@tonic-gate 	if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RXLOOP) != 0) {
23807c478bd9Sstevel@tonic-gate 		freemsg(mp);
23817c478bd9Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_rcvbadinterp, 1);
23827c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
23837c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
23847c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
23857c478bd9Sstevel@tonic-gate 			    "gld_precv: interpreter failed");
23867c478bd9Sstevel@tonic-gate #endif
23877c478bd9Sstevel@tonic-gate 		return;
23887c478bd9Sstevel@tonic-gate 	}
23897c478bd9Sstevel@tonic-gate 
23907c478bd9Sstevel@tonic-gate 	gld_sendup(macinfo, vlan, &pktinfo, mp, gld_paccept);
23917c478bd9Sstevel@tonic-gate }
23927c478bd9Sstevel@tonic-gate 
23937c478bd9Sstevel@tonic-gate /*
23947c478bd9Sstevel@tonic-gate  * called from gld_start_mdt to loopback packet(s) when in promiscuous mode
23957c478bd9Sstevel@tonic-gate  */
23967c478bd9Sstevel@tonic-gate static void
23977c478bd9Sstevel@tonic-gate gld_precv_mdt(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp,
23987c478bd9Sstevel@tonic-gate     pdesc_t *dl_pkt, pktinfo_t *pktinfo)
23997c478bd9Sstevel@tonic-gate {
24007c478bd9Sstevel@tonic-gate 	mblk_t *adjmp;
24017c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
24027c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp = mac_pvt->interfacep;
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
24057c478bd9Sstevel@tonic-gate 
24067c478bd9Sstevel@tonic-gate 	/*
24077c478bd9Sstevel@tonic-gate 	 * Get source/destination.
24087c478bd9Sstevel@tonic-gate 	 */
24097c478bd9Sstevel@tonic-gate 	(void) (*ifp->interpreter_mdt)(macinfo, mp, NULL, pktinfo,
24107c478bd9Sstevel@tonic-gate 	    GLD_MDT_RXLOOP);
24117c478bd9Sstevel@tonic-gate 	if ((adjmp = mmd_transform(dl_pkt)) != NULL)
24127c478bd9Sstevel@tonic-gate 		gld_sendup(macinfo, vlan, pktinfo, adjmp, gld_paccept);
24137c478bd9Sstevel@tonic-gate }
24147c478bd9Sstevel@tonic-gate 
24157c478bd9Sstevel@tonic-gate /*
24167c478bd9Sstevel@tonic-gate  * gld_recv (macinfo, mp)
24177c478bd9Sstevel@tonic-gate  * called with an mac-level packet in a mblock; take the maclock,
24187c478bd9Sstevel@tonic-gate  * try the ip4q and ip6q hack, and otherwise call gld_sendup.
24197c478bd9Sstevel@tonic-gate  *
24207c478bd9Sstevel@tonic-gate  * V0 drivers already are holding the mutex when they call us.
24217c478bd9Sstevel@tonic-gate  */
24227c478bd9Sstevel@tonic-gate void
24237c478bd9Sstevel@tonic-gate gld_recv(gld_mac_info_t *macinfo, mblk_t *mp)
24247c478bd9Sstevel@tonic-gate {
24257c478bd9Sstevel@tonic-gate 	gld_recv_tagged(macinfo, mp, VLAN_VTAG_NONE);
24267c478bd9Sstevel@tonic-gate }
24277c478bd9Sstevel@tonic-gate 
24287c478bd9Sstevel@tonic-gate void
24297c478bd9Sstevel@tonic-gate gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
24307c478bd9Sstevel@tonic-gate {
24317c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
24327c478bd9Sstevel@tonic-gate 	char pbuf[3*GLD_MAX_ADDRLEN];
24337c478bd9Sstevel@tonic-gate 	pktinfo_t pktinfo;
24347c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
24357c478bd9Sstevel@tonic-gate 	queue_t *ipq = NULL;
24367c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
24377c478bd9Sstevel@tonic-gate 	uint32_t vid;
24387c478bd9Sstevel@tonic-gate 
24397c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
24407c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_ref);
24417c478bd9Sstevel@tonic-gate 
24427c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_READER);
24437c478bd9Sstevel@tonic-gate 
24447c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
24457c478bd9Sstevel@tonic-gate 		/* We're probably being called from a leftover interrupt */
24467c478bd9Sstevel@tonic-gate 		freemsg(mp);
24477c478bd9Sstevel@tonic-gate 		goto done;
24487c478bd9Sstevel@tonic-gate 	}
24497c478bd9Sstevel@tonic-gate 
24507c478bd9Sstevel@tonic-gate 	vid = GLD_VTAG_VID(vtag);
24517c478bd9Sstevel@tonic-gate 	if ((vlan = gld_find_vlan(macinfo, vid)) == NULL) {
24527c478bd9Sstevel@tonic-gate 		freemsg(mp);
24537c478bd9Sstevel@tonic-gate 		goto done;
24547c478bd9Sstevel@tonic-gate 	}
24557c478bd9Sstevel@tonic-gate 
24567c478bd9Sstevel@tonic-gate 	/*
24577c478bd9Sstevel@tonic-gate 	 * Check whether underlying media code supports the IPQ hack,
24587c478bd9Sstevel@tonic-gate 	 * and if so, whether the interpreter can quickly parse the
24597c478bd9Sstevel@tonic-gate 	 * packet to get some relevant parameters.
24607c478bd9Sstevel@tonic-gate 	 */
24617c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
24627c478bd9Sstevel@tonic-gate 	ifp = mac_pvt->interfacep;
24637c478bd9Sstevel@tonic-gate 	if (((*ifp->interpreter)(macinfo, mp, &pktinfo,
24647c478bd9Sstevel@tonic-gate 	    GLD_RXQUICK) == 0) && (vlan->gldv_ipq_flags == 0)) {
24657c478bd9Sstevel@tonic-gate 		switch (pktinfo.ethertype) {
24667c478bd9Sstevel@tonic-gate 		case ETHERTYPE_IP:
24677c478bd9Sstevel@tonic-gate 			ipq = vlan->gldv_ipq;
24687c478bd9Sstevel@tonic-gate 			break;
24697c478bd9Sstevel@tonic-gate 		case ETHERTYPE_IPV6:
24707c478bd9Sstevel@tonic-gate 			ipq = vlan->gldv_ipv6q;
24717c478bd9Sstevel@tonic-gate 			break;
24727c478bd9Sstevel@tonic-gate 		}
24737c478bd9Sstevel@tonic-gate 	}
24747c478bd9Sstevel@tonic-gate 
24757c478bd9Sstevel@tonic-gate 	BUMP(vlan->gldv_stats->glds_bytercv64, pktinfo.pktLen);
24767c478bd9Sstevel@tonic-gate 	BUMP(vlan->gldv_stats->glds_pktrcv64, 1);
24777c478bd9Sstevel@tonic-gate 
24787c478bd9Sstevel@tonic-gate 	/*
24797c478bd9Sstevel@tonic-gate 	 * Special case for IP; we can simply do the putnext here, if:
24807c478bd9Sstevel@tonic-gate 	 * o ipq != NULL, and therefore:
24817c478bd9Sstevel@tonic-gate 	 * - the device type supports IPQ (ethernet and IPoIB);
24827c478bd9Sstevel@tonic-gate 	 * - the interpreter could quickly parse the packet;
24837c478bd9Sstevel@tonic-gate 	 * - there are no PROMISC_SAP streams (on this VLAN);
24847c478bd9Sstevel@tonic-gate 	 * - there is one, and only one, IP stream bound (to this VLAN);
24857c478bd9Sstevel@tonic-gate 	 * - that stream is a "fastpath" stream;
24867c478bd9Sstevel@tonic-gate 	 * - the packet is of type ETHERTYPE_IP or ETHERTYPE_IPV6
24877c478bd9Sstevel@tonic-gate 	 *
24887c478bd9Sstevel@tonic-gate 	 * o the packet is specifically for me, and therefore:
24897c478bd9Sstevel@tonic-gate 	 * - the packet is not multicast or broadcast (fastpath only
24907c478bd9Sstevel@tonic-gate 	 *   wants unicast packets).
24917c478bd9Sstevel@tonic-gate 	 *
24927c478bd9Sstevel@tonic-gate 	 * o the stream is not asserting flow control.
24937c478bd9Sstevel@tonic-gate 	 */
24947c478bd9Sstevel@tonic-gate 	if (ipq != NULL &&
24957c478bd9Sstevel@tonic-gate 	    pktinfo.isForMe &&
24967c478bd9Sstevel@tonic-gate 	    canputnext(ipq)) {
24977c478bd9Sstevel@tonic-gate 		/*
24987c478bd9Sstevel@tonic-gate 		 * Skip the mac header. We know there is no LLC1/SNAP header
24997c478bd9Sstevel@tonic-gate 		 * in this packet
25007c478bd9Sstevel@tonic-gate 		 */
25017c478bd9Sstevel@tonic-gate 		mp->b_rptr += pktinfo.macLen;
25027c478bd9Sstevel@tonic-gate 		putnext(ipq, mp);
25037c478bd9Sstevel@tonic-gate 		goto done;
25047c478bd9Sstevel@tonic-gate 	}
25057c478bd9Sstevel@tonic-gate 
25067c478bd9Sstevel@tonic-gate 	/*
25077c478bd9Sstevel@tonic-gate 	 * call the media specific packet interpreter routine
25087c478bd9Sstevel@tonic-gate 	 */
25097c478bd9Sstevel@tonic-gate 	if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RX) != 0) {
25107c478bd9Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_rcvbadinterp, 1);
25117c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
25127c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
25137c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
25147c478bd9Sstevel@tonic-gate 			    "gld_recv_tagged: interpreter failed");
25157c478bd9Sstevel@tonic-gate #endif
25167c478bd9Sstevel@tonic-gate 		freemsg(mp);
25177c478bd9Sstevel@tonic-gate 		goto done;
25187c478bd9Sstevel@tonic-gate 	}
25197c478bd9Sstevel@tonic-gate 
25207c478bd9Sstevel@tonic-gate 	/*
25217c478bd9Sstevel@tonic-gate 	 * This is safe even if vtag is VLAN_VTAG_NONE
25227c478bd9Sstevel@tonic-gate 	 */
25237c478bd9Sstevel@tonic-gate 
25247c478bd9Sstevel@tonic-gate 	pktinfo.vid = vid;
25257c478bd9Sstevel@tonic-gate 	pktinfo.cfi = GLD_VTAG_CFI(vtag);
25267c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
25277c478bd9Sstevel@tonic-gate 	if (pktinfo.cfi != VLAN_CFI_ETHER)
25287c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "gld_recv_tagged: non-ETHER CFI");
25297c478bd9Sstevel@tonic-gate #endif
25307c478bd9Sstevel@tonic-gate 	pktinfo.user_pri = GLD_VTAG_PRI(vtag);
25317c478bd9Sstevel@tonic-gate 
25327c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
25337c478bd9Sstevel@tonic-gate 	if ((gld_debug & GLDRECV) &&
25347c478bd9Sstevel@tonic-gate 	    (!(gld_debug & GLDNOBR) ||
25357c478bd9Sstevel@tonic-gate 	    (!pktinfo.isBroadcast && !pktinfo.isMulticast))) {
25367c478bd9Sstevel@tonic-gate 		char pbuf2[3*GLD_MAX_ADDRLEN];
25377c478bd9Sstevel@tonic-gate 
25387c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "gld_recv_tagged: machdr=<%s -> %s>\n",
25397c478bd9Sstevel@tonic-gate 		    gld_macaddr_sprintf(pbuf, pktinfo.shost,
25407c478bd9Sstevel@tonic-gate 		    macinfo->gldm_addrlen), gld_macaddr_sprintf(pbuf2,
25417c478bd9Sstevel@tonic-gate 		    pktinfo.dhost, macinfo->gldm_addrlen));
25427c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "gld_recv_tagged: VlanId %d UserPri %d\n",
25437c478bd9Sstevel@tonic-gate 		    pktinfo.vid,
25447c478bd9Sstevel@tonic-gate 		    pktinfo.user_pri);
25457c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "gld_recv_tagged: ethertype: %4x Len: %4d "
25467c478bd9Sstevel@tonic-gate 		    "Hdr: %d,%d isMulticast: %s\n",
25477c478bd9Sstevel@tonic-gate 		    pktinfo.ethertype,
25487c478bd9Sstevel@tonic-gate 		    pktinfo.pktLen,
25497c478bd9Sstevel@tonic-gate 		    pktinfo.macLen,
25507c478bd9Sstevel@tonic-gate 		    pktinfo.hdrLen,
25517c478bd9Sstevel@tonic-gate 		    pktinfo.isMulticast ? "Y" : "N");
25527c478bd9Sstevel@tonic-gate 	}
25537c478bd9Sstevel@tonic-gate #endif
25547c478bd9Sstevel@tonic-gate 
25557c478bd9Sstevel@tonic-gate 	gld_sendup(macinfo, vlan, &pktinfo, mp, gld_accept);
25567c478bd9Sstevel@tonic-gate 
25577c478bd9Sstevel@tonic-gate done:
25587c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
25597c478bd9Sstevel@tonic-gate }
25607c478bd9Sstevel@tonic-gate 
25617c478bd9Sstevel@tonic-gate /* =================================================================== */
25627c478bd9Sstevel@tonic-gate /* receive group: called from gld_recv and gld_precv* with maclock held */
25637c478bd9Sstevel@tonic-gate /* =================================================================== */
25647c478bd9Sstevel@tonic-gate 
25657c478bd9Sstevel@tonic-gate /*
25667c478bd9Sstevel@tonic-gate  * gld_sendup (macinfo, mp)
25677c478bd9Sstevel@tonic-gate  * called with an ethernet packet in a mblock; must decide whether
25687c478bd9Sstevel@tonic-gate  * packet is for us and which streams to queue it to.
25697c478bd9Sstevel@tonic-gate  */
25707c478bd9Sstevel@tonic-gate static void
25717c478bd9Sstevel@tonic-gate gld_sendup(gld_mac_info_t *macinfo, gld_vlan_t *vlan, pktinfo_t *pktinfo,
25727c478bd9Sstevel@tonic-gate     mblk_t *mp, int (*acceptfunc)())
25737c478bd9Sstevel@tonic-gate {
25747c478bd9Sstevel@tonic-gate 	gld_t *gld;
25757c478bd9Sstevel@tonic-gate 	gld_t *fgld = NULL;
25767c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
25777c478bd9Sstevel@tonic-gate 	void (*send)(queue_t *qp, mblk_t *mp);
25787c478bd9Sstevel@tonic-gate 	int (*cansend)(queue_t *qp);
25797c478bd9Sstevel@tonic-gate 
25807c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
25817c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
25827c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_sendup(%p, %p)", (void *)mp,
25837c478bd9Sstevel@tonic-gate 		    (void *)macinfo);
25847c478bd9Sstevel@tonic-gate #endif
25857c478bd9Sstevel@tonic-gate 
25867c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
25877c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
25887c478bd9Sstevel@tonic-gate 	ASSERT(vlan != NULL);
25897c478bd9Sstevel@tonic-gate 	ASSERT(pktinfo != NULL);
25907c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(macinfo));
25917c478bd9Sstevel@tonic-gate 
25927c478bd9Sstevel@tonic-gate 	/*
25937c478bd9Sstevel@tonic-gate 	 * The "fast" in "GLDOPT_FAST_RECV" refers to the speed at which
25947c478bd9Sstevel@tonic-gate 	 * gld_recv returns to the caller's interrupt routine.  The total
25957c478bd9Sstevel@tonic-gate 	 * network throughput would normally be lower when selecting this
25967c478bd9Sstevel@tonic-gate 	 * option, because we putq the messages and process them later,
25977c478bd9Sstevel@tonic-gate 	 * instead of sending them with putnext now.  Some time critical
25987c478bd9Sstevel@tonic-gate 	 * device might need this, so it's here but undocumented.
25997c478bd9Sstevel@tonic-gate 	 */
26007c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_options & GLDOPT_FAST_RECV) {
26017c478bd9Sstevel@tonic-gate 		send = (void (*)(queue_t *, mblk_t *))putq;
26027c478bd9Sstevel@tonic-gate 		cansend = canput;
26037c478bd9Sstevel@tonic-gate 	} else {
26047c478bd9Sstevel@tonic-gate 		send = (void (*)(queue_t *, mblk_t *))putnext;
26057c478bd9Sstevel@tonic-gate 		cansend = canputnext;
26067c478bd9Sstevel@tonic-gate 	}
26077c478bd9Sstevel@tonic-gate 
26087c478bd9Sstevel@tonic-gate 	/*
26097c478bd9Sstevel@tonic-gate 	 * Search all the streams attached to this macinfo looking for
26107c478bd9Sstevel@tonic-gate 	 * those eligible to receive the present packet.
26117c478bd9Sstevel@tonic-gate 	 */
26127c478bd9Sstevel@tonic-gate 	for (gld = vlan->gldv_str_next;
26137c478bd9Sstevel@tonic-gate 	    gld != (gld_t *)&vlan->gldv_str_next; gld = gld->gld_next) {
26147c478bd9Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
26157c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_sendup: SAP: %4x QPTR: %p QSTATE: %s",
26167c478bd9Sstevel@tonic-gate 		    gld->gld_sap, (void *)gld->gld_qptr,
26177c478bd9Sstevel@tonic-gate 		    gld->gld_state == DL_IDLE ? "IDLE": "NOT IDLE");
26187c478bd9Sstevel@tonic-gate #endif
26197c478bd9Sstevel@tonic-gate 		ASSERT(gld->gld_qptr != NULL);
26207c478bd9Sstevel@tonic-gate 		ASSERT(gld->gld_state == DL_IDLE ||
26217c478bd9Sstevel@tonic-gate 		    gld->gld_state == DL_UNBOUND);
26227c478bd9Sstevel@tonic-gate 		ASSERT(gld->gld_mac_info == macinfo);
26237c478bd9Sstevel@tonic-gate 		ASSERT(gld->gld_vlan == vlan);
26247c478bd9Sstevel@tonic-gate 
26257c478bd9Sstevel@tonic-gate 		if (gld->gld_state != DL_IDLE)
26267c478bd9Sstevel@tonic-gate 			continue;	/* not eligible to receive */
26277c478bd9Sstevel@tonic-gate 		if (gld->gld_flags & GLD_STR_CLOSING)
26287c478bd9Sstevel@tonic-gate 			continue;	/* not eligible to receive */
26297c478bd9Sstevel@tonic-gate 
26307c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
26317c478bd9Sstevel@tonic-gate 		if ((gld_debug & GLDRECV) &&
26327c478bd9Sstevel@tonic-gate 		    (!(gld_debug & GLDNOBR) ||
26337c478bd9Sstevel@tonic-gate 		    (!pktinfo->isBroadcast && !pktinfo->isMulticast)))
26347c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
26357c478bd9Sstevel@tonic-gate 			    "gld_sendup: queue sap: %4x promis: %s %s %s",
26367c478bd9Sstevel@tonic-gate 			    gld->gld_sap,
26377c478bd9Sstevel@tonic-gate 			    gld->gld_flags & GLD_PROM_PHYS ? "phys " : "     ",
26387c478bd9Sstevel@tonic-gate 			    gld->gld_flags & GLD_PROM_SAP  ? "sap  " : "     ",
26397c478bd9Sstevel@tonic-gate 			    gld->gld_flags & GLD_PROM_MULT ? "multi" : "     ");
26407c478bd9Sstevel@tonic-gate #endif
26417c478bd9Sstevel@tonic-gate 
26427c478bd9Sstevel@tonic-gate 		/*
26437c478bd9Sstevel@tonic-gate 		 * The accept function differs depending on whether this is
26447c478bd9Sstevel@tonic-gate 		 * a packet that we received from the wire or a loopback.
26457c478bd9Sstevel@tonic-gate 		 */
26467c478bd9Sstevel@tonic-gate 		if ((*acceptfunc)(gld, pktinfo)) {
26477c478bd9Sstevel@tonic-gate 			/* sap matches */
26487c478bd9Sstevel@tonic-gate 			pktinfo->wasAccepted = 1;	/* known protocol */
26497c478bd9Sstevel@tonic-gate 
26507c478bd9Sstevel@tonic-gate 			if (!(*cansend)(gld->gld_qptr)) {
26517c478bd9Sstevel@tonic-gate 				/*
26527c478bd9Sstevel@tonic-gate 				 * Upper stream is not accepting messages, i.e.
26537c478bd9Sstevel@tonic-gate 				 * it is flow controlled, therefore we will
26547c478bd9Sstevel@tonic-gate 				 * forgo sending the message up this stream.
26557c478bd9Sstevel@tonic-gate 				 */
26567c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
26577c478bd9Sstevel@tonic-gate 				if (gld_debug & GLDETRACE)
26587c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
26597c478bd9Sstevel@tonic-gate 					    "gld_sendup: canput failed");
26607c478bd9Sstevel@tonic-gate #endif
26617c478bd9Sstevel@tonic-gate 				BUMP(vlan->gldv_stats->glds_blocked, 1);
26627c478bd9Sstevel@tonic-gate 				qenable(gld->gld_qptr);
26637c478bd9Sstevel@tonic-gate 				continue;
26647c478bd9Sstevel@tonic-gate 			}
26657c478bd9Sstevel@tonic-gate 
26667c478bd9Sstevel@tonic-gate 			/*
26677c478bd9Sstevel@tonic-gate 			 * we are trying to avoid an extra dumpmsg() here.
26687c478bd9Sstevel@tonic-gate 			 * If this is the first eligible queue, remember the
26697c478bd9Sstevel@tonic-gate 			 * queue and send up the message after the loop.
26707c478bd9Sstevel@tonic-gate 			 */
26717c478bd9Sstevel@tonic-gate 			if (!fgld) {
26727c478bd9Sstevel@tonic-gate 				fgld = gld;
26737c478bd9Sstevel@tonic-gate 				continue;
26747c478bd9Sstevel@tonic-gate 			}
26757c478bd9Sstevel@tonic-gate 
26767c478bd9Sstevel@tonic-gate 			/* duplicate the packet for this stream */
26777c478bd9Sstevel@tonic-gate 			nmp = dupmsg(mp);
26787c478bd9Sstevel@tonic-gate 			if (nmp == NULL) {
26797c478bd9Sstevel@tonic-gate 				BUMP(vlan->gldv_stats->glds_gldnorcvbuf, 1);
26807c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
26817c478bd9Sstevel@tonic-gate 				if (gld_debug & GLDERRS)
26827c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
26837c478bd9Sstevel@tonic-gate 					    "gld_sendup: dupmsg failed");
26847c478bd9Sstevel@tonic-gate #endif
26857c478bd9Sstevel@tonic-gate 				break;	/* couldn't get resources; drop it */
26867c478bd9Sstevel@tonic-gate 			}
26877c478bd9Sstevel@tonic-gate 			/* pass the message up the stream */
26887c478bd9Sstevel@tonic-gate 			gld_passon(gld, nmp, pktinfo, send);
26897c478bd9Sstevel@tonic-gate 		}
26907c478bd9Sstevel@tonic-gate 	}
26917c478bd9Sstevel@tonic-gate 
26927c478bd9Sstevel@tonic-gate 	ASSERT(mp);
26937c478bd9Sstevel@tonic-gate 	/* send the original dup of the packet up the first stream found */
26947c478bd9Sstevel@tonic-gate 	if (fgld)
26957c478bd9Sstevel@tonic-gate 		gld_passon(fgld, mp, pktinfo, send);
26967c478bd9Sstevel@tonic-gate 	else
26977c478bd9Sstevel@tonic-gate 		freemsg(mp);	/* no streams matched */
26987c478bd9Sstevel@tonic-gate 
26997c478bd9Sstevel@tonic-gate 	/* We do not count looped back packets */
27007c478bd9Sstevel@tonic-gate 	if (acceptfunc == gld_paccept)
27017c478bd9Sstevel@tonic-gate 		return;		/* transmit loopback case */
27027c478bd9Sstevel@tonic-gate 
27037c478bd9Sstevel@tonic-gate 	if (pktinfo->isBroadcast)
27047c478bd9Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_brdcstrcv, 1);
27057c478bd9Sstevel@tonic-gate 	else if (pktinfo->isMulticast)
27067c478bd9Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_multircv, 1);
27077c478bd9Sstevel@tonic-gate 
27087c478bd9Sstevel@tonic-gate 	/* No stream accepted this packet */
27097c478bd9Sstevel@tonic-gate 	if (!pktinfo->wasAccepted)
27107c478bd9Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_unknowns, 1);
27117c478bd9Sstevel@tonic-gate }
27127c478bd9Sstevel@tonic-gate 
27137c478bd9Sstevel@tonic-gate /*
27147c478bd9Sstevel@tonic-gate  * A packet matches a stream if:
27157c478bd9Sstevel@tonic-gate  *     the stream accepts EtherType encoded packets and the type matches
27167c478bd9Sstevel@tonic-gate  *  or the stream accepts LLC packets and the packet is an LLC packet
27177c478bd9Sstevel@tonic-gate  */
27187c478bd9Sstevel@tonic-gate #define	MATCH(stream, pktinfo) \
27197c478bd9Sstevel@tonic-gate 	((stream->gld_ethertype && stream->gld_sap == pktinfo->ethertype) || \
27207c478bd9Sstevel@tonic-gate 	(!stream->gld_ethertype && pktinfo->isLLC))
27217c478bd9Sstevel@tonic-gate 
27227c478bd9Sstevel@tonic-gate /*
27237c478bd9Sstevel@tonic-gate  * This function validates a packet for sending up a particular
27247c478bd9Sstevel@tonic-gate  * stream. The message header has been parsed and its characteristic
27257c478bd9Sstevel@tonic-gate  * are recorded in the pktinfo data structure. The streams stack info
27267c478bd9Sstevel@tonic-gate  * are presented in gld data structures.
27277c478bd9Sstevel@tonic-gate  */
27287c478bd9Sstevel@tonic-gate static int
27297c478bd9Sstevel@tonic-gate gld_accept(gld_t *gld, pktinfo_t *pktinfo)
27307c478bd9Sstevel@tonic-gate {
27317c478bd9Sstevel@tonic-gate 	/*
27327c478bd9Sstevel@tonic-gate 	 * if there is no match do not bother checking further.
27337c478bd9Sstevel@tonic-gate 	 */
27347c478bd9Sstevel@tonic-gate 	if (!MATCH(gld, pktinfo) && !(gld->gld_flags & GLD_PROM_SAP))
27357c478bd9Sstevel@tonic-gate 		return (0);
27367c478bd9Sstevel@tonic-gate 
27377c478bd9Sstevel@tonic-gate 	/*
27387c478bd9Sstevel@tonic-gate 	 * We don't accept any packet from the hardware if we originated it.
27397c478bd9Sstevel@tonic-gate 	 * (Contrast gld_paccept, the send-loopback accept function.)
27407c478bd9Sstevel@tonic-gate 	 */
27417c478bd9Sstevel@tonic-gate 	if (pktinfo->isLooped)
27427c478bd9Sstevel@tonic-gate 		return (0);
27437c478bd9Sstevel@tonic-gate 
27447c478bd9Sstevel@tonic-gate 	/*
27457c478bd9Sstevel@tonic-gate 	 * If the packet is broadcast or sent to us directly we will accept it.
27467c478bd9Sstevel@tonic-gate 	 * Also we will accept multicast packets requested by the stream.
27477c478bd9Sstevel@tonic-gate 	 */
27487c478bd9Sstevel@tonic-gate 	if (pktinfo->isForMe || pktinfo->isBroadcast ||
27497c478bd9Sstevel@tonic-gate 	    gld_mcmatch(gld, pktinfo))
27507c478bd9Sstevel@tonic-gate 		return (1);
27517c478bd9Sstevel@tonic-gate 
27527c478bd9Sstevel@tonic-gate 	/*
27537c478bd9Sstevel@tonic-gate 	 * Finally, accept anything else if we're in promiscuous mode
27547c478bd9Sstevel@tonic-gate 	 */
27557c478bd9Sstevel@tonic-gate 	if (gld->gld_flags & GLD_PROM_PHYS)
27567c478bd9Sstevel@tonic-gate 		return (1);
27577c478bd9Sstevel@tonic-gate 
27587c478bd9Sstevel@tonic-gate 	return (0);
27597c478bd9Sstevel@tonic-gate }
27607c478bd9Sstevel@tonic-gate 
27617c478bd9Sstevel@tonic-gate /*
27627c478bd9Sstevel@tonic-gate  * Return TRUE if the given multicast address is one
27637c478bd9Sstevel@tonic-gate  * of those that this particular Stream is interested in.
27647c478bd9Sstevel@tonic-gate  */
27657c478bd9Sstevel@tonic-gate static int
27667c478bd9Sstevel@tonic-gate gld_mcmatch(gld_t *gld, pktinfo_t *pktinfo)
27677c478bd9Sstevel@tonic-gate {
27687c478bd9Sstevel@tonic-gate 	/*
27697c478bd9Sstevel@tonic-gate 	 * Return FALSE if not a multicast address.
27707c478bd9Sstevel@tonic-gate 	 */
27717c478bd9Sstevel@tonic-gate 	if (!pktinfo->isMulticast)
27727c478bd9Sstevel@tonic-gate 		return (0);
27737c478bd9Sstevel@tonic-gate 
27747c478bd9Sstevel@tonic-gate 	/*
27757c478bd9Sstevel@tonic-gate 	 * Check if all multicasts have been enabled for this Stream
27767c478bd9Sstevel@tonic-gate 	 */
27777c478bd9Sstevel@tonic-gate 	if (gld->gld_flags & GLD_PROM_MULT)
27787c478bd9Sstevel@tonic-gate 		return (1);
27797c478bd9Sstevel@tonic-gate 
27807c478bd9Sstevel@tonic-gate 	/*
27817c478bd9Sstevel@tonic-gate 	 * Return FALSE if no multicast addresses enabled for this Stream.
27827c478bd9Sstevel@tonic-gate 	 */
27837c478bd9Sstevel@tonic-gate 	if (!gld->gld_mcast)
27847c478bd9Sstevel@tonic-gate 		return (0);
27857c478bd9Sstevel@tonic-gate 
27867c478bd9Sstevel@tonic-gate 	/*
27877c478bd9Sstevel@tonic-gate 	 * Otherwise, look for it in the table.
27887c478bd9Sstevel@tonic-gate 	 */
27897c478bd9Sstevel@tonic-gate 	return (gld_multicast(pktinfo->dhost, gld));
27907c478bd9Sstevel@tonic-gate }
27917c478bd9Sstevel@tonic-gate 
27927c478bd9Sstevel@tonic-gate /*
27937c478bd9Sstevel@tonic-gate  * gld_multicast determines if the address is a multicast address for
27947c478bd9Sstevel@tonic-gate  * this stream.
27957c478bd9Sstevel@tonic-gate  */
27967c478bd9Sstevel@tonic-gate static int
27977c478bd9Sstevel@tonic-gate gld_multicast(unsigned char *macaddr, gld_t *gld)
27987c478bd9Sstevel@tonic-gate {
27997c478bd9Sstevel@tonic-gate 	int i;
28007c478bd9Sstevel@tonic-gate 
28017c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(gld->gld_mac_info));
28027c478bd9Sstevel@tonic-gate 
28037c478bd9Sstevel@tonic-gate 	if (!gld->gld_mcast)
28047c478bd9Sstevel@tonic-gate 		return (0);
28057c478bd9Sstevel@tonic-gate 
28067c478bd9Sstevel@tonic-gate 	for (i = 0; i < gld->gld_multicnt; i++) {
28077c478bd9Sstevel@tonic-gate 		if (gld->gld_mcast[i]) {
28087c478bd9Sstevel@tonic-gate 			ASSERT(gld->gld_mcast[i]->gldm_refcnt);
28097c478bd9Sstevel@tonic-gate 			if (mac_eq(gld->gld_mcast[i]->gldm_addr, macaddr,
28107c478bd9Sstevel@tonic-gate 			    gld->gld_mac_info->gldm_addrlen))
28117c478bd9Sstevel@tonic-gate 				return (1);
28127c478bd9Sstevel@tonic-gate 		}
28137c478bd9Sstevel@tonic-gate 	}
28147c478bd9Sstevel@tonic-gate 
28157c478bd9Sstevel@tonic-gate 	return (0);
28167c478bd9Sstevel@tonic-gate }
28177c478bd9Sstevel@tonic-gate 
28187c478bd9Sstevel@tonic-gate /*
28197c478bd9Sstevel@tonic-gate  * accept function for looped back packets
28207c478bd9Sstevel@tonic-gate  */
28217c478bd9Sstevel@tonic-gate static int
28227c478bd9Sstevel@tonic-gate gld_paccept(gld_t *gld, pktinfo_t *pktinfo)
28237c478bd9Sstevel@tonic-gate {
28247c478bd9Sstevel@tonic-gate 	return (gld->gld_flags & GLD_PROM_PHYS &&
28257c478bd9Sstevel@tonic-gate 	    (MATCH(gld, pktinfo) || gld->gld_flags & GLD_PROM_SAP));
28267c478bd9Sstevel@tonic-gate }
28277c478bd9Sstevel@tonic-gate 
28287c478bd9Sstevel@tonic-gate static void
28297c478bd9Sstevel@tonic-gate gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo,
28307c478bd9Sstevel@tonic-gate 	void (*send)(queue_t *qp, mblk_t *mp))
28317c478bd9Sstevel@tonic-gate {
28327c478bd9Sstevel@tonic-gate 	int skiplen;
28337c478bd9Sstevel@tonic-gate 
28347c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
28357c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
28367c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_passon(%p, %p, %p)", (void *)gld,
28377c478bd9Sstevel@tonic-gate 		    (void *)mp, (void *)pktinfo);
28387c478bd9Sstevel@tonic-gate 
28397c478bd9Sstevel@tonic-gate 	if ((gld_debug & GLDRECV) && (!(gld_debug & GLDNOBR) ||
28407c478bd9Sstevel@tonic-gate 	    (!pktinfo->isBroadcast && !pktinfo->isMulticast)))
28417c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_passon: q: %p mblk: %p minor: %d sap: %x",
28427c478bd9Sstevel@tonic-gate 		    (void *)gld->gld_qptr->q_next, (void *)mp, gld->gld_minor,
28437c478bd9Sstevel@tonic-gate 		    gld->gld_sap);
28447c478bd9Sstevel@tonic-gate #endif
28457c478bd9Sstevel@tonic-gate 
28467c478bd9Sstevel@tonic-gate 	/*
28477c478bd9Sstevel@tonic-gate 	 * Figure out how much of the packet header to throw away.
28487c478bd9Sstevel@tonic-gate 	 *
28497c478bd9Sstevel@tonic-gate 	 * RAW streams expect to see the whole packet.
28507c478bd9Sstevel@tonic-gate 	 *
28517c478bd9Sstevel@tonic-gate 	 * Other streams expect to see the packet with the MAC header
28527c478bd9Sstevel@tonic-gate 	 * removed.
28537c478bd9Sstevel@tonic-gate 	 *
28547c478bd9Sstevel@tonic-gate 	 * Normal DLPI (non RAW/FAST) streams also want the
28557c478bd9Sstevel@tonic-gate 	 * DL_UNITDATA_IND M_PROTO message block prepended to the M_DATA.
28567c478bd9Sstevel@tonic-gate 	 */
28577c478bd9Sstevel@tonic-gate 	if (gld->gld_flags & GLD_RAW) {
28587c478bd9Sstevel@tonic-gate 		skiplen = 0;
28597c478bd9Sstevel@tonic-gate 	} else {
28607c478bd9Sstevel@tonic-gate 		skiplen = pktinfo->macLen;		/* skip mac header */
28617c478bd9Sstevel@tonic-gate 		if (gld->gld_ethertype)
28627c478bd9Sstevel@tonic-gate 			skiplen += pktinfo->hdrLen;	/* skip any extra */
28637c478bd9Sstevel@tonic-gate 	}
28647c478bd9Sstevel@tonic-gate 
28657c478bd9Sstevel@tonic-gate 	if (skiplen >= pktinfo->pktLen) {
28667c478bd9Sstevel@tonic-gate 		/*
28677c478bd9Sstevel@tonic-gate 		 * If the interpreter did its job right, then it cannot be
28687c478bd9Sstevel@tonic-gate 		 * asking us to skip more bytes than are in the packet!
28697c478bd9Sstevel@tonic-gate 		 * However, there could be zero data bytes left after the
28707c478bd9Sstevel@tonic-gate 		 * amount to skip.  DLPI specifies that passed M_DATA blocks
28717c478bd9Sstevel@tonic-gate 		 * should contain at least one byte of data, so if we have
28727c478bd9Sstevel@tonic-gate 		 * none we just drop it.
28737c478bd9Sstevel@tonic-gate 		 */
28747c478bd9Sstevel@tonic-gate 		ASSERT(!(skiplen > pktinfo->pktLen));
28757c478bd9Sstevel@tonic-gate 		freemsg(mp);
28767c478bd9Sstevel@tonic-gate 		return;
28777c478bd9Sstevel@tonic-gate 	}
28787c478bd9Sstevel@tonic-gate 
28797c478bd9Sstevel@tonic-gate 	/*
28807c478bd9Sstevel@tonic-gate 	 * Skip over the header(s), taking care to possibly handle message
28817c478bd9Sstevel@tonic-gate 	 * fragments shorter than the amount we need to skip.  Hopefully
28827c478bd9Sstevel@tonic-gate 	 * the driver will put the entire packet, or at least the entire
28837c478bd9Sstevel@tonic-gate 	 * header, into a single message block.  But we handle it if not.
28847c478bd9Sstevel@tonic-gate 	 */
28857c478bd9Sstevel@tonic-gate 	while (skiplen >= MBLKL(mp)) {
28867c478bd9Sstevel@tonic-gate 		mblk_t *tmp = mp;
28877c478bd9Sstevel@tonic-gate 		skiplen -= MBLKL(mp);
28887c478bd9Sstevel@tonic-gate 		mp = mp->b_cont;
28897c478bd9Sstevel@tonic-gate 		ASSERT(mp != NULL);	/* because skiplen < pktinfo->pktLen */
28907c478bd9Sstevel@tonic-gate 		freeb(tmp);
28917c478bd9Sstevel@tonic-gate 	}
28927c478bd9Sstevel@tonic-gate 	mp->b_rptr += skiplen;
28937c478bd9Sstevel@tonic-gate 
28947c478bd9Sstevel@tonic-gate 	/* Add M_PROTO if necessary, and pass upstream */
28957c478bd9Sstevel@tonic-gate 	if (((gld->gld_flags & GLD_FAST) && !pktinfo->isMulticast &&
28967c478bd9Sstevel@tonic-gate 	    !pktinfo->isBroadcast) || (gld->gld_flags & GLD_RAW)) {
28977c478bd9Sstevel@tonic-gate 		/* RAW/FAST: just send up the M_DATA */
28987c478bd9Sstevel@tonic-gate 		(*send)(gld->gld_qptr, mp);
28997c478bd9Sstevel@tonic-gate 	} else {
29007c478bd9Sstevel@tonic-gate 		/* everybody else wants to see a unitdata_ind structure */
29017c478bd9Sstevel@tonic-gate 		mp = gld_addudind(gld, mp, pktinfo);
29027c478bd9Sstevel@tonic-gate 		if (mp)
29037c478bd9Sstevel@tonic-gate 			(*send)(gld->gld_qptr, mp);
29047c478bd9Sstevel@tonic-gate 		/* if it failed, gld_addudind already bumped statistic */
29057c478bd9Sstevel@tonic-gate 	}
29067c478bd9Sstevel@tonic-gate }
29077c478bd9Sstevel@tonic-gate 
29087c478bd9Sstevel@tonic-gate /*
29097c478bd9Sstevel@tonic-gate  * gld_addudind(gld, mp, pktinfo)
29107c478bd9Sstevel@tonic-gate  * format a DL_UNITDATA_IND message to be sent upstream to the user
29117c478bd9Sstevel@tonic-gate  */
29127c478bd9Sstevel@tonic-gate static mblk_t *
29137c478bd9Sstevel@tonic-gate gld_addudind(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo)
29147c478bd9Sstevel@tonic-gate {
29157c478bd9Sstevel@tonic-gate 	gld_mac_info_t		*macinfo = gld->gld_mac_info;
29167c478bd9Sstevel@tonic-gate 	gld_vlan_t		*vlan = (gld_vlan_t *)gld->gld_vlan;
29177c478bd9Sstevel@tonic-gate 	dl_unitdata_ind_t	*dludindp;
29187c478bd9Sstevel@tonic-gate 	mblk_t			*nmp;
29197c478bd9Sstevel@tonic-gate 	int			size;
29207c478bd9Sstevel@tonic-gate 	int			type;
29217c478bd9Sstevel@tonic-gate 
29227c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
29237c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
29247c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_addudind(%p, %p, %p)", (void *)gld,
29257c478bd9Sstevel@tonic-gate 		    (void *)mp, (void *)pktinfo);
29267c478bd9Sstevel@tonic-gate #endif
29277c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
29287c478bd9Sstevel@tonic-gate 
29297c478bd9Sstevel@tonic-gate 	/*
29307c478bd9Sstevel@tonic-gate 	 * Allocate the DL_UNITDATA_IND M_PROTO header, if allocation fails
29317c478bd9Sstevel@tonic-gate 	 * might as well discard since we can't go further
29327c478bd9Sstevel@tonic-gate 	 */
29337c478bd9Sstevel@tonic-gate 	size = sizeof (dl_unitdata_ind_t) +
29347c478bd9Sstevel@tonic-gate 	    2 * (macinfo->gldm_addrlen + abs(macinfo->gldm_saplen));
29357c478bd9Sstevel@tonic-gate 	if ((nmp = allocb(size, BPRI_MED)) == NULL) {
29367c478bd9Sstevel@tonic-gate 		freemsg(mp);
29377c478bd9Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_gldnorcvbuf, 1);
29387c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
29397c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
29407c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
29417c478bd9Sstevel@tonic-gate 			    "gld_addudind: allocb failed");
29427c478bd9Sstevel@tonic-gate #endif
29437c478bd9Sstevel@tonic-gate 		return ((mblk_t *)NULL);
29447c478bd9Sstevel@tonic-gate 	}
29457c478bd9Sstevel@tonic-gate 	DB_TYPE(nmp) = M_PROTO;
29467c478bd9Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_datap->db_lim - size;
29477c478bd9Sstevel@tonic-gate 
29487c478bd9Sstevel@tonic-gate 	type = (gld->gld_ethertype) ? pktinfo->ethertype : 0;
29497c478bd9Sstevel@tonic-gate 
29507c478bd9Sstevel@tonic-gate 	/*
29517c478bd9Sstevel@tonic-gate 	 * now setup the DL_UNITDATA_IND header
29527c478bd9Sstevel@tonic-gate 	 *
29537c478bd9Sstevel@tonic-gate 	 * XXX This looks broken if the saps aren't two bytes.
29547c478bd9Sstevel@tonic-gate 	 */
29557c478bd9Sstevel@tonic-gate 	dludindp = (dl_unitdata_ind_t *)nmp->b_rptr;
29567c478bd9Sstevel@tonic-gate 	dludindp->dl_primitive = DL_UNITDATA_IND;
29577c478bd9Sstevel@tonic-gate 	dludindp->dl_src_addr_length =
29587c478bd9Sstevel@tonic-gate 	    dludindp->dl_dest_addr_length = macinfo->gldm_addrlen +
29597c478bd9Sstevel@tonic-gate 					abs(macinfo->gldm_saplen);
29607c478bd9Sstevel@tonic-gate 	dludindp->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
29617c478bd9Sstevel@tonic-gate 	dludindp->dl_src_addr_offset = dludindp->dl_dest_addr_offset +
29627c478bd9Sstevel@tonic-gate 					dludindp->dl_dest_addr_length;
29637c478bd9Sstevel@tonic-gate 
29647c478bd9Sstevel@tonic-gate 	dludindp->dl_group_address = (pktinfo->isMulticast ||
29657c478bd9Sstevel@tonic-gate 					pktinfo->isBroadcast);
29667c478bd9Sstevel@tonic-gate 
29677c478bd9Sstevel@tonic-gate 	nmp->b_wptr = nmp->b_rptr + dludindp->dl_dest_addr_offset;
29687c478bd9Sstevel@tonic-gate 
29697c478bd9Sstevel@tonic-gate 	mac_copy(pktinfo->dhost, nmp->b_wptr, macinfo->gldm_addrlen);
29707c478bd9Sstevel@tonic-gate 	nmp->b_wptr += macinfo->gldm_addrlen;
29717c478bd9Sstevel@tonic-gate 
29727c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_saplen == -2);	/* XXX following code assumes */
29737c478bd9Sstevel@tonic-gate 	*(ushort_t *)(nmp->b_wptr) = type;
29747c478bd9Sstevel@tonic-gate 	nmp->b_wptr += abs(macinfo->gldm_saplen);
29757c478bd9Sstevel@tonic-gate 
29767c478bd9Sstevel@tonic-gate 	ASSERT(nmp->b_wptr == nmp->b_rptr + dludindp->dl_src_addr_offset);
29777c478bd9Sstevel@tonic-gate 
29787c478bd9Sstevel@tonic-gate 	mac_copy(pktinfo->shost, nmp->b_wptr, macinfo->gldm_addrlen);
29797c478bd9Sstevel@tonic-gate 	nmp->b_wptr += macinfo->gldm_addrlen;
29807c478bd9Sstevel@tonic-gate 
29817c478bd9Sstevel@tonic-gate 	*(ushort_t *)(nmp->b_wptr) = type;
29827c478bd9Sstevel@tonic-gate 	nmp->b_wptr += abs(macinfo->gldm_saplen);
29837c478bd9Sstevel@tonic-gate 
29847c478bd9Sstevel@tonic-gate 	if (pktinfo->nosource)
29857c478bd9Sstevel@tonic-gate 		dludindp->dl_src_addr_offset = dludindp->dl_src_addr_length = 0;
29867c478bd9Sstevel@tonic-gate 	linkb(nmp, mp);
29877c478bd9Sstevel@tonic-gate 	return (nmp);
29887c478bd9Sstevel@tonic-gate }
29897c478bd9Sstevel@tonic-gate 
29907c478bd9Sstevel@tonic-gate /* ======================================================= */
29917c478bd9Sstevel@tonic-gate /* wsrv group: called from wsrv, single threaded per queue */
29927c478bd9Sstevel@tonic-gate /* ======================================================= */
29937c478bd9Sstevel@tonic-gate 
29947c478bd9Sstevel@tonic-gate /*
29957c478bd9Sstevel@tonic-gate  * We go to some trouble to avoid taking the same lock during normal
29967c478bd9Sstevel@tonic-gate  * transmit processing as we do during normal receive processing.
29977c478bd9Sstevel@tonic-gate  *
29987c478bd9Sstevel@tonic-gate  * Elements of the per-instance macinfo and per-stream gld_t structures
29997c478bd9Sstevel@tonic-gate  * are for the most part protected by the GLDM_LOCK rwlock/mutex.
30007c478bd9Sstevel@tonic-gate  * (Elements of the gld_mac_pvt_t structure are considered part of the
30017c478bd9Sstevel@tonic-gate  * macinfo structure for purposes of this discussion).
30027c478bd9Sstevel@tonic-gate  *
30037c478bd9Sstevel@tonic-gate  * However, it is more complicated than that:
30047c478bd9Sstevel@tonic-gate  *
30057c478bd9Sstevel@tonic-gate  *	Elements of the macinfo structure that are set before the macinfo
30067c478bd9Sstevel@tonic-gate  *	structure is added to its device list by gld_register(), and never
30077c478bd9Sstevel@tonic-gate  *	thereafter modified, are accessed without requiring taking the lock.
30087c478bd9Sstevel@tonic-gate  *	A similar rule applies to those elements of the gld_t structure that
30097c478bd9Sstevel@tonic-gate  *	are written by gld_open() before the stream is added to any list.
30107c478bd9Sstevel@tonic-gate  *
30117c478bd9Sstevel@tonic-gate  *	Most other elements of the macinfo structure may only be read or
30127c478bd9Sstevel@tonic-gate  *	written while holding the maclock.
30137c478bd9Sstevel@tonic-gate  *
30147c478bd9Sstevel@tonic-gate  *	Most writable elements of the gld_t structure are written only
30157c478bd9Sstevel@tonic-gate  *	within the single-threaded domain of wsrv() and subsidiaries.
30167c478bd9Sstevel@tonic-gate  *	(This domain includes open/close while qprocs are not on.)
30177c478bd9Sstevel@tonic-gate  *	The maclock need not be taken while within that domain
30187c478bd9Sstevel@tonic-gate  *	simply to read those elements.  Writing to them, even within
30197c478bd9Sstevel@tonic-gate  *	that domain, or reading from it outside that domain, requires
30207c478bd9Sstevel@tonic-gate  *	holding the maclock.  Exception:  if the stream is not
30217c478bd9Sstevel@tonic-gate  *	presently attached to a PPA, there is no associated macinfo,
30227c478bd9Sstevel@tonic-gate  *	and no maclock need be taken.
30237c478bd9Sstevel@tonic-gate  *
30247c478bd9Sstevel@tonic-gate  *	The curr_macaddr element of the mac private structure is also
30257c478bd9Sstevel@tonic-gate  *      protected by the GLDM_LOCK rwlock/mutex, like most other members
30267c478bd9Sstevel@tonic-gate  *      of that structure. However, there are a few instances in the
30277c478bd9Sstevel@tonic-gate  *      transmit path where we choose to forgo lock protection when
30287c478bd9Sstevel@tonic-gate  *      reading this variable. This is to avoid lock contention between
30297c478bd9Sstevel@tonic-gate  *      threads executing the DL_UNITDATA_REQ case and receive threads.
30307c478bd9Sstevel@tonic-gate  *      In doing so we will take a small risk or a few corrupted packets
30317c478bd9Sstevel@tonic-gate  *      during the short an rare times when someone is changing the interface's
30327c478bd9Sstevel@tonic-gate  *      physical address. We consider the small cost in this rare case to be
30337c478bd9Sstevel@tonic-gate  *      worth the benefit of reduced lock contention under normal operating
30347c478bd9Sstevel@tonic-gate  *      conditions. The risk/cost is small because:
30357c478bd9Sstevel@tonic-gate  *          1. there is no guarantee at this layer of uncorrupted delivery.
30367c478bd9Sstevel@tonic-gate  *          2. the physaddr doesn't change very often - no performance hit.
30377c478bd9Sstevel@tonic-gate  *          3. if the physaddr changes, other stuff is going to be screwed
30387c478bd9Sstevel@tonic-gate  *             up for a while anyway, while other sites refigure ARP, etc.,
30397c478bd9Sstevel@tonic-gate  *             so losing a couple of packets is the least of our worries.
30407c478bd9Sstevel@tonic-gate  *
30417c478bd9Sstevel@tonic-gate  *	The list of streams associated with a macinfo is protected by
30427c478bd9Sstevel@tonic-gate  *	two locks:  the per-macinfo maclock, and the per-major-device
30437c478bd9Sstevel@tonic-gate  *	gld_devlock.  Both must be held to modify the list, but either
30447c478bd9Sstevel@tonic-gate  *	may be held to protect the list during reading/traversing.  This
30457c478bd9Sstevel@tonic-gate  *	allows independent locking for multiple instances in the receive
30467c478bd9Sstevel@tonic-gate  *	path (using macinfo), while facilitating routines that must search
30477c478bd9Sstevel@tonic-gate  *	the entire set of streams associated with a major device, such as
30487c478bd9Sstevel@tonic-gate  *	gld_findminor(), gld_finddevinfo(), close().  The "nstreams"
30497c478bd9Sstevel@tonic-gate  *	macinfo	element, and the gld_mac_info gld_t element, are similarly
30507c478bd9Sstevel@tonic-gate  *	protected, since they change at exactly the same time macinfo
30517c478bd9Sstevel@tonic-gate  *	streams list does.
30527c478bd9Sstevel@tonic-gate  *
30537c478bd9Sstevel@tonic-gate  *	The list of macinfo structures associated with a major device
30547c478bd9Sstevel@tonic-gate  *	structure is protected by the gld_devlock, as is the per-major
30557c478bd9Sstevel@tonic-gate  *	list of Style 2 streams in the DL_UNATTACHED state.
30567c478bd9Sstevel@tonic-gate  *
30577c478bd9Sstevel@tonic-gate  *	The list of major devices is kept on a module-global list
30587c478bd9Sstevel@tonic-gate  *	gld_device_list, which has its own lock to protect the list.
30597c478bd9Sstevel@tonic-gate  *
30607c478bd9Sstevel@tonic-gate  *	When it is necessary to hold more than one lock at a time, they
30617c478bd9Sstevel@tonic-gate  *	are acquired in this "outside in" order:
30627c478bd9Sstevel@tonic-gate  *		gld_device_list.gld_devlock
30637c478bd9Sstevel@tonic-gate  *		glddev->gld_devlock
30647c478bd9Sstevel@tonic-gate  *		GLDM_LOCK(macinfo)
30657c478bd9Sstevel@tonic-gate  *
30667c478bd9Sstevel@tonic-gate  *	Finally, there are some "volatile" elements of the gld_t structure
30677c478bd9Sstevel@tonic-gate  *	used for synchronization between various routines that don't share
30687c478bd9Sstevel@tonic-gate  *	the same mutexes.  See the routines for details.  These are:
30697c478bd9Sstevel@tonic-gate  *		gld_xwait	between gld_wsrv() and gld_sched()
30707c478bd9Sstevel@tonic-gate  *		gld_sched_ran	between gld_wsrv() and gld_sched()
30717c478bd9Sstevel@tonic-gate  *		gld_in_unbind	between gld_wput() and wsrv's gld_unbind()
30727c478bd9Sstevel@tonic-gate  *		gld_wput_count	between gld_wput() and wsrv's gld_unbind()
30737c478bd9Sstevel@tonic-gate  *		gld_in_wsrv	between gld_wput() and gld_wsrv()
30747c478bd9Sstevel@tonic-gate  *				(used in conjunction with q->q_first)
30757c478bd9Sstevel@tonic-gate  */
30767c478bd9Sstevel@tonic-gate 
30777c478bd9Sstevel@tonic-gate /*
30787c478bd9Sstevel@tonic-gate  * gld_ioctl (q, mp)
30797c478bd9Sstevel@tonic-gate  * handles all ioctl requests passed downstream. This routine is
30807c478bd9Sstevel@tonic-gate  * passed a pointer to the message block with the ioctl request in it, and a
30817c478bd9Sstevel@tonic-gate  * pointer to the queue so it can respond to the ioctl request with an ack.
30827c478bd9Sstevel@tonic-gate  */
30837c478bd9Sstevel@tonic-gate int
30847c478bd9Sstevel@tonic-gate gld_ioctl(queue_t *q, mblk_t *mp)
30857c478bd9Sstevel@tonic-gate {
30867c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
30877c478bd9Sstevel@tonic-gate 	gld_t *gld;
30887c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
30897c478bd9Sstevel@tonic-gate 
30907c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
30917c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
30927c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_ioctl(%p %p)", (void *)q, (void *)mp);
30937c478bd9Sstevel@tonic-gate #endif
30947c478bd9Sstevel@tonic-gate 	gld = (gld_t *)q->q_ptr;
30957c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
30967c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
30977c478bd9Sstevel@tonic-gate 	case DLIOCRAW:		/* raw M_DATA mode */
30987c478bd9Sstevel@tonic-gate 		gld->gld_flags |= GLD_RAW;
30997c478bd9Sstevel@tonic-gate 		DB_TYPE(mp) = M_IOCACK;
31007c478bd9Sstevel@tonic-gate 		qreply(q, mp);
31017c478bd9Sstevel@tonic-gate 		break;
31027c478bd9Sstevel@tonic-gate 
31037c478bd9Sstevel@tonic-gate 	case DL_IOC_HDR_INFO:	/* fastpath */
31047c478bd9Sstevel@tonic-gate 		if (gld_global_options & GLD_OPT_NO_FASTPATH) {
31057c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
31067c478bd9Sstevel@tonic-gate 			break;
31077c478bd9Sstevel@tonic-gate 		}
31087c478bd9Sstevel@tonic-gate 		gld_fastpath(gld, q, mp);
31097c478bd9Sstevel@tonic-gate 		break;
31107c478bd9Sstevel@tonic-gate 
31117c478bd9Sstevel@tonic-gate 	default:
31127c478bd9Sstevel@tonic-gate 		macinfo	 = gld->gld_mac_info;
31137c478bd9Sstevel@tonic-gate 		if (macinfo == NULL || macinfo->gldm_ioctl == NULL) {
31147c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
31157c478bd9Sstevel@tonic-gate 			break;
31167c478bd9Sstevel@tonic-gate 		}
31177c478bd9Sstevel@tonic-gate 
31187c478bd9Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
31197c478bd9Sstevel@tonic-gate 		(void) (*macinfo->gldm_ioctl) (macinfo, q, mp);
31207c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
31217c478bd9Sstevel@tonic-gate 		break;
31227c478bd9Sstevel@tonic-gate 	}
31237c478bd9Sstevel@tonic-gate 	return (0);
31247c478bd9Sstevel@tonic-gate }
31257c478bd9Sstevel@tonic-gate 
31267c478bd9Sstevel@tonic-gate /*
31277c478bd9Sstevel@tonic-gate  * Since the rules for "fastpath" mode don't seem to be documented
31287c478bd9Sstevel@tonic-gate  * anywhere, I will describe GLD's rules for fastpath users here:
31297c478bd9Sstevel@tonic-gate  *
31307c478bd9Sstevel@tonic-gate  * Once in this mode you remain there until close.
31317c478bd9Sstevel@tonic-gate  * If you unbind/rebind you should get a new header using DL_IOC_HDR_INFO.
31327c478bd9Sstevel@tonic-gate  * You must be bound (DL_IDLE) to transmit.
31337c478bd9Sstevel@tonic-gate  * There are other rules not listed above.
31347c478bd9Sstevel@tonic-gate  */
31357c478bd9Sstevel@tonic-gate static void
31367c478bd9Sstevel@tonic-gate gld_fastpath(gld_t *gld, queue_t *q, mblk_t *mp)
31377c478bd9Sstevel@tonic-gate {
31387c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
31397c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
31407c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t *dludp;
31417c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
31427c478bd9Sstevel@tonic-gate 	t_scalar_t off, len;
31437c478bd9Sstevel@tonic-gate 	uint_t maclen;
31447c478bd9Sstevel@tonic-gate 	int error;
31457c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
31467c478bd9Sstevel@tonic-gate 
31477c478bd9Sstevel@tonic-gate 	if (gld->gld_state != DL_IDLE) {
31487c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, EINVAL);
31497c478bd9Sstevel@tonic-gate 		return;
31507c478bd9Sstevel@tonic-gate 	}
31517c478bd9Sstevel@tonic-gate 
31527c478bd9Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
31537c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
31547c478bd9Sstevel@tonic-gate 	maclen = macinfo->gldm_addrlen + abs(macinfo->gldm_saplen);
31557c478bd9Sstevel@tonic-gate 
31567c478bd9Sstevel@tonic-gate 	error = miocpullup(mp, sizeof (dl_unitdata_req_t) + maclen);
31577c478bd9Sstevel@tonic-gate 	if (error != 0) {
31587c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, error);
31597c478bd9Sstevel@tonic-gate 		return;
31607c478bd9Sstevel@tonic-gate 	}
31617c478bd9Sstevel@tonic-gate 
31627c478bd9Sstevel@tonic-gate 	dludp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
31637c478bd9Sstevel@tonic-gate 	off = dludp->dl_dest_addr_offset;
31647c478bd9Sstevel@tonic-gate 	len = dludp->dl_dest_addr_length;
31657c478bd9Sstevel@tonic-gate 	if (dludp->dl_primitive != DL_UNITDATA_REQ ||
31667c478bd9Sstevel@tonic-gate 	    !MBLKIN(mp->b_cont, off, len) || len != maclen) {
31677c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, EINVAL);
31687c478bd9Sstevel@tonic-gate 		return;
31697c478bd9Sstevel@tonic-gate 	}
31707c478bd9Sstevel@tonic-gate 
31717c478bd9Sstevel@tonic-gate 	/*
31727c478bd9Sstevel@tonic-gate 	 * We take his fastpath request as a declaration that he will accept
31737c478bd9Sstevel@tonic-gate 	 * M_DATA messages from us, whether or not we are willing to accept
31747c478bd9Sstevel@tonic-gate 	 * them from him.  This allows us to have fastpath in one direction
31757c478bd9Sstevel@tonic-gate 	 * (flow upstream) even on media with Source Routing, where we are
31767c478bd9Sstevel@tonic-gate 	 * unable to provide a fixed MAC header to be prepended to downstream
31777c478bd9Sstevel@tonic-gate 	 * flowing packets.  So we set GLD_FAST whether or not we decide to
31787c478bd9Sstevel@tonic-gate 	 * allow him to send M_DATA down to us.
31797c478bd9Sstevel@tonic-gate 	 */
31807c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
31817c478bd9Sstevel@tonic-gate 	gld->gld_flags |= GLD_FAST;
31827c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
31837c478bd9Sstevel@tonic-gate 	vlan->gldv_ipq_flags &= ~IPQ_DISABLED;
31847c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
31857c478bd9Sstevel@tonic-gate 
31867c478bd9Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
31877c478bd9Sstevel@tonic-gate 
31887c478bd9Sstevel@tonic-gate 	/* This will fail for Source Routing media */
31897c478bd9Sstevel@tonic-gate 	/* Also on Ethernet on 802.2 SAPs */
31907c478bd9Sstevel@tonic-gate 	if ((nmp = (*ifp->mkfastpath)(gld, mp)) == NULL) {
31917c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, ENOMEM);
31927c478bd9Sstevel@tonic-gate 		return;
31937c478bd9Sstevel@tonic-gate 	}
31947c478bd9Sstevel@tonic-gate 
31957c478bd9Sstevel@tonic-gate 	/*
31967c478bd9Sstevel@tonic-gate 	 * Link new mblk in after the "request" mblks.
31977c478bd9Sstevel@tonic-gate 	 */
31987c478bd9Sstevel@tonic-gate 	linkb(mp, nmp);
31997c478bd9Sstevel@tonic-gate 	miocack(q, mp, msgdsize(mp->b_cont), 0);
32007c478bd9Sstevel@tonic-gate }
32017c478bd9Sstevel@tonic-gate 
32027c478bd9Sstevel@tonic-gate /*
32037c478bd9Sstevel@tonic-gate  * gld_cmds (q, mp)
32047c478bd9Sstevel@tonic-gate  *	process the DL commands as defined in dlpi.h
32057c478bd9Sstevel@tonic-gate  *	note that the primitives return status which is passed back
32067c478bd9Sstevel@tonic-gate  *	to the service procedure.  If the value is GLDE_RETRY, then
32077c478bd9Sstevel@tonic-gate  *	it is assumed that processing must stop and the primitive has
32087c478bd9Sstevel@tonic-gate  *	been put back onto the queue.  If the value is any other error,
32097c478bd9Sstevel@tonic-gate  *	then an error ack is generated by the service procedure.
32107c478bd9Sstevel@tonic-gate  */
32117c478bd9Sstevel@tonic-gate static int
32127c478bd9Sstevel@tonic-gate gld_cmds(queue_t *q, mblk_t *mp)
32137c478bd9Sstevel@tonic-gate {
32147c478bd9Sstevel@tonic-gate 	union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr;
32157c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)(q->q_ptr);
32167c478bd9Sstevel@tonic-gate 	int result = DL_BADPRIM;
32177c478bd9Sstevel@tonic-gate 	int mblkl = MBLKL(mp);
32187c478bd9Sstevel@tonic-gate 	t_uscalar_t dlreq;
32197c478bd9Sstevel@tonic-gate 
32207c478bd9Sstevel@tonic-gate 	/* Make sure we have at least dlp->dl_primitive */
32217c478bd9Sstevel@tonic-gate 	if (mblkl < sizeof (dlp->dl_primitive))
32227c478bd9Sstevel@tonic-gate 		return (DL_BADPRIM);
32237c478bd9Sstevel@tonic-gate 
32247c478bd9Sstevel@tonic-gate 	dlreq = dlp->dl_primitive;
32257c478bd9Sstevel@tonic-gate #ifdef	GLD_DEBUG
32267c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
32277c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE,
32287c478bd9Sstevel@tonic-gate 		    "gld_cmds(%p, %p):dlp=%p, dlp->dl_primitive=%d",
32297c478bd9Sstevel@tonic-gate 		    (void *)q, (void *)mp, (void *)dlp, dlreq);
32307c478bd9Sstevel@tonic-gate #endif
32317c478bd9Sstevel@tonic-gate 
32327c478bd9Sstevel@tonic-gate 	switch (dlreq) {
32337c478bd9Sstevel@tonic-gate 	case DL_UDQOS_REQ:
32347c478bd9Sstevel@tonic-gate 		if (mblkl < DL_UDQOS_REQ_SIZE)
32357c478bd9Sstevel@tonic-gate 			break;
32367c478bd9Sstevel@tonic-gate 		result = gld_udqos(q, mp);
32377c478bd9Sstevel@tonic-gate 		break;
32387c478bd9Sstevel@tonic-gate 
32397c478bd9Sstevel@tonic-gate 	case DL_BIND_REQ:
32407c478bd9Sstevel@tonic-gate 		if (mblkl < DL_BIND_REQ_SIZE)
32417c478bd9Sstevel@tonic-gate 			break;
32427c478bd9Sstevel@tonic-gate 		result = gld_bind(q, mp);
32437c478bd9Sstevel@tonic-gate 		break;
32447c478bd9Sstevel@tonic-gate 
32457c478bd9Sstevel@tonic-gate 	case DL_UNBIND_REQ:
32467c478bd9Sstevel@tonic-gate 		if (mblkl < DL_UNBIND_REQ_SIZE)
32477c478bd9Sstevel@tonic-gate 			break;
32487c478bd9Sstevel@tonic-gate 		result = gld_unbind(q, mp);
32497c478bd9Sstevel@tonic-gate 		break;
32507c478bd9Sstevel@tonic-gate 
32517c478bd9Sstevel@tonic-gate 	case DL_UNITDATA_REQ:
32527c478bd9Sstevel@tonic-gate 		if (mblkl < DL_UNITDATA_REQ_SIZE)
32537c478bd9Sstevel@tonic-gate 			break;
32547c478bd9Sstevel@tonic-gate 		result = gld_unitdata(q, mp);
32557c478bd9Sstevel@tonic-gate 		break;
32567c478bd9Sstevel@tonic-gate 
32577c478bd9Sstevel@tonic-gate 	case DL_INFO_REQ:
32587c478bd9Sstevel@tonic-gate 		if (mblkl < DL_INFO_REQ_SIZE)
32597c478bd9Sstevel@tonic-gate 			break;
32607c478bd9Sstevel@tonic-gate 		result = gld_inforeq(q, mp);
32617c478bd9Sstevel@tonic-gate 		break;
32627c478bd9Sstevel@tonic-gate 
32637c478bd9Sstevel@tonic-gate 	case DL_ATTACH_REQ:
32647c478bd9Sstevel@tonic-gate 		if (mblkl < DL_ATTACH_REQ_SIZE)
32657c478bd9Sstevel@tonic-gate 			break;
32667c478bd9Sstevel@tonic-gate 		if (gld->gld_style == DL_STYLE2)
32677c478bd9Sstevel@tonic-gate 			result = gldattach(q, mp);
32687c478bd9Sstevel@tonic-gate 		else
32697c478bd9Sstevel@tonic-gate 			result = DL_NOTSUPPORTED;
32707c478bd9Sstevel@tonic-gate 		break;
32717c478bd9Sstevel@tonic-gate 
32727c478bd9Sstevel@tonic-gate 	case DL_DETACH_REQ:
32737c478bd9Sstevel@tonic-gate 		if (mblkl < DL_DETACH_REQ_SIZE)
32747c478bd9Sstevel@tonic-gate 			break;
32757c478bd9Sstevel@tonic-gate 		if (gld->gld_style == DL_STYLE2)
32767c478bd9Sstevel@tonic-gate 			result = gldunattach(q, mp);
32777c478bd9Sstevel@tonic-gate 		else
32787c478bd9Sstevel@tonic-gate 			result = DL_NOTSUPPORTED;
32797c478bd9Sstevel@tonic-gate 		break;
32807c478bd9Sstevel@tonic-gate 
32817c478bd9Sstevel@tonic-gate 	case DL_ENABMULTI_REQ:
32827c478bd9Sstevel@tonic-gate 		if (mblkl < DL_ENABMULTI_REQ_SIZE)
32837c478bd9Sstevel@tonic-gate 			break;
32847c478bd9Sstevel@tonic-gate 		result = gld_enable_multi(q, mp);
32857c478bd9Sstevel@tonic-gate 		break;
32867c478bd9Sstevel@tonic-gate 
32877c478bd9Sstevel@tonic-gate 	case DL_DISABMULTI_REQ:
32887c478bd9Sstevel@tonic-gate 		if (mblkl < DL_DISABMULTI_REQ_SIZE)
32897c478bd9Sstevel@tonic-gate 			break;
32907c478bd9Sstevel@tonic-gate 		result = gld_disable_multi(q, mp);
32917c478bd9Sstevel@tonic-gate 		break;
32927c478bd9Sstevel@tonic-gate 
32937c478bd9Sstevel@tonic-gate 	case DL_PHYS_ADDR_REQ:
32947c478bd9Sstevel@tonic-gate 		if (mblkl < DL_PHYS_ADDR_REQ_SIZE)
32957c478bd9Sstevel@tonic-gate 			break;
32967c478bd9Sstevel@tonic-gate 		result = gld_physaddr(q, mp);
32977c478bd9Sstevel@tonic-gate 		break;
32987c478bd9Sstevel@tonic-gate 
32997c478bd9Sstevel@tonic-gate 	case DL_SET_PHYS_ADDR_REQ:
33007c478bd9Sstevel@tonic-gate 		if (mblkl < DL_SET_PHYS_ADDR_REQ_SIZE)
33017c478bd9Sstevel@tonic-gate 			break;
33027c478bd9Sstevel@tonic-gate 		result = gld_setaddr(q, mp);
33037c478bd9Sstevel@tonic-gate 		break;
33047c478bd9Sstevel@tonic-gate 
33057c478bd9Sstevel@tonic-gate 	case DL_PROMISCON_REQ:
33067c478bd9Sstevel@tonic-gate 		if (mblkl < DL_PROMISCON_REQ_SIZE)
33077c478bd9Sstevel@tonic-gate 			break;
33087c478bd9Sstevel@tonic-gate 		result = gld_promisc(q, mp, dlreq, B_TRUE);
33097c478bd9Sstevel@tonic-gate 		break;
33107c478bd9Sstevel@tonic-gate 
33117c478bd9Sstevel@tonic-gate 	case DL_PROMISCOFF_REQ:
33127c478bd9Sstevel@tonic-gate 		if (mblkl < DL_PROMISCOFF_REQ_SIZE)
33137c478bd9Sstevel@tonic-gate 			break;
33147c478bd9Sstevel@tonic-gate 		result = gld_promisc(q, mp, dlreq, B_FALSE);
33157c478bd9Sstevel@tonic-gate 		break;
33167c478bd9Sstevel@tonic-gate 
33177c478bd9Sstevel@tonic-gate 	case DL_GET_STATISTICS_REQ:
33187c478bd9Sstevel@tonic-gate 		if (mblkl < DL_GET_STATISTICS_REQ_SIZE)
33197c478bd9Sstevel@tonic-gate 			break;
33207c478bd9Sstevel@tonic-gate 		result = gld_get_statistics(q, mp);
33217c478bd9Sstevel@tonic-gate 		break;
33227c478bd9Sstevel@tonic-gate 
33237c478bd9Sstevel@tonic-gate 	case DL_CAPABILITY_REQ:
33247c478bd9Sstevel@tonic-gate 		if (mblkl < DL_CAPABILITY_REQ_SIZE)
33257c478bd9Sstevel@tonic-gate 			break;
33267c478bd9Sstevel@tonic-gate 		result = gld_cap(q, mp);
33277c478bd9Sstevel@tonic-gate 		break;
33287c478bd9Sstevel@tonic-gate 
33297c478bd9Sstevel@tonic-gate 	case DL_NOTIFY_REQ:
33307c478bd9Sstevel@tonic-gate 		if (mblkl < DL_NOTIFY_REQ_SIZE)
33317c478bd9Sstevel@tonic-gate 			break;
33327c478bd9Sstevel@tonic-gate 		result = gld_notify_req(q, mp);
33337c478bd9Sstevel@tonic-gate 		break;
33347c478bd9Sstevel@tonic-gate 
33357c478bd9Sstevel@tonic-gate 	case DL_XID_REQ:
33367c478bd9Sstevel@tonic-gate 	case DL_XID_RES:
33377c478bd9Sstevel@tonic-gate 	case DL_TEST_REQ:
33387c478bd9Sstevel@tonic-gate 	case DL_TEST_RES:
33397c478bd9Sstevel@tonic-gate 	case DL_CONTROL_REQ:
334098b1442aSmeem 	case DL_PASSIVE_REQ:
33417c478bd9Sstevel@tonic-gate 		result = DL_NOTSUPPORTED;
33427c478bd9Sstevel@tonic-gate 		break;
33437c478bd9Sstevel@tonic-gate 
33447c478bd9Sstevel@tonic-gate 	default:
33457c478bd9Sstevel@tonic-gate #ifdef	GLD_DEBUG
33467c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
33477c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
33487c478bd9Sstevel@tonic-gate 			    "gld_cmds: unknown M_PROTO message: %d",
33497c478bd9Sstevel@tonic-gate 			    dlreq);
33507c478bd9Sstevel@tonic-gate #endif
33517c478bd9Sstevel@tonic-gate 		result = DL_BADPRIM;
33527c478bd9Sstevel@tonic-gate 	}
33537c478bd9Sstevel@tonic-gate 
33547c478bd9Sstevel@tonic-gate 	return (result);
33557c478bd9Sstevel@tonic-gate }
33567c478bd9Sstevel@tonic-gate 
33577c478bd9Sstevel@tonic-gate static int
33587c478bd9Sstevel@tonic-gate gld_cap(queue_t *q, mblk_t *mp)
33597c478bd9Sstevel@tonic-gate {
33607c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
33617c478bd9Sstevel@tonic-gate 	dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr;
33627c478bd9Sstevel@tonic-gate 
33637c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
33647c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
33657c478bd9Sstevel@tonic-gate 
33667c478bd9Sstevel@tonic-gate 	if (dlp->dl_sub_length == 0)
33677c478bd9Sstevel@tonic-gate 		return (gld_cap_ack(q, mp));
33687c478bd9Sstevel@tonic-gate 
33697c478bd9Sstevel@tonic-gate 	return (gld_cap_enable(q, mp));
33707c478bd9Sstevel@tonic-gate }
33717c478bd9Sstevel@tonic-gate 
33727c478bd9Sstevel@tonic-gate static int
33737c478bd9Sstevel@tonic-gate gld_cap_ack(queue_t *q, mblk_t *mp)
33747c478bd9Sstevel@tonic-gate {
33757c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
33767c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
33777c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
33787c478bd9Sstevel@tonic-gate 	dl_capability_ack_t *dlap;
33797c478bd9Sstevel@tonic-gate 	dl_capability_sub_t *dlsp;
33807c478bd9Sstevel@tonic-gate 	size_t size = sizeof (dl_capability_ack_t);
33817c478bd9Sstevel@tonic-gate 	size_t subsize = 0;
33827c478bd9Sstevel@tonic-gate 
33837c478bd9Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
33847c478bd9Sstevel@tonic-gate 
33857c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_ANY)
33867c478bd9Sstevel@tonic-gate 		subsize += sizeof (dl_capability_sub_t) +
33877c478bd9Sstevel@tonic-gate 		    sizeof (dl_capab_hcksum_t);
33887c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_ZEROCOPY)
33897c478bd9Sstevel@tonic-gate 		subsize += sizeof (dl_capability_sub_t) +
33907c478bd9Sstevel@tonic-gate 		    sizeof (dl_capab_zerocopy_t);
33917c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_options & GLDOPT_MDT)
33927c478bd9Sstevel@tonic-gate 		subsize += (sizeof (dl_capability_sub_t) +
33937c478bd9Sstevel@tonic-gate 		    sizeof (dl_capab_mdt_t));
33947c478bd9Sstevel@tonic-gate 
33957c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, size + subsize, M_PROTO,
33967c478bd9Sstevel@tonic-gate 	    DL_CAPABILITY_ACK)) == NULL)
33977c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
33987c478bd9Sstevel@tonic-gate 
33997c478bd9Sstevel@tonic-gate 	dlap = (dl_capability_ack_t *)mp->b_rptr;
34007c478bd9Sstevel@tonic-gate 	dlap->dl_sub_offset = 0;
34017c478bd9Sstevel@tonic-gate 	if ((dlap->dl_sub_length = subsize) != 0)
34027c478bd9Sstevel@tonic-gate 		dlap->dl_sub_offset = sizeof (dl_capability_ack_t);
34037c478bd9Sstevel@tonic-gate 	dlsp = (dl_capability_sub_t *)&dlap[1];
34047c478bd9Sstevel@tonic-gate 
34057c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_ANY) {
34067c478bd9Sstevel@tonic-gate 		dl_capab_hcksum_t *dlhp = (dl_capab_hcksum_t *)&dlsp[1];
34077c478bd9Sstevel@tonic-gate 
34087c478bd9Sstevel@tonic-gate 		dlsp->dl_cap = DL_CAPAB_HCKSUM;
34097c478bd9Sstevel@tonic-gate 		dlsp->dl_length = sizeof (dl_capab_hcksum_t);
34107c478bd9Sstevel@tonic-gate 
34117c478bd9Sstevel@tonic-gate 		dlhp->hcksum_version = HCKSUM_VERSION_1;
34127c478bd9Sstevel@tonic-gate 
34137c478bd9Sstevel@tonic-gate 		dlhp->hcksum_txflags = 0;
34147c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_PARTIAL)
34157c478bd9Sstevel@tonic-gate 			dlhp->hcksum_txflags |= HCKSUM_INET_PARTIAL;
34167c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_FULL_V4)
34177c478bd9Sstevel@tonic-gate 			dlhp->hcksum_txflags |= HCKSUM_INET_FULL_V4;
3418ff550d0eSmasputra 		if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_FULL_V6)
3419ff550d0eSmasputra 			dlhp->hcksum_txflags |= HCKSUM_INET_FULL_V6;
34207c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_IPHDR)
34217c478bd9Sstevel@tonic-gate 			dlhp->hcksum_txflags |= HCKSUM_IPHDRCKSUM;
34227c478bd9Sstevel@tonic-gate 
34237c478bd9Sstevel@tonic-gate 		dlcapabsetqid(&(dlhp->hcksum_mid), RD(q));
34247c478bd9Sstevel@tonic-gate 		dlsp = (dl_capability_sub_t *)&dlhp[1];
34257c478bd9Sstevel@tonic-gate 	}
34267c478bd9Sstevel@tonic-gate 
34277c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_ZEROCOPY) {
34287c478bd9Sstevel@tonic-gate 		dl_capab_zerocopy_t *dlzp = (dl_capab_zerocopy_t *)&dlsp[1];
34297c478bd9Sstevel@tonic-gate 
34307c478bd9Sstevel@tonic-gate 		dlsp->dl_cap = DL_CAPAB_ZEROCOPY;
34317c478bd9Sstevel@tonic-gate 		dlsp->dl_length = sizeof (dl_capab_zerocopy_t);
34327c478bd9Sstevel@tonic-gate 		dlzp->zerocopy_version = ZEROCOPY_VERSION_1;
34337c478bd9Sstevel@tonic-gate 		dlzp->zerocopy_flags = DL_CAPAB_VMSAFE_MEM;
34347c478bd9Sstevel@tonic-gate 
34357c478bd9Sstevel@tonic-gate 		dlcapabsetqid(&(dlzp->zerocopy_mid), RD(q));
34367c478bd9Sstevel@tonic-gate 		dlsp = (dl_capability_sub_t *)&dlzp[1];
34377c478bd9Sstevel@tonic-gate 	}
34387c478bd9Sstevel@tonic-gate 
34397c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_options & GLDOPT_MDT) {
34407c478bd9Sstevel@tonic-gate 		dl_capab_mdt_t *dlmp = (dl_capab_mdt_t *)&dlsp[1];
34417c478bd9Sstevel@tonic-gate 
34427c478bd9Sstevel@tonic-gate 		dlsp->dl_cap = DL_CAPAB_MDT;
34437c478bd9Sstevel@tonic-gate 		dlsp->dl_length = sizeof (dl_capab_mdt_t);
34447c478bd9Sstevel@tonic-gate 
34457c478bd9Sstevel@tonic-gate 		dlmp->mdt_version = MDT_VERSION_2;
34467c478bd9Sstevel@tonic-gate 		dlmp->mdt_max_pld = macinfo->gldm_mdt_segs;
34477c478bd9Sstevel@tonic-gate 		dlmp->mdt_span_limit = macinfo->gldm_mdt_sgl;
34487c478bd9Sstevel@tonic-gate 		dlcapabsetqid(&dlmp->mdt_mid, OTHERQ(q));
34497c478bd9Sstevel@tonic-gate 		dlmp->mdt_flags = DL_CAPAB_MDT_ENABLE;
34507c478bd9Sstevel@tonic-gate 		dlmp->mdt_hdr_head = ifp->hdr_size;
34517c478bd9Sstevel@tonic-gate 		dlmp->mdt_hdr_tail = 0;
34527c478bd9Sstevel@tonic-gate 	}
34537c478bd9Sstevel@tonic-gate 
34547c478bd9Sstevel@tonic-gate 	qreply(q, mp);
34557c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
34567c478bd9Sstevel@tonic-gate }
34577c478bd9Sstevel@tonic-gate 
34587c478bd9Sstevel@tonic-gate static int
34597c478bd9Sstevel@tonic-gate gld_cap_enable(queue_t *q, mblk_t *mp)
34607c478bd9Sstevel@tonic-gate {
34617c478bd9Sstevel@tonic-gate 	dl_capability_req_t *dlp;
34627c478bd9Sstevel@tonic-gate 	dl_capability_sub_t *dlsp;
34637c478bd9Sstevel@tonic-gate 	dl_capab_hcksum_t *dlhp;
34647c478bd9Sstevel@tonic-gate 	offset_t off;
34657c478bd9Sstevel@tonic-gate 	size_t len;
34667c478bd9Sstevel@tonic-gate 	size_t size;
34677c478bd9Sstevel@tonic-gate 	offset_t end;
34687c478bd9Sstevel@tonic-gate 
34697c478bd9Sstevel@tonic-gate 	dlp = (dl_capability_req_t *)mp->b_rptr;
34707c478bd9Sstevel@tonic-gate 	dlp->dl_primitive = DL_CAPABILITY_ACK;
34717c478bd9Sstevel@tonic-gate 
34727c478bd9Sstevel@tonic-gate 	off = dlp->dl_sub_offset;
34737c478bd9Sstevel@tonic-gate 	len = dlp->dl_sub_length;
34747c478bd9Sstevel@tonic-gate 
34757c478bd9Sstevel@tonic-gate 	if (!MBLKIN(mp, off, len))
34767c478bd9Sstevel@tonic-gate 		return (DL_BADPRIM);
34777c478bd9Sstevel@tonic-gate 
34787c478bd9Sstevel@tonic-gate 	end = off + len;
34797c478bd9Sstevel@tonic-gate 	while (off < end) {
34807c478bd9Sstevel@tonic-gate 		dlsp = (dl_capability_sub_t *)(mp->b_rptr + off);
34817c478bd9Sstevel@tonic-gate 		size = sizeof (dl_capability_sub_t) + dlsp->dl_length;
34827c478bd9Sstevel@tonic-gate 		if (off + size > end)
34837c478bd9Sstevel@tonic-gate 			return (DL_BADPRIM);
34847c478bd9Sstevel@tonic-gate 
34857c478bd9Sstevel@tonic-gate 		switch (dlsp->dl_cap) {
34867c478bd9Sstevel@tonic-gate 		case DL_CAPAB_HCKSUM:
34877c478bd9Sstevel@tonic-gate 			dlhp = (dl_capab_hcksum_t *)&dlsp[1];
34887c478bd9Sstevel@tonic-gate 			/* nothing useful we can do with the contents */
34897c478bd9Sstevel@tonic-gate 			dlcapabsetqid(&(dlhp->hcksum_mid), RD(q));
34907c478bd9Sstevel@tonic-gate 			break;
34917c478bd9Sstevel@tonic-gate 		default:
34927c478bd9Sstevel@tonic-gate 			break;
34937c478bd9Sstevel@tonic-gate 		}
34947c478bd9Sstevel@tonic-gate 
34957c478bd9Sstevel@tonic-gate 		off += size;
34967c478bd9Sstevel@tonic-gate 	}
34977c478bd9Sstevel@tonic-gate 
34987c478bd9Sstevel@tonic-gate 	qreply(q, mp);
34997c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
35007c478bd9Sstevel@tonic-gate }
35017c478bd9Sstevel@tonic-gate 
35027c478bd9Sstevel@tonic-gate /*
35037c478bd9Sstevel@tonic-gate  * Send a copy of the DL_NOTIFY_IND message <mp> to each stream that has
35047c478bd9Sstevel@tonic-gate  * requested the specific <notification> that the message carries AND is
35057c478bd9Sstevel@tonic-gate  * eligible and ready to receive the notification immediately.
35067c478bd9Sstevel@tonic-gate  *
35077c478bd9Sstevel@tonic-gate  * This routine ignores flow control. Notifications will be sent regardless.
35087c478bd9Sstevel@tonic-gate  *
35097c478bd9Sstevel@tonic-gate  * In all cases, the original message passed in is freed at the end of
35107c478bd9Sstevel@tonic-gate  * the routine.
35117c478bd9Sstevel@tonic-gate  */
35127c478bd9Sstevel@tonic-gate static void
35137c478bd9Sstevel@tonic-gate gld_notify_qs(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t notification)
35147c478bd9Sstevel@tonic-gate {
35157c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
35167c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
35177c478bd9Sstevel@tonic-gate 	gld_t *gld;
35187c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
35197c478bd9Sstevel@tonic-gate 	int i;
35207c478bd9Sstevel@tonic-gate 
35217c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
35227c478bd9Sstevel@tonic-gate 
35237c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
35247c478bd9Sstevel@tonic-gate 
35257c478bd9Sstevel@tonic-gate 	/*
35267c478bd9Sstevel@tonic-gate 	 * Search all the streams attached to this macinfo looking
35277c478bd9Sstevel@tonic-gate 	 * for those eligible to receive the present notification.
35287c478bd9Sstevel@tonic-gate 	 */
35297c478bd9Sstevel@tonic-gate 	for (i = 0; i < VLAN_HASHSZ; i++) {
35307c478bd9Sstevel@tonic-gate 		for (vlan = mac_pvt->vlan_hash[i];
35317c478bd9Sstevel@tonic-gate 		    vlan != NULL; vlan = vlan->gldv_next) {
35327c478bd9Sstevel@tonic-gate 			for (gld = vlan->gldv_str_next;
35337c478bd9Sstevel@tonic-gate 			    gld != (gld_t *)&vlan->gldv_str_next;
35347c478bd9Sstevel@tonic-gate 			    gld = gld->gld_next) {
35357c478bd9Sstevel@tonic-gate 				ASSERT(gld->gld_qptr != NULL);
35367c478bd9Sstevel@tonic-gate 				ASSERT(gld->gld_state == DL_IDLE ||
35377c478bd9Sstevel@tonic-gate 				    gld->gld_state == DL_UNBOUND);
35387c478bd9Sstevel@tonic-gate 				ASSERT(gld->gld_mac_info == macinfo);
35397c478bd9Sstevel@tonic-gate 
35407c478bd9Sstevel@tonic-gate 				if (gld->gld_flags & GLD_STR_CLOSING)
35417c478bd9Sstevel@tonic-gate 					continue; /* not eligible - skip */
35427c478bd9Sstevel@tonic-gate 				if (!(notification & gld->gld_notifications))
35437c478bd9Sstevel@tonic-gate 					continue; /* not wanted - skip */
35447c478bd9Sstevel@tonic-gate 				if ((nmp = dupmsg(mp)) == NULL)
35457c478bd9Sstevel@tonic-gate 					continue; /* can't copy - skip */
35467c478bd9Sstevel@tonic-gate 
35477c478bd9Sstevel@tonic-gate 				/*
35487c478bd9Sstevel@tonic-gate 				 * All OK; send dup'd notification up this
35497c478bd9Sstevel@tonic-gate 				 * stream
35507c478bd9Sstevel@tonic-gate 				 */
35517c478bd9Sstevel@tonic-gate 				qreply(WR(gld->gld_qptr), nmp);
35527c478bd9Sstevel@tonic-gate 			}
35537c478bd9Sstevel@tonic-gate 		}
35547c478bd9Sstevel@tonic-gate 	}
35557c478bd9Sstevel@tonic-gate 
35567c478bd9Sstevel@tonic-gate 	/*
35577c478bd9Sstevel@tonic-gate 	 * Drop the original message block now
35587c478bd9Sstevel@tonic-gate 	 */
35597c478bd9Sstevel@tonic-gate 	freemsg(mp);
35607c478bd9Sstevel@tonic-gate }
35617c478bd9Sstevel@tonic-gate 
35627c478bd9Sstevel@tonic-gate /*
35637c478bd9Sstevel@tonic-gate  * For each (understood) bit in the <notifications> argument, contruct
35647c478bd9Sstevel@tonic-gate  * a DL_NOTIFY_IND message and send it to the specified <q>, or to all
35657c478bd9Sstevel@tonic-gate  * eligible queues if <q> is NULL.
35667c478bd9Sstevel@tonic-gate  */
35677c478bd9Sstevel@tonic-gate static void
35687c478bd9Sstevel@tonic-gate gld_notify_ind(gld_mac_info_t *macinfo, uint32_t notifications, queue_t *q)
35697c478bd9Sstevel@tonic-gate {
35707c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
35717c478bd9Sstevel@tonic-gate 	dl_notify_ind_t *dlnip;
35727c478bd9Sstevel@tonic-gate 	struct gld_stats *stats;
35737c478bd9Sstevel@tonic-gate 	mblk_t *mp;
35747c478bd9Sstevel@tonic-gate 	size_t size;
35757c478bd9Sstevel@tonic-gate 	uint32_t bit;
35767c478bd9Sstevel@tonic-gate 
35777c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
35787c478bd9Sstevel@tonic-gate 
35797c478bd9Sstevel@tonic-gate 	/*
35807c478bd9Sstevel@tonic-gate 	 * The following cases shouldn't happen, but just in case the
35817c478bd9Sstevel@tonic-gate 	 * MAC driver calls gld_linkstate() at an inappropriate time, we
35827c478bd9Sstevel@tonic-gate 	 * check anyway ...
35837c478bd9Sstevel@tonic-gate 	 */
35847c478bd9Sstevel@tonic-gate 	if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY)) {
35857c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
35867c478bd9Sstevel@tonic-gate 		return;				/* not ready yet	*/
35877c478bd9Sstevel@tonic-gate 	}
35887c478bd9Sstevel@tonic-gate 
35897c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
35907c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
35917c478bd9Sstevel@tonic-gate 		return;				/* not ready anymore	*/
35927c478bd9Sstevel@tonic-gate 	}
35937c478bd9Sstevel@tonic-gate 
35947c478bd9Sstevel@tonic-gate 	/*
35957c478bd9Sstevel@tonic-gate 	 * Make sure the kstats are up to date, 'cos we use some of
35967c478bd9Sstevel@tonic-gate 	 * the kstat values below, specifically the link speed ...
35977c478bd9Sstevel@tonic-gate 	 */
35987c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
35997c478bd9Sstevel@tonic-gate 	stats = mac_pvt->statistics;
36007c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_get_stats)
36017c478bd9Sstevel@tonic-gate 		(void) (*macinfo->gldm_get_stats)(macinfo, stats);
36027c478bd9Sstevel@tonic-gate 
36037c478bd9Sstevel@tonic-gate 	for (bit = 1; notifications != 0; bit <<= 1) {
36047c478bd9Sstevel@tonic-gate 		if ((notifications & bit) == 0)
36057c478bd9Sstevel@tonic-gate 			continue;
36067c478bd9Sstevel@tonic-gate 		notifications &= ~bit;
36077c478bd9Sstevel@tonic-gate 
36087c478bd9Sstevel@tonic-gate 		size = DL_NOTIFY_IND_SIZE;
36097c478bd9Sstevel@tonic-gate 		if (bit == DL_NOTE_PHYS_ADDR)
36107c478bd9Sstevel@tonic-gate 			size += macinfo->gldm_addrlen;
36117c478bd9Sstevel@tonic-gate 		if ((mp = allocb(size, BPRI_MED)) == NULL)
36127c478bd9Sstevel@tonic-gate 			continue;
36137c478bd9Sstevel@tonic-gate 
36147c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PROTO;
36157c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + size;
36167c478bd9Sstevel@tonic-gate 		dlnip = (dl_notify_ind_t *)mp->b_rptr;
36177c478bd9Sstevel@tonic-gate 		dlnip->dl_primitive = DL_NOTIFY_IND;
36187c478bd9Sstevel@tonic-gate 		dlnip->dl_notification = 0;
36197c478bd9Sstevel@tonic-gate 		dlnip->dl_data = 0;
36207c478bd9Sstevel@tonic-gate 		dlnip->dl_addr_length = 0;
36217c478bd9Sstevel@tonic-gate 		dlnip->dl_addr_offset = 0;
36227c478bd9Sstevel@tonic-gate 
36237c478bd9Sstevel@tonic-gate 		switch (bit) {
36247c478bd9Sstevel@tonic-gate 		case DL_NOTE_PROMISC_ON_PHYS:
36257c478bd9Sstevel@tonic-gate 		case DL_NOTE_PROMISC_OFF_PHYS:
36267c478bd9Sstevel@tonic-gate 			if (mac_pvt->nprom != 0)
36277c478bd9Sstevel@tonic-gate 				dlnip->dl_notification = bit;
36287c478bd9Sstevel@tonic-gate 			break;
36297c478bd9Sstevel@tonic-gate 
36307c478bd9Sstevel@tonic-gate 		case DL_NOTE_LINK_DOWN:
36317c478bd9Sstevel@tonic-gate 			if (macinfo->gldm_linkstate == GLD_LINKSTATE_DOWN)
36327c478bd9Sstevel@tonic-gate 				dlnip->dl_notification = bit;
36337c478bd9Sstevel@tonic-gate 			break;
36347c478bd9Sstevel@tonic-gate 
36357c478bd9Sstevel@tonic-gate 		case DL_NOTE_LINK_UP:
36367c478bd9Sstevel@tonic-gate 			if (macinfo->gldm_linkstate == GLD_LINKSTATE_UP)
36377c478bd9Sstevel@tonic-gate 				dlnip->dl_notification = bit;
36387c478bd9Sstevel@tonic-gate 			break;
36397c478bd9Sstevel@tonic-gate 
36407c478bd9Sstevel@tonic-gate 		case DL_NOTE_SPEED:
36417c478bd9Sstevel@tonic-gate 			/*
36427c478bd9Sstevel@tonic-gate 			 * Conversion required here:
36437c478bd9Sstevel@tonic-gate 			 *	GLD keeps the speed in bit/s in a uint64
36447c478bd9Sstevel@tonic-gate 			 *	DLPI wants it in kb/s in a uint32
36457c478bd9Sstevel@tonic-gate 			 * Fortunately this is still big enough for 10Gb/s!
36467c478bd9Sstevel@tonic-gate 			 */
36477c478bd9Sstevel@tonic-gate 			dlnip->dl_notification = bit;
36487c478bd9Sstevel@tonic-gate 			dlnip->dl_data = stats->glds_speed/1000ULL;
36497c478bd9Sstevel@tonic-gate 			break;
36507c478bd9Sstevel@tonic-gate 
36517c478bd9Sstevel@tonic-gate 		case DL_NOTE_PHYS_ADDR:
36527c478bd9Sstevel@tonic-gate 			dlnip->dl_notification = bit;
36537c478bd9Sstevel@tonic-gate 			dlnip->dl_data = DL_CURR_PHYS_ADDR;
36547c478bd9Sstevel@tonic-gate 			dlnip->dl_addr_offset = sizeof (dl_notify_ind_t);
36557c478bd9Sstevel@tonic-gate 			dlnip->dl_addr_length = macinfo->gldm_addrlen +
36567c478bd9Sstevel@tonic-gate 			    abs(macinfo->gldm_saplen);
36577c478bd9Sstevel@tonic-gate 			mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
36587c478bd9Sstevel@tonic-gate 			mac_copy(mac_pvt->curr_macaddr,
36597c478bd9Sstevel@tonic-gate 			    mp->b_rptr + sizeof (dl_notify_ind_t),
36607c478bd9Sstevel@tonic-gate 			    macinfo->gldm_addrlen);
36617c478bd9Sstevel@tonic-gate 			break;
36627c478bd9Sstevel@tonic-gate 
36637c478bd9Sstevel@tonic-gate 		default:
36647c478bd9Sstevel@tonic-gate 			break;
36657c478bd9Sstevel@tonic-gate 		}
36667c478bd9Sstevel@tonic-gate 
36677c478bd9Sstevel@tonic-gate 		if (dlnip->dl_notification == 0)
36687c478bd9Sstevel@tonic-gate 			freemsg(mp);
36697c478bd9Sstevel@tonic-gate 		else if (q != NULL)
36707c478bd9Sstevel@tonic-gate 			qreply(q, mp);
36717c478bd9Sstevel@tonic-gate 		else
36727c478bd9Sstevel@tonic-gate 			gld_notify_qs(macinfo, mp, bit);
36737c478bd9Sstevel@tonic-gate 	}
36747c478bd9Sstevel@tonic-gate 
36757c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
36767c478bd9Sstevel@tonic-gate }
36777c478bd9Sstevel@tonic-gate 
36787c478bd9Sstevel@tonic-gate /*
36797c478bd9Sstevel@tonic-gate  * gld_notify_req - handle a DL_NOTIFY_REQ message
36807c478bd9Sstevel@tonic-gate  */
36817c478bd9Sstevel@tonic-gate static int
36827c478bd9Sstevel@tonic-gate gld_notify_req(queue_t *q, mblk_t *mp)
36837c478bd9Sstevel@tonic-gate {
36847c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
36857c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
36867c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *pvt;
36877c478bd9Sstevel@tonic-gate 	dl_notify_req_t *dlnrp;
36887c478bd9Sstevel@tonic-gate 	dl_notify_ack_t *dlnap;
36897c478bd9Sstevel@tonic-gate 
36907c478bd9Sstevel@tonic-gate 	ASSERT(gld != NULL);
36917c478bd9Sstevel@tonic-gate 	ASSERT(gld->gld_qptr == RD(q));
36927c478bd9Sstevel@tonic-gate 
36937c478bd9Sstevel@tonic-gate 	dlnrp = (dl_notify_req_t *)mp->b_rptr;
36947c478bd9Sstevel@tonic-gate 
36957c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
36967c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
36977c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_notify_req(%p %p)",
36987c478bd9Sstevel@tonic-gate 			(void *)q, (void *)mp);
36997c478bd9Sstevel@tonic-gate #endif
37007c478bd9Sstevel@tonic-gate 
37017c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED) {
37027c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
37037c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
37047c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_notify_req: wrong state (%d)",
37057c478bd9Sstevel@tonic-gate 				gld->gld_state);
37067c478bd9Sstevel@tonic-gate #endif
37077c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
37087c478bd9Sstevel@tonic-gate 	}
37097c478bd9Sstevel@tonic-gate 
37107c478bd9Sstevel@tonic-gate 	/*
37117c478bd9Sstevel@tonic-gate 	 * Remember what notifications are required by this stream
37127c478bd9Sstevel@tonic-gate 	 */
37137c478bd9Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
37147c478bd9Sstevel@tonic-gate 	pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
37157c478bd9Sstevel@tonic-gate 
37167c478bd9Sstevel@tonic-gate 	gld->gld_notifications = dlnrp->dl_notifications & pvt->notifications;
37177c478bd9Sstevel@tonic-gate 
37187c478bd9Sstevel@tonic-gate 	/*
37197c478bd9Sstevel@tonic-gate 	 * The return DL_NOTIFY_ACK carries the bitset of notifications
37207c478bd9Sstevel@tonic-gate 	 * that this driver can provide, independently of which ones have
37217c478bd9Sstevel@tonic-gate 	 * previously been or are now being requested.
37227c478bd9Sstevel@tonic-gate 	 */
37237c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, sizeof (dl_notify_ack_t), M_PCPROTO,
37247c478bd9Sstevel@tonic-gate 	    DL_NOTIFY_ACK)) == NULL)
37257c478bd9Sstevel@tonic-gate 		return (DL_SYSERR);
37267c478bd9Sstevel@tonic-gate 
37277c478bd9Sstevel@tonic-gate 	dlnap = (dl_notify_ack_t *)mp->b_rptr;
37287c478bd9Sstevel@tonic-gate 	dlnap->dl_notifications = pvt->notifications;
37297c478bd9Sstevel@tonic-gate 	qreply(q, mp);
37307c478bd9Sstevel@tonic-gate 
37317c478bd9Sstevel@tonic-gate 	/*
37327c478bd9Sstevel@tonic-gate 	 * A side effect of a DL_NOTIFY_REQ is that after the DL_NOTIFY_ACK
37337c478bd9Sstevel@tonic-gate 	 * reply, the the requestor gets zero or more DL_NOTIFY_IND messages
37347c478bd9Sstevel@tonic-gate 	 * that provide the current status.
37357c478bd9Sstevel@tonic-gate 	 */
37367c478bd9Sstevel@tonic-gate 	gld_notify_ind(macinfo, gld->gld_notifications, q);
37377c478bd9Sstevel@tonic-gate 
37387c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
37397c478bd9Sstevel@tonic-gate }
37407c478bd9Sstevel@tonic-gate 
37417c478bd9Sstevel@tonic-gate /*
37427c478bd9Sstevel@tonic-gate  * gld_linkstate()
37437c478bd9Sstevel@tonic-gate  *	Called by driver to tell GLD the state of the physical link.
37447c478bd9Sstevel@tonic-gate  *	As a side effect, sends a DL_NOTE_LINK_UP or DL_NOTE_LINK_DOWN
37457c478bd9Sstevel@tonic-gate  *	notification to each client that has previously requested such
37467c478bd9Sstevel@tonic-gate  *	notifications
37477c478bd9Sstevel@tonic-gate  */
37487c478bd9Sstevel@tonic-gate void
37497c478bd9Sstevel@tonic-gate gld_linkstate(gld_mac_info_t *macinfo, int32_t newstate)
37507c478bd9Sstevel@tonic-gate {
37517c478bd9Sstevel@tonic-gate 	uint32_t notification;
37527c478bd9Sstevel@tonic-gate 
37537c478bd9Sstevel@tonic-gate 	switch (newstate) {
37547c478bd9Sstevel@tonic-gate 	default:
37557c478bd9Sstevel@tonic-gate 		return;
37567c478bd9Sstevel@tonic-gate 
37577c478bd9Sstevel@tonic-gate 	case GLD_LINKSTATE_DOWN:
37587c478bd9Sstevel@tonic-gate 		notification = DL_NOTE_LINK_DOWN;
37597c478bd9Sstevel@tonic-gate 		break;
37607c478bd9Sstevel@tonic-gate 
37617c478bd9Sstevel@tonic-gate 	case GLD_LINKSTATE_UP:
37627c478bd9Sstevel@tonic-gate 		notification = DL_NOTE_LINK_UP | DL_NOTE_SPEED;
37637c478bd9Sstevel@tonic-gate 		break;
37647c478bd9Sstevel@tonic-gate 
37657c478bd9Sstevel@tonic-gate 	case GLD_LINKSTATE_UNKNOWN:
37667c478bd9Sstevel@tonic-gate 		notification = 0;
37677c478bd9Sstevel@tonic-gate 		break;
37687c478bd9Sstevel@tonic-gate 	}
37697c478bd9Sstevel@tonic-gate 
37707c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
37717c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_linkstate == newstate)
37727c478bd9Sstevel@tonic-gate 		notification = 0;
37737c478bd9Sstevel@tonic-gate 	else
37747c478bd9Sstevel@tonic-gate 		macinfo->gldm_linkstate = newstate;
37757c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
37767c478bd9Sstevel@tonic-gate 
37777c478bd9Sstevel@tonic-gate 	if (notification)
37787c478bd9Sstevel@tonic-gate 		gld_notify_ind(macinfo, notification, NULL);
37797c478bd9Sstevel@tonic-gate }
37807c478bd9Sstevel@tonic-gate 
37817c478bd9Sstevel@tonic-gate /*
37827c478bd9Sstevel@tonic-gate  * gld_udqos - set the current QoS parameters (priority only at the moment).
37837c478bd9Sstevel@tonic-gate  */
37847c478bd9Sstevel@tonic-gate static int
37857c478bd9Sstevel@tonic-gate gld_udqos(queue_t *q, mblk_t *mp)
37867c478bd9Sstevel@tonic-gate {
37877c478bd9Sstevel@tonic-gate 	dl_udqos_req_t *dlp;
37887c478bd9Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
37897c478bd9Sstevel@tonic-gate 	int off;
37907c478bd9Sstevel@tonic-gate 	int len;
37917c478bd9Sstevel@tonic-gate 	dl_qos_cl_sel1_t *selp;
37927c478bd9Sstevel@tonic-gate 
37937c478bd9Sstevel@tonic-gate 	ASSERT(gld);
37947c478bd9Sstevel@tonic-gate 	ASSERT(gld->gld_qptr == RD(q));
37957c478bd9Sstevel@tonic-gate 
37967c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
37977c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
37987c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_udqos(%p %p)", (void *)q, (void *)mp);
37997c478bd9Sstevel@tonic-gate #endif
38007c478bd9Sstevel@tonic-gate 
38017c478bd9Sstevel@tonic-gate 	if (gld->gld_state != DL_IDLE) {
38027c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
38037c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
38047c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_udqos: wrong state (%d)",
38057c478bd9Sstevel@tonic-gate 			    gld->gld_state);
38067c478bd9Sstevel@tonic-gate #endif
38077c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
38087c478bd9Sstevel@tonic-gate 	}
38097c478bd9Sstevel@tonic-gate 
38107c478bd9Sstevel@tonic-gate 	dlp = (dl_udqos_req_t *)mp->b_rptr;
38117c478bd9Sstevel@tonic-gate 	off = dlp->dl_qos_offset;
38127c478bd9Sstevel@tonic-gate 	len = dlp->dl_qos_length;
38137c478bd9Sstevel@tonic-gate 
38147c478bd9Sstevel@tonic-gate 	if (len != sizeof (dl_qos_cl_sel1_t) || !MBLKIN(mp, off, len))
38157c478bd9Sstevel@tonic-gate 		return (DL_BADQOSTYPE);
38167c478bd9Sstevel@tonic-gate 
38177c478bd9Sstevel@tonic-gate 	selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off);
38187c478bd9Sstevel@tonic-gate 	if (selp->dl_qos_type != DL_QOS_CL_SEL1)
38197c478bd9Sstevel@tonic-gate 		return (DL_BADQOSTYPE);
38207c478bd9Sstevel@tonic-gate 
38217c478bd9Sstevel@tonic-gate 	if (selp->dl_trans_delay != 0 &&
38227c478bd9Sstevel@tonic-gate 	    selp->dl_trans_delay != DL_QOS_DONT_CARE)
38237c478bd9Sstevel@tonic-gate 		return (DL_BADQOSPARAM);
38247c478bd9Sstevel@tonic-gate 	if (selp->dl_protection != 0 &&
38257c478bd9Sstevel@tonic-gate 	    selp->dl_protection != DL_QOS_DONT_CARE)
38267c478bd9Sstevel@tonic-gate 		return (DL_BADQOSPARAM);
38277c478bd9Sstevel@tonic-gate 	if (selp->dl_residual_error != 0 &&
38287c478bd9Sstevel@tonic-gate 	    selp->dl_residual_error != DL_QOS_DONT_CARE)
38297c478bd9Sstevel@tonic-gate 		return (DL_BADQOSPARAM);
38307c478bd9Sstevel@tonic-gate 	if (selp->dl_priority < 0 || selp->dl_priority > 7)
38317c478bd9Sstevel@tonic-gate 		return (DL_BADQOSPARAM);
38327c478bd9Sstevel@tonic-gate 
38337c478bd9Sstevel@tonic-gate 	gld->gld_upri = selp->dl_priority;
38347c478bd9Sstevel@tonic-gate 
38357c478bd9Sstevel@tonic-gate 	dlokack(q, mp, DL_UDQOS_REQ);
38367c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
38377c478bd9Sstevel@tonic-gate }
38387c478bd9Sstevel@tonic-gate 
38397c478bd9Sstevel@tonic-gate static mblk_t *
38407c478bd9Sstevel@tonic-gate gld_bindack(queue_t *q, mblk_t *mp)
38417c478bd9Sstevel@tonic-gate {
38427c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
38437c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
38447c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
38457c478bd9Sstevel@tonic-gate 	dl_bind_ack_t *dlp;
38467c478bd9Sstevel@tonic-gate 	size_t size;
38477c478bd9Sstevel@tonic-gate 	t_uscalar_t addrlen;
38487c478bd9Sstevel@tonic-gate 	uchar_t *sapp;
38497c478bd9Sstevel@tonic-gate 
38507c478bd9Sstevel@tonic-gate 	addrlen = macinfo->gldm_addrlen + abs(macinfo->gldm_saplen);
38517c478bd9Sstevel@tonic-gate 	size = sizeof (dl_bind_ack_t) + addrlen;
38527c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, size, M_PCPROTO, DL_BIND_ACK)) == NULL)
38537c478bd9Sstevel@tonic-gate 		return (NULL);
38547c478bd9Sstevel@tonic-gate 
38557c478bd9Sstevel@tonic-gate 	dlp = (dl_bind_ack_t *)mp->b_rptr;
38567c478bd9Sstevel@tonic-gate 	dlp->dl_sap = gld->gld_sap;
38577c478bd9Sstevel@tonic-gate 	dlp->dl_addr_length = addrlen;
38587c478bd9Sstevel@tonic-gate 	dlp->dl_addr_offset = sizeof (dl_bind_ack_t);
38597c478bd9Sstevel@tonic-gate 	dlp->dl_max_conind = 0;
38607c478bd9Sstevel@tonic-gate 	dlp->dl_xidtest_flg = 0;
38617c478bd9Sstevel@tonic-gate 
38627c478bd9Sstevel@tonic-gate 	mac_copy(mac_pvt->curr_macaddr, (uchar_t *)&dlp[1],
38637c478bd9Sstevel@tonic-gate 	    macinfo->gldm_addrlen);
38647c478bd9Sstevel@tonic-gate 	sapp = mp->b_rptr + dlp->dl_addr_offset + macinfo->gldm_addrlen;
38657c478bd9Sstevel@tonic-gate 	*(ushort_t *)sapp = gld->gld_sap;
38667c478bd9Sstevel@tonic-gate 
38677c478bd9Sstevel@tonic-gate 	return (mp);
38687c478bd9Sstevel@tonic-gate }
38697c478bd9Sstevel@tonic-gate 
38707c478bd9Sstevel@tonic-gate /*
38717c478bd9Sstevel@tonic-gate  * gld_bind - determine if a SAP is already allocated and whether it is legal
38727c478bd9Sstevel@tonic-gate  * to do the bind at this time
38737c478bd9Sstevel@tonic-gate  */
38747c478bd9Sstevel@tonic-gate static int
38757c478bd9Sstevel@tonic-gate gld_bind(queue_t *q, mblk_t *mp)
38767c478bd9Sstevel@tonic-gate {
38777c478bd9Sstevel@tonic-gate 	ulong_t	sap;
38787c478bd9Sstevel@tonic-gate 	dl_bind_req_t *dlp;
38797c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
38807c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
38817c478bd9Sstevel@tonic-gate 
38827c478bd9Sstevel@tonic-gate 	ASSERT(gld);
38837c478bd9Sstevel@tonic-gate 	ASSERT(gld->gld_qptr == RD(q));
38847c478bd9Sstevel@tonic-gate 
38857c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
38867c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
38877c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_bind(%p %p)", (void *)q, (void *)mp);
38887c478bd9Sstevel@tonic-gate #endif
38897c478bd9Sstevel@tonic-gate 
38907c478bd9Sstevel@tonic-gate 	dlp = (dl_bind_req_t *)mp->b_rptr;
38917c478bd9Sstevel@tonic-gate 	sap = dlp->dl_sap;
38927c478bd9Sstevel@tonic-gate 
38937c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
38947c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT)
38957c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_bind: lsap=%lx", sap);
38967c478bd9Sstevel@tonic-gate #endif
38977c478bd9Sstevel@tonic-gate 
38987c478bd9Sstevel@tonic-gate 	if (gld->gld_state != DL_UNBOUND) {
38997c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
39007c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
39017c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_bind: bound or not attached (%d)",
39027c478bd9Sstevel@tonic-gate 				gld->gld_state);
39037c478bd9Sstevel@tonic-gate #endif
39047c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
39057c478bd9Sstevel@tonic-gate 	}
39067c478bd9Sstevel@tonic-gate 	ASSERT(macinfo);
39077c478bd9Sstevel@tonic-gate 
39087c478bd9Sstevel@tonic-gate 	if (dlp->dl_service_mode != DL_CLDLS) {
39097c478bd9Sstevel@tonic-gate 		return (DL_UNSUPPORTED);
39107c478bd9Sstevel@tonic-gate 	}
39117c478bd9Sstevel@tonic-gate 	if (dlp->dl_xidtest_flg & (DL_AUTO_XID | DL_AUTO_TEST)) {
39127c478bd9Sstevel@tonic-gate 		return (DL_NOAUTO);
39137c478bd9Sstevel@tonic-gate 	}
39147c478bd9Sstevel@tonic-gate 
39157c478bd9Sstevel@tonic-gate 	/*
39167c478bd9Sstevel@tonic-gate 	 * Check sap validity and decide whether this stream accepts
39177c478bd9Sstevel@tonic-gate 	 * IEEE 802.2 (LLC) packets.
39187c478bd9Sstevel@tonic-gate 	 */
39197c478bd9Sstevel@tonic-gate 	if (sap > ETHERTYPE_MAX)
39207c478bd9Sstevel@tonic-gate 		return (DL_BADSAP);
39217c478bd9Sstevel@tonic-gate 
39227c478bd9Sstevel@tonic-gate 	/*
39237c478bd9Sstevel@tonic-gate 	 * Decide whether the SAP value selects EtherType encoding/decoding.
39247c478bd9Sstevel@tonic-gate 	 * For compatibility with monolithic ethernet drivers, the range of
39257c478bd9Sstevel@tonic-gate 	 * SAP values is different for DL_ETHER media.
39267c478bd9Sstevel@tonic-gate 	 */
39277c478bd9Sstevel@tonic-gate 	switch (macinfo->gldm_type) {
39287c478bd9Sstevel@tonic-gate 	case DL_ETHER:
39297c478bd9Sstevel@tonic-gate 		gld->gld_ethertype = (sap > ETHERMTU);
39307c478bd9Sstevel@tonic-gate 		break;
39317c478bd9Sstevel@tonic-gate 	default:
39327c478bd9Sstevel@tonic-gate 		gld->gld_ethertype = (sap > GLD_MAX_802_SAP);
39337c478bd9Sstevel@tonic-gate 		break;
39347c478bd9Sstevel@tonic-gate 	}
39357c478bd9Sstevel@tonic-gate 
39367c478bd9Sstevel@tonic-gate 	/* if we get to here, then the SAP is legal enough */
39377c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
39387c478bd9Sstevel@tonic-gate 	gld->gld_state = DL_IDLE;	/* bound and ready */
39397c478bd9Sstevel@tonic-gate 	gld->gld_sap = sap;
39407c478bd9Sstevel@tonic-gate 	gld_set_ipq(gld);
39417c478bd9Sstevel@tonic-gate 
39427c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
39437c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT)
39447c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_bind: ok - sap = %d", gld->gld_sap);
39457c478bd9Sstevel@tonic-gate #endif
39467c478bd9Sstevel@tonic-gate 
39477c478bd9Sstevel@tonic-gate 	/* ACK the BIND */
39487c478bd9Sstevel@tonic-gate 	mp = gld_bindack(q, mp);
39497c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
39507c478bd9Sstevel@tonic-gate 
39517c478bd9Sstevel@tonic-gate 	if (mp != NULL) {
39527c478bd9Sstevel@tonic-gate 		qreply(q, mp);
39537c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
39547c478bd9Sstevel@tonic-gate 	}
39557c478bd9Sstevel@tonic-gate 
39567c478bd9Sstevel@tonic-gate 	return (DL_SYSERR);
39577c478bd9Sstevel@tonic-gate }
39587c478bd9Sstevel@tonic-gate 
39597c478bd9Sstevel@tonic-gate /*
39607c478bd9Sstevel@tonic-gate  * gld_unbind - perform an unbind of an LSAP or ether type on the stream.
39617c478bd9Sstevel@tonic-gate  * The stream is still open and can be re-bound.
39627c478bd9Sstevel@tonic-gate  */
39637c478bd9Sstevel@tonic-gate static int
39647c478bd9Sstevel@tonic-gate gld_unbind(queue_t *q, mblk_t *mp)
39657c478bd9Sstevel@tonic-gate {
39667c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
39677c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
39687c478bd9Sstevel@tonic-gate 
39697c478bd9Sstevel@tonic-gate 	ASSERT(gld);
39707c478bd9Sstevel@tonic-gate 
39717c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
39727c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
39737c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_unbind(%p %p)", (void *)q, (void *)mp);
39747c478bd9Sstevel@tonic-gate #endif
39757c478bd9Sstevel@tonic-gate 
39767c478bd9Sstevel@tonic-gate 	if (gld->gld_state != DL_IDLE) {
39777c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
39787c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
39797c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unbind: wrong state (%d)",
39807c478bd9Sstevel@tonic-gate 				gld->gld_state);
39817c478bd9Sstevel@tonic-gate #endif
39827c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
39837c478bd9Sstevel@tonic-gate 	}
39847c478bd9Sstevel@tonic-gate 	ASSERT(macinfo);
39857c478bd9Sstevel@tonic-gate 
39867c478bd9Sstevel@tonic-gate 	/*
39877c478bd9Sstevel@tonic-gate 	 * Avoid unbinding (DL_UNBIND_REQ) while FAST/RAW is inside wput.
39887c478bd9Sstevel@tonic-gate 	 * See comments above gld_start().
39897c478bd9Sstevel@tonic-gate 	 */
39907c478bd9Sstevel@tonic-gate 	gld->gld_in_unbind = B_TRUE;	/* disallow wput=>start */
39917c478bd9Sstevel@tonic-gate 	membar_enter();
39927c478bd9Sstevel@tonic-gate 	if (gld->gld_wput_count != 0) {
39937c478bd9Sstevel@tonic-gate 		gld->gld_in_unbind = B_FALSE;
39947c478bd9Sstevel@tonic-gate 		ASSERT(mp);		/* we didn't come from close */
39957c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
39967c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDETRACE)
39977c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unbind: defer for wput");
39987c478bd9Sstevel@tonic-gate #endif
39997c478bd9Sstevel@tonic-gate 		(void) putbq(q, mp);
40007c478bd9Sstevel@tonic-gate 		qenable(q);		/* try again soon */
40017c478bd9Sstevel@tonic-gate 		return (GLDE_RETRY);
40027c478bd9Sstevel@tonic-gate 	}
40037c478bd9Sstevel@tonic-gate 
40047c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
40057c478bd9Sstevel@tonic-gate 	gld->gld_state = DL_UNBOUND;
40067c478bd9Sstevel@tonic-gate 	gld->gld_sap = 0;
40077c478bd9Sstevel@tonic-gate 	gld_set_ipq(gld);
40087c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
40097c478bd9Sstevel@tonic-gate 
40107c478bd9Sstevel@tonic-gate 	membar_exit();
40117c478bd9Sstevel@tonic-gate 	gld->gld_in_unbind = B_FALSE;
40127c478bd9Sstevel@tonic-gate 
40137c478bd9Sstevel@tonic-gate 	/* mp is NULL if we came from close */
40147c478bd9Sstevel@tonic-gate 	if (mp) {
40157c478bd9Sstevel@tonic-gate 		gld_flushqueue(q);	/* flush the queues */
40167c478bd9Sstevel@tonic-gate 		dlokack(q, mp, DL_UNBIND_REQ);
40177c478bd9Sstevel@tonic-gate 	}
40187c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
40197c478bd9Sstevel@tonic-gate }
40207c478bd9Sstevel@tonic-gate 
40217c478bd9Sstevel@tonic-gate /*
40227c478bd9Sstevel@tonic-gate  * gld_inforeq - generate the response to an info request
40237c478bd9Sstevel@tonic-gate  */
40247c478bd9Sstevel@tonic-gate static int
40257c478bd9Sstevel@tonic-gate gld_inforeq(queue_t *q, mblk_t *mp)
40267c478bd9Sstevel@tonic-gate {
40277c478bd9Sstevel@tonic-gate 	gld_t		*gld;
40287c478bd9Sstevel@tonic-gate 	dl_info_ack_t	*dlp;
40297c478bd9Sstevel@tonic-gate 	int		bufsize;
40307c478bd9Sstevel@tonic-gate 	glddev_t	*glddev;
40317c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*macinfo;
40327c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt;
40337c478bd9Sstevel@tonic-gate 	int		sel_offset = 0;
40347c478bd9Sstevel@tonic-gate 	int		range_offset = 0;
40357c478bd9Sstevel@tonic-gate 	int		addr_offset;
40367c478bd9Sstevel@tonic-gate 	int		addr_length;
40377c478bd9Sstevel@tonic-gate 	int		sap_length;
40387c478bd9Sstevel@tonic-gate 	int		brdcst_offset;
40397c478bd9Sstevel@tonic-gate 	int		brdcst_length;
40407c478bd9Sstevel@tonic-gate 	gld_vlan_t	*vlan;
40417c478bd9Sstevel@tonic-gate 	uchar_t		*sapp;
40427c478bd9Sstevel@tonic-gate 
40437c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
40447c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
40457c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_inforeq(%p %p)", (void *)q, (void *)mp);
40467c478bd9Sstevel@tonic-gate #endif
40477c478bd9Sstevel@tonic-gate 	gld = (gld_t *)q->q_ptr;
40487c478bd9Sstevel@tonic-gate 	ASSERT(gld);
40497c478bd9Sstevel@tonic-gate 	glddev = gld->gld_device;
40507c478bd9Sstevel@tonic-gate 	ASSERT(glddev);
40517c478bd9Sstevel@tonic-gate 
40527c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_IDLE || gld->gld_state == DL_UNBOUND) {
40537c478bd9Sstevel@tonic-gate 		macinfo = gld->gld_mac_info;
40547c478bd9Sstevel@tonic-gate 		ASSERT(macinfo != NULL);
40557c478bd9Sstevel@tonic-gate 
40567c478bd9Sstevel@tonic-gate 		mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
40577c478bd9Sstevel@tonic-gate 
40587c478bd9Sstevel@tonic-gate 		addr_length = macinfo->gldm_addrlen;
40597c478bd9Sstevel@tonic-gate 		sap_length = macinfo->gldm_saplen;
40607c478bd9Sstevel@tonic-gate 		brdcst_length = macinfo->gldm_addrlen;
40617c478bd9Sstevel@tonic-gate 	} else {
40627c478bd9Sstevel@tonic-gate 		addr_length = glddev->gld_addrlen;
40637c478bd9Sstevel@tonic-gate 		sap_length = glddev->gld_saplen;
40647c478bd9Sstevel@tonic-gate 		brdcst_length = glddev->gld_addrlen;
40657c478bd9Sstevel@tonic-gate 	}
40667c478bd9Sstevel@tonic-gate 
40677c478bd9Sstevel@tonic-gate 	bufsize = sizeof (dl_info_ack_t);
40687c478bd9Sstevel@tonic-gate 
40697c478bd9Sstevel@tonic-gate 	addr_offset = bufsize;
40707c478bd9Sstevel@tonic-gate 	bufsize += addr_length;
40717c478bd9Sstevel@tonic-gate 	bufsize += abs(sap_length);
40727c478bd9Sstevel@tonic-gate 
40737c478bd9Sstevel@tonic-gate 	brdcst_offset = bufsize;
40747c478bd9Sstevel@tonic-gate 	bufsize += brdcst_length;
40757c478bd9Sstevel@tonic-gate 
40767c478bd9Sstevel@tonic-gate 	if ((vlan = (gld_vlan_t *)gld->gld_vlan) != NULL &&
40777c478bd9Sstevel@tonic-gate 	    vlan->gldv_id != VLAN_VID_NONE) {
40787c478bd9Sstevel@tonic-gate 		sel_offset = P2ROUNDUP(bufsize, sizeof (int64_t));
40797c478bd9Sstevel@tonic-gate 		bufsize = sel_offset + sizeof (dl_qos_cl_sel1_t);
40807c478bd9Sstevel@tonic-gate 
40817c478bd9Sstevel@tonic-gate 		range_offset = P2ROUNDUP(bufsize, sizeof (int64_t));
40827c478bd9Sstevel@tonic-gate 		bufsize = range_offset + sizeof (dl_qos_cl_range1_t);
40837c478bd9Sstevel@tonic-gate 	}
40847c478bd9Sstevel@tonic-gate 
40857c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, bufsize, M_PCPROTO, DL_INFO_ACK)) == NULL)
40867c478bd9Sstevel@tonic-gate 		return (GLDE_OK);	/* nothing more to be done */
40877c478bd9Sstevel@tonic-gate 
40887c478bd9Sstevel@tonic-gate 	bzero(mp->b_rptr, bufsize);
40897c478bd9Sstevel@tonic-gate 
40907c478bd9Sstevel@tonic-gate 	dlp = (dl_info_ack_t *)mp->b_rptr;
40917c478bd9Sstevel@tonic-gate 	dlp->dl_primitive = DL_INFO_ACK;
40927c478bd9Sstevel@tonic-gate 	dlp->dl_version = DL_VERSION_2;
40937c478bd9Sstevel@tonic-gate 	dlp->dl_service_mode = DL_CLDLS;
40947c478bd9Sstevel@tonic-gate 	dlp->dl_current_state = gld->gld_state;
40957c478bd9Sstevel@tonic-gate 	dlp->dl_provider_style = gld->gld_style;
40967c478bd9Sstevel@tonic-gate 
40977c478bd9Sstevel@tonic-gate 	if (sel_offset != 0) {
40987c478bd9Sstevel@tonic-gate 		dl_qos_cl_sel1_t	*selp;
40997c478bd9Sstevel@tonic-gate 		dl_qos_cl_range1_t	*rangep;
41007c478bd9Sstevel@tonic-gate 
41017c478bd9Sstevel@tonic-gate 		ASSERT(range_offset != 0);
41027c478bd9Sstevel@tonic-gate 
41037c478bd9Sstevel@tonic-gate 		dlp->dl_qos_offset = sel_offset;
41047c478bd9Sstevel@tonic-gate 		dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t);
41057c478bd9Sstevel@tonic-gate 		dlp->dl_qos_range_offset = range_offset;
41067c478bd9Sstevel@tonic-gate 		dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t);
41077c478bd9Sstevel@tonic-gate 
41087c478bd9Sstevel@tonic-gate 		selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + sel_offset);
41097c478bd9Sstevel@tonic-gate 		selp->dl_qos_type = DL_QOS_CL_SEL1;
41107c478bd9Sstevel@tonic-gate 		selp->dl_priority = gld->gld_upri;
41117c478bd9Sstevel@tonic-gate 
41127c478bd9Sstevel@tonic-gate 		rangep = (dl_qos_cl_range1_t *)(mp->b_rptr + range_offset);
41137c478bd9Sstevel@tonic-gate 		rangep->dl_qos_type = DL_QOS_CL_RANGE1;
41147c478bd9Sstevel@tonic-gate 		rangep->dl_priority.dl_min = 0;
41157c478bd9Sstevel@tonic-gate 		rangep->dl_priority.dl_max = 7;
41167c478bd9Sstevel@tonic-gate 	}
41177c478bd9Sstevel@tonic-gate 
41187c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_IDLE || gld->gld_state == DL_UNBOUND) {
41197c478bd9Sstevel@tonic-gate 		dlp->dl_min_sdu = macinfo->gldm_minpkt;
41207c478bd9Sstevel@tonic-gate 		dlp->dl_max_sdu = macinfo->gldm_maxpkt;
41217c478bd9Sstevel@tonic-gate 		dlp->dl_mac_type = macinfo->gldm_type;
41227c478bd9Sstevel@tonic-gate 		dlp->dl_addr_length = addr_length + abs(sap_length);
41237c478bd9Sstevel@tonic-gate 		dlp->dl_sap_length = sap_length;
41247c478bd9Sstevel@tonic-gate 
41257c478bd9Sstevel@tonic-gate 		if (gld->gld_state == DL_IDLE) {
41267c478bd9Sstevel@tonic-gate 			/*
41277c478bd9Sstevel@tonic-gate 			 * If we are bound to a non-LLC SAP on any medium
41287c478bd9Sstevel@tonic-gate 			 * other than Ethernet, then we need room for a
41297c478bd9Sstevel@tonic-gate 			 * SNAP header.  So we have to adjust the MTU size
41307c478bd9Sstevel@tonic-gate 			 * accordingly.  XXX I suppose this should be done
41317c478bd9Sstevel@tonic-gate 			 * in gldutil.c, but it seems likely that this will
41327c478bd9Sstevel@tonic-gate 			 * always be true for everything GLD supports but
41337c478bd9Sstevel@tonic-gate 			 * Ethernet.  Check this if you add another medium.
41347c478bd9Sstevel@tonic-gate 			 */
41357c478bd9Sstevel@tonic-gate 			if ((macinfo->gldm_type == DL_TPR ||
41367c478bd9Sstevel@tonic-gate 			    macinfo->gldm_type == DL_FDDI) &&
41377c478bd9Sstevel@tonic-gate 			    gld->gld_ethertype)
41387c478bd9Sstevel@tonic-gate 				dlp->dl_max_sdu -= LLC_SNAP_HDR_LEN;
41397c478bd9Sstevel@tonic-gate 
41407c478bd9Sstevel@tonic-gate 			/* copy macaddr and sap */
41417c478bd9Sstevel@tonic-gate 			dlp->dl_addr_offset = addr_offset;
41427c478bd9Sstevel@tonic-gate 
41437c478bd9Sstevel@tonic-gate 			mac_copy(mac_pvt->curr_macaddr, mp->b_rptr +
41447c478bd9Sstevel@tonic-gate 			    addr_offset, macinfo->gldm_addrlen);
41457c478bd9Sstevel@tonic-gate 			sapp = mp->b_rptr + addr_offset +
41467c478bd9Sstevel@tonic-gate 			    macinfo->gldm_addrlen;
41477c478bd9Sstevel@tonic-gate 			*(ushort_t *)sapp = gld->gld_sap;
41487c478bd9Sstevel@tonic-gate 		} else {
41497c478bd9Sstevel@tonic-gate 			dlp->dl_addr_offset = 0;
41507c478bd9Sstevel@tonic-gate 		}
41517c478bd9Sstevel@tonic-gate 
41527c478bd9Sstevel@tonic-gate 		/* copy broadcast addr */
41537c478bd9Sstevel@tonic-gate 		dlp->dl_brdcst_addr_length = macinfo->gldm_addrlen;
41547c478bd9Sstevel@tonic-gate 		dlp->dl_brdcst_addr_offset = brdcst_offset;
41557c478bd9Sstevel@tonic-gate 		mac_copy((caddr_t)macinfo->gldm_broadcast_addr,
41567c478bd9Sstevel@tonic-gate 		    mp->b_rptr + brdcst_offset, brdcst_length);
41577c478bd9Sstevel@tonic-gate 	} else {
41587c478bd9Sstevel@tonic-gate 		/*
41597c478bd9Sstevel@tonic-gate 		 * No PPA is attached.
41607c478bd9Sstevel@tonic-gate 		 * The best we can do is use the values provided
41617c478bd9Sstevel@tonic-gate 		 * by the first mac that called gld_register.
41627c478bd9Sstevel@tonic-gate 		 */
41637c478bd9Sstevel@tonic-gate 		dlp->dl_min_sdu = glddev->gld_minsdu;
41647c478bd9Sstevel@tonic-gate 		dlp->dl_max_sdu = glddev->gld_maxsdu;
41657c478bd9Sstevel@tonic-gate 		dlp->dl_mac_type = glddev->gld_type;
41667c478bd9Sstevel@tonic-gate 		dlp->dl_addr_length = addr_length + abs(sap_length);
41677c478bd9Sstevel@tonic-gate 		dlp->dl_sap_length = sap_length;
41687c478bd9Sstevel@tonic-gate 		dlp->dl_addr_offset = 0;
41697c478bd9Sstevel@tonic-gate 		dlp->dl_brdcst_addr_offset = brdcst_offset;
41707c478bd9Sstevel@tonic-gate 		dlp->dl_brdcst_addr_length = brdcst_length;
41717c478bd9Sstevel@tonic-gate 		mac_copy((caddr_t)glddev->gld_broadcast,
41727c478bd9Sstevel@tonic-gate 		    mp->b_rptr + brdcst_offset, brdcst_length);
41737c478bd9Sstevel@tonic-gate 	}
41747c478bd9Sstevel@tonic-gate 	qreply(q, mp);
41757c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
41767c478bd9Sstevel@tonic-gate }
41777c478bd9Sstevel@tonic-gate 
41787c478bd9Sstevel@tonic-gate /*
41797c478bd9Sstevel@tonic-gate  * gld_unitdata (q, mp)
41807c478bd9Sstevel@tonic-gate  * send a datagram.  Destination address/lsap is in M_PROTO
41817c478bd9Sstevel@tonic-gate  * message (first mblock), data is in remainder of message.
41827c478bd9Sstevel@tonic-gate  *
41837c478bd9Sstevel@tonic-gate  */
41847c478bd9Sstevel@tonic-gate static int
41857c478bd9Sstevel@tonic-gate gld_unitdata(queue_t *q, mblk_t *mp)
41867c478bd9Sstevel@tonic-gate {
41877c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
41887c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
41897c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
41907c478bd9Sstevel@tonic-gate 	size_t	msglen;
41917c478bd9Sstevel@tonic-gate 	mblk_t	*nmp;
41927c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
41937c478bd9Sstevel@tonic-gate 	uint32_t start;
41947c478bd9Sstevel@tonic-gate 	uint32_t stuff;
41957c478bd9Sstevel@tonic-gate 	uint32_t end;
41967c478bd9Sstevel@tonic-gate 	uint32_t value;
41977c478bd9Sstevel@tonic-gate 	uint32_t flags;
41987c478bd9Sstevel@tonic-gate 	uint32_t upri;
41997c478bd9Sstevel@tonic-gate 
42007c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
42017c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
42027c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_unitdata(%p %p)", (void *)q, (void *)mp);
42037c478bd9Sstevel@tonic-gate #endif
42047c478bd9Sstevel@tonic-gate 
42057c478bd9Sstevel@tonic-gate 	if (gld->gld_state != DL_IDLE) {
42067c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
42077c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
42087c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unitdata: wrong state (%d)",
42097c478bd9Sstevel@tonic-gate 				gld->gld_state);
42107c478bd9Sstevel@tonic-gate #endif
42117c478bd9Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
42127c478bd9Sstevel@tonic-gate 		    dlp->dl_dest_addr_length, DL_OUTSTATE, 0);
42137c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
42147c478bd9Sstevel@tonic-gate 	}
42157c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
42167c478bd9Sstevel@tonic-gate 
42177c478bd9Sstevel@tonic-gate 	if (!MBLKIN(mp, dlp->dl_dest_addr_offset, dlp->dl_dest_addr_length) ||
42187c478bd9Sstevel@tonic-gate 	    dlp->dl_dest_addr_length !=
42197c478bd9Sstevel@tonic-gate 	    macinfo->gldm_addrlen + abs(macinfo->gldm_saplen)) {
42207c478bd9Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
42217c478bd9Sstevel@tonic-gate 		    dlp->dl_dest_addr_length, DL_BADADDR, 0);
42227c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
42237c478bd9Sstevel@tonic-gate 	}
42247c478bd9Sstevel@tonic-gate 
42257c478bd9Sstevel@tonic-gate 	upri = dlp->dl_priority.dl_max;
42267c478bd9Sstevel@tonic-gate 
42277c478bd9Sstevel@tonic-gate 	msglen = msgdsize(mp);
42287c478bd9Sstevel@tonic-gate 	if (msglen == 0 || msglen > macinfo->gldm_maxpkt) {
42297c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
42307c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
42317c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unitdata: bad msglen (%d)",
42327c478bd9Sstevel@tonic-gate 				(int)msglen);
42337c478bd9Sstevel@tonic-gate #endif
42347c478bd9Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
42357c478bd9Sstevel@tonic-gate 		    dlp->dl_dest_addr_length, DL_BADDATA, 0);
42367c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
42377c478bd9Sstevel@tonic-gate 	}
42387c478bd9Sstevel@tonic-gate 
42397c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_cont != NULL);	/* because msgdsize(mp) is nonzero */
42407c478bd9Sstevel@tonic-gate 
42417c478bd9Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
42427c478bd9Sstevel@tonic-gate 
42437c478bd9Sstevel@tonic-gate 	/* grab any checksum information that may be present */
42447c478bd9Sstevel@tonic-gate 	hcksum_retrieve(mp->b_cont, NULL, NULL, &start, &stuff, &end,
42457c478bd9Sstevel@tonic-gate 	    &value, &flags);
42467c478bd9Sstevel@tonic-gate 
42477c478bd9Sstevel@tonic-gate 	/*
42487c478bd9Sstevel@tonic-gate 	 * Prepend a valid header for transmission
42497c478bd9Sstevel@tonic-gate 	 */
42507c478bd9Sstevel@tonic-gate 	if ((nmp = (*ifp->mkunitdata)(gld, mp)) == NULL) {
42517c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
42527c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
42537c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unitdata: mkunitdata failed.");
42547c478bd9Sstevel@tonic-gate #endif
42557c478bd9Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
42567c478bd9Sstevel@tonic-gate 		    dlp->dl_dest_addr_length, DL_SYSERR, ENOSR);
42577c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
42587c478bd9Sstevel@tonic-gate 	}
42597c478bd9Sstevel@tonic-gate 
42607c478bd9Sstevel@tonic-gate 	/* apply any checksum information to the first block in the chain */
42617c478bd9Sstevel@tonic-gate 	(void) hcksum_assoc(nmp, NULL, NULL, start, stuff, end, value,
42627c478bd9Sstevel@tonic-gate 	    flags, 0);
42637c478bd9Sstevel@tonic-gate 
42647c478bd9Sstevel@tonic-gate 	if (gld_start(q, nmp, GLD_WSRV, upri) == GLD_NORESOURCES) {
42657c478bd9Sstevel@tonic-gate 		qenable(q);
42667c478bd9Sstevel@tonic-gate 		return (GLDE_RETRY);
42677c478bd9Sstevel@tonic-gate 	}
42687c478bd9Sstevel@tonic-gate 
42697c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
42707c478bd9Sstevel@tonic-gate }
42717c478bd9Sstevel@tonic-gate 
42727c478bd9Sstevel@tonic-gate /*
42737c478bd9Sstevel@tonic-gate  * gldattach(q, mp)
42747c478bd9Sstevel@tonic-gate  * DLPI DL_ATTACH_REQ
42757c478bd9Sstevel@tonic-gate  * this attaches the stream to a PPA
42767c478bd9Sstevel@tonic-gate  */
42777c478bd9Sstevel@tonic-gate static int
42787c478bd9Sstevel@tonic-gate gldattach(queue_t *q, mblk_t *mp)
42797c478bd9Sstevel@tonic-gate {
42807c478bd9Sstevel@tonic-gate 	dl_attach_req_t *at;
42817c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
42827c478bd9Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
42837c478bd9Sstevel@tonic-gate 	glddev_t *glddev;
42847c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
42857c478bd9Sstevel@tonic-gate 	uint32_t ppa;
42867c478bd9Sstevel@tonic-gate 	uint32_t vid;
42877c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
42887c478bd9Sstevel@tonic-gate 
42897c478bd9Sstevel@tonic-gate 	at = (dl_attach_req_t *)mp->b_rptr;
42907c478bd9Sstevel@tonic-gate 
42917c478bd9Sstevel@tonic-gate 	if (gld->gld_state != DL_UNATTACHED)
42927c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
42937c478bd9Sstevel@tonic-gate 
42947c478bd9Sstevel@tonic-gate 	ASSERT(!gld->gld_mac_info);
42957c478bd9Sstevel@tonic-gate 
42967c478bd9Sstevel@tonic-gate 	ppa = at->dl_ppa % GLD_VLAN_SCALE;	/* 0 .. 999	*/
42977c478bd9Sstevel@tonic-gate 	vid = at->dl_ppa / GLD_VLAN_SCALE;	/* 0 .. 4094	*/
42987c478bd9Sstevel@tonic-gate 	if (vid > VLAN_VID_MAX)
42997c478bd9Sstevel@tonic-gate 		return (DL_BADPPA);
43007c478bd9Sstevel@tonic-gate 
43017c478bd9Sstevel@tonic-gate 	glddev = gld->gld_device;
43027c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
43037c478bd9Sstevel@tonic-gate 	for (macinfo = glddev->gld_mac_next;
43047c478bd9Sstevel@tonic-gate 	    macinfo != (gld_mac_info_t *)&glddev->gld_mac_next;
43057c478bd9Sstevel@tonic-gate 	    macinfo = macinfo->gldm_next) {
43067c478bd9Sstevel@tonic-gate 		int inst;
43077c478bd9Sstevel@tonic-gate 
43087c478bd9Sstevel@tonic-gate 		ASSERT(macinfo != NULL);
43097c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_ppa != ppa)
43107c478bd9Sstevel@tonic-gate 			continue;
43117c478bd9Sstevel@tonic-gate 
43127c478bd9Sstevel@tonic-gate 		if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY))
43137c478bd9Sstevel@tonic-gate 			continue;	/* this one's not ready yet */
43147c478bd9Sstevel@tonic-gate 
43157c478bd9Sstevel@tonic-gate 		/*
43167c478bd9Sstevel@tonic-gate 		 * VLAN sanity check
43177c478bd9Sstevel@tonic-gate 		 */
43187c478bd9Sstevel@tonic-gate 		if (vid != VLAN_VID_NONE && !VLAN_CAPABLE(macinfo)) {
43197c478bd9Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
43207c478bd9Sstevel@tonic-gate 			return (DL_BADPPA);
43217c478bd9Sstevel@tonic-gate 		}
43227c478bd9Sstevel@tonic-gate 
43237c478bd9Sstevel@tonic-gate 		/*
43247c478bd9Sstevel@tonic-gate 		 * We found the correct PPA, hold the instance
43257c478bd9Sstevel@tonic-gate 		 */
43267c478bd9Sstevel@tonic-gate 		inst = ddi_get_instance(macinfo->gldm_devinfo);
43277c478bd9Sstevel@tonic-gate 		if (inst == -1 || qassociate(q, inst) != 0) {
43287c478bd9Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
43297c478bd9Sstevel@tonic-gate 			return (DL_BADPPA);
43307c478bd9Sstevel@tonic-gate 		}
43317c478bd9Sstevel@tonic-gate 
43327c478bd9Sstevel@tonic-gate 		/* Take the stream off the per-driver-class list */
43337c478bd9Sstevel@tonic-gate 		gldremque(gld);
43347c478bd9Sstevel@tonic-gate 
43357c478bd9Sstevel@tonic-gate 		/*
43367c478bd9Sstevel@tonic-gate 		 * We must hold the lock to prevent multiple calls
43377c478bd9Sstevel@tonic-gate 		 * to the reset and start routines.
43387c478bd9Sstevel@tonic-gate 		 */
43397c478bd9Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
43407c478bd9Sstevel@tonic-gate 
43417c478bd9Sstevel@tonic-gate 		gld->gld_mac_info = macinfo;
43427c478bd9Sstevel@tonic-gate 
43437c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_send_tagged != NULL)
43447c478bd9Sstevel@tonic-gate 			gld->gld_send = macinfo->gldm_send_tagged;
43457c478bd9Sstevel@tonic-gate 		else
43467c478bd9Sstevel@tonic-gate 			gld->gld_send = macinfo->gldm_send;
43477c478bd9Sstevel@tonic-gate 
43487c478bd9Sstevel@tonic-gate 		if ((vlan = gld_get_vlan(macinfo, vid)) == NULL) {
43497c478bd9Sstevel@tonic-gate 			GLDM_UNLOCK(macinfo);
43507c478bd9Sstevel@tonic-gate 			gldinsque(gld, glddev->gld_str_prev);
43517c478bd9Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
43527c478bd9Sstevel@tonic-gate 			(void) qassociate(q, -1);
43537c478bd9Sstevel@tonic-gate 			return (DL_BADPPA);
43547c478bd9Sstevel@tonic-gate 		}
43557c478bd9Sstevel@tonic-gate 
43567c478bd9Sstevel@tonic-gate 		mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
43577c478bd9Sstevel@tonic-gate 		if (!mac_pvt->started) {
43587c478bd9Sstevel@tonic-gate 			if (gld_start_mac(macinfo) != GLD_SUCCESS) {
43597c478bd9Sstevel@tonic-gate 				gld_rem_vlan(vlan);
43607c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
43617c478bd9Sstevel@tonic-gate 				gldinsque(gld, glddev->gld_str_prev);
43627c478bd9Sstevel@tonic-gate 				mutex_exit(&glddev->gld_devlock);
43637c478bd9Sstevel@tonic-gate 				dlerrorack(q, mp, DL_ATTACH_REQ, DL_SYSERR,
43647c478bd9Sstevel@tonic-gate 				    EIO);
43657c478bd9Sstevel@tonic-gate 				(void) qassociate(q, -1);
43667c478bd9Sstevel@tonic-gate 				return (GLDE_OK);
43677c478bd9Sstevel@tonic-gate 			}
43687c478bd9Sstevel@tonic-gate 		}
43697c478bd9Sstevel@tonic-gate 
43707c478bd9Sstevel@tonic-gate 		gld->gld_vlan = vlan;
43717c478bd9Sstevel@tonic-gate 		vlan->gldv_nstreams++;
43727c478bd9Sstevel@tonic-gate 		gldinsque(gld, vlan->gldv_str_prev);
43737c478bd9Sstevel@tonic-gate 		gld->gld_state = DL_UNBOUND;
43747c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
43757c478bd9Sstevel@tonic-gate 
43767c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
43777c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDPROT) {
43787c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gldattach(%p, %p, PPA = %d)",
43797c478bd9Sstevel@tonic-gate 			    (void *)q, (void *)mp, macinfo->gldm_ppa);
43807c478bd9Sstevel@tonic-gate 		}
43817c478bd9Sstevel@tonic-gate #endif
43827c478bd9Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
43837c478bd9Sstevel@tonic-gate 		dlokack(q, mp, DL_ATTACH_REQ);
43847c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
43857c478bd9Sstevel@tonic-gate 	}
43867c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
43877c478bd9Sstevel@tonic-gate 	return (DL_BADPPA);
43887c478bd9Sstevel@tonic-gate }
43897c478bd9Sstevel@tonic-gate 
43907c478bd9Sstevel@tonic-gate /*
43917c478bd9Sstevel@tonic-gate  * gldunattach(q, mp)
43927c478bd9Sstevel@tonic-gate  * DLPI DL_DETACH_REQ
43937c478bd9Sstevel@tonic-gate  * detaches the mac layer from the stream
43947c478bd9Sstevel@tonic-gate  */
43957c478bd9Sstevel@tonic-gate int
43967c478bd9Sstevel@tonic-gate gldunattach(queue_t *q, mblk_t *mp)
43977c478bd9Sstevel@tonic-gate {
43987c478bd9Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
43997c478bd9Sstevel@tonic-gate 	glddev_t *glddev = gld->gld_device;
44007c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
44017c478bd9Sstevel@tonic-gate 	int	state = gld->gld_state;
44027c478bd9Sstevel@tonic-gate 	int	i;
44037c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
44047c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
44057c478bd9Sstevel@tonic-gate 	boolean_t phys_off;
44067c478bd9Sstevel@tonic-gate 	boolean_t mult_off;
44077c478bd9Sstevel@tonic-gate 	int op = GLD_MAC_PROMISC_NOOP;
44087c478bd9Sstevel@tonic-gate 
44097c478bd9Sstevel@tonic-gate 	if (state != DL_UNBOUND)
44107c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
44117c478bd9Sstevel@tonic-gate 
44127c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
44137c478bd9Sstevel@tonic-gate 	ASSERT(gld->gld_sap == 0);
44147c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
44157c478bd9Sstevel@tonic-gate 
44167c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
44177c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
44187c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gldunattach(%p, %p, PPA = %d)",
44197c478bd9Sstevel@tonic-gate 		    (void *)q, (void *)mp, macinfo->gldm_ppa);
44207c478bd9Sstevel@tonic-gate 	}
44217c478bd9Sstevel@tonic-gate #endif
44227c478bd9Sstevel@tonic-gate 
44237c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
44247c478bd9Sstevel@tonic-gate 
44257c478bd9Sstevel@tonic-gate 	if (gld->gld_mcast) {
44267c478bd9Sstevel@tonic-gate 		for (i = 0; i < gld->gld_multicnt; i++) {
44277c478bd9Sstevel@tonic-gate 			gld_mcast_t *mcast;
44287c478bd9Sstevel@tonic-gate 
44297c478bd9Sstevel@tonic-gate 			if ((mcast = gld->gld_mcast[i]) != NULL) {
44307c478bd9Sstevel@tonic-gate 				ASSERT(mcast->gldm_refcnt);
44317c478bd9Sstevel@tonic-gate 				gld_send_disable_multi(macinfo, mcast);
44327c478bd9Sstevel@tonic-gate 			}
44337c478bd9Sstevel@tonic-gate 		}
44347c478bd9Sstevel@tonic-gate 		kmem_free(gld->gld_mcast,
44357c478bd9Sstevel@tonic-gate 		    sizeof (gld_mcast_t *) * gld->gld_multicnt);
44367c478bd9Sstevel@tonic-gate 		gld->gld_mcast = NULL;
44377c478bd9Sstevel@tonic-gate 		gld->gld_multicnt = 0;
44387c478bd9Sstevel@tonic-gate 	}
44397c478bd9Sstevel@tonic-gate 
44407c478bd9Sstevel@tonic-gate 	/* decide if we need to turn off any promiscuity */
44417c478bd9Sstevel@tonic-gate 	phys_off = (gld->gld_flags & GLD_PROM_PHYS &&
44427c478bd9Sstevel@tonic-gate 	    --mac_pvt->nprom == 0);
44437c478bd9Sstevel@tonic-gate 	mult_off = (gld->gld_flags & GLD_PROM_MULT &&
44447c478bd9Sstevel@tonic-gate 	    --mac_pvt->nprom_multi == 0);
44457c478bd9Sstevel@tonic-gate 
44467c478bd9Sstevel@tonic-gate 	gld->gld_flags &= ~(GLD_PROM_PHYS | GLD_PROM_SAP | GLD_PROM_MULT);
44477c478bd9Sstevel@tonic-gate 
44487c478bd9Sstevel@tonic-gate 	if (phys_off) {
44497c478bd9Sstevel@tonic-gate 		op = (mac_pvt->nprom_multi == 0) ? GLD_MAC_PROMISC_NONE :
44507c478bd9Sstevel@tonic-gate 		    GLD_MAC_PROMISC_MULTI;
44517c478bd9Sstevel@tonic-gate 	} else if (mult_off) {
44527c478bd9Sstevel@tonic-gate 		op = (mac_pvt->nprom == 0) ? GLD_MAC_PROMISC_NONE :
44537c478bd9Sstevel@tonic-gate 		    GLD_MAC_PROMISC_NOOP;	/* phys overrides multi */
44547c478bd9Sstevel@tonic-gate 	}
44557c478bd9Sstevel@tonic-gate 
44567c478bd9Sstevel@tonic-gate 	if (op != GLD_MAC_PROMISC_NOOP)
44577c478bd9Sstevel@tonic-gate 		(void) (*macinfo->gldm_set_promiscuous)(macinfo, op);
44587c478bd9Sstevel@tonic-gate 
44597c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
44607c478bd9Sstevel@tonic-gate 
44617c478bd9Sstevel@tonic-gate 	if (phys_off)
44627c478bd9Sstevel@tonic-gate 		gld_notify_ind(macinfo, DL_NOTE_PROMISC_OFF_PHYS, NULL);
44637c478bd9Sstevel@tonic-gate 
44647c478bd9Sstevel@tonic-gate 	/*
44657c478bd9Sstevel@tonic-gate 	 * We need to hold both locks when modifying the mac stream list
44667c478bd9Sstevel@tonic-gate 	 * to protect findminor as well as everyone else.
44677c478bd9Sstevel@tonic-gate 	 */
44687c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
44697c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
44707c478bd9Sstevel@tonic-gate 
44717c478bd9Sstevel@tonic-gate 	/* disassociate this stream with its vlan and underlying mac */
44727c478bd9Sstevel@tonic-gate 	gldremque(gld);
44737c478bd9Sstevel@tonic-gate 
44747c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
44757c478bd9Sstevel@tonic-gate 	if (--vlan->gldv_nstreams == 0) {
44767c478bd9Sstevel@tonic-gate 		gld_rem_vlan(vlan);
44777c478bd9Sstevel@tonic-gate 		gld->gld_vlan = NULL;
44787c478bd9Sstevel@tonic-gate 	}
44797c478bd9Sstevel@tonic-gate 
44807c478bd9Sstevel@tonic-gate 	gld->gld_mac_info = NULL;
44817c478bd9Sstevel@tonic-gate 	gld->gld_state = DL_UNATTACHED;
44827c478bd9Sstevel@tonic-gate 
44837c478bd9Sstevel@tonic-gate 	/* cleanup mac layer if last vlan */
44847c478bd9Sstevel@tonic-gate 	if (mac_pvt->nvlan == 0) {
44857c478bd9Sstevel@tonic-gate 		gld_stop_mac(macinfo);
44867c478bd9Sstevel@tonic-gate 		macinfo->gldm_GLD_flags &= ~GLD_INTR_WAIT;
44877c478bd9Sstevel@tonic-gate 	}
44887c478bd9Sstevel@tonic-gate 
44897c478bd9Sstevel@tonic-gate 	/* make sure no references to this gld for gld_v0_sched */
44907c478bd9Sstevel@tonic-gate 	if (mac_pvt->last_sched == gld)
44917c478bd9Sstevel@tonic-gate 		mac_pvt->last_sched = NULL;
44927c478bd9Sstevel@tonic-gate 
44937c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
44947c478bd9Sstevel@tonic-gate 
44957c478bd9Sstevel@tonic-gate 	/* put the stream on the unattached Style 2 list */
44967c478bd9Sstevel@tonic-gate 	gldinsque(gld, glddev->gld_str_prev);
44977c478bd9Sstevel@tonic-gate 
44987c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
44997c478bd9Sstevel@tonic-gate 
45007c478bd9Sstevel@tonic-gate 	/* There will be no mp if we were called from close */
45017c478bd9Sstevel@tonic-gate 	if (mp) {
45027c478bd9Sstevel@tonic-gate 		dlokack(q, mp, DL_DETACH_REQ);
45037c478bd9Sstevel@tonic-gate 	}
45047c478bd9Sstevel@tonic-gate 	if (gld->gld_style == DL_STYLE2)
45057c478bd9Sstevel@tonic-gate 		(void) qassociate(q, -1);
45067c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
45077c478bd9Sstevel@tonic-gate }
45087c478bd9Sstevel@tonic-gate 
45097c478bd9Sstevel@tonic-gate /*
45107c478bd9Sstevel@tonic-gate  * gld_enable_multi (q, mp)
45117c478bd9Sstevel@tonic-gate  * Enables multicast address on the stream.  If the mac layer
45127c478bd9Sstevel@tonic-gate  * isn't enabled for this address, enable at that level as well.
45137c478bd9Sstevel@tonic-gate  */
45147c478bd9Sstevel@tonic-gate static int
45157c478bd9Sstevel@tonic-gate gld_enable_multi(queue_t *q, mblk_t *mp)
45167c478bd9Sstevel@tonic-gate {
45177c478bd9Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
45187c478bd9Sstevel@tonic-gate 	glddev_t *glddev;
45197c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
45207c478bd9Sstevel@tonic-gate 	unsigned char *maddr;
45217c478bd9Sstevel@tonic-gate 	dl_enabmulti_req_t *multi;
45227c478bd9Sstevel@tonic-gate 	gld_mcast_t *mcast;
45237c478bd9Sstevel@tonic-gate 	int	i, rc;
45247c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
45257c478bd9Sstevel@tonic-gate 
45267c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
45277c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
45287c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_enable_multi(%p, %p)", (void *)q,
45297c478bd9Sstevel@tonic-gate 		    (void *)mp);
45307c478bd9Sstevel@tonic-gate 	}
45317c478bd9Sstevel@tonic-gate #endif
45327c478bd9Sstevel@tonic-gate 
45337c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
45347c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
45357c478bd9Sstevel@tonic-gate 
45367c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
45377c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
45387c478bd9Sstevel@tonic-gate 
45397c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_set_multicast == NULL) {
45407c478bd9Sstevel@tonic-gate 		return (DL_UNSUPPORTED);
45417c478bd9Sstevel@tonic-gate 	}
45427c478bd9Sstevel@tonic-gate 
45437c478bd9Sstevel@tonic-gate 	multi = (dl_enabmulti_req_t *)mp->b_rptr;
45447c478bd9Sstevel@tonic-gate 
45457c478bd9Sstevel@tonic-gate 	if (!MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length) ||
45467c478bd9Sstevel@tonic-gate 	    multi->dl_addr_length != macinfo->gldm_addrlen)
45477c478bd9Sstevel@tonic-gate 		return (DL_BADADDR);
45487c478bd9Sstevel@tonic-gate 
45497c478bd9Sstevel@tonic-gate 	/* request appears to be valid */
45507c478bd9Sstevel@tonic-gate 
45517c478bd9Sstevel@tonic-gate 	glddev = mac_pvt->major_dev;
45527c478bd9Sstevel@tonic-gate 	ASSERT(glddev == gld->gld_device);
45537c478bd9Sstevel@tonic-gate 
45547c478bd9Sstevel@tonic-gate 	maddr = mp->b_rptr + multi->dl_addr_offset;
45557c478bd9Sstevel@tonic-gate 
45567c478bd9Sstevel@tonic-gate 	/*
45577c478bd9Sstevel@tonic-gate 	 * The multicast addresses live in a per-device table, along
45587c478bd9Sstevel@tonic-gate 	 * with a reference count.  Each stream has a table that
45597c478bd9Sstevel@tonic-gate 	 * points to entries in the device table, with the reference
45607c478bd9Sstevel@tonic-gate 	 * count reflecting the number of streams pointing at it.  If
45617c478bd9Sstevel@tonic-gate 	 * this multicast address is already in the per-device table,
45627c478bd9Sstevel@tonic-gate 	 * all we have to do is point at it.
45637c478bd9Sstevel@tonic-gate 	 */
45647c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
45657c478bd9Sstevel@tonic-gate 
45667c478bd9Sstevel@tonic-gate 	/* does this address appear in current table? */
45677c478bd9Sstevel@tonic-gate 	if (gld->gld_mcast == NULL) {
45687c478bd9Sstevel@tonic-gate 		/* no mcast addresses -- allocate table */
45697c478bd9Sstevel@tonic-gate 		gld->gld_mcast = GETSTRUCT(gld_mcast_t *,
45707c478bd9Sstevel@tonic-gate 					    glddev->gld_multisize);
45717c478bd9Sstevel@tonic-gate 		if (gld->gld_mcast == NULL) {
45727c478bd9Sstevel@tonic-gate 			GLDM_UNLOCK(macinfo);
45737c478bd9Sstevel@tonic-gate 			dlerrorack(q, mp, DL_ENABMULTI_REQ, DL_SYSERR, ENOSR);
45747c478bd9Sstevel@tonic-gate 			return (GLDE_OK);
45757c478bd9Sstevel@tonic-gate 		}
45767c478bd9Sstevel@tonic-gate 		gld->gld_multicnt = glddev->gld_multisize;
45777c478bd9Sstevel@tonic-gate 	} else {
45787c478bd9Sstevel@tonic-gate 		for (i = 0; i < gld->gld_multicnt; i++) {
45797c478bd9Sstevel@tonic-gate 			if (gld->gld_mcast[i] &&
45807c478bd9Sstevel@tonic-gate 			    mac_eq(gld->gld_mcast[i]->gldm_addr,
45817c478bd9Sstevel@tonic-gate 				maddr, macinfo->gldm_addrlen)) {
45827c478bd9Sstevel@tonic-gate 				/* this is a match -- just succeed */
45837c478bd9Sstevel@tonic-gate 				ASSERT(gld->gld_mcast[i]->gldm_refcnt);
45847c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
45857c478bd9Sstevel@tonic-gate 				dlokack(q, mp, DL_ENABMULTI_REQ);
45867c478bd9Sstevel@tonic-gate 				return (GLDE_OK);
45877c478bd9Sstevel@tonic-gate 			}
45887c478bd9Sstevel@tonic-gate 		}
45897c478bd9Sstevel@tonic-gate 	}
45907c478bd9Sstevel@tonic-gate 
45917c478bd9Sstevel@tonic-gate 	/*
45927c478bd9Sstevel@tonic-gate 	 * it wasn't in the stream so check to see if the mac layer has it
45937c478bd9Sstevel@tonic-gate 	 */
45947c478bd9Sstevel@tonic-gate 	mcast = NULL;
45957c478bd9Sstevel@tonic-gate 	if (mac_pvt->mcast_table == NULL) {
45967c478bd9Sstevel@tonic-gate 		mac_pvt->mcast_table = GETSTRUCT(gld_mcast_t,
45977c478bd9Sstevel@tonic-gate 						glddev->gld_multisize);
45987c478bd9Sstevel@tonic-gate 		if (mac_pvt->mcast_table == NULL) {
45997c478bd9Sstevel@tonic-gate 			GLDM_UNLOCK(macinfo);
46007c478bd9Sstevel@tonic-gate 			dlerrorack(q, mp, DL_ENABMULTI_REQ, DL_SYSERR, ENOSR);
46017c478bd9Sstevel@tonic-gate 			return (GLDE_OK);
46027c478bd9Sstevel@tonic-gate 		}
46037c478bd9Sstevel@tonic-gate 	} else {
46047c478bd9Sstevel@tonic-gate 		for (i = 0; i < glddev->gld_multisize; i++) {
46057c478bd9Sstevel@tonic-gate 			if (mac_pvt->mcast_table[i].gldm_refcnt &&
46067c478bd9Sstevel@tonic-gate 			    mac_eq(mac_pvt->mcast_table[i].gldm_addr,
46077c478bd9Sstevel@tonic-gate 			    maddr, macinfo->gldm_addrlen)) {
46087c478bd9Sstevel@tonic-gate 				mcast = &mac_pvt->mcast_table[i];
46097c478bd9Sstevel@tonic-gate 				break;
46107c478bd9Sstevel@tonic-gate 			}
46117c478bd9Sstevel@tonic-gate 		}
46127c478bd9Sstevel@tonic-gate 	}
46137c478bd9Sstevel@tonic-gate 	if (mcast == NULL) {
46147c478bd9Sstevel@tonic-gate 		/* not in mac layer -- find an empty mac slot to fill in */
46157c478bd9Sstevel@tonic-gate 		for (i = 0; i < glddev->gld_multisize; i++) {
46167c478bd9Sstevel@tonic-gate 			if (mac_pvt->mcast_table[i].gldm_refcnt == 0) {
46177c478bd9Sstevel@tonic-gate 				mcast = &mac_pvt->mcast_table[i];
46187c478bd9Sstevel@tonic-gate 				mac_copy(maddr, mcast->gldm_addr,
46197c478bd9Sstevel@tonic-gate 				    macinfo->gldm_addrlen);
46207c478bd9Sstevel@tonic-gate 				break;
46217c478bd9Sstevel@tonic-gate 			}
46227c478bd9Sstevel@tonic-gate 		}
46237c478bd9Sstevel@tonic-gate 	}
46247c478bd9Sstevel@tonic-gate 	if (mcast == NULL) {
46257c478bd9Sstevel@tonic-gate 		/* couldn't get a mac layer slot */
46267c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
46277c478bd9Sstevel@tonic-gate 		return (DL_TOOMANY);
46287c478bd9Sstevel@tonic-gate 	}
46297c478bd9Sstevel@tonic-gate 
46307c478bd9Sstevel@tonic-gate 	/* now we have a mac layer slot in mcast -- get a stream slot */
46317c478bd9Sstevel@tonic-gate 	for (i = 0; i < gld->gld_multicnt; i++) {
46327c478bd9Sstevel@tonic-gate 		if (gld->gld_mcast[i] != NULL)
46337c478bd9Sstevel@tonic-gate 			continue;
46347c478bd9Sstevel@tonic-gate 		/* found an empty slot */
46357c478bd9Sstevel@tonic-gate 		if (!mcast->gldm_refcnt) {
46367c478bd9Sstevel@tonic-gate 			/* set mcast in hardware */
46377c478bd9Sstevel@tonic-gate 			unsigned char cmaddr[GLD_MAX_ADDRLEN];
46387c478bd9Sstevel@tonic-gate 
46397c478bd9Sstevel@tonic-gate 			ASSERT(sizeof (cmaddr) >= macinfo->gldm_addrlen);
46407c478bd9Sstevel@tonic-gate 			cmac_copy(maddr, cmaddr,
46417c478bd9Sstevel@tonic-gate 			    macinfo->gldm_addrlen, macinfo);
46427c478bd9Sstevel@tonic-gate 
46437c478bd9Sstevel@tonic-gate 			rc = (*macinfo->gldm_set_multicast)
46447c478bd9Sstevel@tonic-gate 			    (macinfo, cmaddr, GLD_MULTI_ENABLE);
46457c478bd9Sstevel@tonic-gate 			if (rc == GLD_NOTSUPPORTED) {
46467c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
46477c478bd9Sstevel@tonic-gate 				return (DL_NOTSUPPORTED);
46487c478bd9Sstevel@tonic-gate 			} else if (rc == GLD_NORESOURCES) {
46497c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
46507c478bd9Sstevel@tonic-gate 				return (DL_TOOMANY);
46517c478bd9Sstevel@tonic-gate 			} else if (rc == GLD_BADARG) {
46527c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
46537c478bd9Sstevel@tonic-gate 				return (DL_BADADDR);
46547c478bd9Sstevel@tonic-gate 			} else if (rc == GLD_RETRY) {
46557c478bd9Sstevel@tonic-gate 				/*
46567c478bd9Sstevel@tonic-gate 				 * The putbq and gld_xwait must be
46577c478bd9Sstevel@tonic-gate 				 * within the lock to prevent races
46587c478bd9Sstevel@tonic-gate 				 * with gld_sched.
46597c478bd9Sstevel@tonic-gate 				 */
46607c478bd9Sstevel@tonic-gate 				(void) putbq(q, mp);
46617c478bd9Sstevel@tonic-gate 				gld->gld_xwait = B_TRUE;
46627c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
46637c478bd9Sstevel@tonic-gate 				return (GLDE_RETRY);
46647c478bd9Sstevel@tonic-gate 			} else if (rc != GLD_SUCCESS) {
46657c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
46667c478bd9Sstevel@tonic-gate 				dlerrorack(q, mp, DL_ENABMULTI_REQ,
46677c478bd9Sstevel@tonic-gate 				    DL_SYSERR, EIO);
46687c478bd9Sstevel@tonic-gate 				return (GLDE_OK);
46697c478bd9Sstevel@tonic-gate 			}
46707c478bd9Sstevel@tonic-gate 		}
46717c478bd9Sstevel@tonic-gate 		gld->gld_mcast[i] = mcast;
46727c478bd9Sstevel@tonic-gate 		mcast->gldm_refcnt++;
46737c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
46747c478bd9Sstevel@tonic-gate 		dlokack(q, mp, DL_ENABMULTI_REQ);
46757c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
46767c478bd9Sstevel@tonic-gate 	}
46777c478bd9Sstevel@tonic-gate 
46787c478bd9Sstevel@tonic-gate 	/* couldn't get a stream slot */
46797c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
46807c478bd9Sstevel@tonic-gate 	return (DL_TOOMANY);
46817c478bd9Sstevel@tonic-gate }
46827c478bd9Sstevel@tonic-gate 
46837c478bd9Sstevel@tonic-gate 
46847c478bd9Sstevel@tonic-gate /*
46857c478bd9Sstevel@tonic-gate  * gld_disable_multi (q, mp)
46867c478bd9Sstevel@tonic-gate  * Disable the multicast address on the stream.  If last
46877c478bd9Sstevel@tonic-gate  * reference for the mac layer, disable there as well.
46887c478bd9Sstevel@tonic-gate  */
46897c478bd9Sstevel@tonic-gate static int
46907c478bd9Sstevel@tonic-gate gld_disable_multi(queue_t *q, mblk_t *mp)
46917c478bd9Sstevel@tonic-gate {
46927c478bd9Sstevel@tonic-gate 	gld_t  *gld;
46937c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
46947c478bd9Sstevel@tonic-gate 	unsigned char *maddr;
46957c478bd9Sstevel@tonic-gate 	dl_disabmulti_req_t *multi;
46967c478bd9Sstevel@tonic-gate 	int i;
46977c478bd9Sstevel@tonic-gate 	gld_mcast_t *mcast;
46987c478bd9Sstevel@tonic-gate 
46997c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
47007c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
47017c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_disable_multi(%p, %p)", (void *)q,
47027c478bd9Sstevel@tonic-gate 		    (void *)mp);
47037c478bd9Sstevel@tonic-gate 	}
47047c478bd9Sstevel@tonic-gate #endif
47057c478bd9Sstevel@tonic-gate 
47067c478bd9Sstevel@tonic-gate 	gld = (gld_t *)q->q_ptr;
47077c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
47087c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
47097c478bd9Sstevel@tonic-gate 
47107c478bd9Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
47117c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
47127c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_set_multicast == NULL) {
47137c478bd9Sstevel@tonic-gate 		return (DL_UNSUPPORTED);
47147c478bd9Sstevel@tonic-gate 	}
47157c478bd9Sstevel@tonic-gate 
47167c478bd9Sstevel@tonic-gate 	multi = (dl_disabmulti_req_t *)mp->b_rptr;
47177c478bd9Sstevel@tonic-gate 
47187c478bd9Sstevel@tonic-gate 	if (!MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length) ||
47197c478bd9Sstevel@tonic-gate 	    multi->dl_addr_length != macinfo->gldm_addrlen)
47207c478bd9Sstevel@tonic-gate 		return (DL_BADADDR);
47217c478bd9Sstevel@tonic-gate 
47227c478bd9Sstevel@tonic-gate 	maddr = mp->b_rptr + multi->dl_addr_offset;
47237c478bd9Sstevel@tonic-gate 
47247c478bd9Sstevel@tonic-gate 	/* request appears to be valid */
47257c478bd9Sstevel@tonic-gate 	/* does this address appear in current table? */
47267c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
47277c478bd9Sstevel@tonic-gate 	if (gld->gld_mcast != NULL) {
47287c478bd9Sstevel@tonic-gate 		for (i = 0; i < gld->gld_multicnt; i++)
47297c478bd9Sstevel@tonic-gate 			if (((mcast = gld->gld_mcast[i]) != NULL) &&
47307c478bd9Sstevel@tonic-gate 			    mac_eq(mcast->gldm_addr,
47317c478bd9Sstevel@tonic-gate 			    maddr, macinfo->gldm_addrlen)) {
47327c478bd9Sstevel@tonic-gate 				ASSERT(mcast->gldm_refcnt);
47337c478bd9Sstevel@tonic-gate 				gld_send_disable_multi(macinfo, mcast);
47347c478bd9Sstevel@tonic-gate 				gld->gld_mcast[i] = NULL;
47357c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
47367c478bd9Sstevel@tonic-gate 				dlokack(q, mp, DL_DISABMULTI_REQ);
47377c478bd9Sstevel@tonic-gate 				return (GLDE_OK);
47387c478bd9Sstevel@tonic-gate 			}
47397c478bd9Sstevel@tonic-gate 	}
47407c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
47417c478bd9Sstevel@tonic-gate 	return (DL_NOTENAB); /* not an enabled address */
47427c478bd9Sstevel@tonic-gate }
47437c478bd9Sstevel@tonic-gate 
47447c478bd9Sstevel@tonic-gate /*
47457c478bd9Sstevel@tonic-gate  * gld_send_disable_multi(macinfo, mcast)
47467c478bd9Sstevel@tonic-gate  * this function is used to disable a multicast address if the reference
47477c478bd9Sstevel@tonic-gate  * count goes to zero. The disable request will then be forwarded to the
47487c478bd9Sstevel@tonic-gate  * lower stream.
47497c478bd9Sstevel@tonic-gate  */
47507c478bd9Sstevel@tonic-gate static void
47517c478bd9Sstevel@tonic-gate gld_send_disable_multi(gld_mac_info_t *macinfo, gld_mcast_t *mcast)
47527c478bd9Sstevel@tonic-gate {
47537c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
47547c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
47557c478bd9Sstevel@tonic-gate 	ASSERT(mcast != NULL);
47567c478bd9Sstevel@tonic-gate 	ASSERT(mcast->gldm_refcnt);
47577c478bd9Sstevel@tonic-gate 
47587c478bd9Sstevel@tonic-gate 	if (!mcast->gldm_refcnt) {
47597c478bd9Sstevel@tonic-gate 		return;			/* "cannot happen" */
47607c478bd9Sstevel@tonic-gate 	}
47617c478bd9Sstevel@tonic-gate 
47627c478bd9Sstevel@tonic-gate 	if (--mcast->gldm_refcnt > 0) {
47637c478bd9Sstevel@tonic-gate 		return;
47647c478bd9Sstevel@tonic-gate 	}
47657c478bd9Sstevel@tonic-gate 
47667c478bd9Sstevel@tonic-gate 	/*
47677c478bd9Sstevel@tonic-gate 	 * This must be converted from canonical form to device form.
47687c478bd9Sstevel@tonic-gate 	 * The refcnt is now zero so we can trash the data.
47697c478bd9Sstevel@tonic-gate 	 */
47707c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_options & GLDOPT_CANONICAL_ADDR)
47717c478bd9Sstevel@tonic-gate 		gld_bitreverse(mcast->gldm_addr, macinfo->gldm_addrlen);
47727c478bd9Sstevel@tonic-gate 
47737c478bd9Sstevel@tonic-gate 	/* XXX Ought to check for GLD_NORESOURCES or GLD_FAILURE */
47747c478bd9Sstevel@tonic-gate 	(void) (*macinfo->gldm_set_multicast)
47757c478bd9Sstevel@tonic-gate 	    (macinfo, mcast->gldm_addr, GLD_MULTI_DISABLE);
47767c478bd9Sstevel@tonic-gate }
47777c478bd9Sstevel@tonic-gate 
47787c478bd9Sstevel@tonic-gate /*
47797c478bd9Sstevel@tonic-gate  * gld_promisc (q, mp, req, on)
47807c478bd9Sstevel@tonic-gate  *	enable or disable the use of promiscuous mode with the hardware
47817c478bd9Sstevel@tonic-gate  */
47827c478bd9Sstevel@tonic-gate static int
47837c478bd9Sstevel@tonic-gate gld_promisc(queue_t *q, mblk_t *mp, t_uscalar_t req, boolean_t on)
47847c478bd9Sstevel@tonic-gate {
47857c478bd9Sstevel@tonic-gate 	gld_t *gld;
47867c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
47877c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
47887c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
47897c478bd9Sstevel@tonic-gate 	union DL_primitives *prim;
47907c478bd9Sstevel@tonic-gate 	int macrc = GLD_SUCCESS;
47917c478bd9Sstevel@tonic-gate 	int dlerr = GLDE_OK;
47927c478bd9Sstevel@tonic-gate 	int op = GLD_MAC_PROMISC_NOOP;
47937c478bd9Sstevel@tonic-gate 
47947c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
47957c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
47967c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_promisc(%p, %p, %d, %d)",
47977c478bd9Sstevel@tonic-gate 		    (void *)q, (void *)mp, req, on);
47987c478bd9Sstevel@tonic-gate #endif
47997c478bd9Sstevel@tonic-gate 
48007c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
48017c478bd9Sstevel@tonic-gate 	prim = (union DL_primitives *)mp->b_rptr;
48027c478bd9Sstevel@tonic-gate 
48037c478bd9Sstevel@tonic-gate 	/* XXX I think spec allows promisc in unattached state */
48047c478bd9Sstevel@tonic-gate 	gld = (gld_t *)q->q_ptr;
48057c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
48067c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
48077c478bd9Sstevel@tonic-gate 
48087c478bd9Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
48097c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
48107c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
48117c478bd9Sstevel@tonic-gate 
48127c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
48137c478bd9Sstevel@tonic-gate 	ASSERT(vlan != NULL);
48147c478bd9Sstevel@tonic-gate 
48157c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
48167c478bd9Sstevel@tonic-gate 
48177c478bd9Sstevel@tonic-gate 	/*
48187c478bd9Sstevel@tonic-gate 	 * Work out what request (if any) has to be made to the MAC layer
48197c478bd9Sstevel@tonic-gate 	 */
48207c478bd9Sstevel@tonic-gate 	if (on) {
48217c478bd9Sstevel@tonic-gate 		switch (prim->promiscon_req.dl_level) {
48227c478bd9Sstevel@tonic-gate 		default:
48237c478bd9Sstevel@tonic-gate 			dlerr = DL_UNSUPPORTED;	/* this is an error */
48247c478bd9Sstevel@tonic-gate 			break;
48257c478bd9Sstevel@tonic-gate 
48267c478bd9Sstevel@tonic-gate 		case DL_PROMISC_PHYS:
48277c478bd9Sstevel@tonic-gate 			if (mac_pvt->nprom == 0)
48287c478bd9Sstevel@tonic-gate 				op = GLD_MAC_PROMISC_PHYS;
48297c478bd9Sstevel@tonic-gate 			break;
48307c478bd9Sstevel@tonic-gate 
48317c478bd9Sstevel@tonic-gate 		case DL_PROMISC_MULTI:
48327c478bd9Sstevel@tonic-gate 			if (mac_pvt->nprom_multi == 0)
48337c478bd9Sstevel@tonic-gate 				if (mac_pvt->nprom == 0)
48347c478bd9Sstevel@tonic-gate 					op = GLD_MAC_PROMISC_MULTI;
48357c478bd9Sstevel@tonic-gate 			break;
48367c478bd9Sstevel@tonic-gate 
48377c478bd9Sstevel@tonic-gate 		case DL_PROMISC_SAP:
48387c478bd9Sstevel@tonic-gate 			/* We can do this without reference to the MAC */
48397c478bd9Sstevel@tonic-gate 			break;
48407c478bd9Sstevel@tonic-gate 		}
48417c478bd9Sstevel@tonic-gate 	} else {
48427c478bd9Sstevel@tonic-gate 		switch (prim->promiscoff_req.dl_level) {
48437c478bd9Sstevel@tonic-gate 		default:
48447c478bd9Sstevel@tonic-gate 			dlerr = DL_UNSUPPORTED;	/* this is an error */
48457c478bd9Sstevel@tonic-gate 			break;
48467c478bd9Sstevel@tonic-gate 
48477c478bd9Sstevel@tonic-gate 		case DL_PROMISC_PHYS:
48487c478bd9Sstevel@tonic-gate 			if (!(gld->gld_flags & GLD_PROM_PHYS))
48497c478bd9Sstevel@tonic-gate 				dlerr = DL_NOTENAB;
48507c478bd9Sstevel@tonic-gate 			else if (mac_pvt->nprom == 1)
48517c478bd9Sstevel@tonic-gate 				if (mac_pvt->nprom_multi)
48527c478bd9Sstevel@tonic-gate 					op = GLD_MAC_PROMISC_MULTI;
48537c478bd9Sstevel@tonic-gate 				else
48547c478bd9Sstevel@tonic-gate 					op = GLD_MAC_PROMISC_NONE;
48557c478bd9Sstevel@tonic-gate 			break;
48567c478bd9Sstevel@tonic-gate 
48577c478bd9Sstevel@tonic-gate 		case DL_PROMISC_MULTI:
48587c478bd9Sstevel@tonic-gate 			if (!(gld->gld_flags & GLD_PROM_MULT))
48597c478bd9Sstevel@tonic-gate 				dlerr = DL_NOTENAB;
48607c478bd9Sstevel@tonic-gate 			else if (mac_pvt->nprom_multi == 1)
48617c478bd9Sstevel@tonic-gate 				if (mac_pvt->nprom == 0)
48627c478bd9Sstevel@tonic-gate 					op = GLD_MAC_PROMISC_NONE;
48637c478bd9Sstevel@tonic-gate 			break;
48647c478bd9Sstevel@tonic-gate 
48657c478bd9Sstevel@tonic-gate 		case DL_PROMISC_SAP:
48667c478bd9Sstevel@tonic-gate 			if (!(gld->gld_flags & GLD_PROM_SAP))
48677c478bd9Sstevel@tonic-gate 				dlerr = DL_NOTENAB;
48687c478bd9Sstevel@tonic-gate 
48697c478bd9Sstevel@tonic-gate 			/* We can do this without reference to the MAC */
48707c478bd9Sstevel@tonic-gate 			break;
48717c478bd9Sstevel@tonic-gate 		}
48727c478bd9Sstevel@tonic-gate 	}
48737c478bd9Sstevel@tonic-gate 
48747c478bd9Sstevel@tonic-gate 	/*
48757c478bd9Sstevel@tonic-gate 	 * The request was invalid in some way so no need to continue.
48767c478bd9Sstevel@tonic-gate 	 */
48777c478bd9Sstevel@tonic-gate 	if (dlerr != GLDE_OK) {
48787c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
48797c478bd9Sstevel@tonic-gate 		return (dlerr);
48807c478bd9Sstevel@tonic-gate 	}
48817c478bd9Sstevel@tonic-gate 
48827c478bd9Sstevel@tonic-gate 	/*
48837c478bd9Sstevel@tonic-gate 	 * Issue the request to the MAC layer, if required
48847c478bd9Sstevel@tonic-gate 	 */
48857c478bd9Sstevel@tonic-gate 	if (op != GLD_MAC_PROMISC_NOOP) {
48867c478bd9Sstevel@tonic-gate 		macrc = (*macinfo->gldm_set_promiscuous)(macinfo, op);
48877c478bd9Sstevel@tonic-gate 	}
48887c478bd9Sstevel@tonic-gate 
48897c478bd9Sstevel@tonic-gate 	/*
48907c478bd9Sstevel@tonic-gate 	 * On success, update the appropriate flags & refcounts
48917c478bd9Sstevel@tonic-gate 	 */
48927c478bd9Sstevel@tonic-gate 	if (macrc == GLD_SUCCESS) {
48937c478bd9Sstevel@tonic-gate 		if (on) {
48947c478bd9Sstevel@tonic-gate 			switch (prim->promiscon_req.dl_level) {
48957c478bd9Sstevel@tonic-gate 			case DL_PROMISC_PHYS:
48967c478bd9Sstevel@tonic-gate 				mac_pvt->nprom++;
48977c478bd9Sstevel@tonic-gate 				gld->gld_flags |= GLD_PROM_PHYS;
48987c478bd9Sstevel@tonic-gate 				break;
48997c478bd9Sstevel@tonic-gate 
49007c478bd9Sstevel@tonic-gate 			case DL_PROMISC_MULTI:
49017c478bd9Sstevel@tonic-gate 				mac_pvt->nprom_multi++;
49027c478bd9Sstevel@tonic-gate 				gld->gld_flags |= GLD_PROM_MULT;
49037c478bd9Sstevel@tonic-gate 				break;
49047c478bd9Sstevel@tonic-gate 
49057c478bd9Sstevel@tonic-gate 			case DL_PROMISC_SAP:
49067c478bd9Sstevel@tonic-gate 				gld->gld_flags |= GLD_PROM_SAP;
49077c478bd9Sstevel@tonic-gate 				break;
49087c478bd9Sstevel@tonic-gate 
49097c478bd9Sstevel@tonic-gate 			default:
49107c478bd9Sstevel@tonic-gate 				break;
49117c478bd9Sstevel@tonic-gate 			}
49127c478bd9Sstevel@tonic-gate 		} else {
49137c478bd9Sstevel@tonic-gate 			switch (prim->promiscoff_req.dl_level) {
49147c478bd9Sstevel@tonic-gate 			case DL_PROMISC_PHYS:
49157c478bd9Sstevel@tonic-gate 				mac_pvt->nprom--;
49167c478bd9Sstevel@tonic-gate 				gld->gld_flags &= ~GLD_PROM_PHYS;
49177c478bd9Sstevel@tonic-gate 				break;
49187c478bd9Sstevel@tonic-gate 
49197c478bd9Sstevel@tonic-gate 			case DL_PROMISC_MULTI:
49207c478bd9Sstevel@tonic-gate 				mac_pvt->nprom_multi--;
49217c478bd9Sstevel@tonic-gate 				gld->gld_flags &= ~GLD_PROM_MULT;
49227c478bd9Sstevel@tonic-gate 				break;
49237c478bd9Sstevel@tonic-gate 
49247c478bd9Sstevel@tonic-gate 			case DL_PROMISC_SAP:
49257c478bd9Sstevel@tonic-gate 				gld->gld_flags &= ~GLD_PROM_SAP;
49267c478bd9Sstevel@tonic-gate 				break;
49277c478bd9Sstevel@tonic-gate 
49287c478bd9Sstevel@tonic-gate 			default:
49297c478bd9Sstevel@tonic-gate 				break;
49307c478bd9Sstevel@tonic-gate 			}
49317c478bd9Sstevel@tonic-gate 		}
49327c478bd9Sstevel@tonic-gate 	} else if (macrc == GLD_RETRY) {
49337c478bd9Sstevel@tonic-gate 		/*
49347c478bd9Sstevel@tonic-gate 		 * The putbq and gld_xwait must be within the lock to
49357c478bd9Sstevel@tonic-gate 		 * prevent races with gld_sched.
49367c478bd9Sstevel@tonic-gate 		 */
49377c478bd9Sstevel@tonic-gate 		(void) putbq(q, mp);
49387c478bd9Sstevel@tonic-gate 		gld->gld_xwait = B_TRUE;
49397c478bd9Sstevel@tonic-gate 	}
49407c478bd9Sstevel@tonic-gate 
49417c478bd9Sstevel@tonic-gate 	/*
49427c478bd9Sstevel@tonic-gate 	 * Update VLAN IPQ status -- it may have changed
49437c478bd9Sstevel@tonic-gate 	 */
49447c478bd9Sstevel@tonic-gate 	if (gld->gld_flags & (GLD_PROM_SAP | GLD_PROM_MULT | GLD_PROM_PHYS))
49457c478bd9Sstevel@tonic-gate 		vlan->gldv_ipq_flags |= IPQ_FORBIDDEN;
49467c478bd9Sstevel@tonic-gate 	else
49477c478bd9Sstevel@tonic-gate 		vlan->gldv_ipq_flags &= ~IPQ_FORBIDDEN;
49487c478bd9Sstevel@tonic-gate 
49497c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
49507c478bd9Sstevel@tonic-gate 
49517c478bd9Sstevel@tonic-gate 	/*
49527c478bd9Sstevel@tonic-gate 	 * Finally, decide how to reply.
49537c478bd9Sstevel@tonic-gate 	 *
49547c478bd9Sstevel@tonic-gate 	 * If <macrc> is not GLD_SUCCESS, the request was put to the MAC
49557c478bd9Sstevel@tonic-gate 	 * layer but failed.  In such cases, we can return a DL_* error
49567c478bd9Sstevel@tonic-gate 	 * code and let the caller send an error-ack reply upstream, or
49577c478bd9Sstevel@tonic-gate 	 * we can send a reply here and then return GLDE_OK so that the
49587c478bd9Sstevel@tonic-gate 	 * caller doesn't also respond.
49597c478bd9Sstevel@tonic-gate 	 *
49607c478bd9Sstevel@tonic-gate 	 * If physical-promiscuous mode was (successfully) switched on or
49617c478bd9Sstevel@tonic-gate 	 * off, send a notification (DL_NOTIFY_IND) to anyone interested.
49627c478bd9Sstevel@tonic-gate 	 */
49637c478bd9Sstevel@tonic-gate 	switch (macrc) {
49647c478bd9Sstevel@tonic-gate 	case GLD_NOTSUPPORTED:
49657c478bd9Sstevel@tonic-gate 		return (DL_NOTSUPPORTED);
49667c478bd9Sstevel@tonic-gate 
49677c478bd9Sstevel@tonic-gate 	case GLD_NORESOURCES:
49687c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, req, DL_SYSERR, ENOSR);
49697c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
49707c478bd9Sstevel@tonic-gate 
49717c478bd9Sstevel@tonic-gate 	case GLD_RETRY:
49727c478bd9Sstevel@tonic-gate 		return (GLDE_RETRY);
49737c478bd9Sstevel@tonic-gate 
49747c478bd9Sstevel@tonic-gate 	default:
49757c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, req, DL_SYSERR, EIO);
49767c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
49777c478bd9Sstevel@tonic-gate 
49787c478bd9Sstevel@tonic-gate 	case GLD_SUCCESS:
49797c478bd9Sstevel@tonic-gate 		dlokack(q, mp, req);
49807c478bd9Sstevel@tonic-gate 		break;
49817c478bd9Sstevel@tonic-gate 	}
49827c478bd9Sstevel@tonic-gate 
49837c478bd9Sstevel@tonic-gate 	switch (op) {
49847c478bd9Sstevel@tonic-gate 	case GLD_MAC_PROMISC_NOOP:
49857c478bd9Sstevel@tonic-gate 		break;
49867c478bd9Sstevel@tonic-gate 
49877c478bd9Sstevel@tonic-gate 	case GLD_MAC_PROMISC_PHYS:
49887c478bd9Sstevel@tonic-gate 		gld_notify_ind(macinfo, DL_NOTE_PROMISC_ON_PHYS, NULL);
49897c478bd9Sstevel@tonic-gate 		break;
49907c478bd9Sstevel@tonic-gate 
49917c478bd9Sstevel@tonic-gate 	default:
49927c478bd9Sstevel@tonic-gate 		gld_notify_ind(macinfo, DL_NOTE_PROMISC_OFF_PHYS, NULL);
49937c478bd9Sstevel@tonic-gate 		break;
49947c478bd9Sstevel@tonic-gate 	}
49957c478bd9Sstevel@tonic-gate 
49967c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
49977c478bd9Sstevel@tonic-gate }
49987c478bd9Sstevel@tonic-gate 
49997c478bd9Sstevel@tonic-gate /*
50007c478bd9Sstevel@tonic-gate  * gld_physaddr()
50017c478bd9Sstevel@tonic-gate  *	get the current or factory physical address value
50027c478bd9Sstevel@tonic-gate  */
50037c478bd9Sstevel@tonic-gate static int
50047c478bd9Sstevel@tonic-gate gld_physaddr(queue_t *q, mblk_t *mp)
50057c478bd9Sstevel@tonic-gate {
50067c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
50077c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
50087c478bd9Sstevel@tonic-gate 	union DL_primitives *prim = (union DL_primitives *)mp->b_rptr;
50097c478bd9Sstevel@tonic-gate 	unsigned char addr[GLD_MAX_ADDRLEN];
50107c478bd9Sstevel@tonic-gate 
50117c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
50127c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
50137c478bd9Sstevel@tonic-gate 
50147c478bd9Sstevel@tonic-gate 	macinfo = (gld_mac_info_t *)gld->gld_mac_info;
50157c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
50167c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_addrlen <= GLD_MAX_ADDRLEN);
50177c478bd9Sstevel@tonic-gate 
50187c478bd9Sstevel@tonic-gate 	switch (prim->physaddr_req.dl_addr_type) {
50197c478bd9Sstevel@tonic-gate 	case DL_FACT_PHYS_ADDR:
50207c478bd9Sstevel@tonic-gate 		mac_copy((caddr_t)macinfo->gldm_vendor_addr,
50217c478bd9Sstevel@tonic-gate 		    (caddr_t)addr, macinfo->gldm_addrlen);
50227c478bd9Sstevel@tonic-gate 		break;
50237c478bd9Sstevel@tonic-gate 	case DL_CURR_PHYS_ADDR:
50247c478bd9Sstevel@tonic-gate 		/* make a copy so we don't hold the lock across qreply */
50257c478bd9Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
50267c478bd9Sstevel@tonic-gate 		mac_copy((caddr_t)
50277c478bd9Sstevel@tonic-gate 		    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
50287c478bd9Sstevel@tonic-gate 		    (caddr_t)addr, macinfo->gldm_addrlen);
50297c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
50307c478bd9Sstevel@tonic-gate 		break;
50317c478bd9Sstevel@tonic-gate 	default:
50327c478bd9Sstevel@tonic-gate 		return (DL_BADPRIM);
50337c478bd9Sstevel@tonic-gate 	}
50347c478bd9Sstevel@tonic-gate 	dlphysaddrack(q, mp, (caddr_t)addr, macinfo->gldm_addrlen);
50357c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
50367c478bd9Sstevel@tonic-gate }
50377c478bd9Sstevel@tonic-gate 
50387c478bd9Sstevel@tonic-gate /*
50397c478bd9Sstevel@tonic-gate  * gld_setaddr()
50407c478bd9Sstevel@tonic-gate  *	change the hardware's physical address to a user specified value
50417c478bd9Sstevel@tonic-gate  */
50427c478bd9Sstevel@tonic-gate static int
50437c478bd9Sstevel@tonic-gate gld_setaddr(queue_t *q, mblk_t *mp)
50447c478bd9Sstevel@tonic-gate {
50457c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
50467c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
50477c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
50487c478bd9Sstevel@tonic-gate 	union DL_primitives *prim = (union DL_primitives *)mp->b_rptr;
50497c478bd9Sstevel@tonic-gate 	unsigned char *addr;
50507c478bd9Sstevel@tonic-gate 	unsigned char cmaddr[GLD_MAX_ADDRLEN];
50517c478bd9Sstevel@tonic-gate 	int rc;
50527c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
50537c478bd9Sstevel@tonic-gate 
50547c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
50557c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
50567c478bd9Sstevel@tonic-gate 
50577c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
50587c478bd9Sstevel@tonic-gate 	ASSERT(vlan != NULL);
50597c478bd9Sstevel@tonic-gate 
50607c478bd9Sstevel@tonic-gate 	if (vlan->gldv_id != VLAN_VID_NONE)
50617c478bd9Sstevel@tonic-gate 		return (DL_NOTSUPPORTED);
50627c478bd9Sstevel@tonic-gate 
50637c478bd9Sstevel@tonic-gate 	macinfo = (gld_mac_info_t *)gld->gld_mac_info;
50647c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
50657c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
50667c478bd9Sstevel@tonic-gate 
50677c478bd9Sstevel@tonic-gate 	if (!MBLKIN(mp, prim->set_physaddr_req.dl_addr_offset,
50687c478bd9Sstevel@tonic-gate 	    prim->set_physaddr_req.dl_addr_length) ||
50697c478bd9Sstevel@tonic-gate 	    prim->set_physaddr_req.dl_addr_length != macinfo->gldm_addrlen)
50707c478bd9Sstevel@tonic-gate 		return (DL_BADADDR);
50717c478bd9Sstevel@tonic-gate 
50727c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
50737c478bd9Sstevel@tonic-gate 
50747c478bd9Sstevel@tonic-gate 	/* now do the set at the hardware level */
50757c478bd9Sstevel@tonic-gate 	addr = mp->b_rptr + prim->set_physaddr_req.dl_addr_offset;
50767c478bd9Sstevel@tonic-gate 	ASSERT(sizeof (cmaddr) >= macinfo->gldm_addrlen);
50777c478bd9Sstevel@tonic-gate 	cmac_copy(addr, cmaddr, macinfo->gldm_addrlen, macinfo);
50787c478bd9Sstevel@tonic-gate 
50797c478bd9Sstevel@tonic-gate 	rc = (*macinfo->gldm_set_mac_addr)(macinfo, cmaddr);
50807c478bd9Sstevel@tonic-gate 	if (rc == GLD_SUCCESS)
50817c478bd9Sstevel@tonic-gate 		mac_copy(addr, mac_pvt->curr_macaddr,
50827c478bd9Sstevel@tonic-gate 		    macinfo->gldm_addrlen);
50837c478bd9Sstevel@tonic-gate 
50847c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
50857c478bd9Sstevel@tonic-gate 
50867c478bd9Sstevel@tonic-gate 	switch (rc) {
50877c478bd9Sstevel@tonic-gate 	case GLD_SUCCESS:
50887c478bd9Sstevel@tonic-gate 		break;
50897c478bd9Sstevel@tonic-gate 	case GLD_NOTSUPPORTED:
50907c478bd9Sstevel@tonic-gate 		return (DL_NOTSUPPORTED);
50917c478bd9Sstevel@tonic-gate 	case GLD_BADARG:
50927c478bd9Sstevel@tonic-gate 		return (DL_BADADDR);
50937c478bd9Sstevel@tonic-gate 	case GLD_NORESOURCES:
50947c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, DL_SYSERR, ENOSR);
50957c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
50967c478bd9Sstevel@tonic-gate 	default:
50977c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, DL_SYSERR, EIO);
50987c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
50997c478bd9Sstevel@tonic-gate 	}
51007c478bd9Sstevel@tonic-gate 
51017c478bd9Sstevel@tonic-gate 	gld_notify_ind(macinfo, DL_NOTE_PHYS_ADDR, NULL);
51027c478bd9Sstevel@tonic-gate 
51037c478bd9Sstevel@tonic-gate 	dlokack(q, mp, DL_SET_PHYS_ADDR_REQ);
51047c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
51057c478bd9Sstevel@tonic-gate }
51067c478bd9Sstevel@tonic-gate 
51077c478bd9Sstevel@tonic-gate int
51087c478bd9Sstevel@tonic-gate gld_get_statistics(queue_t *q, mblk_t *mp)
51097c478bd9Sstevel@tonic-gate {
51107c478bd9Sstevel@tonic-gate 	dl_get_statistics_ack_t *dlsp;
51117c478bd9Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
51127c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
51137c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
51147c478bd9Sstevel@tonic-gate 
51157c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
51167c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
51177c478bd9Sstevel@tonic-gate 
51187c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
51197c478bd9Sstevel@tonic-gate 
51207c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
51217c478bd9Sstevel@tonic-gate 	(void) gld_update_kstat(mac_pvt->kstatp, KSTAT_READ);
51227c478bd9Sstevel@tonic-gate 
51237c478bd9Sstevel@tonic-gate 	mp = mexchange(q, mp, DL_GET_STATISTICS_ACK_SIZE +
51247c478bd9Sstevel@tonic-gate 	    sizeof (struct gldkstats), M_PCPROTO, DL_GET_STATISTICS_ACK);
51257c478bd9Sstevel@tonic-gate 
51267c478bd9Sstevel@tonic-gate 	if (mp == NULL)
51277c478bd9Sstevel@tonic-gate 		return (GLDE_OK);	/* mexchange already sent merror */
51287c478bd9Sstevel@tonic-gate 
51297c478bd9Sstevel@tonic-gate 	dlsp = (dl_get_statistics_ack_t *)mp->b_rptr;
51307c478bd9Sstevel@tonic-gate 	dlsp->dl_primitive = DL_GET_STATISTICS_ACK;
51317c478bd9Sstevel@tonic-gate 	dlsp->dl_stat_length = sizeof (struct gldkstats);
51327c478bd9Sstevel@tonic-gate 	dlsp->dl_stat_offset = DL_GET_STATISTICS_ACK_SIZE;
51337c478bd9Sstevel@tonic-gate 
51347c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
51357c478bd9Sstevel@tonic-gate 	bcopy(mac_pvt->kstatp->ks_data,
51367c478bd9Sstevel@tonic-gate 	    (mp->b_rptr + DL_GET_STATISTICS_ACK_SIZE),
51377c478bd9Sstevel@tonic-gate 	    sizeof (struct gldkstats));
51387c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
51397c478bd9Sstevel@tonic-gate 
51407c478bd9Sstevel@tonic-gate 	qreply(q, mp);
51417c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
51427c478bd9Sstevel@tonic-gate }
51437c478bd9Sstevel@tonic-gate 
51447c478bd9Sstevel@tonic-gate /* =================================================== */
51457c478bd9Sstevel@tonic-gate /* misc utilities, some requiring various mutexes held */
51467c478bd9Sstevel@tonic-gate /* =================================================== */
51477c478bd9Sstevel@tonic-gate 
51487c478bd9Sstevel@tonic-gate /*
51497c478bd9Sstevel@tonic-gate  * Initialize and start the driver.
51507c478bd9Sstevel@tonic-gate  */
51517c478bd9Sstevel@tonic-gate static int
51527c478bd9Sstevel@tonic-gate gld_start_mac(gld_mac_info_t *macinfo)
51537c478bd9Sstevel@tonic-gate {
51547c478bd9Sstevel@tonic-gate 	int	rc;
51557c478bd9Sstevel@tonic-gate 	unsigned char cmaddr[GLD_MAX_ADDRLEN];
51567c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
51577c478bd9Sstevel@tonic-gate 
51587c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
51597c478bd9Sstevel@tonic-gate 	ASSERT(!mac_pvt->started);
51607c478bd9Sstevel@tonic-gate 
51617c478bd9Sstevel@tonic-gate 	rc = (*macinfo->gldm_reset)(macinfo);
51627c478bd9Sstevel@tonic-gate 	if (rc != GLD_SUCCESS)
51637c478bd9Sstevel@tonic-gate 		return (GLD_FAILURE);
51647c478bd9Sstevel@tonic-gate 
51657c478bd9Sstevel@tonic-gate 	/* set the addr after we reset the device */
51667c478bd9Sstevel@tonic-gate 	ASSERT(sizeof (cmaddr) >= macinfo->gldm_addrlen);
51677c478bd9Sstevel@tonic-gate 	cmac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)
51687c478bd9Sstevel@tonic-gate 	    ->curr_macaddr, cmaddr, macinfo->gldm_addrlen, macinfo);
51697c478bd9Sstevel@tonic-gate 
51707c478bd9Sstevel@tonic-gate 	rc = (*macinfo->gldm_set_mac_addr)(macinfo, cmaddr);
51717c478bd9Sstevel@tonic-gate 	ASSERT(rc != GLD_BADARG);  /* this address was good before */
51727c478bd9Sstevel@tonic-gate 	if (rc != GLD_SUCCESS && rc != GLD_NOTSUPPORTED)
51737c478bd9Sstevel@tonic-gate 		return (GLD_FAILURE);
51747c478bd9Sstevel@tonic-gate 
51757c478bd9Sstevel@tonic-gate 	rc = (*macinfo->gldm_start)(macinfo);
51767c478bd9Sstevel@tonic-gate 	if (rc != GLD_SUCCESS)
51777c478bd9Sstevel@tonic-gate 		return (GLD_FAILURE);
51787c478bd9Sstevel@tonic-gate 
51797c478bd9Sstevel@tonic-gate 	mac_pvt->started = B_TRUE;
51807c478bd9Sstevel@tonic-gate 	return (GLD_SUCCESS);
51817c478bd9Sstevel@tonic-gate }
51827c478bd9Sstevel@tonic-gate 
51837c478bd9Sstevel@tonic-gate /*
51847c478bd9Sstevel@tonic-gate  * Stop the driver.
51857c478bd9Sstevel@tonic-gate  */
51867c478bd9Sstevel@tonic-gate static void
51877c478bd9Sstevel@tonic-gate gld_stop_mac(gld_mac_info_t *macinfo)
51887c478bd9Sstevel@tonic-gate {
51897c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
51907c478bd9Sstevel@tonic-gate 
51917c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
51927c478bd9Sstevel@tonic-gate 	ASSERT(mac_pvt->started);
51937c478bd9Sstevel@tonic-gate 
51947c478bd9Sstevel@tonic-gate 	(void) (*macinfo->gldm_stop)(macinfo);
51957c478bd9Sstevel@tonic-gate 
51967c478bd9Sstevel@tonic-gate 	mac_pvt->started = B_FALSE;
51977c478bd9Sstevel@tonic-gate }
51987c478bd9Sstevel@tonic-gate 
51997c478bd9Sstevel@tonic-gate 
52007c478bd9Sstevel@tonic-gate /*
52017c478bd9Sstevel@tonic-gate  * gld_set_ipq will set a pointer to the queue which is bound to the
52027c478bd9Sstevel@tonic-gate  * IP sap if:
52037c478bd9Sstevel@tonic-gate  * o the device type is ethernet or IPoIB.
52047c478bd9Sstevel@tonic-gate  * o there is no stream in SAP promiscuous mode.
52057c478bd9Sstevel@tonic-gate  * o there is exactly one stream bound to the IP sap.
52067c478bd9Sstevel@tonic-gate  * o the stream is in "fastpath" mode.
52077c478bd9Sstevel@tonic-gate  */
52087c478bd9Sstevel@tonic-gate static void
52097c478bd9Sstevel@tonic-gate gld_set_ipq(gld_t *gld)
52107c478bd9Sstevel@tonic-gate {
52117c478bd9Sstevel@tonic-gate 	gld_vlan_t	*vlan;
52127c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*macinfo = gld->gld_mac_info;
52137c478bd9Sstevel@tonic-gate 	gld_t		*ip_gld = NULL;
52147c478bd9Sstevel@tonic-gate 	uint_t		ipq_candidates = 0;
52157c478bd9Sstevel@tonic-gate 	gld_t		*ipv6_gld = NULL;
52167c478bd9Sstevel@tonic-gate 	uint_t		ipv6q_candidates = 0;
52177c478bd9Sstevel@tonic-gate 
52187c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
52197c478bd9Sstevel@tonic-gate 
52207c478bd9Sstevel@tonic-gate 	/* The ipq code in gld_recv() is intimate with ethernet/IPoIB */
52217c478bd9Sstevel@tonic-gate 	if (((macinfo->gldm_type != DL_ETHER) &&
52227c478bd9Sstevel@tonic-gate 	    (macinfo->gldm_type != DL_IB)) ||
52237c478bd9Sstevel@tonic-gate 	    (gld_global_options & GLD_OPT_NO_IPQ))
52247c478bd9Sstevel@tonic-gate 		return;
52257c478bd9Sstevel@tonic-gate 
52267c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
52277c478bd9Sstevel@tonic-gate 	ASSERT(vlan != NULL);
52287c478bd9Sstevel@tonic-gate 
52297c478bd9Sstevel@tonic-gate 	/* clear down any previously defined ipqs */
52307c478bd9Sstevel@tonic-gate 	vlan->gldv_ipq = NULL;
52317c478bd9Sstevel@tonic-gate 	vlan->gldv_ipv6q = NULL;
52327c478bd9Sstevel@tonic-gate 
52337c478bd9Sstevel@tonic-gate 	/* Try to find a single stream eligible to receive IP packets */
52347c478bd9Sstevel@tonic-gate 	for (gld = vlan->gldv_str_next;
52357c478bd9Sstevel@tonic-gate 	    gld != (gld_t *)&vlan->gldv_str_next; gld = gld->gld_next) {
52367c478bd9Sstevel@tonic-gate 		if (gld->gld_state != DL_IDLE)
52377c478bd9Sstevel@tonic-gate 			continue;	/* not eligible to receive */
52387c478bd9Sstevel@tonic-gate 		if (gld->gld_flags & GLD_STR_CLOSING)
52397c478bd9Sstevel@tonic-gate 			continue;	/* not eligible to receive */
52407c478bd9Sstevel@tonic-gate 
52417c478bd9Sstevel@tonic-gate 		if (gld->gld_sap == ETHERTYPE_IP) {
52427c478bd9Sstevel@tonic-gate 			ip_gld = gld;
52437c478bd9Sstevel@tonic-gate 			ipq_candidates++;
52447c478bd9Sstevel@tonic-gate 		}
52457c478bd9Sstevel@tonic-gate 
52467c478bd9Sstevel@tonic-gate 		if (gld->gld_sap == ETHERTYPE_IPV6) {
52477c478bd9Sstevel@tonic-gate 			ipv6_gld = gld;
52487c478bd9Sstevel@tonic-gate 			ipv6q_candidates++;
52497c478bd9Sstevel@tonic-gate 		}
52507c478bd9Sstevel@tonic-gate 	}
52517c478bd9Sstevel@tonic-gate 
52527c478bd9Sstevel@tonic-gate 	if (ipq_candidates == 1) {
52537c478bd9Sstevel@tonic-gate 		ASSERT(ip_gld != NULL);
52547c478bd9Sstevel@tonic-gate 
52557c478bd9Sstevel@tonic-gate 		if (ip_gld->gld_flags & GLD_FAST)	/* eligible for ipq */
52567c478bd9Sstevel@tonic-gate 			vlan->gldv_ipq = ip_gld->gld_qptr;
52577c478bd9Sstevel@tonic-gate 	}
52587c478bd9Sstevel@tonic-gate 
52597c478bd9Sstevel@tonic-gate 	if (ipv6q_candidates == 1) {
52607c478bd9Sstevel@tonic-gate 		ASSERT(ipv6_gld != NULL);
52617c478bd9Sstevel@tonic-gate 
52627c478bd9Sstevel@tonic-gate 		if (ipv6_gld->gld_flags & GLD_FAST)	/* eligible for ipq */
52637c478bd9Sstevel@tonic-gate 			vlan->gldv_ipv6q = ipv6_gld->gld_qptr;
52647c478bd9Sstevel@tonic-gate 	}
52657c478bd9Sstevel@tonic-gate }
52667c478bd9Sstevel@tonic-gate 
52677c478bd9Sstevel@tonic-gate /*
52687c478bd9Sstevel@tonic-gate  * gld_flushqueue (q)
52697c478bd9Sstevel@tonic-gate  *	used by DLPI primitives that require flushing the queues.
52707c478bd9Sstevel@tonic-gate  *	essentially, this is DL_UNBIND_REQ.
52717c478bd9Sstevel@tonic-gate  */
52727c478bd9Sstevel@tonic-gate static void
52737c478bd9Sstevel@tonic-gate gld_flushqueue(queue_t *q)
52747c478bd9Sstevel@tonic-gate {
52757c478bd9Sstevel@tonic-gate 	/* flush all data in both queues */
52767c478bd9Sstevel@tonic-gate 	/* XXX Should these be FLUSHALL? */
52777c478bd9Sstevel@tonic-gate 	flushq(q, FLUSHDATA);
52787c478bd9Sstevel@tonic-gate 	flushq(WR(q), FLUSHDATA);
52797c478bd9Sstevel@tonic-gate 	/* flush all the queues upstream */
52807c478bd9Sstevel@tonic-gate 	(void) putctl1(q, M_FLUSH, FLUSHRW);
52817c478bd9Sstevel@tonic-gate }
52827c478bd9Sstevel@tonic-gate 
52837c478bd9Sstevel@tonic-gate /*
52847c478bd9Sstevel@tonic-gate  * gld_devlookup (major)
52857c478bd9Sstevel@tonic-gate  * search the device table for the device with specified
52867c478bd9Sstevel@tonic-gate  * major number and return a pointer to it if it exists
52877c478bd9Sstevel@tonic-gate  */
52887c478bd9Sstevel@tonic-gate static glddev_t *
52897c478bd9Sstevel@tonic-gate gld_devlookup(int major)
52907c478bd9Sstevel@tonic-gate {
52917c478bd9Sstevel@tonic-gate 	struct glddevice *dev;
52927c478bd9Sstevel@tonic-gate 
52937c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&gld_device_list.gld_devlock));
52947c478bd9Sstevel@tonic-gate 
52957c478bd9Sstevel@tonic-gate 	for (dev = gld_device_list.gld_next;
52967c478bd9Sstevel@tonic-gate 	    dev != &gld_device_list;
52977c478bd9Sstevel@tonic-gate 	    dev = dev->gld_next) {
52987c478bd9Sstevel@tonic-gate 		ASSERT(dev);
52997c478bd9Sstevel@tonic-gate 		if (dev->gld_major == major)
53007c478bd9Sstevel@tonic-gate 			return (dev);
53017c478bd9Sstevel@tonic-gate 	}
53027c478bd9Sstevel@tonic-gate 	return (NULL);
53037c478bd9Sstevel@tonic-gate }
53047c478bd9Sstevel@tonic-gate 
53057c478bd9Sstevel@tonic-gate /*
53067c478bd9Sstevel@tonic-gate  * gld_findminor(device)
53077c478bd9Sstevel@tonic-gate  * Returns a minor number currently unused by any stream in the current
53087c478bd9Sstevel@tonic-gate  * device class (major) list.
53097c478bd9Sstevel@tonic-gate  */
53107c478bd9Sstevel@tonic-gate static int
53117c478bd9Sstevel@tonic-gate gld_findminor(glddev_t *device)
53127c478bd9Sstevel@tonic-gate {
53137c478bd9Sstevel@tonic-gate 	gld_t		*next;
53147c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*nextmac;
53157c478bd9Sstevel@tonic-gate 	gld_vlan_t	*nextvlan;
53167c478bd9Sstevel@tonic-gate 	int		minor;
53177c478bd9Sstevel@tonic-gate 	int		i;
53187c478bd9Sstevel@tonic-gate 
53197c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&device->gld_devlock));
53207c478bd9Sstevel@tonic-gate 
53217c478bd9Sstevel@tonic-gate 	/* The fast way */
53227c478bd9Sstevel@tonic-gate 	if (device->gld_nextminor >= GLD_MIN_CLONE_MINOR &&
53237c478bd9Sstevel@tonic-gate 	    device->gld_nextminor <= GLD_MAX_CLONE_MINOR)
53247c478bd9Sstevel@tonic-gate 		return (device->gld_nextminor++);
53257c478bd9Sstevel@tonic-gate 
53267c478bd9Sstevel@tonic-gate 	/* The steady way */
53277c478bd9Sstevel@tonic-gate 	for (minor = GLD_MIN_CLONE_MINOR; minor <= GLD_MAX_CLONE_MINOR;
53287c478bd9Sstevel@tonic-gate 	    minor++) {
53297c478bd9Sstevel@tonic-gate 		/* Search all unattached streams */
53307c478bd9Sstevel@tonic-gate 		for (next = device->gld_str_next;
53317c478bd9Sstevel@tonic-gate 		    next != (gld_t *)&device->gld_str_next;
53327c478bd9Sstevel@tonic-gate 		    next = next->gld_next) {
53337c478bd9Sstevel@tonic-gate 			if (minor == next->gld_minor)
53347c478bd9Sstevel@tonic-gate 				goto nextminor;
53357c478bd9Sstevel@tonic-gate 		}
53367c478bd9Sstevel@tonic-gate 		/* Search all attached streams; we don't need maclock because */
53377c478bd9Sstevel@tonic-gate 		/* mac stream list is protected by devlock as well as maclock */
53387c478bd9Sstevel@tonic-gate 		for (nextmac = device->gld_mac_next;
53397c478bd9Sstevel@tonic-gate 		    nextmac != (gld_mac_info_t *)&device->gld_mac_next;
53407c478bd9Sstevel@tonic-gate 		    nextmac = nextmac->gldm_next) {
53417c478bd9Sstevel@tonic-gate 			gld_mac_pvt_t *pvt =
53427c478bd9Sstevel@tonic-gate 			    (gld_mac_pvt_t *)nextmac->gldm_mac_pvt;
53437c478bd9Sstevel@tonic-gate 
53447c478bd9Sstevel@tonic-gate 			if (!(nextmac->gldm_GLD_flags & GLD_MAC_READY))
53457c478bd9Sstevel@tonic-gate 				continue;	/* this one's not ready yet */
53467c478bd9Sstevel@tonic-gate 
53477c478bd9Sstevel@tonic-gate 			for (i = 0; i < VLAN_HASHSZ; i++) {
53487c478bd9Sstevel@tonic-gate 				for (nextvlan = pvt->vlan_hash[i];
53497c478bd9Sstevel@tonic-gate 				    nextvlan != NULL;
53507c478bd9Sstevel@tonic-gate 				    nextvlan = nextvlan->gldv_next) {
53517c478bd9Sstevel@tonic-gate 					for (next = nextvlan->gldv_str_next;
53527c478bd9Sstevel@tonic-gate 					    next !=
53537c478bd9Sstevel@tonic-gate 					    (gld_t *)&nextvlan->gldv_str_next;
53547c478bd9Sstevel@tonic-gate 					    next = next->gld_next) {
53557c478bd9Sstevel@tonic-gate 						if (minor == next->gld_minor)
53567c478bd9Sstevel@tonic-gate 							goto nextminor;
53577c478bd9Sstevel@tonic-gate 					}
53587c478bd9Sstevel@tonic-gate 				}
53597c478bd9Sstevel@tonic-gate 			}
53607c478bd9Sstevel@tonic-gate 		}
53617c478bd9Sstevel@tonic-gate 
53627c478bd9Sstevel@tonic-gate 		return (minor);
53637c478bd9Sstevel@tonic-gate nextminor:
53647c478bd9Sstevel@tonic-gate 		/* don't need to do anything */
53657c478bd9Sstevel@tonic-gate 		;
53667c478bd9Sstevel@tonic-gate 	}
53677c478bd9Sstevel@tonic-gate 	cmn_err(CE_WARN, "GLD ran out of minor numbers for %s",
53687c478bd9Sstevel@tonic-gate 		device->gld_name);
53697c478bd9Sstevel@tonic-gate 	return (0);
53707c478bd9Sstevel@tonic-gate }
53717c478bd9Sstevel@tonic-gate 
53727c478bd9Sstevel@tonic-gate /*
53737c478bd9Sstevel@tonic-gate  * version of insque/remque for use by this driver
53747c478bd9Sstevel@tonic-gate  */
53757c478bd9Sstevel@tonic-gate struct qelem {
53767c478bd9Sstevel@tonic-gate 	struct qelem *q_forw;
53777c478bd9Sstevel@tonic-gate 	struct qelem *q_back;
53787c478bd9Sstevel@tonic-gate 	/* rest of structure */
53797c478bd9Sstevel@tonic-gate };
53807c478bd9Sstevel@tonic-gate 
53817c478bd9Sstevel@tonic-gate static void
53827c478bd9Sstevel@tonic-gate gldinsque(void *elem, void *pred)
53837c478bd9Sstevel@tonic-gate {
53847c478bd9Sstevel@tonic-gate 	struct qelem *pelem = elem;
53857c478bd9Sstevel@tonic-gate 	struct qelem *ppred = pred;
53867c478bd9Sstevel@tonic-gate 	struct qelem *pnext = ppred->q_forw;
53877c478bd9Sstevel@tonic-gate 
53887c478bd9Sstevel@tonic-gate 	pelem->q_forw = pnext;
53897c478bd9Sstevel@tonic-gate 	pelem->q_back = ppred;
53907c478bd9Sstevel@tonic-gate 	ppred->q_forw = pelem;
53917c478bd9Sstevel@tonic-gate 	pnext->q_back = pelem;
53927c478bd9Sstevel@tonic-gate }
53937c478bd9Sstevel@tonic-gate 
53947c478bd9Sstevel@tonic-gate static void
53957c478bd9Sstevel@tonic-gate gldremque(void *arg)
53967c478bd9Sstevel@tonic-gate {
53977c478bd9Sstevel@tonic-gate 	struct qelem *pelem = arg;
53987c478bd9Sstevel@tonic-gate 	struct qelem *elem = arg;
53997c478bd9Sstevel@tonic-gate 
54007c478bd9Sstevel@tonic-gate 	pelem->q_forw->q_back = pelem->q_back;
54017c478bd9Sstevel@tonic-gate 	pelem->q_back->q_forw = pelem->q_forw;
54027c478bd9Sstevel@tonic-gate 	elem->q_back = elem->q_forw = NULL;
54037c478bd9Sstevel@tonic-gate }
54047c478bd9Sstevel@tonic-gate 
54057c478bd9Sstevel@tonic-gate static gld_vlan_t *
54067c478bd9Sstevel@tonic-gate gld_add_vlan(gld_mac_info_t *macinfo, uint32_t vid)
54077c478bd9Sstevel@tonic-gate {
54087c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
54097c478bd9Sstevel@tonic-gate 	gld_vlan_t	**pp;
54107c478bd9Sstevel@tonic-gate 	gld_vlan_t	*p;
54117c478bd9Sstevel@tonic-gate 
54127c478bd9Sstevel@tonic-gate 	pp = &(mac_pvt->vlan_hash[vid % VLAN_HASHSZ]);
54137c478bd9Sstevel@tonic-gate 	while ((p = *pp) != NULL) {
54147c478bd9Sstevel@tonic-gate 		ASSERT(p->gldv_id != vid);
54157c478bd9Sstevel@tonic-gate 		pp = &(p->gldv_next);
54167c478bd9Sstevel@tonic-gate 	}
54177c478bd9Sstevel@tonic-gate 
54187c478bd9Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (gld_vlan_t), KM_NOSLEEP)) == NULL)
54197c478bd9Sstevel@tonic-gate 		return (NULL);
54207c478bd9Sstevel@tonic-gate 
54217c478bd9Sstevel@tonic-gate 	p->gldv_mac = macinfo;
54227c478bd9Sstevel@tonic-gate 	p->gldv_id = vid;
54237c478bd9Sstevel@tonic-gate 
54247c478bd9Sstevel@tonic-gate 	if (vid == VLAN_VID_NONE) {
54257c478bd9Sstevel@tonic-gate 		p->gldv_ptag = VLAN_VTAG_NONE;
54267c478bd9Sstevel@tonic-gate 		p->gldv_stats = mac_pvt->statistics;
54277c478bd9Sstevel@tonic-gate 		p->gldv_kstatp = NULL;
54287c478bd9Sstevel@tonic-gate 	} else {
54297c478bd9Sstevel@tonic-gate 		p->gldv_ptag = GLD_MK_PTAG(VLAN_CFI_ETHER, vid);
54307c478bd9Sstevel@tonic-gate 		p->gldv_stats = kmem_zalloc(sizeof (struct gld_stats),
54317c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
54327c478bd9Sstevel@tonic-gate 
54337c478bd9Sstevel@tonic-gate 		if (gld_init_vlan_stats(p) != GLD_SUCCESS) {
54347c478bd9Sstevel@tonic-gate 			kmem_free(p->gldv_stats, sizeof (struct gld_stats));
54357c478bd9Sstevel@tonic-gate 			kmem_free(p, sizeof (gld_vlan_t));
54367c478bd9Sstevel@tonic-gate 			return (NULL);
54377c478bd9Sstevel@tonic-gate 		}
54387c478bd9Sstevel@tonic-gate 	}
54397c478bd9Sstevel@tonic-gate 
54407c478bd9Sstevel@tonic-gate 	p->gldv_str_next = p->gldv_str_prev = (gld_t *)&p->gldv_str_next;
54417c478bd9Sstevel@tonic-gate 	mac_pvt->nvlan++;
54427c478bd9Sstevel@tonic-gate 	*pp = p;
54437c478bd9Sstevel@tonic-gate 
54447c478bd9Sstevel@tonic-gate 	return (p);
54457c478bd9Sstevel@tonic-gate }
54467c478bd9Sstevel@tonic-gate 
54477c478bd9Sstevel@tonic-gate static void
54487c478bd9Sstevel@tonic-gate gld_rem_vlan(gld_vlan_t *vlan)
54497c478bd9Sstevel@tonic-gate {
54507c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*macinfo = vlan->gldv_mac;
54517c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
54527c478bd9Sstevel@tonic-gate 	gld_vlan_t	**pp;
54537c478bd9Sstevel@tonic-gate 	gld_vlan_t	*p;
54547c478bd9Sstevel@tonic-gate 
54557c478bd9Sstevel@tonic-gate 	pp = &(mac_pvt->vlan_hash[vlan->gldv_id % VLAN_HASHSZ]);
54567c478bd9Sstevel@tonic-gate 	while ((p = *pp) != NULL) {
54577c478bd9Sstevel@tonic-gate 		if (p->gldv_id == vlan->gldv_id)
54587c478bd9Sstevel@tonic-gate 			break;
54597c478bd9Sstevel@tonic-gate 		pp = &(p->gldv_next);
54607c478bd9Sstevel@tonic-gate 	}
54617c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
54627c478bd9Sstevel@tonic-gate 
54637c478bd9Sstevel@tonic-gate 	*pp = p->gldv_next;
54647c478bd9Sstevel@tonic-gate 	mac_pvt->nvlan--;
54657c478bd9Sstevel@tonic-gate 	if (p->gldv_id != VLAN_VID_NONE) {
54667c478bd9Sstevel@tonic-gate 		ASSERT(p->gldv_kstatp != NULL);
54677c478bd9Sstevel@tonic-gate 		kstat_delete(p->gldv_kstatp);
54687c478bd9Sstevel@tonic-gate 		kmem_free(p->gldv_stats, sizeof (struct gld_stats));
54697c478bd9Sstevel@tonic-gate 	}
54707c478bd9Sstevel@tonic-gate 	kmem_free(p, sizeof (gld_vlan_t));
54717c478bd9Sstevel@tonic-gate }
54727c478bd9Sstevel@tonic-gate 
54737c478bd9Sstevel@tonic-gate gld_vlan_t *
54747c478bd9Sstevel@tonic-gate gld_find_vlan(gld_mac_info_t *macinfo, uint32_t vid)
54757c478bd9Sstevel@tonic-gate {
54767c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
54777c478bd9Sstevel@tonic-gate 	gld_vlan_t	*p;
54787c478bd9Sstevel@tonic-gate 
54797c478bd9Sstevel@tonic-gate 	p = mac_pvt->vlan_hash[vid % VLAN_HASHSZ];
54807c478bd9Sstevel@tonic-gate 	while (p != NULL) {
54817c478bd9Sstevel@tonic-gate 		if (p->gldv_id == vid)
54827c478bd9Sstevel@tonic-gate 			return (p);
54837c478bd9Sstevel@tonic-gate 		p = p->gldv_next;
54847c478bd9Sstevel@tonic-gate 	}
54857c478bd9Sstevel@tonic-gate 	return (NULL);
54867c478bd9Sstevel@tonic-gate }
54877c478bd9Sstevel@tonic-gate 
54887c478bd9Sstevel@tonic-gate gld_vlan_t *
54897c478bd9Sstevel@tonic-gate gld_get_vlan(gld_mac_info_t *macinfo, uint32_t vid)
54907c478bd9Sstevel@tonic-gate {
54917c478bd9Sstevel@tonic-gate 	gld_vlan_t	*vlan;
54927c478bd9Sstevel@tonic-gate 
54937c478bd9Sstevel@tonic-gate 	if ((vlan = gld_find_vlan(macinfo, vid)) == NULL)
54947c478bd9Sstevel@tonic-gate 		vlan = gld_add_vlan(macinfo, vid);
54957c478bd9Sstevel@tonic-gate 
54967c478bd9Sstevel@tonic-gate 	return (vlan);
54977c478bd9Sstevel@tonic-gate }
54987c478bd9Sstevel@tonic-gate 
54997c478bd9Sstevel@tonic-gate /*
55007c478bd9Sstevel@tonic-gate  * gld_bitrevcopy()
55017c478bd9Sstevel@tonic-gate  * This is essentially bcopy, with the ability to bit reverse the
55027c478bd9Sstevel@tonic-gate  * the source bytes. The MAC addresses bytes as transmitted by FDDI
55037c478bd9Sstevel@tonic-gate  * interfaces are bit reversed.
55047c478bd9Sstevel@tonic-gate  */
55057c478bd9Sstevel@tonic-gate void
55067c478bd9Sstevel@tonic-gate gld_bitrevcopy(caddr_t src, caddr_t target, size_t n)
55077c478bd9Sstevel@tonic-gate {
55087c478bd9Sstevel@tonic-gate 	while (n--)
55097c478bd9Sstevel@tonic-gate 		*target++ = bit_rev[(uchar_t)*src++];
55107c478bd9Sstevel@tonic-gate }
55117c478bd9Sstevel@tonic-gate 
55127c478bd9Sstevel@tonic-gate /*
55137c478bd9Sstevel@tonic-gate  * gld_bitreverse()
55147c478bd9Sstevel@tonic-gate  * Convert the bit order by swaping all the bits, using a
55157c478bd9Sstevel@tonic-gate  * lookup table.
55167c478bd9Sstevel@tonic-gate  */
55177c478bd9Sstevel@tonic-gate void
55187c478bd9Sstevel@tonic-gate gld_bitreverse(uchar_t *rptr, size_t n)
55197c478bd9Sstevel@tonic-gate {
55207c478bd9Sstevel@tonic-gate 	while (n--) {
55217c478bd9Sstevel@tonic-gate 		*rptr = bit_rev[*rptr];
55227c478bd9Sstevel@tonic-gate 		rptr++;
55237c478bd9Sstevel@tonic-gate 	}
55247c478bd9Sstevel@tonic-gate }
55257c478bd9Sstevel@tonic-gate 
55267c478bd9Sstevel@tonic-gate char *
55277c478bd9Sstevel@tonic-gate gld_macaddr_sprintf(char *etherbuf, unsigned char *ap, int len)
55287c478bd9Sstevel@tonic-gate {
55297c478bd9Sstevel@tonic-gate 	int i;
55307c478bd9Sstevel@tonic-gate 	char *cp = etherbuf;
55317c478bd9Sstevel@tonic-gate 	static char digits[] = "0123456789abcdef";
55327c478bd9Sstevel@tonic-gate 
55337c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
55347c478bd9Sstevel@tonic-gate 		*cp++ = digits[*ap >> 4];
55357c478bd9Sstevel@tonic-gate 		*cp++ = digits[*ap++ & 0xf];
55367c478bd9Sstevel@tonic-gate 		*cp++ = ':';
55377c478bd9Sstevel@tonic-gate 	}
55387c478bd9Sstevel@tonic-gate 	*--cp = 0;
55397c478bd9Sstevel@tonic-gate 	return (etherbuf);
55407c478bd9Sstevel@tonic-gate }
55417c478bd9Sstevel@tonic-gate 
55427c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
55437c478bd9Sstevel@tonic-gate static void
55447c478bd9Sstevel@tonic-gate gld_check_assertions()
55457c478bd9Sstevel@tonic-gate {
55467c478bd9Sstevel@tonic-gate 	glddev_t	*dev;
55477c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*mac;
55487c478bd9Sstevel@tonic-gate 	gld_t		*str;
55497c478bd9Sstevel@tonic-gate 	gld_vlan_t	*vlan;
55507c478bd9Sstevel@tonic-gate 	int		i;
55517c478bd9Sstevel@tonic-gate 
55527c478bd9Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
55537c478bd9Sstevel@tonic-gate 
55547c478bd9Sstevel@tonic-gate 	for (dev = gld_device_list.gld_next;
55557c478bd9Sstevel@tonic-gate 	    dev != (glddev_t *)&gld_device_list.gld_next;
55567c478bd9Sstevel@tonic-gate 	    dev = dev->gld_next) {
55577c478bd9Sstevel@tonic-gate 		mutex_enter(&dev->gld_devlock);
55587c478bd9Sstevel@tonic-gate 		ASSERT(dev->gld_broadcast != NULL);
55597c478bd9Sstevel@tonic-gate 		for (str = dev->gld_str_next;
55607c478bd9Sstevel@tonic-gate 		    str != (gld_t *)&dev->gld_str_next;
55617c478bd9Sstevel@tonic-gate 		    str = str->gld_next) {
55627c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_device == dev);
55637c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_mac_info == NULL);
55647c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_qptr != NULL);
55657c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_minor >= GLD_MIN_CLONE_MINOR);
55667c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_multicnt == 0);
55677c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_mcast == NULL);
55687c478bd9Sstevel@tonic-gate 			ASSERT(!(str->gld_flags &
55697c478bd9Sstevel@tonic-gate 			    (GLD_PROM_PHYS|GLD_PROM_MULT|GLD_PROM_SAP)));
55707c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_sap == 0);
55717c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_state == DL_UNATTACHED);
55727c478bd9Sstevel@tonic-gate 		}
55737c478bd9Sstevel@tonic-gate 		for (mac = dev->gld_mac_next;
55747c478bd9Sstevel@tonic-gate 		    mac != (gld_mac_info_t *)&dev->gld_mac_next;
55757c478bd9Sstevel@tonic-gate 		    mac = mac->gldm_next) {
55767c478bd9Sstevel@tonic-gate 			int nvlan = 0;
55777c478bd9Sstevel@tonic-gate 			gld_mac_pvt_t *pvt = (gld_mac_pvt_t *)mac->gldm_mac_pvt;
55787c478bd9Sstevel@tonic-gate 
55797c478bd9Sstevel@tonic-gate 			if (!(mac->gldm_GLD_flags & GLD_MAC_READY))
55807c478bd9Sstevel@tonic-gate 				continue;	/* this one's not ready yet */
55817c478bd9Sstevel@tonic-gate 
55827c478bd9Sstevel@tonic-gate 			GLDM_LOCK(mac, RW_WRITER);
55837c478bd9Sstevel@tonic-gate 			ASSERT(mac->gldm_devinfo != NULL);
55847c478bd9Sstevel@tonic-gate 			ASSERT(mac->gldm_mac_pvt != NULL);
55857c478bd9Sstevel@tonic-gate 			ASSERT(pvt->interfacep != NULL);
55867c478bd9Sstevel@tonic-gate 			ASSERT(pvt->kstatp != NULL);
55877c478bd9Sstevel@tonic-gate 			ASSERT(pvt->statistics != NULL);
55887c478bd9Sstevel@tonic-gate 			ASSERT(pvt->major_dev == dev);
55897c478bd9Sstevel@tonic-gate 
55907c478bd9Sstevel@tonic-gate 			for (i = 0; i < VLAN_HASHSZ; i++) {
55917c478bd9Sstevel@tonic-gate 				for (vlan = pvt->vlan_hash[i];
55927c478bd9Sstevel@tonic-gate 				    vlan != NULL; vlan = vlan->gldv_next) {
55937c478bd9Sstevel@tonic-gate 					int nstr = 0;
55947c478bd9Sstevel@tonic-gate 
55957c478bd9Sstevel@tonic-gate 					ASSERT(vlan->gldv_mac == mac);
55967c478bd9Sstevel@tonic-gate 
55977c478bd9Sstevel@tonic-gate 					for (str = vlan->gldv_str_next;
55987c478bd9Sstevel@tonic-gate 					    str !=
55997c478bd9Sstevel@tonic-gate 					    (gld_t *)&vlan->gldv_str_next;
56007c478bd9Sstevel@tonic-gate 					    str = str->gld_next) {
56017c478bd9Sstevel@tonic-gate 						ASSERT(str->gld_device == dev);
56027c478bd9Sstevel@tonic-gate 						ASSERT(str->gld_mac_info ==
56037c478bd9Sstevel@tonic-gate 						    mac);
56047c478bd9Sstevel@tonic-gate 						ASSERT(str->gld_qptr != NULL);
56057c478bd9Sstevel@tonic-gate 						ASSERT(str->gld_minor >=
56067c478bd9Sstevel@tonic-gate 						    GLD_MIN_CLONE_MINOR);
56077c478bd9Sstevel@tonic-gate 						ASSERT(
56087c478bd9Sstevel@tonic-gate 						    str->gld_multicnt == 0 ||
56097c478bd9Sstevel@tonic-gate 						    str->gld_mcast);
56107c478bd9Sstevel@tonic-gate 						nstr++;
56117c478bd9Sstevel@tonic-gate 					}
56127c478bd9Sstevel@tonic-gate 					ASSERT(vlan->gldv_nstreams == nstr);
56137c478bd9Sstevel@tonic-gate 					nvlan++;
56147c478bd9Sstevel@tonic-gate 				}
56157c478bd9Sstevel@tonic-gate 			}
56167c478bd9Sstevel@tonic-gate 			ASSERT(pvt->nvlan == nvlan);
56177c478bd9Sstevel@tonic-gate 			GLDM_UNLOCK(mac);
56187c478bd9Sstevel@tonic-gate 		}
56197c478bd9Sstevel@tonic-gate 		mutex_exit(&dev->gld_devlock);
56207c478bd9Sstevel@tonic-gate 	}
56217c478bd9Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
56227c478bd9Sstevel@tonic-gate }
56237c478bd9Sstevel@tonic-gate #endif
5624