xref: /titanic_53/usr/src/uts/common/io/gld.c (revision 7c478bd95313f5f23a4c958a745db2134aa03244)
1*7c478bd9Sstevel@tonic-gate /*
2*7c478bd9Sstevel@tonic-gate  * CDDL HEADER START
3*7c478bd9Sstevel@tonic-gate  *
4*7c478bd9Sstevel@tonic-gate  * The contents of this file are subject to the terms of the
5*7c478bd9Sstevel@tonic-gate  * Common Development and Distribution License, Version 1.0 only
6*7c478bd9Sstevel@tonic-gate  * (the "License").  You may not use this file except in compliance
7*7c478bd9Sstevel@tonic-gate  * with the License.
8*7c478bd9Sstevel@tonic-gate  *
9*7c478bd9Sstevel@tonic-gate  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10*7c478bd9Sstevel@tonic-gate  * or http://www.opensolaris.org/os/licensing.
11*7c478bd9Sstevel@tonic-gate  * See the License for the specific language governing permissions
12*7c478bd9Sstevel@tonic-gate  * and limitations under the License.
13*7c478bd9Sstevel@tonic-gate  *
14*7c478bd9Sstevel@tonic-gate  * When distributing Covered Code, include this CDDL HEADER in each
15*7c478bd9Sstevel@tonic-gate  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16*7c478bd9Sstevel@tonic-gate  * If applicable, add the following below this CDDL HEADER, with the
17*7c478bd9Sstevel@tonic-gate  * fields enclosed by brackets "[]" replaced with your own identifying
18*7c478bd9Sstevel@tonic-gate  * information: Portions Copyright [yyyy] [name of copyright owner]
19*7c478bd9Sstevel@tonic-gate  *
20*7c478bd9Sstevel@tonic-gate  * CDDL HEADER END
21*7c478bd9Sstevel@tonic-gate  */
22*7c478bd9Sstevel@tonic-gate /*
23*7c478bd9Sstevel@tonic-gate  * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24*7c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
25*7c478bd9Sstevel@tonic-gate  */
26*7c478bd9Sstevel@tonic-gate 
27*7c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
28*7c478bd9Sstevel@tonic-gate 
29*7c478bd9Sstevel@tonic-gate /*
30*7c478bd9Sstevel@tonic-gate  * gld - Generic LAN Driver Version 2, PSARC/1997/382
31*7c478bd9Sstevel@tonic-gate  *
32*7c478bd9Sstevel@tonic-gate  * This is a utility module that provides generic facilities for
33*7c478bd9Sstevel@tonic-gate  * LAN	drivers.  The DLPI protocol and most STREAMS interfaces
34*7c478bd9Sstevel@tonic-gate  * are handled here.
35*7c478bd9Sstevel@tonic-gate  *
36*7c478bd9Sstevel@tonic-gate  * It no longer provides compatibility with drivers
37*7c478bd9Sstevel@tonic-gate  * implemented according to the GLD v0 documentation published
38*7c478bd9Sstevel@tonic-gate  * in 1993. (See PSARC 2003/728)
39*7c478bd9Sstevel@tonic-gate  */
40*7c478bd9Sstevel@tonic-gate 
41*7c478bd9Sstevel@tonic-gate 
42*7c478bd9Sstevel@tonic-gate #include <sys/types.h>
43*7c478bd9Sstevel@tonic-gate #include <sys/errno.h>
44*7c478bd9Sstevel@tonic-gate #include <sys/stropts.h>
45*7c478bd9Sstevel@tonic-gate #include <sys/stream.h>
46*7c478bd9Sstevel@tonic-gate #include <sys/kmem.h>
47*7c478bd9Sstevel@tonic-gate #include <sys/stat.h>
48*7c478bd9Sstevel@tonic-gate #include <sys/modctl.h>
49*7c478bd9Sstevel@tonic-gate #include <sys/kstat.h>
50*7c478bd9Sstevel@tonic-gate #include <sys/debug.h>
51*7c478bd9Sstevel@tonic-gate #include <sys/note.h>
52*7c478bd9Sstevel@tonic-gate #include <sys/sysmacros.h>
53*7c478bd9Sstevel@tonic-gate 
54*7c478bd9Sstevel@tonic-gate #include <sys/byteorder.h>
55*7c478bd9Sstevel@tonic-gate #include <sys/strsun.h>
56*7c478bd9Sstevel@tonic-gate #include <sys/strsubr.h>
57*7c478bd9Sstevel@tonic-gate #include <sys/dlpi.h>
58*7c478bd9Sstevel@tonic-gate #include <sys/pattr.h>
59*7c478bd9Sstevel@tonic-gate #include <sys/ethernet.h>
60*7c478bd9Sstevel@tonic-gate #include <sys/ib/clients/ibd/ibd.h>
61*7c478bd9Sstevel@tonic-gate #include <sys/policy.h>
62*7c478bd9Sstevel@tonic-gate #include <sys/atomic.h>
63*7c478bd9Sstevel@tonic-gate 
64*7c478bd9Sstevel@tonic-gate #include <sys/multidata.h>
65*7c478bd9Sstevel@tonic-gate #include <sys/gld.h>
66*7c478bd9Sstevel@tonic-gate #include <sys/gldpriv.h>
67*7c478bd9Sstevel@tonic-gate 
68*7c478bd9Sstevel@tonic-gate #include <sys/ddi.h>
69*7c478bd9Sstevel@tonic-gate #include <sys/sunddi.h>
70*7c478bd9Sstevel@tonic-gate 
71*7c478bd9Sstevel@tonic-gate /*
72*7c478bd9Sstevel@tonic-gate  * Macro to atomically increment counters of type uint32_t, uint64_t
73*7c478bd9Sstevel@tonic-gate  * and ulong_t.
74*7c478bd9Sstevel@tonic-gate  */
75*7c478bd9Sstevel@tonic-gate #define	BUMP(stat, delta)	do {				\
76*7c478bd9Sstevel@tonic-gate 	_NOTE(CONSTANTCONDITION)				\
77*7c478bd9Sstevel@tonic-gate 	if (sizeof (stat) == sizeof (uint32_t))	{		\
78*7c478bd9Sstevel@tonic-gate 		atomic_add_32((uint32_t *)&stat, delta);	\
79*7c478bd9Sstevel@tonic-gate 	_NOTE(CONSTANTCONDITION)				\
80*7c478bd9Sstevel@tonic-gate 	} else if (sizeof (stat) == sizeof (uint64_t)) {	\
81*7c478bd9Sstevel@tonic-gate 		atomic_add_64((uint64_t *)&stat, delta);	\
82*7c478bd9Sstevel@tonic-gate 	}							\
83*7c478bd9Sstevel@tonic-gate 	_NOTE(CONSTANTCONDITION)				\
84*7c478bd9Sstevel@tonic-gate } while (0)
85*7c478bd9Sstevel@tonic-gate 
86*7c478bd9Sstevel@tonic-gate #define	UPDATE_STATS(vlan, pktinfo, number)	{		\
87*7c478bd9Sstevel@tonic-gate 	if ((pktinfo).isBroadcast)				\
88*7c478bd9Sstevel@tonic-gate 		(vlan)->gldv_stats->glds_brdcstxmt += (number);	\
89*7c478bd9Sstevel@tonic-gate 	else if ((pktinfo).isMulticast)				\
90*7c478bd9Sstevel@tonic-gate 		(vlan)->gldv_stats->glds_multixmt += (number);	\
91*7c478bd9Sstevel@tonic-gate 	(vlan)->gldv_stats->glds_bytexmt64 += (pktinfo).pktLen;	\
92*7c478bd9Sstevel@tonic-gate 	(vlan)->gldv_stats->glds_pktxmt64 += (number);		\
93*7c478bd9Sstevel@tonic-gate }
94*7c478bd9Sstevel@tonic-gate 
95*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
96*7c478bd9Sstevel@tonic-gate int gld_debug = GLDERRS;
97*7c478bd9Sstevel@tonic-gate #endif
98*7c478bd9Sstevel@tonic-gate 
99*7c478bd9Sstevel@tonic-gate /* called from gld_register */
100*7c478bd9Sstevel@tonic-gate static int gld_initstats(gld_mac_info_t *);
101*7c478bd9Sstevel@tonic-gate 
102*7c478bd9Sstevel@tonic-gate /* called from kstat mechanism, and from wsrv's get_statistics */
103*7c478bd9Sstevel@tonic-gate static int gld_update_kstat(kstat_t *, int);
104*7c478bd9Sstevel@tonic-gate 
105*7c478bd9Sstevel@tonic-gate /* statistics for additional vlans */
106*7c478bd9Sstevel@tonic-gate static int gld_init_vlan_stats(gld_vlan_t *);
107*7c478bd9Sstevel@tonic-gate static int gld_update_vlan_kstat(kstat_t *, int);
108*7c478bd9Sstevel@tonic-gate 
109*7c478bd9Sstevel@tonic-gate /* called from gld_getinfo */
110*7c478bd9Sstevel@tonic-gate static dev_info_t *gld_finddevinfo(dev_t);
111*7c478bd9Sstevel@tonic-gate 
112*7c478bd9Sstevel@tonic-gate /* called from wput, wsrv, unidata, and v0_sched to send a packet */
113*7c478bd9Sstevel@tonic-gate /* also from the source routing stuff for sending RDE protocol packets */
114*7c478bd9Sstevel@tonic-gate static int gld_start(queue_t *, mblk_t *, int, uint32_t);
115*7c478bd9Sstevel@tonic-gate static int gld_start_mdt(queue_t *, mblk_t *, int);
116*7c478bd9Sstevel@tonic-gate 
117*7c478bd9Sstevel@tonic-gate /* called from gld_start[_mdt] to loopback packet(s) in promiscuous mode */
118*7c478bd9Sstevel@tonic-gate static void gld_precv(gld_mac_info_t *, gld_vlan_t *, mblk_t *);
119*7c478bd9Sstevel@tonic-gate static void gld_precv_mdt(gld_mac_info_t *, gld_vlan_t *, mblk_t *,
120*7c478bd9Sstevel@tonic-gate     pdesc_t *, pktinfo_t *);
121*7c478bd9Sstevel@tonic-gate 
122*7c478bd9Sstevel@tonic-gate /* receive group: called from gld_recv and gld_precv* with maclock held */
123*7c478bd9Sstevel@tonic-gate static void gld_sendup(gld_mac_info_t *, gld_vlan_t *, pktinfo_t *, mblk_t *,
124*7c478bd9Sstevel@tonic-gate     int (*)());
125*7c478bd9Sstevel@tonic-gate static int gld_accept(gld_t *, pktinfo_t *);
126*7c478bd9Sstevel@tonic-gate static int gld_mcmatch(gld_t *, pktinfo_t *);
127*7c478bd9Sstevel@tonic-gate static int gld_multicast(unsigned char *, gld_t *);
128*7c478bd9Sstevel@tonic-gate static int gld_paccept(gld_t *, pktinfo_t *);
129*7c478bd9Sstevel@tonic-gate static void gld_passon(gld_t *, mblk_t *, pktinfo_t *,
130*7c478bd9Sstevel@tonic-gate     void (*)(queue_t *, mblk_t *));
131*7c478bd9Sstevel@tonic-gate static mblk_t *gld_addudind(gld_t *, mblk_t *, pktinfo_t *);
132*7c478bd9Sstevel@tonic-gate 
133*7c478bd9Sstevel@tonic-gate /* wsrv group: called from wsrv, single threaded per queue */
134*7c478bd9Sstevel@tonic-gate static int gld_ioctl(queue_t *, mblk_t *);
135*7c478bd9Sstevel@tonic-gate static void gld_fastpath(gld_t *, queue_t *, mblk_t *);
136*7c478bd9Sstevel@tonic-gate static int gld_cmds(queue_t *, mblk_t *);
137*7c478bd9Sstevel@tonic-gate static mblk_t *gld_bindack(queue_t *, mblk_t *);
138*7c478bd9Sstevel@tonic-gate static int gld_notify_req(queue_t *, mblk_t *);
139*7c478bd9Sstevel@tonic-gate static int gld_udqos(queue_t *, mblk_t *);
140*7c478bd9Sstevel@tonic-gate static int gld_bind(queue_t *, mblk_t *);
141*7c478bd9Sstevel@tonic-gate static int gld_unbind(queue_t *, mblk_t *);
142*7c478bd9Sstevel@tonic-gate static int gld_inforeq(queue_t *, mblk_t *);
143*7c478bd9Sstevel@tonic-gate static int gld_unitdata(queue_t *, mblk_t *);
144*7c478bd9Sstevel@tonic-gate static int gldattach(queue_t *, mblk_t *);
145*7c478bd9Sstevel@tonic-gate static int gldunattach(queue_t *, mblk_t *);
146*7c478bd9Sstevel@tonic-gate static int gld_enable_multi(queue_t *, mblk_t *);
147*7c478bd9Sstevel@tonic-gate static int gld_disable_multi(queue_t *, mblk_t *);
148*7c478bd9Sstevel@tonic-gate static void gld_send_disable_multi(gld_mac_info_t *, gld_mcast_t *);
149*7c478bd9Sstevel@tonic-gate static int gld_promisc(queue_t *, mblk_t *, t_uscalar_t, boolean_t);
150*7c478bd9Sstevel@tonic-gate static int gld_physaddr(queue_t *, mblk_t *);
151*7c478bd9Sstevel@tonic-gate static int gld_setaddr(queue_t *, mblk_t *);
152*7c478bd9Sstevel@tonic-gate static int gld_get_statistics(queue_t *, mblk_t *);
153*7c478bd9Sstevel@tonic-gate static int gld_cap(queue_t *, mblk_t *);
154*7c478bd9Sstevel@tonic-gate static int gld_cap_ack(queue_t *, mblk_t *);
155*7c478bd9Sstevel@tonic-gate static int gld_cap_enable(queue_t *, mblk_t *);
156*7c478bd9Sstevel@tonic-gate 
157*7c478bd9Sstevel@tonic-gate /* misc utilities, some requiring various mutexes held */
158*7c478bd9Sstevel@tonic-gate static int gld_start_mac(gld_mac_info_t *);
159*7c478bd9Sstevel@tonic-gate static void gld_stop_mac(gld_mac_info_t *);
160*7c478bd9Sstevel@tonic-gate static void gld_set_ipq(gld_t *);
161*7c478bd9Sstevel@tonic-gate static void gld_flushqueue(queue_t *);
162*7c478bd9Sstevel@tonic-gate static glddev_t *gld_devlookup(int);
163*7c478bd9Sstevel@tonic-gate static int gld_findminor(glddev_t *);
164*7c478bd9Sstevel@tonic-gate static void gldinsque(void *, void *);
165*7c478bd9Sstevel@tonic-gate static void gldremque(void *);
166*7c478bd9Sstevel@tonic-gate void gld_bitrevcopy(caddr_t, caddr_t, size_t);
167*7c478bd9Sstevel@tonic-gate void gld_bitreverse(uchar_t *, size_t);
168*7c478bd9Sstevel@tonic-gate char *gld_macaddr_sprintf(char *, unsigned char *, int);
169*7c478bd9Sstevel@tonic-gate static gld_vlan_t *gld_add_vlan(gld_mac_info_t *, uint32_t vid);
170*7c478bd9Sstevel@tonic-gate static void gld_rem_vlan(gld_vlan_t *);
171*7c478bd9Sstevel@tonic-gate gld_vlan_t *gld_find_vlan(gld_mac_info_t *, uint32_t);
172*7c478bd9Sstevel@tonic-gate gld_vlan_t *gld_get_vlan(gld_mac_info_t *, uint32_t);
173*7c478bd9Sstevel@tonic-gate 
174*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
175*7c478bd9Sstevel@tonic-gate static void gld_check_assertions(void);
176*7c478bd9Sstevel@tonic-gate extern void gld_sr_dump(gld_mac_info_t *);
177*7c478bd9Sstevel@tonic-gate #endif
178*7c478bd9Sstevel@tonic-gate 
179*7c478bd9Sstevel@tonic-gate /*
180*7c478bd9Sstevel@tonic-gate  * Allocate and zero-out "number" structures each of type "structure" in
181*7c478bd9Sstevel@tonic-gate  * kernel memory.
182*7c478bd9Sstevel@tonic-gate  */
183*7c478bd9Sstevel@tonic-gate #define	GETSTRUCT(structure, number)   \
184*7c478bd9Sstevel@tonic-gate 	(kmem_zalloc((uint_t)(sizeof (structure) * (number)), KM_NOSLEEP))
185*7c478bd9Sstevel@tonic-gate 
186*7c478bd9Sstevel@tonic-gate #define	abs(a) ((a) < 0 ? -(a) : a)
187*7c478bd9Sstevel@tonic-gate 
188*7c478bd9Sstevel@tonic-gate uint32_t gld_global_options = GLD_OPT_NO_ETHRXSNAP;
189*7c478bd9Sstevel@tonic-gate 
190*7c478bd9Sstevel@tonic-gate /*
191*7c478bd9Sstevel@tonic-gate  * VLANs are only supported on ethernet devices that manipulate VLAN headers
192*7c478bd9Sstevel@tonic-gate  * themselves.
193*7c478bd9Sstevel@tonic-gate  */
194*7c478bd9Sstevel@tonic-gate #define	VLAN_CAPABLE(macinfo) \
195*7c478bd9Sstevel@tonic-gate 	((macinfo)->gldm_type == DL_ETHER && \
196*7c478bd9Sstevel@tonic-gate 	(macinfo)->gldm_send_tagged != NULL)
197*7c478bd9Sstevel@tonic-gate 
198*7c478bd9Sstevel@tonic-gate /*
199*7c478bd9Sstevel@tonic-gate  * The set of notifications generatable by GLD itself, the additional
200*7c478bd9Sstevel@tonic-gate  * set that can be generated if the MAC driver provide the link-state
201*7c478bd9Sstevel@tonic-gate  * tracking callback capability, and the set supported by the GLD
202*7c478bd9Sstevel@tonic-gate  * notification code below.
203*7c478bd9Sstevel@tonic-gate  *
204*7c478bd9Sstevel@tonic-gate  * PLEASE keep these in sync with what the code actually does!
205*7c478bd9Sstevel@tonic-gate  */
206*7c478bd9Sstevel@tonic-gate static const uint32_t gld_internal_notes =	DL_NOTE_PROMISC_ON_PHYS |
207*7c478bd9Sstevel@tonic-gate 						DL_NOTE_PROMISC_OFF_PHYS |
208*7c478bd9Sstevel@tonic-gate 						DL_NOTE_PHYS_ADDR;
209*7c478bd9Sstevel@tonic-gate static const uint32_t gld_linkstate_notes =	DL_NOTE_LINK_DOWN |
210*7c478bd9Sstevel@tonic-gate 						DL_NOTE_LINK_UP |
211*7c478bd9Sstevel@tonic-gate 						DL_NOTE_SPEED;
212*7c478bd9Sstevel@tonic-gate static const uint32_t gld_supported_notes =	DL_NOTE_PROMISC_ON_PHYS |
213*7c478bd9Sstevel@tonic-gate 						DL_NOTE_PROMISC_OFF_PHYS |
214*7c478bd9Sstevel@tonic-gate 						DL_NOTE_PHYS_ADDR |
215*7c478bd9Sstevel@tonic-gate 						DL_NOTE_LINK_DOWN |
216*7c478bd9Sstevel@tonic-gate 						DL_NOTE_LINK_UP |
217*7c478bd9Sstevel@tonic-gate 						DL_NOTE_SPEED;
218*7c478bd9Sstevel@tonic-gate 
219*7c478bd9Sstevel@tonic-gate /* Media must correspond to #defines in gld.h */
220*7c478bd9Sstevel@tonic-gate static char *gld_media[] = {
221*7c478bd9Sstevel@tonic-gate 	"unknown",	/* GLDM_UNKNOWN - driver cannot determine media */
222*7c478bd9Sstevel@tonic-gate 	"aui",		/* GLDM_AUI */
223*7c478bd9Sstevel@tonic-gate 	"bnc",		/* GLDM_BNC */
224*7c478bd9Sstevel@tonic-gate 	"twpair",	/* GLDM_TP */
225*7c478bd9Sstevel@tonic-gate 	"fiber",	/* GLDM_FIBER */
226*7c478bd9Sstevel@tonic-gate 	"100baseT",	/* GLDM_100BT */
227*7c478bd9Sstevel@tonic-gate 	"100vgAnyLan",	/* GLDM_VGANYLAN */
228*7c478bd9Sstevel@tonic-gate 	"10baseT",	/* GLDM_10BT */
229*7c478bd9Sstevel@tonic-gate 	"ring4",	/* GLDM_RING4 */
230*7c478bd9Sstevel@tonic-gate 	"ring16",	/* GLDM_RING16 */
231*7c478bd9Sstevel@tonic-gate 	"PHY/MII",	/* GLDM_PHYMII */
232*7c478bd9Sstevel@tonic-gate 	"100baseTX",	/* GLDM_100BTX */
233*7c478bd9Sstevel@tonic-gate 	"100baseT4",	/* GLDM_100BT4 */
234*7c478bd9Sstevel@tonic-gate 	"unknown",	/* skip */
235*7c478bd9Sstevel@tonic-gate 	"ipib",		/* GLDM_IB */
236*7c478bd9Sstevel@tonic-gate };
237*7c478bd9Sstevel@tonic-gate 
238*7c478bd9Sstevel@tonic-gate /* Must correspond to #defines in gld.h */
239*7c478bd9Sstevel@tonic-gate static char *gld_duplex[] = {
240*7c478bd9Sstevel@tonic-gate 	"unknown",	/* GLD_DUPLEX_UNKNOWN - not known or not applicable */
241*7c478bd9Sstevel@tonic-gate 	"half",		/* GLD_DUPLEX_HALF */
242*7c478bd9Sstevel@tonic-gate 	"full"		/* GLD_DUPLEX_FULL */
243*7c478bd9Sstevel@tonic-gate };
244*7c478bd9Sstevel@tonic-gate 
245*7c478bd9Sstevel@tonic-gate extern int gld_interpret_ether(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
246*7c478bd9Sstevel@tonic-gate extern int gld_interpret_fddi(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
247*7c478bd9Sstevel@tonic-gate extern int gld_interpret_tr(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
248*7c478bd9Sstevel@tonic-gate extern int gld_interpret_ib(gld_mac_info_t *, mblk_t *, pktinfo_t *, int);
249*7c478bd9Sstevel@tonic-gate extern void gld_interpret_mdt_ib(gld_mac_info_t *, mblk_t *, pdescinfo_t *,
250*7c478bd9Sstevel@tonic-gate     pktinfo_t *, int);
251*7c478bd9Sstevel@tonic-gate 
252*7c478bd9Sstevel@tonic-gate extern mblk_t *gld_fastpath_ether(gld_t *, mblk_t *);
253*7c478bd9Sstevel@tonic-gate extern mblk_t *gld_fastpath_fddi(gld_t *, mblk_t *);
254*7c478bd9Sstevel@tonic-gate extern mblk_t *gld_fastpath_tr(gld_t *, mblk_t *);
255*7c478bd9Sstevel@tonic-gate extern mblk_t *gld_fastpath_ib(gld_t *, mblk_t *);
256*7c478bd9Sstevel@tonic-gate 
257*7c478bd9Sstevel@tonic-gate extern mblk_t *gld_unitdata_ether(gld_t *, mblk_t *);
258*7c478bd9Sstevel@tonic-gate extern mblk_t *gld_unitdata_fddi(gld_t *, mblk_t *);
259*7c478bd9Sstevel@tonic-gate extern mblk_t *gld_unitdata_tr(gld_t *, mblk_t *);
260*7c478bd9Sstevel@tonic-gate extern mblk_t *gld_unitdata_ib(gld_t *, mblk_t *);
261*7c478bd9Sstevel@tonic-gate 
262*7c478bd9Sstevel@tonic-gate extern void gld_init_ether(gld_mac_info_t *);
263*7c478bd9Sstevel@tonic-gate extern void gld_init_fddi(gld_mac_info_t *);
264*7c478bd9Sstevel@tonic-gate extern void gld_init_tr(gld_mac_info_t *);
265*7c478bd9Sstevel@tonic-gate extern void gld_init_ib(gld_mac_info_t *);
266*7c478bd9Sstevel@tonic-gate 
267*7c478bd9Sstevel@tonic-gate extern void gld_uninit_ether(gld_mac_info_t *);
268*7c478bd9Sstevel@tonic-gate extern void gld_uninit_fddi(gld_mac_info_t *);
269*7c478bd9Sstevel@tonic-gate extern void gld_uninit_tr(gld_mac_info_t *);
270*7c478bd9Sstevel@tonic-gate extern void gld_uninit_ib(gld_mac_info_t *);
271*7c478bd9Sstevel@tonic-gate 
272*7c478bd9Sstevel@tonic-gate /*
273*7c478bd9Sstevel@tonic-gate  * Interface types currently supported by GLD.
274*7c478bd9Sstevel@tonic-gate  * If you add new types, you must check all "XXX" strings in the GLD source
275*7c478bd9Sstevel@tonic-gate  * for implementation issues that may affect the support of your new type.
276*7c478bd9Sstevel@tonic-gate  * In particular, any type with gldm_addrlen > 6, or gldm_saplen != -2, will
277*7c478bd9Sstevel@tonic-gate  * require generalizing this GLD source to handle the new cases.  In other
278*7c478bd9Sstevel@tonic-gate  * words there are assumptions built into the code in a few places that must
279*7c478bd9Sstevel@tonic-gate  * be fixed.  Be sure to turn on DEBUG/ASSERT code when testing a new type.
280*7c478bd9Sstevel@tonic-gate  */
281*7c478bd9Sstevel@tonic-gate static gld_interface_t interfaces[] = {
282*7c478bd9Sstevel@tonic-gate 
283*7c478bd9Sstevel@tonic-gate 	/* Ethernet Bus */
284*7c478bd9Sstevel@tonic-gate 	{
285*7c478bd9Sstevel@tonic-gate 		DL_ETHER,
286*7c478bd9Sstevel@tonic-gate 		(uint_t)-1,
287*7c478bd9Sstevel@tonic-gate 		sizeof (struct ether_mac_frm),
288*7c478bd9Sstevel@tonic-gate 		gld_interpret_ether,
289*7c478bd9Sstevel@tonic-gate 		NULL,
290*7c478bd9Sstevel@tonic-gate 		gld_fastpath_ether,
291*7c478bd9Sstevel@tonic-gate 		gld_unitdata_ether,
292*7c478bd9Sstevel@tonic-gate 		gld_init_ether,
293*7c478bd9Sstevel@tonic-gate 		gld_uninit_ether,
294*7c478bd9Sstevel@tonic-gate 		"ether"
295*7c478bd9Sstevel@tonic-gate 	},
296*7c478bd9Sstevel@tonic-gate 
297*7c478bd9Sstevel@tonic-gate 	/* Fiber Distributed data interface */
298*7c478bd9Sstevel@tonic-gate 	{
299*7c478bd9Sstevel@tonic-gate 		DL_FDDI,
300*7c478bd9Sstevel@tonic-gate 		4352,
301*7c478bd9Sstevel@tonic-gate 		sizeof (struct fddi_mac_frm),
302*7c478bd9Sstevel@tonic-gate 		gld_interpret_fddi,
303*7c478bd9Sstevel@tonic-gate 		NULL,
304*7c478bd9Sstevel@tonic-gate 		gld_fastpath_fddi,
305*7c478bd9Sstevel@tonic-gate 		gld_unitdata_fddi,
306*7c478bd9Sstevel@tonic-gate 		gld_init_fddi,
307*7c478bd9Sstevel@tonic-gate 		gld_uninit_fddi,
308*7c478bd9Sstevel@tonic-gate 		"fddi"
309*7c478bd9Sstevel@tonic-gate 	},
310*7c478bd9Sstevel@tonic-gate 
311*7c478bd9Sstevel@tonic-gate 	/* Token Ring interface */
312*7c478bd9Sstevel@tonic-gate 	{
313*7c478bd9Sstevel@tonic-gate 		DL_TPR,
314*7c478bd9Sstevel@tonic-gate 		17914,
315*7c478bd9Sstevel@tonic-gate 		-1,			/* variable header size */
316*7c478bd9Sstevel@tonic-gate 		gld_interpret_tr,
317*7c478bd9Sstevel@tonic-gate 		NULL,
318*7c478bd9Sstevel@tonic-gate 		gld_fastpath_tr,
319*7c478bd9Sstevel@tonic-gate 		gld_unitdata_tr,
320*7c478bd9Sstevel@tonic-gate 		gld_init_tr,
321*7c478bd9Sstevel@tonic-gate 		gld_uninit_tr,
322*7c478bd9Sstevel@tonic-gate 		"tpr"
323*7c478bd9Sstevel@tonic-gate 	},
324*7c478bd9Sstevel@tonic-gate 
325*7c478bd9Sstevel@tonic-gate 	/* Infiniband */
326*7c478bd9Sstevel@tonic-gate 	{
327*7c478bd9Sstevel@tonic-gate 		DL_IB,
328*7c478bd9Sstevel@tonic-gate 		4092,
329*7c478bd9Sstevel@tonic-gate 		sizeof (struct ipoib_header),
330*7c478bd9Sstevel@tonic-gate 		gld_interpret_ib,
331*7c478bd9Sstevel@tonic-gate 		gld_interpret_mdt_ib,
332*7c478bd9Sstevel@tonic-gate 		gld_fastpath_ib,
333*7c478bd9Sstevel@tonic-gate 		gld_unitdata_ib,
334*7c478bd9Sstevel@tonic-gate 		gld_init_ib,
335*7c478bd9Sstevel@tonic-gate 		gld_uninit_ib,
336*7c478bd9Sstevel@tonic-gate 		"ipib"
337*7c478bd9Sstevel@tonic-gate 	},
338*7c478bd9Sstevel@tonic-gate };
339*7c478bd9Sstevel@tonic-gate 
340*7c478bd9Sstevel@tonic-gate /*
341*7c478bd9Sstevel@tonic-gate  * bit reversal lookup table.
342*7c478bd9Sstevel@tonic-gate  */
343*7c478bd9Sstevel@tonic-gate static	uchar_t bit_rev[] = {
344*7c478bd9Sstevel@tonic-gate 	0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0,
345*7c478bd9Sstevel@tonic-gate 	0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
346*7c478bd9Sstevel@tonic-gate 	0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4,
347*7c478bd9Sstevel@tonic-gate 	0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
348*7c478bd9Sstevel@tonic-gate 	0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc,
349*7c478bd9Sstevel@tonic-gate 	0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
350*7c478bd9Sstevel@tonic-gate 	0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca,
351*7c478bd9Sstevel@tonic-gate 	0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
352*7c478bd9Sstevel@tonic-gate 	0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6,
353*7c478bd9Sstevel@tonic-gate 	0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
354*7c478bd9Sstevel@tonic-gate 	0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1,
355*7c478bd9Sstevel@tonic-gate 	0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
356*7c478bd9Sstevel@tonic-gate 	0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
357*7c478bd9Sstevel@tonic-gate 	0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
358*7c478bd9Sstevel@tonic-gate 	0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd,
359*7c478bd9Sstevel@tonic-gate 	0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
360*7c478bd9Sstevel@tonic-gate 	0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3,
361*7c478bd9Sstevel@tonic-gate 	0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
362*7c478bd9Sstevel@tonic-gate 	0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7,
363*7c478bd9Sstevel@tonic-gate 	0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
364*7c478bd9Sstevel@tonic-gate 	0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf,
365*7c478bd9Sstevel@tonic-gate 	0x3f, 0xbf, 0x7f, 0xff,
366*7c478bd9Sstevel@tonic-gate };
367*7c478bd9Sstevel@tonic-gate 
368*7c478bd9Sstevel@tonic-gate /*
369*7c478bd9Sstevel@tonic-gate  * User priorities, mapped from b_band.
370*7c478bd9Sstevel@tonic-gate  */
371*7c478bd9Sstevel@tonic-gate static uint32_t user_priority[] = {
372*7c478bd9Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
373*7c478bd9Sstevel@tonic-gate 	0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
374*7c478bd9Sstevel@tonic-gate 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
375*7c478bd9Sstevel@tonic-gate 	1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
376*7c478bd9Sstevel@tonic-gate 	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
377*7c478bd9Sstevel@tonic-gate 	2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
378*7c478bd9Sstevel@tonic-gate 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
379*7c478bd9Sstevel@tonic-gate 	3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
380*7c478bd9Sstevel@tonic-gate 	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
381*7c478bd9Sstevel@tonic-gate 	4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
382*7c478bd9Sstevel@tonic-gate 	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
383*7c478bd9Sstevel@tonic-gate 	5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
384*7c478bd9Sstevel@tonic-gate 	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
385*7c478bd9Sstevel@tonic-gate 	6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
386*7c478bd9Sstevel@tonic-gate 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
387*7c478bd9Sstevel@tonic-gate 	7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
388*7c478bd9Sstevel@tonic-gate };
389*7c478bd9Sstevel@tonic-gate 
390*7c478bd9Sstevel@tonic-gate #define	UPRI(gld, band)	((band != 0) ? user_priority[(band)] : (gld)->gld_upri)
391*7c478bd9Sstevel@tonic-gate 
392*7c478bd9Sstevel@tonic-gate static struct glddevice gld_device_list;  /* Per-system root of GLD tables */
393*7c478bd9Sstevel@tonic-gate 
394*7c478bd9Sstevel@tonic-gate /*
395*7c478bd9Sstevel@tonic-gate  * Module linkage information for the kernel.
396*7c478bd9Sstevel@tonic-gate  */
397*7c478bd9Sstevel@tonic-gate 
398*7c478bd9Sstevel@tonic-gate static struct modldrv modlmisc = {
399*7c478bd9Sstevel@tonic-gate 	&mod_miscops,		/* Type of module - a utility provider */
400*7c478bd9Sstevel@tonic-gate 	"Generic LAN Driver (" GLD_VERSION_STRING ") %I%"
401*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
402*7c478bd9Sstevel@tonic-gate 	" DEBUG"
403*7c478bd9Sstevel@tonic-gate #endif
404*7c478bd9Sstevel@tonic-gate };
405*7c478bd9Sstevel@tonic-gate 
406*7c478bd9Sstevel@tonic-gate static struct modlinkage modlinkage = {
407*7c478bd9Sstevel@tonic-gate 	MODREV_1, &modlmisc, NULL
408*7c478bd9Sstevel@tonic-gate };
409*7c478bd9Sstevel@tonic-gate 
410*7c478bd9Sstevel@tonic-gate int
411*7c478bd9Sstevel@tonic-gate _init(void)
412*7c478bd9Sstevel@tonic-gate {
413*7c478bd9Sstevel@tonic-gate 	int e;
414*7c478bd9Sstevel@tonic-gate 
415*7c478bd9Sstevel@tonic-gate 	/* initialize gld_device_list mutex */
416*7c478bd9Sstevel@tonic-gate 	mutex_init(&gld_device_list.gld_devlock, NULL, MUTEX_DRIVER, NULL);
417*7c478bd9Sstevel@tonic-gate 
418*7c478bd9Sstevel@tonic-gate 	/* initialize device driver (per-major) list */
419*7c478bd9Sstevel@tonic-gate 	gld_device_list.gld_next =
420*7c478bd9Sstevel@tonic-gate 	    gld_device_list.gld_prev = &gld_device_list;
421*7c478bd9Sstevel@tonic-gate 
422*7c478bd9Sstevel@tonic-gate 	if ((e = mod_install(&modlinkage)) != 0)
423*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&gld_device_list.gld_devlock);
424*7c478bd9Sstevel@tonic-gate 
425*7c478bd9Sstevel@tonic-gate 	return (e);
426*7c478bd9Sstevel@tonic-gate }
427*7c478bd9Sstevel@tonic-gate 
428*7c478bd9Sstevel@tonic-gate int
429*7c478bd9Sstevel@tonic-gate _fini(void)
430*7c478bd9Sstevel@tonic-gate {
431*7c478bd9Sstevel@tonic-gate 	int e;
432*7c478bd9Sstevel@tonic-gate 
433*7c478bd9Sstevel@tonic-gate 	if ((e = mod_remove(&modlinkage)) != 0)
434*7c478bd9Sstevel@tonic-gate 		return (e);
435*7c478bd9Sstevel@tonic-gate 
436*7c478bd9Sstevel@tonic-gate 	ASSERT(gld_device_list.gld_next ==
437*7c478bd9Sstevel@tonic-gate 	    (glddev_t *)&gld_device_list.gld_next);
438*7c478bd9Sstevel@tonic-gate 	ASSERT(gld_device_list.gld_prev ==
439*7c478bd9Sstevel@tonic-gate 	    (glddev_t *)&gld_device_list.gld_next);
440*7c478bd9Sstevel@tonic-gate 	mutex_destroy(&gld_device_list.gld_devlock);
441*7c478bd9Sstevel@tonic-gate 
442*7c478bd9Sstevel@tonic-gate 	return (e);
443*7c478bd9Sstevel@tonic-gate }
444*7c478bd9Sstevel@tonic-gate 
445*7c478bd9Sstevel@tonic-gate int
446*7c478bd9Sstevel@tonic-gate _info(struct modinfo *modinfop)
447*7c478bd9Sstevel@tonic-gate {
448*7c478bd9Sstevel@tonic-gate 	return (mod_info(&modlinkage, modinfop));
449*7c478bd9Sstevel@tonic-gate }
450*7c478bd9Sstevel@tonic-gate 
451*7c478bd9Sstevel@tonic-gate /*
452*7c478bd9Sstevel@tonic-gate  * GLD service routines
453*7c478bd9Sstevel@tonic-gate  */
454*7c478bd9Sstevel@tonic-gate 
455*7c478bd9Sstevel@tonic-gate /* So this gld binary maybe can be forward compatible with future v2 drivers */
456*7c478bd9Sstevel@tonic-gate #define	GLD_MAC_RESERVED (16 * sizeof (caddr_t))
457*7c478bd9Sstevel@tonic-gate 
458*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
459*7c478bd9Sstevel@tonic-gate gld_mac_info_t *
460*7c478bd9Sstevel@tonic-gate gld_mac_alloc(dev_info_t *devinfo)
461*7c478bd9Sstevel@tonic-gate {
462*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
463*7c478bd9Sstevel@tonic-gate 
464*7c478bd9Sstevel@tonic-gate 	macinfo = kmem_zalloc(sizeof (gld_mac_info_t) + GLD_MAC_RESERVED,
465*7c478bd9Sstevel@tonic-gate 	    KM_SLEEP);
466*7c478bd9Sstevel@tonic-gate 
467*7c478bd9Sstevel@tonic-gate 	/*
468*7c478bd9Sstevel@tonic-gate 	 * The setting of gldm_driver_version will not be documented or allowed
469*7c478bd9Sstevel@tonic-gate 	 * until a future release.
470*7c478bd9Sstevel@tonic-gate 	 */
471*7c478bd9Sstevel@tonic-gate 	macinfo->gldm_driver_version = GLD_VERSION_200;
472*7c478bd9Sstevel@tonic-gate 
473*7c478bd9Sstevel@tonic-gate 	/*
474*7c478bd9Sstevel@tonic-gate 	 * GLD's version.  This also is undocumented for now, but will be
475*7c478bd9Sstevel@tonic-gate 	 * available if needed in the future.
476*7c478bd9Sstevel@tonic-gate 	 */
477*7c478bd9Sstevel@tonic-gate 	macinfo->gldm_GLD_version = GLD_VERSION;
478*7c478bd9Sstevel@tonic-gate 
479*7c478bd9Sstevel@tonic-gate 	return (macinfo);
480*7c478bd9Sstevel@tonic-gate }
481*7c478bd9Sstevel@tonic-gate 
482*7c478bd9Sstevel@tonic-gate /*
483*7c478bd9Sstevel@tonic-gate  * gld_mac_free must be called after the driver has removed interrupts
484*7c478bd9Sstevel@tonic-gate  * and completely stopped calling gld_recv() and gld_sched().  At that
485*7c478bd9Sstevel@tonic-gate  * point the interrupt routine is guaranteed by the system to have been
486*7c478bd9Sstevel@tonic-gate  * exited and the maclock is no longer needed.  Of course, it is
487*7c478bd9Sstevel@tonic-gate  * expected (required) that (assuming gld_register() succeeded),
488*7c478bd9Sstevel@tonic-gate  * gld_unregister() was called before gld_mac_free().
489*7c478bd9Sstevel@tonic-gate  */
490*7c478bd9Sstevel@tonic-gate void
491*7c478bd9Sstevel@tonic-gate gld_mac_free(gld_mac_info_t *macinfo)
492*7c478bd9Sstevel@tonic-gate {
493*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo);
494*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_GLD_version == GLD_VERSION);
495*7c478bd9Sstevel@tonic-gate 
496*7c478bd9Sstevel@tonic-gate 	/*
497*7c478bd9Sstevel@tonic-gate 	 * Assert that if we made it through gld_register, then we must
498*7c478bd9Sstevel@tonic-gate 	 * have unregistered.
499*7c478bd9Sstevel@tonic-gate 	 */
500*7c478bd9Sstevel@tonic-gate 	ASSERT(!GLDM_LOCK_INITED(macinfo) ||
501*7c478bd9Sstevel@tonic-gate 	    (macinfo->gldm_GLD_flags & GLD_UNREGISTERED));
502*7c478bd9Sstevel@tonic-gate 
503*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK_DESTROY(macinfo);
504*7c478bd9Sstevel@tonic-gate 
505*7c478bd9Sstevel@tonic-gate 	kmem_free(macinfo, sizeof (gld_mac_info_t) + GLD_MAC_RESERVED);
506*7c478bd9Sstevel@tonic-gate }
507*7c478bd9Sstevel@tonic-gate 
508*7c478bd9Sstevel@tonic-gate /*
509*7c478bd9Sstevel@tonic-gate  * gld_register -- called once per device instance (PPA)
510*7c478bd9Sstevel@tonic-gate  *
511*7c478bd9Sstevel@tonic-gate  * During its attach routine, a real device driver will register with GLD
512*7c478bd9Sstevel@tonic-gate  * so that later opens and dl_attach_reqs will work.  The arguments are the
513*7c478bd9Sstevel@tonic-gate  * devinfo pointer, the device name, and a macinfo structure describing the
514*7c478bd9Sstevel@tonic-gate  * physical device instance.
515*7c478bd9Sstevel@tonic-gate  */
516*7c478bd9Sstevel@tonic-gate int
517*7c478bd9Sstevel@tonic-gate gld_register(dev_info_t *devinfo, char *devname, gld_mac_info_t *macinfo)
518*7c478bd9Sstevel@tonic-gate {
519*7c478bd9Sstevel@tonic-gate 	int mediatype;
520*7c478bd9Sstevel@tonic-gate 	int major = ddi_name_to_major(devname), i;
521*7c478bd9Sstevel@tonic-gate 	glddev_t *glddev;
522*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
523*7c478bd9Sstevel@tonic-gate 	char minordev[32];
524*7c478bd9Sstevel@tonic-gate 	char pbuf[3*GLD_MAX_ADDRLEN];
525*7c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
526*7c478bd9Sstevel@tonic-gate 
527*7c478bd9Sstevel@tonic-gate 	ASSERT(devinfo != NULL);
528*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
529*7c478bd9Sstevel@tonic-gate 
530*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_driver_version != GLD_VERSION)
531*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
532*7c478bd9Sstevel@tonic-gate 
533*7c478bd9Sstevel@tonic-gate 	mediatype = macinfo->gldm_type;
534*7c478bd9Sstevel@tonic-gate 
535*7c478bd9Sstevel@tonic-gate 	/*
536*7c478bd9Sstevel@tonic-gate 	 * Entry points should be ready for us.
537*7c478bd9Sstevel@tonic-gate 	 * ioctl is optional.
538*7c478bd9Sstevel@tonic-gate 	 * set_multicast and get_stats are optional in v0.
539*7c478bd9Sstevel@tonic-gate 	 * intr is only required if you add an interrupt.
540*7c478bd9Sstevel@tonic-gate 	 */
541*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_reset != NULL);
542*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_start != NULL);
543*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_stop != NULL);
544*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_set_mac_addr != NULL);
545*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_set_promiscuous != NULL);
546*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_send != NULL);
547*7c478bd9Sstevel@tonic-gate 
548*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_maxpkt >= macinfo->gldm_minpkt);
549*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_GLD_version == GLD_VERSION);
550*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_broadcast_addr != NULL);
551*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_vendor_addr != NULL);
552*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_ident != NULL);
553*7c478bd9Sstevel@tonic-gate 
554*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_addrlen > GLD_MAX_ADDRLEN) {
555*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "GLD: %s driver gldm_addrlen %d > %d not sup"
556*7c478bd9Sstevel@tonic-gate 		    "ported", devname, macinfo->gldm_addrlen, GLD_MAX_ADDRLEN);
557*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
558*7c478bd9Sstevel@tonic-gate 	}
559*7c478bd9Sstevel@tonic-gate 
560*7c478bd9Sstevel@tonic-gate 	/*
561*7c478bd9Sstevel@tonic-gate 	 * GLD only functions properly with saplen == -2
562*7c478bd9Sstevel@tonic-gate 	 */
563*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_saplen != -2) {
564*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "GLD: %s driver gldm_saplen %d != -2 "
565*7c478bd9Sstevel@tonic-gate 		    "not supported", devname, macinfo->gldm_saplen);
566*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
567*7c478bd9Sstevel@tonic-gate 	}
568*7c478bd9Sstevel@tonic-gate 
569*7c478bd9Sstevel@tonic-gate 	/* see gld_rsrv() */
570*7c478bd9Sstevel@tonic-gate 	if (ddi_getprop(DDI_DEV_T_NONE, devinfo, 0, "fast_recv", 0))
571*7c478bd9Sstevel@tonic-gate 		macinfo->gldm_options |= GLDOPT_FAST_RECV;
572*7c478bd9Sstevel@tonic-gate 
573*7c478bd9Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
574*7c478bd9Sstevel@tonic-gate 	glddev = gld_devlookup(major);
575*7c478bd9Sstevel@tonic-gate 
576*7c478bd9Sstevel@tonic-gate 	/*
577*7c478bd9Sstevel@tonic-gate 	 *  Allocate per-driver (major) data structure if necessary
578*7c478bd9Sstevel@tonic-gate 	 */
579*7c478bd9Sstevel@tonic-gate 	if (glddev == NULL) {
580*7c478bd9Sstevel@tonic-gate 		/* first occurrence of this device name (major number) */
581*7c478bd9Sstevel@tonic-gate 		glddev = GETSTRUCT(glddev_t, 1);
582*7c478bd9Sstevel@tonic-gate 		if (glddev == NULL) {
583*7c478bd9Sstevel@tonic-gate 			mutex_exit(&gld_device_list.gld_devlock);
584*7c478bd9Sstevel@tonic-gate 			return (DDI_FAILURE);
585*7c478bd9Sstevel@tonic-gate 		}
586*7c478bd9Sstevel@tonic-gate 		(void) strncpy(glddev->gld_name, devname,
587*7c478bd9Sstevel@tonic-gate 		    sizeof (glddev->gld_name) - 1);
588*7c478bd9Sstevel@tonic-gate 		glddev->gld_major = major;
589*7c478bd9Sstevel@tonic-gate 		glddev->gld_nextminor = GLD_MIN_CLONE_MINOR;
590*7c478bd9Sstevel@tonic-gate 		glddev->gld_mac_next = glddev->gld_mac_prev =
591*7c478bd9Sstevel@tonic-gate 			(gld_mac_info_t *)&glddev->gld_mac_next;
592*7c478bd9Sstevel@tonic-gate 		glddev->gld_str_next = glddev->gld_str_prev =
593*7c478bd9Sstevel@tonic-gate 			(gld_t *)&glddev->gld_str_next;
594*7c478bd9Sstevel@tonic-gate 		mutex_init(&glddev->gld_devlock, NULL, MUTEX_DRIVER, NULL);
595*7c478bd9Sstevel@tonic-gate 
596*7c478bd9Sstevel@tonic-gate 		/* allow increase of number of supported multicast addrs */
597*7c478bd9Sstevel@tonic-gate 		glddev->gld_multisize = ddi_getprop(DDI_DEV_T_NONE,
598*7c478bd9Sstevel@tonic-gate 		    devinfo, 0, "multisize", GLD_MAX_MULTICAST);
599*7c478bd9Sstevel@tonic-gate 
600*7c478bd9Sstevel@tonic-gate 		/*
601*7c478bd9Sstevel@tonic-gate 		 * Optionally restrict DLPI provider style
602*7c478bd9Sstevel@tonic-gate 		 *
603*7c478bd9Sstevel@tonic-gate 		 * -1 - don't create style 1 nodes
604*7c478bd9Sstevel@tonic-gate 		 * -2 - don't create style 2 nodes
605*7c478bd9Sstevel@tonic-gate 		 */
606*7c478bd9Sstevel@tonic-gate 		glddev->gld_styles = ddi_getprop(DDI_DEV_T_NONE, devinfo, 0,
607*7c478bd9Sstevel@tonic-gate 		    "gld-provider-styles", 0);
608*7c478bd9Sstevel@tonic-gate 
609*7c478bd9Sstevel@tonic-gate 		/* Stuff that's needed before any PPA gets attached */
610*7c478bd9Sstevel@tonic-gate 		glddev->gld_type = macinfo->gldm_type;
611*7c478bd9Sstevel@tonic-gate 		glddev->gld_minsdu = macinfo->gldm_minpkt;
612*7c478bd9Sstevel@tonic-gate 		glddev->gld_saplen = macinfo->gldm_saplen;
613*7c478bd9Sstevel@tonic-gate 		glddev->gld_addrlen = macinfo->gldm_addrlen;
614*7c478bd9Sstevel@tonic-gate 		glddev->gld_broadcast = kmem_zalloc(macinfo->gldm_addrlen,
615*7c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
616*7c478bd9Sstevel@tonic-gate 		bcopy(macinfo->gldm_broadcast_addr,
617*7c478bd9Sstevel@tonic-gate 		    glddev->gld_broadcast, macinfo->gldm_addrlen);
618*7c478bd9Sstevel@tonic-gate 		glddev->gld_maxsdu = macinfo->gldm_maxpkt;
619*7c478bd9Sstevel@tonic-gate 		gldinsque(glddev, gld_device_list.gld_prev);
620*7c478bd9Sstevel@tonic-gate 	}
621*7c478bd9Sstevel@tonic-gate 	glddev->gld_ndevice++;
622*7c478bd9Sstevel@tonic-gate 	/* Now glddev can't go away until we unregister this mac (or fail) */
623*7c478bd9Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
624*7c478bd9Sstevel@tonic-gate 
625*7c478bd9Sstevel@tonic-gate 	/*
626*7c478bd9Sstevel@tonic-gate 	 *  Per-instance initialization
627*7c478bd9Sstevel@tonic-gate 	 */
628*7c478bd9Sstevel@tonic-gate 
629*7c478bd9Sstevel@tonic-gate 	/*
630*7c478bd9Sstevel@tonic-gate 	 * Initialize per-mac structure that is private to GLD.
631*7c478bd9Sstevel@tonic-gate 	 * Set up interface pointer. These are device class specific pointers
632*7c478bd9Sstevel@tonic-gate 	 * used to handle FDDI/TR/ETHER/IPoIB specific packets.
633*7c478bd9Sstevel@tonic-gate 	 */
634*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < sizeof (interfaces)/sizeof (*interfaces); i++) {
635*7c478bd9Sstevel@tonic-gate 		if (mediatype != interfaces[i].mac_type)
636*7c478bd9Sstevel@tonic-gate 			continue;
637*7c478bd9Sstevel@tonic-gate 
638*7c478bd9Sstevel@tonic-gate 		macinfo->gldm_mac_pvt = kmem_zalloc(sizeof (gld_mac_pvt_t),
639*7c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
640*7c478bd9Sstevel@tonic-gate 		((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep = ifp =
641*7c478bd9Sstevel@tonic-gate 		    &interfaces[i];
642*7c478bd9Sstevel@tonic-gate 		break;
643*7c478bd9Sstevel@tonic-gate 	}
644*7c478bd9Sstevel@tonic-gate 
645*7c478bd9Sstevel@tonic-gate 	if (ifp == NULL) {
646*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "GLD: this version does not support %s driver "
647*7c478bd9Sstevel@tonic-gate 		    "of type %d", devname, mediatype);
648*7c478bd9Sstevel@tonic-gate 		goto failure;
649*7c478bd9Sstevel@tonic-gate 	}
650*7c478bd9Sstevel@tonic-gate 
651*7c478bd9Sstevel@tonic-gate 	/*
652*7c478bd9Sstevel@tonic-gate 	 * Driver can only register MTU within legal media range.
653*7c478bd9Sstevel@tonic-gate 	 */
654*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_maxpkt > ifp->mtu_size) {
655*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "GLD: oversize MTU is specified by driver %s",
656*7c478bd9Sstevel@tonic-gate 		    devname);
657*7c478bd9Sstevel@tonic-gate 		goto failure;
658*7c478bd9Sstevel@tonic-gate 	}
659*7c478bd9Sstevel@tonic-gate 
660*7c478bd9Sstevel@tonic-gate 	/*
661*7c478bd9Sstevel@tonic-gate 	 * For now, only Infiniband drivers can use MDT. Do not add
662*7c478bd9Sstevel@tonic-gate 	 * support for Ethernet, FDDI or TR.
663*7c478bd9Sstevel@tonic-gate 	 */
664*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_mdt_pre != NULL) {
665*7c478bd9Sstevel@tonic-gate 		if (mediatype != DL_IB) {
666*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "GLD: MDT not supported for %s "
667*7c478bd9Sstevel@tonic-gate 			    "driver of type %d", devname, mediatype);
668*7c478bd9Sstevel@tonic-gate 			goto failure;
669*7c478bd9Sstevel@tonic-gate 		}
670*7c478bd9Sstevel@tonic-gate 
671*7c478bd9Sstevel@tonic-gate 		/*
672*7c478bd9Sstevel@tonic-gate 		 * Validate entry points.
673*7c478bd9Sstevel@tonic-gate 		 */
674*7c478bd9Sstevel@tonic-gate 		if ((macinfo->gldm_mdt_send == NULL) ||
675*7c478bd9Sstevel@tonic-gate 		    (macinfo->gldm_mdt_post == NULL)) {
676*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN, "GLD: invalid MDT entry points for "
677*7c478bd9Sstevel@tonic-gate 			    "%s driver of type %d", devname, mediatype);
678*7c478bd9Sstevel@tonic-gate 			goto failure;
679*7c478bd9Sstevel@tonic-gate 		}
680*7c478bd9Sstevel@tonic-gate 		macinfo->gldm_options |= GLDOPT_MDT;
681*7c478bd9Sstevel@tonic-gate 	}
682*7c478bd9Sstevel@tonic-gate 
683*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
684*7c478bd9Sstevel@tonic-gate 	mac_pvt->major_dev = glddev;
685*7c478bd9Sstevel@tonic-gate 
686*7c478bd9Sstevel@tonic-gate 	mac_pvt->curr_macaddr = kmem_zalloc(macinfo->gldm_addrlen, KM_SLEEP);
687*7c478bd9Sstevel@tonic-gate 	/*
688*7c478bd9Sstevel@tonic-gate 	 * XXX Do bit-reversed devices store gldm_vendor in canonical
689*7c478bd9Sstevel@tonic-gate 	 * format or in wire format?  Also gldm_broadcast.  For now
690*7c478bd9Sstevel@tonic-gate 	 * we are assuming canonical, but I'm not sure that makes the
691*7c478bd9Sstevel@tonic-gate 	 * most sense for ease of driver implementation.
692*7c478bd9Sstevel@tonic-gate 	 */
693*7c478bd9Sstevel@tonic-gate 	bcopy(macinfo->gldm_vendor_addr, mac_pvt->curr_macaddr,
694*7c478bd9Sstevel@tonic-gate 	    macinfo->gldm_addrlen);
695*7c478bd9Sstevel@tonic-gate 	mac_pvt->statistics = kmem_zalloc(sizeof (struct gld_stats), KM_SLEEP);
696*7c478bd9Sstevel@tonic-gate 
697*7c478bd9Sstevel@tonic-gate 	/*
698*7c478bd9Sstevel@tonic-gate 	 * The available set of notifications is those generatable by GLD
699*7c478bd9Sstevel@tonic-gate 	 * itself, plus those corresponding to the capabilities of the MAC
700*7c478bd9Sstevel@tonic-gate 	 * driver, intersected with those supported by gld_notify_ind() above.
701*7c478bd9Sstevel@tonic-gate 	 */
702*7c478bd9Sstevel@tonic-gate 	mac_pvt->notifications = gld_internal_notes;
703*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_LINKSTATE)
704*7c478bd9Sstevel@tonic-gate 		mac_pvt->notifications |= gld_linkstate_notes;
705*7c478bd9Sstevel@tonic-gate 	mac_pvt->notifications &= gld_supported_notes;
706*7c478bd9Sstevel@tonic-gate 
707*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK_INIT(macinfo);
708*7c478bd9Sstevel@tonic-gate 
709*7c478bd9Sstevel@tonic-gate 	ddi_set_driver_private(devinfo, macinfo);
710*7c478bd9Sstevel@tonic-gate 
711*7c478bd9Sstevel@tonic-gate 	/*
712*7c478bd9Sstevel@tonic-gate 	 * Now atomically get a PPA and put ourselves on the mac list.
713*7c478bd9Sstevel@tonic-gate 	 */
714*7c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
715*7c478bd9Sstevel@tonic-gate 
716*7c478bd9Sstevel@tonic-gate #ifdef DEBUG
717*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_ppa != ddi_get_instance(devinfo))
718*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "%s%d instance != ppa %d",
719*7c478bd9Sstevel@tonic-gate 		    ddi_driver_name(devinfo), ddi_get_instance(devinfo),
720*7c478bd9Sstevel@tonic-gate 		    macinfo->gldm_ppa);
721*7c478bd9Sstevel@tonic-gate #endif
722*7c478bd9Sstevel@tonic-gate 
723*7c478bd9Sstevel@tonic-gate 	/*
724*7c478bd9Sstevel@tonic-gate 	 * Create style 2 node (gated by gld-provider-styles property).
725*7c478bd9Sstevel@tonic-gate 	 *
726*7c478bd9Sstevel@tonic-gate 	 * NOTE: When the CLONE_DEV flag is specified to
727*7c478bd9Sstevel@tonic-gate 	 *	 ddi_create_minor_node() the minor number argument is
728*7c478bd9Sstevel@tonic-gate 	 *	 immaterial. Opens of that node will go via the clone
729*7c478bd9Sstevel@tonic-gate 	 *	 driver and gld_open() will always be passed a dev_t with
730*7c478bd9Sstevel@tonic-gate 	 *	 minor of zero.
731*7c478bd9Sstevel@tonic-gate 	 */
732*7c478bd9Sstevel@tonic-gate 	if (glddev->gld_styles != -2) {
733*7c478bd9Sstevel@tonic-gate 		if (ddi_create_minor_node(devinfo, glddev->gld_name, S_IFCHR,
734*7c478bd9Sstevel@tonic-gate 		    0, DDI_NT_NET, CLONE_DEV) == DDI_FAILURE) {
735*7c478bd9Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
736*7c478bd9Sstevel@tonic-gate 			goto late_failure;
737*7c478bd9Sstevel@tonic-gate 		}
738*7c478bd9Sstevel@tonic-gate 	}
739*7c478bd9Sstevel@tonic-gate 
740*7c478bd9Sstevel@tonic-gate 	/*
741*7c478bd9Sstevel@tonic-gate 	 * Create style 1 node (gated by gld-provider-styles property)
742*7c478bd9Sstevel@tonic-gate 	 */
743*7c478bd9Sstevel@tonic-gate 	if (glddev->gld_styles != -1) {
744*7c478bd9Sstevel@tonic-gate 		(void) sprintf(minordev, "%s%d", glddev->gld_name,
745*7c478bd9Sstevel@tonic-gate 		    macinfo->gldm_ppa);
746*7c478bd9Sstevel@tonic-gate 		if (ddi_create_minor_node(devinfo, minordev, S_IFCHR,
747*7c478bd9Sstevel@tonic-gate 		    GLD_STYLE1_PPA_TO_MINOR(macinfo->gldm_ppa), DDI_NT_NET,
748*7c478bd9Sstevel@tonic-gate 		    0) != DDI_SUCCESS) {
749*7c478bd9Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
750*7c478bd9Sstevel@tonic-gate 			goto late_failure;
751*7c478bd9Sstevel@tonic-gate 		}
752*7c478bd9Sstevel@tonic-gate 	}
753*7c478bd9Sstevel@tonic-gate 
754*7c478bd9Sstevel@tonic-gate 	/* add ourselves to this major device's linked list of instances */
755*7c478bd9Sstevel@tonic-gate 	gldinsque(macinfo, glddev->gld_mac_prev);
756*7c478bd9Sstevel@tonic-gate 
757*7c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
758*7c478bd9Sstevel@tonic-gate 
759*7c478bd9Sstevel@tonic-gate 	/*
760*7c478bd9Sstevel@tonic-gate 	 * Unfortunately we need the ppa before we call gld_initstats();
761*7c478bd9Sstevel@tonic-gate 	 * otherwise we would like to do this just above the mutex_enter
762*7c478bd9Sstevel@tonic-gate 	 * above.  In which case we could have set MAC_READY inside the
763*7c478bd9Sstevel@tonic-gate 	 * mutex and we wouldn't have needed to check it in open and
764*7c478bd9Sstevel@tonic-gate 	 * DL_ATTACH.  We wouldn't like to do the initstats/kstat_create
765*7c478bd9Sstevel@tonic-gate 	 * inside the mutex because it might get taken in our kstat_update
766*7c478bd9Sstevel@tonic-gate 	 * routine and cause a deadlock with kstat_chain_lock.
767*7c478bd9Sstevel@tonic-gate 	 */
768*7c478bd9Sstevel@tonic-gate 
769*7c478bd9Sstevel@tonic-gate 	/* gld_initstats() calls (*ifp->init)() */
770*7c478bd9Sstevel@tonic-gate 	if (gld_initstats(macinfo) != GLD_SUCCESS) {
771*7c478bd9Sstevel@tonic-gate 		mutex_enter(&glddev->gld_devlock);
772*7c478bd9Sstevel@tonic-gate 		gldremque(macinfo);
773*7c478bd9Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
774*7c478bd9Sstevel@tonic-gate 		goto late_failure;
775*7c478bd9Sstevel@tonic-gate 	}
776*7c478bd9Sstevel@tonic-gate 
777*7c478bd9Sstevel@tonic-gate 	/*
778*7c478bd9Sstevel@tonic-gate 	 * Need to indicate we are NOW ready to process interrupts;
779*7c478bd9Sstevel@tonic-gate 	 * any interrupt before this is set is for someone else.
780*7c478bd9Sstevel@tonic-gate 	 * This flag is also now used to tell open, et. al. that this
781*7c478bd9Sstevel@tonic-gate 	 * mac is now fully ready and available for use.
782*7c478bd9Sstevel@tonic-gate 	 */
783*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
784*7c478bd9Sstevel@tonic-gate 	macinfo->gldm_GLD_flags |= GLD_MAC_READY;
785*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
786*7c478bd9Sstevel@tonic-gate 
787*7c478bd9Sstevel@tonic-gate 	/* log local ethernet address -- XXX not DDI compliant */
788*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_addrlen == sizeof (struct ether_addr))
789*7c478bd9Sstevel@tonic-gate 		(void) localetheraddr(
790*7c478bd9Sstevel@tonic-gate 		    (struct ether_addr *)macinfo->gldm_vendor_addr, NULL);
791*7c478bd9Sstevel@tonic-gate 
792*7c478bd9Sstevel@tonic-gate 	/* now put announcement into the message buffer */
793*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_CONT, "!%s%d: %s: type \"%s\" mac address %s\n",
794*7c478bd9Sstevel@tonic-gate 	    glddev->gld_name,
795*7c478bd9Sstevel@tonic-gate 	    macinfo->gldm_ppa, macinfo->gldm_ident,
796*7c478bd9Sstevel@tonic-gate 	    mac_pvt->interfacep->mac_string,
797*7c478bd9Sstevel@tonic-gate 	    gld_macaddr_sprintf(pbuf, macinfo->gldm_vendor_addr,
798*7c478bd9Sstevel@tonic-gate 	    macinfo->gldm_addrlen));
799*7c478bd9Sstevel@tonic-gate 
800*7c478bd9Sstevel@tonic-gate 	ddi_report_dev(devinfo);
801*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
802*7c478bd9Sstevel@tonic-gate 
803*7c478bd9Sstevel@tonic-gate late_failure:
804*7c478bd9Sstevel@tonic-gate 	ddi_remove_minor_node(devinfo, NULL);
805*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK_DESTROY(macinfo);
806*7c478bd9Sstevel@tonic-gate 	if (mac_pvt->curr_macaddr != NULL)
807*7c478bd9Sstevel@tonic-gate 	    kmem_free(mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
808*7c478bd9Sstevel@tonic-gate 	if (mac_pvt->statistics != NULL)
809*7c478bd9Sstevel@tonic-gate 	    kmem_free(mac_pvt->statistics, sizeof (struct gld_stats));
810*7c478bd9Sstevel@tonic-gate 	kmem_free(macinfo->gldm_mac_pvt, sizeof (gld_mac_pvt_t));
811*7c478bd9Sstevel@tonic-gate 	macinfo->gldm_mac_pvt = NULL;
812*7c478bd9Sstevel@tonic-gate 
813*7c478bd9Sstevel@tonic-gate failure:
814*7c478bd9Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
815*7c478bd9Sstevel@tonic-gate 	glddev->gld_ndevice--;
816*7c478bd9Sstevel@tonic-gate 	/*
817*7c478bd9Sstevel@tonic-gate 	 * Note that just because this goes to zero here does not necessarily
818*7c478bd9Sstevel@tonic-gate 	 * mean that we were the one who added the glddev above.  It's
819*7c478bd9Sstevel@tonic-gate 	 * possible that the first mac unattached while were were in here
820*7c478bd9Sstevel@tonic-gate 	 * failing to attach the second mac.  But we're now the last.
821*7c478bd9Sstevel@tonic-gate 	 */
822*7c478bd9Sstevel@tonic-gate 	if (glddev->gld_ndevice == 0) {
823*7c478bd9Sstevel@tonic-gate 		/* There should be no macinfos left */
824*7c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_mac_next ==
825*7c478bd9Sstevel@tonic-gate 		    (gld_mac_info_t *)&glddev->gld_mac_next);
826*7c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_mac_prev ==
827*7c478bd9Sstevel@tonic-gate 		    (gld_mac_info_t *)&glddev->gld_mac_next);
828*7c478bd9Sstevel@tonic-gate 
829*7c478bd9Sstevel@tonic-gate 		/*
830*7c478bd9Sstevel@tonic-gate 		 * There should be no DL_UNATTACHED streams: the system
831*7c478bd9Sstevel@tonic-gate 		 * should not have detached the "first" devinfo which has
832*7c478bd9Sstevel@tonic-gate 		 * all the open style 2 streams.
833*7c478bd9Sstevel@tonic-gate 		 *
834*7c478bd9Sstevel@tonic-gate 		 * XXX This is not clear.  See gld_getinfo and Bug 1165519
835*7c478bd9Sstevel@tonic-gate 		 */
836*7c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_str_next == (gld_t *)&glddev->gld_str_next);
837*7c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_str_prev == (gld_t *)&glddev->gld_str_next);
838*7c478bd9Sstevel@tonic-gate 
839*7c478bd9Sstevel@tonic-gate 		gldremque(glddev);
840*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&glddev->gld_devlock);
841*7c478bd9Sstevel@tonic-gate 		if (glddev->gld_broadcast != NULL)
842*7c478bd9Sstevel@tonic-gate 			kmem_free(glddev->gld_broadcast, glddev->gld_addrlen);
843*7c478bd9Sstevel@tonic-gate 		kmem_free(glddev, sizeof (glddev_t));
844*7c478bd9Sstevel@tonic-gate 	}
845*7c478bd9Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
846*7c478bd9Sstevel@tonic-gate 
847*7c478bd9Sstevel@tonic-gate 	return (DDI_FAILURE);
848*7c478bd9Sstevel@tonic-gate }
849*7c478bd9Sstevel@tonic-gate 
850*7c478bd9Sstevel@tonic-gate /*
851*7c478bd9Sstevel@tonic-gate  * gld_unregister (macinfo)
852*7c478bd9Sstevel@tonic-gate  * remove the macinfo structure from local structures
853*7c478bd9Sstevel@tonic-gate  * this is cleanup for a driver to be unloaded
854*7c478bd9Sstevel@tonic-gate  */
855*7c478bd9Sstevel@tonic-gate int
856*7c478bd9Sstevel@tonic-gate gld_unregister(gld_mac_info_t *macinfo)
857*7c478bd9Sstevel@tonic-gate {
858*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
859*7c478bd9Sstevel@tonic-gate 	glddev_t *glddev = mac_pvt->major_dev;
860*7c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
861*7c478bd9Sstevel@tonic-gate 	int multisize = sizeof (gld_mcast_t) * glddev->gld_multisize;
862*7c478bd9Sstevel@tonic-gate 
863*7c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
864*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
865*7c478bd9Sstevel@tonic-gate 
866*7c478bd9Sstevel@tonic-gate 	if (mac_pvt->nvlan > 0) {
867*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
868*7c478bd9Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
869*7c478bd9Sstevel@tonic-gate 		return (DDI_FAILURE);
870*7c478bd9Sstevel@tonic-gate 	}
871*7c478bd9Sstevel@tonic-gate 
872*7c478bd9Sstevel@tonic-gate #ifdef	GLD_DEBUG
873*7c478bd9Sstevel@tonic-gate 	{
874*7c478bd9Sstevel@tonic-gate 		int i;
875*7c478bd9Sstevel@tonic-gate 
876*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < VLAN_HASHSZ; i++) {
877*7c478bd9Sstevel@tonic-gate 			if ((mac_pvt->vlan_hash[i] != NULL))
878*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_PANIC,
879*7c478bd9Sstevel@tonic-gate 				    "%s, line %d: "
880*7c478bd9Sstevel@tonic-gate 				    "mac_pvt->vlan_hash[%d] != NULL",
881*7c478bd9Sstevel@tonic-gate 				    __FILE__, __LINE__, i);
882*7c478bd9Sstevel@tonic-gate 		}
883*7c478bd9Sstevel@tonic-gate 	}
884*7c478bd9Sstevel@tonic-gate #endif
885*7c478bd9Sstevel@tonic-gate 
886*7c478bd9Sstevel@tonic-gate 	/* Delete this mac */
887*7c478bd9Sstevel@tonic-gate 	gldremque(macinfo);
888*7c478bd9Sstevel@tonic-gate 
889*7c478bd9Sstevel@tonic-gate 	/* Disallow further entries to gld_recv() and gld_sched() */
890*7c478bd9Sstevel@tonic-gate 	macinfo->gldm_GLD_flags |= GLD_UNREGISTERED;
891*7c478bd9Sstevel@tonic-gate 
892*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
893*7c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
894*7c478bd9Sstevel@tonic-gate 
895*7c478bd9Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
896*7c478bd9Sstevel@tonic-gate 	(*ifp->uninit)(macinfo);
897*7c478bd9Sstevel@tonic-gate 
898*7c478bd9Sstevel@tonic-gate 	ASSERT(mac_pvt->kstatp);
899*7c478bd9Sstevel@tonic-gate 	kstat_delete(mac_pvt->kstatp);
900*7c478bd9Sstevel@tonic-gate 
901*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_INITED(macinfo));
902*7c478bd9Sstevel@tonic-gate 	kmem_free(mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
903*7c478bd9Sstevel@tonic-gate 	kmem_free(mac_pvt->statistics, sizeof (struct gld_stats));
904*7c478bd9Sstevel@tonic-gate 
905*7c478bd9Sstevel@tonic-gate 	if (mac_pvt->mcast_table != NULL)
906*7c478bd9Sstevel@tonic-gate 		kmem_free(mac_pvt->mcast_table, multisize);
907*7c478bd9Sstevel@tonic-gate 	kmem_free(macinfo->gldm_mac_pvt, sizeof (gld_mac_pvt_t));
908*7c478bd9Sstevel@tonic-gate 	macinfo->gldm_mac_pvt = (caddr_t)NULL;
909*7c478bd9Sstevel@tonic-gate 
910*7c478bd9Sstevel@tonic-gate 	/* We now have one fewer instance for this major device */
911*7c478bd9Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
912*7c478bd9Sstevel@tonic-gate 	glddev->gld_ndevice--;
913*7c478bd9Sstevel@tonic-gate 	if (glddev->gld_ndevice == 0) {
914*7c478bd9Sstevel@tonic-gate 		/* There should be no macinfos left */
915*7c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_mac_next ==
916*7c478bd9Sstevel@tonic-gate 		    (gld_mac_info_t *)&glddev->gld_mac_next);
917*7c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_mac_prev ==
918*7c478bd9Sstevel@tonic-gate 		    (gld_mac_info_t *)&glddev->gld_mac_next);
919*7c478bd9Sstevel@tonic-gate 
920*7c478bd9Sstevel@tonic-gate 		/*
921*7c478bd9Sstevel@tonic-gate 		 * There should be no DL_UNATTACHED streams: the system
922*7c478bd9Sstevel@tonic-gate 		 * should not have detached the "first" devinfo which has
923*7c478bd9Sstevel@tonic-gate 		 * all the open style 2 streams.
924*7c478bd9Sstevel@tonic-gate 		 *
925*7c478bd9Sstevel@tonic-gate 		 * XXX This is not clear.  See gld_getinfo and Bug 1165519
926*7c478bd9Sstevel@tonic-gate 		 */
927*7c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_str_next == (gld_t *)&glddev->gld_str_next);
928*7c478bd9Sstevel@tonic-gate 		ASSERT(glddev->gld_str_prev == (gld_t *)&glddev->gld_str_next);
929*7c478bd9Sstevel@tonic-gate 
930*7c478bd9Sstevel@tonic-gate 		ddi_remove_minor_node(macinfo->gldm_devinfo, NULL);
931*7c478bd9Sstevel@tonic-gate 		gldremque(glddev);
932*7c478bd9Sstevel@tonic-gate 		mutex_destroy(&glddev->gld_devlock);
933*7c478bd9Sstevel@tonic-gate 		if (glddev->gld_broadcast != NULL)
934*7c478bd9Sstevel@tonic-gate 			kmem_free(glddev->gld_broadcast, glddev->gld_addrlen);
935*7c478bd9Sstevel@tonic-gate 		kmem_free(glddev, sizeof (glddev_t));
936*7c478bd9Sstevel@tonic-gate 	}
937*7c478bd9Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
938*7c478bd9Sstevel@tonic-gate 
939*7c478bd9Sstevel@tonic-gate 	return (DDI_SUCCESS);
940*7c478bd9Sstevel@tonic-gate }
941*7c478bd9Sstevel@tonic-gate 
942*7c478bd9Sstevel@tonic-gate /*
943*7c478bd9Sstevel@tonic-gate  * gld_initstats
944*7c478bd9Sstevel@tonic-gate  * called from gld_register
945*7c478bd9Sstevel@tonic-gate  */
946*7c478bd9Sstevel@tonic-gate static int
947*7c478bd9Sstevel@tonic-gate gld_initstats(gld_mac_info_t *macinfo)
948*7c478bd9Sstevel@tonic-gate {
949*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
950*7c478bd9Sstevel@tonic-gate 	struct gldkstats *sp;
951*7c478bd9Sstevel@tonic-gate 	glddev_t *glddev;
952*7c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
953*7c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
954*7c478bd9Sstevel@tonic-gate 
955*7c478bd9Sstevel@tonic-gate 	glddev = mac_pvt->major_dev;
956*7c478bd9Sstevel@tonic-gate 
957*7c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_create(glddev->gld_name, macinfo->gldm_ppa,
958*7c478bd9Sstevel@tonic-gate 	    NULL, "net", KSTAT_TYPE_NAMED,
959*7c478bd9Sstevel@tonic-gate 	    sizeof (struct gldkstats) / sizeof (kstat_named_t), 0)) == NULL) {
960*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
961*7c478bd9Sstevel@tonic-gate 		    "GLD: failed to create kstat structure for %s%d",
962*7c478bd9Sstevel@tonic-gate 		    glddev->gld_name, macinfo->gldm_ppa);
963*7c478bd9Sstevel@tonic-gate 		return (GLD_FAILURE);
964*7c478bd9Sstevel@tonic-gate 	}
965*7c478bd9Sstevel@tonic-gate 	mac_pvt->kstatp = ksp;
966*7c478bd9Sstevel@tonic-gate 
967*7c478bd9Sstevel@tonic-gate 	ksp->ks_update = gld_update_kstat;
968*7c478bd9Sstevel@tonic-gate 	ksp->ks_private = (void *)macinfo;
969*7c478bd9Sstevel@tonic-gate 
970*7c478bd9Sstevel@tonic-gate 	sp = ksp->ks_data;
971*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktrcv, "ipackets", KSTAT_DATA_UINT32);
972*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktxmt, "opackets", KSTAT_DATA_UINT32);
973*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_errrcv, "ierrors", KSTAT_DATA_ULONG);
974*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_errxmt, "oerrors", KSTAT_DATA_ULONG);
975*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytexmt, "obytes", KSTAT_DATA_UINT32);
976*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytercv, "rbytes", KSTAT_DATA_UINT32);
977*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_multixmt, "multixmt", KSTAT_DATA_ULONG);
978*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_multircv, "multircv", KSTAT_DATA_ULONG);
979*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_brdcstxmt, "brdcstxmt", KSTAT_DATA_ULONG);
980*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_brdcstrcv, "brdcstrcv", KSTAT_DATA_ULONG);
981*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_blocked, "blocked", KSTAT_DATA_ULONG);
982*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_noxmtbuf, "noxmtbuf", KSTAT_DATA_ULONG);
983*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_norcvbuf, "norcvbuf", KSTAT_DATA_ULONG);
984*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtretry, "xmtretry", KSTAT_DATA_ULONG);
985*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_intr, "intr", KSTAT_DATA_ULONG);
986*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktrcv64, "ipackets64", KSTAT_DATA_UINT64);
987*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktxmt64, "opackets64", KSTAT_DATA_UINT64);
988*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytexmt64, "obytes64", KSTAT_DATA_UINT64);
989*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytercv64, "rbytes64", KSTAT_DATA_UINT64);
990*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_unknowns, "unknowns", KSTAT_DATA_ULONG);
991*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_speed, "ifspeed", KSTAT_DATA_UINT64);
992*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_media, "media", KSTAT_DATA_CHAR);
993*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_prom, "promisc", KSTAT_DATA_CHAR);
994*7c478bd9Sstevel@tonic-gate 
995*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_overflow, "oflo", KSTAT_DATA_ULONG);
996*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_underflow, "uflo", KSTAT_DATA_ULONG);
997*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_missed, "missed", KSTAT_DATA_ULONG);
998*7c478bd9Sstevel@tonic-gate 
999*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtbadinterp, "xmt_badinterp",
1000*7c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
1001*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_rcvbadinterp, "rcv_badinterp",
1002*7c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
1003*7c478bd9Sstevel@tonic-gate 
1004*7c478bd9Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
1005*7c478bd9Sstevel@tonic-gate 
1006*7c478bd9Sstevel@tonic-gate 	(*ifp->init)(macinfo);
1007*7c478bd9Sstevel@tonic-gate 
1008*7c478bd9Sstevel@tonic-gate 	kstat_install(ksp);
1009*7c478bd9Sstevel@tonic-gate 
1010*7c478bd9Sstevel@tonic-gate 	return (GLD_SUCCESS);
1011*7c478bd9Sstevel@tonic-gate }
1012*7c478bd9Sstevel@tonic-gate 
1013*7c478bd9Sstevel@tonic-gate /* called from kstat mechanism, and from wsrv's get_statistics_req */
1014*7c478bd9Sstevel@tonic-gate static int
1015*7c478bd9Sstevel@tonic-gate gld_update_kstat(kstat_t *ksp, int rw)
1016*7c478bd9Sstevel@tonic-gate {
1017*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*macinfo;
1018*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt;
1019*7c478bd9Sstevel@tonic-gate 	struct gldkstats *gsp;
1020*7c478bd9Sstevel@tonic-gate 	struct gld_stats *stats;
1021*7c478bd9Sstevel@tonic-gate 
1022*7c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
1023*7c478bd9Sstevel@tonic-gate 		return (EACCES);
1024*7c478bd9Sstevel@tonic-gate 
1025*7c478bd9Sstevel@tonic-gate 	macinfo = (gld_mac_info_t *)ksp->ks_private;
1026*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
1027*7c478bd9Sstevel@tonic-gate 
1028*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
1029*7c478bd9Sstevel@tonic-gate 
1030*7c478bd9Sstevel@tonic-gate 	if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY)) {
1031*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
1032*7c478bd9Sstevel@tonic-gate 		return (EIO);	/* this one's not ready yet */
1033*7c478bd9Sstevel@tonic-gate 	}
1034*7c478bd9Sstevel@tonic-gate 
1035*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
1036*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
1037*7c478bd9Sstevel@tonic-gate 		return (EIO);	/* this one's not ready any more */
1038*7c478bd9Sstevel@tonic-gate 	}
1039*7c478bd9Sstevel@tonic-gate 
1040*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
1041*7c478bd9Sstevel@tonic-gate 	gsp = mac_pvt->kstatp->ks_data;
1042*7c478bd9Sstevel@tonic-gate 	ASSERT(gsp);
1043*7c478bd9Sstevel@tonic-gate 	stats = mac_pvt->statistics;
1044*7c478bd9Sstevel@tonic-gate 
1045*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_get_stats)
1046*7c478bd9Sstevel@tonic-gate 		(void) (*macinfo->gldm_get_stats)(macinfo, stats);
1047*7c478bd9Sstevel@tonic-gate 
1048*7c478bd9Sstevel@tonic-gate 	gsp->glds_pktxmt.value.ui32 = stats->glds_pktxmt64 & 0xffffffff;
1049*7c478bd9Sstevel@tonic-gate 	gsp->glds_bytexmt.value.ui32 = stats->glds_bytexmt64 & 0xffffffff;
1050*7c478bd9Sstevel@tonic-gate 	gsp->glds_multixmt.value.ul = stats->glds_multixmt;
1051*7c478bd9Sstevel@tonic-gate 	gsp->glds_brdcstxmt.value.ul = stats->glds_brdcstxmt;
1052*7c478bd9Sstevel@tonic-gate 	gsp->glds_noxmtbuf.value.ul = stats->glds_noxmtbuf;	/* 0 for now */
1053*7c478bd9Sstevel@tonic-gate 	gsp->glds_xmtretry.value.ul = stats->glds_xmtretry;
1054*7c478bd9Sstevel@tonic-gate 
1055*7c478bd9Sstevel@tonic-gate 	gsp->glds_pktxmt64.value.ui64 = stats->glds_pktxmt64;
1056*7c478bd9Sstevel@tonic-gate 	gsp->glds_bytexmt64.value.ui64 = stats->glds_bytexmt64;
1057*7c478bd9Sstevel@tonic-gate 	gsp->glds_xmtbadinterp.value.ui32 = stats->glds_xmtbadinterp;
1058*7c478bd9Sstevel@tonic-gate 
1059*7c478bd9Sstevel@tonic-gate 	gsp->glds_pktrcv.value.ui32 = stats->glds_pktrcv64 & 0xffffffff;
1060*7c478bd9Sstevel@tonic-gate 	gsp->glds_errxmt.value.ul = stats->glds_errxmt;
1061*7c478bd9Sstevel@tonic-gate 	gsp->glds_errrcv.value.ul = stats->glds_errrcv;
1062*7c478bd9Sstevel@tonic-gate 	gsp->glds_bytercv.value.ui32 = stats->glds_bytercv64 & 0xffffffff;
1063*7c478bd9Sstevel@tonic-gate 	gsp->glds_multircv.value.ul = stats->glds_multircv;
1064*7c478bd9Sstevel@tonic-gate 	gsp->glds_brdcstrcv.value.ul = stats->glds_brdcstrcv;
1065*7c478bd9Sstevel@tonic-gate 	gsp->glds_blocked.value.ul = stats->glds_blocked;
1066*7c478bd9Sstevel@tonic-gate 	gsp->glds_overflow.value.ul = stats->glds_overflow;
1067*7c478bd9Sstevel@tonic-gate 	gsp->glds_underflow.value.ul = stats->glds_underflow;
1068*7c478bd9Sstevel@tonic-gate 	gsp->glds_missed.value.ul = stats->glds_missed;
1069*7c478bd9Sstevel@tonic-gate 	gsp->glds_norcvbuf.value.ul = stats->glds_norcvbuf +
1070*7c478bd9Sstevel@tonic-gate 	    stats->glds_gldnorcvbuf;
1071*7c478bd9Sstevel@tonic-gate 	gsp->glds_intr.value.ul = stats->glds_intr;
1072*7c478bd9Sstevel@tonic-gate 
1073*7c478bd9Sstevel@tonic-gate 	gsp->glds_speed.value.ui64 = stats->glds_speed;
1074*7c478bd9Sstevel@tonic-gate 	gsp->glds_unknowns.value.ul = stats->glds_unknowns;
1075*7c478bd9Sstevel@tonic-gate 	gsp->glds_pktrcv64.value.ui64 = stats->glds_pktrcv64;
1076*7c478bd9Sstevel@tonic-gate 	gsp->glds_bytercv64.value.ui64 = stats->glds_bytercv64;
1077*7c478bd9Sstevel@tonic-gate 	gsp->glds_rcvbadinterp.value.ui32 = stats->glds_rcvbadinterp;
1078*7c478bd9Sstevel@tonic-gate 
1079*7c478bd9Sstevel@tonic-gate 	if (mac_pvt->nprom)
1080*7c478bd9Sstevel@tonic-gate 		(void) strcpy(gsp->glds_prom.value.c, "phys");
1081*7c478bd9Sstevel@tonic-gate 	else if (mac_pvt->nprom_multi)
1082*7c478bd9Sstevel@tonic-gate 		(void) strcpy(gsp->glds_prom.value.c, "multi");
1083*7c478bd9Sstevel@tonic-gate 	else
1084*7c478bd9Sstevel@tonic-gate 		(void) strcpy(gsp->glds_prom.value.c, "off");
1085*7c478bd9Sstevel@tonic-gate 
1086*7c478bd9Sstevel@tonic-gate 	(void) strcpy(gsp->glds_media.value.c, gld_media[
1087*7c478bd9Sstevel@tonic-gate 	    stats->glds_media < sizeof (gld_media) / sizeof (gld_media[0])
1088*7c478bd9Sstevel@tonic-gate 	    ? stats->glds_media : 0]);
1089*7c478bd9Sstevel@tonic-gate 
1090*7c478bd9Sstevel@tonic-gate 	switch (macinfo->gldm_type) {
1091*7c478bd9Sstevel@tonic-gate 	case DL_ETHER:
1092*7c478bd9Sstevel@tonic-gate 		gsp->glds_frame.value.ul = stats->glds_frame;
1093*7c478bd9Sstevel@tonic-gate 		gsp->glds_crc.value.ul = stats->glds_crc;
1094*7c478bd9Sstevel@tonic-gate 		gsp->glds_collisions.value.ul = stats->glds_collisions;
1095*7c478bd9Sstevel@tonic-gate 		gsp->glds_excoll.value.ul = stats->glds_excoll;
1096*7c478bd9Sstevel@tonic-gate 		gsp->glds_defer.value.ul = stats->glds_defer;
1097*7c478bd9Sstevel@tonic-gate 		gsp->glds_short.value.ul = stats->glds_short;
1098*7c478bd9Sstevel@tonic-gate 		gsp->glds_xmtlatecoll.value.ul = stats->glds_xmtlatecoll;
1099*7c478bd9Sstevel@tonic-gate 		gsp->glds_nocarrier.value.ul = stats->glds_nocarrier;
1100*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot3_first_coll.value.ui32 =
1101*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot3_first_coll;
1102*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot3_multi_coll.value.ui32 =
1103*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot3_multi_coll;
1104*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot3_sqe_error.value.ui32 =
1105*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot3_sqe_error;
1106*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot3_mac_xmt_error.value.ui32 =
1107*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot3_mac_xmt_error;
1108*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot3_mac_rcv_error.value.ui32 =
1109*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot3_mac_rcv_error;
1110*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot3_frame_too_long.value.ui32 =
1111*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot3_frame_too_long;
1112*7c478bd9Sstevel@tonic-gate 		(void) strcpy(gsp->glds_duplex.value.c, gld_duplex[
1113*7c478bd9Sstevel@tonic-gate 		    stats->glds_duplex <
1114*7c478bd9Sstevel@tonic-gate 		    sizeof (gld_duplex) / sizeof (gld_duplex[0]) ?
1115*7c478bd9Sstevel@tonic-gate 		    stats->glds_duplex : 0]);
1116*7c478bd9Sstevel@tonic-gate 		break;
1117*7c478bd9Sstevel@tonic-gate 	case DL_TPR:
1118*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_line_error.value.ui32 =
1119*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_line_error;
1120*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_burst_error.value.ui32 =
1121*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_burst_error;
1122*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_signal_loss.value.ui32 =
1123*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_signal_loss;
1124*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_ace_error.value.ui32 =
1125*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_ace_error;
1126*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_internal_error.value.ui32 =
1127*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_internal_error;
1128*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_lost_frame_error.value.ui32 =
1129*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_lost_frame_error;
1130*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_frame_copied_error.value.ui32 =
1131*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_frame_copied_error;
1132*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_token_error.value.ui32 =
1133*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_token_error;
1134*7c478bd9Sstevel@tonic-gate 		gsp->glds_dot5_freq_error.value.ui32 =
1135*7c478bd9Sstevel@tonic-gate 		    stats->glds_dot5_freq_error;
1136*7c478bd9Sstevel@tonic-gate 		break;
1137*7c478bd9Sstevel@tonic-gate 	case DL_FDDI:
1138*7c478bd9Sstevel@tonic-gate 		gsp->glds_fddi_mac_error.value.ui32 =
1139*7c478bd9Sstevel@tonic-gate 		    stats->glds_fddi_mac_error;
1140*7c478bd9Sstevel@tonic-gate 		gsp->glds_fddi_mac_lost.value.ui32 =
1141*7c478bd9Sstevel@tonic-gate 		    stats->glds_fddi_mac_lost;
1142*7c478bd9Sstevel@tonic-gate 		gsp->glds_fddi_mac_token.value.ui32 =
1143*7c478bd9Sstevel@tonic-gate 		    stats->glds_fddi_mac_token;
1144*7c478bd9Sstevel@tonic-gate 		gsp->glds_fddi_mac_tvx_expired.value.ui32 =
1145*7c478bd9Sstevel@tonic-gate 		    stats->glds_fddi_mac_tvx_expired;
1146*7c478bd9Sstevel@tonic-gate 		gsp->glds_fddi_mac_late.value.ui32 =
1147*7c478bd9Sstevel@tonic-gate 		    stats->glds_fddi_mac_late;
1148*7c478bd9Sstevel@tonic-gate 		gsp->glds_fddi_mac_ring_op.value.ui32 =
1149*7c478bd9Sstevel@tonic-gate 		    stats->glds_fddi_mac_ring_op;
1150*7c478bd9Sstevel@tonic-gate 		break;
1151*7c478bd9Sstevel@tonic-gate 	case DL_IB:
1152*7c478bd9Sstevel@tonic-gate 		break;
1153*7c478bd9Sstevel@tonic-gate 	default:
1154*7c478bd9Sstevel@tonic-gate 		break;
1155*7c478bd9Sstevel@tonic-gate 	}
1156*7c478bd9Sstevel@tonic-gate 
1157*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
1158*7c478bd9Sstevel@tonic-gate 
1159*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1160*7c478bd9Sstevel@tonic-gate 	gld_check_assertions();
1161*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDRDE)
1162*7c478bd9Sstevel@tonic-gate 		gld_sr_dump(macinfo);
1163*7c478bd9Sstevel@tonic-gate #endif
1164*7c478bd9Sstevel@tonic-gate 
1165*7c478bd9Sstevel@tonic-gate 	return (0);
1166*7c478bd9Sstevel@tonic-gate }
1167*7c478bd9Sstevel@tonic-gate 
1168*7c478bd9Sstevel@tonic-gate static int
1169*7c478bd9Sstevel@tonic-gate gld_init_vlan_stats(gld_vlan_t *vlan)
1170*7c478bd9Sstevel@tonic-gate {
1171*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *mac = vlan->gldv_mac;
1172*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)mac->gldm_mac_pvt;
1173*7c478bd9Sstevel@tonic-gate 	struct gldkstats *sp;
1174*7c478bd9Sstevel@tonic-gate 	glddev_t *glddev;
1175*7c478bd9Sstevel@tonic-gate 	kstat_t *ksp;
1176*7c478bd9Sstevel@tonic-gate 	char *name;
1177*7c478bd9Sstevel@tonic-gate 	int instance;
1178*7c478bd9Sstevel@tonic-gate 
1179*7c478bd9Sstevel@tonic-gate 	glddev = mac_pvt->major_dev;
1180*7c478bd9Sstevel@tonic-gate 	name = glddev->gld_name;
1181*7c478bd9Sstevel@tonic-gate 	instance = (vlan->gldv_id * GLD_VLAN_SCALE) + mac->gldm_ppa;
1182*7c478bd9Sstevel@tonic-gate 
1183*7c478bd9Sstevel@tonic-gate 	if ((ksp = kstat_create(name, instance,
1184*7c478bd9Sstevel@tonic-gate 	    NULL, "net", KSTAT_TYPE_NAMED,
1185*7c478bd9Sstevel@tonic-gate 	    sizeof (struct gldkstats) / sizeof (kstat_named_t), 0)) == NULL) {
1186*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN,
1187*7c478bd9Sstevel@tonic-gate 		    "GLD: failed to create kstat structure for %s%d",
1188*7c478bd9Sstevel@tonic-gate 		    name, instance);
1189*7c478bd9Sstevel@tonic-gate 		return (GLD_FAILURE);
1190*7c478bd9Sstevel@tonic-gate 	}
1191*7c478bd9Sstevel@tonic-gate 
1192*7c478bd9Sstevel@tonic-gate 	vlan->gldv_kstatp = ksp;
1193*7c478bd9Sstevel@tonic-gate 
1194*7c478bd9Sstevel@tonic-gate 	ksp->ks_update = gld_update_vlan_kstat;
1195*7c478bd9Sstevel@tonic-gate 	ksp->ks_private = (void *)vlan;
1196*7c478bd9Sstevel@tonic-gate 
1197*7c478bd9Sstevel@tonic-gate 	sp = ksp->ks_data;
1198*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktrcv, "ipackets", KSTAT_DATA_UINT32);
1199*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktxmt, "opackets", KSTAT_DATA_UINT32);
1200*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_errrcv, "ierrors", KSTAT_DATA_ULONG);
1201*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_errxmt, "oerrors", KSTAT_DATA_ULONG);
1202*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytexmt, "obytes", KSTAT_DATA_UINT32);
1203*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytercv, "rbytes", KSTAT_DATA_UINT32);
1204*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_multixmt, "multixmt", KSTAT_DATA_ULONG);
1205*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_multircv, "multircv", KSTAT_DATA_ULONG);
1206*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_brdcstxmt, "brdcstxmt", KSTAT_DATA_ULONG);
1207*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_brdcstrcv, "brdcstrcv", KSTAT_DATA_ULONG);
1208*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_blocked, "blocked", KSTAT_DATA_ULONG);
1209*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_noxmtbuf, "noxmtbuf", KSTAT_DATA_ULONG);
1210*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_norcvbuf, "norcvbuf", KSTAT_DATA_ULONG);
1211*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtretry, "xmtretry", KSTAT_DATA_ULONG);
1212*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_intr, "intr", KSTAT_DATA_ULONG);
1213*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktrcv64, "ipackets64", KSTAT_DATA_UINT64);
1214*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_pktxmt64, "opackets64", KSTAT_DATA_UINT64);
1215*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytexmt64, "obytes64", KSTAT_DATA_UINT64);
1216*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_bytercv64, "rbytes64", KSTAT_DATA_UINT64);
1217*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_unknowns, "unknowns", KSTAT_DATA_ULONG);
1218*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_speed, "ifspeed", KSTAT_DATA_UINT64);
1219*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_media, "media", KSTAT_DATA_CHAR);
1220*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_prom, "promisc", KSTAT_DATA_CHAR);
1221*7c478bd9Sstevel@tonic-gate 
1222*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_overflow, "oflo", KSTAT_DATA_ULONG);
1223*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_underflow, "uflo", KSTAT_DATA_ULONG);
1224*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_missed, "missed", KSTAT_DATA_ULONG);
1225*7c478bd9Sstevel@tonic-gate 
1226*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_xmtbadinterp, "xmt_badinterp",
1227*7c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
1228*7c478bd9Sstevel@tonic-gate 	kstat_named_init(&sp->glds_rcvbadinterp, "rcv_badinterp",
1229*7c478bd9Sstevel@tonic-gate 	    KSTAT_DATA_UINT32);
1230*7c478bd9Sstevel@tonic-gate 
1231*7c478bd9Sstevel@tonic-gate 	kstat_install(ksp);
1232*7c478bd9Sstevel@tonic-gate 	return (GLD_SUCCESS);
1233*7c478bd9Sstevel@tonic-gate }
1234*7c478bd9Sstevel@tonic-gate 
1235*7c478bd9Sstevel@tonic-gate static int
1236*7c478bd9Sstevel@tonic-gate gld_update_vlan_kstat(kstat_t *ksp, int rw)
1237*7c478bd9Sstevel@tonic-gate {
1238*7c478bd9Sstevel@tonic-gate 	gld_vlan_t	*vlan;
1239*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*macinfo;
1240*7c478bd9Sstevel@tonic-gate 	struct gldkstats *gsp;
1241*7c478bd9Sstevel@tonic-gate 	struct gld_stats *stats;
1242*7c478bd9Sstevel@tonic-gate 
1243*7c478bd9Sstevel@tonic-gate 	if (rw == KSTAT_WRITE)
1244*7c478bd9Sstevel@tonic-gate 		return (EACCES);
1245*7c478bd9Sstevel@tonic-gate 
1246*7c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)ksp->ks_private;
1247*7c478bd9Sstevel@tonic-gate 	ASSERT(vlan != NULL);
1248*7c478bd9Sstevel@tonic-gate 
1249*7c478bd9Sstevel@tonic-gate 	macinfo = vlan->gldv_mac;
1250*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
1251*7c478bd9Sstevel@tonic-gate 
1252*7c478bd9Sstevel@tonic-gate 	gsp = vlan->gldv_kstatp->ks_data;
1253*7c478bd9Sstevel@tonic-gate 	ASSERT(gsp);
1254*7c478bd9Sstevel@tonic-gate 	stats = vlan->gldv_stats;
1255*7c478bd9Sstevel@tonic-gate 
1256*7c478bd9Sstevel@tonic-gate 	gsp->glds_pktxmt.value.ui32 = stats->glds_pktxmt64 & 0xffffffff;
1257*7c478bd9Sstevel@tonic-gate 	gsp->glds_bytexmt.value.ui32 = stats->glds_bytexmt64 & 0xffffffff;
1258*7c478bd9Sstevel@tonic-gate 	gsp->glds_errxmt.value.ul = stats->glds_errxmt;
1259*7c478bd9Sstevel@tonic-gate 	gsp->glds_multixmt.value.ul = stats->glds_multixmt;
1260*7c478bd9Sstevel@tonic-gate 	gsp->glds_brdcstxmt.value.ul = stats->glds_brdcstxmt;
1261*7c478bd9Sstevel@tonic-gate 	gsp->glds_noxmtbuf.value.ul = stats->glds_noxmtbuf;
1262*7c478bd9Sstevel@tonic-gate 	gsp->glds_xmtretry.value.ul = stats->glds_xmtretry;
1263*7c478bd9Sstevel@tonic-gate 	gsp->glds_pktxmt64.value.ui64 = stats->glds_pktxmt64;
1264*7c478bd9Sstevel@tonic-gate 	gsp->glds_bytexmt64.value.ui64 = stats->glds_bytexmt64;
1265*7c478bd9Sstevel@tonic-gate 
1266*7c478bd9Sstevel@tonic-gate 	gsp->glds_pktrcv.value.ui32 = stats->glds_pktrcv64 & 0xffffffff;
1267*7c478bd9Sstevel@tonic-gate 	gsp->glds_bytercv.value.ui32 = stats->glds_bytercv64 & 0xffffffff;
1268*7c478bd9Sstevel@tonic-gate 	gsp->glds_errrcv.value.ul = stats->glds_errrcv;
1269*7c478bd9Sstevel@tonic-gate 	gsp->glds_multircv.value.ul = stats->glds_multircv;
1270*7c478bd9Sstevel@tonic-gate 	gsp->glds_brdcstrcv.value.ul = stats->glds_brdcstrcv;
1271*7c478bd9Sstevel@tonic-gate 	gsp->glds_blocked.value.ul = stats->glds_blocked;
1272*7c478bd9Sstevel@tonic-gate 	gsp->glds_pktrcv64.value.ui64 = stats->glds_pktrcv64;
1273*7c478bd9Sstevel@tonic-gate 	gsp->glds_bytercv64.value.ui64 = stats->glds_bytercv64;
1274*7c478bd9Sstevel@tonic-gate 
1275*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
1276*7c478bd9Sstevel@tonic-gate 	return (0);
1277*7c478bd9Sstevel@tonic-gate }
1278*7c478bd9Sstevel@tonic-gate 
1279*7c478bd9Sstevel@tonic-gate /*
1280*7c478bd9Sstevel@tonic-gate  * The device dependent driver specifies gld_getinfo as its getinfo routine.
1281*7c478bd9Sstevel@tonic-gate  */
1282*7c478bd9Sstevel@tonic-gate /*ARGSUSED*/
1283*7c478bd9Sstevel@tonic-gate int
1284*7c478bd9Sstevel@tonic-gate gld_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
1285*7c478bd9Sstevel@tonic-gate {
1286*7c478bd9Sstevel@tonic-gate 	dev_info_t	*devinfo;
1287*7c478bd9Sstevel@tonic-gate 	minor_t		minor = getminor((dev_t)arg);
1288*7c478bd9Sstevel@tonic-gate 	int		rc = DDI_FAILURE;
1289*7c478bd9Sstevel@tonic-gate 
1290*7c478bd9Sstevel@tonic-gate 	switch (cmd) {
1291*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2DEVINFO:
1292*7c478bd9Sstevel@tonic-gate 		if ((devinfo = gld_finddevinfo((dev_t)arg)) != NULL) {
1293*7c478bd9Sstevel@tonic-gate 			*(dev_info_t **)resultp = devinfo;
1294*7c478bd9Sstevel@tonic-gate 			rc = DDI_SUCCESS;
1295*7c478bd9Sstevel@tonic-gate 		}
1296*7c478bd9Sstevel@tonic-gate 		break;
1297*7c478bd9Sstevel@tonic-gate 	case DDI_INFO_DEVT2INSTANCE:
1298*7c478bd9Sstevel@tonic-gate 		/* Need static mapping for deferred attach */
1299*7c478bd9Sstevel@tonic-gate 		if (minor == GLD_USE_STYLE2) {
1300*7c478bd9Sstevel@tonic-gate 			/*
1301*7c478bd9Sstevel@tonic-gate 			 * Style 2:  this minor number does not correspond to
1302*7c478bd9Sstevel@tonic-gate 			 * any particular instance number.
1303*7c478bd9Sstevel@tonic-gate 			 */
1304*7c478bd9Sstevel@tonic-gate 			rc = DDI_FAILURE;
1305*7c478bd9Sstevel@tonic-gate 		} else if (minor <= GLD_MAX_STYLE1_MINOR) {
1306*7c478bd9Sstevel@tonic-gate 			/* Style 1:  calculate the PPA from the minor */
1307*7c478bd9Sstevel@tonic-gate 			*(int *)resultp = GLD_STYLE1_MINOR_TO_PPA(minor);
1308*7c478bd9Sstevel@tonic-gate 			rc = DDI_SUCCESS;
1309*7c478bd9Sstevel@tonic-gate 		} else {
1310*7c478bd9Sstevel@tonic-gate 			/* Clone:  look for it.  Not a static mapping */
1311*7c478bd9Sstevel@tonic-gate 			if ((devinfo = gld_finddevinfo((dev_t)arg)) != NULL) {
1312*7c478bd9Sstevel@tonic-gate 				*(int *)resultp = ddi_get_instance(devinfo);
1313*7c478bd9Sstevel@tonic-gate 				rc = DDI_SUCCESS;
1314*7c478bd9Sstevel@tonic-gate 			}
1315*7c478bd9Sstevel@tonic-gate 		}
1316*7c478bd9Sstevel@tonic-gate 		break;
1317*7c478bd9Sstevel@tonic-gate 	}
1318*7c478bd9Sstevel@tonic-gate 
1319*7c478bd9Sstevel@tonic-gate 	return (rc);
1320*7c478bd9Sstevel@tonic-gate }
1321*7c478bd9Sstevel@tonic-gate 
1322*7c478bd9Sstevel@tonic-gate /* called from gld_getinfo */
1323*7c478bd9Sstevel@tonic-gate dev_info_t *
1324*7c478bd9Sstevel@tonic-gate gld_finddevinfo(dev_t dev)
1325*7c478bd9Sstevel@tonic-gate {
1326*7c478bd9Sstevel@tonic-gate 	minor_t		minor = getminor(dev);
1327*7c478bd9Sstevel@tonic-gate 	glddev_t	*device;
1328*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*mac;
1329*7c478bd9Sstevel@tonic-gate 	gld_vlan_t	*vlan;
1330*7c478bd9Sstevel@tonic-gate 	gld_t		*str;
1331*7c478bd9Sstevel@tonic-gate 	dev_info_t	*devinfo = NULL;
1332*7c478bd9Sstevel@tonic-gate 	int		i;
1333*7c478bd9Sstevel@tonic-gate 
1334*7c478bd9Sstevel@tonic-gate 	if (minor == GLD_USE_STYLE2) {
1335*7c478bd9Sstevel@tonic-gate 		/*
1336*7c478bd9Sstevel@tonic-gate 		 * Style 2:  this minor number does not correspond to
1337*7c478bd9Sstevel@tonic-gate 		 * any particular instance number.
1338*7c478bd9Sstevel@tonic-gate 		 *
1339*7c478bd9Sstevel@tonic-gate 		 * XXX We don't know what to say.  See Bug 1165519.
1340*7c478bd9Sstevel@tonic-gate 		 */
1341*7c478bd9Sstevel@tonic-gate 		return (NULL);
1342*7c478bd9Sstevel@tonic-gate 	}
1343*7c478bd9Sstevel@tonic-gate 
1344*7c478bd9Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);	/* hold the device */
1345*7c478bd9Sstevel@tonic-gate 
1346*7c478bd9Sstevel@tonic-gate 	device = gld_devlookup(getmajor(dev));
1347*7c478bd9Sstevel@tonic-gate 	if (device == NULL) {
1348*7c478bd9Sstevel@tonic-gate 		/* There are no attached instances of this device */
1349*7c478bd9Sstevel@tonic-gate 		mutex_exit(&gld_device_list.gld_devlock);
1350*7c478bd9Sstevel@tonic-gate 		return (NULL);
1351*7c478bd9Sstevel@tonic-gate 	}
1352*7c478bd9Sstevel@tonic-gate 
1353*7c478bd9Sstevel@tonic-gate 	/*
1354*7c478bd9Sstevel@tonic-gate 	 * Search all attached macs and streams.
1355*7c478bd9Sstevel@tonic-gate 	 *
1356*7c478bd9Sstevel@tonic-gate 	 * XXX We don't bother checking the DL_UNATTACHED streams since
1357*7c478bd9Sstevel@tonic-gate 	 * we don't know what devinfo we should report back even if we
1358*7c478bd9Sstevel@tonic-gate 	 * found the minor.  Maybe we should associate streams that are
1359*7c478bd9Sstevel@tonic-gate 	 * not currently attached to a PPA with the "first" devinfo node
1360*7c478bd9Sstevel@tonic-gate 	 * of the major device to attach -- the one that created the
1361*7c478bd9Sstevel@tonic-gate 	 * minor node for the generic device.
1362*7c478bd9Sstevel@tonic-gate 	 */
1363*7c478bd9Sstevel@tonic-gate 	mutex_enter(&device->gld_devlock);
1364*7c478bd9Sstevel@tonic-gate 
1365*7c478bd9Sstevel@tonic-gate 	for (mac = device->gld_mac_next;
1366*7c478bd9Sstevel@tonic-gate 	    mac != (gld_mac_info_t *)&device->gld_mac_next;
1367*7c478bd9Sstevel@tonic-gate 	    mac = mac->gldm_next) {
1368*7c478bd9Sstevel@tonic-gate 		gld_mac_pvt_t *pvt = (gld_mac_pvt_t *)mac->gldm_mac_pvt;
1369*7c478bd9Sstevel@tonic-gate 
1370*7c478bd9Sstevel@tonic-gate 		if (!(mac->gldm_GLD_flags & GLD_MAC_READY))
1371*7c478bd9Sstevel@tonic-gate 			continue;	/* this one's not ready yet */
1372*7c478bd9Sstevel@tonic-gate 		if (minor <= GLD_MAX_STYLE1_MINOR) {
1373*7c478bd9Sstevel@tonic-gate 			/* Style 1 -- look for the corresponding PPA */
1374*7c478bd9Sstevel@tonic-gate 			if (minor == GLD_STYLE1_PPA_TO_MINOR(mac->gldm_ppa)) {
1375*7c478bd9Sstevel@tonic-gate 				devinfo = mac->gldm_devinfo;
1376*7c478bd9Sstevel@tonic-gate 				goto out;	/* found it! */
1377*7c478bd9Sstevel@tonic-gate 			} else
1378*7c478bd9Sstevel@tonic-gate 				continue;	/* not this PPA */
1379*7c478bd9Sstevel@tonic-gate 		}
1380*7c478bd9Sstevel@tonic-gate 
1381*7c478bd9Sstevel@tonic-gate 		/* We are looking for a clone */
1382*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < VLAN_HASHSZ; i++) {
1383*7c478bd9Sstevel@tonic-gate 			for (vlan = pvt->vlan_hash[i];
1384*7c478bd9Sstevel@tonic-gate 			    vlan != NULL; vlan = vlan->gldv_next) {
1385*7c478bd9Sstevel@tonic-gate 				for (str = vlan->gldv_str_next;
1386*7c478bd9Sstevel@tonic-gate 				    str != (gld_t *)&vlan->gldv_str_next;
1387*7c478bd9Sstevel@tonic-gate 				    str = str->gld_next) {
1388*7c478bd9Sstevel@tonic-gate 					ASSERT(str->gld_mac_info == mac);
1389*7c478bd9Sstevel@tonic-gate 					if (minor == str->gld_minor) {
1390*7c478bd9Sstevel@tonic-gate 						devinfo = mac->gldm_devinfo;
1391*7c478bd9Sstevel@tonic-gate 						goto out;
1392*7c478bd9Sstevel@tonic-gate 					}
1393*7c478bd9Sstevel@tonic-gate 				}
1394*7c478bd9Sstevel@tonic-gate 			}
1395*7c478bd9Sstevel@tonic-gate 		}
1396*7c478bd9Sstevel@tonic-gate 	}
1397*7c478bd9Sstevel@tonic-gate out:
1398*7c478bd9Sstevel@tonic-gate 	mutex_exit(&device->gld_devlock);
1399*7c478bd9Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
1400*7c478bd9Sstevel@tonic-gate 	return (devinfo);
1401*7c478bd9Sstevel@tonic-gate }
1402*7c478bd9Sstevel@tonic-gate 
1403*7c478bd9Sstevel@tonic-gate /*
1404*7c478bd9Sstevel@tonic-gate  * STREAMS open routine.  The device dependent driver specifies this as its
1405*7c478bd9Sstevel@tonic-gate  * open entry point.
1406*7c478bd9Sstevel@tonic-gate  */
1407*7c478bd9Sstevel@tonic-gate /*ARGSUSED2*/
1408*7c478bd9Sstevel@tonic-gate int
1409*7c478bd9Sstevel@tonic-gate gld_open(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *cred)
1410*7c478bd9Sstevel@tonic-gate {
1411*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
1412*7c478bd9Sstevel@tonic-gate 	gld_t *gld;
1413*7c478bd9Sstevel@tonic-gate 	glddev_t *glddev;
1414*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
1415*7c478bd9Sstevel@tonic-gate 	minor_t minor = getminor(*dev);
1416*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
1417*7c478bd9Sstevel@tonic-gate 	t_uscalar_t ppa;
1418*7c478bd9Sstevel@tonic-gate 
1419*7c478bd9Sstevel@tonic-gate 	ASSERT(q != NULL);
1420*7c478bd9Sstevel@tonic-gate 
1421*7c478bd9Sstevel@tonic-gate 	if (minor > GLD_MAX_STYLE1_MINOR)
1422*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1423*7c478bd9Sstevel@tonic-gate 
1424*7c478bd9Sstevel@tonic-gate 	ASSERT(q->q_ptr == NULL);	/* Clone device gives us a fresh Q */
1425*7c478bd9Sstevel@tonic-gate 
1426*7c478bd9Sstevel@tonic-gate 	/* Find our per-major glddev_t structure */
1427*7c478bd9Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
1428*7c478bd9Sstevel@tonic-gate 	glddev = gld_devlookup(getmajor(*dev));
1429*7c478bd9Sstevel@tonic-gate 
1430*7c478bd9Sstevel@tonic-gate 	/*
1431*7c478bd9Sstevel@tonic-gate 	 * This glddev will hang around since detach (and therefore
1432*7c478bd9Sstevel@tonic-gate 	 * gld_unregister) can't run while we're here in the open routine.
1433*7c478bd9Sstevel@tonic-gate 	 */
1434*7c478bd9Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
1435*7c478bd9Sstevel@tonic-gate 
1436*7c478bd9Sstevel@tonic-gate 	if (glddev == NULL)
1437*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1438*7c478bd9Sstevel@tonic-gate 
1439*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1440*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
1441*7c478bd9Sstevel@tonic-gate 		if (minor == GLD_USE_STYLE2)
1442*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_open(%p, Style 2)", (void *)q);
1443*7c478bd9Sstevel@tonic-gate 		else
1444*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_open(%p, Style 1, minor = %d)",
1445*7c478bd9Sstevel@tonic-gate 			    (void *)q, minor);
1446*7c478bd9Sstevel@tonic-gate 	}
1447*7c478bd9Sstevel@tonic-gate #endif
1448*7c478bd9Sstevel@tonic-gate 
1449*7c478bd9Sstevel@tonic-gate 	/*
1450*7c478bd9Sstevel@tonic-gate 	 * get a per-stream structure and link things together so we
1451*7c478bd9Sstevel@tonic-gate 	 * can easily find them later.
1452*7c478bd9Sstevel@tonic-gate 	 */
1453*7c478bd9Sstevel@tonic-gate 	gld = kmem_zalloc(sizeof (gld_t), KM_SLEEP);
1454*7c478bd9Sstevel@tonic-gate 
1455*7c478bd9Sstevel@tonic-gate 	/*
1456*7c478bd9Sstevel@tonic-gate 	 * fill in the structure and state info
1457*7c478bd9Sstevel@tonic-gate 	 */
1458*7c478bd9Sstevel@tonic-gate 	gld->gld_qptr = q;
1459*7c478bd9Sstevel@tonic-gate 	gld->gld_device = glddev;
1460*7c478bd9Sstevel@tonic-gate 	gld->gld_state = DL_UNATTACHED;
1461*7c478bd9Sstevel@tonic-gate 
1462*7c478bd9Sstevel@tonic-gate 	/*
1463*7c478bd9Sstevel@tonic-gate 	 * we must atomically find a free minor number and add the stream
1464*7c478bd9Sstevel@tonic-gate 	 * to a list, because gld_findminor has to traverse the lists to
1465*7c478bd9Sstevel@tonic-gate 	 * determine which minor numbers are free.
1466*7c478bd9Sstevel@tonic-gate 	 */
1467*7c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
1468*7c478bd9Sstevel@tonic-gate 
1469*7c478bd9Sstevel@tonic-gate 	/* find a free minor device number for the clone */
1470*7c478bd9Sstevel@tonic-gate 	gld->gld_minor = gld_findminor(glddev);
1471*7c478bd9Sstevel@tonic-gate 	if (gld->gld_minor == 0) {
1472*7c478bd9Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
1473*7c478bd9Sstevel@tonic-gate 		kmem_free(gld, sizeof (gld_t));
1474*7c478bd9Sstevel@tonic-gate 		return (ENOSR);
1475*7c478bd9Sstevel@tonic-gate 	}
1476*7c478bd9Sstevel@tonic-gate 
1477*7c478bd9Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
1478*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT)
1479*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_open() gld ptr: %p minor: %d",
1480*7c478bd9Sstevel@tonic-gate 		    (void *)gld, gld->gld_minor);
1481*7c478bd9Sstevel@tonic-gate #endif
1482*7c478bd9Sstevel@tonic-gate 
1483*7c478bd9Sstevel@tonic-gate 	if (minor == GLD_USE_STYLE2) {
1484*7c478bd9Sstevel@tonic-gate 		gld->gld_style = DL_STYLE2;
1485*7c478bd9Sstevel@tonic-gate 		*dev = makedevice(getmajor(*dev), gld->gld_minor);
1486*7c478bd9Sstevel@tonic-gate 		WR(q)->q_ptr = q->q_ptr = (caddr_t)gld;
1487*7c478bd9Sstevel@tonic-gate 		gldinsque(gld, glddev->gld_str_prev);
1488*7c478bd9Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
1489*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDPROT)
1490*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "GLDstruct added to device list");
1491*7c478bd9Sstevel@tonic-gate #endif
1492*7c478bd9Sstevel@tonic-gate 		(void) qassociate(q, -1);
1493*7c478bd9Sstevel@tonic-gate 		goto done;
1494*7c478bd9Sstevel@tonic-gate 	}
1495*7c478bd9Sstevel@tonic-gate 
1496*7c478bd9Sstevel@tonic-gate 	gld->gld_style = DL_STYLE1;
1497*7c478bd9Sstevel@tonic-gate 
1498*7c478bd9Sstevel@tonic-gate 	/* the PPA is actually 1 less than the minordev */
1499*7c478bd9Sstevel@tonic-gate 	ppa = GLD_STYLE1_MINOR_TO_PPA(minor);
1500*7c478bd9Sstevel@tonic-gate 
1501*7c478bd9Sstevel@tonic-gate 	for (macinfo = glddev->gld_mac_next;
1502*7c478bd9Sstevel@tonic-gate 	    macinfo != (gld_mac_info_t *)(&glddev->gld_mac_next);
1503*7c478bd9Sstevel@tonic-gate 	    macinfo = macinfo->gldm_next) {
1504*7c478bd9Sstevel@tonic-gate 		ASSERT(macinfo != NULL);
1505*7c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_ppa != ppa)
1506*7c478bd9Sstevel@tonic-gate 			continue;
1507*7c478bd9Sstevel@tonic-gate 
1508*7c478bd9Sstevel@tonic-gate 		if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY))
1509*7c478bd9Sstevel@tonic-gate 			continue;	/* this one's not ready yet */
1510*7c478bd9Sstevel@tonic-gate 
1511*7c478bd9Sstevel@tonic-gate 		/*
1512*7c478bd9Sstevel@tonic-gate 		 * we found the correct PPA
1513*7c478bd9Sstevel@tonic-gate 		 */
1514*7c478bd9Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
1515*7c478bd9Sstevel@tonic-gate 
1516*7c478bd9Sstevel@tonic-gate 		gld->gld_mac_info = macinfo;
1517*7c478bd9Sstevel@tonic-gate 
1518*7c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_send_tagged != NULL)
1519*7c478bd9Sstevel@tonic-gate 			gld->gld_send = macinfo->gldm_send_tagged;
1520*7c478bd9Sstevel@tonic-gate 		else
1521*7c478bd9Sstevel@tonic-gate 			gld->gld_send = macinfo->gldm_send;
1522*7c478bd9Sstevel@tonic-gate 
1523*7c478bd9Sstevel@tonic-gate 		/* now ready for action */
1524*7c478bd9Sstevel@tonic-gate 		gld->gld_state = DL_UNBOUND;
1525*7c478bd9Sstevel@tonic-gate 
1526*7c478bd9Sstevel@tonic-gate 		if ((vlan = gld_get_vlan(macinfo, VLAN_VID_NONE)) == NULL) {
1527*7c478bd9Sstevel@tonic-gate 			GLDM_UNLOCK(macinfo);
1528*7c478bd9Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
1529*7c478bd9Sstevel@tonic-gate 			kmem_free(gld, sizeof (gld_t));
1530*7c478bd9Sstevel@tonic-gate 			return (EIO);
1531*7c478bd9Sstevel@tonic-gate 		}
1532*7c478bd9Sstevel@tonic-gate 
1533*7c478bd9Sstevel@tonic-gate 		mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
1534*7c478bd9Sstevel@tonic-gate 		if (!mac_pvt->started) {
1535*7c478bd9Sstevel@tonic-gate 			if (gld_start_mac(macinfo) != GLD_SUCCESS) {
1536*7c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
1537*7c478bd9Sstevel@tonic-gate 				mutex_exit(&glddev->gld_devlock);
1538*7c478bd9Sstevel@tonic-gate 				kmem_free(gld, sizeof (gld_t));
1539*7c478bd9Sstevel@tonic-gate 				return (EIO);
1540*7c478bd9Sstevel@tonic-gate 			}
1541*7c478bd9Sstevel@tonic-gate 		}
1542*7c478bd9Sstevel@tonic-gate 
1543*7c478bd9Sstevel@tonic-gate 		gld->gld_vlan = vlan;
1544*7c478bd9Sstevel@tonic-gate 		vlan->gldv_nstreams++;
1545*7c478bd9Sstevel@tonic-gate 		gldinsque(gld, vlan->gldv_str_prev);
1546*7c478bd9Sstevel@tonic-gate 		*dev = makedevice(getmajor(*dev), gld->gld_minor);
1547*7c478bd9Sstevel@tonic-gate 		WR(q)->q_ptr = q->q_ptr = (caddr_t)gld;
1548*7c478bd9Sstevel@tonic-gate 
1549*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
1550*7c478bd9Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
1551*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDPROT)
1552*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
1553*7c478bd9Sstevel@tonic-gate 			    "GLDstruct added to instance list");
1554*7c478bd9Sstevel@tonic-gate #endif
1555*7c478bd9Sstevel@tonic-gate 		break;
1556*7c478bd9Sstevel@tonic-gate 	}
1557*7c478bd9Sstevel@tonic-gate 
1558*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED) {
1559*7c478bd9Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
1560*7c478bd9Sstevel@tonic-gate 		kmem_free(gld, sizeof (gld_t));
1561*7c478bd9Sstevel@tonic-gate 		return (ENXIO);
1562*7c478bd9Sstevel@tonic-gate 	}
1563*7c478bd9Sstevel@tonic-gate 
1564*7c478bd9Sstevel@tonic-gate done:
1565*7c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
1566*7c478bd9Sstevel@tonic-gate 	noenable(WR(q));	/* We'll do the qenables manually */
1567*7c478bd9Sstevel@tonic-gate 	qprocson(q);		/* start the queues running */
1568*7c478bd9Sstevel@tonic-gate 	qenable(WR(q));
1569*7c478bd9Sstevel@tonic-gate 	return (0);
1570*7c478bd9Sstevel@tonic-gate }
1571*7c478bd9Sstevel@tonic-gate 
1572*7c478bd9Sstevel@tonic-gate /*
1573*7c478bd9Sstevel@tonic-gate  * normal stream close call checks current status and cleans up
1574*7c478bd9Sstevel@tonic-gate  * data structures that were dynamically allocated
1575*7c478bd9Sstevel@tonic-gate  */
1576*7c478bd9Sstevel@tonic-gate /*ARGSUSED1*/
1577*7c478bd9Sstevel@tonic-gate int
1578*7c478bd9Sstevel@tonic-gate gld_close(queue_t *q, int flag, cred_t *cred)
1579*7c478bd9Sstevel@tonic-gate {
1580*7c478bd9Sstevel@tonic-gate 	gld_t	*gld = (gld_t *)q->q_ptr;
1581*7c478bd9Sstevel@tonic-gate 	glddev_t *glddev = gld->gld_device;
1582*7c478bd9Sstevel@tonic-gate 
1583*7c478bd9Sstevel@tonic-gate 	ASSERT(q);
1584*7c478bd9Sstevel@tonic-gate 	ASSERT(gld);
1585*7c478bd9Sstevel@tonic-gate 
1586*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1587*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
1588*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_close(%p, Style %d)",
1589*7c478bd9Sstevel@tonic-gate 		    (void *)q, (gld->gld_style & 0x1) + 1);
1590*7c478bd9Sstevel@tonic-gate 	}
1591*7c478bd9Sstevel@tonic-gate #endif
1592*7c478bd9Sstevel@tonic-gate 
1593*7c478bd9Sstevel@tonic-gate 	/* Hold all device streams lists still while we check for a macinfo */
1594*7c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
1595*7c478bd9Sstevel@tonic-gate 
1596*7c478bd9Sstevel@tonic-gate 	if (gld->gld_mac_info != NULL) {
1597*7c478bd9Sstevel@tonic-gate 		/* If there's a macinfo, block recv while we change state */
1598*7c478bd9Sstevel@tonic-gate 		GLDM_LOCK(gld->gld_mac_info, RW_WRITER);
1599*7c478bd9Sstevel@tonic-gate 		gld->gld_flags |= GLD_STR_CLOSING; /* no more rcv putnexts */
1600*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(gld->gld_mac_info);
1601*7c478bd9Sstevel@tonic-gate 	} else {
1602*7c478bd9Sstevel@tonic-gate 		/* no mac DL_ATTACHED right now */
1603*7c478bd9Sstevel@tonic-gate 		gld->gld_flags |= GLD_STR_CLOSING;
1604*7c478bd9Sstevel@tonic-gate 	}
1605*7c478bd9Sstevel@tonic-gate 
1606*7c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
1607*7c478bd9Sstevel@tonic-gate 
1608*7c478bd9Sstevel@tonic-gate 	/*
1609*7c478bd9Sstevel@tonic-gate 	 * qprocsoff before we call gld_unbind/gldunattach, so that
1610*7c478bd9Sstevel@tonic-gate 	 * we know wsrv isn't in there trying to undo what we're doing.
1611*7c478bd9Sstevel@tonic-gate 	 */
1612*7c478bd9Sstevel@tonic-gate 	qprocsoff(q);
1613*7c478bd9Sstevel@tonic-gate 
1614*7c478bd9Sstevel@tonic-gate 	ASSERT(gld->gld_wput_count == 0);
1615*7c478bd9Sstevel@tonic-gate 	gld->gld_wput_count = 0;	/* just in case */
1616*7c478bd9Sstevel@tonic-gate 
1617*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_IDLE) {
1618*7c478bd9Sstevel@tonic-gate 		/* Need to unbind */
1619*7c478bd9Sstevel@tonic-gate 		ASSERT(gld->gld_mac_info != NULL);
1620*7c478bd9Sstevel@tonic-gate 		(void) gld_unbind(WR(q), NULL);
1621*7c478bd9Sstevel@tonic-gate 	}
1622*7c478bd9Sstevel@tonic-gate 
1623*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNBOUND) {
1624*7c478bd9Sstevel@tonic-gate 		/*
1625*7c478bd9Sstevel@tonic-gate 		 * Need to unattach
1626*7c478bd9Sstevel@tonic-gate 		 * For style 2 stream, gldunattach also
1627*7c478bd9Sstevel@tonic-gate 		 * associate queue with NULL dip
1628*7c478bd9Sstevel@tonic-gate 		 */
1629*7c478bd9Sstevel@tonic-gate 		ASSERT(gld->gld_mac_info != NULL);
1630*7c478bd9Sstevel@tonic-gate 		(void) gldunattach(WR(q), NULL);
1631*7c478bd9Sstevel@tonic-gate 	}
1632*7c478bd9Sstevel@tonic-gate 
1633*7c478bd9Sstevel@tonic-gate 	/* disassociate the stream from the device */
1634*7c478bd9Sstevel@tonic-gate 	q->q_ptr = WR(q)->q_ptr = NULL;
1635*7c478bd9Sstevel@tonic-gate 
1636*7c478bd9Sstevel@tonic-gate 	/*
1637*7c478bd9Sstevel@tonic-gate 	 * Since we unattached above (if necessary), we know that we're
1638*7c478bd9Sstevel@tonic-gate 	 * on the per-major list of unattached streams, rather than a
1639*7c478bd9Sstevel@tonic-gate 	 * per-PPA list.  So we know we should hold the devlock.
1640*7c478bd9Sstevel@tonic-gate 	 */
1641*7c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
1642*7c478bd9Sstevel@tonic-gate 	gldremque(gld);			/* remove from Style 2 list */
1643*7c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
1644*7c478bd9Sstevel@tonic-gate 
1645*7c478bd9Sstevel@tonic-gate 	kmem_free(gld, sizeof (gld_t));
1646*7c478bd9Sstevel@tonic-gate 
1647*7c478bd9Sstevel@tonic-gate 	return (0);
1648*7c478bd9Sstevel@tonic-gate }
1649*7c478bd9Sstevel@tonic-gate 
1650*7c478bd9Sstevel@tonic-gate /*
1651*7c478bd9Sstevel@tonic-gate  * gld_rsrv (q)
1652*7c478bd9Sstevel@tonic-gate  *	simple read service procedure
1653*7c478bd9Sstevel@tonic-gate  *	purpose is to avoid the time it takes for packets
1654*7c478bd9Sstevel@tonic-gate  *	to move through IP so we can get them off the board
1655*7c478bd9Sstevel@tonic-gate  *	as fast as possible due to limited PC resources.
1656*7c478bd9Sstevel@tonic-gate  *
1657*7c478bd9Sstevel@tonic-gate  *	This is not normally used in the current implementation.  It
1658*7c478bd9Sstevel@tonic-gate  *	can be selected with the undocumented property "fast_recv".
1659*7c478bd9Sstevel@tonic-gate  *	If that property is set, gld_recv will send the packet
1660*7c478bd9Sstevel@tonic-gate  *	upstream with a putq() rather than a putnext(), thus causing
1661*7c478bd9Sstevel@tonic-gate  *	this routine to be scheduled.
1662*7c478bd9Sstevel@tonic-gate  */
1663*7c478bd9Sstevel@tonic-gate int
1664*7c478bd9Sstevel@tonic-gate gld_rsrv(queue_t *q)
1665*7c478bd9Sstevel@tonic-gate {
1666*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
1667*7c478bd9Sstevel@tonic-gate 
1668*7c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
1669*7c478bd9Sstevel@tonic-gate 		if (canputnext(q)) {
1670*7c478bd9Sstevel@tonic-gate 			putnext(q, mp);
1671*7c478bd9Sstevel@tonic-gate 		} else {
1672*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1673*7c478bd9Sstevel@tonic-gate 		}
1674*7c478bd9Sstevel@tonic-gate 	}
1675*7c478bd9Sstevel@tonic-gate 	return (0);
1676*7c478bd9Sstevel@tonic-gate }
1677*7c478bd9Sstevel@tonic-gate 
1678*7c478bd9Sstevel@tonic-gate /*
1679*7c478bd9Sstevel@tonic-gate  * gld_wput (q, mp)
1680*7c478bd9Sstevel@tonic-gate  * general gld stream write put routine. Receives fastpath data from upper
1681*7c478bd9Sstevel@tonic-gate  * modules and processes it immediately.  ioctl and M_PROTO/M_PCPROTO are
1682*7c478bd9Sstevel@tonic-gate  * queued for later processing by the service procedure.
1683*7c478bd9Sstevel@tonic-gate  */
1684*7c478bd9Sstevel@tonic-gate 
1685*7c478bd9Sstevel@tonic-gate int
1686*7c478bd9Sstevel@tonic-gate gld_wput(queue_t *q, mblk_t *mp)
1687*7c478bd9Sstevel@tonic-gate {
1688*7c478bd9Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)(q->q_ptr);
1689*7c478bd9Sstevel@tonic-gate 	int	rc;
1690*7c478bd9Sstevel@tonic-gate 	boolean_t multidata = B_TRUE;
1691*7c478bd9Sstevel@tonic-gate 
1692*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1693*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
1694*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_wput(%p %p): type %x",
1695*7c478bd9Sstevel@tonic-gate 		    (void *)q, (void *)mp, DB_TYPE(mp));
1696*7c478bd9Sstevel@tonic-gate #endif
1697*7c478bd9Sstevel@tonic-gate 	switch (DB_TYPE(mp)) {
1698*7c478bd9Sstevel@tonic-gate 
1699*7c478bd9Sstevel@tonic-gate 	case M_DATA:
1700*7c478bd9Sstevel@tonic-gate 		/* fast data / raw support */
1701*7c478bd9Sstevel@tonic-gate 		/* we must be DL_ATTACHED and DL_BOUND to do this */
1702*7c478bd9Sstevel@tonic-gate 		/* Tricky to access memory without taking the mutex */
1703*7c478bd9Sstevel@tonic-gate 		if ((gld->gld_flags & (GLD_RAW | GLD_FAST)) == 0 ||
1704*7c478bd9Sstevel@tonic-gate 		    gld->gld_state != DL_IDLE) {
1705*7c478bd9Sstevel@tonic-gate 			merror(q, mp, EPROTO);
1706*7c478bd9Sstevel@tonic-gate 			break;
1707*7c478bd9Sstevel@tonic-gate 		}
1708*7c478bd9Sstevel@tonic-gate 		multidata = B_FALSE;
1709*7c478bd9Sstevel@tonic-gate 		/* LINTED: E_CASE_FALLTHRU */
1710*7c478bd9Sstevel@tonic-gate 	case M_MULTIDATA:
1711*7c478bd9Sstevel@tonic-gate 		/* Only call gld_start() directly if nothing queued ahead */
1712*7c478bd9Sstevel@tonic-gate 		/* No guarantees about ordering with different threads */
1713*7c478bd9Sstevel@tonic-gate 		if (q->q_first)
1714*7c478bd9Sstevel@tonic-gate 			goto use_wsrv;
1715*7c478bd9Sstevel@tonic-gate 
1716*7c478bd9Sstevel@tonic-gate 		/*
1717*7c478bd9Sstevel@tonic-gate 		 * This can happen if wsrv has taken off the last mblk but
1718*7c478bd9Sstevel@tonic-gate 		 * is still processing it.
1719*7c478bd9Sstevel@tonic-gate 		 */
1720*7c478bd9Sstevel@tonic-gate 		membar_consumer();
1721*7c478bd9Sstevel@tonic-gate 		if (gld->gld_in_wsrv)
1722*7c478bd9Sstevel@tonic-gate 			goto use_wsrv;
1723*7c478bd9Sstevel@tonic-gate 
1724*7c478bd9Sstevel@tonic-gate 		/*
1725*7c478bd9Sstevel@tonic-gate 		 * Keep a count of current wput calls to start.
1726*7c478bd9Sstevel@tonic-gate 		 * Nonzero count delays any attempted DL_UNBIND.
1727*7c478bd9Sstevel@tonic-gate 		 * See comments above gld_start().
1728*7c478bd9Sstevel@tonic-gate 		 */
1729*7c478bd9Sstevel@tonic-gate 		atomic_add_32((uint32_t *)&gld->gld_wput_count, 1);
1730*7c478bd9Sstevel@tonic-gate 		membar_enter();
1731*7c478bd9Sstevel@tonic-gate 
1732*7c478bd9Sstevel@tonic-gate 		/* Recheck state now wput_count is set to prevent DL_UNBIND */
1733*7c478bd9Sstevel@tonic-gate 		/* If this Q is in process of DL_UNBIND, don't call start */
1734*7c478bd9Sstevel@tonic-gate 		if (gld->gld_state != DL_IDLE || gld->gld_in_unbind) {
1735*7c478bd9Sstevel@tonic-gate 			/* Extremely unlikely */
1736*7c478bd9Sstevel@tonic-gate 			atomic_add_32((uint32_t *)&gld->gld_wput_count, -1);
1737*7c478bd9Sstevel@tonic-gate 			goto use_wsrv;
1738*7c478bd9Sstevel@tonic-gate 		}
1739*7c478bd9Sstevel@tonic-gate 
1740*7c478bd9Sstevel@tonic-gate 		rc = (multidata) ? gld_start_mdt(q, mp, GLD_WPUT) :
1741*7c478bd9Sstevel@tonic-gate 		    gld_start(q, mp, GLD_WPUT, UPRI(gld, mp->b_band));
1742*7c478bd9Sstevel@tonic-gate 
1743*7c478bd9Sstevel@tonic-gate 		/* Allow DL_UNBIND again */
1744*7c478bd9Sstevel@tonic-gate 		membar_exit();
1745*7c478bd9Sstevel@tonic-gate 		atomic_add_32((uint32_t *)&gld->gld_wput_count, -1);
1746*7c478bd9Sstevel@tonic-gate 
1747*7c478bd9Sstevel@tonic-gate 		if (rc == GLD_NORESOURCES)
1748*7c478bd9Sstevel@tonic-gate 			qenable(q);
1749*7c478bd9Sstevel@tonic-gate 		break;	/*  Done with this packet */
1750*7c478bd9Sstevel@tonic-gate 
1751*7c478bd9Sstevel@tonic-gate use_wsrv:
1752*7c478bd9Sstevel@tonic-gate 		/* Q not empty, in DL_DETACH, or start gave NORESOURCES */
1753*7c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
1754*7c478bd9Sstevel@tonic-gate 		qenable(q);
1755*7c478bd9Sstevel@tonic-gate 		break;
1756*7c478bd9Sstevel@tonic-gate 
1757*7c478bd9Sstevel@tonic-gate 	case M_IOCTL:
1758*7c478bd9Sstevel@tonic-gate 		/* ioctl relies on wsrv single threading per queue */
1759*7c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
1760*7c478bd9Sstevel@tonic-gate 		qenable(q);
1761*7c478bd9Sstevel@tonic-gate 		break;
1762*7c478bd9Sstevel@tonic-gate 
1763*7c478bd9Sstevel@tonic-gate 	case M_CTL:
1764*7c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
1765*7c478bd9Sstevel@tonic-gate 		qenable(q);
1766*7c478bd9Sstevel@tonic-gate 		break;
1767*7c478bd9Sstevel@tonic-gate 
1768*7c478bd9Sstevel@tonic-gate 	case M_FLUSH:		/* canonical flush handling */
1769*7c478bd9Sstevel@tonic-gate 		/* XXX Should these be FLUSHALL? */
1770*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHW)
1771*7c478bd9Sstevel@tonic-gate 			flushq(q, 0);
1772*7c478bd9Sstevel@tonic-gate 		if (*mp->b_rptr & FLUSHR) {
1773*7c478bd9Sstevel@tonic-gate 			flushq(RD(q), 0);
1774*7c478bd9Sstevel@tonic-gate 			*mp->b_rptr &= ~FLUSHW;
1775*7c478bd9Sstevel@tonic-gate 			qreply(q, mp);
1776*7c478bd9Sstevel@tonic-gate 		} else
1777*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
1778*7c478bd9Sstevel@tonic-gate 		break;
1779*7c478bd9Sstevel@tonic-gate 
1780*7c478bd9Sstevel@tonic-gate 	case M_PROTO:
1781*7c478bd9Sstevel@tonic-gate 	case M_PCPROTO:
1782*7c478bd9Sstevel@tonic-gate 		/* these rely on wsrv single threading per queue */
1783*7c478bd9Sstevel@tonic-gate 		(void) putq(q, mp);
1784*7c478bd9Sstevel@tonic-gate 		qenable(q);
1785*7c478bd9Sstevel@tonic-gate 		break;
1786*7c478bd9Sstevel@tonic-gate 
1787*7c478bd9Sstevel@tonic-gate 	default:
1788*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1789*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDETRACE)
1790*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
1791*7c478bd9Sstevel@tonic-gate 			    "gld: Unexpected packet type from queue: 0x%x",
1792*7c478bd9Sstevel@tonic-gate 			    DB_TYPE(mp));
1793*7c478bd9Sstevel@tonic-gate #endif
1794*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
1795*7c478bd9Sstevel@tonic-gate 	}
1796*7c478bd9Sstevel@tonic-gate 	return (0);
1797*7c478bd9Sstevel@tonic-gate }
1798*7c478bd9Sstevel@tonic-gate 
1799*7c478bd9Sstevel@tonic-gate /*
1800*7c478bd9Sstevel@tonic-gate  * gld_wsrv - Incoming messages are processed according to the DLPI protocol
1801*7c478bd9Sstevel@tonic-gate  * specification.
1802*7c478bd9Sstevel@tonic-gate  *
1803*7c478bd9Sstevel@tonic-gate  * wsrv is single-threaded per Q.  We make use of this to avoid taking the
1804*7c478bd9Sstevel@tonic-gate  * lock for reading data items that are only ever written by us.
1805*7c478bd9Sstevel@tonic-gate  */
1806*7c478bd9Sstevel@tonic-gate 
1807*7c478bd9Sstevel@tonic-gate int
1808*7c478bd9Sstevel@tonic-gate gld_wsrv(queue_t *q)
1809*7c478bd9Sstevel@tonic-gate {
1810*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
1811*7c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
1812*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
1813*7c478bd9Sstevel@tonic-gate 	union DL_primitives *prim;
1814*7c478bd9Sstevel@tonic-gate 	int err;
1815*7c478bd9Sstevel@tonic-gate 	boolean_t multidata;
1816*7c478bd9Sstevel@tonic-gate 
1817*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1818*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
1819*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_wsrv(%p)", (void *)q);
1820*7c478bd9Sstevel@tonic-gate #endif
1821*7c478bd9Sstevel@tonic-gate 
1822*7c478bd9Sstevel@tonic-gate 	ASSERT(!gld->gld_in_wsrv);
1823*7c478bd9Sstevel@tonic-gate 
1824*7c478bd9Sstevel@tonic-gate 	gld->gld_xwait = B_FALSE; /* We are now going to process this Q */
1825*7c478bd9Sstevel@tonic-gate 
1826*7c478bd9Sstevel@tonic-gate 	if (q->q_first == NULL)
1827*7c478bd9Sstevel@tonic-gate 		return (0);
1828*7c478bd9Sstevel@tonic-gate 
1829*7c478bd9Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
1830*7c478bd9Sstevel@tonic-gate 
1831*7c478bd9Sstevel@tonic-gate 	/*
1832*7c478bd9Sstevel@tonic-gate 	 * Help wput avoid a call to gld_start if there might be a message
1833*7c478bd9Sstevel@tonic-gate 	 * previously queued by that thread being processed here.
1834*7c478bd9Sstevel@tonic-gate 	 */
1835*7c478bd9Sstevel@tonic-gate 	gld->gld_in_wsrv = B_TRUE;
1836*7c478bd9Sstevel@tonic-gate 	membar_enter();
1837*7c478bd9Sstevel@tonic-gate 
1838*7c478bd9Sstevel@tonic-gate 	while ((mp = getq(q)) != NULL) {
1839*7c478bd9Sstevel@tonic-gate 		switch (DB_TYPE(mp)) {
1840*7c478bd9Sstevel@tonic-gate 		case M_DATA:
1841*7c478bd9Sstevel@tonic-gate 		case M_MULTIDATA:
1842*7c478bd9Sstevel@tonic-gate 			multidata = (DB_TYPE(mp) == M_MULTIDATA);
1843*7c478bd9Sstevel@tonic-gate 
1844*7c478bd9Sstevel@tonic-gate 			/*
1845*7c478bd9Sstevel@tonic-gate 			 * retry of a previously processed UNITDATA_REQ
1846*7c478bd9Sstevel@tonic-gate 			 * or is a RAW or FAST message from above.
1847*7c478bd9Sstevel@tonic-gate 			 */
1848*7c478bd9Sstevel@tonic-gate 			if (macinfo == NULL) {
1849*7c478bd9Sstevel@tonic-gate 				/* No longer attached to a PPA, drop packet */
1850*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
1851*7c478bd9Sstevel@tonic-gate 				break;
1852*7c478bd9Sstevel@tonic-gate 			}
1853*7c478bd9Sstevel@tonic-gate 
1854*7c478bd9Sstevel@tonic-gate 			gld->gld_sched_ran = B_FALSE;
1855*7c478bd9Sstevel@tonic-gate 			membar_enter();
1856*7c478bd9Sstevel@tonic-gate 			err = (multidata) ? gld_start_mdt(q, mp, GLD_WSRV) :
1857*7c478bd9Sstevel@tonic-gate 			    gld_start(q, mp, GLD_WSRV, UPRI(gld, mp->b_band));
1858*7c478bd9Sstevel@tonic-gate 			if (err == GLD_NORESOURCES) {
1859*7c478bd9Sstevel@tonic-gate 				/* gld_sched will qenable us later */
1860*7c478bd9Sstevel@tonic-gate 				gld->gld_xwait = B_TRUE; /* want qenable */
1861*7c478bd9Sstevel@tonic-gate 				membar_enter();
1862*7c478bd9Sstevel@tonic-gate 				/*
1863*7c478bd9Sstevel@tonic-gate 				 * v2:  we're not holding the lock; it's
1864*7c478bd9Sstevel@tonic-gate 				 * possible that the driver could have already
1865*7c478bd9Sstevel@tonic-gate 				 * called gld_sched (following up on its
1866*7c478bd9Sstevel@tonic-gate 				 * return of GLD_NORESOURCES), before we got a
1867*7c478bd9Sstevel@tonic-gate 				 * chance to do the putbq() and set gld_xwait.
1868*7c478bd9Sstevel@tonic-gate 				 * So if we saw a call to gld_sched that
1869*7c478bd9Sstevel@tonic-gate 				 * examined this queue, since our call to
1870*7c478bd9Sstevel@tonic-gate 				 * gld_start() above, then it's possible we've
1871*7c478bd9Sstevel@tonic-gate 				 * already seen the only call to gld_sched()
1872*7c478bd9Sstevel@tonic-gate 				 * we're ever going to see.  So we better retry
1873*7c478bd9Sstevel@tonic-gate 				 * transmitting this packet right now.
1874*7c478bd9Sstevel@tonic-gate 				 */
1875*7c478bd9Sstevel@tonic-gate 				if (gld->gld_sched_ran) {
1876*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1877*7c478bd9Sstevel@tonic-gate 					if (gld_debug & GLDTRACE)
1878*7c478bd9Sstevel@tonic-gate 						cmn_err(CE_NOTE, "gld_wsrv: "
1879*7c478bd9Sstevel@tonic-gate 						    "sched was called");
1880*7c478bd9Sstevel@tonic-gate #endif
1881*7c478bd9Sstevel@tonic-gate 					break;	/* try again right now */
1882*7c478bd9Sstevel@tonic-gate 				}
1883*7c478bd9Sstevel@tonic-gate 				gld->gld_in_wsrv = B_FALSE;
1884*7c478bd9Sstevel@tonic-gate 				return (0);
1885*7c478bd9Sstevel@tonic-gate 			}
1886*7c478bd9Sstevel@tonic-gate 			break;
1887*7c478bd9Sstevel@tonic-gate 
1888*7c478bd9Sstevel@tonic-gate 		case M_IOCTL:
1889*7c478bd9Sstevel@tonic-gate 			(void) gld_ioctl(q, mp);
1890*7c478bd9Sstevel@tonic-gate 			break;
1891*7c478bd9Sstevel@tonic-gate 
1892*7c478bd9Sstevel@tonic-gate 		case M_CTL:
1893*7c478bd9Sstevel@tonic-gate 			if (macinfo == NULL) {
1894*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
1895*7c478bd9Sstevel@tonic-gate 				break;
1896*7c478bd9Sstevel@tonic-gate 			}
1897*7c478bd9Sstevel@tonic-gate 
1898*7c478bd9Sstevel@tonic-gate 			if (macinfo->gldm_mctl != NULL) {
1899*7c478bd9Sstevel@tonic-gate 				GLDM_LOCK(macinfo, RW_WRITER);
1900*7c478bd9Sstevel@tonic-gate 				(void) (*macinfo->gldm_mctl) (macinfo, q, mp);
1901*7c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
1902*7c478bd9Sstevel@tonic-gate 			} else {
1903*7c478bd9Sstevel@tonic-gate 				/* This driver doesn't recognize, just drop */
1904*7c478bd9Sstevel@tonic-gate 				freemsg(mp);
1905*7c478bd9Sstevel@tonic-gate 			}
1906*7c478bd9Sstevel@tonic-gate 			break;
1907*7c478bd9Sstevel@tonic-gate 
1908*7c478bd9Sstevel@tonic-gate 		case M_PROTO:	/* Will be an DLPI message of some type */
1909*7c478bd9Sstevel@tonic-gate 		case M_PCPROTO:
1910*7c478bd9Sstevel@tonic-gate 			if ((err = gld_cmds(q, mp)) != GLDE_OK) {
1911*7c478bd9Sstevel@tonic-gate 				if (err == GLDE_RETRY) {
1912*7c478bd9Sstevel@tonic-gate 					gld->gld_in_wsrv = B_FALSE;
1913*7c478bd9Sstevel@tonic-gate 					return (0); /* quit while we're ahead */
1914*7c478bd9Sstevel@tonic-gate 				}
1915*7c478bd9Sstevel@tonic-gate 				prim = (union DL_primitives *)mp->b_rptr;
1916*7c478bd9Sstevel@tonic-gate 				dlerrorack(q, mp, prim->dl_primitive, err, 0);
1917*7c478bd9Sstevel@tonic-gate 			}
1918*7c478bd9Sstevel@tonic-gate 			break;
1919*7c478bd9Sstevel@tonic-gate 
1920*7c478bd9Sstevel@tonic-gate 		default:
1921*7c478bd9Sstevel@tonic-gate 			/* This should never happen */
1922*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
1923*7c478bd9Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
1924*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
1925*7c478bd9Sstevel@tonic-gate 				    "gld_wsrv: db_type(%x) not supported",
1926*7c478bd9Sstevel@tonic-gate 				    mp->b_datap->db_type);
1927*7c478bd9Sstevel@tonic-gate #endif
1928*7c478bd9Sstevel@tonic-gate 			freemsg(mp);	/* unknown types are discarded */
1929*7c478bd9Sstevel@tonic-gate 			break;
1930*7c478bd9Sstevel@tonic-gate 		}
1931*7c478bd9Sstevel@tonic-gate 	}
1932*7c478bd9Sstevel@tonic-gate 
1933*7c478bd9Sstevel@tonic-gate 	membar_exit();
1934*7c478bd9Sstevel@tonic-gate 	gld->gld_in_wsrv = B_FALSE;
1935*7c478bd9Sstevel@tonic-gate 	return (0);
1936*7c478bd9Sstevel@tonic-gate }
1937*7c478bd9Sstevel@tonic-gate 
1938*7c478bd9Sstevel@tonic-gate /*
1939*7c478bd9Sstevel@tonic-gate  * gld_start() can get called from gld_wput(), gld_wsrv(), or gld_unitdata().
1940*7c478bd9Sstevel@tonic-gate  *
1941*7c478bd9Sstevel@tonic-gate  * We only come directly from wput() in the GLD_FAST (fastpath) or RAW case.
1942*7c478bd9Sstevel@tonic-gate  *
1943*7c478bd9Sstevel@tonic-gate  * In particular, we must avoid calling gld_precv*() if we came from wput().
1944*7c478bd9Sstevel@tonic-gate  * gld_precv*() is where we, on the transmit side, loop back our outgoing
1945*7c478bd9Sstevel@tonic-gate  * packets to the receive side if we are in physical promiscuous mode.
1946*7c478bd9Sstevel@tonic-gate  * Since the receive side holds a lock across its call to the upstream
1947*7c478bd9Sstevel@tonic-gate  * putnext, and that upstream module could well have looped back to our
1948*7c478bd9Sstevel@tonic-gate  * wput() routine on the same thread, we cannot call gld_precv* from here
1949*7c478bd9Sstevel@tonic-gate  * for fear of causing a recursive lock entry in our receive code.
1950*7c478bd9Sstevel@tonic-gate  *
1951*7c478bd9Sstevel@tonic-gate  * There is a problem here when coming from gld_wput().  While wput
1952*7c478bd9Sstevel@tonic-gate  * only comes here if the queue is attached to a PPA and bound to a SAP
1953*7c478bd9Sstevel@tonic-gate  * and there are no messages on the queue ahead of the M_DATA that could
1954*7c478bd9Sstevel@tonic-gate  * change that, it is theoretically possible that another thread could
1955*7c478bd9Sstevel@tonic-gate  * now wput a DL_UNBIND and a DL_DETACH message, and the wsrv() routine
1956*7c478bd9Sstevel@tonic-gate  * could wake up and process them, before we finish processing this
1957*7c478bd9Sstevel@tonic-gate  * send of the M_DATA.  This can only possibly happen on a Style 2 RAW or
1958*7c478bd9Sstevel@tonic-gate  * FAST (fastpath) stream:  non RAW/FAST streams always go through wsrv(),
1959*7c478bd9Sstevel@tonic-gate  * and Style 1 streams only DL_DETACH in the close routine, where
1960*7c478bd9Sstevel@tonic-gate  * qprocsoff() protects us.  If this happens we could end up calling
1961*7c478bd9Sstevel@tonic-gate  * gldm_send() after we have detached the stream and possibly called
1962*7c478bd9Sstevel@tonic-gate  * gldm_stop().  Worse, once the number of attached streams goes to zero,
1963*7c478bd9Sstevel@tonic-gate  * detach/unregister could be called, and the macinfo could go away entirely.
1964*7c478bd9Sstevel@tonic-gate  *
1965*7c478bd9Sstevel@tonic-gate  * No one has ever seen this happen.
1966*7c478bd9Sstevel@tonic-gate  *
1967*7c478bd9Sstevel@tonic-gate  * It is some trouble to fix this, and we would rather not add any mutex
1968*7c478bd9Sstevel@tonic-gate  * logic into the wput() routine, which is supposed to be a "fast"
1969*7c478bd9Sstevel@tonic-gate  * path.
1970*7c478bd9Sstevel@tonic-gate  *
1971*7c478bd9Sstevel@tonic-gate  * What I've done is use an atomic counter to keep a count of the number
1972*7c478bd9Sstevel@tonic-gate  * of threads currently calling gld_start() from wput() on this stream.
1973*7c478bd9Sstevel@tonic-gate  * If DL_DETACH sees this as nonzero, it putbqs the request back onto
1974*7c478bd9Sstevel@tonic-gate  * the queue and qenables, hoping to have better luck next time.  Since
1975*7c478bd9Sstevel@tonic-gate  * people shouldn't be trying to send after they've asked to DL_DETACH,
1976*7c478bd9Sstevel@tonic-gate  * hopefully very soon all the wput=>start threads should have returned
1977*7c478bd9Sstevel@tonic-gate  * and the DL_DETACH will succeed.  It's hard to test this since the odds
1978*7c478bd9Sstevel@tonic-gate  * of the failure even trying to happen are so small.  I probably could
1979*7c478bd9Sstevel@tonic-gate  * have ignored the whole issue and never been the worse for it.
1980*7c478bd9Sstevel@tonic-gate  */
1981*7c478bd9Sstevel@tonic-gate static int
1982*7c478bd9Sstevel@tonic-gate gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri)
1983*7c478bd9Sstevel@tonic-gate {
1984*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
1985*7c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
1986*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
1987*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
1988*7c478bd9Sstevel@tonic-gate 	int rc;
1989*7c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
1990*7c478bd9Sstevel@tonic-gate 	pktinfo_t pktinfo;
1991*7c478bd9Sstevel@tonic-gate 	uint32_t vtag;
1992*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
1993*7c478bd9Sstevel@tonic-gate 
1994*7c478bd9Sstevel@tonic-gate 	ASSERT(DB_TYPE(mp) == M_DATA);
1995*7c478bd9Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
1996*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
1997*7c478bd9Sstevel@tonic-gate 	ifp = mac_pvt->interfacep;
1998*7c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
1999*7c478bd9Sstevel@tonic-gate 
2000*7c478bd9Sstevel@tonic-gate 	if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_TX) != 0) {
2001*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2002*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2003*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
2004*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2005*7c478bd9Sstevel@tonic-gate 			    "gld_start: failed to interpret outbound packet");
2006*7c478bd9Sstevel@tonic-gate #endif
2007*7c478bd9Sstevel@tonic-gate 		vlan->gldv_stats->glds_xmtbadinterp++;
2008*7c478bd9Sstevel@tonic-gate 		return (GLD_BADARG);
2009*7c478bd9Sstevel@tonic-gate 	}
2010*7c478bd9Sstevel@tonic-gate 
2011*7c478bd9Sstevel@tonic-gate 	/*
2012*7c478bd9Sstevel@tonic-gate 	 * We're not holding the lock for this check.  If the promiscuous
2013*7c478bd9Sstevel@tonic-gate 	 * state is in flux it doesn't matter much if we get this wrong.
2014*7c478bd9Sstevel@tonic-gate 	 */
2015*7c478bd9Sstevel@tonic-gate 	if (mac_pvt->nprom > 0) {
2016*7c478bd9Sstevel@tonic-gate 		/*
2017*7c478bd9Sstevel@tonic-gate 		 * We want to loopback to the receive side, but to avoid
2018*7c478bd9Sstevel@tonic-gate 		 * recursive lock entry:  if we came from wput(), which
2019*7c478bd9Sstevel@tonic-gate 		 * could have looped back via IP from our own receive
2020*7c478bd9Sstevel@tonic-gate 		 * interrupt thread, we decline this request.  wput()
2021*7c478bd9Sstevel@tonic-gate 		 * will then queue the packet for wsrv().  This means
2022*7c478bd9Sstevel@tonic-gate 		 * that when snoop is running we don't get the advantage
2023*7c478bd9Sstevel@tonic-gate 		 * of the wput() multithreaded direct entry to the
2024*7c478bd9Sstevel@tonic-gate 		 * driver's send routine.
2025*7c478bd9Sstevel@tonic-gate 		 */
2026*7c478bd9Sstevel@tonic-gate 		if (caller == GLD_WPUT) {
2027*7c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
2028*7c478bd9Sstevel@tonic-gate 			return (GLD_NORESOURCES);
2029*7c478bd9Sstevel@tonic-gate 		}
2030*7c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_capabilities & GLD_CAP_ZEROCOPY)
2031*7c478bd9Sstevel@tonic-gate 			nmp = dupmsg_noloan(mp);
2032*7c478bd9Sstevel@tonic-gate 		else
2033*7c478bd9Sstevel@tonic-gate 			nmp = dupmsg(mp);
2034*7c478bd9Sstevel@tonic-gate 	} else
2035*7c478bd9Sstevel@tonic-gate 		nmp = NULL;		/* we need no loopback */
2036*7c478bd9Sstevel@tonic-gate 
2037*7c478bd9Sstevel@tonic-gate 	vtag = GLD_MK_VTAG(vlan->gldv_ptag, upri);
2038*7c478bd9Sstevel@tonic-gate 	if (ifp->hdr_size > 0 &&
2039*7c478bd9Sstevel@tonic-gate 	    pktinfo.pktLen > ifp->hdr_size + (vtag == 0 ? 0 : VTAG_SIZE) +
2040*7c478bd9Sstevel@tonic-gate 	    macinfo->gldm_maxpkt) {
2041*7c478bd9Sstevel@tonic-gate 		freemsg(mp);	/* discard oversized outbound packet */
2042*7c478bd9Sstevel@tonic-gate 		if (nmp)
2043*7c478bd9Sstevel@tonic-gate 			freemsg(nmp);	/* free the duped message */
2044*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2045*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
2046*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2047*7c478bd9Sstevel@tonic-gate 			    "gld_start: oversize outbound packet, size %d,"
2048*7c478bd9Sstevel@tonic-gate 			    "max %d", pktinfo.pktLen,
2049*7c478bd9Sstevel@tonic-gate 			    ifp->hdr_size + macinfo->gldm_maxpkt);
2050*7c478bd9Sstevel@tonic-gate #endif
2051*7c478bd9Sstevel@tonic-gate 		vlan->gldv_stats->glds_xmtbadinterp++;
2052*7c478bd9Sstevel@tonic-gate 		return (GLD_BADARG);
2053*7c478bd9Sstevel@tonic-gate 	}
2054*7c478bd9Sstevel@tonic-gate 
2055*7c478bd9Sstevel@tonic-gate 	rc = (*gld->gld_send)(macinfo, mp, vtag);
2056*7c478bd9Sstevel@tonic-gate 
2057*7c478bd9Sstevel@tonic-gate 	if (rc != GLD_SUCCESS) {
2058*7c478bd9Sstevel@tonic-gate 		if (rc == GLD_NORESOURCES) {
2059*7c478bd9Sstevel@tonic-gate 			vlan->gldv_stats->glds_xmtretry++;
2060*7c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
2061*7c478bd9Sstevel@tonic-gate 		} else {
2062*7c478bd9Sstevel@tonic-gate 			/* transmit error; drop the packet */
2063*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2064*7c478bd9Sstevel@tonic-gate 			/* We're supposed to count failed attempts as well */
2065*7c478bd9Sstevel@tonic-gate 			UPDATE_STATS(vlan, pktinfo, 1);
2066*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2067*7c478bd9Sstevel@tonic-gate 			if (gld_debug & GLDERRS)
2068*7c478bd9Sstevel@tonic-gate 				cmn_err(CE_WARN,
2069*7c478bd9Sstevel@tonic-gate 				    "gld_start: gldm_send failed %d", rc);
2070*7c478bd9Sstevel@tonic-gate #endif
2071*7c478bd9Sstevel@tonic-gate 		}
2072*7c478bd9Sstevel@tonic-gate 		if (nmp)
2073*7c478bd9Sstevel@tonic-gate 			freemsg(nmp);	/* free the dupped message */
2074*7c478bd9Sstevel@tonic-gate 		return (rc);
2075*7c478bd9Sstevel@tonic-gate 	}
2076*7c478bd9Sstevel@tonic-gate 
2077*7c478bd9Sstevel@tonic-gate 	UPDATE_STATS(vlan, pktinfo, 1);
2078*7c478bd9Sstevel@tonic-gate 
2079*7c478bd9Sstevel@tonic-gate 	/*
2080*7c478bd9Sstevel@tonic-gate 	 * Loopback case. The message needs to be returned back on
2081*7c478bd9Sstevel@tonic-gate 	 * the read side. This would silently fail if the dumpmsg fails
2082*7c478bd9Sstevel@tonic-gate 	 * above. This is probably OK, if there is no memory to dup the
2083*7c478bd9Sstevel@tonic-gate 	 * block, then there isn't much we could do anyway.
2084*7c478bd9Sstevel@tonic-gate 	 */
2085*7c478bd9Sstevel@tonic-gate 	if (nmp) {
2086*7c478bd9Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
2087*7c478bd9Sstevel@tonic-gate 		gld_precv(macinfo, vlan, nmp);
2088*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
2089*7c478bd9Sstevel@tonic-gate 	}
2090*7c478bd9Sstevel@tonic-gate 
2091*7c478bd9Sstevel@tonic-gate 	return (GLD_SUCCESS);
2092*7c478bd9Sstevel@tonic-gate }
2093*7c478bd9Sstevel@tonic-gate 
2094*7c478bd9Sstevel@tonic-gate /*
2095*7c478bd9Sstevel@tonic-gate  * With MDT V.2 a single message mp can have one header area and multiple
2096*7c478bd9Sstevel@tonic-gate  * payload areas. A packet is described by dl_pkt_info, and each packet can
2097*7c478bd9Sstevel@tonic-gate  * span multiple payload areas (currently with TCP, each packet will have one
2098*7c478bd9Sstevel@tonic-gate  * header and at the most two payload areas). MACs might have a limit on the
2099*7c478bd9Sstevel@tonic-gate  * number of payload segments (i.e. per packet scatter-gather limit), and
2100*7c478bd9Sstevel@tonic-gate  * MDT V.2 has a way of specifying that with mdt_span_limit; the MAC driver
2101*7c478bd9Sstevel@tonic-gate  * might also have a limit on the total number of payloads in a message, and
2102*7c478bd9Sstevel@tonic-gate  * that is specified by mdt_max_pld.
2103*7c478bd9Sstevel@tonic-gate  */
2104*7c478bd9Sstevel@tonic-gate static int
2105*7c478bd9Sstevel@tonic-gate gld_start_mdt(queue_t *q, mblk_t *mp, int caller)
2106*7c478bd9Sstevel@tonic-gate {
2107*7c478bd9Sstevel@tonic-gate 	mblk_t *nextmp;
2108*7c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
2109*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
2110*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
2111*7c478bd9Sstevel@tonic-gate 	int numpacks, mdtpacks;
2112*7c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp = mac_pvt->interfacep;
2113*7c478bd9Sstevel@tonic-gate 	pktinfo_t pktinfo;
2114*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan = (gld_vlan_t *)gld->gld_vlan;
2115*7c478bd9Sstevel@tonic-gate 	boolean_t doloop = B_FALSE;
2116*7c478bd9Sstevel@tonic-gate 	multidata_t *dlmdp;
2117*7c478bd9Sstevel@tonic-gate 	pdescinfo_t pinfo;
2118*7c478bd9Sstevel@tonic-gate 	pdesc_t *dl_pkt;
2119*7c478bd9Sstevel@tonic-gate 	void *cookie;
2120*7c478bd9Sstevel@tonic-gate 	uint_t totLen = 0;
2121*7c478bd9Sstevel@tonic-gate 
2122*7c478bd9Sstevel@tonic-gate 	ASSERT(DB_TYPE(mp) == M_MULTIDATA);
2123*7c478bd9Sstevel@tonic-gate 
2124*7c478bd9Sstevel@tonic-gate 	/*
2125*7c478bd9Sstevel@tonic-gate 	 * We're not holding the lock for this check.  If the promiscuous
2126*7c478bd9Sstevel@tonic-gate 	 * state is in flux it doesn't matter much if we get this wrong.
2127*7c478bd9Sstevel@tonic-gate 	 */
2128*7c478bd9Sstevel@tonic-gate 	if (mac_pvt->nprom > 0) {
2129*7c478bd9Sstevel@tonic-gate 		/*
2130*7c478bd9Sstevel@tonic-gate 		 * We want to loopback to the receive side, but to avoid
2131*7c478bd9Sstevel@tonic-gate 		 * recursive lock entry:  if we came from wput(), which
2132*7c478bd9Sstevel@tonic-gate 		 * could have looped back via IP from our own receive
2133*7c478bd9Sstevel@tonic-gate 		 * interrupt thread, we decline this request.  wput()
2134*7c478bd9Sstevel@tonic-gate 		 * will then queue the packet for wsrv().  This means
2135*7c478bd9Sstevel@tonic-gate 		 * that when snoop is running we don't get the advantage
2136*7c478bd9Sstevel@tonic-gate 		 * of the wput() multithreaded direct entry to the
2137*7c478bd9Sstevel@tonic-gate 		 * driver's send routine.
2138*7c478bd9Sstevel@tonic-gate 		 */
2139*7c478bd9Sstevel@tonic-gate 		if (caller == GLD_WPUT) {
2140*7c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
2141*7c478bd9Sstevel@tonic-gate 			return (GLD_NORESOURCES);
2142*7c478bd9Sstevel@tonic-gate 		}
2143*7c478bd9Sstevel@tonic-gate 		doloop = B_TRUE;
2144*7c478bd9Sstevel@tonic-gate 
2145*7c478bd9Sstevel@tonic-gate 		/*
2146*7c478bd9Sstevel@tonic-gate 		 * unlike the M_DATA case, we don't have to call
2147*7c478bd9Sstevel@tonic-gate 		 * dupmsg_noloan here because mmd_transform
2148*7c478bd9Sstevel@tonic-gate 		 * (called by gld_precv_mdt) will make a copy of
2149*7c478bd9Sstevel@tonic-gate 		 * each dblk.
2150*7c478bd9Sstevel@tonic-gate 		 */
2151*7c478bd9Sstevel@tonic-gate 	}
2152*7c478bd9Sstevel@tonic-gate 
2153*7c478bd9Sstevel@tonic-gate 	while (mp != NULL) {
2154*7c478bd9Sstevel@tonic-gate 		/*
2155*7c478bd9Sstevel@tonic-gate 		 * The lower layer driver only gets a single multidata
2156*7c478bd9Sstevel@tonic-gate 		 * message; this also makes it easier to handle noresources.
2157*7c478bd9Sstevel@tonic-gate 		 */
2158*7c478bd9Sstevel@tonic-gate 		nextmp = mp->b_cont;
2159*7c478bd9Sstevel@tonic-gate 		mp->b_cont = NULL;
2160*7c478bd9Sstevel@tonic-gate 
2161*7c478bd9Sstevel@tonic-gate 		/*
2162*7c478bd9Sstevel@tonic-gate 		 * Get number of packets in this message; if nothing
2163*7c478bd9Sstevel@tonic-gate 		 * to transmit, go to next message.
2164*7c478bd9Sstevel@tonic-gate 		 */
2165*7c478bd9Sstevel@tonic-gate 		dlmdp = mmd_getmultidata(mp);
2166*7c478bd9Sstevel@tonic-gate 		if ((mdtpacks = (int)mmd_getcnt(dlmdp, NULL, NULL)) == 0) {
2167*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2168*7c478bd9Sstevel@tonic-gate 			mp = nextmp;
2169*7c478bd9Sstevel@tonic-gate 			continue;
2170*7c478bd9Sstevel@tonic-gate 		}
2171*7c478bd9Sstevel@tonic-gate 
2172*7c478bd9Sstevel@tonic-gate 		/*
2173*7c478bd9Sstevel@tonic-gate 		 * Run interpreter to populate media specific pktinfo fields.
2174*7c478bd9Sstevel@tonic-gate 		 * This collects per MDT message information like sap,
2175*7c478bd9Sstevel@tonic-gate 		 * broad/multicast etc.
2176*7c478bd9Sstevel@tonic-gate 		 */
2177*7c478bd9Sstevel@tonic-gate 		(void) (*ifp->interpreter_mdt)(macinfo, mp, NULL, &pktinfo,
2178*7c478bd9Sstevel@tonic-gate 		    GLD_MDT_TX);
2179*7c478bd9Sstevel@tonic-gate 
2180*7c478bd9Sstevel@tonic-gate 		numpacks = (*macinfo->gldm_mdt_pre)(macinfo, mp, &cookie);
2181*7c478bd9Sstevel@tonic-gate 
2182*7c478bd9Sstevel@tonic-gate 		if (numpacks > 0) {
2183*7c478bd9Sstevel@tonic-gate 			/*
2184*7c478bd9Sstevel@tonic-gate 			 * Driver indicates it can transmit at least 1, and
2185*7c478bd9Sstevel@tonic-gate 			 * possibly all, packets in MDT message.
2186*7c478bd9Sstevel@tonic-gate 			 */
2187*7c478bd9Sstevel@tonic-gate 			int count = numpacks;
2188*7c478bd9Sstevel@tonic-gate 
2189*7c478bd9Sstevel@tonic-gate 			for (dl_pkt = mmd_getfirstpdesc(dlmdp, &pinfo);
2190*7c478bd9Sstevel@tonic-gate 			    (dl_pkt != NULL);
2191*7c478bd9Sstevel@tonic-gate 			    dl_pkt = mmd_getnextpdesc(dl_pkt, &pinfo)) {
2192*7c478bd9Sstevel@tonic-gate 				/*
2193*7c478bd9Sstevel@tonic-gate 				 * Format this packet by adding link header and
2194*7c478bd9Sstevel@tonic-gate 				 * adjusting pdescinfo to include it; get
2195*7c478bd9Sstevel@tonic-gate 				 * packet length.
2196*7c478bd9Sstevel@tonic-gate 				 */
2197*7c478bd9Sstevel@tonic-gate 				(void) (*ifp->interpreter_mdt)(macinfo, NULL,
2198*7c478bd9Sstevel@tonic-gate 				    &pinfo, &pktinfo, GLD_MDT_TXPKT);
2199*7c478bd9Sstevel@tonic-gate 
2200*7c478bd9Sstevel@tonic-gate 				totLen += pktinfo.pktLen;
2201*7c478bd9Sstevel@tonic-gate 
2202*7c478bd9Sstevel@tonic-gate 				/*
2203*7c478bd9Sstevel@tonic-gate 				 * Loop back packet before handing to the
2204*7c478bd9Sstevel@tonic-gate 				 * driver.
2205*7c478bd9Sstevel@tonic-gate 				 */
2206*7c478bd9Sstevel@tonic-gate 				if (doloop &&
2207*7c478bd9Sstevel@tonic-gate 				    mmd_adjpdesc(dl_pkt, &pinfo) != NULL) {
2208*7c478bd9Sstevel@tonic-gate 					GLDM_LOCK(macinfo, RW_WRITER);
2209*7c478bd9Sstevel@tonic-gate 					gld_precv_mdt(macinfo, vlan, mp,
2210*7c478bd9Sstevel@tonic-gate 					    dl_pkt, &pktinfo);
2211*7c478bd9Sstevel@tonic-gate 					GLDM_UNLOCK(macinfo);
2212*7c478bd9Sstevel@tonic-gate 				}
2213*7c478bd9Sstevel@tonic-gate 
2214*7c478bd9Sstevel@tonic-gate 				/*
2215*7c478bd9Sstevel@tonic-gate 				 * And send off to driver.
2216*7c478bd9Sstevel@tonic-gate 				 */
2217*7c478bd9Sstevel@tonic-gate 				(*macinfo->gldm_mdt_send)(macinfo, cookie,
2218*7c478bd9Sstevel@tonic-gate 				    &pinfo);
2219*7c478bd9Sstevel@tonic-gate 
2220*7c478bd9Sstevel@tonic-gate 				/*
2221*7c478bd9Sstevel@tonic-gate 				 * Be careful not to invoke getnextpdesc if we
2222*7c478bd9Sstevel@tonic-gate 				 * already sent the last packet, since driver
2223*7c478bd9Sstevel@tonic-gate 				 * might have posted it to hardware causing a
2224*7c478bd9Sstevel@tonic-gate 				 * completion and freemsg() so the MDT data
2225*7c478bd9Sstevel@tonic-gate 				 * structures might not be valid anymore.
2226*7c478bd9Sstevel@tonic-gate 				 */
2227*7c478bd9Sstevel@tonic-gate 				if (--count == 0)
2228*7c478bd9Sstevel@tonic-gate 					break;
2229*7c478bd9Sstevel@tonic-gate 			}
2230*7c478bd9Sstevel@tonic-gate 			(*macinfo->gldm_mdt_post)(macinfo, mp, cookie);
2231*7c478bd9Sstevel@tonic-gate 			pktinfo.pktLen = totLen;
2232*7c478bd9Sstevel@tonic-gate 			UPDATE_STATS(vlan, pktinfo, numpacks);
2233*7c478bd9Sstevel@tonic-gate 
2234*7c478bd9Sstevel@tonic-gate 			/*
2235*7c478bd9Sstevel@tonic-gate 			 * In the noresources case (when driver indicates it
2236*7c478bd9Sstevel@tonic-gate 			 * can not transmit all packets in the MDT message),
2237*7c478bd9Sstevel@tonic-gate 			 * adjust to skip the first few packets on retrial.
2238*7c478bd9Sstevel@tonic-gate 			 */
2239*7c478bd9Sstevel@tonic-gate 			if (numpacks != mdtpacks) {
2240*7c478bd9Sstevel@tonic-gate 				/*
2241*7c478bd9Sstevel@tonic-gate 				 * Release already processed packet descriptors.
2242*7c478bd9Sstevel@tonic-gate 				 */
2243*7c478bd9Sstevel@tonic-gate 				for (count = 0; count < numpacks; count++) {
2244*7c478bd9Sstevel@tonic-gate 					dl_pkt = mmd_getfirstpdesc(dlmdp,
2245*7c478bd9Sstevel@tonic-gate 					    &pinfo);
2246*7c478bd9Sstevel@tonic-gate 					mmd_rempdesc(dl_pkt);
2247*7c478bd9Sstevel@tonic-gate 				}
2248*7c478bd9Sstevel@tonic-gate 				vlan->gldv_stats->glds_xmtretry++;
2249*7c478bd9Sstevel@tonic-gate 				mp->b_cont = nextmp;
2250*7c478bd9Sstevel@tonic-gate 				(void) putbq(q, mp);
2251*7c478bd9Sstevel@tonic-gate 				return (GLD_NORESOURCES);
2252*7c478bd9Sstevel@tonic-gate 			}
2253*7c478bd9Sstevel@tonic-gate 		} else if (numpacks == 0) {
2254*7c478bd9Sstevel@tonic-gate 			/*
2255*7c478bd9Sstevel@tonic-gate 			 * Driver indicates it can not transmit any packets
2256*7c478bd9Sstevel@tonic-gate 			 * currently and will request retrial later.
2257*7c478bd9Sstevel@tonic-gate 			 */
2258*7c478bd9Sstevel@tonic-gate 			vlan->gldv_stats->glds_xmtretry++;
2259*7c478bd9Sstevel@tonic-gate 			mp->b_cont = nextmp;
2260*7c478bd9Sstevel@tonic-gate 			(void) putbq(q, mp);
2261*7c478bd9Sstevel@tonic-gate 			return (GLD_NORESOURCES);
2262*7c478bd9Sstevel@tonic-gate 		} else {
2263*7c478bd9Sstevel@tonic-gate 			ASSERT(numpacks == -1);
2264*7c478bd9Sstevel@tonic-gate 			/*
2265*7c478bd9Sstevel@tonic-gate 			 * We're supposed to count failed attempts as well.
2266*7c478bd9Sstevel@tonic-gate 			 */
2267*7c478bd9Sstevel@tonic-gate 			dl_pkt = mmd_getfirstpdesc(dlmdp, &pinfo);
2268*7c478bd9Sstevel@tonic-gate 			while (dl_pkt != NULL) {
2269*7c478bd9Sstevel@tonic-gate 				/*
2270*7c478bd9Sstevel@tonic-gate 				 * Call interpreter to determine total packet
2271*7c478bd9Sstevel@tonic-gate 				 * bytes that are being dropped.
2272*7c478bd9Sstevel@tonic-gate 				 */
2273*7c478bd9Sstevel@tonic-gate 				(void) (*ifp->interpreter_mdt)(macinfo, NULL,
2274*7c478bd9Sstevel@tonic-gate 				    &pinfo, &pktinfo, GLD_MDT_TXPKT);
2275*7c478bd9Sstevel@tonic-gate 
2276*7c478bd9Sstevel@tonic-gate 				totLen += pktinfo.pktLen;
2277*7c478bd9Sstevel@tonic-gate 
2278*7c478bd9Sstevel@tonic-gate 				dl_pkt = mmd_getnextpdesc(dl_pkt, &pinfo);
2279*7c478bd9Sstevel@tonic-gate 			}
2280*7c478bd9Sstevel@tonic-gate 			pktinfo.pktLen = totLen;
2281*7c478bd9Sstevel@tonic-gate 			UPDATE_STATS(vlan, pktinfo, mdtpacks);
2282*7c478bd9Sstevel@tonic-gate 
2283*7c478bd9Sstevel@tonic-gate 			/*
2284*7c478bd9Sstevel@tonic-gate 			 * Transmit error; drop the message, move on
2285*7c478bd9Sstevel@tonic-gate 			 * to the next one.
2286*7c478bd9Sstevel@tonic-gate 			 */
2287*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
2288*7c478bd9Sstevel@tonic-gate 		}
2289*7c478bd9Sstevel@tonic-gate 
2290*7c478bd9Sstevel@tonic-gate 		/*
2291*7c478bd9Sstevel@tonic-gate 		 * Process the next multidata block, if there is one.
2292*7c478bd9Sstevel@tonic-gate 		 */
2293*7c478bd9Sstevel@tonic-gate 		mp = nextmp;
2294*7c478bd9Sstevel@tonic-gate 	}
2295*7c478bd9Sstevel@tonic-gate 
2296*7c478bd9Sstevel@tonic-gate 	return (GLD_SUCCESS);
2297*7c478bd9Sstevel@tonic-gate }
2298*7c478bd9Sstevel@tonic-gate 
2299*7c478bd9Sstevel@tonic-gate /*
2300*7c478bd9Sstevel@tonic-gate  * gld_intr (macinfo)
2301*7c478bd9Sstevel@tonic-gate  */
2302*7c478bd9Sstevel@tonic-gate uint_t
2303*7c478bd9Sstevel@tonic-gate gld_intr(gld_mac_info_t *macinfo)
2304*7c478bd9Sstevel@tonic-gate {
2305*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
2306*7c478bd9Sstevel@tonic-gate 
2307*7c478bd9Sstevel@tonic-gate 	if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY))
2308*7c478bd9Sstevel@tonic-gate 		return (DDI_INTR_UNCLAIMED);
2309*7c478bd9Sstevel@tonic-gate 
2310*7c478bd9Sstevel@tonic-gate 	return ((*macinfo->gldm_intr)(macinfo));
2311*7c478bd9Sstevel@tonic-gate }
2312*7c478bd9Sstevel@tonic-gate 
2313*7c478bd9Sstevel@tonic-gate /*
2314*7c478bd9Sstevel@tonic-gate  * gld_sched (macinfo)
2315*7c478bd9Sstevel@tonic-gate  *
2316*7c478bd9Sstevel@tonic-gate  * This routine scans the streams that refer to a specific macinfo
2317*7c478bd9Sstevel@tonic-gate  * structure and causes the STREAMS scheduler to try to run them if
2318*7c478bd9Sstevel@tonic-gate  * they are marked as waiting for the transmit buffer.
2319*7c478bd9Sstevel@tonic-gate  */
2320*7c478bd9Sstevel@tonic-gate void
2321*7c478bd9Sstevel@tonic-gate gld_sched(gld_mac_info_t *macinfo)
2322*7c478bd9Sstevel@tonic-gate {
2323*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
2324*7c478bd9Sstevel@tonic-gate 	gld_t *gld;
2325*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
2326*7c478bd9Sstevel@tonic-gate 	int i;
2327*7c478bd9Sstevel@tonic-gate 
2328*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
2329*7c478bd9Sstevel@tonic-gate 
2330*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
2331*7c478bd9Sstevel@tonic-gate 
2332*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
2333*7c478bd9Sstevel@tonic-gate 		/* We're probably being called from a leftover interrupt */
2334*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
2335*7c478bd9Sstevel@tonic-gate 		return;
2336*7c478bd9Sstevel@tonic-gate 	}
2337*7c478bd9Sstevel@tonic-gate 
2338*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
2339*7c478bd9Sstevel@tonic-gate 
2340*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < VLAN_HASHSZ; i++) {
2341*7c478bd9Sstevel@tonic-gate 		for (vlan = mac_pvt->vlan_hash[i];
2342*7c478bd9Sstevel@tonic-gate 		    vlan != NULL; vlan = vlan->gldv_next) {
2343*7c478bd9Sstevel@tonic-gate 			for (gld = vlan->gldv_str_next;
2344*7c478bd9Sstevel@tonic-gate 			    gld != (gld_t *)&vlan->gldv_str_next;
2345*7c478bd9Sstevel@tonic-gate 			    gld = gld->gld_next) {
2346*7c478bd9Sstevel@tonic-gate 				ASSERT(gld->gld_mac_info == macinfo);
2347*7c478bd9Sstevel@tonic-gate 				gld->gld_sched_ran = B_TRUE;
2348*7c478bd9Sstevel@tonic-gate 				membar_enter();
2349*7c478bd9Sstevel@tonic-gate 				if (gld->gld_xwait) {
2350*7c478bd9Sstevel@tonic-gate 					gld->gld_xwait = B_FALSE;
2351*7c478bd9Sstevel@tonic-gate 					qenable(WR(gld->gld_qptr));
2352*7c478bd9Sstevel@tonic-gate 				}
2353*7c478bd9Sstevel@tonic-gate 			}
2354*7c478bd9Sstevel@tonic-gate 		}
2355*7c478bd9Sstevel@tonic-gate 	}
2356*7c478bd9Sstevel@tonic-gate 
2357*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
2358*7c478bd9Sstevel@tonic-gate }
2359*7c478bd9Sstevel@tonic-gate 
2360*7c478bd9Sstevel@tonic-gate /*
2361*7c478bd9Sstevel@tonic-gate  * gld_precv (macinfo, mp)
2362*7c478bd9Sstevel@tonic-gate  * called from gld_start to loopback a packet when in promiscuous mode
2363*7c478bd9Sstevel@tonic-gate  */
2364*7c478bd9Sstevel@tonic-gate static void
2365*7c478bd9Sstevel@tonic-gate gld_precv(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp)
2366*7c478bd9Sstevel@tonic-gate {
2367*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
2368*7c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
2369*7c478bd9Sstevel@tonic-gate 	pktinfo_t pktinfo;
2370*7c478bd9Sstevel@tonic-gate 
2371*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
2372*7c478bd9Sstevel@tonic-gate 
2373*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
2374*7c478bd9Sstevel@tonic-gate 	ifp = mac_pvt->interfacep;
2375*7c478bd9Sstevel@tonic-gate 
2376*7c478bd9Sstevel@tonic-gate 	/*
2377*7c478bd9Sstevel@tonic-gate 	 * call the media specific packet interpreter routine
2378*7c478bd9Sstevel@tonic-gate 	 */
2379*7c478bd9Sstevel@tonic-gate 	if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RXLOOP) != 0) {
2380*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2381*7c478bd9Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_rcvbadinterp, 1);
2382*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2383*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
2384*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2385*7c478bd9Sstevel@tonic-gate 			    "gld_precv: interpreter failed");
2386*7c478bd9Sstevel@tonic-gate #endif
2387*7c478bd9Sstevel@tonic-gate 		return;
2388*7c478bd9Sstevel@tonic-gate 	}
2389*7c478bd9Sstevel@tonic-gate 
2390*7c478bd9Sstevel@tonic-gate 	gld_sendup(macinfo, vlan, &pktinfo, mp, gld_paccept);
2391*7c478bd9Sstevel@tonic-gate }
2392*7c478bd9Sstevel@tonic-gate 
2393*7c478bd9Sstevel@tonic-gate /*
2394*7c478bd9Sstevel@tonic-gate  * called from gld_start_mdt to loopback packet(s) when in promiscuous mode
2395*7c478bd9Sstevel@tonic-gate  */
2396*7c478bd9Sstevel@tonic-gate static void
2397*7c478bd9Sstevel@tonic-gate gld_precv_mdt(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp,
2398*7c478bd9Sstevel@tonic-gate     pdesc_t *dl_pkt, pktinfo_t *pktinfo)
2399*7c478bd9Sstevel@tonic-gate {
2400*7c478bd9Sstevel@tonic-gate 	mblk_t *adjmp;
2401*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
2402*7c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp = mac_pvt->interfacep;
2403*7c478bd9Sstevel@tonic-gate 
2404*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
2405*7c478bd9Sstevel@tonic-gate 
2406*7c478bd9Sstevel@tonic-gate 	/*
2407*7c478bd9Sstevel@tonic-gate 	 * Get source/destination.
2408*7c478bd9Sstevel@tonic-gate 	 */
2409*7c478bd9Sstevel@tonic-gate 	(void) (*ifp->interpreter_mdt)(macinfo, mp, NULL, pktinfo,
2410*7c478bd9Sstevel@tonic-gate 	    GLD_MDT_RXLOOP);
2411*7c478bd9Sstevel@tonic-gate 	if ((adjmp = mmd_transform(dl_pkt)) != NULL)
2412*7c478bd9Sstevel@tonic-gate 		gld_sendup(macinfo, vlan, pktinfo, adjmp, gld_paccept);
2413*7c478bd9Sstevel@tonic-gate }
2414*7c478bd9Sstevel@tonic-gate 
2415*7c478bd9Sstevel@tonic-gate /*
2416*7c478bd9Sstevel@tonic-gate  * gld_recv (macinfo, mp)
2417*7c478bd9Sstevel@tonic-gate  * called with an mac-level packet in a mblock; take the maclock,
2418*7c478bd9Sstevel@tonic-gate  * try the ip4q and ip6q hack, and otherwise call gld_sendup.
2419*7c478bd9Sstevel@tonic-gate  *
2420*7c478bd9Sstevel@tonic-gate  * V0 drivers already are holding the mutex when they call us.
2421*7c478bd9Sstevel@tonic-gate  */
2422*7c478bd9Sstevel@tonic-gate void
2423*7c478bd9Sstevel@tonic-gate gld_recv(gld_mac_info_t *macinfo, mblk_t *mp)
2424*7c478bd9Sstevel@tonic-gate {
2425*7c478bd9Sstevel@tonic-gate 	gld_recv_tagged(macinfo, mp, VLAN_VTAG_NONE);
2426*7c478bd9Sstevel@tonic-gate }
2427*7c478bd9Sstevel@tonic-gate 
2428*7c478bd9Sstevel@tonic-gate void
2429*7c478bd9Sstevel@tonic-gate gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
2430*7c478bd9Sstevel@tonic-gate {
2431*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
2432*7c478bd9Sstevel@tonic-gate 	char pbuf[3*GLD_MAX_ADDRLEN];
2433*7c478bd9Sstevel@tonic-gate 	pktinfo_t pktinfo;
2434*7c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
2435*7c478bd9Sstevel@tonic-gate 	queue_t *ipq = NULL;
2436*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
2437*7c478bd9Sstevel@tonic-gate 	uint32_t vid;
2438*7c478bd9Sstevel@tonic-gate 
2439*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
2440*7c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_datap->db_ref);
2441*7c478bd9Sstevel@tonic-gate 
2442*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_READER);
2443*7c478bd9Sstevel@tonic-gate 
2444*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
2445*7c478bd9Sstevel@tonic-gate 		/* We're probably being called from a leftover interrupt */
2446*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2447*7c478bd9Sstevel@tonic-gate 		goto done;
2448*7c478bd9Sstevel@tonic-gate 	}
2449*7c478bd9Sstevel@tonic-gate 
2450*7c478bd9Sstevel@tonic-gate 	vid = GLD_VTAG_VID(vtag);
2451*7c478bd9Sstevel@tonic-gate 	if ((vlan = gld_find_vlan(macinfo, vid)) == NULL) {
2452*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2453*7c478bd9Sstevel@tonic-gate 		goto done;
2454*7c478bd9Sstevel@tonic-gate 	}
2455*7c478bd9Sstevel@tonic-gate 
2456*7c478bd9Sstevel@tonic-gate 	/*
2457*7c478bd9Sstevel@tonic-gate 	 * Check whether underlying media code supports the IPQ hack,
2458*7c478bd9Sstevel@tonic-gate 	 * and if so, whether the interpreter can quickly parse the
2459*7c478bd9Sstevel@tonic-gate 	 * packet to get some relevant parameters.
2460*7c478bd9Sstevel@tonic-gate 	 */
2461*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
2462*7c478bd9Sstevel@tonic-gate 	ifp = mac_pvt->interfacep;
2463*7c478bd9Sstevel@tonic-gate 	if (((*ifp->interpreter)(macinfo, mp, &pktinfo,
2464*7c478bd9Sstevel@tonic-gate 	    GLD_RXQUICK) == 0) && (vlan->gldv_ipq_flags == 0)) {
2465*7c478bd9Sstevel@tonic-gate 		switch (pktinfo.ethertype) {
2466*7c478bd9Sstevel@tonic-gate 		case ETHERTYPE_IP:
2467*7c478bd9Sstevel@tonic-gate 			ipq = vlan->gldv_ipq;
2468*7c478bd9Sstevel@tonic-gate 			break;
2469*7c478bd9Sstevel@tonic-gate 		case ETHERTYPE_IPV6:
2470*7c478bd9Sstevel@tonic-gate 			ipq = vlan->gldv_ipv6q;
2471*7c478bd9Sstevel@tonic-gate 			break;
2472*7c478bd9Sstevel@tonic-gate 		}
2473*7c478bd9Sstevel@tonic-gate 	}
2474*7c478bd9Sstevel@tonic-gate 
2475*7c478bd9Sstevel@tonic-gate 	BUMP(vlan->gldv_stats->glds_bytercv64, pktinfo.pktLen);
2476*7c478bd9Sstevel@tonic-gate 	BUMP(vlan->gldv_stats->glds_pktrcv64, 1);
2477*7c478bd9Sstevel@tonic-gate 
2478*7c478bd9Sstevel@tonic-gate 	/*
2479*7c478bd9Sstevel@tonic-gate 	 * Special case for IP; we can simply do the putnext here, if:
2480*7c478bd9Sstevel@tonic-gate 	 * o ipq != NULL, and therefore:
2481*7c478bd9Sstevel@tonic-gate 	 * - the device type supports IPQ (ethernet and IPoIB);
2482*7c478bd9Sstevel@tonic-gate 	 * - the interpreter could quickly parse the packet;
2483*7c478bd9Sstevel@tonic-gate 	 * - there are no PROMISC_SAP streams (on this VLAN);
2484*7c478bd9Sstevel@tonic-gate 	 * - there is one, and only one, IP stream bound (to this VLAN);
2485*7c478bd9Sstevel@tonic-gate 	 * - that stream is a "fastpath" stream;
2486*7c478bd9Sstevel@tonic-gate 	 * - the packet is of type ETHERTYPE_IP or ETHERTYPE_IPV6
2487*7c478bd9Sstevel@tonic-gate 	 *
2488*7c478bd9Sstevel@tonic-gate 	 * o the packet is specifically for me, and therefore:
2489*7c478bd9Sstevel@tonic-gate 	 * - the packet is not multicast or broadcast (fastpath only
2490*7c478bd9Sstevel@tonic-gate 	 *   wants unicast packets).
2491*7c478bd9Sstevel@tonic-gate 	 *
2492*7c478bd9Sstevel@tonic-gate 	 * o the stream is not asserting flow control.
2493*7c478bd9Sstevel@tonic-gate 	 */
2494*7c478bd9Sstevel@tonic-gate 	if (ipq != NULL &&
2495*7c478bd9Sstevel@tonic-gate 	    pktinfo.isForMe &&
2496*7c478bd9Sstevel@tonic-gate 	    canputnext(ipq)) {
2497*7c478bd9Sstevel@tonic-gate 		/*
2498*7c478bd9Sstevel@tonic-gate 		 * Skip the mac header. We know there is no LLC1/SNAP header
2499*7c478bd9Sstevel@tonic-gate 		 * in this packet
2500*7c478bd9Sstevel@tonic-gate 		 */
2501*7c478bd9Sstevel@tonic-gate 		mp->b_rptr += pktinfo.macLen;
2502*7c478bd9Sstevel@tonic-gate 		putnext(ipq, mp);
2503*7c478bd9Sstevel@tonic-gate 		goto done;
2504*7c478bd9Sstevel@tonic-gate 	}
2505*7c478bd9Sstevel@tonic-gate 
2506*7c478bd9Sstevel@tonic-gate 	/*
2507*7c478bd9Sstevel@tonic-gate 	 * call the media specific packet interpreter routine
2508*7c478bd9Sstevel@tonic-gate 	 */
2509*7c478bd9Sstevel@tonic-gate 	if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RX) != 0) {
2510*7c478bd9Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_rcvbadinterp, 1);
2511*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2512*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
2513*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2514*7c478bd9Sstevel@tonic-gate 			    "gld_recv_tagged: interpreter failed");
2515*7c478bd9Sstevel@tonic-gate #endif
2516*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2517*7c478bd9Sstevel@tonic-gate 		goto done;
2518*7c478bd9Sstevel@tonic-gate 	}
2519*7c478bd9Sstevel@tonic-gate 
2520*7c478bd9Sstevel@tonic-gate 	/*
2521*7c478bd9Sstevel@tonic-gate 	 * This is safe even if vtag is VLAN_VTAG_NONE
2522*7c478bd9Sstevel@tonic-gate 	 */
2523*7c478bd9Sstevel@tonic-gate 
2524*7c478bd9Sstevel@tonic-gate 	pktinfo.vid = vid;
2525*7c478bd9Sstevel@tonic-gate 	pktinfo.cfi = GLD_VTAG_CFI(vtag);
2526*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2527*7c478bd9Sstevel@tonic-gate 	if (pktinfo.cfi != VLAN_CFI_ETHER)
2528*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_WARN, "gld_recv_tagged: non-ETHER CFI");
2529*7c478bd9Sstevel@tonic-gate #endif
2530*7c478bd9Sstevel@tonic-gate 	pktinfo.user_pri = GLD_VTAG_PRI(vtag);
2531*7c478bd9Sstevel@tonic-gate 
2532*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2533*7c478bd9Sstevel@tonic-gate 	if ((gld_debug & GLDRECV) &&
2534*7c478bd9Sstevel@tonic-gate 	    (!(gld_debug & GLDNOBR) ||
2535*7c478bd9Sstevel@tonic-gate 	    (!pktinfo.isBroadcast && !pktinfo.isMulticast))) {
2536*7c478bd9Sstevel@tonic-gate 		char pbuf2[3*GLD_MAX_ADDRLEN];
2537*7c478bd9Sstevel@tonic-gate 
2538*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "gld_recv_tagged: machdr=<%s -> %s>\n",
2539*7c478bd9Sstevel@tonic-gate 		    gld_macaddr_sprintf(pbuf, pktinfo.shost,
2540*7c478bd9Sstevel@tonic-gate 		    macinfo->gldm_addrlen), gld_macaddr_sprintf(pbuf2,
2541*7c478bd9Sstevel@tonic-gate 		    pktinfo.dhost, macinfo->gldm_addrlen));
2542*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "gld_recv_tagged: VlanId %d UserPri %d\n",
2543*7c478bd9Sstevel@tonic-gate 		    pktinfo.vid,
2544*7c478bd9Sstevel@tonic-gate 		    pktinfo.user_pri);
2545*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_CONT, "gld_recv_tagged: ethertype: %4x Len: %4d "
2546*7c478bd9Sstevel@tonic-gate 		    "Hdr: %d,%d isMulticast: %s\n",
2547*7c478bd9Sstevel@tonic-gate 		    pktinfo.ethertype,
2548*7c478bd9Sstevel@tonic-gate 		    pktinfo.pktLen,
2549*7c478bd9Sstevel@tonic-gate 		    pktinfo.macLen,
2550*7c478bd9Sstevel@tonic-gate 		    pktinfo.hdrLen,
2551*7c478bd9Sstevel@tonic-gate 		    pktinfo.isMulticast ? "Y" : "N");
2552*7c478bd9Sstevel@tonic-gate 	}
2553*7c478bd9Sstevel@tonic-gate #endif
2554*7c478bd9Sstevel@tonic-gate 
2555*7c478bd9Sstevel@tonic-gate 	gld_sendup(macinfo, vlan, &pktinfo, mp, gld_accept);
2556*7c478bd9Sstevel@tonic-gate 
2557*7c478bd9Sstevel@tonic-gate done:
2558*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
2559*7c478bd9Sstevel@tonic-gate }
2560*7c478bd9Sstevel@tonic-gate 
2561*7c478bd9Sstevel@tonic-gate /* =================================================================== */
2562*7c478bd9Sstevel@tonic-gate /* receive group: called from gld_recv and gld_precv* with maclock held */
2563*7c478bd9Sstevel@tonic-gate /* =================================================================== */
2564*7c478bd9Sstevel@tonic-gate 
2565*7c478bd9Sstevel@tonic-gate /*
2566*7c478bd9Sstevel@tonic-gate  * gld_sendup (macinfo, mp)
2567*7c478bd9Sstevel@tonic-gate  * called with an ethernet packet in a mblock; must decide whether
2568*7c478bd9Sstevel@tonic-gate  * packet is for us and which streams to queue it to.
2569*7c478bd9Sstevel@tonic-gate  */
2570*7c478bd9Sstevel@tonic-gate static void
2571*7c478bd9Sstevel@tonic-gate gld_sendup(gld_mac_info_t *macinfo, gld_vlan_t *vlan, pktinfo_t *pktinfo,
2572*7c478bd9Sstevel@tonic-gate     mblk_t *mp, int (*acceptfunc)())
2573*7c478bd9Sstevel@tonic-gate {
2574*7c478bd9Sstevel@tonic-gate 	gld_t *gld;
2575*7c478bd9Sstevel@tonic-gate 	gld_t *fgld = NULL;
2576*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
2577*7c478bd9Sstevel@tonic-gate 	void (*send)(queue_t *qp, mblk_t *mp);
2578*7c478bd9Sstevel@tonic-gate 	int (*cansend)(queue_t *qp);
2579*7c478bd9Sstevel@tonic-gate 
2580*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2581*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
2582*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_sendup(%p, %p)", (void *)mp,
2583*7c478bd9Sstevel@tonic-gate 		    (void *)macinfo);
2584*7c478bd9Sstevel@tonic-gate #endif
2585*7c478bd9Sstevel@tonic-gate 
2586*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
2587*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
2588*7c478bd9Sstevel@tonic-gate 	ASSERT(vlan != NULL);
2589*7c478bd9Sstevel@tonic-gate 	ASSERT(pktinfo != NULL);
2590*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(macinfo));
2591*7c478bd9Sstevel@tonic-gate 
2592*7c478bd9Sstevel@tonic-gate 	/*
2593*7c478bd9Sstevel@tonic-gate 	 * The "fast" in "GLDOPT_FAST_RECV" refers to the speed at which
2594*7c478bd9Sstevel@tonic-gate 	 * gld_recv returns to the caller's interrupt routine.  The total
2595*7c478bd9Sstevel@tonic-gate 	 * network throughput would normally be lower when selecting this
2596*7c478bd9Sstevel@tonic-gate 	 * option, because we putq the messages and process them later,
2597*7c478bd9Sstevel@tonic-gate 	 * instead of sending them with putnext now.  Some time critical
2598*7c478bd9Sstevel@tonic-gate 	 * device might need this, so it's here but undocumented.
2599*7c478bd9Sstevel@tonic-gate 	 */
2600*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_options & GLDOPT_FAST_RECV) {
2601*7c478bd9Sstevel@tonic-gate 		send = (void (*)(queue_t *, mblk_t *))putq;
2602*7c478bd9Sstevel@tonic-gate 		cansend = canput;
2603*7c478bd9Sstevel@tonic-gate 	} else {
2604*7c478bd9Sstevel@tonic-gate 		send = (void (*)(queue_t *, mblk_t *))putnext;
2605*7c478bd9Sstevel@tonic-gate 		cansend = canputnext;
2606*7c478bd9Sstevel@tonic-gate 	}
2607*7c478bd9Sstevel@tonic-gate 
2608*7c478bd9Sstevel@tonic-gate 	/*
2609*7c478bd9Sstevel@tonic-gate 	 * Search all the streams attached to this macinfo looking for
2610*7c478bd9Sstevel@tonic-gate 	 * those eligible to receive the present packet.
2611*7c478bd9Sstevel@tonic-gate 	 */
2612*7c478bd9Sstevel@tonic-gate 	for (gld = vlan->gldv_str_next;
2613*7c478bd9Sstevel@tonic-gate 	    gld != (gld_t *)&vlan->gldv_str_next; gld = gld->gld_next) {
2614*7c478bd9Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
2615*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_sendup: SAP: %4x QPTR: %p QSTATE: %s",
2616*7c478bd9Sstevel@tonic-gate 		    gld->gld_sap, (void *)gld->gld_qptr,
2617*7c478bd9Sstevel@tonic-gate 		    gld->gld_state == DL_IDLE ? "IDLE": "NOT IDLE");
2618*7c478bd9Sstevel@tonic-gate #endif
2619*7c478bd9Sstevel@tonic-gate 		ASSERT(gld->gld_qptr != NULL);
2620*7c478bd9Sstevel@tonic-gate 		ASSERT(gld->gld_state == DL_IDLE ||
2621*7c478bd9Sstevel@tonic-gate 		    gld->gld_state == DL_UNBOUND);
2622*7c478bd9Sstevel@tonic-gate 		ASSERT(gld->gld_mac_info == macinfo);
2623*7c478bd9Sstevel@tonic-gate 		ASSERT(gld->gld_vlan == vlan);
2624*7c478bd9Sstevel@tonic-gate 
2625*7c478bd9Sstevel@tonic-gate 		if (gld->gld_state != DL_IDLE)
2626*7c478bd9Sstevel@tonic-gate 			continue;	/* not eligible to receive */
2627*7c478bd9Sstevel@tonic-gate 		if (gld->gld_flags & GLD_STR_CLOSING)
2628*7c478bd9Sstevel@tonic-gate 			continue;	/* not eligible to receive */
2629*7c478bd9Sstevel@tonic-gate 
2630*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2631*7c478bd9Sstevel@tonic-gate 		if ((gld_debug & GLDRECV) &&
2632*7c478bd9Sstevel@tonic-gate 		    (!(gld_debug & GLDNOBR) ||
2633*7c478bd9Sstevel@tonic-gate 		    (!pktinfo->isBroadcast && !pktinfo->isMulticast)))
2634*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE,
2635*7c478bd9Sstevel@tonic-gate 			    "gld_sendup: queue sap: %4x promis: %s %s %s",
2636*7c478bd9Sstevel@tonic-gate 			    gld->gld_sap,
2637*7c478bd9Sstevel@tonic-gate 			    gld->gld_flags & GLD_PROM_PHYS ? "phys " : "     ",
2638*7c478bd9Sstevel@tonic-gate 			    gld->gld_flags & GLD_PROM_SAP  ? "sap  " : "     ",
2639*7c478bd9Sstevel@tonic-gate 			    gld->gld_flags & GLD_PROM_MULT ? "multi" : "     ");
2640*7c478bd9Sstevel@tonic-gate #endif
2641*7c478bd9Sstevel@tonic-gate 
2642*7c478bd9Sstevel@tonic-gate 		/*
2643*7c478bd9Sstevel@tonic-gate 		 * The accept function differs depending on whether this is
2644*7c478bd9Sstevel@tonic-gate 		 * a packet that we received from the wire or a loopback.
2645*7c478bd9Sstevel@tonic-gate 		 */
2646*7c478bd9Sstevel@tonic-gate 		if ((*acceptfunc)(gld, pktinfo)) {
2647*7c478bd9Sstevel@tonic-gate 			/* sap matches */
2648*7c478bd9Sstevel@tonic-gate 			pktinfo->wasAccepted = 1;	/* known protocol */
2649*7c478bd9Sstevel@tonic-gate 
2650*7c478bd9Sstevel@tonic-gate 			if (!(*cansend)(gld->gld_qptr)) {
2651*7c478bd9Sstevel@tonic-gate 				/*
2652*7c478bd9Sstevel@tonic-gate 				 * Upper stream is not accepting messages, i.e.
2653*7c478bd9Sstevel@tonic-gate 				 * it is flow controlled, therefore we will
2654*7c478bd9Sstevel@tonic-gate 				 * forgo sending the message up this stream.
2655*7c478bd9Sstevel@tonic-gate 				 */
2656*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2657*7c478bd9Sstevel@tonic-gate 				if (gld_debug & GLDETRACE)
2658*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
2659*7c478bd9Sstevel@tonic-gate 					    "gld_sendup: canput failed");
2660*7c478bd9Sstevel@tonic-gate #endif
2661*7c478bd9Sstevel@tonic-gate 				BUMP(vlan->gldv_stats->glds_blocked, 1);
2662*7c478bd9Sstevel@tonic-gate 				qenable(gld->gld_qptr);
2663*7c478bd9Sstevel@tonic-gate 				continue;
2664*7c478bd9Sstevel@tonic-gate 			}
2665*7c478bd9Sstevel@tonic-gate 
2666*7c478bd9Sstevel@tonic-gate 			/*
2667*7c478bd9Sstevel@tonic-gate 			 * we are trying to avoid an extra dumpmsg() here.
2668*7c478bd9Sstevel@tonic-gate 			 * If this is the first eligible queue, remember the
2669*7c478bd9Sstevel@tonic-gate 			 * queue and send up the message after the loop.
2670*7c478bd9Sstevel@tonic-gate 			 */
2671*7c478bd9Sstevel@tonic-gate 			if (!fgld) {
2672*7c478bd9Sstevel@tonic-gate 				fgld = gld;
2673*7c478bd9Sstevel@tonic-gate 				continue;
2674*7c478bd9Sstevel@tonic-gate 			}
2675*7c478bd9Sstevel@tonic-gate 
2676*7c478bd9Sstevel@tonic-gate 			/* duplicate the packet for this stream */
2677*7c478bd9Sstevel@tonic-gate 			nmp = dupmsg(mp);
2678*7c478bd9Sstevel@tonic-gate 			if (nmp == NULL) {
2679*7c478bd9Sstevel@tonic-gate 				BUMP(vlan->gldv_stats->glds_gldnorcvbuf, 1);
2680*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2681*7c478bd9Sstevel@tonic-gate 				if (gld_debug & GLDERRS)
2682*7c478bd9Sstevel@tonic-gate 					cmn_err(CE_WARN,
2683*7c478bd9Sstevel@tonic-gate 					    "gld_sendup: dupmsg failed");
2684*7c478bd9Sstevel@tonic-gate #endif
2685*7c478bd9Sstevel@tonic-gate 				break;	/* couldn't get resources; drop it */
2686*7c478bd9Sstevel@tonic-gate 			}
2687*7c478bd9Sstevel@tonic-gate 			/* pass the message up the stream */
2688*7c478bd9Sstevel@tonic-gate 			gld_passon(gld, nmp, pktinfo, send);
2689*7c478bd9Sstevel@tonic-gate 		}
2690*7c478bd9Sstevel@tonic-gate 	}
2691*7c478bd9Sstevel@tonic-gate 
2692*7c478bd9Sstevel@tonic-gate 	ASSERT(mp);
2693*7c478bd9Sstevel@tonic-gate 	/* send the original dup of the packet up the first stream found */
2694*7c478bd9Sstevel@tonic-gate 	if (fgld)
2695*7c478bd9Sstevel@tonic-gate 		gld_passon(fgld, mp, pktinfo, send);
2696*7c478bd9Sstevel@tonic-gate 	else
2697*7c478bd9Sstevel@tonic-gate 		freemsg(mp);	/* no streams matched */
2698*7c478bd9Sstevel@tonic-gate 
2699*7c478bd9Sstevel@tonic-gate 	/* We do not count looped back packets */
2700*7c478bd9Sstevel@tonic-gate 	if (acceptfunc == gld_paccept)
2701*7c478bd9Sstevel@tonic-gate 		return;		/* transmit loopback case */
2702*7c478bd9Sstevel@tonic-gate 
2703*7c478bd9Sstevel@tonic-gate 	if (pktinfo->isBroadcast)
2704*7c478bd9Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_brdcstrcv, 1);
2705*7c478bd9Sstevel@tonic-gate 	else if (pktinfo->isMulticast)
2706*7c478bd9Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_multircv, 1);
2707*7c478bd9Sstevel@tonic-gate 
2708*7c478bd9Sstevel@tonic-gate 	/* No stream accepted this packet */
2709*7c478bd9Sstevel@tonic-gate 	if (!pktinfo->wasAccepted)
2710*7c478bd9Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_unknowns, 1);
2711*7c478bd9Sstevel@tonic-gate }
2712*7c478bd9Sstevel@tonic-gate 
2713*7c478bd9Sstevel@tonic-gate /*
2714*7c478bd9Sstevel@tonic-gate  * A packet matches a stream if:
2715*7c478bd9Sstevel@tonic-gate  *     the stream accepts EtherType encoded packets and the type matches
2716*7c478bd9Sstevel@tonic-gate  *  or the stream accepts LLC packets and the packet is an LLC packet
2717*7c478bd9Sstevel@tonic-gate  */
2718*7c478bd9Sstevel@tonic-gate #define	MATCH(stream, pktinfo) \
2719*7c478bd9Sstevel@tonic-gate 	((stream->gld_ethertype && stream->gld_sap == pktinfo->ethertype) || \
2720*7c478bd9Sstevel@tonic-gate 	(!stream->gld_ethertype && pktinfo->isLLC))
2721*7c478bd9Sstevel@tonic-gate 
2722*7c478bd9Sstevel@tonic-gate /*
2723*7c478bd9Sstevel@tonic-gate  * This function validates a packet for sending up a particular
2724*7c478bd9Sstevel@tonic-gate  * stream. The message header has been parsed and its characteristic
2725*7c478bd9Sstevel@tonic-gate  * are recorded in the pktinfo data structure. The streams stack info
2726*7c478bd9Sstevel@tonic-gate  * are presented in gld data structures.
2727*7c478bd9Sstevel@tonic-gate  */
2728*7c478bd9Sstevel@tonic-gate static int
2729*7c478bd9Sstevel@tonic-gate gld_accept(gld_t *gld, pktinfo_t *pktinfo)
2730*7c478bd9Sstevel@tonic-gate {
2731*7c478bd9Sstevel@tonic-gate 	/*
2732*7c478bd9Sstevel@tonic-gate 	 * if there is no match do not bother checking further.
2733*7c478bd9Sstevel@tonic-gate 	 */
2734*7c478bd9Sstevel@tonic-gate 	if (!MATCH(gld, pktinfo) && !(gld->gld_flags & GLD_PROM_SAP))
2735*7c478bd9Sstevel@tonic-gate 		return (0);
2736*7c478bd9Sstevel@tonic-gate 
2737*7c478bd9Sstevel@tonic-gate 	/*
2738*7c478bd9Sstevel@tonic-gate 	 * We don't accept any packet from the hardware if we originated it.
2739*7c478bd9Sstevel@tonic-gate 	 * (Contrast gld_paccept, the send-loopback accept function.)
2740*7c478bd9Sstevel@tonic-gate 	 */
2741*7c478bd9Sstevel@tonic-gate 	if (pktinfo->isLooped)
2742*7c478bd9Sstevel@tonic-gate 		return (0);
2743*7c478bd9Sstevel@tonic-gate 
2744*7c478bd9Sstevel@tonic-gate 	/*
2745*7c478bd9Sstevel@tonic-gate 	 * If the packet is broadcast or sent to us directly we will accept it.
2746*7c478bd9Sstevel@tonic-gate 	 * Also we will accept multicast packets requested by the stream.
2747*7c478bd9Sstevel@tonic-gate 	 */
2748*7c478bd9Sstevel@tonic-gate 	if (pktinfo->isForMe || pktinfo->isBroadcast ||
2749*7c478bd9Sstevel@tonic-gate 	    gld_mcmatch(gld, pktinfo))
2750*7c478bd9Sstevel@tonic-gate 		return (1);
2751*7c478bd9Sstevel@tonic-gate 
2752*7c478bd9Sstevel@tonic-gate 	/*
2753*7c478bd9Sstevel@tonic-gate 	 * Finally, accept anything else if we're in promiscuous mode
2754*7c478bd9Sstevel@tonic-gate 	 */
2755*7c478bd9Sstevel@tonic-gate 	if (gld->gld_flags & GLD_PROM_PHYS)
2756*7c478bd9Sstevel@tonic-gate 		return (1);
2757*7c478bd9Sstevel@tonic-gate 
2758*7c478bd9Sstevel@tonic-gate 	return (0);
2759*7c478bd9Sstevel@tonic-gate }
2760*7c478bd9Sstevel@tonic-gate 
2761*7c478bd9Sstevel@tonic-gate /*
2762*7c478bd9Sstevel@tonic-gate  * Return TRUE if the given multicast address is one
2763*7c478bd9Sstevel@tonic-gate  * of those that this particular Stream is interested in.
2764*7c478bd9Sstevel@tonic-gate  */
2765*7c478bd9Sstevel@tonic-gate static int
2766*7c478bd9Sstevel@tonic-gate gld_mcmatch(gld_t *gld, pktinfo_t *pktinfo)
2767*7c478bd9Sstevel@tonic-gate {
2768*7c478bd9Sstevel@tonic-gate 	/*
2769*7c478bd9Sstevel@tonic-gate 	 * Return FALSE if not a multicast address.
2770*7c478bd9Sstevel@tonic-gate 	 */
2771*7c478bd9Sstevel@tonic-gate 	if (!pktinfo->isMulticast)
2772*7c478bd9Sstevel@tonic-gate 		return (0);
2773*7c478bd9Sstevel@tonic-gate 
2774*7c478bd9Sstevel@tonic-gate 	/*
2775*7c478bd9Sstevel@tonic-gate 	 * Check if all multicasts have been enabled for this Stream
2776*7c478bd9Sstevel@tonic-gate 	 */
2777*7c478bd9Sstevel@tonic-gate 	if (gld->gld_flags & GLD_PROM_MULT)
2778*7c478bd9Sstevel@tonic-gate 		return (1);
2779*7c478bd9Sstevel@tonic-gate 
2780*7c478bd9Sstevel@tonic-gate 	/*
2781*7c478bd9Sstevel@tonic-gate 	 * Return FALSE if no multicast addresses enabled for this Stream.
2782*7c478bd9Sstevel@tonic-gate 	 */
2783*7c478bd9Sstevel@tonic-gate 	if (!gld->gld_mcast)
2784*7c478bd9Sstevel@tonic-gate 		return (0);
2785*7c478bd9Sstevel@tonic-gate 
2786*7c478bd9Sstevel@tonic-gate 	/*
2787*7c478bd9Sstevel@tonic-gate 	 * Otherwise, look for it in the table.
2788*7c478bd9Sstevel@tonic-gate 	 */
2789*7c478bd9Sstevel@tonic-gate 	return (gld_multicast(pktinfo->dhost, gld));
2790*7c478bd9Sstevel@tonic-gate }
2791*7c478bd9Sstevel@tonic-gate 
2792*7c478bd9Sstevel@tonic-gate /*
2793*7c478bd9Sstevel@tonic-gate  * gld_multicast determines if the address is a multicast address for
2794*7c478bd9Sstevel@tonic-gate  * this stream.
2795*7c478bd9Sstevel@tonic-gate  */
2796*7c478bd9Sstevel@tonic-gate static int
2797*7c478bd9Sstevel@tonic-gate gld_multicast(unsigned char *macaddr, gld_t *gld)
2798*7c478bd9Sstevel@tonic-gate {
2799*7c478bd9Sstevel@tonic-gate 	int i;
2800*7c478bd9Sstevel@tonic-gate 
2801*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD(gld->gld_mac_info));
2802*7c478bd9Sstevel@tonic-gate 
2803*7c478bd9Sstevel@tonic-gate 	if (!gld->gld_mcast)
2804*7c478bd9Sstevel@tonic-gate 		return (0);
2805*7c478bd9Sstevel@tonic-gate 
2806*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < gld->gld_multicnt; i++) {
2807*7c478bd9Sstevel@tonic-gate 		if (gld->gld_mcast[i]) {
2808*7c478bd9Sstevel@tonic-gate 			ASSERT(gld->gld_mcast[i]->gldm_refcnt);
2809*7c478bd9Sstevel@tonic-gate 			if (mac_eq(gld->gld_mcast[i]->gldm_addr, macaddr,
2810*7c478bd9Sstevel@tonic-gate 			    gld->gld_mac_info->gldm_addrlen))
2811*7c478bd9Sstevel@tonic-gate 				return (1);
2812*7c478bd9Sstevel@tonic-gate 		}
2813*7c478bd9Sstevel@tonic-gate 	}
2814*7c478bd9Sstevel@tonic-gate 
2815*7c478bd9Sstevel@tonic-gate 	return (0);
2816*7c478bd9Sstevel@tonic-gate }
2817*7c478bd9Sstevel@tonic-gate 
2818*7c478bd9Sstevel@tonic-gate /*
2819*7c478bd9Sstevel@tonic-gate  * accept function for looped back packets
2820*7c478bd9Sstevel@tonic-gate  */
2821*7c478bd9Sstevel@tonic-gate static int
2822*7c478bd9Sstevel@tonic-gate gld_paccept(gld_t *gld, pktinfo_t *pktinfo)
2823*7c478bd9Sstevel@tonic-gate {
2824*7c478bd9Sstevel@tonic-gate 	return (gld->gld_flags & GLD_PROM_PHYS &&
2825*7c478bd9Sstevel@tonic-gate 	    (MATCH(gld, pktinfo) || gld->gld_flags & GLD_PROM_SAP));
2826*7c478bd9Sstevel@tonic-gate }
2827*7c478bd9Sstevel@tonic-gate 
2828*7c478bd9Sstevel@tonic-gate static void
2829*7c478bd9Sstevel@tonic-gate gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo,
2830*7c478bd9Sstevel@tonic-gate 	void (*send)(queue_t *qp, mblk_t *mp))
2831*7c478bd9Sstevel@tonic-gate {
2832*7c478bd9Sstevel@tonic-gate 	int skiplen;
2833*7c478bd9Sstevel@tonic-gate 
2834*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2835*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
2836*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_passon(%p, %p, %p)", (void *)gld,
2837*7c478bd9Sstevel@tonic-gate 		    (void *)mp, (void *)pktinfo);
2838*7c478bd9Sstevel@tonic-gate 
2839*7c478bd9Sstevel@tonic-gate 	if ((gld_debug & GLDRECV) && (!(gld_debug & GLDNOBR) ||
2840*7c478bd9Sstevel@tonic-gate 	    (!pktinfo->isBroadcast && !pktinfo->isMulticast)))
2841*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_passon: q: %p mblk: %p minor: %d sap: %x",
2842*7c478bd9Sstevel@tonic-gate 		    (void *)gld->gld_qptr->q_next, (void *)mp, gld->gld_minor,
2843*7c478bd9Sstevel@tonic-gate 		    gld->gld_sap);
2844*7c478bd9Sstevel@tonic-gate #endif
2845*7c478bd9Sstevel@tonic-gate 
2846*7c478bd9Sstevel@tonic-gate 	/*
2847*7c478bd9Sstevel@tonic-gate 	 * Figure out how much of the packet header to throw away.
2848*7c478bd9Sstevel@tonic-gate 	 *
2849*7c478bd9Sstevel@tonic-gate 	 * RAW streams expect to see the whole packet.
2850*7c478bd9Sstevel@tonic-gate 	 *
2851*7c478bd9Sstevel@tonic-gate 	 * Other streams expect to see the packet with the MAC header
2852*7c478bd9Sstevel@tonic-gate 	 * removed.
2853*7c478bd9Sstevel@tonic-gate 	 *
2854*7c478bd9Sstevel@tonic-gate 	 * Normal DLPI (non RAW/FAST) streams also want the
2855*7c478bd9Sstevel@tonic-gate 	 * DL_UNITDATA_IND M_PROTO message block prepended to the M_DATA.
2856*7c478bd9Sstevel@tonic-gate 	 */
2857*7c478bd9Sstevel@tonic-gate 	if (gld->gld_flags & GLD_RAW) {
2858*7c478bd9Sstevel@tonic-gate 		skiplen = 0;
2859*7c478bd9Sstevel@tonic-gate 	} else {
2860*7c478bd9Sstevel@tonic-gate 		skiplen = pktinfo->macLen;		/* skip mac header */
2861*7c478bd9Sstevel@tonic-gate 		if (gld->gld_ethertype)
2862*7c478bd9Sstevel@tonic-gate 			skiplen += pktinfo->hdrLen;	/* skip any extra */
2863*7c478bd9Sstevel@tonic-gate 	}
2864*7c478bd9Sstevel@tonic-gate 
2865*7c478bd9Sstevel@tonic-gate 	if (skiplen >= pktinfo->pktLen) {
2866*7c478bd9Sstevel@tonic-gate 		/*
2867*7c478bd9Sstevel@tonic-gate 		 * If the interpreter did its job right, then it cannot be
2868*7c478bd9Sstevel@tonic-gate 		 * asking us to skip more bytes than are in the packet!
2869*7c478bd9Sstevel@tonic-gate 		 * However, there could be zero data bytes left after the
2870*7c478bd9Sstevel@tonic-gate 		 * amount to skip.  DLPI specifies that passed M_DATA blocks
2871*7c478bd9Sstevel@tonic-gate 		 * should contain at least one byte of data, so if we have
2872*7c478bd9Sstevel@tonic-gate 		 * none we just drop it.
2873*7c478bd9Sstevel@tonic-gate 		 */
2874*7c478bd9Sstevel@tonic-gate 		ASSERT(!(skiplen > pktinfo->pktLen));
2875*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2876*7c478bd9Sstevel@tonic-gate 		return;
2877*7c478bd9Sstevel@tonic-gate 	}
2878*7c478bd9Sstevel@tonic-gate 
2879*7c478bd9Sstevel@tonic-gate 	/*
2880*7c478bd9Sstevel@tonic-gate 	 * Skip over the header(s), taking care to possibly handle message
2881*7c478bd9Sstevel@tonic-gate 	 * fragments shorter than the amount we need to skip.  Hopefully
2882*7c478bd9Sstevel@tonic-gate 	 * the driver will put the entire packet, or at least the entire
2883*7c478bd9Sstevel@tonic-gate 	 * header, into a single message block.  But we handle it if not.
2884*7c478bd9Sstevel@tonic-gate 	 */
2885*7c478bd9Sstevel@tonic-gate 	while (skiplen >= MBLKL(mp)) {
2886*7c478bd9Sstevel@tonic-gate 		mblk_t *tmp = mp;
2887*7c478bd9Sstevel@tonic-gate 		skiplen -= MBLKL(mp);
2888*7c478bd9Sstevel@tonic-gate 		mp = mp->b_cont;
2889*7c478bd9Sstevel@tonic-gate 		ASSERT(mp != NULL);	/* because skiplen < pktinfo->pktLen */
2890*7c478bd9Sstevel@tonic-gate 		freeb(tmp);
2891*7c478bd9Sstevel@tonic-gate 	}
2892*7c478bd9Sstevel@tonic-gate 	mp->b_rptr += skiplen;
2893*7c478bd9Sstevel@tonic-gate 
2894*7c478bd9Sstevel@tonic-gate 	/* Add M_PROTO if necessary, and pass upstream */
2895*7c478bd9Sstevel@tonic-gate 	if (((gld->gld_flags & GLD_FAST) && !pktinfo->isMulticast &&
2896*7c478bd9Sstevel@tonic-gate 	    !pktinfo->isBroadcast) || (gld->gld_flags & GLD_RAW)) {
2897*7c478bd9Sstevel@tonic-gate 		/* RAW/FAST: just send up the M_DATA */
2898*7c478bd9Sstevel@tonic-gate 		(*send)(gld->gld_qptr, mp);
2899*7c478bd9Sstevel@tonic-gate 	} else {
2900*7c478bd9Sstevel@tonic-gate 		/* everybody else wants to see a unitdata_ind structure */
2901*7c478bd9Sstevel@tonic-gate 		mp = gld_addudind(gld, mp, pktinfo);
2902*7c478bd9Sstevel@tonic-gate 		if (mp)
2903*7c478bd9Sstevel@tonic-gate 			(*send)(gld->gld_qptr, mp);
2904*7c478bd9Sstevel@tonic-gate 		/* if it failed, gld_addudind already bumped statistic */
2905*7c478bd9Sstevel@tonic-gate 	}
2906*7c478bd9Sstevel@tonic-gate }
2907*7c478bd9Sstevel@tonic-gate 
2908*7c478bd9Sstevel@tonic-gate /*
2909*7c478bd9Sstevel@tonic-gate  * gld_addudind(gld, mp, pktinfo)
2910*7c478bd9Sstevel@tonic-gate  * format a DL_UNITDATA_IND message to be sent upstream to the user
2911*7c478bd9Sstevel@tonic-gate  */
2912*7c478bd9Sstevel@tonic-gate static mblk_t *
2913*7c478bd9Sstevel@tonic-gate gld_addudind(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo)
2914*7c478bd9Sstevel@tonic-gate {
2915*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t		*macinfo = gld->gld_mac_info;
2916*7c478bd9Sstevel@tonic-gate 	gld_vlan_t		*vlan = (gld_vlan_t *)gld->gld_vlan;
2917*7c478bd9Sstevel@tonic-gate 	dl_unitdata_ind_t	*dludindp;
2918*7c478bd9Sstevel@tonic-gate 	mblk_t			*nmp;
2919*7c478bd9Sstevel@tonic-gate 	int			size;
2920*7c478bd9Sstevel@tonic-gate 	int			type;
2921*7c478bd9Sstevel@tonic-gate 
2922*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2923*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
2924*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_addudind(%p, %p, %p)", (void *)gld,
2925*7c478bd9Sstevel@tonic-gate 		    (void *)mp, (void *)pktinfo);
2926*7c478bd9Sstevel@tonic-gate #endif
2927*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
2928*7c478bd9Sstevel@tonic-gate 
2929*7c478bd9Sstevel@tonic-gate 	/*
2930*7c478bd9Sstevel@tonic-gate 	 * Allocate the DL_UNITDATA_IND M_PROTO header, if allocation fails
2931*7c478bd9Sstevel@tonic-gate 	 * might as well discard since we can't go further
2932*7c478bd9Sstevel@tonic-gate 	 */
2933*7c478bd9Sstevel@tonic-gate 	size = sizeof (dl_unitdata_ind_t) +
2934*7c478bd9Sstevel@tonic-gate 	    2 * (macinfo->gldm_addrlen + abs(macinfo->gldm_saplen));
2935*7c478bd9Sstevel@tonic-gate 	if ((nmp = allocb(size, BPRI_MED)) == NULL) {
2936*7c478bd9Sstevel@tonic-gate 		freemsg(mp);
2937*7c478bd9Sstevel@tonic-gate 		BUMP(vlan->gldv_stats->glds_gldnorcvbuf, 1);
2938*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
2939*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
2940*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
2941*7c478bd9Sstevel@tonic-gate 			    "gld_addudind: allocb failed");
2942*7c478bd9Sstevel@tonic-gate #endif
2943*7c478bd9Sstevel@tonic-gate 		return ((mblk_t *)NULL);
2944*7c478bd9Sstevel@tonic-gate 	}
2945*7c478bd9Sstevel@tonic-gate 	DB_TYPE(nmp) = M_PROTO;
2946*7c478bd9Sstevel@tonic-gate 	nmp->b_rptr = nmp->b_datap->db_lim - size;
2947*7c478bd9Sstevel@tonic-gate 
2948*7c478bd9Sstevel@tonic-gate 	type = (gld->gld_ethertype) ? pktinfo->ethertype : 0;
2949*7c478bd9Sstevel@tonic-gate 
2950*7c478bd9Sstevel@tonic-gate 	/*
2951*7c478bd9Sstevel@tonic-gate 	 * now setup the DL_UNITDATA_IND header
2952*7c478bd9Sstevel@tonic-gate 	 *
2953*7c478bd9Sstevel@tonic-gate 	 * XXX This looks broken if the saps aren't two bytes.
2954*7c478bd9Sstevel@tonic-gate 	 */
2955*7c478bd9Sstevel@tonic-gate 	dludindp = (dl_unitdata_ind_t *)nmp->b_rptr;
2956*7c478bd9Sstevel@tonic-gate 	dludindp->dl_primitive = DL_UNITDATA_IND;
2957*7c478bd9Sstevel@tonic-gate 	dludindp->dl_src_addr_length =
2958*7c478bd9Sstevel@tonic-gate 	    dludindp->dl_dest_addr_length = macinfo->gldm_addrlen +
2959*7c478bd9Sstevel@tonic-gate 					abs(macinfo->gldm_saplen);
2960*7c478bd9Sstevel@tonic-gate 	dludindp->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
2961*7c478bd9Sstevel@tonic-gate 	dludindp->dl_src_addr_offset = dludindp->dl_dest_addr_offset +
2962*7c478bd9Sstevel@tonic-gate 					dludindp->dl_dest_addr_length;
2963*7c478bd9Sstevel@tonic-gate 
2964*7c478bd9Sstevel@tonic-gate 	dludindp->dl_group_address = (pktinfo->isMulticast ||
2965*7c478bd9Sstevel@tonic-gate 					pktinfo->isBroadcast);
2966*7c478bd9Sstevel@tonic-gate 
2967*7c478bd9Sstevel@tonic-gate 	nmp->b_wptr = nmp->b_rptr + dludindp->dl_dest_addr_offset;
2968*7c478bd9Sstevel@tonic-gate 
2969*7c478bd9Sstevel@tonic-gate 	mac_copy(pktinfo->dhost, nmp->b_wptr, macinfo->gldm_addrlen);
2970*7c478bd9Sstevel@tonic-gate 	nmp->b_wptr += macinfo->gldm_addrlen;
2971*7c478bd9Sstevel@tonic-gate 
2972*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_saplen == -2);	/* XXX following code assumes */
2973*7c478bd9Sstevel@tonic-gate 	*(ushort_t *)(nmp->b_wptr) = type;
2974*7c478bd9Sstevel@tonic-gate 	nmp->b_wptr += abs(macinfo->gldm_saplen);
2975*7c478bd9Sstevel@tonic-gate 
2976*7c478bd9Sstevel@tonic-gate 	ASSERT(nmp->b_wptr == nmp->b_rptr + dludindp->dl_src_addr_offset);
2977*7c478bd9Sstevel@tonic-gate 
2978*7c478bd9Sstevel@tonic-gate 	mac_copy(pktinfo->shost, nmp->b_wptr, macinfo->gldm_addrlen);
2979*7c478bd9Sstevel@tonic-gate 	nmp->b_wptr += macinfo->gldm_addrlen;
2980*7c478bd9Sstevel@tonic-gate 
2981*7c478bd9Sstevel@tonic-gate 	*(ushort_t *)(nmp->b_wptr) = type;
2982*7c478bd9Sstevel@tonic-gate 	nmp->b_wptr += abs(macinfo->gldm_saplen);
2983*7c478bd9Sstevel@tonic-gate 
2984*7c478bd9Sstevel@tonic-gate 	if (pktinfo->nosource)
2985*7c478bd9Sstevel@tonic-gate 		dludindp->dl_src_addr_offset = dludindp->dl_src_addr_length = 0;
2986*7c478bd9Sstevel@tonic-gate 	linkb(nmp, mp);
2987*7c478bd9Sstevel@tonic-gate 	return (nmp);
2988*7c478bd9Sstevel@tonic-gate }
2989*7c478bd9Sstevel@tonic-gate 
2990*7c478bd9Sstevel@tonic-gate /* ======================================================= */
2991*7c478bd9Sstevel@tonic-gate /* wsrv group: called from wsrv, single threaded per queue */
2992*7c478bd9Sstevel@tonic-gate /* ======================================================= */
2993*7c478bd9Sstevel@tonic-gate 
2994*7c478bd9Sstevel@tonic-gate /*
2995*7c478bd9Sstevel@tonic-gate  * We go to some trouble to avoid taking the same lock during normal
2996*7c478bd9Sstevel@tonic-gate  * transmit processing as we do during normal receive processing.
2997*7c478bd9Sstevel@tonic-gate  *
2998*7c478bd9Sstevel@tonic-gate  * Elements of the per-instance macinfo and per-stream gld_t structures
2999*7c478bd9Sstevel@tonic-gate  * are for the most part protected by the GLDM_LOCK rwlock/mutex.
3000*7c478bd9Sstevel@tonic-gate  * (Elements of the gld_mac_pvt_t structure are considered part of the
3001*7c478bd9Sstevel@tonic-gate  * macinfo structure for purposes of this discussion).
3002*7c478bd9Sstevel@tonic-gate  *
3003*7c478bd9Sstevel@tonic-gate  * However, it is more complicated than that:
3004*7c478bd9Sstevel@tonic-gate  *
3005*7c478bd9Sstevel@tonic-gate  *	Elements of the macinfo structure that are set before the macinfo
3006*7c478bd9Sstevel@tonic-gate  *	structure is added to its device list by gld_register(), and never
3007*7c478bd9Sstevel@tonic-gate  *	thereafter modified, are accessed without requiring taking the lock.
3008*7c478bd9Sstevel@tonic-gate  *	A similar rule applies to those elements of the gld_t structure that
3009*7c478bd9Sstevel@tonic-gate  *	are written by gld_open() before the stream is added to any list.
3010*7c478bd9Sstevel@tonic-gate  *
3011*7c478bd9Sstevel@tonic-gate  *	Most other elements of the macinfo structure may only be read or
3012*7c478bd9Sstevel@tonic-gate  *	written while holding the maclock.
3013*7c478bd9Sstevel@tonic-gate  *
3014*7c478bd9Sstevel@tonic-gate  *	Most writable elements of the gld_t structure are written only
3015*7c478bd9Sstevel@tonic-gate  *	within the single-threaded domain of wsrv() and subsidiaries.
3016*7c478bd9Sstevel@tonic-gate  *	(This domain includes open/close while qprocs are not on.)
3017*7c478bd9Sstevel@tonic-gate  *	The maclock need not be taken while within that domain
3018*7c478bd9Sstevel@tonic-gate  *	simply to read those elements.  Writing to them, even within
3019*7c478bd9Sstevel@tonic-gate  *	that domain, or reading from it outside that domain, requires
3020*7c478bd9Sstevel@tonic-gate  *	holding the maclock.  Exception:  if the stream is not
3021*7c478bd9Sstevel@tonic-gate  *	presently attached to a PPA, there is no associated macinfo,
3022*7c478bd9Sstevel@tonic-gate  *	and no maclock need be taken.
3023*7c478bd9Sstevel@tonic-gate  *
3024*7c478bd9Sstevel@tonic-gate  *	The curr_macaddr element of the mac private structure is also
3025*7c478bd9Sstevel@tonic-gate  *      protected by the GLDM_LOCK rwlock/mutex, like most other members
3026*7c478bd9Sstevel@tonic-gate  *      of that structure. However, there are a few instances in the
3027*7c478bd9Sstevel@tonic-gate  *      transmit path where we choose to forgo lock protection when
3028*7c478bd9Sstevel@tonic-gate  *      reading this variable. This is to avoid lock contention between
3029*7c478bd9Sstevel@tonic-gate  *      threads executing the DL_UNITDATA_REQ case and receive threads.
3030*7c478bd9Sstevel@tonic-gate  *      In doing so we will take a small risk or a few corrupted packets
3031*7c478bd9Sstevel@tonic-gate  *      during the short an rare times when someone is changing the interface's
3032*7c478bd9Sstevel@tonic-gate  *      physical address. We consider the small cost in this rare case to be
3033*7c478bd9Sstevel@tonic-gate  *      worth the benefit of reduced lock contention under normal operating
3034*7c478bd9Sstevel@tonic-gate  *      conditions. The risk/cost is small because:
3035*7c478bd9Sstevel@tonic-gate  *          1. there is no guarantee at this layer of uncorrupted delivery.
3036*7c478bd9Sstevel@tonic-gate  *          2. the physaddr doesn't change very often - no performance hit.
3037*7c478bd9Sstevel@tonic-gate  *          3. if the physaddr changes, other stuff is going to be screwed
3038*7c478bd9Sstevel@tonic-gate  *             up for a while anyway, while other sites refigure ARP, etc.,
3039*7c478bd9Sstevel@tonic-gate  *             so losing a couple of packets is the least of our worries.
3040*7c478bd9Sstevel@tonic-gate  *
3041*7c478bd9Sstevel@tonic-gate  *	The list of streams associated with a macinfo is protected by
3042*7c478bd9Sstevel@tonic-gate  *	two locks:  the per-macinfo maclock, and the per-major-device
3043*7c478bd9Sstevel@tonic-gate  *	gld_devlock.  Both must be held to modify the list, but either
3044*7c478bd9Sstevel@tonic-gate  *	may be held to protect the list during reading/traversing.  This
3045*7c478bd9Sstevel@tonic-gate  *	allows independent locking for multiple instances in the receive
3046*7c478bd9Sstevel@tonic-gate  *	path (using macinfo), while facilitating routines that must search
3047*7c478bd9Sstevel@tonic-gate  *	the entire set of streams associated with a major device, such as
3048*7c478bd9Sstevel@tonic-gate  *	gld_findminor(), gld_finddevinfo(), close().  The "nstreams"
3049*7c478bd9Sstevel@tonic-gate  *	macinfo	element, and the gld_mac_info gld_t element, are similarly
3050*7c478bd9Sstevel@tonic-gate  *	protected, since they change at exactly the same time macinfo
3051*7c478bd9Sstevel@tonic-gate  *	streams list does.
3052*7c478bd9Sstevel@tonic-gate  *
3053*7c478bd9Sstevel@tonic-gate  *	The list of macinfo structures associated with a major device
3054*7c478bd9Sstevel@tonic-gate  *	structure is protected by the gld_devlock, as is the per-major
3055*7c478bd9Sstevel@tonic-gate  *	list of Style 2 streams in the DL_UNATTACHED state.
3056*7c478bd9Sstevel@tonic-gate  *
3057*7c478bd9Sstevel@tonic-gate  *	The list of major devices is kept on a module-global list
3058*7c478bd9Sstevel@tonic-gate  *	gld_device_list, which has its own lock to protect the list.
3059*7c478bd9Sstevel@tonic-gate  *
3060*7c478bd9Sstevel@tonic-gate  *	When it is necessary to hold more than one lock at a time, they
3061*7c478bd9Sstevel@tonic-gate  *	are acquired in this "outside in" order:
3062*7c478bd9Sstevel@tonic-gate  *		gld_device_list.gld_devlock
3063*7c478bd9Sstevel@tonic-gate  *		glddev->gld_devlock
3064*7c478bd9Sstevel@tonic-gate  *		GLDM_LOCK(macinfo)
3065*7c478bd9Sstevel@tonic-gate  *
3066*7c478bd9Sstevel@tonic-gate  *	Finally, there are some "volatile" elements of the gld_t structure
3067*7c478bd9Sstevel@tonic-gate  *	used for synchronization between various routines that don't share
3068*7c478bd9Sstevel@tonic-gate  *	the same mutexes.  See the routines for details.  These are:
3069*7c478bd9Sstevel@tonic-gate  *		gld_xwait	between gld_wsrv() and gld_sched()
3070*7c478bd9Sstevel@tonic-gate  *		gld_sched_ran	between gld_wsrv() and gld_sched()
3071*7c478bd9Sstevel@tonic-gate  *		gld_in_unbind	between gld_wput() and wsrv's gld_unbind()
3072*7c478bd9Sstevel@tonic-gate  *		gld_wput_count	between gld_wput() and wsrv's gld_unbind()
3073*7c478bd9Sstevel@tonic-gate  *		gld_in_wsrv	between gld_wput() and gld_wsrv()
3074*7c478bd9Sstevel@tonic-gate  *				(used in conjunction with q->q_first)
3075*7c478bd9Sstevel@tonic-gate  */
3076*7c478bd9Sstevel@tonic-gate 
3077*7c478bd9Sstevel@tonic-gate /*
3078*7c478bd9Sstevel@tonic-gate  * gld_ioctl (q, mp)
3079*7c478bd9Sstevel@tonic-gate  * handles all ioctl requests passed downstream. This routine is
3080*7c478bd9Sstevel@tonic-gate  * passed a pointer to the message block with the ioctl request in it, and a
3081*7c478bd9Sstevel@tonic-gate  * pointer to the queue so it can respond to the ioctl request with an ack.
3082*7c478bd9Sstevel@tonic-gate  */
3083*7c478bd9Sstevel@tonic-gate int
3084*7c478bd9Sstevel@tonic-gate gld_ioctl(queue_t *q, mblk_t *mp)
3085*7c478bd9Sstevel@tonic-gate {
3086*7c478bd9Sstevel@tonic-gate 	struct iocblk *iocp;
3087*7c478bd9Sstevel@tonic-gate 	gld_t *gld;
3088*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
3089*7c478bd9Sstevel@tonic-gate 
3090*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
3091*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
3092*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_ioctl(%p %p)", (void *)q, (void *)mp);
3093*7c478bd9Sstevel@tonic-gate #endif
3094*7c478bd9Sstevel@tonic-gate 	gld = (gld_t *)q->q_ptr;
3095*7c478bd9Sstevel@tonic-gate 	iocp = (struct iocblk *)mp->b_rptr;
3096*7c478bd9Sstevel@tonic-gate 	switch (iocp->ioc_cmd) {
3097*7c478bd9Sstevel@tonic-gate 	case DLIOCRAW:		/* raw M_DATA mode */
3098*7c478bd9Sstevel@tonic-gate 		gld->gld_flags |= GLD_RAW;
3099*7c478bd9Sstevel@tonic-gate 		DB_TYPE(mp) = M_IOCACK;
3100*7c478bd9Sstevel@tonic-gate 		qreply(q, mp);
3101*7c478bd9Sstevel@tonic-gate 		break;
3102*7c478bd9Sstevel@tonic-gate 
3103*7c478bd9Sstevel@tonic-gate 	case DL_IOC_HDR_INFO:	/* fastpath */
3104*7c478bd9Sstevel@tonic-gate 		if (gld_global_options & GLD_OPT_NO_FASTPATH) {
3105*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
3106*7c478bd9Sstevel@tonic-gate 			break;
3107*7c478bd9Sstevel@tonic-gate 		}
3108*7c478bd9Sstevel@tonic-gate 		gld_fastpath(gld, q, mp);
3109*7c478bd9Sstevel@tonic-gate 		break;
3110*7c478bd9Sstevel@tonic-gate 
3111*7c478bd9Sstevel@tonic-gate 	default:
3112*7c478bd9Sstevel@tonic-gate 		macinfo	 = gld->gld_mac_info;
3113*7c478bd9Sstevel@tonic-gate 		if (macinfo == NULL || macinfo->gldm_ioctl == NULL) {
3114*7c478bd9Sstevel@tonic-gate 			miocnak(q, mp, 0, EINVAL);
3115*7c478bd9Sstevel@tonic-gate 			break;
3116*7c478bd9Sstevel@tonic-gate 		}
3117*7c478bd9Sstevel@tonic-gate 
3118*7c478bd9Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
3119*7c478bd9Sstevel@tonic-gate 		(void) (*macinfo->gldm_ioctl) (macinfo, q, mp);
3120*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
3121*7c478bd9Sstevel@tonic-gate 		break;
3122*7c478bd9Sstevel@tonic-gate 	}
3123*7c478bd9Sstevel@tonic-gate 	return (0);
3124*7c478bd9Sstevel@tonic-gate }
3125*7c478bd9Sstevel@tonic-gate 
3126*7c478bd9Sstevel@tonic-gate /*
3127*7c478bd9Sstevel@tonic-gate  * Since the rules for "fastpath" mode don't seem to be documented
3128*7c478bd9Sstevel@tonic-gate  * anywhere, I will describe GLD's rules for fastpath users here:
3129*7c478bd9Sstevel@tonic-gate  *
3130*7c478bd9Sstevel@tonic-gate  * Once in this mode you remain there until close.
3131*7c478bd9Sstevel@tonic-gate  * If you unbind/rebind you should get a new header using DL_IOC_HDR_INFO.
3132*7c478bd9Sstevel@tonic-gate  * You must be bound (DL_IDLE) to transmit.
3133*7c478bd9Sstevel@tonic-gate  * There are other rules not listed above.
3134*7c478bd9Sstevel@tonic-gate  */
3135*7c478bd9Sstevel@tonic-gate static void
3136*7c478bd9Sstevel@tonic-gate gld_fastpath(gld_t *gld, queue_t *q, mblk_t *mp)
3137*7c478bd9Sstevel@tonic-gate {
3138*7c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
3139*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
3140*7c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t *dludp;
3141*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
3142*7c478bd9Sstevel@tonic-gate 	t_scalar_t off, len;
3143*7c478bd9Sstevel@tonic-gate 	uint_t maclen;
3144*7c478bd9Sstevel@tonic-gate 	int error;
3145*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
3146*7c478bd9Sstevel@tonic-gate 
3147*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state != DL_IDLE) {
3148*7c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, EINVAL);
3149*7c478bd9Sstevel@tonic-gate 		return;
3150*7c478bd9Sstevel@tonic-gate 	}
3151*7c478bd9Sstevel@tonic-gate 
3152*7c478bd9Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
3153*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
3154*7c478bd9Sstevel@tonic-gate 	maclen = macinfo->gldm_addrlen + abs(macinfo->gldm_saplen);
3155*7c478bd9Sstevel@tonic-gate 
3156*7c478bd9Sstevel@tonic-gate 	error = miocpullup(mp, sizeof (dl_unitdata_req_t) + maclen);
3157*7c478bd9Sstevel@tonic-gate 	if (error != 0) {
3158*7c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, error);
3159*7c478bd9Sstevel@tonic-gate 		return;
3160*7c478bd9Sstevel@tonic-gate 	}
3161*7c478bd9Sstevel@tonic-gate 
3162*7c478bd9Sstevel@tonic-gate 	dludp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
3163*7c478bd9Sstevel@tonic-gate 	off = dludp->dl_dest_addr_offset;
3164*7c478bd9Sstevel@tonic-gate 	len = dludp->dl_dest_addr_length;
3165*7c478bd9Sstevel@tonic-gate 	if (dludp->dl_primitive != DL_UNITDATA_REQ ||
3166*7c478bd9Sstevel@tonic-gate 	    !MBLKIN(mp->b_cont, off, len) || len != maclen) {
3167*7c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, EINVAL);
3168*7c478bd9Sstevel@tonic-gate 		return;
3169*7c478bd9Sstevel@tonic-gate 	}
3170*7c478bd9Sstevel@tonic-gate 
3171*7c478bd9Sstevel@tonic-gate 	/*
3172*7c478bd9Sstevel@tonic-gate 	 * We take his fastpath request as a declaration that he will accept
3173*7c478bd9Sstevel@tonic-gate 	 * M_DATA messages from us, whether or not we are willing to accept
3174*7c478bd9Sstevel@tonic-gate 	 * them from him.  This allows us to have fastpath in one direction
3175*7c478bd9Sstevel@tonic-gate 	 * (flow upstream) even on media with Source Routing, where we are
3176*7c478bd9Sstevel@tonic-gate 	 * unable to provide a fixed MAC header to be prepended to downstream
3177*7c478bd9Sstevel@tonic-gate 	 * flowing packets.  So we set GLD_FAST whether or not we decide to
3178*7c478bd9Sstevel@tonic-gate 	 * allow him to send M_DATA down to us.
3179*7c478bd9Sstevel@tonic-gate 	 */
3180*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
3181*7c478bd9Sstevel@tonic-gate 	gld->gld_flags |= GLD_FAST;
3182*7c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
3183*7c478bd9Sstevel@tonic-gate 	vlan->gldv_ipq_flags &= ~IPQ_DISABLED;
3184*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
3185*7c478bd9Sstevel@tonic-gate 
3186*7c478bd9Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
3187*7c478bd9Sstevel@tonic-gate 
3188*7c478bd9Sstevel@tonic-gate 	/* This will fail for Source Routing media */
3189*7c478bd9Sstevel@tonic-gate 	/* Also on Ethernet on 802.2 SAPs */
3190*7c478bd9Sstevel@tonic-gate 	if ((nmp = (*ifp->mkfastpath)(gld, mp)) == NULL) {
3191*7c478bd9Sstevel@tonic-gate 		miocnak(q, mp, 0, ENOMEM);
3192*7c478bd9Sstevel@tonic-gate 		return;
3193*7c478bd9Sstevel@tonic-gate 	}
3194*7c478bd9Sstevel@tonic-gate 
3195*7c478bd9Sstevel@tonic-gate 	/*
3196*7c478bd9Sstevel@tonic-gate 	 * Link new mblk in after the "request" mblks.
3197*7c478bd9Sstevel@tonic-gate 	 */
3198*7c478bd9Sstevel@tonic-gate 	linkb(mp, nmp);
3199*7c478bd9Sstevel@tonic-gate 	miocack(q, mp, msgdsize(mp->b_cont), 0);
3200*7c478bd9Sstevel@tonic-gate }
3201*7c478bd9Sstevel@tonic-gate 
3202*7c478bd9Sstevel@tonic-gate /*
3203*7c478bd9Sstevel@tonic-gate  * gld_cmds (q, mp)
3204*7c478bd9Sstevel@tonic-gate  *	process the DL commands as defined in dlpi.h
3205*7c478bd9Sstevel@tonic-gate  *	note that the primitives return status which is passed back
3206*7c478bd9Sstevel@tonic-gate  *	to the service procedure.  If the value is GLDE_RETRY, then
3207*7c478bd9Sstevel@tonic-gate  *	it is assumed that processing must stop and the primitive has
3208*7c478bd9Sstevel@tonic-gate  *	been put back onto the queue.  If the value is any other error,
3209*7c478bd9Sstevel@tonic-gate  *	then an error ack is generated by the service procedure.
3210*7c478bd9Sstevel@tonic-gate  */
3211*7c478bd9Sstevel@tonic-gate static int
3212*7c478bd9Sstevel@tonic-gate gld_cmds(queue_t *q, mblk_t *mp)
3213*7c478bd9Sstevel@tonic-gate {
3214*7c478bd9Sstevel@tonic-gate 	union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr;
3215*7c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)(q->q_ptr);
3216*7c478bd9Sstevel@tonic-gate 	int result = DL_BADPRIM;
3217*7c478bd9Sstevel@tonic-gate 	int mblkl = MBLKL(mp);
3218*7c478bd9Sstevel@tonic-gate 	t_uscalar_t dlreq;
3219*7c478bd9Sstevel@tonic-gate 
3220*7c478bd9Sstevel@tonic-gate 	/* Make sure we have at least dlp->dl_primitive */
3221*7c478bd9Sstevel@tonic-gate 	if (mblkl < sizeof (dlp->dl_primitive))
3222*7c478bd9Sstevel@tonic-gate 		return (DL_BADPRIM);
3223*7c478bd9Sstevel@tonic-gate 
3224*7c478bd9Sstevel@tonic-gate 	dlreq = dlp->dl_primitive;
3225*7c478bd9Sstevel@tonic-gate #ifdef	GLD_DEBUG
3226*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
3227*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE,
3228*7c478bd9Sstevel@tonic-gate 		    "gld_cmds(%p, %p):dlp=%p, dlp->dl_primitive=%d",
3229*7c478bd9Sstevel@tonic-gate 		    (void *)q, (void *)mp, (void *)dlp, dlreq);
3230*7c478bd9Sstevel@tonic-gate #endif
3231*7c478bd9Sstevel@tonic-gate 
3232*7c478bd9Sstevel@tonic-gate 	switch (dlreq) {
3233*7c478bd9Sstevel@tonic-gate 	case DL_UDQOS_REQ:
3234*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_UDQOS_REQ_SIZE)
3235*7c478bd9Sstevel@tonic-gate 			break;
3236*7c478bd9Sstevel@tonic-gate 		result = gld_udqos(q, mp);
3237*7c478bd9Sstevel@tonic-gate 		break;
3238*7c478bd9Sstevel@tonic-gate 
3239*7c478bd9Sstevel@tonic-gate 	case DL_BIND_REQ:
3240*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_BIND_REQ_SIZE)
3241*7c478bd9Sstevel@tonic-gate 			break;
3242*7c478bd9Sstevel@tonic-gate 		result = gld_bind(q, mp);
3243*7c478bd9Sstevel@tonic-gate 		break;
3244*7c478bd9Sstevel@tonic-gate 
3245*7c478bd9Sstevel@tonic-gate 	case DL_UNBIND_REQ:
3246*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_UNBIND_REQ_SIZE)
3247*7c478bd9Sstevel@tonic-gate 			break;
3248*7c478bd9Sstevel@tonic-gate 		result = gld_unbind(q, mp);
3249*7c478bd9Sstevel@tonic-gate 		break;
3250*7c478bd9Sstevel@tonic-gate 
3251*7c478bd9Sstevel@tonic-gate 	case DL_UNITDATA_REQ:
3252*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_UNITDATA_REQ_SIZE)
3253*7c478bd9Sstevel@tonic-gate 			break;
3254*7c478bd9Sstevel@tonic-gate 		result = gld_unitdata(q, mp);
3255*7c478bd9Sstevel@tonic-gate 		break;
3256*7c478bd9Sstevel@tonic-gate 
3257*7c478bd9Sstevel@tonic-gate 	case DL_INFO_REQ:
3258*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_INFO_REQ_SIZE)
3259*7c478bd9Sstevel@tonic-gate 			break;
3260*7c478bd9Sstevel@tonic-gate 		result = gld_inforeq(q, mp);
3261*7c478bd9Sstevel@tonic-gate 		break;
3262*7c478bd9Sstevel@tonic-gate 
3263*7c478bd9Sstevel@tonic-gate 	case DL_ATTACH_REQ:
3264*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_ATTACH_REQ_SIZE)
3265*7c478bd9Sstevel@tonic-gate 			break;
3266*7c478bd9Sstevel@tonic-gate 		if (gld->gld_style == DL_STYLE2)
3267*7c478bd9Sstevel@tonic-gate 			result = gldattach(q, mp);
3268*7c478bd9Sstevel@tonic-gate 		else
3269*7c478bd9Sstevel@tonic-gate 			result = DL_NOTSUPPORTED;
3270*7c478bd9Sstevel@tonic-gate 		break;
3271*7c478bd9Sstevel@tonic-gate 
3272*7c478bd9Sstevel@tonic-gate 	case DL_DETACH_REQ:
3273*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_DETACH_REQ_SIZE)
3274*7c478bd9Sstevel@tonic-gate 			break;
3275*7c478bd9Sstevel@tonic-gate 		if (gld->gld_style == DL_STYLE2)
3276*7c478bd9Sstevel@tonic-gate 			result = gldunattach(q, mp);
3277*7c478bd9Sstevel@tonic-gate 		else
3278*7c478bd9Sstevel@tonic-gate 			result = DL_NOTSUPPORTED;
3279*7c478bd9Sstevel@tonic-gate 		break;
3280*7c478bd9Sstevel@tonic-gate 
3281*7c478bd9Sstevel@tonic-gate 	case DL_ENABMULTI_REQ:
3282*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_ENABMULTI_REQ_SIZE)
3283*7c478bd9Sstevel@tonic-gate 			break;
3284*7c478bd9Sstevel@tonic-gate 		result = gld_enable_multi(q, mp);
3285*7c478bd9Sstevel@tonic-gate 		break;
3286*7c478bd9Sstevel@tonic-gate 
3287*7c478bd9Sstevel@tonic-gate 	case DL_DISABMULTI_REQ:
3288*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_DISABMULTI_REQ_SIZE)
3289*7c478bd9Sstevel@tonic-gate 			break;
3290*7c478bd9Sstevel@tonic-gate 		result = gld_disable_multi(q, mp);
3291*7c478bd9Sstevel@tonic-gate 		break;
3292*7c478bd9Sstevel@tonic-gate 
3293*7c478bd9Sstevel@tonic-gate 	case DL_PHYS_ADDR_REQ:
3294*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_PHYS_ADDR_REQ_SIZE)
3295*7c478bd9Sstevel@tonic-gate 			break;
3296*7c478bd9Sstevel@tonic-gate 		result = gld_physaddr(q, mp);
3297*7c478bd9Sstevel@tonic-gate 		break;
3298*7c478bd9Sstevel@tonic-gate 
3299*7c478bd9Sstevel@tonic-gate 	case DL_SET_PHYS_ADDR_REQ:
3300*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_SET_PHYS_ADDR_REQ_SIZE)
3301*7c478bd9Sstevel@tonic-gate 			break;
3302*7c478bd9Sstevel@tonic-gate 		result = gld_setaddr(q, mp);
3303*7c478bd9Sstevel@tonic-gate 		break;
3304*7c478bd9Sstevel@tonic-gate 
3305*7c478bd9Sstevel@tonic-gate 	case DL_PROMISCON_REQ:
3306*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_PROMISCON_REQ_SIZE)
3307*7c478bd9Sstevel@tonic-gate 			break;
3308*7c478bd9Sstevel@tonic-gate 		result = gld_promisc(q, mp, dlreq, B_TRUE);
3309*7c478bd9Sstevel@tonic-gate 		break;
3310*7c478bd9Sstevel@tonic-gate 
3311*7c478bd9Sstevel@tonic-gate 	case DL_PROMISCOFF_REQ:
3312*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_PROMISCOFF_REQ_SIZE)
3313*7c478bd9Sstevel@tonic-gate 			break;
3314*7c478bd9Sstevel@tonic-gate 		result = gld_promisc(q, mp, dlreq, B_FALSE);
3315*7c478bd9Sstevel@tonic-gate 		break;
3316*7c478bd9Sstevel@tonic-gate 
3317*7c478bd9Sstevel@tonic-gate 	case DL_GET_STATISTICS_REQ:
3318*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_GET_STATISTICS_REQ_SIZE)
3319*7c478bd9Sstevel@tonic-gate 			break;
3320*7c478bd9Sstevel@tonic-gate 		result = gld_get_statistics(q, mp);
3321*7c478bd9Sstevel@tonic-gate 		break;
3322*7c478bd9Sstevel@tonic-gate 
3323*7c478bd9Sstevel@tonic-gate 	case DL_CAPABILITY_REQ:
3324*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_CAPABILITY_REQ_SIZE)
3325*7c478bd9Sstevel@tonic-gate 			break;
3326*7c478bd9Sstevel@tonic-gate 		result = gld_cap(q, mp);
3327*7c478bd9Sstevel@tonic-gate 		break;
3328*7c478bd9Sstevel@tonic-gate 
3329*7c478bd9Sstevel@tonic-gate 	case DL_NOTIFY_REQ:
3330*7c478bd9Sstevel@tonic-gate 		if (mblkl < DL_NOTIFY_REQ_SIZE)
3331*7c478bd9Sstevel@tonic-gate 			break;
3332*7c478bd9Sstevel@tonic-gate 		result = gld_notify_req(q, mp);
3333*7c478bd9Sstevel@tonic-gate 		break;
3334*7c478bd9Sstevel@tonic-gate 
3335*7c478bd9Sstevel@tonic-gate 	case DL_XID_REQ:
3336*7c478bd9Sstevel@tonic-gate 	case DL_XID_RES:
3337*7c478bd9Sstevel@tonic-gate 	case DL_TEST_REQ:
3338*7c478bd9Sstevel@tonic-gate 	case DL_TEST_RES:
3339*7c478bd9Sstevel@tonic-gate 	case DL_CONTROL_REQ:
3340*7c478bd9Sstevel@tonic-gate 		result = DL_NOTSUPPORTED;
3341*7c478bd9Sstevel@tonic-gate 		break;
3342*7c478bd9Sstevel@tonic-gate 
3343*7c478bd9Sstevel@tonic-gate 	default:
3344*7c478bd9Sstevel@tonic-gate #ifdef	GLD_DEBUG
3345*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
3346*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_WARN,
3347*7c478bd9Sstevel@tonic-gate 			    "gld_cmds: unknown M_PROTO message: %d",
3348*7c478bd9Sstevel@tonic-gate 			    dlreq);
3349*7c478bd9Sstevel@tonic-gate #endif
3350*7c478bd9Sstevel@tonic-gate 		result = DL_BADPRIM;
3351*7c478bd9Sstevel@tonic-gate 	}
3352*7c478bd9Sstevel@tonic-gate 
3353*7c478bd9Sstevel@tonic-gate 	return (result);
3354*7c478bd9Sstevel@tonic-gate }
3355*7c478bd9Sstevel@tonic-gate 
3356*7c478bd9Sstevel@tonic-gate static int
3357*7c478bd9Sstevel@tonic-gate gld_cap(queue_t *q, mblk_t *mp)
3358*7c478bd9Sstevel@tonic-gate {
3359*7c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
3360*7c478bd9Sstevel@tonic-gate 	dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr;
3361*7c478bd9Sstevel@tonic-gate 
3362*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
3363*7c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
3364*7c478bd9Sstevel@tonic-gate 
3365*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_sub_length == 0)
3366*7c478bd9Sstevel@tonic-gate 		return (gld_cap_ack(q, mp));
3367*7c478bd9Sstevel@tonic-gate 
3368*7c478bd9Sstevel@tonic-gate 	return (gld_cap_enable(q, mp));
3369*7c478bd9Sstevel@tonic-gate }
3370*7c478bd9Sstevel@tonic-gate 
3371*7c478bd9Sstevel@tonic-gate static int
3372*7c478bd9Sstevel@tonic-gate gld_cap_ack(queue_t *q, mblk_t *mp)
3373*7c478bd9Sstevel@tonic-gate {
3374*7c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
3375*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
3376*7c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
3377*7c478bd9Sstevel@tonic-gate 	dl_capability_ack_t *dlap;
3378*7c478bd9Sstevel@tonic-gate 	dl_capability_sub_t *dlsp;
3379*7c478bd9Sstevel@tonic-gate 	size_t size = sizeof (dl_capability_ack_t);
3380*7c478bd9Sstevel@tonic-gate 	size_t subsize = 0;
3381*7c478bd9Sstevel@tonic-gate 
3382*7c478bd9Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
3383*7c478bd9Sstevel@tonic-gate 
3384*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_ANY)
3385*7c478bd9Sstevel@tonic-gate 		subsize += sizeof (dl_capability_sub_t) +
3386*7c478bd9Sstevel@tonic-gate 		    sizeof (dl_capab_hcksum_t);
3387*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_ZEROCOPY)
3388*7c478bd9Sstevel@tonic-gate 		subsize += sizeof (dl_capability_sub_t) +
3389*7c478bd9Sstevel@tonic-gate 		    sizeof (dl_capab_zerocopy_t);
3390*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_options & GLDOPT_MDT)
3391*7c478bd9Sstevel@tonic-gate 		subsize += (sizeof (dl_capability_sub_t) +
3392*7c478bd9Sstevel@tonic-gate 		    sizeof (dl_capab_mdt_t));
3393*7c478bd9Sstevel@tonic-gate 
3394*7c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, size + subsize, M_PROTO,
3395*7c478bd9Sstevel@tonic-gate 	    DL_CAPABILITY_ACK)) == NULL)
3396*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
3397*7c478bd9Sstevel@tonic-gate 
3398*7c478bd9Sstevel@tonic-gate 	dlap = (dl_capability_ack_t *)mp->b_rptr;
3399*7c478bd9Sstevel@tonic-gate 	dlap->dl_sub_offset = 0;
3400*7c478bd9Sstevel@tonic-gate 	if ((dlap->dl_sub_length = subsize) != 0)
3401*7c478bd9Sstevel@tonic-gate 		dlap->dl_sub_offset = sizeof (dl_capability_ack_t);
3402*7c478bd9Sstevel@tonic-gate 	dlsp = (dl_capability_sub_t *)&dlap[1];
3403*7c478bd9Sstevel@tonic-gate 
3404*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_ANY) {
3405*7c478bd9Sstevel@tonic-gate 		dl_capab_hcksum_t *dlhp = (dl_capab_hcksum_t *)&dlsp[1];
3406*7c478bd9Sstevel@tonic-gate 
3407*7c478bd9Sstevel@tonic-gate 		dlsp->dl_cap = DL_CAPAB_HCKSUM;
3408*7c478bd9Sstevel@tonic-gate 		dlsp->dl_length = sizeof (dl_capab_hcksum_t);
3409*7c478bd9Sstevel@tonic-gate 
3410*7c478bd9Sstevel@tonic-gate 		dlhp->hcksum_version = HCKSUM_VERSION_1;
3411*7c478bd9Sstevel@tonic-gate 
3412*7c478bd9Sstevel@tonic-gate 		dlhp->hcksum_txflags = 0;
3413*7c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_PARTIAL)
3414*7c478bd9Sstevel@tonic-gate 			dlhp->hcksum_txflags |= HCKSUM_INET_PARTIAL;
3415*7c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_FULL_V4)
3416*7c478bd9Sstevel@tonic-gate 			dlhp->hcksum_txflags |= HCKSUM_INET_FULL_V4;
3417*7c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_IPHDR)
3418*7c478bd9Sstevel@tonic-gate 			dlhp->hcksum_txflags |= HCKSUM_IPHDRCKSUM;
3419*7c478bd9Sstevel@tonic-gate 
3420*7c478bd9Sstevel@tonic-gate 		dlcapabsetqid(&(dlhp->hcksum_mid), RD(q));
3421*7c478bd9Sstevel@tonic-gate 		dlsp = (dl_capability_sub_t *)&dlhp[1];
3422*7c478bd9Sstevel@tonic-gate 	}
3423*7c478bd9Sstevel@tonic-gate 
3424*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_capabilities & GLD_CAP_ZEROCOPY) {
3425*7c478bd9Sstevel@tonic-gate 		dl_capab_zerocopy_t *dlzp = (dl_capab_zerocopy_t *)&dlsp[1];
3426*7c478bd9Sstevel@tonic-gate 
3427*7c478bd9Sstevel@tonic-gate 		dlsp->dl_cap = DL_CAPAB_ZEROCOPY;
3428*7c478bd9Sstevel@tonic-gate 		dlsp->dl_length = sizeof (dl_capab_zerocopy_t);
3429*7c478bd9Sstevel@tonic-gate 		dlzp->zerocopy_version = ZEROCOPY_VERSION_1;
3430*7c478bd9Sstevel@tonic-gate 		dlzp->zerocopy_flags = DL_CAPAB_VMSAFE_MEM;
3431*7c478bd9Sstevel@tonic-gate 
3432*7c478bd9Sstevel@tonic-gate 		dlcapabsetqid(&(dlzp->zerocopy_mid), RD(q));
3433*7c478bd9Sstevel@tonic-gate 		dlsp = (dl_capability_sub_t *)&dlzp[1];
3434*7c478bd9Sstevel@tonic-gate 	}
3435*7c478bd9Sstevel@tonic-gate 
3436*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_options & GLDOPT_MDT) {
3437*7c478bd9Sstevel@tonic-gate 		dl_capab_mdt_t *dlmp = (dl_capab_mdt_t *)&dlsp[1];
3438*7c478bd9Sstevel@tonic-gate 
3439*7c478bd9Sstevel@tonic-gate 		dlsp->dl_cap = DL_CAPAB_MDT;
3440*7c478bd9Sstevel@tonic-gate 		dlsp->dl_length = sizeof (dl_capab_mdt_t);
3441*7c478bd9Sstevel@tonic-gate 
3442*7c478bd9Sstevel@tonic-gate 		dlmp->mdt_version = MDT_VERSION_2;
3443*7c478bd9Sstevel@tonic-gate 		dlmp->mdt_max_pld = macinfo->gldm_mdt_segs;
3444*7c478bd9Sstevel@tonic-gate 		dlmp->mdt_span_limit = macinfo->gldm_mdt_sgl;
3445*7c478bd9Sstevel@tonic-gate 		dlcapabsetqid(&dlmp->mdt_mid, OTHERQ(q));
3446*7c478bd9Sstevel@tonic-gate 		dlmp->mdt_flags = DL_CAPAB_MDT_ENABLE;
3447*7c478bd9Sstevel@tonic-gate 		dlmp->mdt_hdr_head = ifp->hdr_size;
3448*7c478bd9Sstevel@tonic-gate 		dlmp->mdt_hdr_tail = 0;
3449*7c478bd9Sstevel@tonic-gate 	}
3450*7c478bd9Sstevel@tonic-gate 
3451*7c478bd9Sstevel@tonic-gate 	qreply(q, mp);
3452*7c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
3453*7c478bd9Sstevel@tonic-gate }
3454*7c478bd9Sstevel@tonic-gate 
3455*7c478bd9Sstevel@tonic-gate static int
3456*7c478bd9Sstevel@tonic-gate gld_cap_enable(queue_t *q, mblk_t *mp)
3457*7c478bd9Sstevel@tonic-gate {
3458*7c478bd9Sstevel@tonic-gate 	dl_capability_req_t *dlp;
3459*7c478bd9Sstevel@tonic-gate 	dl_capability_sub_t *dlsp;
3460*7c478bd9Sstevel@tonic-gate 	dl_capab_hcksum_t *dlhp;
3461*7c478bd9Sstevel@tonic-gate 	offset_t off;
3462*7c478bd9Sstevel@tonic-gate 	size_t len;
3463*7c478bd9Sstevel@tonic-gate 	size_t size;
3464*7c478bd9Sstevel@tonic-gate 	offset_t end;
3465*7c478bd9Sstevel@tonic-gate 
3466*7c478bd9Sstevel@tonic-gate 	dlp = (dl_capability_req_t *)mp->b_rptr;
3467*7c478bd9Sstevel@tonic-gate 	dlp->dl_primitive = DL_CAPABILITY_ACK;
3468*7c478bd9Sstevel@tonic-gate 
3469*7c478bd9Sstevel@tonic-gate 	off = dlp->dl_sub_offset;
3470*7c478bd9Sstevel@tonic-gate 	len = dlp->dl_sub_length;
3471*7c478bd9Sstevel@tonic-gate 
3472*7c478bd9Sstevel@tonic-gate 	if (!MBLKIN(mp, off, len))
3473*7c478bd9Sstevel@tonic-gate 		return (DL_BADPRIM);
3474*7c478bd9Sstevel@tonic-gate 
3475*7c478bd9Sstevel@tonic-gate 	end = off + len;
3476*7c478bd9Sstevel@tonic-gate 	while (off < end) {
3477*7c478bd9Sstevel@tonic-gate 		dlsp = (dl_capability_sub_t *)(mp->b_rptr + off);
3478*7c478bd9Sstevel@tonic-gate 		size = sizeof (dl_capability_sub_t) + dlsp->dl_length;
3479*7c478bd9Sstevel@tonic-gate 		if (off + size > end)
3480*7c478bd9Sstevel@tonic-gate 			return (DL_BADPRIM);
3481*7c478bd9Sstevel@tonic-gate 
3482*7c478bd9Sstevel@tonic-gate 		switch (dlsp->dl_cap) {
3483*7c478bd9Sstevel@tonic-gate 		case DL_CAPAB_HCKSUM:
3484*7c478bd9Sstevel@tonic-gate 			dlhp = (dl_capab_hcksum_t *)&dlsp[1];
3485*7c478bd9Sstevel@tonic-gate 			/* nothing useful we can do with the contents */
3486*7c478bd9Sstevel@tonic-gate 			dlcapabsetqid(&(dlhp->hcksum_mid), RD(q));
3487*7c478bd9Sstevel@tonic-gate 			break;
3488*7c478bd9Sstevel@tonic-gate 		default:
3489*7c478bd9Sstevel@tonic-gate 			break;
3490*7c478bd9Sstevel@tonic-gate 		}
3491*7c478bd9Sstevel@tonic-gate 
3492*7c478bd9Sstevel@tonic-gate 		off += size;
3493*7c478bd9Sstevel@tonic-gate 	}
3494*7c478bd9Sstevel@tonic-gate 
3495*7c478bd9Sstevel@tonic-gate 	qreply(q, mp);
3496*7c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
3497*7c478bd9Sstevel@tonic-gate }
3498*7c478bd9Sstevel@tonic-gate 
3499*7c478bd9Sstevel@tonic-gate /*
3500*7c478bd9Sstevel@tonic-gate  * Send a copy of the DL_NOTIFY_IND message <mp> to each stream that has
3501*7c478bd9Sstevel@tonic-gate  * requested the specific <notification> that the message carries AND is
3502*7c478bd9Sstevel@tonic-gate  * eligible and ready to receive the notification immediately.
3503*7c478bd9Sstevel@tonic-gate  *
3504*7c478bd9Sstevel@tonic-gate  * This routine ignores flow control. Notifications will be sent regardless.
3505*7c478bd9Sstevel@tonic-gate  *
3506*7c478bd9Sstevel@tonic-gate  * In all cases, the original message passed in is freed at the end of
3507*7c478bd9Sstevel@tonic-gate  * the routine.
3508*7c478bd9Sstevel@tonic-gate  */
3509*7c478bd9Sstevel@tonic-gate static void
3510*7c478bd9Sstevel@tonic-gate gld_notify_qs(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t notification)
3511*7c478bd9Sstevel@tonic-gate {
3512*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
3513*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
3514*7c478bd9Sstevel@tonic-gate 	gld_t *gld;
3515*7c478bd9Sstevel@tonic-gate 	mblk_t *nmp;
3516*7c478bd9Sstevel@tonic-gate 	int i;
3517*7c478bd9Sstevel@tonic-gate 
3518*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
3519*7c478bd9Sstevel@tonic-gate 
3520*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
3521*7c478bd9Sstevel@tonic-gate 
3522*7c478bd9Sstevel@tonic-gate 	/*
3523*7c478bd9Sstevel@tonic-gate 	 * Search all the streams attached to this macinfo looking
3524*7c478bd9Sstevel@tonic-gate 	 * for those eligible to receive the present notification.
3525*7c478bd9Sstevel@tonic-gate 	 */
3526*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < VLAN_HASHSZ; i++) {
3527*7c478bd9Sstevel@tonic-gate 		for (vlan = mac_pvt->vlan_hash[i];
3528*7c478bd9Sstevel@tonic-gate 		    vlan != NULL; vlan = vlan->gldv_next) {
3529*7c478bd9Sstevel@tonic-gate 			for (gld = vlan->gldv_str_next;
3530*7c478bd9Sstevel@tonic-gate 			    gld != (gld_t *)&vlan->gldv_str_next;
3531*7c478bd9Sstevel@tonic-gate 			    gld = gld->gld_next) {
3532*7c478bd9Sstevel@tonic-gate 				ASSERT(gld->gld_qptr != NULL);
3533*7c478bd9Sstevel@tonic-gate 				ASSERT(gld->gld_state == DL_IDLE ||
3534*7c478bd9Sstevel@tonic-gate 				    gld->gld_state == DL_UNBOUND);
3535*7c478bd9Sstevel@tonic-gate 				ASSERT(gld->gld_mac_info == macinfo);
3536*7c478bd9Sstevel@tonic-gate 
3537*7c478bd9Sstevel@tonic-gate 				if (gld->gld_flags & GLD_STR_CLOSING)
3538*7c478bd9Sstevel@tonic-gate 					continue; /* not eligible - skip */
3539*7c478bd9Sstevel@tonic-gate 				if (!(notification & gld->gld_notifications))
3540*7c478bd9Sstevel@tonic-gate 					continue; /* not wanted - skip */
3541*7c478bd9Sstevel@tonic-gate 				if ((nmp = dupmsg(mp)) == NULL)
3542*7c478bd9Sstevel@tonic-gate 					continue; /* can't copy - skip */
3543*7c478bd9Sstevel@tonic-gate 
3544*7c478bd9Sstevel@tonic-gate 				/*
3545*7c478bd9Sstevel@tonic-gate 				 * All OK; send dup'd notification up this
3546*7c478bd9Sstevel@tonic-gate 				 * stream
3547*7c478bd9Sstevel@tonic-gate 				 */
3548*7c478bd9Sstevel@tonic-gate 				qreply(WR(gld->gld_qptr), nmp);
3549*7c478bd9Sstevel@tonic-gate 			}
3550*7c478bd9Sstevel@tonic-gate 		}
3551*7c478bd9Sstevel@tonic-gate 	}
3552*7c478bd9Sstevel@tonic-gate 
3553*7c478bd9Sstevel@tonic-gate 	/*
3554*7c478bd9Sstevel@tonic-gate 	 * Drop the original message block now
3555*7c478bd9Sstevel@tonic-gate 	 */
3556*7c478bd9Sstevel@tonic-gate 	freemsg(mp);
3557*7c478bd9Sstevel@tonic-gate }
3558*7c478bd9Sstevel@tonic-gate 
3559*7c478bd9Sstevel@tonic-gate /*
3560*7c478bd9Sstevel@tonic-gate  * For each (understood) bit in the <notifications> argument, contruct
3561*7c478bd9Sstevel@tonic-gate  * a DL_NOTIFY_IND message and send it to the specified <q>, or to all
3562*7c478bd9Sstevel@tonic-gate  * eligible queues if <q> is NULL.
3563*7c478bd9Sstevel@tonic-gate  */
3564*7c478bd9Sstevel@tonic-gate static void
3565*7c478bd9Sstevel@tonic-gate gld_notify_ind(gld_mac_info_t *macinfo, uint32_t notifications, queue_t *q)
3566*7c478bd9Sstevel@tonic-gate {
3567*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
3568*7c478bd9Sstevel@tonic-gate 	dl_notify_ind_t *dlnip;
3569*7c478bd9Sstevel@tonic-gate 	struct gld_stats *stats;
3570*7c478bd9Sstevel@tonic-gate 	mblk_t *mp;
3571*7c478bd9Sstevel@tonic-gate 	size_t size;
3572*7c478bd9Sstevel@tonic-gate 	uint32_t bit;
3573*7c478bd9Sstevel@tonic-gate 
3574*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
3575*7c478bd9Sstevel@tonic-gate 
3576*7c478bd9Sstevel@tonic-gate 	/*
3577*7c478bd9Sstevel@tonic-gate 	 * The following cases shouldn't happen, but just in case the
3578*7c478bd9Sstevel@tonic-gate 	 * MAC driver calls gld_linkstate() at an inappropriate time, we
3579*7c478bd9Sstevel@tonic-gate 	 * check anyway ...
3580*7c478bd9Sstevel@tonic-gate 	 */
3581*7c478bd9Sstevel@tonic-gate 	if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY)) {
3582*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
3583*7c478bd9Sstevel@tonic-gate 		return;				/* not ready yet	*/
3584*7c478bd9Sstevel@tonic-gate 	}
3585*7c478bd9Sstevel@tonic-gate 
3586*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
3587*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
3588*7c478bd9Sstevel@tonic-gate 		return;				/* not ready anymore	*/
3589*7c478bd9Sstevel@tonic-gate 	}
3590*7c478bd9Sstevel@tonic-gate 
3591*7c478bd9Sstevel@tonic-gate 	/*
3592*7c478bd9Sstevel@tonic-gate 	 * Make sure the kstats are up to date, 'cos we use some of
3593*7c478bd9Sstevel@tonic-gate 	 * the kstat values below, specifically the link speed ...
3594*7c478bd9Sstevel@tonic-gate 	 */
3595*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
3596*7c478bd9Sstevel@tonic-gate 	stats = mac_pvt->statistics;
3597*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_get_stats)
3598*7c478bd9Sstevel@tonic-gate 		(void) (*macinfo->gldm_get_stats)(macinfo, stats);
3599*7c478bd9Sstevel@tonic-gate 
3600*7c478bd9Sstevel@tonic-gate 	for (bit = 1; notifications != 0; bit <<= 1) {
3601*7c478bd9Sstevel@tonic-gate 		if ((notifications & bit) == 0)
3602*7c478bd9Sstevel@tonic-gate 			continue;
3603*7c478bd9Sstevel@tonic-gate 		notifications &= ~bit;
3604*7c478bd9Sstevel@tonic-gate 
3605*7c478bd9Sstevel@tonic-gate 		size = DL_NOTIFY_IND_SIZE;
3606*7c478bd9Sstevel@tonic-gate 		if (bit == DL_NOTE_PHYS_ADDR)
3607*7c478bd9Sstevel@tonic-gate 			size += macinfo->gldm_addrlen;
3608*7c478bd9Sstevel@tonic-gate 		if ((mp = allocb(size, BPRI_MED)) == NULL)
3609*7c478bd9Sstevel@tonic-gate 			continue;
3610*7c478bd9Sstevel@tonic-gate 
3611*7c478bd9Sstevel@tonic-gate 		mp->b_datap->db_type = M_PROTO;
3612*7c478bd9Sstevel@tonic-gate 		mp->b_wptr = mp->b_rptr + size;
3613*7c478bd9Sstevel@tonic-gate 		dlnip = (dl_notify_ind_t *)mp->b_rptr;
3614*7c478bd9Sstevel@tonic-gate 		dlnip->dl_primitive = DL_NOTIFY_IND;
3615*7c478bd9Sstevel@tonic-gate 		dlnip->dl_notification = 0;
3616*7c478bd9Sstevel@tonic-gate 		dlnip->dl_data = 0;
3617*7c478bd9Sstevel@tonic-gate 		dlnip->dl_addr_length = 0;
3618*7c478bd9Sstevel@tonic-gate 		dlnip->dl_addr_offset = 0;
3619*7c478bd9Sstevel@tonic-gate 
3620*7c478bd9Sstevel@tonic-gate 		switch (bit) {
3621*7c478bd9Sstevel@tonic-gate 		case DL_NOTE_PROMISC_ON_PHYS:
3622*7c478bd9Sstevel@tonic-gate 		case DL_NOTE_PROMISC_OFF_PHYS:
3623*7c478bd9Sstevel@tonic-gate 			if (mac_pvt->nprom != 0)
3624*7c478bd9Sstevel@tonic-gate 				dlnip->dl_notification = bit;
3625*7c478bd9Sstevel@tonic-gate 			break;
3626*7c478bd9Sstevel@tonic-gate 
3627*7c478bd9Sstevel@tonic-gate 		case DL_NOTE_LINK_DOWN:
3628*7c478bd9Sstevel@tonic-gate 			if (macinfo->gldm_linkstate == GLD_LINKSTATE_DOWN)
3629*7c478bd9Sstevel@tonic-gate 				dlnip->dl_notification = bit;
3630*7c478bd9Sstevel@tonic-gate 			break;
3631*7c478bd9Sstevel@tonic-gate 
3632*7c478bd9Sstevel@tonic-gate 		case DL_NOTE_LINK_UP:
3633*7c478bd9Sstevel@tonic-gate 			if (macinfo->gldm_linkstate == GLD_LINKSTATE_UP)
3634*7c478bd9Sstevel@tonic-gate 				dlnip->dl_notification = bit;
3635*7c478bd9Sstevel@tonic-gate 			break;
3636*7c478bd9Sstevel@tonic-gate 
3637*7c478bd9Sstevel@tonic-gate 		case DL_NOTE_SPEED:
3638*7c478bd9Sstevel@tonic-gate 			/*
3639*7c478bd9Sstevel@tonic-gate 			 * Conversion required here:
3640*7c478bd9Sstevel@tonic-gate 			 *	GLD keeps the speed in bit/s in a uint64
3641*7c478bd9Sstevel@tonic-gate 			 *	DLPI wants it in kb/s in a uint32
3642*7c478bd9Sstevel@tonic-gate 			 * Fortunately this is still big enough for 10Gb/s!
3643*7c478bd9Sstevel@tonic-gate 			 */
3644*7c478bd9Sstevel@tonic-gate 			dlnip->dl_notification = bit;
3645*7c478bd9Sstevel@tonic-gate 			dlnip->dl_data = stats->glds_speed/1000ULL;
3646*7c478bd9Sstevel@tonic-gate 			break;
3647*7c478bd9Sstevel@tonic-gate 
3648*7c478bd9Sstevel@tonic-gate 		case DL_NOTE_PHYS_ADDR:
3649*7c478bd9Sstevel@tonic-gate 			dlnip->dl_notification = bit;
3650*7c478bd9Sstevel@tonic-gate 			dlnip->dl_data = DL_CURR_PHYS_ADDR;
3651*7c478bd9Sstevel@tonic-gate 			dlnip->dl_addr_offset = sizeof (dl_notify_ind_t);
3652*7c478bd9Sstevel@tonic-gate 			dlnip->dl_addr_length = macinfo->gldm_addrlen +
3653*7c478bd9Sstevel@tonic-gate 			    abs(macinfo->gldm_saplen);
3654*7c478bd9Sstevel@tonic-gate 			mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
3655*7c478bd9Sstevel@tonic-gate 			mac_copy(mac_pvt->curr_macaddr,
3656*7c478bd9Sstevel@tonic-gate 			    mp->b_rptr + sizeof (dl_notify_ind_t),
3657*7c478bd9Sstevel@tonic-gate 			    macinfo->gldm_addrlen);
3658*7c478bd9Sstevel@tonic-gate 			break;
3659*7c478bd9Sstevel@tonic-gate 
3660*7c478bd9Sstevel@tonic-gate 		default:
3661*7c478bd9Sstevel@tonic-gate 			break;
3662*7c478bd9Sstevel@tonic-gate 		}
3663*7c478bd9Sstevel@tonic-gate 
3664*7c478bd9Sstevel@tonic-gate 		if (dlnip->dl_notification == 0)
3665*7c478bd9Sstevel@tonic-gate 			freemsg(mp);
3666*7c478bd9Sstevel@tonic-gate 		else if (q != NULL)
3667*7c478bd9Sstevel@tonic-gate 			qreply(q, mp);
3668*7c478bd9Sstevel@tonic-gate 		else
3669*7c478bd9Sstevel@tonic-gate 			gld_notify_qs(macinfo, mp, bit);
3670*7c478bd9Sstevel@tonic-gate 	}
3671*7c478bd9Sstevel@tonic-gate 
3672*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
3673*7c478bd9Sstevel@tonic-gate }
3674*7c478bd9Sstevel@tonic-gate 
3675*7c478bd9Sstevel@tonic-gate /*
3676*7c478bd9Sstevel@tonic-gate  * gld_notify_req - handle a DL_NOTIFY_REQ message
3677*7c478bd9Sstevel@tonic-gate  */
3678*7c478bd9Sstevel@tonic-gate static int
3679*7c478bd9Sstevel@tonic-gate gld_notify_req(queue_t *q, mblk_t *mp)
3680*7c478bd9Sstevel@tonic-gate {
3681*7c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
3682*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
3683*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *pvt;
3684*7c478bd9Sstevel@tonic-gate 	dl_notify_req_t *dlnrp;
3685*7c478bd9Sstevel@tonic-gate 	dl_notify_ack_t *dlnap;
3686*7c478bd9Sstevel@tonic-gate 
3687*7c478bd9Sstevel@tonic-gate 	ASSERT(gld != NULL);
3688*7c478bd9Sstevel@tonic-gate 	ASSERT(gld->gld_qptr == RD(q));
3689*7c478bd9Sstevel@tonic-gate 
3690*7c478bd9Sstevel@tonic-gate 	dlnrp = (dl_notify_req_t *)mp->b_rptr;
3691*7c478bd9Sstevel@tonic-gate 
3692*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
3693*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
3694*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_notify_req(%p %p)",
3695*7c478bd9Sstevel@tonic-gate 			(void *)q, (void *)mp);
3696*7c478bd9Sstevel@tonic-gate #endif
3697*7c478bd9Sstevel@tonic-gate 
3698*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED) {
3699*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
3700*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
3701*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_notify_req: wrong state (%d)",
3702*7c478bd9Sstevel@tonic-gate 				gld->gld_state);
3703*7c478bd9Sstevel@tonic-gate #endif
3704*7c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
3705*7c478bd9Sstevel@tonic-gate 	}
3706*7c478bd9Sstevel@tonic-gate 
3707*7c478bd9Sstevel@tonic-gate 	/*
3708*7c478bd9Sstevel@tonic-gate 	 * Remember what notifications are required by this stream
3709*7c478bd9Sstevel@tonic-gate 	 */
3710*7c478bd9Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
3711*7c478bd9Sstevel@tonic-gate 	pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
3712*7c478bd9Sstevel@tonic-gate 
3713*7c478bd9Sstevel@tonic-gate 	gld->gld_notifications = dlnrp->dl_notifications & pvt->notifications;
3714*7c478bd9Sstevel@tonic-gate 
3715*7c478bd9Sstevel@tonic-gate 	/*
3716*7c478bd9Sstevel@tonic-gate 	 * The return DL_NOTIFY_ACK carries the bitset of notifications
3717*7c478bd9Sstevel@tonic-gate 	 * that this driver can provide, independently of which ones have
3718*7c478bd9Sstevel@tonic-gate 	 * previously been or are now being requested.
3719*7c478bd9Sstevel@tonic-gate 	 */
3720*7c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, sizeof (dl_notify_ack_t), M_PCPROTO,
3721*7c478bd9Sstevel@tonic-gate 	    DL_NOTIFY_ACK)) == NULL)
3722*7c478bd9Sstevel@tonic-gate 		return (DL_SYSERR);
3723*7c478bd9Sstevel@tonic-gate 
3724*7c478bd9Sstevel@tonic-gate 	dlnap = (dl_notify_ack_t *)mp->b_rptr;
3725*7c478bd9Sstevel@tonic-gate 	dlnap->dl_notifications = pvt->notifications;
3726*7c478bd9Sstevel@tonic-gate 	qreply(q, mp);
3727*7c478bd9Sstevel@tonic-gate 
3728*7c478bd9Sstevel@tonic-gate 	/*
3729*7c478bd9Sstevel@tonic-gate 	 * A side effect of a DL_NOTIFY_REQ is that after the DL_NOTIFY_ACK
3730*7c478bd9Sstevel@tonic-gate 	 * reply, the the requestor gets zero or more DL_NOTIFY_IND messages
3731*7c478bd9Sstevel@tonic-gate 	 * that provide the current status.
3732*7c478bd9Sstevel@tonic-gate 	 */
3733*7c478bd9Sstevel@tonic-gate 	gld_notify_ind(macinfo, gld->gld_notifications, q);
3734*7c478bd9Sstevel@tonic-gate 
3735*7c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
3736*7c478bd9Sstevel@tonic-gate }
3737*7c478bd9Sstevel@tonic-gate 
3738*7c478bd9Sstevel@tonic-gate /*
3739*7c478bd9Sstevel@tonic-gate  * gld_linkstate()
3740*7c478bd9Sstevel@tonic-gate  *	Called by driver to tell GLD the state of the physical link.
3741*7c478bd9Sstevel@tonic-gate  *	As a side effect, sends a DL_NOTE_LINK_UP or DL_NOTE_LINK_DOWN
3742*7c478bd9Sstevel@tonic-gate  *	notification to each client that has previously requested such
3743*7c478bd9Sstevel@tonic-gate  *	notifications
3744*7c478bd9Sstevel@tonic-gate  */
3745*7c478bd9Sstevel@tonic-gate void
3746*7c478bd9Sstevel@tonic-gate gld_linkstate(gld_mac_info_t *macinfo, int32_t newstate)
3747*7c478bd9Sstevel@tonic-gate {
3748*7c478bd9Sstevel@tonic-gate 	uint32_t notification;
3749*7c478bd9Sstevel@tonic-gate 
3750*7c478bd9Sstevel@tonic-gate 	switch (newstate) {
3751*7c478bd9Sstevel@tonic-gate 	default:
3752*7c478bd9Sstevel@tonic-gate 		return;
3753*7c478bd9Sstevel@tonic-gate 
3754*7c478bd9Sstevel@tonic-gate 	case GLD_LINKSTATE_DOWN:
3755*7c478bd9Sstevel@tonic-gate 		notification = DL_NOTE_LINK_DOWN;
3756*7c478bd9Sstevel@tonic-gate 		break;
3757*7c478bd9Sstevel@tonic-gate 
3758*7c478bd9Sstevel@tonic-gate 	case GLD_LINKSTATE_UP:
3759*7c478bd9Sstevel@tonic-gate 		notification = DL_NOTE_LINK_UP | DL_NOTE_SPEED;
3760*7c478bd9Sstevel@tonic-gate 		break;
3761*7c478bd9Sstevel@tonic-gate 
3762*7c478bd9Sstevel@tonic-gate 	case GLD_LINKSTATE_UNKNOWN:
3763*7c478bd9Sstevel@tonic-gate 		notification = 0;
3764*7c478bd9Sstevel@tonic-gate 		break;
3765*7c478bd9Sstevel@tonic-gate 	}
3766*7c478bd9Sstevel@tonic-gate 
3767*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
3768*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_linkstate == newstate)
3769*7c478bd9Sstevel@tonic-gate 		notification = 0;
3770*7c478bd9Sstevel@tonic-gate 	else
3771*7c478bd9Sstevel@tonic-gate 		macinfo->gldm_linkstate = newstate;
3772*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
3773*7c478bd9Sstevel@tonic-gate 
3774*7c478bd9Sstevel@tonic-gate 	if (notification)
3775*7c478bd9Sstevel@tonic-gate 		gld_notify_ind(macinfo, notification, NULL);
3776*7c478bd9Sstevel@tonic-gate }
3777*7c478bd9Sstevel@tonic-gate 
3778*7c478bd9Sstevel@tonic-gate /*
3779*7c478bd9Sstevel@tonic-gate  * gld_udqos - set the current QoS parameters (priority only at the moment).
3780*7c478bd9Sstevel@tonic-gate  */
3781*7c478bd9Sstevel@tonic-gate static int
3782*7c478bd9Sstevel@tonic-gate gld_udqos(queue_t *q, mblk_t *mp)
3783*7c478bd9Sstevel@tonic-gate {
3784*7c478bd9Sstevel@tonic-gate 	dl_udqos_req_t *dlp;
3785*7c478bd9Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
3786*7c478bd9Sstevel@tonic-gate 	int off;
3787*7c478bd9Sstevel@tonic-gate 	int len;
3788*7c478bd9Sstevel@tonic-gate 	dl_qos_cl_sel1_t *selp;
3789*7c478bd9Sstevel@tonic-gate 
3790*7c478bd9Sstevel@tonic-gate 	ASSERT(gld);
3791*7c478bd9Sstevel@tonic-gate 	ASSERT(gld->gld_qptr == RD(q));
3792*7c478bd9Sstevel@tonic-gate 
3793*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
3794*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
3795*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_udqos(%p %p)", (void *)q, (void *)mp);
3796*7c478bd9Sstevel@tonic-gate #endif
3797*7c478bd9Sstevel@tonic-gate 
3798*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state != DL_IDLE) {
3799*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
3800*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
3801*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_udqos: wrong state (%d)",
3802*7c478bd9Sstevel@tonic-gate 			    gld->gld_state);
3803*7c478bd9Sstevel@tonic-gate #endif
3804*7c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
3805*7c478bd9Sstevel@tonic-gate 	}
3806*7c478bd9Sstevel@tonic-gate 
3807*7c478bd9Sstevel@tonic-gate 	dlp = (dl_udqos_req_t *)mp->b_rptr;
3808*7c478bd9Sstevel@tonic-gate 	off = dlp->dl_qos_offset;
3809*7c478bd9Sstevel@tonic-gate 	len = dlp->dl_qos_length;
3810*7c478bd9Sstevel@tonic-gate 
3811*7c478bd9Sstevel@tonic-gate 	if (len != sizeof (dl_qos_cl_sel1_t) || !MBLKIN(mp, off, len))
3812*7c478bd9Sstevel@tonic-gate 		return (DL_BADQOSTYPE);
3813*7c478bd9Sstevel@tonic-gate 
3814*7c478bd9Sstevel@tonic-gate 	selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off);
3815*7c478bd9Sstevel@tonic-gate 	if (selp->dl_qos_type != DL_QOS_CL_SEL1)
3816*7c478bd9Sstevel@tonic-gate 		return (DL_BADQOSTYPE);
3817*7c478bd9Sstevel@tonic-gate 
3818*7c478bd9Sstevel@tonic-gate 	if (selp->dl_trans_delay != 0 &&
3819*7c478bd9Sstevel@tonic-gate 	    selp->dl_trans_delay != DL_QOS_DONT_CARE)
3820*7c478bd9Sstevel@tonic-gate 		return (DL_BADQOSPARAM);
3821*7c478bd9Sstevel@tonic-gate 	if (selp->dl_protection != 0 &&
3822*7c478bd9Sstevel@tonic-gate 	    selp->dl_protection != DL_QOS_DONT_CARE)
3823*7c478bd9Sstevel@tonic-gate 		return (DL_BADQOSPARAM);
3824*7c478bd9Sstevel@tonic-gate 	if (selp->dl_residual_error != 0 &&
3825*7c478bd9Sstevel@tonic-gate 	    selp->dl_residual_error != DL_QOS_DONT_CARE)
3826*7c478bd9Sstevel@tonic-gate 		return (DL_BADQOSPARAM);
3827*7c478bd9Sstevel@tonic-gate 	if (selp->dl_priority < 0 || selp->dl_priority > 7)
3828*7c478bd9Sstevel@tonic-gate 		return (DL_BADQOSPARAM);
3829*7c478bd9Sstevel@tonic-gate 
3830*7c478bd9Sstevel@tonic-gate 	gld->gld_upri = selp->dl_priority;
3831*7c478bd9Sstevel@tonic-gate 
3832*7c478bd9Sstevel@tonic-gate 	dlokack(q, mp, DL_UDQOS_REQ);
3833*7c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
3834*7c478bd9Sstevel@tonic-gate }
3835*7c478bd9Sstevel@tonic-gate 
3836*7c478bd9Sstevel@tonic-gate static mblk_t *
3837*7c478bd9Sstevel@tonic-gate gld_bindack(queue_t *q, mblk_t *mp)
3838*7c478bd9Sstevel@tonic-gate {
3839*7c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
3840*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
3841*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
3842*7c478bd9Sstevel@tonic-gate 	dl_bind_ack_t *dlp;
3843*7c478bd9Sstevel@tonic-gate 	size_t size;
3844*7c478bd9Sstevel@tonic-gate 	t_uscalar_t addrlen;
3845*7c478bd9Sstevel@tonic-gate 	uchar_t *sapp;
3846*7c478bd9Sstevel@tonic-gate 
3847*7c478bd9Sstevel@tonic-gate 	addrlen = macinfo->gldm_addrlen + abs(macinfo->gldm_saplen);
3848*7c478bd9Sstevel@tonic-gate 	size = sizeof (dl_bind_ack_t) + addrlen;
3849*7c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, size, M_PCPROTO, DL_BIND_ACK)) == NULL)
3850*7c478bd9Sstevel@tonic-gate 		return (NULL);
3851*7c478bd9Sstevel@tonic-gate 
3852*7c478bd9Sstevel@tonic-gate 	dlp = (dl_bind_ack_t *)mp->b_rptr;
3853*7c478bd9Sstevel@tonic-gate 	dlp->dl_sap = gld->gld_sap;
3854*7c478bd9Sstevel@tonic-gate 	dlp->dl_addr_length = addrlen;
3855*7c478bd9Sstevel@tonic-gate 	dlp->dl_addr_offset = sizeof (dl_bind_ack_t);
3856*7c478bd9Sstevel@tonic-gate 	dlp->dl_max_conind = 0;
3857*7c478bd9Sstevel@tonic-gate 	dlp->dl_xidtest_flg = 0;
3858*7c478bd9Sstevel@tonic-gate 
3859*7c478bd9Sstevel@tonic-gate 	mac_copy(mac_pvt->curr_macaddr, (uchar_t *)&dlp[1],
3860*7c478bd9Sstevel@tonic-gate 	    macinfo->gldm_addrlen);
3861*7c478bd9Sstevel@tonic-gate 	sapp = mp->b_rptr + dlp->dl_addr_offset + macinfo->gldm_addrlen;
3862*7c478bd9Sstevel@tonic-gate 	*(ushort_t *)sapp = gld->gld_sap;
3863*7c478bd9Sstevel@tonic-gate 
3864*7c478bd9Sstevel@tonic-gate 	return (mp);
3865*7c478bd9Sstevel@tonic-gate }
3866*7c478bd9Sstevel@tonic-gate 
3867*7c478bd9Sstevel@tonic-gate /*
3868*7c478bd9Sstevel@tonic-gate  * gld_bind - determine if a SAP is already allocated and whether it is legal
3869*7c478bd9Sstevel@tonic-gate  * to do the bind at this time
3870*7c478bd9Sstevel@tonic-gate  */
3871*7c478bd9Sstevel@tonic-gate static int
3872*7c478bd9Sstevel@tonic-gate gld_bind(queue_t *q, mblk_t *mp)
3873*7c478bd9Sstevel@tonic-gate {
3874*7c478bd9Sstevel@tonic-gate 	ulong_t	sap;
3875*7c478bd9Sstevel@tonic-gate 	dl_bind_req_t *dlp;
3876*7c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
3877*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
3878*7c478bd9Sstevel@tonic-gate 
3879*7c478bd9Sstevel@tonic-gate 	ASSERT(gld);
3880*7c478bd9Sstevel@tonic-gate 	ASSERT(gld->gld_qptr == RD(q));
3881*7c478bd9Sstevel@tonic-gate 
3882*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
3883*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
3884*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_bind(%p %p)", (void *)q, (void *)mp);
3885*7c478bd9Sstevel@tonic-gate #endif
3886*7c478bd9Sstevel@tonic-gate 
3887*7c478bd9Sstevel@tonic-gate 	dlp = (dl_bind_req_t *)mp->b_rptr;
3888*7c478bd9Sstevel@tonic-gate 	sap = dlp->dl_sap;
3889*7c478bd9Sstevel@tonic-gate 
3890*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
3891*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT)
3892*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_bind: lsap=%lx", sap);
3893*7c478bd9Sstevel@tonic-gate #endif
3894*7c478bd9Sstevel@tonic-gate 
3895*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state != DL_UNBOUND) {
3896*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
3897*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
3898*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_bind: bound or not attached (%d)",
3899*7c478bd9Sstevel@tonic-gate 				gld->gld_state);
3900*7c478bd9Sstevel@tonic-gate #endif
3901*7c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
3902*7c478bd9Sstevel@tonic-gate 	}
3903*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo);
3904*7c478bd9Sstevel@tonic-gate 
3905*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_service_mode != DL_CLDLS) {
3906*7c478bd9Sstevel@tonic-gate 		return (DL_UNSUPPORTED);
3907*7c478bd9Sstevel@tonic-gate 	}
3908*7c478bd9Sstevel@tonic-gate 	if (dlp->dl_xidtest_flg & (DL_AUTO_XID | DL_AUTO_TEST)) {
3909*7c478bd9Sstevel@tonic-gate 		return (DL_NOAUTO);
3910*7c478bd9Sstevel@tonic-gate 	}
3911*7c478bd9Sstevel@tonic-gate 
3912*7c478bd9Sstevel@tonic-gate 	/*
3913*7c478bd9Sstevel@tonic-gate 	 * Check sap validity and decide whether this stream accepts
3914*7c478bd9Sstevel@tonic-gate 	 * IEEE 802.2 (LLC) packets.
3915*7c478bd9Sstevel@tonic-gate 	 */
3916*7c478bd9Sstevel@tonic-gate 	if (sap > ETHERTYPE_MAX)
3917*7c478bd9Sstevel@tonic-gate 		return (DL_BADSAP);
3918*7c478bd9Sstevel@tonic-gate 
3919*7c478bd9Sstevel@tonic-gate 	/*
3920*7c478bd9Sstevel@tonic-gate 	 * Decide whether the SAP value selects EtherType encoding/decoding.
3921*7c478bd9Sstevel@tonic-gate 	 * For compatibility with monolithic ethernet drivers, the range of
3922*7c478bd9Sstevel@tonic-gate 	 * SAP values is different for DL_ETHER media.
3923*7c478bd9Sstevel@tonic-gate 	 */
3924*7c478bd9Sstevel@tonic-gate 	switch (macinfo->gldm_type) {
3925*7c478bd9Sstevel@tonic-gate 	case DL_ETHER:
3926*7c478bd9Sstevel@tonic-gate 		gld->gld_ethertype = (sap > ETHERMTU);
3927*7c478bd9Sstevel@tonic-gate 		break;
3928*7c478bd9Sstevel@tonic-gate 	default:
3929*7c478bd9Sstevel@tonic-gate 		gld->gld_ethertype = (sap > GLD_MAX_802_SAP);
3930*7c478bd9Sstevel@tonic-gate 		break;
3931*7c478bd9Sstevel@tonic-gate 	}
3932*7c478bd9Sstevel@tonic-gate 
3933*7c478bd9Sstevel@tonic-gate 	/* if we get to here, then the SAP is legal enough */
3934*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
3935*7c478bd9Sstevel@tonic-gate 	gld->gld_state = DL_IDLE;	/* bound and ready */
3936*7c478bd9Sstevel@tonic-gate 	gld->gld_sap = sap;
3937*7c478bd9Sstevel@tonic-gate 	gld_set_ipq(gld);
3938*7c478bd9Sstevel@tonic-gate 
3939*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
3940*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT)
3941*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_bind: ok - sap = %d", gld->gld_sap);
3942*7c478bd9Sstevel@tonic-gate #endif
3943*7c478bd9Sstevel@tonic-gate 
3944*7c478bd9Sstevel@tonic-gate 	/* ACK the BIND */
3945*7c478bd9Sstevel@tonic-gate 	mp = gld_bindack(q, mp);
3946*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
3947*7c478bd9Sstevel@tonic-gate 
3948*7c478bd9Sstevel@tonic-gate 	if (mp != NULL) {
3949*7c478bd9Sstevel@tonic-gate 		qreply(q, mp);
3950*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
3951*7c478bd9Sstevel@tonic-gate 	}
3952*7c478bd9Sstevel@tonic-gate 
3953*7c478bd9Sstevel@tonic-gate 	return (DL_SYSERR);
3954*7c478bd9Sstevel@tonic-gate }
3955*7c478bd9Sstevel@tonic-gate 
3956*7c478bd9Sstevel@tonic-gate /*
3957*7c478bd9Sstevel@tonic-gate  * gld_unbind - perform an unbind of an LSAP or ether type on the stream.
3958*7c478bd9Sstevel@tonic-gate  * The stream is still open and can be re-bound.
3959*7c478bd9Sstevel@tonic-gate  */
3960*7c478bd9Sstevel@tonic-gate static int
3961*7c478bd9Sstevel@tonic-gate gld_unbind(queue_t *q, mblk_t *mp)
3962*7c478bd9Sstevel@tonic-gate {
3963*7c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
3964*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
3965*7c478bd9Sstevel@tonic-gate 
3966*7c478bd9Sstevel@tonic-gate 	ASSERT(gld);
3967*7c478bd9Sstevel@tonic-gate 
3968*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
3969*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
3970*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_unbind(%p %p)", (void *)q, (void *)mp);
3971*7c478bd9Sstevel@tonic-gate #endif
3972*7c478bd9Sstevel@tonic-gate 
3973*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state != DL_IDLE) {
3974*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
3975*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
3976*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unbind: wrong state (%d)",
3977*7c478bd9Sstevel@tonic-gate 				gld->gld_state);
3978*7c478bd9Sstevel@tonic-gate #endif
3979*7c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
3980*7c478bd9Sstevel@tonic-gate 	}
3981*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo);
3982*7c478bd9Sstevel@tonic-gate 
3983*7c478bd9Sstevel@tonic-gate 	/*
3984*7c478bd9Sstevel@tonic-gate 	 * Avoid unbinding (DL_UNBIND_REQ) while FAST/RAW is inside wput.
3985*7c478bd9Sstevel@tonic-gate 	 * See comments above gld_start().
3986*7c478bd9Sstevel@tonic-gate 	 */
3987*7c478bd9Sstevel@tonic-gate 	gld->gld_in_unbind = B_TRUE;	/* disallow wput=>start */
3988*7c478bd9Sstevel@tonic-gate 	membar_enter();
3989*7c478bd9Sstevel@tonic-gate 	if (gld->gld_wput_count != 0) {
3990*7c478bd9Sstevel@tonic-gate 		gld->gld_in_unbind = B_FALSE;
3991*7c478bd9Sstevel@tonic-gate 		ASSERT(mp);		/* we didn't come from close */
3992*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
3993*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDETRACE)
3994*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unbind: defer for wput");
3995*7c478bd9Sstevel@tonic-gate #endif
3996*7c478bd9Sstevel@tonic-gate 		(void) putbq(q, mp);
3997*7c478bd9Sstevel@tonic-gate 		qenable(q);		/* try again soon */
3998*7c478bd9Sstevel@tonic-gate 		return (GLDE_RETRY);
3999*7c478bd9Sstevel@tonic-gate 	}
4000*7c478bd9Sstevel@tonic-gate 
4001*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
4002*7c478bd9Sstevel@tonic-gate 	gld->gld_state = DL_UNBOUND;
4003*7c478bd9Sstevel@tonic-gate 	gld->gld_sap = 0;
4004*7c478bd9Sstevel@tonic-gate 	gld_set_ipq(gld);
4005*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
4006*7c478bd9Sstevel@tonic-gate 
4007*7c478bd9Sstevel@tonic-gate 	membar_exit();
4008*7c478bd9Sstevel@tonic-gate 	gld->gld_in_unbind = B_FALSE;
4009*7c478bd9Sstevel@tonic-gate 
4010*7c478bd9Sstevel@tonic-gate 	/* mp is NULL if we came from close */
4011*7c478bd9Sstevel@tonic-gate 	if (mp) {
4012*7c478bd9Sstevel@tonic-gate 		gld_flushqueue(q);	/* flush the queues */
4013*7c478bd9Sstevel@tonic-gate 		dlokack(q, mp, DL_UNBIND_REQ);
4014*7c478bd9Sstevel@tonic-gate 	}
4015*7c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
4016*7c478bd9Sstevel@tonic-gate }
4017*7c478bd9Sstevel@tonic-gate 
4018*7c478bd9Sstevel@tonic-gate /*
4019*7c478bd9Sstevel@tonic-gate  * gld_inforeq - generate the response to an info request
4020*7c478bd9Sstevel@tonic-gate  */
4021*7c478bd9Sstevel@tonic-gate static int
4022*7c478bd9Sstevel@tonic-gate gld_inforeq(queue_t *q, mblk_t *mp)
4023*7c478bd9Sstevel@tonic-gate {
4024*7c478bd9Sstevel@tonic-gate 	gld_t		*gld;
4025*7c478bd9Sstevel@tonic-gate 	dl_info_ack_t	*dlp;
4026*7c478bd9Sstevel@tonic-gate 	int		bufsize;
4027*7c478bd9Sstevel@tonic-gate 	glddev_t	*glddev;
4028*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*macinfo;
4029*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt;
4030*7c478bd9Sstevel@tonic-gate 	int		sel_offset = 0;
4031*7c478bd9Sstevel@tonic-gate 	int		range_offset = 0;
4032*7c478bd9Sstevel@tonic-gate 	int		addr_offset;
4033*7c478bd9Sstevel@tonic-gate 	int		addr_length;
4034*7c478bd9Sstevel@tonic-gate 	int		sap_length;
4035*7c478bd9Sstevel@tonic-gate 	int		brdcst_offset;
4036*7c478bd9Sstevel@tonic-gate 	int		brdcst_length;
4037*7c478bd9Sstevel@tonic-gate 	gld_vlan_t	*vlan;
4038*7c478bd9Sstevel@tonic-gate 	uchar_t		*sapp;
4039*7c478bd9Sstevel@tonic-gate 
4040*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
4041*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
4042*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_inforeq(%p %p)", (void *)q, (void *)mp);
4043*7c478bd9Sstevel@tonic-gate #endif
4044*7c478bd9Sstevel@tonic-gate 	gld = (gld_t *)q->q_ptr;
4045*7c478bd9Sstevel@tonic-gate 	ASSERT(gld);
4046*7c478bd9Sstevel@tonic-gate 	glddev = gld->gld_device;
4047*7c478bd9Sstevel@tonic-gate 	ASSERT(glddev);
4048*7c478bd9Sstevel@tonic-gate 
4049*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_IDLE || gld->gld_state == DL_UNBOUND) {
4050*7c478bd9Sstevel@tonic-gate 		macinfo = gld->gld_mac_info;
4051*7c478bd9Sstevel@tonic-gate 		ASSERT(macinfo != NULL);
4052*7c478bd9Sstevel@tonic-gate 
4053*7c478bd9Sstevel@tonic-gate 		mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
4054*7c478bd9Sstevel@tonic-gate 
4055*7c478bd9Sstevel@tonic-gate 		addr_length = macinfo->gldm_addrlen;
4056*7c478bd9Sstevel@tonic-gate 		sap_length = macinfo->gldm_saplen;
4057*7c478bd9Sstevel@tonic-gate 		brdcst_length = macinfo->gldm_addrlen;
4058*7c478bd9Sstevel@tonic-gate 	} else {
4059*7c478bd9Sstevel@tonic-gate 		addr_length = glddev->gld_addrlen;
4060*7c478bd9Sstevel@tonic-gate 		sap_length = glddev->gld_saplen;
4061*7c478bd9Sstevel@tonic-gate 		brdcst_length = glddev->gld_addrlen;
4062*7c478bd9Sstevel@tonic-gate 	}
4063*7c478bd9Sstevel@tonic-gate 
4064*7c478bd9Sstevel@tonic-gate 	bufsize = sizeof (dl_info_ack_t);
4065*7c478bd9Sstevel@tonic-gate 
4066*7c478bd9Sstevel@tonic-gate 	addr_offset = bufsize;
4067*7c478bd9Sstevel@tonic-gate 	bufsize += addr_length;
4068*7c478bd9Sstevel@tonic-gate 	bufsize += abs(sap_length);
4069*7c478bd9Sstevel@tonic-gate 
4070*7c478bd9Sstevel@tonic-gate 	brdcst_offset = bufsize;
4071*7c478bd9Sstevel@tonic-gate 	bufsize += brdcst_length;
4072*7c478bd9Sstevel@tonic-gate 
4073*7c478bd9Sstevel@tonic-gate 	if ((vlan = (gld_vlan_t *)gld->gld_vlan) != NULL &&
4074*7c478bd9Sstevel@tonic-gate 	    vlan->gldv_id != VLAN_VID_NONE) {
4075*7c478bd9Sstevel@tonic-gate 		sel_offset = P2ROUNDUP(bufsize, sizeof (int64_t));
4076*7c478bd9Sstevel@tonic-gate 		bufsize = sel_offset + sizeof (dl_qos_cl_sel1_t);
4077*7c478bd9Sstevel@tonic-gate 
4078*7c478bd9Sstevel@tonic-gate 		range_offset = P2ROUNDUP(bufsize, sizeof (int64_t));
4079*7c478bd9Sstevel@tonic-gate 		bufsize = range_offset + sizeof (dl_qos_cl_range1_t);
4080*7c478bd9Sstevel@tonic-gate 	}
4081*7c478bd9Sstevel@tonic-gate 
4082*7c478bd9Sstevel@tonic-gate 	if ((mp = mexchange(q, mp, bufsize, M_PCPROTO, DL_INFO_ACK)) == NULL)
4083*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);	/* nothing more to be done */
4084*7c478bd9Sstevel@tonic-gate 
4085*7c478bd9Sstevel@tonic-gate 	bzero(mp->b_rptr, bufsize);
4086*7c478bd9Sstevel@tonic-gate 
4087*7c478bd9Sstevel@tonic-gate 	dlp = (dl_info_ack_t *)mp->b_rptr;
4088*7c478bd9Sstevel@tonic-gate 	dlp->dl_primitive = DL_INFO_ACK;
4089*7c478bd9Sstevel@tonic-gate 	dlp->dl_version = DL_VERSION_2;
4090*7c478bd9Sstevel@tonic-gate 	dlp->dl_service_mode = DL_CLDLS;
4091*7c478bd9Sstevel@tonic-gate 	dlp->dl_current_state = gld->gld_state;
4092*7c478bd9Sstevel@tonic-gate 	dlp->dl_provider_style = gld->gld_style;
4093*7c478bd9Sstevel@tonic-gate 
4094*7c478bd9Sstevel@tonic-gate 	if (sel_offset != 0) {
4095*7c478bd9Sstevel@tonic-gate 		dl_qos_cl_sel1_t	*selp;
4096*7c478bd9Sstevel@tonic-gate 		dl_qos_cl_range1_t	*rangep;
4097*7c478bd9Sstevel@tonic-gate 
4098*7c478bd9Sstevel@tonic-gate 		ASSERT(range_offset != 0);
4099*7c478bd9Sstevel@tonic-gate 
4100*7c478bd9Sstevel@tonic-gate 		dlp->dl_qos_offset = sel_offset;
4101*7c478bd9Sstevel@tonic-gate 		dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t);
4102*7c478bd9Sstevel@tonic-gate 		dlp->dl_qos_range_offset = range_offset;
4103*7c478bd9Sstevel@tonic-gate 		dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t);
4104*7c478bd9Sstevel@tonic-gate 
4105*7c478bd9Sstevel@tonic-gate 		selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + sel_offset);
4106*7c478bd9Sstevel@tonic-gate 		selp->dl_qos_type = DL_QOS_CL_SEL1;
4107*7c478bd9Sstevel@tonic-gate 		selp->dl_priority = gld->gld_upri;
4108*7c478bd9Sstevel@tonic-gate 
4109*7c478bd9Sstevel@tonic-gate 		rangep = (dl_qos_cl_range1_t *)(mp->b_rptr + range_offset);
4110*7c478bd9Sstevel@tonic-gate 		rangep->dl_qos_type = DL_QOS_CL_RANGE1;
4111*7c478bd9Sstevel@tonic-gate 		rangep->dl_priority.dl_min = 0;
4112*7c478bd9Sstevel@tonic-gate 		rangep->dl_priority.dl_max = 7;
4113*7c478bd9Sstevel@tonic-gate 	}
4114*7c478bd9Sstevel@tonic-gate 
4115*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_IDLE || gld->gld_state == DL_UNBOUND) {
4116*7c478bd9Sstevel@tonic-gate 		dlp->dl_min_sdu = macinfo->gldm_minpkt;
4117*7c478bd9Sstevel@tonic-gate 		dlp->dl_max_sdu = macinfo->gldm_maxpkt;
4118*7c478bd9Sstevel@tonic-gate 		dlp->dl_mac_type = macinfo->gldm_type;
4119*7c478bd9Sstevel@tonic-gate 		dlp->dl_addr_length = addr_length + abs(sap_length);
4120*7c478bd9Sstevel@tonic-gate 		dlp->dl_sap_length = sap_length;
4121*7c478bd9Sstevel@tonic-gate 
4122*7c478bd9Sstevel@tonic-gate 		if (gld->gld_state == DL_IDLE) {
4123*7c478bd9Sstevel@tonic-gate 			/*
4124*7c478bd9Sstevel@tonic-gate 			 * If we are bound to a non-LLC SAP on any medium
4125*7c478bd9Sstevel@tonic-gate 			 * other than Ethernet, then we need room for a
4126*7c478bd9Sstevel@tonic-gate 			 * SNAP header.  So we have to adjust the MTU size
4127*7c478bd9Sstevel@tonic-gate 			 * accordingly.  XXX I suppose this should be done
4128*7c478bd9Sstevel@tonic-gate 			 * in gldutil.c, but it seems likely that this will
4129*7c478bd9Sstevel@tonic-gate 			 * always be true for everything GLD supports but
4130*7c478bd9Sstevel@tonic-gate 			 * Ethernet.  Check this if you add another medium.
4131*7c478bd9Sstevel@tonic-gate 			 */
4132*7c478bd9Sstevel@tonic-gate 			if ((macinfo->gldm_type == DL_TPR ||
4133*7c478bd9Sstevel@tonic-gate 			    macinfo->gldm_type == DL_FDDI) &&
4134*7c478bd9Sstevel@tonic-gate 			    gld->gld_ethertype)
4135*7c478bd9Sstevel@tonic-gate 				dlp->dl_max_sdu -= LLC_SNAP_HDR_LEN;
4136*7c478bd9Sstevel@tonic-gate 
4137*7c478bd9Sstevel@tonic-gate 			/* copy macaddr and sap */
4138*7c478bd9Sstevel@tonic-gate 			dlp->dl_addr_offset = addr_offset;
4139*7c478bd9Sstevel@tonic-gate 
4140*7c478bd9Sstevel@tonic-gate 			mac_copy(mac_pvt->curr_macaddr, mp->b_rptr +
4141*7c478bd9Sstevel@tonic-gate 			    addr_offset, macinfo->gldm_addrlen);
4142*7c478bd9Sstevel@tonic-gate 			sapp = mp->b_rptr + addr_offset +
4143*7c478bd9Sstevel@tonic-gate 			    macinfo->gldm_addrlen;
4144*7c478bd9Sstevel@tonic-gate 			*(ushort_t *)sapp = gld->gld_sap;
4145*7c478bd9Sstevel@tonic-gate 		} else {
4146*7c478bd9Sstevel@tonic-gate 			dlp->dl_addr_offset = 0;
4147*7c478bd9Sstevel@tonic-gate 		}
4148*7c478bd9Sstevel@tonic-gate 
4149*7c478bd9Sstevel@tonic-gate 		/* copy broadcast addr */
4150*7c478bd9Sstevel@tonic-gate 		dlp->dl_brdcst_addr_length = macinfo->gldm_addrlen;
4151*7c478bd9Sstevel@tonic-gate 		dlp->dl_brdcst_addr_offset = brdcst_offset;
4152*7c478bd9Sstevel@tonic-gate 		mac_copy((caddr_t)macinfo->gldm_broadcast_addr,
4153*7c478bd9Sstevel@tonic-gate 		    mp->b_rptr + brdcst_offset, brdcst_length);
4154*7c478bd9Sstevel@tonic-gate 	} else {
4155*7c478bd9Sstevel@tonic-gate 		/*
4156*7c478bd9Sstevel@tonic-gate 		 * No PPA is attached.
4157*7c478bd9Sstevel@tonic-gate 		 * The best we can do is use the values provided
4158*7c478bd9Sstevel@tonic-gate 		 * by the first mac that called gld_register.
4159*7c478bd9Sstevel@tonic-gate 		 */
4160*7c478bd9Sstevel@tonic-gate 		dlp->dl_min_sdu = glddev->gld_minsdu;
4161*7c478bd9Sstevel@tonic-gate 		dlp->dl_max_sdu = glddev->gld_maxsdu;
4162*7c478bd9Sstevel@tonic-gate 		dlp->dl_mac_type = glddev->gld_type;
4163*7c478bd9Sstevel@tonic-gate 		dlp->dl_addr_length = addr_length + abs(sap_length);
4164*7c478bd9Sstevel@tonic-gate 		dlp->dl_sap_length = sap_length;
4165*7c478bd9Sstevel@tonic-gate 		dlp->dl_addr_offset = 0;
4166*7c478bd9Sstevel@tonic-gate 		dlp->dl_brdcst_addr_offset = brdcst_offset;
4167*7c478bd9Sstevel@tonic-gate 		dlp->dl_brdcst_addr_length = brdcst_length;
4168*7c478bd9Sstevel@tonic-gate 		mac_copy((caddr_t)glddev->gld_broadcast,
4169*7c478bd9Sstevel@tonic-gate 		    mp->b_rptr + brdcst_offset, brdcst_length);
4170*7c478bd9Sstevel@tonic-gate 	}
4171*7c478bd9Sstevel@tonic-gate 	qreply(q, mp);
4172*7c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
4173*7c478bd9Sstevel@tonic-gate }
4174*7c478bd9Sstevel@tonic-gate 
4175*7c478bd9Sstevel@tonic-gate /*
4176*7c478bd9Sstevel@tonic-gate  * gld_unitdata (q, mp)
4177*7c478bd9Sstevel@tonic-gate  * send a datagram.  Destination address/lsap is in M_PROTO
4178*7c478bd9Sstevel@tonic-gate  * message (first mblock), data is in remainder of message.
4179*7c478bd9Sstevel@tonic-gate  *
4180*7c478bd9Sstevel@tonic-gate  */
4181*7c478bd9Sstevel@tonic-gate static int
4182*7c478bd9Sstevel@tonic-gate gld_unitdata(queue_t *q, mblk_t *mp)
4183*7c478bd9Sstevel@tonic-gate {
4184*7c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
4185*7c478bd9Sstevel@tonic-gate 	dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
4186*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
4187*7c478bd9Sstevel@tonic-gate 	size_t	msglen;
4188*7c478bd9Sstevel@tonic-gate 	mblk_t	*nmp;
4189*7c478bd9Sstevel@tonic-gate 	gld_interface_t *ifp;
4190*7c478bd9Sstevel@tonic-gate 	uint32_t start;
4191*7c478bd9Sstevel@tonic-gate 	uint32_t stuff;
4192*7c478bd9Sstevel@tonic-gate 	uint32_t end;
4193*7c478bd9Sstevel@tonic-gate 	uint32_t value;
4194*7c478bd9Sstevel@tonic-gate 	uint32_t flags;
4195*7c478bd9Sstevel@tonic-gate 	uint32_t upri;
4196*7c478bd9Sstevel@tonic-gate 
4197*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
4198*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
4199*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_unitdata(%p %p)", (void *)q, (void *)mp);
4200*7c478bd9Sstevel@tonic-gate #endif
4201*7c478bd9Sstevel@tonic-gate 
4202*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state != DL_IDLE) {
4203*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
4204*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
4205*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unitdata: wrong state (%d)",
4206*7c478bd9Sstevel@tonic-gate 				gld->gld_state);
4207*7c478bd9Sstevel@tonic-gate #endif
4208*7c478bd9Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
4209*7c478bd9Sstevel@tonic-gate 		    dlp->dl_dest_addr_length, DL_OUTSTATE, 0);
4210*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
4211*7c478bd9Sstevel@tonic-gate 	}
4212*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
4213*7c478bd9Sstevel@tonic-gate 
4214*7c478bd9Sstevel@tonic-gate 	if (!MBLKIN(mp, dlp->dl_dest_addr_offset, dlp->dl_dest_addr_length) ||
4215*7c478bd9Sstevel@tonic-gate 	    dlp->dl_dest_addr_length !=
4216*7c478bd9Sstevel@tonic-gate 	    macinfo->gldm_addrlen + abs(macinfo->gldm_saplen)) {
4217*7c478bd9Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
4218*7c478bd9Sstevel@tonic-gate 		    dlp->dl_dest_addr_length, DL_BADADDR, 0);
4219*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
4220*7c478bd9Sstevel@tonic-gate 	}
4221*7c478bd9Sstevel@tonic-gate 
4222*7c478bd9Sstevel@tonic-gate 	upri = dlp->dl_priority.dl_max;
4223*7c478bd9Sstevel@tonic-gate 
4224*7c478bd9Sstevel@tonic-gate 	msglen = msgdsize(mp);
4225*7c478bd9Sstevel@tonic-gate 	if (msglen == 0 || msglen > macinfo->gldm_maxpkt) {
4226*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
4227*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
4228*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unitdata: bad msglen (%d)",
4229*7c478bd9Sstevel@tonic-gate 				(int)msglen);
4230*7c478bd9Sstevel@tonic-gate #endif
4231*7c478bd9Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
4232*7c478bd9Sstevel@tonic-gate 		    dlp->dl_dest_addr_length, DL_BADDATA, 0);
4233*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
4234*7c478bd9Sstevel@tonic-gate 	}
4235*7c478bd9Sstevel@tonic-gate 
4236*7c478bd9Sstevel@tonic-gate 	ASSERT(mp->b_cont != NULL);	/* because msgdsize(mp) is nonzero */
4237*7c478bd9Sstevel@tonic-gate 
4238*7c478bd9Sstevel@tonic-gate 	ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
4239*7c478bd9Sstevel@tonic-gate 
4240*7c478bd9Sstevel@tonic-gate 	/* grab any checksum information that may be present */
4241*7c478bd9Sstevel@tonic-gate 	hcksum_retrieve(mp->b_cont, NULL, NULL, &start, &stuff, &end,
4242*7c478bd9Sstevel@tonic-gate 	    &value, &flags);
4243*7c478bd9Sstevel@tonic-gate 
4244*7c478bd9Sstevel@tonic-gate 	/*
4245*7c478bd9Sstevel@tonic-gate 	 * Prepend a valid header for transmission
4246*7c478bd9Sstevel@tonic-gate 	 */
4247*7c478bd9Sstevel@tonic-gate 	if ((nmp = (*ifp->mkunitdata)(gld, mp)) == NULL) {
4248*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
4249*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDERRS)
4250*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gld_unitdata: mkunitdata failed.");
4251*7c478bd9Sstevel@tonic-gate #endif
4252*7c478bd9Sstevel@tonic-gate 		dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
4253*7c478bd9Sstevel@tonic-gate 		    dlp->dl_dest_addr_length, DL_SYSERR, ENOSR);
4254*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
4255*7c478bd9Sstevel@tonic-gate 	}
4256*7c478bd9Sstevel@tonic-gate 
4257*7c478bd9Sstevel@tonic-gate 	/* apply any checksum information to the first block in the chain */
4258*7c478bd9Sstevel@tonic-gate 	(void) hcksum_assoc(nmp, NULL, NULL, start, stuff, end, value,
4259*7c478bd9Sstevel@tonic-gate 	    flags, 0);
4260*7c478bd9Sstevel@tonic-gate 
4261*7c478bd9Sstevel@tonic-gate 	if (gld_start(q, nmp, GLD_WSRV, upri) == GLD_NORESOURCES) {
4262*7c478bd9Sstevel@tonic-gate 		qenable(q);
4263*7c478bd9Sstevel@tonic-gate 		return (GLDE_RETRY);
4264*7c478bd9Sstevel@tonic-gate 	}
4265*7c478bd9Sstevel@tonic-gate 
4266*7c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
4267*7c478bd9Sstevel@tonic-gate }
4268*7c478bd9Sstevel@tonic-gate 
4269*7c478bd9Sstevel@tonic-gate /*
4270*7c478bd9Sstevel@tonic-gate  * gldattach(q, mp)
4271*7c478bd9Sstevel@tonic-gate  * DLPI DL_ATTACH_REQ
4272*7c478bd9Sstevel@tonic-gate  * this attaches the stream to a PPA
4273*7c478bd9Sstevel@tonic-gate  */
4274*7c478bd9Sstevel@tonic-gate static int
4275*7c478bd9Sstevel@tonic-gate gldattach(queue_t *q, mblk_t *mp)
4276*7c478bd9Sstevel@tonic-gate {
4277*7c478bd9Sstevel@tonic-gate 	dl_attach_req_t *at;
4278*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
4279*7c478bd9Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
4280*7c478bd9Sstevel@tonic-gate 	glddev_t *glddev;
4281*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
4282*7c478bd9Sstevel@tonic-gate 	uint32_t ppa;
4283*7c478bd9Sstevel@tonic-gate 	uint32_t vid;
4284*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
4285*7c478bd9Sstevel@tonic-gate 
4286*7c478bd9Sstevel@tonic-gate 	at = (dl_attach_req_t *)mp->b_rptr;
4287*7c478bd9Sstevel@tonic-gate 
4288*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state != DL_UNATTACHED)
4289*7c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
4290*7c478bd9Sstevel@tonic-gate 
4291*7c478bd9Sstevel@tonic-gate 	ASSERT(!gld->gld_mac_info);
4292*7c478bd9Sstevel@tonic-gate 
4293*7c478bd9Sstevel@tonic-gate 	ppa = at->dl_ppa % GLD_VLAN_SCALE;	/* 0 .. 999	*/
4294*7c478bd9Sstevel@tonic-gate 	vid = at->dl_ppa / GLD_VLAN_SCALE;	/* 0 .. 4094	*/
4295*7c478bd9Sstevel@tonic-gate 	if (vid > VLAN_VID_MAX)
4296*7c478bd9Sstevel@tonic-gate 		return (DL_BADPPA);
4297*7c478bd9Sstevel@tonic-gate 
4298*7c478bd9Sstevel@tonic-gate 	glddev = gld->gld_device;
4299*7c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
4300*7c478bd9Sstevel@tonic-gate 	for (macinfo = glddev->gld_mac_next;
4301*7c478bd9Sstevel@tonic-gate 	    macinfo != (gld_mac_info_t *)&glddev->gld_mac_next;
4302*7c478bd9Sstevel@tonic-gate 	    macinfo = macinfo->gldm_next) {
4303*7c478bd9Sstevel@tonic-gate 		int inst;
4304*7c478bd9Sstevel@tonic-gate 
4305*7c478bd9Sstevel@tonic-gate 		ASSERT(macinfo != NULL);
4306*7c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_ppa != ppa)
4307*7c478bd9Sstevel@tonic-gate 			continue;
4308*7c478bd9Sstevel@tonic-gate 
4309*7c478bd9Sstevel@tonic-gate 		if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY))
4310*7c478bd9Sstevel@tonic-gate 			continue;	/* this one's not ready yet */
4311*7c478bd9Sstevel@tonic-gate 
4312*7c478bd9Sstevel@tonic-gate 		/*
4313*7c478bd9Sstevel@tonic-gate 		 * VLAN sanity check
4314*7c478bd9Sstevel@tonic-gate 		 */
4315*7c478bd9Sstevel@tonic-gate 		if (vid != VLAN_VID_NONE && !VLAN_CAPABLE(macinfo)) {
4316*7c478bd9Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
4317*7c478bd9Sstevel@tonic-gate 			return (DL_BADPPA);
4318*7c478bd9Sstevel@tonic-gate 		}
4319*7c478bd9Sstevel@tonic-gate 
4320*7c478bd9Sstevel@tonic-gate 		/*
4321*7c478bd9Sstevel@tonic-gate 		 * We found the correct PPA, hold the instance
4322*7c478bd9Sstevel@tonic-gate 		 */
4323*7c478bd9Sstevel@tonic-gate 		inst = ddi_get_instance(macinfo->gldm_devinfo);
4324*7c478bd9Sstevel@tonic-gate 		if (inst == -1 || qassociate(q, inst) != 0) {
4325*7c478bd9Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
4326*7c478bd9Sstevel@tonic-gate 			return (DL_BADPPA);
4327*7c478bd9Sstevel@tonic-gate 		}
4328*7c478bd9Sstevel@tonic-gate 
4329*7c478bd9Sstevel@tonic-gate 		/* Take the stream off the per-driver-class list */
4330*7c478bd9Sstevel@tonic-gate 		gldremque(gld);
4331*7c478bd9Sstevel@tonic-gate 
4332*7c478bd9Sstevel@tonic-gate 		/*
4333*7c478bd9Sstevel@tonic-gate 		 * We must hold the lock to prevent multiple calls
4334*7c478bd9Sstevel@tonic-gate 		 * to the reset and start routines.
4335*7c478bd9Sstevel@tonic-gate 		 */
4336*7c478bd9Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
4337*7c478bd9Sstevel@tonic-gate 
4338*7c478bd9Sstevel@tonic-gate 		gld->gld_mac_info = macinfo;
4339*7c478bd9Sstevel@tonic-gate 
4340*7c478bd9Sstevel@tonic-gate 		if (macinfo->gldm_send_tagged != NULL)
4341*7c478bd9Sstevel@tonic-gate 			gld->gld_send = macinfo->gldm_send_tagged;
4342*7c478bd9Sstevel@tonic-gate 		else
4343*7c478bd9Sstevel@tonic-gate 			gld->gld_send = macinfo->gldm_send;
4344*7c478bd9Sstevel@tonic-gate 
4345*7c478bd9Sstevel@tonic-gate 		if ((vlan = gld_get_vlan(macinfo, vid)) == NULL) {
4346*7c478bd9Sstevel@tonic-gate 			GLDM_UNLOCK(macinfo);
4347*7c478bd9Sstevel@tonic-gate 			gldinsque(gld, glddev->gld_str_prev);
4348*7c478bd9Sstevel@tonic-gate 			mutex_exit(&glddev->gld_devlock);
4349*7c478bd9Sstevel@tonic-gate 			(void) qassociate(q, -1);
4350*7c478bd9Sstevel@tonic-gate 			return (DL_BADPPA);
4351*7c478bd9Sstevel@tonic-gate 		}
4352*7c478bd9Sstevel@tonic-gate 
4353*7c478bd9Sstevel@tonic-gate 		mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
4354*7c478bd9Sstevel@tonic-gate 		if (!mac_pvt->started) {
4355*7c478bd9Sstevel@tonic-gate 			if (gld_start_mac(macinfo) != GLD_SUCCESS) {
4356*7c478bd9Sstevel@tonic-gate 				gld_rem_vlan(vlan);
4357*7c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
4358*7c478bd9Sstevel@tonic-gate 				gldinsque(gld, glddev->gld_str_prev);
4359*7c478bd9Sstevel@tonic-gate 				mutex_exit(&glddev->gld_devlock);
4360*7c478bd9Sstevel@tonic-gate 				dlerrorack(q, mp, DL_ATTACH_REQ, DL_SYSERR,
4361*7c478bd9Sstevel@tonic-gate 				    EIO);
4362*7c478bd9Sstevel@tonic-gate 				(void) qassociate(q, -1);
4363*7c478bd9Sstevel@tonic-gate 				return (GLDE_OK);
4364*7c478bd9Sstevel@tonic-gate 			}
4365*7c478bd9Sstevel@tonic-gate 		}
4366*7c478bd9Sstevel@tonic-gate 
4367*7c478bd9Sstevel@tonic-gate 		gld->gld_vlan = vlan;
4368*7c478bd9Sstevel@tonic-gate 		vlan->gldv_nstreams++;
4369*7c478bd9Sstevel@tonic-gate 		gldinsque(gld, vlan->gldv_str_prev);
4370*7c478bd9Sstevel@tonic-gate 		gld->gld_state = DL_UNBOUND;
4371*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
4372*7c478bd9Sstevel@tonic-gate 
4373*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
4374*7c478bd9Sstevel@tonic-gate 		if (gld_debug & GLDPROT) {
4375*7c478bd9Sstevel@tonic-gate 			cmn_err(CE_NOTE, "gldattach(%p, %p, PPA = %d)",
4376*7c478bd9Sstevel@tonic-gate 			    (void *)q, (void *)mp, macinfo->gldm_ppa);
4377*7c478bd9Sstevel@tonic-gate 		}
4378*7c478bd9Sstevel@tonic-gate #endif
4379*7c478bd9Sstevel@tonic-gate 		mutex_exit(&glddev->gld_devlock);
4380*7c478bd9Sstevel@tonic-gate 		dlokack(q, mp, DL_ATTACH_REQ);
4381*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
4382*7c478bd9Sstevel@tonic-gate 	}
4383*7c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
4384*7c478bd9Sstevel@tonic-gate 	return (DL_BADPPA);
4385*7c478bd9Sstevel@tonic-gate }
4386*7c478bd9Sstevel@tonic-gate 
4387*7c478bd9Sstevel@tonic-gate /*
4388*7c478bd9Sstevel@tonic-gate  * gldunattach(q, mp)
4389*7c478bd9Sstevel@tonic-gate  * DLPI DL_DETACH_REQ
4390*7c478bd9Sstevel@tonic-gate  * detaches the mac layer from the stream
4391*7c478bd9Sstevel@tonic-gate  */
4392*7c478bd9Sstevel@tonic-gate int
4393*7c478bd9Sstevel@tonic-gate gldunattach(queue_t *q, mblk_t *mp)
4394*7c478bd9Sstevel@tonic-gate {
4395*7c478bd9Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
4396*7c478bd9Sstevel@tonic-gate 	glddev_t *glddev = gld->gld_device;
4397*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
4398*7c478bd9Sstevel@tonic-gate 	int	state = gld->gld_state;
4399*7c478bd9Sstevel@tonic-gate 	int	i;
4400*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
4401*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
4402*7c478bd9Sstevel@tonic-gate 	boolean_t phys_off;
4403*7c478bd9Sstevel@tonic-gate 	boolean_t mult_off;
4404*7c478bd9Sstevel@tonic-gate 	int op = GLD_MAC_PROMISC_NOOP;
4405*7c478bd9Sstevel@tonic-gate 
4406*7c478bd9Sstevel@tonic-gate 	if (state != DL_UNBOUND)
4407*7c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
4408*7c478bd9Sstevel@tonic-gate 
4409*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
4410*7c478bd9Sstevel@tonic-gate 	ASSERT(gld->gld_sap == 0);
4411*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
4412*7c478bd9Sstevel@tonic-gate 
4413*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
4414*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
4415*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gldunattach(%p, %p, PPA = %d)",
4416*7c478bd9Sstevel@tonic-gate 		    (void *)q, (void *)mp, macinfo->gldm_ppa);
4417*7c478bd9Sstevel@tonic-gate 	}
4418*7c478bd9Sstevel@tonic-gate #endif
4419*7c478bd9Sstevel@tonic-gate 
4420*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
4421*7c478bd9Sstevel@tonic-gate 
4422*7c478bd9Sstevel@tonic-gate 	if (gld->gld_mcast) {
4423*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < gld->gld_multicnt; i++) {
4424*7c478bd9Sstevel@tonic-gate 			gld_mcast_t *mcast;
4425*7c478bd9Sstevel@tonic-gate 
4426*7c478bd9Sstevel@tonic-gate 			if ((mcast = gld->gld_mcast[i]) != NULL) {
4427*7c478bd9Sstevel@tonic-gate 				ASSERT(mcast->gldm_refcnt);
4428*7c478bd9Sstevel@tonic-gate 				gld_send_disable_multi(macinfo, mcast);
4429*7c478bd9Sstevel@tonic-gate 			}
4430*7c478bd9Sstevel@tonic-gate 		}
4431*7c478bd9Sstevel@tonic-gate 		kmem_free(gld->gld_mcast,
4432*7c478bd9Sstevel@tonic-gate 		    sizeof (gld_mcast_t *) * gld->gld_multicnt);
4433*7c478bd9Sstevel@tonic-gate 		gld->gld_mcast = NULL;
4434*7c478bd9Sstevel@tonic-gate 		gld->gld_multicnt = 0;
4435*7c478bd9Sstevel@tonic-gate 	}
4436*7c478bd9Sstevel@tonic-gate 
4437*7c478bd9Sstevel@tonic-gate 	/* decide if we need to turn off any promiscuity */
4438*7c478bd9Sstevel@tonic-gate 	phys_off = (gld->gld_flags & GLD_PROM_PHYS &&
4439*7c478bd9Sstevel@tonic-gate 	    --mac_pvt->nprom == 0);
4440*7c478bd9Sstevel@tonic-gate 	mult_off = (gld->gld_flags & GLD_PROM_MULT &&
4441*7c478bd9Sstevel@tonic-gate 	    --mac_pvt->nprom_multi == 0);
4442*7c478bd9Sstevel@tonic-gate 
4443*7c478bd9Sstevel@tonic-gate 	gld->gld_flags &= ~(GLD_PROM_PHYS | GLD_PROM_SAP | GLD_PROM_MULT);
4444*7c478bd9Sstevel@tonic-gate 
4445*7c478bd9Sstevel@tonic-gate 	if (phys_off) {
4446*7c478bd9Sstevel@tonic-gate 		op = (mac_pvt->nprom_multi == 0) ? GLD_MAC_PROMISC_NONE :
4447*7c478bd9Sstevel@tonic-gate 		    GLD_MAC_PROMISC_MULTI;
4448*7c478bd9Sstevel@tonic-gate 	} else if (mult_off) {
4449*7c478bd9Sstevel@tonic-gate 		op = (mac_pvt->nprom == 0) ? GLD_MAC_PROMISC_NONE :
4450*7c478bd9Sstevel@tonic-gate 		    GLD_MAC_PROMISC_NOOP;	/* phys overrides multi */
4451*7c478bd9Sstevel@tonic-gate 	}
4452*7c478bd9Sstevel@tonic-gate 
4453*7c478bd9Sstevel@tonic-gate 	if (op != GLD_MAC_PROMISC_NOOP)
4454*7c478bd9Sstevel@tonic-gate 		(void) (*macinfo->gldm_set_promiscuous)(macinfo, op);
4455*7c478bd9Sstevel@tonic-gate 
4456*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
4457*7c478bd9Sstevel@tonic-gate 
4458*7c478bd9Sstevel@tonic-gate 	if (phys_off)
4459*7c478bd9Sstevel@tonic-gate 		gld_notify_ind(macinfo, DL_NOTE_PROMISC_OFF_PHYS, NULL);
4460*7c478bd9Sstevel@tonic-gate 
4461*7c478bd9Sstevel@tonic-gate 	/*
4462*7c478bd9Sstevel@tonic-gate 	 * We need to hold both locks when modifying the mac stream list
4463*7c478bd9Sstevel@tonic-gate 	 * to protect findminor as well as everyone else.
4464*7c478bd9Sstevel@tonic-gate 	 */
4465*7c478bd9Sstevel@tonic-gate 	mutex_enter(&glddev->gld_devlock);
4466*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
4467*7c478bd9Sstevel@tonic-gate 
4468*7c478bd9Sstevel@tonic-gate 	/* disassociate this stream with its vlan and underlying mac */
4469*7c478bd9Sstevel@tonic-gate 	gldremque(gld);
4470*7c478bd9Sstevel@tonic-gate 
4471*7c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
4472*7c478bd9Sstevel@tonic-gate 	if (--vlan->gldv_nstreams == 0) {
4473*7c478bd9Sstevel@tonic-gate 		gld_rem_vlan(vlan);
4474*7c478bd9Sstevel@tonic-gate 		gld->gld_vlan = NULL;
4475*7c478bd9Sstevel@tonic-gate 	}
4476*7c478bd9Sstevel@tonic-gate 
4477*7c478bd9Sstevel@tonic-gate 	gld->gld_mac_info = NULL;
4478*7c478bd9Sstevel@tonic-gate 	gld->gld_state = DL_UNATTACHED;
4479*7c478bd9Sstevel@tonic-gate 
4480*7c478bd9Sstevel@tonic-gate 	/* cleanup mac layer if last vlan */
4481*7c478bd9Sstevel@tonic-gate 	if (mac_pvt->nvlan == 0) {
4482*7c478bd9Sstevel@tonic-gate 		gld_stop_mac(macinfo);
4483*7c478bd9Sstevel@tonic-gate 		macinfo->gldm_GLD_flags &= ~GLD_INTR_WAIT;
4484*7c478bd9Sstevel@tonic-gate 	}
4485*7c478bd9Sstevel@tonic-gate 
4486*7c478bd9Sstevel@tonic-gate 	/* make sure no references to this gld for gld_v0_sched */
4487*7c478bd9Sstevel@tonic-gate 	if (mac_pvt->last_sched == gld)
4488*7c478bd9Sstevel@tonic-gate 		mac_pvt->last_sched = NULL;
4489*7c478bd9Sstevel@tonic-gate 
4490*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
4491*7c478bd9Sstevel@tonic-gate 
4492*7c478bd9Sstevel@tonic-gate 	/* put the stream on the unattached Style 2 list */
4493*7c478bd9Sstevel@tonic-gate 	gldinsque(gld, glddev->gld_str_prev);
4494*7c478bd9Sstevel@tonic-gate 
4495*7c478bd9Sstevel@tonic-gate 	mutex_exit(&glddev->gld_devlock);
4496*7c478bd9Sstevel@tonic-gate 
4497*7c478bd9Sstevel@tonic-gate 	/* There will be no mp if we were called from close */
4498*7c478bd9Sstevel@tonic-gate 	if (mp) {
4499*7c478bd9Sstevel@tonic-gate 		dlokack(q, mp, DL_DETACH_REQ);
4500*7c478bd9Sstevel@tonic-gate 	}
4501*7c478bd9Sstevel@tonic-gate 	if (gld->gld_style == DL_STYLE2)
4502*7c478bd9Sstevel@tonic-gate 		(void) qassociate(q, -1);
4503*7c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
4504*7c478bd9Sstevel@tonic-gate }
4505*7c478bd9Sstevel@tonic-gate 
4506*7c478bd9Sstevel@tonic-gate /*
4507*7c478bd9Sstevel@tonic-gate  * gld_enable_multi (q, mp)
4508*7c478bd9Sstevel@tonic-gate  * Enables multicast address on the stream.  If the mac layer
4509*7c478bd9Sstevel@tonic-gate  * isn't enabled for this address, enable at that level as well.
4510*7c478bd9Sstevel@tonic-gate  */
4511*7c478bd9Sstevel@tonic-gate static int
4512*7c478bd9Sstevel@tonic-gate gld_enable_multi(queue_t *q, mblk_t *mp)
4513*7c478bd9Sstevel@tonic-gate {
4514*7c478bd9Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
4515*7c478bd9Sstevel@tonic-gate 	glddev_t *glddev;
4516*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
4517*7c478bd9Sstevel@tonic-gate 	unsigned char *maddr;
4518*7c478bd9Sstevel@tonic-gate 	dl_enabmulti_req_t *multi;
4519*7c478bd9Sstevel@tonic-gate 	gld_mcast_t *mcast;
4520*7c478bd9Sstevel@tonic-gate 	int	i, rc;
4521*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
4522*7c478bd9Sstevel@tonic-gate 
4523*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
4524*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
4525*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_enable_multi(%p, %p)", (void *)q,
4526*7c478bd9Sstevel@tonic-gate 		    (void *)mp);
4527*7c478bd9Sstevel@tonic-gate 	}
4528*7c478bd9Sstevel@tonic-gate #endif
4529*7c478bd9Sstevel@tonic-gate 
4530*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
4531*7c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
4532*7c478bd9Sstevel@tonic-gate 
4533*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
4534*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
4535*7c478bd9Sstevel@tonic-gate 
4536*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_set_multicast == NULL) {
4537*7c478bd9Sstevel@tonic-gate 		return (DL_UNSUPPORTED);
4538*7c478bd9Sstevel@tonic-gate 	}
4539*7c478bd9Sstevel@tonic-gate 
4540*7c478bd9Sstevel@tonic-gate 	multi = (dl_enabmulti_req_t *)mp->b_rptr;
4541*7c478bd9Sstevel@tonic-gate 
4542*7c478bd9Sstevel@tonic-gate 	if (!MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length) ||
4543*7c478bd9Sstevel@tonic-gate 	    multi->dl_addr_length != macinfo->gldm_addrlen)
4544*7c478bd9Sstevel@tonic-gate 		return (DL_BADADDR);
4545*7c478bd9Sstevel@tonic-gate 
4546*7c478bd9Sstevel@tonic-gate 	/* request appears to be valid */
4547*7c478bd9Sstevel@tonic-gate 
4548*7c478bd9Sstevel@tonic-gate 	glddev = mac_pvt->major_dev;
4549*7c478bd9Sstevel@tonic-gate 	ASSERT(glddev == gld->gld_device);
4550*7c478bd9Sstevel@tonic-gate 
4551*7c478bd9Sstevel@tonic-gate 	maddr = mp->b_rptr + multi->dl_addr_offset;
4552*7c478bd9Sstevel@tonic-gate 
4553*7c478bd9Sstevel@tonic-gate 	/*
4554*7c478bd9Sstevel@tonic-gate 	 * The multicast addresses live in a per-device table, along
4555*7c478bd9Sstevel@tonic-gate 	 * with a reference count.  Each stream has a table that
4556*7c478bd9Sstevel@tonic-gate 	 * points to entries in the device table, with the reference
4557*7c478bd9Sstevel@tonic-gate 	 * count reflecting the number of streams pointing at it.  If
4558*7c478bd9Sstevel@tonic-gate 	 * this multicast address is already in the per-device table,
4559*7c478bd9Sstevel@tonic-gate 	 * all we have to do is point at it.
4560*7c478bd9Sstevel@tonic-gate 	 */
4561*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
4562*7c478bd9Sstevel@tonic-gate 
4563*7c478bd9Sstevel@tonic-gate 	/* does this address appear in current table? */
4564*7c478bd9Sstevel@tonic-gate 	if (gld->gld_mcast == NULL) {
4565*7c478bd9Sstevel@tonic-gate 		/* no mcast addresses -- allocate table */
4566*7c478bd9Sstevel@tonic-gate 		gld->gld_mcast = GETSTRUCT(gld_mcast_t *,
4567*7c478bd9Sstevel@tonic-gate 					    glddev->gld_multisize);
4568*7c478bd9Sstevel@tonic-gate 		if (gld->gld_mcast == NULL) {
4569*7c478bd9Sstevel@tonic-gate 			GLDM_UNLOCK(macinfo);
4570*7c478bd9Sstevel@tonic-gate 			dlerrorack(q, mp, DL_ENABMULTI_REQ, DL_SYSERR, ENOSR);
4571*7c478bd9Sstevel@tonic-gate 			return (GLDE_OK);
4572*7c478bd9Sstevel@tonic-gate 		}
4573*7c478bd9Sstevel@tonic-gate 		gld->gld_multicnt = glddev->gld_multisize;
4574*7c478bd9Sstevel@tonic-gate 	} else {
4575*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < gld->gld_multicnt; i++) {
4576*7c478bd9Sstevel@tonic-gate 			if (gld->gld_mcast[i] &&
4577*7c478bd9Sstevel@tonic-gate 			    mac_eq(gld->gld_mcast[i]->gldm_addr,
4578*7c478bd9Sstevel@tonic-gate 				maddr, macinfo->gldm_addrlen)) {
4579*7c478bd9Sstevel@tonic-gate 				/* this is a match -- just succeed */
4580*7c478bd9Sstevel@tonic-gate 				ASSERT(gld->gld_mcast[i]->gldm_refcnt);
4581*7c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
4582*7c478bd9Sstevel@tonic-gate 				dlokack(q, mp, DL_ENABMULTI_REQ);
4583*7c478bd9Sstevel@tonic-gate 				return (GLDE_OK);
4584*7c478bd9Sstevel@tonic-gate 			}
4585*7c478bd9Sstevel@tonic-gate 		}
4586*7c478bd9Sstevel@tonic-gate 	}
4587*7c478bd9Sstevel@tonic-gate 
4588*7c478bd9Sstevel@tonic-gate 	/*
4589*7c478bd9Sstevel@tonic-gate 	 * it wasn't in the stream so check to see if the mac layer has it
4590*7c478bd9Sstevel@tonic-gate 	 */
4591*7c478bd9Sstevel@tonic-gate 	mcast = NULL;
4592*7c478bd9Sstevel@tonic-gate 	if (mac_pvt->mcast_table == NULL) {
4593*7c478bd9Sstevel@tonic-gate 		mac_pvt->mcast_table = GETSTRUCT(gld_mcast_t,
4594*7c478bd9Sstevel@tonic-gate 						glddev->gld_multisize);
4595*7c478bd9Sstevel@tonic-gate 		if (mac_pvt->mcast_table == NULL) {
4596*7c478bd9Sstevel@tonic-gate 			GLDM_UNLOCK(macinfo);
4597*7c478bd9Sstevel@tonic-gate 			dlerrorack(q, mp, DL_ENABMULTI_REQ, DL_SYSERR, ENOSR);
4598*7c478bd9Sstevel@tonic-gate 			return (GLDE_OK);
4599*7c478bd9Sstevel@tonic-gate 		}
4600*7c478bd9Sstevel@tonic-gate 	} else {
4601*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < glddev->gld_multisize; i++) {
4602*7c478bd9Sstevel@tonic-gate 			if (mac_pvt->mcast_table[i].gldm_refcnt &&
4603*7c478bd9Sstevel@tonic-gate 			    mac_eq(mac_pvt->mcast_table[i].gldm_addr,
4604*7c478bd9Sstevel@tonic-gate 			    maddr, macinfo->gldm_addrlen)) {
4605*7c478bd9Sstevel@tonic-gate 				mcast = &mac_pvt->mcast_table[i];
4606*7c478bd9Sstevel@tonic-gate 				break;
4607*7c478bd9Sstevel@tonic-gate 			}
4608*7c478bd9Sstevel@tonic-gate 		}
4609*7c478bd9Sstevel@tonic-gate 	}
4610*7c478bd9Sstevel@tonic-gate 	if (mcast == NULL) {
4611*7c478bd9Sstevel@tonic-gate 		/* not in mac layer -- find an empty mac slot to fill in */
4612*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < glddev->gld_multisize; i++) {
4613*7c478bd9Sstevel@tonic-gate 			if (mac_pvt->mcast_table[i].gldm_refcnt == 0) {
4614*7c478bd9Sstevel@tonic-gate 				mcast = &mac_pvt->mcast_table[i];
4615*7c478bd9Sstevel@tonic-gate 				mac_copy(maddr, mcast->gldm_addr,
4616*7c478bd9Sstevel@tonic-gate 				    macinfo->gldm_addrlen);
4617*7c478bd9Sstevel@tonic-gate 				break;
4618*7c478bd9Sstevel@tonic-gate 			}
4619*7c478bd9Sstevel@tonic-gate 		}
4620*7c478bd9Sstevel@tonic-gate 	}
4621*7c478bd9Sstevel@tonic-gate 	if (mcast == NULL) {
4622*7c478bd9Sstevel@tonic-gate 		/* couldn't get a mac layer slot */
4623*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
4624*7c478bd9Sstevel@tonic-gate 		return (DL_TOOMANY);
4625*7c478bd9Sstevel@tonic-gate 	}
4626*7c478bd9Sstevel@tonic-gate 
4627*7c478bd9Sstevel@tonic-gate 	/* now we have a mac layer slot in mcast -- get a stream slot */
4628*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < gld->gld_multicnt; i++) {
4629*7c478bd9Sstevel@tonic-gate 		if (gld->gld_mcast[i] != NULL)
4630*7c478bd9Sstevel@tonic-gate 			continue;
4631*7c478bd9Sstevel@tonic-gate 		/* found an empty slot */
4632*7c478bd9Sstevel@tonic-gate 		if (!mcast->gldm_refcnt) {
4633*7c478bd9Sstevel@tonic-gate 			/* set mcast in hardware */
4634*7c478bd9Sstevel@tonic-gate 			unsigned char cmaddr[GLD_MAX_ADDRLEN];
4635*7c478bd9Sstevel@tonic-gate 
4636*7c478bd9Sstevel@tonic-gate 			ASSERT(sizeof (cmaddr) >= macinfo->gldm_addrlen);
4637*7c478bd9Sstevel@tonic-gate 			cmac_copy(maddr, cmaddr,
4638*7c478bd9Sstevel@tonic-gate 			    macinfo->gldm_addrlen, macinfo);
4639*7c478bd9Sstevel@tonic-gate 
4640*7c478bd9Sstevel@tonic-gate 			rc = (*macinfo->gldm_set_multicast)
4641*7c478bd9Sstevel@tonic-gate 			    (macinfo, cmaddr, GLD_MULTI_ENABLE);
4642*7c478bd9Sstevel@tonic-gate 			if (rc == GLD_NOTSUPPORTED) {
4643*7c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
4644*7c478bd9Sstevel@tonic-gate 				return (DL_NOTSUPPORTED);
4645*7c478bd9Sstevel@tonic-gate 			} else if (rc == GLD_NORESOURCES) {
4646*7c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
4647*7c478bd9Sstevel@tonic-gate 				return (DL_TOOMANY);
4648*7c478bd9Sstevel@tonic-gate 			} else if (rc == GLD_BADARG) {
4649*7c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
4650*7c478bd9Sstevel@tonic-gate 				return (DL_BADADDR);
4651*7c478bd9Sstevel@tonic-gate 			} else if (rc == GLD_RETRY) {
4652*7c478bd9Sstevel@tonic-gate 				/*
4653*7c478bd9Sstevel@tonic-gate 				 * The putbq and gld_xwait must be
4654*7c478bd9Sstevel@tonic-gate 				 * within the lock to prevent races
4655*7c478bd9Sstevel@tonic-gate 				 * with gld_sched.
4656*7c478bd9Sstevel@tonic-gate 				 */
4657*7c478bd9Sstevel@tonic-gate 				(void) putbq(q, mp);
4658*7c478bd9Sstevel@tonic-gate 				gld->gld_xwait = B_TRUE;
4659*7c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
4660*7c478bd9Sstevel@tonic-gate 				return (GLDE_RETRY);
4661*7c478bd9Sstevel@tonic-gate 			} else if (rc != GLD_SUCCESS) {
4662*7c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
4663*7c478bd9Sstevel@tonic-gate 				dlerrorack(q, mp, DL_ENABMULTI_REQ,
4664*7c478bd9Sstevel@tonic-gate 				    DL_SYSERR, EIO);
4665*7c478bd9Sstevel@tonic-gate 				return (GLDE_OK);
4666*7c478bd9Sstevel@tonic-gate 			}
4667*7c478bd9Sstevel@tonic-gate 		}
4668*7c478bd9Sstevel@tonic-gate 		gld->gld_mcast[i] = mcast;
4669*7c478bd9Sstevel@tonic-gate 		mcast->gldm_refcnt++;
4670*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
4671*7c478bd9Sstevel@tonic-gate 		dlokack(q, mp, DL_ENABMULTI_REQ);
4672*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
4673*7c478bd9Sstevel@tonic-gate 	}
4674*7c478bd9Sstevel@tonic-gate 
4675*7c478bd9Sstevel@tonic-gate 	/* couldn't get a stream slot */
4676*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
4677*7c478bd9Sstevel@tonic-gate 	return (DL_TOOMANY);
4678*7c478bd9Sstevel@tonic-gate }
4679*7c478bd9Sstevel@tonic-gate 
4680*7c478bd9Sstevel@tonic-gate 
4681*7c478bd9Sstevel@tonic-gate /*
4682*7c478bd9Sstevel@tonic-gate  * gld_disable_multi (q, mp)
4683*7c478bd9Sstevel@tonic-gate  * Disable the multicast address on the stream.  If last
4684*7c478bd9Sstevel@tonic-gate  * reference for the mac layer, disable there as well.
4685*7c478bd9Sstevel@tonic-gate  */
4686*7c478bd9Sstevel@tonic-gate static int
4687*7c478bd9Sstevel@tonic-gate gld_disable_multi(queue_t *q, mblk_t *mp)
4688*7c478bd9Sstevel@tonic-gate {
4689*7c478bd9Sstevel@tonic-gate 	gld_t  *gld;
4690*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
4691*7c478bd9Sstevel@tonic-gate 	unsigned char *maddr;
4692*7c478bd9Sstevel@tonic-gate 	dl_disabmulti_req_t *multi;
4693*7c478bd9Sstevel@tonic-gate 	int i;
4694*7c478bd9Sstevel@tonic-gate 	gld_mcast_t *mcast;
4695*7c478bd9Sstevel@tonic-gate 
4696*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
4697*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDPROT) {
4698*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_disable_multi(%p, %p)", (void *)q,
4699*7c478bd9Sstevel@tonic-gate 		    (void *)mp);
4700*7c478bd9Sstevel@tonic-gate 	}
4701*7c478bd9Sstevel@tonic-gate #endif
4702*7c478bd9Sstevel@tonic-gate 
4703*7c478bd9Sstevel@tonic-gate 	gld = (gld_t *)q->q_ptr;
4704*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
4705*7c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
4706*7c478bd9Sstevel@tonic-gate 
4707*7c478bd9Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
4708*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
4709*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_set_multicast == NULL) {
4710*7c478bd9Sstevel@tonic-gate 		return (DL_UNSUPPORTED);
4711*7c478bd9Sstevel@tonic-gate 	}
4712*7c478bd9Sstevel@tonic-gate 
4713*7c478bd9Sstevel@tonic-gate 	multi = (dl_disabmulti_req_t *)mp->b_rptr;
4714*7c478bd9Sstevel@tonic-gate 
4715*7c478bd9Sstevel@tonic-gate 	if (!MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length) ||
4716*7c478bd9Sstevel@tonic-gate 	    multi->dl_addr_length != macinfo->gldm_addrlen)
4717*7c478bd9Sstevel@tonic-gate 		return (DL_BADADDR);
4718*7c478bd9Sstevel@tonic-gate 
4719*7c478bd9Sstevel@tonic-gate 	maddr = mp->b_rptr + multi->dl_addr_offset;
4720*7c478bd9Sstevel@tonic-gate 
4721*7c478bd9Sstevel@tonic-gate 	/* request appears to be valid */
4722*7c478bd9Sstevel@tonic-gate 	/* does this address appear in current table? */
4723*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
4724*7c478bd9Sstevel@tonic-gate 	if (gld->gld_mcast != NULL) {
4725*7c478bd9Sstevel@tonic-gate 		for (i = 0; i < gld->gld_multicnt; i++)
4726*7c478bd9Sstevel@tonic-gate 			if (((mcast = gld->gld_mcast[i]) != NULL) &&
4727*7c478bd9Sstevel@tonic-gate 			    mac_eq(mcast->gldm_addr,
4728*7c478bd9Sstevel@tonic-gate 			    maddr, macinfo->gldm_addrlen)) {
4729*7c478bd9Sstevel@tonic-gate 				ASSERT(mcast->gldm_refcnt);
4730*7c478bd9Sstevel@tonic-gate 				gld_send_disable_multi(macinfo, mcast);
4731*7c478bd9Sstevel@tonic-gate 				gld->gld_mcast[i] = NULL;
4732*7c478bd9Sstevel@tonic-gate 				GLDM_UNLOCK(macinfo);
4733*7c478bd9Sstevel@tonic-gate 				dlokack(q, mp, DL_DISABMULTI_REQ);
4734*7c478bd9Sstevel@tonic-gate 				return (GLDE_OK);
4735*7c478bd9Sstevel@tonic-gate 			}
4736*7c478bd9Sstevel@tonic-gate 	}
4737*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
4738*7c478bd9Sstevel@tonic-gate 	return (DL_NOTENAB); /* not an enabled address */
4739*7c478bd9Sstevel@tonic-gate }
4740*7c478bd9Sstevel@tonic-gate 
4741*7c478bd9Sstevel@tonic-gate /*
4742*7c478bd9Sstevel@tonic-gate  * gld_send_disable_multi(macinfo, mcast)
4743*7c478bd9Sstevel@tonic-gate  * this function is used to disable a multicast address if the reference
4744*7c478bd9Sstevel@tonic-gate  * count goes to zero. The disable request will then be forwarded to the
4745*7c478bd9Sstevel@tonic-gate  * lower stream.
4746*7c478bd9Sstevel@tonic-gate  */
4747*7c478bd9Sstevel@tonic-gate static void
4748*7c478bd9Sstevel@tonic-gate gld_send_disable_multi(gld_mac_info_t *macinfo, gld_mcast_t *mcast)
4749*7c478bd9Sstevel@tonic-gate {
4750*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
4751*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
4752*7c478bd9Sstevel@tonic-gate 	ASSERT(mcast != NULL);
4753*7c478bd9Sstevel@tonic-gate 	ASSERT(mcast->gldm_refcnt);
4754*7c478bd9Sstevel@tonic-gate 
4755*7c478bd9Sstevel@tonic-gate 	if (!mcast->gldm_refcnt) {
4756*7c478bd9Sstevel@tonic-gate 		return;			/* "cannot happen" */
4757*7c478bd9Sstevel@tonic-gate 	}
4758*7c478bd9Sstevel@tonic-gate 
4759*7c478bd9Sstevel@tonic-gate 	if (--mcast->gldm_refcnt > 0) {
4760*7c478bd9Sstevel@tonic-gate 		return;
4761*7c478bd9Sstevel@tonic-gate 	}
4762*7c478bd9Sstevel@tonic-gate 
4763*7c478bd9Sstevel@tonic-gate 	/*
4764*7c478bd9Sstevel@tonic-gate 	 * This must be converted from canonical form to device form.
4765*7c478bd9Sstevel@tonic-gate 	 * The refcnt is now zero so we can trash the data.
4766*7c478bd9Sstevel@tonic-gate 	 */
4767*7c478bd9Sstevel@tonic-gate 	if (macinfo->gldm_options & GLDOPT_CANONICAL_ADDR)
4768*7c478bd9Sstevel@tonic-gate 		gld_bitreverse(mcast->gldm_addr, macinfo->gldm_addrlen);
4769*7c478bd9Sstevel@tonic-gate 
4770*7c478bd9Sstevel@tonic-gate 	/* XXX Ought to check for GLD_NORESOURCES or GLD_FAILURE */
4771*7c478bd9Sstevel@tonic-gate 	(void) (*macinfo->gldm_set_multicast)
4772*7c478bd9Sstevel@tonic-gate 	    (macinfo, mcast->gldm_addr, GLD_MULTI_DISABLE);
4773*7c478bd9Sstevel@tonic-gate }
4774*7c478bd9Sstevel@tonic-gate 
4775*7c478bd9Sstevel@tonic-gate /*
4776*7c478bd9Sstevel@tonic-gate  * gld_promisc (q, mp, req, on)
4777*7c478bd9Sstevel@tonic-gate  *	enable or disable the use of promiscuous mode with the hardware
4778*7c478bd9Sstevel@tonic-gate  */
4779*7c478bd9Sstevel@tonic-gate static int
4780*7c478bd9Sstevel@tonic-gate gld_promisc(queue_t *q, mblk_t *mp, t_uscalar_t req, boolean_t on)
4781*7c478bd9Sstevel@tonic-gate {
4782*7c478bd9Sstevel@tonic-gate 	gld_t *gld;
4783*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
4784*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
4785*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
4786*7c478bd9Sstevel@tonic-gate 	union DL_primitives *prim;
4787*7c478bd9Sstevel@tonic-gate 	int macrc = GLD_SUCCESS;
4788*7c478bd9Sstevel@tonic-gate 	int dlerr = GLDE_OK;
4789*7c478bd9Sstevel@tonic-gate 	int op = GLD_MAC_PROMISC_NOOP;
4790*7c478bd9Sstevel@tonic-gate 
4791*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
4792*7c478bd9Sstevel@tonic-gate 	if (gld_debug & GLDTRACE)
4793*7c478bd9Sstevel@tonic-gate 		cmn_err(CE_NOTE, "gld_promisc(%p, %p, %d, %d)",
4794*7c478bd9Sstevel@tonic-gate 		    (void *)q, (void *)mp, req, on);
4795*7c478bd9Sstevel@tonic-gate #endif
4796*7c478bd9Sstevel@tonic-gate 
4797*7c478bd9Sstevel@tonic-gate 	ASSERT(mp != NULL);
4798*7c478bd9Sstevel@tonic-gate 	prim = (union DL_primitives *)mp->b_rptr;
4799*7c478bd9Sstevel@tonic-gate 
4800*7c478bd9Sstevel@tonic-gate 	/* XXX I think spec allows promisc in unattached state */
4801*7c478bd9Sstevel@tonic-gate 	gld = (gld_t *)q->q_ptr;
4802*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
4803*7c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
4804*7c478bd9Sstevel@tonic-gate 
4805*7c478bd9Sstevel@tonic-gate 	macinfo = gld->gld_mac_info;
4806*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
4807*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
4808*7c478bd9Sstevel@tonic-gate 
4809*7c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
4810*7c478bd9Sstevel@tonic-gate 	ASSERT(vlan != NULL);
4811*7c478bd9Sstevel@tonic-gate 
4812*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
4813*7c478bd9Sstevel@tonic-gate 
4814*7c478bd9Sstevel@tonic-gate 	/*
4815*7c478bd9Sstevel@tonic-gate 	 * Work out what request (if any) has to be made to the MAC layer
4816*7c478bd9Sstevel@tonic-gate 	 */
4817*7c478bd9Sstevel@tonic-gate 	if (on) {
4818*7c478bd9Sstevel@tonic-gate 		switch (prim->promiscon_req.dl_level) {
4819*7c478bd9Sstevel@tonic-gate 		default:
4820*7c478bd9Sstevel@tonic-gate 			dlerr = DL_UNSUPPORTED;	/* this is an error */
4821*7c478bd9Sstevel@tonic-gate 			break;
4822*7c478bd9Sstevel@tonic-gate 
4823*7c478bd9Sstevel@tonic-gate 		case DL_PROMISC_PHYS:
4824*7c478bd9Sstevel@tonic-gate 			if (mac_pvt->nprom == 0)
4825*7c478bd9Sstevel@tonic-gate 				op = GLD_MAC_PROMISC_PHYS;
4826*7c478bd9Sstevel@tonic-gate 			break;
4827*7c478bd9Sstevel@tonic-gate 
4828*7c478bd9Sstevel@tonic-gate 		case DL_PROMISC_MULTI:
4829*7c478bd9Sstevel@tonic-gate 			if (mac_pvt->nprom_multi == 0)
4830*7c478bd9Sstevel@tonic-gate 				if (mac_pvt->nprom == 0)
4831*7c478bd9Sstevel@tonic-gate 					op = GLD_MAC_PROMISC_MULTI;
4832*7c478bd9Sstevel@tonic-gate 			break;
4833*7c478bd9Sstevel@tonic-gate 
4834*7c478bd9Sstevel@tonic-gate 		case DL_PROMISC_SAP:
4835*7c478bd9Sstevel@tonic-gate 			/* We can do this without reference to the MAC */
4836*7c478bd9Sstevel@tonic-gate 			break;
4837*7c478bd9Sstevel@tonic-gate 		}
4838*7c478bd9Sstevel@tonic-gate 	} else {
4839*7c478bd9Sstevel@tonic-gate 		switch (prim->promiscoff_req.dl_level) {
4840*7c478bd9Sstevel@tonic-gate 		default:
4841*7c478bd9Sstevel@tonic-gate 			dlerr = DL_UNSUPPORTED;	/* this is an error */
4842*7c478bd9Sstevel@tonic-gate 			break;
4843*7c478bd9Sstevel@tonic-gate 
4844*7c478bd9Sstevel@tonic-gate 		case DL_PROMISC_PHYS:
4845*7c478bd9Sstevel@tonic-gate 			if (!(gld->gld_flags & GLD_PROM_PHYS))
4846*7c478bd9Sstevel@tonic-gate 				dlerr = DL_NOTENAB;
4847*7c478bd9Sstevel@tonic-gate 			else if (mac_pvt->nprom == 1)
4848*7c478bd9Sstevel@tonic-gate 				if (mac_pvt->nprom_multi)
4849*7c478bd9Sstevel@tonic-gate 					op = GLD_MAC_PROMISC_MULTI;
4850*7c478bd9Sstevel@tonic-gate 				else
4851*7c478bd9Sstevel@tonic-gate 					op = GLD_MAC_PROMISC_NONE;
4852*7c478bd9Sstevel@tonic-gate 			break;
4853*7c478bd9Sstevel@tonic-gate 
4854*7c478bd9Sstevel@tonic-gate 		case DL_PROMISC_MULTI:
4855*7c478bd9Sstevel@tonic-gate 			if (!(gld->gld_flags & GLD_PROM_MULT))
4856*7c478bd9Sstevel@tonic-gate 				dlerr = DL_NOTENAB;
4857*7c478bd9Sstevel@tonic-gate 			else if (mac_pvt->nprom_multi == 1)
4858*7c478bd9Sstevel@tonic-gate 				if (mac_pvt->nprom == 0)
4859*7c478bd9Sstevel@tonic-gate 					op = GLD_MAC_PROMISC_NONE;
4860*7c478bd9Sstevel@tonic-gate 			break;
4861*7c478bd9Sstevel@tonic-gate 
4862*7c478bd9Sstevel@tonic-gate 		case DL_PROMISC_SAP:
4863*7c478bd9Sstevel@tonic-gate 			if (!(gld->gld_flags & GLD_PROM_SAP))
4864*7c478bd9Sstevel@tonic-gate 				dlerr = DL_NOTENAB;
4865*7c478bd9Sstevel@tonic-gate 
4866*7c478bd9Sstevel@tonic-gate 			/* We can do this without reference to the MAC */
4867*7c478bd9Sstevel@tonic-gate 			break;
4868*7c478bd9Sstevel@tonic-gate 		}
4869*7c478bd9Sstevel@tonic-gate 	}
4870*7c478bd9Sstevel@tonic-gate 
4871*7c478bd9Sstevel@tonic-gate 	/*
4872*7c478bd9Sstevel@tonic-gate 	 * The request was invalid in some way so no need to continue.
4873*7c478bd9Sstevel@tonic-gate 	 */
4874*7c478bd9Sstevel@tonic-gate 	if (dlerr != GLDE_OK) {
4875*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
4876*7c478bd9Sstevel@tonic-gate 		return (dlerr);
4877*7c478bd9Sstevel@tonic-gate 	}
4878*7c478bd9Sstevel@tonic-gate 
4879*7c478bd9Sstevel@tonic-gate 	/*
4880*7c478bd9Sstevel@tonic-gate 	 * Issue the request to the MAC layer, if required
4881*7c478bd9Sstevel@tonic-gate 	 */
4882*7c478bd9Sstevel@tonic-gate 	if (op != GLD_MAC_PROMISC_NOOP) {
4883*7c478bd9Sstevel@tonic-gate 		macrc = (*macinfo->gldm_set_promiscuous)(macinfo, op);
4884*7c478bd9Sstevel@tonic-gate 	}
4885*7c478bd9Sstevel@tonic-gate 
4886*7c478bd9Sstevel@tonic-gate 	/*
4887*7c478bd9Sstevel@tonic-gate 	 * On success, update the appropriate flags & refcounts
4888*7c478bd9Sstevel@tonic-gate 	 */
4889*7c478bd9Sstevel@tonic-gate 	if (macrc == GLD_SUCCESS) {
4890*7c478bd9Sstevel@tonic-gate 		if (on) {
4891*7c478bd9Sstevel@tonic-gate 			switch (prim->promiscon_req.dl_level) {
4892*7c478bd9Sstevel@tonic-gate 			case DL_PROMISC_PHYS:
4893*7c478bd9Sstevel@tonic-gate 				mac_pvt->nprom++;
4894*7c478bd9Sstevel@tonic-gate 				gld->gld_flags |= GLD_PROM_PHYS;
4895*7c478bd9Sstevel@tonic-gate 				break;
4896*7c478bd9Sstevel@tonic-gate 
4897*7c478bd9Sstevel@tonic-gate 			case DL_PROMISC_MULTI:
4898*7c478bd9Sstevel@tonic-gate 				mac_pvt->nprom_multi++;
4899*7c478bd9Sstevel@tonic-gate 				gld->gld_flags |= GLD_PROM_MULT;
4900*7c478bd9Sstevel@tonic-gate 				break;
4901*7c478bd9Sstevel@tonic-gate 
4902*7c478bd9Sstevel@tonic-gate 			case DL_PROMISC_SAP:
4903*7c478bd9Sstevel@tonic-gate 				gld->gld_flags |= GLD_PROM_SAP;
4904*7c478bd9Sstevel@tonic-gate 				break;
4905*7c478bd9Sstevel@tonic-gate 
4906*7c478bd9Sstevel@tonic-gate 			default:
4907*7c478bd9Sstevel@tonic-gate 				break;
4908*7c478bd9Sstevel@tonic-gate 			}
4909*7c478bd9Sstevel@tonic-gate 		} else {
4910*7c478bd9Sstevel@tonic-gate 			switch (prim->promiscoff_req.dl_level) {
4911*7c478bd9Sstevel@tonic-gate 			case DL_PROMISC_PHYS:
4912*7c478bd9Sstevel@tonic-gate 				mac_pvt->nprom--;
4913*7c478bd9Sstevel@tonic-gate 				gld->gld_flags &= ~GLD_PROM_PHYS;
4914*7c478bd9Sstevel@tonic-gate 				break;
4915*7c478bd9Sstevel@tonic-gate 
4916*7c478bd9Sstevel@tonic-gate 			case DL_PROMISC_MULTI:
4917*7c478bd9Sstevel@tonic-gate 				mac_pvt->nprom_multi--;
4918*7c478bd9Sstevel@tonic-gate 				gld->gld_flags &= ~GLD_PROM_MULT;
4919*7c478bd9Sstevel@tonic-gate 				break;
4920*7c478bd9Sstevel@tonic-gate 
4921*7c478bd9Sstevel@tonic-gate 			case DL_PROMISC_SAP:
4922*7c478bd9Sstevel@tonic-gate 				gld->gld_flags &= ~GLD_PROM_SAP;
4923*7c478bd9Sstevel@tonic-gate 				break;
4924*7c478bd9Sstevel@tonic-gate 
4925*7c478bd9Sstevel@tonic-gate 			default:
4926*7c478bd9Sstevel@tonic-gate 				break;
4927*7c478bd9Sstevel@tonic-gate 			}
4928*7c478bd9Sstevel@tonic-gate 		}
4929*7c478bd9Sstevel@tonic-gate 	} else if (macrc == GLD_RETRY) {
4930*7c478bd9Sstevel@tonic-gate 		/*
4931*7c478bd9Sstevel@tonic-gate 		 * The putbq and gld_xwait must be within the lock to
4932*7c478bd9Sstevel@tonic-gate 		 * prevent races with gld_sched.
4933*7c478bd9Sstevel@tonic-gate 		 */
4934*7c478bd9Sstevel@tonic-gate 		(void) putbq(q, mp);
4935*7c478bd9Sstevel@tonic-gate 		gld->gld_xwait = B_TRUE;
4936*7c478bd9Sstevel@tonic-gate 	}
4937*7c478bd9Sstevel@tonic-gate 
4938*7c478bd9Sstevel@tonic-gate 	/*
4939*7c478bd9Sstevel@tonic-gate 	 * Update VLAN IPQ status -- it may have changed
4940*7c478bd9Sstevel@tonic-gate 	 */
4941*7c478bd9Sstevel@tonic-gate 	if (gld->gld_flags & (GLD_PROM_SAP | GLD_PROM_MULT | GLD_PROM_PHYS))
4942*7c478bd9Sstevel@tonic-gate 		vlan->gldv_ipq_flags |= IPQ_FORBIDDEN;
4943*7c478bd9Sstevel@tonic-gate 	else
4944*7c478bd9Sstevel@tonic-gate 		vlan->gldv_ipq_flags &= ~IPQ_FORBIDDEN;
4945*7c478bd9Sstevel@tonic-gate 
4946*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
4947*7c478bd9Sstevel@tonic-gate 
4948*7c478bd9Sstevel@tonic-gate 	/*
4949*7c478bd9Sstevel@tonic-gate 	 * Finally, decide how to reply.
4950*7c478bd9Sstevel@tonic-gate 	 *
4951*7c478bd9Sstevel@tonic-gate 	 * If <macrc> is not GLD_SUCCESS, the request was put to the MAC
4952*7c478bd9Sstevel@tonic-gate 	 * layer but failed.  In such cases, we can return a DL_* error
4953*7c478bd9Sstevel@tonic-gate 	 * code and let the caller send an error-ack reply upstream, or
4954*7c478bd9Sstevel@tonic-gate 	 * we can send a reply here and then return GLDE_OK so that the
4955*7c478bd9Sstevel@tonic-gate 	 * caller doesn't also respond.
4956*7c478bd9Sstevel@tonic-gate 	 *
4957*7c478bd9Sstevel@tonic-gate 	 * If physical-promiscuous mode was (successfully) switched on or
4958*7c478bd9Sstevel@tonic-gate 	 * off, send a notification (DL_NOTIFY_IND) to anyone interested.
4959*7c478bd9Sstevel@tonic-gate 	 */
4960*7c478bd9Sstevel@tonic-gate 	switch (macrc) {
4961*7c478bd9Sstevel@tonic-gate 	case GLD_NOTSUPPORTED:
4962*7c478bd9Sstevel@tonic-gate 		return (DL_NOTSUPPORTED);
4963*7c478bd9Sstevel@tonic-gate 
4964*7c478bd9Sstevel@tonic-gate 	case GLD_NORESOURCES:
4965*7c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, req, DL_SYSERR, ENOSR);
4966*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
4967*7c478bd9Sstevel@tonic-gate 
4968*7c478bd9Sstevel@tonic-gate 	case GLD_RETRY:
4969*7c478bd9Sstevel@tonic-gate 		return (GLDE_RETRY);
4970*7c478bd9Sstevel@tonic-gate 
4971*7c478bd9Sstevel@tonic-gate 	default:
4972*7c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, req, DL_SYSERR, EIO);
4973*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
4974*7c478bd9Sstevel@tonic-gate 
4975*7c478bd9Sstevel@tonic-gate 	case GLD_SUCCESS:
4976*7c478bd9Sstevel@tonic-gate 		dlokack(q, mp, req);
4977*7c478bd9Sstevel@tonic-gate 		break;
4978*7c478bd9Sstevel@tonic-gate 	}
4979*7c478bd9Sstevel@tonic-gate 
4980*7c478bd9Sstevel@tonic-gate 	switch (op) {
4981*7c478bd9Sstevel@tonic-gate 	case GLD_MAC_PROMISC_NOOP:
4982*7c478bd9Sstevel@tonic-gate 		break;
4983*7c478bd9Sstevel@tonic-gate 
4984*7c478bd9Sstevel@tonic-gate 	case GLD_MAC_PROMISC_PHYS:
4985*7c478bd9Sstevel@tonic-gate 		gld_notify_ind(macinfo, DL_NOTE_PROMISC_ON_PHYS, NULL);
4986*7c478bd9Sstevel@tonic-gate 		break;
4987*7c478bd9Sstevel@tonic-gate 
4988*7c478bd9Sstevel@tonic-gate 	default:
4989*7c478bd9Sstevel@tonic-gate 		gld_notify_ind(macinfo, DL_NOTE_PROMISC_OFF_PHYS, NULL);
4990*7c478bd9Sstevel@tonic-gate 		break;
4991*7c478bd9Sstevel@tonic-gate 	}
4992*7c478bd9Sstevel@tonic-gate 
4993*7c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
4994*7c478bd9Sstevel@tonic-gate }
4995*7c478bd9Sstevel@tonic-gate 
4996*7c478bd9Sstevel@tonic-gate /*
4997*7c478bd9Sstevel@tonic-gate  * gld_physaddr()
4998*7c478bd9Sstevel@tonic-gate  *	get the current or factory physical address value
4999*7c478bd9Sstevel@tonic-gate  */
5000*7c478bd9Sstevel@tonic-gate static int
5001*7c478bd9Sstevel@tonic-gate gld_physaddr(queue_t *q, mblk_t *mp)
5002*7c478bd9Sstevel@tonic-gate {
5003*7c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
5004*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
5005*7c478bd9Sstevel@tonic-gate 	union DL_primitives *prim = (union DL_primitives *)mp->b_rptr;
5006*7c478bd9Sstevel@tonic-gate 	unsigned char addr[GLD_MAX_ADDRLEN];
5007*7c478bd9Sstevel@tonic-gate 
5008*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
5009*7c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
5010*7c478bd9Sstevel@tonic-gate 
5011*7c478bd9Sstevel@tonic-gate 	macinfo = (gld_mac_info_t *)gld->gld_mac_info;
5012*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
5013*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo->gldm_addrlen <= GLD_MAX_ADDRLEN);
5014*7c478bd9Sstevel@tonic-gate 
5015*7c478bd9Sstevel@tonic-gate 	switch (prim->physaddr_req.dl_addr_type) {
5016*7c478bd9Sstevel@tonic-gate 	case DL_FACT_PHYS_ADDR:
5017*7c478bd9Sstevel@tonic-gate 		mac_copy((caddr_t)macinfo->gldm_vendor_addr,
5018*7c478bd9Sstevel@tonic-gate 		    (caddr_t)addr, macinfo->gldm_addrlen);
5019*7c478bd9Sstevel@tonic-gate 		break;
5020*7c478bd9Sstevel@tonic-gate 	case DL_CURR_PHYS_ADDR:
5021*7c478bd9Sstevel@tonic-gate 		/* make a copy so we don't hold the lock across qreply */
5022*7c478bd9Sstevel@tonic-gate 		GLDM_LOCK(macinfo, RW_WRITER);
5023*7c478bd9Sstevel@tonic-gate 		mac_copy((caddr_t)
5024*7c478bd9Sstevel@tonic-gate 		    ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
5025*7c478bd9Sstevel@tonic-gate 		    (caddr_t)addr, macinfo->gldm_addrlen);
5026*7c478bd9Sstevel@tonic-gate 		GLDM_UNLOCK(macinfo);
5027*7c478bd9Sstevel@tonic-gate 		break;
5028*7c478bd9Sstevel@tonic-gate 	default:
5029*7c478bd9Sstevel@tonic-gate 		return (DL_BADPRIM);
5030*7c478bd9Sstevel@tonic-gate 	}
5031*7c478bd9Sstevel@tonic-gate 	dlphysaddrack(q, mp, (caddr_t)addr, macinfo->gldm_addrlen);
5032*7c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
5033*7c478bd9Sstevel@tonic-gate }
5034*7c478bd9Sstevel@tonic-gate 
5035*7c478bd9Sstevel@tonic-gate /*
5036*7c478bd9Sstevel@tonic-gate  * gld_setaddr()
5037*7c478bd9Sstevel@tonic-gate  *	change the hardware's physical address to a user specified value
5038*7c478bd9Sstevel@tonic-gate  */
5039*7c478bd9Sstevel@tonic-gate static int
5040*7c478bd9Sstevel@tonic-gate gld_setaddr(queue_t *q, mblk_t *mp)
5041*7c478bd9Sstevel@tonic-gate {
5042*7c478bd9Sstevel@tonic-gate 	gld_t *gld = (gld_t *)q->q_ptr;
5043*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo;
5044*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
5045*7c478bd9Sstevel@tonic-gate 	union DL_primitives *prim = (union DL_primitives *)mp->b_rptr;
5046*7c478bd9Sstevel@tonic-gate 	unsigned char *addr;
5047*7c478bd9Sstevel@tonic-gate 	unsigned char cmaddr[GLD_MAX_ADDRLEN];
5048*7c478bd9Sstevel@tonic-gate 	int rc;
5049*7c478bd9Sstevel@tonic-gate 	gld_vlan_t *vlan;
5050*7c478bd9Sstevel@tonic-gate 
5051*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
5052*7c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
5053*7c478bd9Sstevel@tonic-gate 
5054*7c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
5055*7c478bd9Sstevel@tonic-gate 	ASSERT(vlan != NULL);
5056*7c478bd9Sstevel@tonic-gate 
5057*7c478bd9Sstevel@tonic-gate 	if (vlan->gldv_id != VLAN_VID_NONE)
5058*7c478bd9Sstevel@tonic-gate 		return (DL_NOTSUPPORTED);
5059*7c478bd9Sstevel@tonic-gate 
5060*7c478bd9Sstevel@tonic-gate 	macinfo = (gld_mac_info_t *)gld->gld_mac_info;
5061*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
5062*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
5063*7c478bd9Sstevel@tonic-gate 
5064*7c478bd9Sstevel@tonic-gate 	if (!MBLKIN(mp, prim->set_physaddr_req.dl_addr_offset,
5065*7c478bd9Sstevel@tonic-gate 	    prim->set_physaddr_req.dl_addr_length) ||
5066*7c478bd9Sstevel@tonic-gate 	    prim->set_physaddr_req.dl_addr_length != macinfo->gldm_addrlen)
5067*7c478bd9Sstevel@tonic-gate 		return (DL_BADADDR);
5068*7c478bd9Sstevel@tonic-gate 
5069*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
5070*7c478bd9Sstevel@tonic-gate 
5071*7c478bd9Sstevel@tonic-gate 	/* now do the set at the hardware level */
5072*7c478bd9Sstevel@tonic-gate 	addr = mp->b_rptr + prim->set_physaddr_req.dl_addr_offset;
5073*7c478bd9Sstevel@tonic-gate 	ASSERT(sizeof (cmaddr) >= macinfo->gldm_addrlen);
5074*7c478bd9Sstevel@tonic-gate 	cmac_copy(addr, cmaddr, macinfo->gldm_addrlen, macinfo);
5075*7c478bd9Sstevel@tonic-gate 
5076*7c478bd9Sstevel@tonic-gate 	rc = (*macinfo->gldm_set_mac_addr)(macinfo, cmaddr);
5077*7c478bd9Sstevel@tonic-gate 	if (rc == GLD_SUCCESS)
5078*7c478bd9Sstevel@tonic-gate 		mac_copy(addr, mac_pvt->curr_macaddr,
5079*7c478bd9Sstevel@tonic-gate 		    macinfo->gldm_addrlen);
5080*7c478bd9Sstevel@tonic-gate 
5081*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
5082*7c478bd9Sstevel@tonic-gate 
5083*7c478bd9Sstevel@tonic-gate 	switch (rc) {
5084*7c478bd9Sstevel@tonic-gate 	case GLD_SUCCESS:
5085*7c478bd9Sstevel@tonic-gate 		break;
5086*7c478bd9Sstevel@tonic-gate 	case GLD_NOTSUPPORTED:
5087*7c478bd9Sstevel@tonic-gate 		return (DL_NOTSUPPORTED);
5088*7c478bd9Sstevel@tonic-gate 	case GLD_BADARG:
5089*7c478bd9Sstevel@tonic-gate 		return (DL_BADADDR);
5090*7c478bd9Sstevel@tonic-gate 	case GLD_NORESOURCES:
5091*7c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, DL_SYSERR, ENOSR);
5092*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
5093*7c478bd9Sstevel@tonic-gate 	default:
5094*7c478bd9Sstevel@tonic-gate 		dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, DL_SYSERR, EIO);
5095*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);
5096*7c478bd9Sstevel@tonic-gate 	}
5097*7c478bd9Sstevel@tonic-gate 
5098*7c478bd9Sstevel@tonic-gate 	gld_notify_ind(macinfo, DL_NOTE_PHYS_ADDR, NULL);
5099*7c478bd9Sstevel@tonic-gate 
5100*7c478bd9Sstevel@tonic-gate 	dlokack(q, mp, DL_SET_PHYS_ADDR_REQ);
5101*7c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
5102*7c478bd9Sstevel@tonic-gate }
5103*7c478bd9Sstevel@tonic-gate 
5104*7c478bd9Sstevel@tonic-gate int
5105*7c478bd9Sstevel@tonic-gate gld_get_statistics(queue_t *q, mblk_t *mp)
5106*7c478bd9Sstevel@tonic-gate {
5107*7c478bd9Sstevel@tonic-gate 	dl_get_statistics_ack_t *dlsp;
5108*7c478bd9Sstevel@tonic-gate 	gld_t  *gld = (gld_t *)q->q_ptr;
5109*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t *macinfo = gld->gld_mac_info;
5110*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt;
5111*7c478bd9Sstevel@tonic-gate 
5112*7c478bd9Sstevel@tonic-gate 	if (gld->gld_state == DL_UNATTACHED)
5113*7c478bd9Sstevel@tonic-gate 		return (DL_OUTSTATE);
5114*7c478bd9Sstevel@tonic-gate 
5115*7c478bd9Sstevel@tonic-gate 	ASSERT(macinfo != NULL);
5116*7c478bd9Sstevel@tonic-gate 
5117*7c478bd9Sstevel@tonic-gate 	mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
5118*7c478bd9Sstevel@tonic-gate 	(void) gld_update_kstat(mac_pvt->kstatp, KSTAT_READ);
5119*7c478bd9Sstevel@tonic-gate 
5120*7c478bd9Sstevel@tonic-gate 	mp = mexchange(q, mp, DL_GET_STATISTICS_ACK_SIZE +
5121*7c478bd9Sstevel@tonic-gate 	    sizeof (struct gldkstats), M_PCPROTO, DL_GET_STATISTICS_ACK);
5122*7c478bd9Sstevel@tonic-gate 
5123*7c478bd9Sstevel@tonic-gate 	if (mp == NULL)
5124*7c478bd9Sstevel@tonic-gate 		return (GLDE_OK);	/* mexchange already sent merror */
5125*7c478bd9Sstevel@tonic-gate 
5126*7c478bd9Sstevel@tonic-gate 	dlsp = (dl_get_statistics_ack_t *)mp->b_rptr;
5127*7c478bd9Sstevel@tonic-gate 	dlsp->dl_primitive = DL_GET_STATISTICS_ACK;
5128*7c478bd9Sstevel@tonic-gate 	dlsp->dl_stat_length = sizeof (struct gldkstats);
5129*7c478bd9Sstevel@tonic-gate 	dlsp->dl_stat_offset = DL_GET_STATISTICS_ACK_SIZE;
5130*7c478bd9Sstevel@tonic-gate 
5131*7c478bd9Sstevel@tonic-gate 	GLDM_LOCK(macinfo, RW_WRITER);
5132*7c478bd9Sstevel@tonic-gate 	bcopy(mac_pvt->kstatp->ks_data,
5133*7c478bd9Sstevel@tonic-gate 	    (mp->b_rptr + DL_GET_STATISTICS_ACK_SIZE),
5134*7c478bd9Sstevel@tonic-gate 	    sizeof (struct gldkstats));
5135*7c478bd9Sstevel@tonic-gate 	GLDM_UNLOCK(macinfo);
5136*7c478bd9Sstevel@tonic-gate 
5137*7c478bd9Sstevel@tonic-gate 	qreply(q, mp);
5138*7c478bd9Sstevel@tonic-gate 	return (GLDE_OK);
5139*7c478bd9Sstevel@tonic-gate }
5140*7c478bd9Sstevel@tonic-gate 
5141*7c478bd9Sstevel@tonic-gate /* =================================================== */
5142*7c478bd9Sstevel@tonic-gate /* misc utilities, some requiring various mutexes held */
5143*7c478bd9Sstevel@tonic-gate /* =================================================== */
5144*7c478bd9Sstevel@tonic-gate 
5145*7c478bd9Sstevel@tonic-gate /*
5146*7c478bd9Sstevel@tonic-gate  * Initialize and start the driver.
5147*7c478bd9Sstevel@tonic-gate  */
5148*7c478bd9Sstevel@tonic-gate static int
5149*7c478bd9Sstevel@tonic-gate gld_start_mac(gld_mac_info_t *macinfo)
5150*7c478bd9Sstevel@tonic-gate {
5151*7c478bd9Sstevel@tonic-gate 	int	rc;
5152*7c478bd9Sstevel@tonic-gate 	unsigned char cmaddr[GLD_MAX_ADDRLEN];
5153*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
5154*7c478bd9Sstevel@tonic-gate 
5155*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
5156*7c478bd9Sstevel@tonic-gate 	ASSERT(!mac_pvt->started);
5157*7c478bd9Sstevel@tonic-gate 
5158*7c478bd9Sstevel@tonic-gate 	rc = (*macinfo->gldm_reset)(macinfo);
5159*7c478bd9Sstevel@tonic-gate 	if (rc != GLD_SUCCESS)
5160*7c478bd9Sstevel@tonic-gate 		return (GLD_FAILURE);
5161*7c478bd9Sstevel@tonic-gate 
5162*7c478bd9Sstevel@tonic-gate 	/* set the addr after we reset the device */
5163*7c478bd9Sstevel@tonic-gate 	ASSERT(sizeof (cmaddr) >= macinfo->gldm_addrlen);
5164*7c478bd9Sstevel@tonic-gate 	cmac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)
5165*7c478bd9Sstevel@tonic-gate 	    ->curr_macaddr, cmaddr, macinfo->gldm_addrlen, macinfo);
5166*7c478bd9Sstevel@tonic-gate 
5167*7c478bd9Sstevel@tonic-gate 	rc = (*macinfo->gldm_set_mac_addr)(macinfo, cmaddr);
5168*7c478bd9Sstevel@tonic-gate 	ASSERT(rc != GLD_BADARG);  /* this address was good before */
5169*7c478bd9Sstevel@tonic-gate 	if (rc != GLD_SUCCESS && rc != GLD_NOTSUPPORTED)
5170*7c478bd9Sstevel@tonic-gate 		return (GLD_FAILURE);
5171*7c478bd9Sstevel@tonic-gate 
5172*7c478bd9Sstevel@tonic-gate 	rc = (*macinfo->gldm_start)(macinfo);
5173*7c478bd9Sstevel@tonic-gate 	if (rc != GLD_SUCCESS)
5174*7c478bd9Sstevel@tonic-gate 		return (GLD_FAILURE);
5175*7c478bd9Sstevel@tonic-gate 
5176*7c478bd9Sstevel@tonic-gate 	mac_pvt->started = B_TRUE;
5177*7c478bd9Sstevel@tonic-gate 	return (GLD_SUCCESS);
5178*7c478bd9Sstevel@tonic-gate }
5179*7c478bd9Sstevel@tonic-gate 
5180*7c478bd9Sstevel@tonic-gate /*
5181*7c478bd9Sstevel@tonic-gate  * Stop the driver.
5182*7c478bd9Sstevel@tonic-gate  */
5183*7c478bd9Sstevel@tonic-gate static void
5184*7c478bd9Sstevel@tonic-gate gld_stop_mac(gld_mac_info_t *macinfo)
5185*7c478bd9Sstevel@tonic-gate {
5186*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
5187*7c478bd9Sstevel@tonic-gate 
5188*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
5189*7c478bd9Sstevel@tonic-gate 	ASSERT(mac_pvt->started);
5190*7c478bd9Sstevel@tonic-gate 
5191*7c478bd9Sstevel@tonic-gate 	(void) (*macinfo->gldm_stop)(macinfo);
5192*7c478bd9Sstevel@tonic-gate 
5193*7c478bd9Sstevel@tonic-gate 	mac_pvt->started = B_FALSE;
5194*7c478bd9Sstevel@tonic-gate }
5195*7c478bd9Sstevel@tonic-gate 
5196*7c478bd9Sstevel@tonic-gate 
5197*7c478bd9Sstevel@tonic-gate /*
5198*7c478bd9Sstevel@tonic-gate  * gld_set_ipq will set a pointer to the queue which is bound to the
5199*7c478bd9Sstevel@tonic-gate  * IP sap if:
5200*7c478bd9Sstevel@tonic-gate  * o the device type is ethernet or IPoIB.
5201*7c478bd9Sstevel@tonic-gate  * o there is no stream in SAP promiscuous mode.
5202*7c478bd9Sstevel@tonic-gate  * o there is exactly one stream bound to the IP sap.
5203*7c478bd9Sstevel@tonic-gate  * o the stream is in "fastpath" mode.
5204*7c478bd9Sstevel@tonic-gate  */
5205*7c478bd9Sstevel@tonic-gate static void
5206*7c478bd9Sstevel@tonic-gate gld_set_ipq(gld_t *gld)
5207*7c478bd9Sstevel@tonic-gate {
5208*7c478bd9Sstevel@tonic-gate 	gld_vlan_t	*vlan;
5209*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*macinfo = gld->gld_mac_info;
5210*7c478bd9Sstevel@tonic-gate 	gld_t		*ip_gld = NULL;
5211*7c478bd9Sstevel@tonic-gate 	uint_t		ipq_candidates = 0;
5212*7c478bd9Sstevel@tonic-gate 	gld_t		*ipv6_gld = NULL;
5213*7c478bd9Sstevel@tonic-gate 	uint_t		ipv6q_candidates = 0;
5214*7c478bd9Sstevel@tonic-gate 
5215*7c478bd9Sstevel@tonic-gate 	ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
5216*7c478bd9Sstevel@tonic-gate 
5217*7c478bd9Sstevel@tonic-gate 	/* The ipq code in gld_recv() is intimate with ethernet/IPoIB */
5218*7c478bd9Sstevel@tonic-gate 	if (((macinfo->gldm_type != DL_ETHER) &&
5219*7c478bd9Sstevel@tonic-gate 	    (macinfo->gldm_type != DL_IB)) ||
5220*7c478bd9Sstevel@tonic-gate 	    (gld_global_options & GLD_OPT_NO_IPQ))
5221*7c478bd9Sstevel@tonic-gate 		return;
5222*7c478bd9Sstevel@tonic-gate 
5223*7c478bd9Sstevel@tonic-gate 	vlan = (gld_vlan_t *)gld->gld_vlan;
5224*7c478bd9Sstevel@tonic-gate 	ASSERT(vlan != NULL);
5225*7c478bd9Sstevel@tonic-gate 
5226*7c478bd9Sstevel@tonic-gate 	/* clear down any previously defined ipqs */
5227*7c478bd9Sstevel@tonic-gate 	vlan->gldv_ipq = NULL;
5228*7c478bd9Sstevel@tonic-gate 	vlan->gldv_ipv6q = NULL;
5229*7c478bd9Sstevel@tonic-gate 
5230*7c478bd9Sstevel@tonic-gate 	/* Try to find a single stream eligible to receive IP packets */
5231*7c478bd9Sstevel@tonic-gate 	for (gld = vlan->gldv_str_next;
5232*7c478bd9Sstevel@tonic-gate 	    gld != (gld_t *)&vlan->gldv_str_next; gld = gld->gld_next) {
5233*7c478bd9Sstevel@tonic-gate 		if (gld->gld_state != DL_IDLE)
5234*7c478bd9Sstevel@tonic-gate 			continue;	/* not eligible to receive */
5235*7c478bd9Sstevel@tonic-gate 		if (gld->gld_flags & GLD_STR_CLOSING)
5236*7c478bd9Sstevel@tonic-gate 			continue;	/* not eligible to receive */
5237*7c478bd9Sstevel@tonic-gate 
5238*7c478bd9Sstevel@tonic-gate 		if (gld->gld_sap == ETHERTYPE_IP) {
5239*7c478bd9Sstevel@tonic-gate 			ip_gld = gld;
5240*7c478bd9Sstevel@tonic-gate 			ipq_candidates++;
5241*7c478bd9Sstevel@tonic-gate 		}
5242*7c478bd9Sstevel@tonic-gate 
5243*7c478bd9Sstevel@tonic-gate 		if (gld->gld_sap == ETHERTYPE_IPV6) {
5244*7c478bd9Sstevel@tonic-gate 			ipv6_gld = gld;
5245*7c478bd9Sstevel@tonic-gate 			ipv6q_candidates++;
5246*7c478bd9Sstevel@tonic-gate 		}
5247*7c478bd9Sstevel@tonic-gate 	}
5248*7c478bd9Sstevel@tonic-gate 
5249*7c478bd9Sstevel@tonic-gate 	if (ipq_candidates == 1) {
5250*7c478bd9Sstevel@tonic-gate 		ASSERT(ip_gld != NULL);
5251*7c478bd9Sstevel@tonic-gate 
5252*7c478bd9Sstevel@tonic-gate 		if (ip_gld->gld_flags & GLD_FAST)	/* eligible for ipq */
5253*7c478bd9Sstevel@tonic-gate 			vlan->gldv_ipq = ip_gld->gld_qptr;
5254*7c478bd9Sstevel@tonic-gate 	}
5255*7c478bd9Sstevel@tonic-gate 
5256*7c478bd9Sstevel@tonic-gate 	if (ipv6q_candidates == 1) {
5257*7c478bd9Sstevel@tonic-gate 		ASSERT(ipv6_gld != NULL);
5258*7c478bd9Sstevel@tonic-gate 
5259*7c478bd9Sstevel@tonic-gate 		if (ipv6_gld->gld_flags & GLD_FAST)	/* eligible for ipq */
5260*7c478bd9Sstevel@tonic-gate 			vlan->gldv_ipv6q = ipv6_gld->gld_qptr;
5261*7c478bd9Sstevel@tonic-gate 	}
5262*7c478bd9Sstevel@tonic-gate }
5263*7c478bd9Sstevel@tonic-gate 
5264*7c478bd9Sstevel@tonic-gate /*
5265*7c478bd9Sstevel@tonic-gate  * gld_flushqueue (q)
5266*7c478bd9Sstevel@tonic-gate  *	used by DLPI primitives that require flushing the queues.
5267*7c478bd9Sstevel@tonic-gate  *	essentially, this is DL_UNBIND_REQ.
5268*7c478bd9Sstevel@tonic-gate  */
5269*7c478bd9Sstevel@tonic-gate static void
5270*7c478bd9Sstevel@tonic-gate gld_flushqueue(queue_t *q)
5271*7c478bd9Sstevel@tonic-gate {
5272*7c478bd9Sstevel@tonic-gate 	/* flush all data in both queues */
5273*7c478bd9Sstevel@tonic-gate 	/* XXX Should these be FLUSHALL? */
5274*7c478bd9Sstevel@tonic-gate 	flushq(q, FLUSHDATA);
5275*7c478bd9Sstevel@tonic-gate 	flushq(WR(q), FLUSHDATA);
5276*7c478bd9Sstevel@tonic-gate 	/* flush all the queues upstream */
5277*7c478bd9Sstevel@tonic-gate 	(void) putctl1(q, M_FLUSH, FLUSHRW);
5278*7c478bd9Sstevel@tonic-gate }
5279*7c478bd9Sstevel@tonic-gate 
5280*7c478bd9Sstevel@tonic-gate /*
5281*7c478bd9Sstevel@tonic-gate  * gld_devlookup (major)
5282*7c478bd9Sstevel@tonic-gate  * search the device table for the device with specified
5283*7c478bd9Sstevel@tonic-gate  * major number and return a pointer to it if it exists
5284*7c478bd9Sstevel@tonic-gate  */
5285*7c478bd9Sstevel@tonic-gate static glddev_t *
5286*7c478bd9Sstevel@tonic-gate gld_devlookup(int major)
5287*7c478bd9Sstevel@tonic-gate {
5288*7c478bd9Sstevel@tonic-gate 	struct glddevice *dev;
5289*7c478bd9Sstevel@tonic-gate 
5290*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&gld_device_list.gld_devlock));
5291*7c478bd9Sstevel@tonic-gate 
5292*7c478bd9Sstevel@tonic-gate 	for (dev = gld_device_list.gld_next;
5293*7c478bd9Sstevel@tonic-gate 	    dev != &gld_device_list;
5294*7c478bd9Sstevel@tonic-gate 	    dev = dev->gld_next) {
5295*7c478bd9Sstevel@tonic-gate 		ASSERT(dev);
5296*7c478bd9Sstevel@tonic-gate 		if (dev->gld_major == major)
5297*7c478bd9Sstevel@tonic-gate 			return (dev);
5298*7c478bd9Sstevel@tonic-gate 	}
5299*7c478bd9Sstevel@tonic-gate 	return (NULL);
5300*7c478bd9Sstevel@tonic-gate }
5301*7c478bd9Sstevel@tonic-gate 
5302*7c478bd9Sstevel@tonic-gate /*
5303*7c478bd9Sstevel@tonic-gate  * gld_findminor(device)
5304*7c478bd9Sstevel@tonic-gate  * Returns a minor number currently unused by any stream in the current
5305*7c478bd9Sstevel@tonic-gate  * device class (major) list.
5306*7c478bd9Sstevel@tonic-gate  */
5307*7c478bd9Sstevel@tonic-gate static int
5308*7c478bd9Sstevel@tonic-gate gld_findminor(glddev_t *device)
5309*7c478bd9Sstevel@tonic-gate {
5310*7c478bd9Sstevel@tonic-gate 	gld_t		*next;
5311*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*nextmac;
5312*7c478bd9Sstevel@tonic-gate 	gld_vlan_t	*nextvlan;
5313*7c478bd9Sstevel@tonic-gate 	int		minor;
5314*7c478bd9Sstevel@tonic-gate 	int		i;
5315*7c478bd9Sstevel@tonic-gate 
5316*7c478bd9Sstevel@tonic-gate 	ASSERT(mutex_owned(&device->gld_devlock));
5317*7c478bd9Sstevel@tonic-gate 
5318*7c478bd9Sstevel@tonic-gate 	/* The fast way */
5319*7c478bd9Sstevel@tonic-gate 	if (device->gld_nextminor >= GLD_MIN_CLONE_MINOR &&
5320*7c478bd9Sstevel@tonic-gate 	    device->gld_nextminor <= GLD_MAX_CLONE_MINOR)
5321*7c478bd9Sstevel@tonic-gate 		return (device->gld_nextminor++);
5322*7c478bd9Sstevel@tonic-gate 
5323*7c478bd9Sstevel@tonic-gate 	/* The steady way */
5324*7c478bd9Sstevel@tonic-gate 	for (minor = GLD_MIN_CLONE_MINOR; minor <= GLD_MAX_CLONE_MINOR;
5325*7c478bd9Sstevel@tonic-gate 	    minor++) {
5326*7c478bd9Sstevel@tonic-gate 		/* Search all unattached streams */
5327*7c478bd9Sstevel@tonic-gate 		for (next = device->gld_str_next;
5328*7c478bd9Sstevel@tonic-gate 		    next != (gld_t *)&device->gld_str_next;
5329*7c478bd9Sstevel@tonic-gate 		    next = next->gld_next) {
5330*7c478bd9Sstevel@tonic-gate 			if (minor == next->gld_minor)
5331*7c478bd9Sstevel@tonic-gate 				goto nextminor;
5332*7c478bd9Sstevel@tonic-gate 		}
5333*7c478bd9Sstevel@tonic-gate 		/* Search all attached streams; we don't need maclock because */
5334*7c478bd9Sstevel@tonic-gate 		/* mac stream list is protected by devlock as well as maclock */
5335*7c478bd9Sstevel@tonic-gate 		for (nextmac = device->gld_mac_next;
5336*7c478bd9Sstevel@tonic-gate 		    nextmac != (gld_mac_info_t *)&device->gld_mac_next;
5337*7c478bd9Sstevel@tonic-gate 		    nextmac = nextmac->gldm_next) {
5338*7c478bd9Sstevel@tonic-gate 			gld_mac_pvt_t *pvt =
5339*7c478bd9Sstevel@tonic-gate 			    (gld_mac_pvt_t *)nextmac->gldm_mac_pvt;
5340*7c478bd9Sstevel@tonic-gate 
5341*7c478bd9Sstevel@tonic-gate 			if (!(nextmac->gldm_GLD_flags & GLD_MAC_READY))
5342*7c478bd9Sstevel@tonic-gate 				continue;	/* this one's not ready yet */
5343*7c478bd9Sstevel@tonic-gate 
5344*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < VLAN_HASHSZ; i++) {
5345*7c478bd9Sstevel@tonic-gate 				for (nextvlan = pvt->vlan_hash[i];
5346*7c478bd9Sstevel@tonic-gate 				    nextvlan != NULL;
5347*7c478bd9Sstevel@tonic-gate 				    nextvlan = nextvlan->gldv_next) {
5348*7c478bd9Sstevel@tonic-gate 					for (next = nextvlan->gldv_str_next;
5349*7c478bd9Sstevel@tonic-gate 					    next !=
5350*7c478bd9Sstevel@tonic-gate 					    (gld_t *)&nextvlan->gldv_str_next;
5351*7c478bd9Sstevel@tonic-gate 					    next = next->gld_next) {
5352*7c478bd9Sstevel@tonic-gate 						if (minor == next->gld_minor)
5353*7c478bd9Sstevel@tonic-gate 							goto nextminor;
5354*7c478bd9Sstevel@tonic-gate 					}
5355*7c478bd9Sstevel@tonic-gate 				}
5356*7c478bd9Sstevel@tonic-gate 			}
5357*7c478bd9Sstevel@tonic-gate 		}
5358*7c478bd9Sstevel@tonic-gate 
5359*7c478bd9Sstevel@tonic-gate 		return (minor);
5360*7c478bd9Sstevel@tonic-gate nextminor:
5361*7c478bd9Sstevel@tonic-gate 		/* don't need to do anything */
5362*7c478bd9Sstevel@tonic-gate 		;
5363*7c478bd9Sstevel@tonic-gate 	}
5364*7c478bd9Sstevel@tonic-gate 	cmn_err(CE_WARN, "GLD ran out of minor numbers for %s",
5365*7c478bd9Sstevel@tonic-gate 		device->gld_name);
5366*7c478bd9Sstevel@tonic-gate 	return (0);
5367*7c478bd9Sstevel@tonic-gate }
5368*7c478bd9Sstevel@tonic-gate 
5369*7c478bd9Sstevel@tonic-gate /*
5370*7c478bd9Sstevel@tonic-gate  * version of insque/remque for use by this driver
5371*7c478bd9Sstevel@tonic-gate  */
5372*7c478bd9Sstevel@tonic-gate struct qelem {
5373*7c478bd9Sstevel@tonic-gate 	struct qelem *q_forw;
5374*7c478bd9Sstevel@tonic-gate 	struct qelem *q_back;
5375*7c478bd9Sstevel@tonic-gate 	/* rest of structure */
5376*7c478bd9Sstevel@tonic-gate };
5377*7c478bd9Sstevel@tonic-gate 
5378*7c478bd9Sstevel@tonic-gate static void
5379*7c478bd9Sstevel@tonic-gate gldinsque(void *elem, void *pred)
5380*7c478bd9Sstevel@tonic-gate {
5381*7c478bd9Sstevel@tonic-gate 	struct qelem *pelem = elem;
5382*7c478bd9Sstevel@tonic-gate 	struct qelem *ppred = pred;
5383*7c478bd9Sstevel@tonic-gate 	struct qelem *pnext = ppred->q_forw;
5384*7c478bd9Sstevel@tonic-gate 
5385*7c478bd9Sstevel@tonic-gate 	pelem->q_forw = pnext;
5386*7c478bd9Sstevel@tonic-gate 	pelem->q_back = ppred;
5387*7c478bd9Sstevel@tonic-gate 	ppred->q_forw = pelem;
5388*7c478bd9Sstevel@tonic-gate 	pnext->q_back = pelem;
5389*7c478bd9Sstevel@tonic-gate }
5390*7c478bd9Sstevel@tonic-gate 
5391*7c478bd9Sstevel@tonic-gate static void
5392*7c478bd9Sstevel@tonic-gate gldremque(void *arg)
5393*7c478bd9Sstevel@tonic-gate {
5394*7c478bd9Sstevel@tonic-gate 	struct qelem *pelem = arg;
5395*7c478bd9Sstevel@tonic-gate 	struct qelem *elem = arg;
5396*7c478bd9Sstevel@tonic-gate 
5397*7c478bd9Sstevel@tonic-gate 	pelem->q_forw->q_back = pelem->q_back;
5398*7c478bd9Sstevel@tonic-gate 	pelem->q_back->q_forw = pelem->q_forw;
5399*7c478bd9Sstevel@tonic-gate 	elem->q_back = elem->q_forw = NULL;
5400*7c478bd9Sstevel@tonic-gate }
5401*7c478bd9Sstevel@tonic-gate 
5402*7c478bd9Sstevel@tonic-gate static gld_vlan_t *
5403*7c478bd9Sstevel@tonic-gate gld_add_vlan(gld_mac_info_t *macinfo, uint32_t vid)
5404*7c478bd9Sstevel@tonic-gate {
5405*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
5406*7c478bd9Sstevel@tonic-gate 	gld_vlan_t	**pp;
5407*7c478bd9Sstevel@tonic-gate 	gld_vlan_t	*p;
5408*7c478bd9Sstevel@tonic-gate 
5409*7c478bd9Sstevel@tonic-gate 	pp = &(mac_pvt->vlan_hash[vid % VLAN_HASHSZ]);
5410*7c478bd9Sstevel@tonic-gate 	while ((p = *pp) != NULL) {
5411*7c478bd9Sstevel@tonic-gate 		ASSERT(p->gldv_id != vid);
5412*7c478bd9Sstevel@tonic-gate 		pp = &(p->gldv_next);
5413*7c478bd9Sstevel@tonic-gate 	}
5414*7c478bd9Sstevel@tonic-gate 
5415*7c478bd9Sstevel@tonic-gate 	if ((p = kmem_zalloc(sizeof (gld_vlan_t), KM_NOSLEEP)) == NULL)
5416*7c478bd9Sstevel@tonic-gate 		return (NULL);
5417*7c478bd9Sstevel@tonic-gate 
5418*7c478bd9Sstevel@tonic-gate 	p->gldv_mac = macinfo;
5419*7c478bd9Sstevel@tonic-gate 	p->gldv_id = vid;
5420*7c478bd9Sstevel@tonic-gate 
5421*7c478bd9Sstevel@tonic-gate 	if (vid == VLAN_VID_NONE) {
5422*7c478bd9Sstevel@tonic-gate 		p->gldv_ptag = VLAN_VTAG_NONE;
5423*7c478bd9Sstevel@tonic-gate 		p->gldv_stats = mac_pvt->statistics;
5424*7c478bd9Sstevel@tonic-gate 		p->gldv_kstatp = NULL;
5425*7c478bd9Sstevel@tonic-gate 	} else {
5426*7c478bd9Sstevel@tonic-gate 		p->gldv_ptag = GLD_MK_PTAG(VLAN_CFI_ETHER, vid);
5427*7c478bd9Sstevel@tonic-gate 		p->gldv_stats = kmem_zalloc(sizeof (struct gld_stats),
5428*7c478bd9Sstevel@tonic-gate 		    KM_SLEEP);
5429*7c478bd9Sstevel@tonic-gate 
5430*7c478bd9Sstevel@tonic-gate 		if (gld_init_vlan_stats(p) != GLD_SUCCESS) {
5431*7c478bd9Sstevel@tonic-gate 			kmem_free(p->gldv_stats, sizeof (struct gld_stats));
5432*7c478bd9Sstevel@tonic-gate 			kmem_free(p, sizeof (gld_vlan_t));
5433*7c478bd9Sstevel@tonic-gate 			return (NULL);
5434*7c478bd9Sstevel@tonic-gate 		}
5435*7c478bd9Sstevel@tonic-gate 	}
5436*7c478bd9Sstevel@tonic-gate 
5437*7c478bd9Sstevel@tonic-gate 	p->gldv_str_next = p->gldv_str_prev = (gld_t *)&p->gldv_str_next;
5438*7c478bd9Sstevel@tonic-gate 	mac_pvt->nvlan++;
5439*7c478bd9Sstevel@tonic-gate 	*pp = p;
5440*7c478bd9Sstevel@tonic-gate 
5441*7c478bd9Sstevel@tonic-gate 	return (p);
5442*7c478bd9Sstevel@tonic-gate }
5443*7c478bd9Sstevel@tonic-gate 
5444*7c478bd9Sstevel@tonic-gate static void
5445*7c478bd9Sstevel@tonic-gate gld_rem_vlan(gld_vlan_t *vlan)
5446*7c478bd9Sstevel@tonic-gate {
5447*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*macinfo = vlan->gldv_mac;
5448*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
5449*7c478bd9Sstevel@tonic-gate 	gld_vlan_t	**pp;
5450*7c478bd9Sstevel@tonic-gate 	gld_vlan_t	*p;
5451*7c478bd9Sstevel@tonic-gate 
5452*7c478bd9Sstevel@tonic-gate 	pp = &(mac_pvt->vlan_hash[vlan->gldv_id % VLAN_HASHSZ]);
5453*7c478bd9Sstevel@tonic-gate 	while ((p = *pp) != NULL) {
5454*7c478bd9Sstevel@tonic-gate 		if (p->gldv_id == vlan->gldv_id)
5455*7c478bd9Sstevel@tonic-gate 			break;
5456*7c478bd9Sstevel@tonic-gate 		pp = &(p->gldv_next);
5457*7c478bd9Sstevel@tonic-gate 	}
5458*7c478bd9Sstevel@tonic-gate 	ASSERT(p != NULL);
5459*7c478bd9Sstevel@tonic-gate 
5460*7c478bd9Sstevel@tonic-gate 	*pp = p->gldv_next;
5461*7c478bd9Sstevel@tonic-gate 	mac_pvt->nvlan--;
5462*7c478bd9Sstevel@tonic-gate 	if (p->gldv_id != VLAN_VID_NONE) {
5463*7c478bd9Sstevel@tonic-gate 		ASSERT(p->gldv_kstatp != NULL);
5464*7c478bd9Sstevel@tonic-gate 		kstat_delete(p->gldv_kstatp);
5465*7c478bd9Sstevel@tonic-gate 		kmem_free(p->gldv_stats, sizeof (struct gld_stats));
5466*7c478bd9Sstevel@tonic-gate 	}
5467*7c478bd9Sstevel@tonic-gate 	kmem_free(p, sizeof (gld_vlan_t));
5468*7c478bd9Sstevel@tonic-gate }
5469*7c478bd9Sstevel@tonic-gate 
5470*7c478bd9Sstevel@tonic-gate gld_vlan_t *
5471*7c478bd9Sstevel@tonic-gate gld_find_vlan(gld_mac_info_t *macinfo, uint32_t vid)
5472*7c478bd9Sstevel@tonic-gate {
5473*7c478bd9Sstevel@tonic-gate 	gld_mac_pvt_t	*mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
5474*7c478bd9Sstevel@tonic-gate 	gld_vlan_t	*p;
5475*7c478bd9Sstevel@tonic-gate 
5476*7c478bd9Sstevel@tonic-gate 	p = mac_pvt->vlan_hash[vid % VLAN_HASHSZ];
5477*7c478bd9Sstevel@tonic-gate 	while (p != NULL) {
5478*7c478bd9Sstevel@tonic-gate 		if (p->gldv_id == vid)
5479*7c478bd9Sstevel@tonic-gate 			return (p);
5480*7c478bd9Sstevel@tonic-gate 		p = p->gldv_next;
5481*7c478bd9Sstevel@tonic-gate 	}
5482*7c478bd9Sstevel@tonic-gate 	return (NULL);
5483*7c478bd9Sstevel@tonic-gate }
5484*7c478bd9Sstevel@tonic-gate 
5485*7c478bd9Sstevel@tonic-gate gld_vlan_t *
5486*7c478bd9Sstevel@tonic-gate gld_get_vlan(gld_mac_info_t *macinfo, uint32_t vid)
5487*7c478bd9Sstevel@tonic-gate {
5488*7c478bd9Sstevel@tonic-gate 	gld_vlan_t	*vlan;
5489*7c478bd9Sstevel@tonic-gate 
5490*7c478bd9Sstevel@tonic-gate 	if ((vlan = gld_find_vlan(macinfo, vid)) == NULL)
5491*7c478bd9Sstevel@tonic-gate 		vlan = gld_add_vlan(macinfo, vid);
5492*7c478bd9Sstevel@tonic-gate 
5493*7c478bd9Sstevel@tonic-gate 	return (vlan);
5494*7c478bd9Sstevel@tonic-gate }
5495*7c478bd9Sstevel@tonic-gate 
5496*7c478bd9Sstevel@tonic-gate /*
5497*7c478bd9Sstevel@tonic-gate  * gld_bitrevcopy()
5498*7c478bd9Sstevel@tonic-gate  * This is essentially bcopy, with the ability to bit reverse the
5499*7c478bd9Sstevel@tonic-gate  * the source bytes. The MAC addresses bytes as transmitted by FDDI
5500*7c478bd9Sstevel@tonic-gate  * interfaces are bit reversed.
5501*7c478bd9Sstevel@tonic-gate  */
5502*7c478bd9Sstevel@tonic-gate void
5503*7c478bd9Sstevel@tonic-gate gld_bitrevcopy(caddr_t src, caddr_t target, size_t n)
5504*7c478bd9Sstevel@tonic-gate {
5505*7c478bd9Sstevel@tonic-gate 	while (n--)
5506*7c478bd9Sstevel@tonic-gate 		*target++ = bit_rev[(uchar_t)*src++];
5507*7c478bd9Sstevel@tonic-gate }
5508*7c478bd9Sstevel@tonic-gate 
5509*7c478bd9Sstevel@tonic-gate /*
5510*7c478bd9Sstevel@tonic-gate  * gld_bitreverse()
5511*7c478bd9Sstevel@tonic-gate  * Convert the bit order by swaping all the bits, using a
5512*7c478bd9Sstevel@tonic-gate  * lookup table.
5513*7c478bd9Sstevel@tonic-gate  */
5514*7c478bd9Sstevel@tonic-gate void
5515*7c478bd9Sstevel@tonic-gate gld_bitreverse(uchar_t *rptr, size_t n)
5516*7c478bd9Sstevel@tonic-gate {
5517*7c478bd9Sstevel@tonic-gate 	while (n--) {
5518*7c478bd9Sstevel@tonic-gate 		*rptr = bit_rev[*rptr];
5519*7c478bd9Sstevel@tonic-gate 		rptr++;
5520*7c478bd9Sstevel@tonic-gate 	}
5521*7c478bd9Sstevel@tonic-gate }
5522*7c478bd9Sstevel@tonic-gate 
5523*7c478bd9Sstevel@tonic-gate char *
5524*7c478bd9Sstevel@tonic-gate gld_macaddr_sprintf(char *etherbuf, unsigned char *ap, int len)
5525*7c478bd9Sstevel@tonic-gate {
5526*7c478bd9Sstevel@tonic-gate 	int i;
5527*7c478bd9Sstevel@tonic-gate 	char *cp = etherbuf;
5528*7c478bd9Sstevel@tonic-gate 	static char digits[] = "0123456789abcdef";
5529*7c478bd9Sstevel@tonic-gate 
5530*7c478bd9Sstevel@tonic-gate 	for (i = 0; i < len; i++) {
5531*7c478bd9Sstevel@tonic-gate 		*cp++ = digits[*ap >> 4];
5532*7c478bd9Sstevel@tonic-gate 		*cp++ = digits[*ap++ & 0xf];
5533*7c478bd9Sstevel@tonic-gate 		*cp++ = ':';
5534*7c478bd9Sstevel@tonic-gate 	}
5535*7c478bd9Sstevel@tonic-gate 	*--cp = 0;
5536*7c478bd9Sstevel@tonic-gate 	return (etherbuf);
5537*7c478bd9Sstevel@tonic-gate }
5538*7c478bd9Sstevel@tonic-gate 
5539*7c478bd9Sstevel@tonic-gate #ifdef GLD_DEBUG
5540*7c478bd9Sstevel@tonic-gate static void
5541*7c478bd9Sstevel@tonic-gate gld_check_assertions()
5542*7c478bd9Sstevel@tonic-gate {
5543*7c478bd9Sstevel@tonic-gate 	glddev_t	*dev;
5544*7c478bd9Sstevel@tonic-gate 	gld_mac_info_t	*mac;
5545*7c478bd9Sstevel@tonic-gate 	gld_t		*str;
5546*7c478bd9Sstevel@tonic-gate 	gld_vlan_t	*vlan;
5547*7c478bd9Sstevel@tonic-gate 	int		i;
5548*7c478bd9Sstevel@tonic-gate 
5549*7c478bd9Sstevel@tonic-gate 	mutex_enter(&gld_device_list.gld_devlock);
5550*7c478bd9Sstevel@tonic-gate 
5551*7c478bd9Sstevel@tonic-gate 	for (dev = gld_device_list.gld_next;
5552*7c478bd9Sstevel@tonic-gate 	    dev != (glddev_t *)&gld_device_list.gld_next;
5553*7c478bd9Sstevel@tonic-gate 	    dev = dev->gld_next) {
5554*7c478bd9Sstevel@tonic-gate 		mutex_enter(&dev->gld_devlock);
5555*7c478bd9Sstevel@tonic-gate 		ASSERT(dev->gld_broadcast != NULL);
5556*7c478bd9Sstevel@tonic-gate 		for (str = dev->gld_str_next;
5557*7c478bd9Sstevel@tonic-gate 		    str != (gld_t *)&dev->gld_str_next;
5558*7c478bd9Sstevel@tonic-gate 		    str = str->gld_next) {
5559*7c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_device == dev);
5560*7c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_mac_info == NULL);
5561*7c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_qptr != NULL);
5562*7c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_minor >= GLD_MIN_CLONE_MINOR);
5563*7c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_multicnt == 0);
5564*7c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_mcast == NULL);
5565*7c478bd9Sstevel@tonic-gate 			ASSERT(!(str->gld_flags &
5566*7c478bd9Sstevel@tonic-gate 			    (GLD_PROM_PHYS|GLD_PROM_MULT|GLD_PROM_SAP)));
5567*7c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_sap == 0);
5568*7c478bd9Sstevel@tonic-gate 			ASSERT(str->gld_state == DL_UNATTACHED);
5569*7c478bd9Sstevel@tonic-gate 		}
5570*7c478bd9Sstevel@tonic-gate 		for (mac = dev->gld_mac_next;
5571*7c478bd9Sstevel@tonic-gate 		    mac != (gld_mac_info_t *)&dev->gld_mac_next;
5572*7c478bd9Sstevel@tonic-gate 		    mac = mac->gldm_next) {
5573*7c478bd9Sstevel@tonic-gate 			int nvlan = 0;
5574*7c478bd9Sstevel@tonic-gate 			gld_mac_pvt_t *pvt = (gld_mac_pvt_t *)mac->gldm_mac_pvt;
5575*7c478bd9Sstevel@tonic-gate 
5576*7c478bd9Sstevel@tonic-gate 			if (!(mac->gldm_GLD_flags & GLD_MAC_READY))
5577*7c478bd9Sstevel@tonic-gate 				continue;	/* this one's not ready yet */
5578*7c478bd9Sstevel@tonic-gate 
5579*7c478bd9Sstevel@tonic-gate 			GLDM_LOCK(mac, RW_WRITER);
5580*7c478bd9Sstevel@tonic-gate 			ASSERT(mac->gldm_devinfo != NULL);
5581*7c478bd9Sstevel@tonic-gate 			ASSERT(mac->gldm_mac_pvt != NULL);
5582*7c478bd9Sstevel@tonic-gate 			ASSERT(pvt->interfacep != NULL);
5583*7c478bd9Sstevel@tonic-gate 			ASSERT(pvt->kstatp != NULL);
5584*7c478bd9Sstevel@tonic-gate 			ASSERT(pvt->statistics != NULL);
5585*7c478bd9Sstevel@tonic-gate 			ASSERT(pvt->major_dev == dev);
5586*7c478bd9Sstevel@tonic-gate 
5587*7c478bd9Sstevel@tonic-gate 			for (i = 0; i < VLAN_HASHSZ; i++) {
5588*7c478bd9Sstevel@tonic-gate 				for (vlan = pvt->vlan_hash[i];
5589*7c478bd9Sstevel@tonic-gate 				    vlan != NULL; vlan = vlan->gldv_next) {
5590*7c478bd9Sstevel@tonic-gate 					int nstr = 0;
5591*7c478bd9Sstevel@tonic-gate 
5592*7c478bd9Sstevel@tonic-gate 					ASSERT(vlan->gldv_mac == mac);
5593*7c478bd9Sstevel@tonic-gate 
5594*7c478bd9Sstevel@tonic-gate 					for (str = vlan->gldv_str_next;
5595*7c478bd9Sstevel@tonic-gate 					    str !=
5596*7c478bd9Sstevel@tonic-gate 					    (gld_t *)&vlan->gldv_str_next;
5597*7c478bd9Sstevel@tonic-gate 					    str = str->gld_next) {
5598*7c478bd9Sstevel@tonic-gate 						ASSERT(str->gld_device == dev);
5599*7c478bd9Sstevel@tonic-gate 						ASSERT(str->gld_mac_info ==
5600*7c478bd9Sstevel@tonic-gate 						    mac);
5601*7c478bd9Sstevel@tonic-gate 						ASSERT(str->gld_qptr != NULL);
5602*7c478bd9Sstevel@tonic-gate 						ASSERT(str->gld_minor >=
5603*7c478bd9Sstevel@tonic-gate 						    GLD_MIN_CLONE_MINOR);
5604*7c478bd9Sstevel@tonic-gate 						ASSERT(
5605*7c478bd9Sstevel@tonic-gate 						    str->gld_multicnt == 0 ||
5606*7c478bd9Sstevel@tonic-gate 						    str->gld_mcast);
5607*7c478bd9Sstevel@tonic-gate 						nstr++;
5608*7c478bd9Sstevel@tonic-gate 					}
5609*7c478bd9Sstevel@tonic-gate 					ASSERT(vlan->gldv_nstreams == nstr);
5610*7c478bd9Sstevel@tonic-gate 					nvlan++;
5611*7c478bd9Sstevel@tonic-gate 				}
5612*7c478bd9Sstevel@tonic-gate 			}
5613*7c478bd9Sstevel@tonic-gate 			ASSERT(pvt->nvlan == nvlan);
5614*7c478bd9Sstevel@tonic-gate 			GLDM_UNLOCK(mac);
5615*7c478bd9Sstevel@tonic-gate 		}
5616*7c478bd9Sstevel@tonic-gate 		mutex_exit(&dev->gld_devlock);
5617*7c478bd9Sstevel@tonic-gate 	}
5618*7c478bd9Sstevel@tonic-gate 	mutex_exit(&gld_device_list.gld_devlock);
5619*7c478bd9Sstevel@tonic-gate }
5620*7c478bd9Sstevel@tonic-gate #endif
5621