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