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