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