10Sstevel@tonic-gate /*
20Sstevel@tonic-gate * CDDL HEADER START
30Sstevel@tonic-gate *
40Sstevel@tonic-gate * The contents of this file are subject to the terms of the
51521Syz147064 * Common Development and Distribution License (the "License").
61521Syz147064 * You may not use this file except in compliance with the License.
70Sstevel@tonic-gate *
80Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
90Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing.
100Sstevel@tonic-gate * See the License for the specific language governing permissions
110Sstevel@tonic-gate * and limitations under the License.
120Sstevel@tonic-gate *
130Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each
140Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
150Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the
160Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying
170Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner]
180Sstevel@tonic-gate *
190Sstevel@tonic-gate * CDDL HEADER END
200Sstevel@tonic-gate */
210Sstevel@tonic-gate /*
22*10223SPeter.Memishian@Sun.COM * Copyright 2009 Sun Microsystems, Inc. All rights reserved.
230Sstevel@tonic-gate * Use is subject to license terms.
240Sstevel@tonic-gate */
250Sstevel@tonic-gate
260Sstevel@tonic-gate /*
270Sstevel@tonic-gate * gld - Generic LAN Driver Version 2, PSARC/1997/382
280Sstevel@tonic-gate *
290Sstevel@tonic-gate * This is a utility module that provides generic facilities for
300Sstevel@tonic-gate * LAN drivers. The DLPI protocol and most STREAMS interfaces
310Sstevel@tonic-gate * are handled here.
320Sstevel@tonic-gate *
330Sstevel@tonic-gate * It no longer provides compatibility with drivers
340Sstevel@tonic-gate * implemented according to the GLD v0 documentation published
350Sstevel@tonic-gate * in 1993. (See PSARC 2003/728)
360Sstevel@tonic-gate */
370Sstevel@tonic-gate
380Sstevel@tonic-gate
390Sstevel@tonic-gate #include <sys/types.h>
400Sstevel@tonic-gate #include <sys/errno.h>
410Sstevel@tonic-gate #include <sys/stropts.h>
420Sstevel@tonic-gate #include <sys/stream.h>
430Sstevel@tonic-gate #include <sys/kmem.h>
440Sstevel@tonic-gate #include <sys/stat.h>
450Sstevel@tonic-gate #include <sys/modctl.h>
460Sstevel@tonic-gate #include <sys/kstat.h>
470Sstevel@tonic-gate #include <sys/debug.h>
480Sstevel@tonic-gate #include <sys/note.h>
490Sstevel@tonic-gate #include <sys/sysmacros.h>
500Sstevel@tonic-gate
510Sstevel@tonic-gate #include <sys/byteorder.h>
520Sstevel@tonic-gate #include <sys/strsun.h>
530Sstevel@tonic-gate #include <sys/strsubr.h>
540Sstevel@tonic-gate #include <sys/dlpi.h>
550Sstevel@tonic-gate #include <sys/pattr.h>
560Sstevel@tonic-gate #include <sys/ethernet.h>
570Sstevel@tonic-gate #include <sys/ib/clients/ibd/ibd.h>
580Sstevel@tonic-gate #include <sys/policy.h>
590Sstevel@tonic-gate #include <sys/atomic.h>
600Sstevel@tonic-gate
610Sstevel@tonic-gate #include <sys/multidata.h>
620Sstevel@tonic-gate #include <sys/gld.h>
630Sstevel@tonic-gate #include <sys/gldpriv.h>
640Sstevel@tonic-gate
650Sstevel@tonic-gate #include <sys/ddi.h>
660Sstevel@tonic-gate #include <sys/sunddi.h>
670Sstevel@tonic-gate
680Sstevel@tonic-gate /*
692760Sdg199075 * Macros to increment statistics.
702760Sdg199075 */
712760Sdg199075
722760Sdg199075 /*
732760Sdg199075 * Increase kstats. Note this operation is not atomic. It can be used when
742760Sdg199075 * GLDM_LOCK_HELD_WRITE(macinfo).
750Sstevel@tonic-gate */
762760Sdg199075 #define BUMP(stats, vstats, stat, delta) do { \
772760Sdg199075 ((stats)->stat) += (delta); \
782760Sdg199075 _NOTE(CONSTANTCONDITION) \
792760Sdg199075 if ((vstats) != NULL) \
802760Sdg199075 ((struct gld_stats *)(vstats))->stat += (delta); \
812760Sdg199075 _NOTE(CONSTANTCONDITION) \
822760Sdg199075 } while (0)
832760Sdg199075
842760Sdg199075 #define ATOMIC_BUMP_STAT(stat, delta) do { \
850Sstevel@tonic-gate _NOTE(CONSTANTCONDITION) \
862760Sdg199075 if (sizeof ((stat)) == sizeof (uint32_t)) { \
872760Sdg199075 atomic_add_32((uint32_t *)&(stat), (delta)); \
880Sstevel@tonic-gate _NOTE(CONSTANTCONDITION) \
892760Sdg199075 } else if (sizeof ((stat)) == sizeof (uint64_t)) { \
902760Sdg199075 atomic_add_64((uint64_t *)&(stat), (delta)); \
910Sstevel@tonic-gate } \
920Sstevel@tonic-gate _NOTE(CONSTANTCONDITION) \
930Sstevel@tonic-gate } while (0)
940Sstevel@tonic-gate
952760Sdg199075 #define ATOMIC_BUMP(stats, vstats, stat, delta) do { \
962760Sdg199075 ATOMIC_BUMP_STAT((stats)->stat, (delta)); \
972760Sdg199075 _NOTE(CONSTANTCONDITION) \
982760Sdg199075 if ((vstats) != NULL) { \
992760Sdg199075 ATOMIC_BUMP_STAT(((struct gld_stats *)(vstats))->stat, \
1002760Sdg199075 (delta)); \
1012760Sdg199075 } \
1022760Sdg199075 _NOTE(CONSTANTCONDITION) \
1032760Sdg199075 } while (0)
1042760Sdg199075
1052760Sdg199075 #define UPDATE_STATS(stats, vstats, pktinfo, delta) { \
1062760Sdg199075 if ((pktinfo).isBroadcast) { \
1072760Sdg199075 ATOMIC_BUMP((stats), (vstats), \
1082760Sdg199075 glds_brdcstxmt, (delta)); \
1092760Sdg199075 } else if ((pktinfo).isMulticast) { \
1102760Sdg199075 ATOMIC_BUMP((stats), (vstats), glds_multixmt, (delta)); \
1112760Sdg199075 } \
1122760Sdg199075 ATOMIC_BUMP((stats), (vstats), glds_bytexmt64, \
1132760Sdg199075 ((pktinfo).pktLen)); \
1142760Sdg199075 ATOMIC_BUMP((stats), (vstats), glds_pktxmt64, (delta)); \
1150Sstevel@tonic-gate }
1160Sstevel@tonic-gate
1170Sstevel@tonic-gate #ifdef GLD_DEBUG
1180Sstevel@tonic-gate int gld_debug = GLDERRS;
1190Sstevel@tonic-gate #endif
1200Sstevel@tonic-gate
1210Sstevel@tonic-gate /* called from gld_register */
1220Sstevel@tonic-gate static int gld_initstats(gld_mac_info_t *);
1230Sstevel@tonic-gate
1240Sstevel@tonic-gate /* called from kstat mechanism, and from wsrv's get_statistics */
1250Sstevel@tonic-gate static int gld_update_kstat(kstat_t *, int);
1260Sstevel@tonic-gate
1270Sstevel@tonic-gate /* statistics for additional vlans */
1280Sstevel@tonic-gate static int gld_init_vlan_stats(gld_vlan_t *);
1290Sstevel@tonic-gate static int gld_update_vlan_kstat(kstat_t *, int);
1300Sstevel@tonic-gate
1310Sstevel@tonic-gate /* called from gld_getinfo */
1320Sstevel@tonic-gate static dev_info_t *gld_finddevinfo(dev_t);
1330Sstevel@tonic-gate
1340Sstevel@tonic-gate /* called from wput, wsrv, unidata, and v0_sched to send a packet */
1350Sstevel@tonic-gate /* also from the source routing stuff for sending RDE protocol packets */
1360Sstevel@tonic-gate static int gld_start(queue_t *, mblk_t *, int, uint32_t);
1370Sstevel@tonic-gate static int gld_start_mdt(queue_t *, mblk_t *, int);
1380Sstevel@tonic-gate
1390Sstevel@tonic-gate /* called from gld_start[_mdt] to loopback packet(s) in promiscuous mode */
1402760Sdg199075 static void gld_precv(gld_mac_info_t *, mblk_t *, uint32_t, struct gld_stats *);
1410Sstevel@tonic-gate static void gld_precv_mdt(gld_mac_info_t *, gld_vlan_t *, mblk_t *,
1420Sstevel@tonic-gate pdesc_t *, pktinfo_t *);
1430Sstevel@tonic-gate
1440Sstevel@tonic-gate /* receive group: called from gld_recv and gld_precv* with maclock held */
1452760Sdg199075 static void gld_sendup(gld_mac_info_t *, pktinfo_t *, mblk_t *,
1460Sstevel@tonic-gate int (*)());
1470Sstevel@tonic-gate static int gld_accept(gld_t *, pktinfo_t *);
1480Sstevel@tonic-gate static int gld_mcmatch(gld_t *, pktinfo_t *);
1490Sstevel@tonic-gate static int gld_multicast(unsigned char *, gld_t *);
1500Sstevel@tonic-gate static int gld_paccept(gld_t *, pktinfo_t *);
1510Sstevel@tonic-gate static void gld_passon(gld_t *, mblk_t *, pktinfo_t *,
1520Sstevel@tonic-gate void (*)(queue_t *, mblk_t *));
1532760Sdg199075 static mblk_t *gld_addudind(gld_t *, mblk_t *, pktinfo_t *, boolean_t);
1540Sstevel@tonic-gate
1550Sstevel@tonic-gate /* wsrv group: called from wsrv, single threaded per queue */
1560Sstevel@tonic-gate static int gld_ioctl(queue_t *, mblk_t *);
1570Sstevel@tonic-gate static void gld_fastpath(gld_t *, queue_t *, mblk_t *);
1580Sstevel@tonic-gate static int gld_cmds(queue_t *, mblk_t *);
1590Sstevel@tonic-gate static mblk_t *gld_bindack(queue_t *, mblk_t *);
1600Sstevel@tonic-gate static int gld_notify_req(queue_t *, mblk_t *);
1610Sstevel@tonic-gate static int gld_udqos(queue_t *, mblk_t *);
1620Sstevel@tonic-gate static int gld_bind(queue_t *, mblk_t *);
1630Sstevel@tonic-gate static int gld_unbind(queue_t *, mblk_t *);
1640Sstevel@tonic-gate static int gld_inforeq(queue_t *, mblk_t *);
1650Sstevel@tonic-gate static int gld_unitdata(queue_t *, mblk_t *);
1660Sstevel@tonic-gate static int gldattach(queue_t *, mblk_t *);
1670Sstevel@tonic-gate static int gldunattach(queue_t *, mblk_t *);
1680Sstevel@tonic-gate static int gld_enable_multi(queue_t *, mblk_t *);
1690Sstevel@tonic-gate static int gld_disable_multi(queue_t *, mblk_t *);
1700Sstevel@tonic-gate static void gld_send_disable_multi(gld_mac_info_t *, gld_mcast_t *);
1710Sstevel@tonic-gate static int gld_promisc(queue_t *, mblk_t *, t_uscalar_t, boolean_t);
1720Sstevel@tonic-gate static int gld_physaddr(queue_t *, mblk_t *);
1730Sstevel@tonic-gate static int gld_setaddr(queue_t *, mblk_t *);
1740Sstevel@tonic-gate static int gld_get_statistics(queue_t *, mblk_t *);
1750Sstevel@tonic-gate static int gld_cap(queue_t *, mblk_t *);
1760Sstevel@tonic-gate static int gld_cap_ack(queue_t *, mblk_t *);
1770Sstevel@tonic-gate static int gld_cap_enable(queue_t *, mblk_t *);
1780Sstevel@tonic-gate
1790Sstevel@tonic-gate /* misc utilities, some requiring various mutexes held */
1800Sstevel@tonic-gate static int gld_start_mac(gld_mac_info_t *);
1810Sstevel@tonic-gate static void gld_stop_mac(gld_mac_info_t *);
1820Sstevel@tonic-gate static void gld_set_ipq(gld_t *);
1830Sstevel@tonic-gate static void gld_flushqueue(queue_t *);
1840Sstevel@tonic-gate static glddev_t *gld_devlookup(int);
1850Sstevel@tonic-gate static int gld_findminor(glddev_t *);
1860Sstevel@tonic-gate static void gldinsque(void *, void *);
1870Sstevel@tonic-gate static void gldremque(void *);
1880Sstevel@tonic-gate void gld_bitrevcopy(caddr_t, caddr_t, size_t);
1890Sstevel@tonic-gate void gld_bitreverse(uchar_t *, size_t);
1900Sstevel@tonic-gate char *gld_macaddr_sprintf(char *, unsigned char *, int);
1910Sstevel@tonic-gate static gld_vlan_t *gld_add_vlan(gld_mac_info_t *, uint32_t vid);
1920Sstevel@tonic-gate static void gld_rem_vlan(gld_vlan_t *);
1930Sstevel@tonic-gate gld_vlan_t *gld_find_vlan(gld_mac_info_t *, uint32_t);
1940Sstevel@tonic-gate gld_vlan_t *gld_get_vlan(gld_mac_info_t *, uint32_t);
1950Sstevel@tonic-gate
1960Sstevel@tonic-gate #ifdef GLD_DEBUG
1970Sstevel@tonic-gate static void gld_check_assertions(void);
1980Sstevel@tonic-gate extern void gld_sr_dump(gld_mac_info_t *);
1990Sstevel@tonic-gate #endif
2000Sstevel@tonic-gate
2010Sstevel@tonic-gate /*
2020Sstevel@tonic-gate * Allocate and zero-out "number" structures each of type "structure" in
2030Sstevel@tonic-gate * kernel memory.
2040Sstevel@tonic-gate */
2055903Ssowmini #define GLD_GETSTRUCT(structure, number) \
2060Sstevel@tonic-gate (kmem_zalloc((uint_t)(sizeof (structure) * (number)), KM_NOSLEEP))
2070Sstevel@tonic-gate
2080Sstevel@tonic-gate #define abs(a) ((a) < 0 ? -(a) : a)
2090Sstevel@tonic-gate
2100Sstevel@tonic-gate uint32_t gld_global_options = GLD_OPT_NO_ETHRXSNAP;
2110Sstevel@tonic-gate
2120Sstevel@tonic-gate /*
2135895Syz147064 * The device is of DL_ETHER type and is able to support VLAN by itself.
2140Sstevel@tonic-gate */
2150Sstevel@tonic-gate #define VLAN_CAPABLE(macinfo) \
2160Sstevel@tonic-gate ((macinfo)->gldm_type == DL_ETHER && \
2170Sstevel@tonic-gate (macinfo)->gldm_send_tagged != NULL)
2180Sstevel@tonic-gate
2190Sstevel@tonic-gate /*
2200Sstevel@tonic-gate * The set of notifications generatable by GLD itself, the additional
2210Sstevel@tonic-gate * set that can be generated if the MAC driver provide the link-state
2220Sstevel@tonic-gate * tracking callback capability, and the set supported by the GLD
2230Sstevel@tonic-gate * notification code below.
2240Sstevel@tonic-gate *
2250Sstevel@tonic-gate * PLEASE keep these in sync with what the code actually does!
2260Sstevel@tonic-gate */
2270Sstevel@tonic-gate static const uint32_t gld_internal_notes = DL_NOTE_PROMISC_ON_PHYS |
2280Sstevel@tonic-gate DL_NOTE_PROMISC_OFF_PHYS |
2290Sstevel@tonic-gate DL_NOTE_PHYS_ADDR;
2300Sstevel@tonic-gate static const uint32_t gld_linkstate_notes = DL_NOTE_LINK_DOWN |
2310Sstevel@tonic-gate DL_NOTE_LINK_UP |
2320Sstevel@tonic-gate DL_NOTE_SPEED;
2330Sstevel@tonic-gate static const uint32_t gld_supported_notes = DL_NOTE_PROMISC_ON_PHYS |
2340Sstevel@tonic-gate DL_NOTE_PROMISC_OFF_PHYS |
2350Sstevel@tonic-gate DL_NOTE_PHYS_ADDR |
2360Sstevel@tonic-gate DL_NOTE_LINK_DOWN |
2370Sstevel@tonic-gate DL_NOTE_LINK_UP |
2380Sstevel@tonic-gate DL_NOTE_SPEED;
2390Sstevel@tonic-gate
2400Sstevel@tonic-gate /* Media must correspond to #defines in gld.h */
2410Sstevel@tonic-gate static char *gld_media[] = {
2420Sstevel@tonic-gate "unknown", /* GLDM_UNKNOWN - driver cannot determine media */
2430Sstevel@tonic-gate "aui", /* GLDM_AUI */
2440Sstevel@tonic-gate "bnc", /* GLDM_BNC */
2450Sstevel@tonic-gate "twpair", /* GLDM_TP */
2460Sstevel@tonic-gate "fiber", /* GLDM_FIBER */
2470Sstevel@tonic-gate "100baseT", /* GLDM_100BT */
2480Sstevel@tonic-gate "100vgAnyLan", /* GLDM_VGANYLAN */
2490Sstevel@tonic-gate "10baseT", /* GLDM_10BT */
2500Sstevel@tonic-gate "ring4", /* GLDM_RING4 */
2510Sstevel@tonic-gate "ring16", /* GLDM_RING16 */
2520Sstevel@tonic-gate "PHY/MII", /* GLDM_PHYMII */
2530Sstevel@tonic-gate "100baseTX", /* GLDM_100BTX */
2540Sstevel@tonic-gate "100baseT4", /* GLDM_100BT4 */
2550Sstevel@tonic-gate "unknown", /* skip */
2560Sstevel@tonic-gate "ipib", /* GLDM_IB */
2570Sstevel@tonic-gate };
2580Sstevel@tonic-gate
2590Sstevel@tonic-gate /* Must correspond to #defines in gld.h */
2600Sstevel@tonic-gate static char *gld_duplex[] = {
2610Sstevel@tonic-gate "unknown", /* GLD_DUPLEX_UNKNOWN - not known or not applicable */
2620Sstevel@tonic-gate "half", /* GLD_DUPLEX_HALF */
2630Sstevel@tonic-gate "full" /* GLD_DUPLEX_FULL */
2640Sstevel@tonic-gate };
2650Sstevel@tonic-gate
2660Sstevel@tonic-gate /*
2670Sstevel@tonic-gate * Interface types currently supported by GLD.
2680Sstevel@tonic-gate * If you add new types, you must check all "XXX" strings in the GLD source
2690Sstevel@tonic-gate * for implementation issues that may affect the support of your new type.
2700Sstevel@tonic-gate * In particular, any type with gldm_addrlen > 6, or gldm_saplen != -2, will
2710Sstevel@tonic-gate * require generalizing this GLD source to handle the new cases. In other
2720Sstevel@tonic-gate * words there are assumptions built into the code in a few places that must
2730Sstevel@tonic-gate * be fixed. Be sure to turn on DEBUG/ASSERT code when testing a new type.
2740Sstevel@tonic-gate */
2750Sstevel@tonic-gate static gld_interface_t interfaces[] = {
2760Sstevel@tonic-gate
2770Sstevel@tonic-gate /* Ethernet Bus */
2780Sstevel@tonic-gate {
2790Sstevel@tonic-gate DL_ETHER,
2800Sstevel@tonic-gate (uint_t)-1,
2812760Sdg199075 sizeof (struct ether_header),
2820Sstevel@tonic-gate gld_interpret_ether,
2830Sstevel@tonic-gate NULL,
2840Sstevel@tonic-gate gld_fastpath_ether,
2850Sstevel@tonic-gate gld_unitdata_ether,
2860Sstevel@tonic-gate gld_init_ether,
2870Sstevel@tonic-gate gld_uninit_ether,
2880Sstevel@tonic-gate "ether"
2890Sstevel@tonic-gate },
2900Sstevel@tonic-gate
2910Sstevel@tonic-gate /* Fiber Distributed data interface */
2920Sstevel@tonic-gate {
2930Sstevel@tonic-gate DL_FDDI,
2940Sstevel@tonic-gate 4352,
2950Sstevel@tonic-gate sizeof (struct fddi_mac_frm),
2960Sstevel@tonic-gate gld_interpret_fddi,
2970Sstevel@tonic-gate NULL,
2980Sstevel@tonic-gate gld_fastpath_fddi,
2990Sstevel@tonic-gate gld_unitdata_fddi,
3000Sstevel@tonic-gate gld_init_fddi,
3010Sstevel@tonic-gate gld_uninit_fddi,
3020Sstevel@tonic-gate "fddi"
3030Sstevel@tonic-gate },
3040Sstevel@tonic-gate
3050Sstevel@tonic-gate /* Token Ring interface */
3060Sstevel@tonic-gate {
3070Sstevel@tonic-gate DL_TPR,
3080Sstevel@tonic-gate 17914,
3090Sstevel@tonic-gate -1, /* variable header size */
3100Sstevel@tonic-gate gld_interpret_tr,
3110Sstevel@tonic-gate NULL,
3120Sstevel@tonic-gate gld_fastpath_tr,
3130Sstevel@tonic-gate gld_unitdata_tr,
3140Sstevel@tonic-gate gld_init_tr,
3150Sstevel@tonic-gate gld_uninit_tr,
3160Sstevel@tonic-gate "tpr"
3170Sstevel@tonic-gate },
3180Sstevel@tonic-gate
3190Sstevel@tonic-gate /* Infiniband */
3200Sstevel@tonic-gate {
3210Sstevel@tonic-gate DL_IB,
3220Sstevel@tonic-gate 4092,
3230Sstevel@tonic-gate sizeof (struct ipoib_header),
3240Sstevel@tonic-gate gld_interpret_ib,
3250Sstevel@tonic-gate gld_interpret_mdt_ib,
3260Sstevel@tonic-gate gld_fastpath_ib,
3270Sstevel@tonic-gate gld_unitdata_ib,
3280Sstevel@tonic-gate gld_init_ib,
3290Sstevel@tonic-gate gld_uninit_ib,
3300Sstevel@tonic-gate "ipib"
3310Sstevel@tonic-gate },
3320Sstevel@tonic-gate };
3330Sstevel@tonic-gate
3340Sstevel@tonic-gate /*
3350Sstevel@tonic-gate * bit reversal lookup table.
3360Sstevel@tonic-gate */
3370Sstevel@tonic-gate static uchar_t bit_rev[] = {
3380Sstevel@tonic-gate 0x00, 0x80, 0x40, 0xc0, 0x20, 0xa0, 0x60, 0xe0, 0x10, 0x90, 0x50, 0xd0,
3390Sstevel@tonic-gate 0x30, 0xb0, 0x70, 0xf0, 0x08, 0x88, 0x48, 0xc8, 0x28, 0xa8, 0x68, 0xe8,
3400Sstevel@tonic-gate 0x18, 0x98, 0x58, 0xd8, 0x38, 0xb8, 0x78, 0xf8, 0x04, 0x84, 0x44, 0xc4,
3410Sstevel@tonic-gate 0x24, 0xa4, 0x64, 0xe4, 0x14, 0x94, 0x54, 0xd4, 0x34, 0xb4, 0x74, 0xf4,
3420Sstevel@tonic-gate 0x0c, 0x8c, 0x4c, 0xcc, 0x2c, 0xac, 0x6c, 0xec, 0x1c, 0x9c, 0x5c, 0xdc,
3430Sstevel@tonic-gate 0x3c, 0xbc, 0x7c, 0xfc, 0x02, 0x82, 0x42, 0xc2, 0x22, 0xa2, 0x62, 0xe2,
3440Sstevel@tonic-gate 0x12, 0x92, 0x52, 0xd2, 0x32, 0xb2, 0x72, 0xf2, 0x0a, 0x8a, 0x4a, 0xca,
3450Sstevel@tonic-gate 0x2a, 0xaa, 0x6a, 0xea, 0x1a, 0x9a, 0x5a, 0xda, 0x3a, 0xba, 0x7a, 0xfa,
3460Sstevel@tonic-gate 0x06, 0x86, 0x46, 0xc6, 0x26, 0xa6, 0x66, 0xe6, 0x16, 0x96, 0x56, 0xd6,
3470Sstevel@tonic-gate 0x36, 0xb6, 0x76, 0xf6, 0x0e, 0x8e, 0x4e, 0xce, 0x2e, 0xae, 0x6e, 0xee,
3480Sstevel@tonic-gate 0x1e, 0x9e, 0x5e, 0xde, 0x3e, 0xbe, 0x7e, 0xfe, 0x01, 0x81, 0x41, 0xc1,
3490Sstevel@tonic-gate 0x21, 0xa1, 0x61, 0xe1, 0x11, 0x91, 0x51, 0xd1, 0x31, 0xb1, 0x71, 0xf1,
3500Sstevel@tonic-gate 0x09, 0x89, 0x49, 0xc9, 0x29, 0xa9, 0x69, 0xe9, 0x19, 0x99, 0x59, 0xd9,
3510Sstevel@tonic-gate 0x39, 0xb9, 0x79, 0xf9, 0x05, 0x85, 0x45, 0xc5, 0x25, 0xa5, 0x65, 0xe5,
3520Sstevel@tonic-gate 0x15, 0x95, 0x55, 0xd5, 0x35, 0xb5, 0x75, 0xf5, 0x0d, 0x8d, 0x4d, 0xcd,
3530Sstevel@tonic-gate 0x2d, 0xad, 0x6d, 0xed, 0x1d, 0x9d, 0x5d, 0xdd, 0x3d, 0xbd, 0x7d, 0xfd,
3540Sstevel@tonic-gate 0x03, 0x83, 0x43, 0xc3, 0x23, 0xa3, 0x63, 0xe3, 0x13, 0x93, 0x53, 0xd3,
3550Sstevel@tonic-gate 0x33, 0xb3, 0x73, 0xf3, 0x0b, 0x8b, 0x4b, 0xcb, 0x2b, 0xab, 0x6b, 0xeb,
3560Sstevel@tonic-gate 0x1b, 0x9b, 0x5b, 0xdb, 0x3b, 0xbb, 0x7b, 0xfb, 0x07, 0x87, 0x47, 0xc7,
3570Sstevel@tonic-gate 0x27, 0xa7, 0x67, 0xe7, 0x17, 0x97, 0x57, 0xd7, 0x37, 0xb7, 0x77, 0xf7,
3580Sstevel@tonic-gate 0x0f, 0x8f, 0x4f, 0xcf, 0x2f, 0xaf, 0x6f, 0xef, 0x1f, 0x9f, 0x5f, 0xdf,
3590Sstevel@tonic-gate 0x3f, 0xbf, 0x7f, 0xff,
3600Sstevel@tonic-gate };
3610Sstevel@tonic-gate
3620Sstevel@tonic-gate /*
3630Sstevel@tonic-gate * User priorities, mapped from b_band.
3640Sstevel@tonic-gate */
3650Sstevel@tonic-gate static uint32_t user_priority[] = {
3660Sstevel@tonic-gate 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3670Sstevel@tonic-gate 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
3680Sstevel@tonic-gate 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3690Sstevel@tonic-gate 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
3700Sstevel@tonic-gate 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3710Sstevel@tonic-gate 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2,
3720Sstevel@tonic-gate 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3730Sstevel@tonic-gate 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3,
3740Sstevel@tonic-gate 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3750Sstevel@tonic-gate 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4,
3760Sstevel@tonic-gate 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3770Sstevel@tonic-gate 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5,
3780Sstevel@tonic-gate 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
3790Sstevel@tonic-gate 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6, 6,
3800Sstevel@tonic-gate 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7,
3810Sstevel@tonic-gate 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7
3820Sstevel@tonic-gate };
3830Sstevel@tonic-gate
3840Sstevel@tonic-gate #define UPRI(gld, band) ((band != 0) ? user_priority[(band)] : (gld)->gld_upri)
3850Sstevel@tonic-gate
3860Sstevel@tonic-gate static struct glddevice gld_device_list; /* Per-system root of GLD tables */
3870Sstevel@tonic-gate
3880Sstevel@tonic-gate /*
3890Sstevel@tonic-gate * Module linkage information for the kernel.
3900Sstevel@tonic-gate */
3910Sstevel@tonic-gate
3920Sstevel@tonic-gate static struct modldrv modlmisc = {
3930Sstevel@tonic-gate &mod_miscops, /* Type of module - a utility provider */
3947862SRichard.Bean@Sun.COM "Generic LAN Driver (" GLD_VERSION_STRING ")"
3950Sstevel@tonic-gate #ifdef GLD_DEBUG
3960Sstevel@tonic-gate " DEBUG"
3970Sstevel@tonic-gate #endif
3980Sstevel@tonic-gate };
3990Sstevel@tonic-gate
4000Sstevel@tonic-gate static struct modlinkage modlinkage = {
4010Sstevel@tonic-gate MODREV_1, &modlmisc, NULL
4020Sstevel@tonic-gate };
4030Sstevel@tonic-gate
4040Sstevel@tonic-gate int
_init(void)4050Sstevel@tonic-gate _init(void)
4060Sstevel@tonic-gate {
4070Sstevel@tonic-gate int e;
4080Sstevel@tonic-gate
4090Sstevel@tonic-gate /* initialize gld_device_list mutex */
4100Sstevel@tonic-gate mutex_init(&gld_device_list.gld_devlock, NULL, MUTEX_DRIVER, NULL);
4110Sstevel@tonic-gate
4120Sstevel@tonic-gate /* initialize device driver (per-major) list */
4130Sstevel@tonic-gate gld_device_list.gld_next =
4140Sstevel@tonic-gate gld_device_list.gld_prev = &gld_device_list;
4150Sstevel@tonic-gate
4160Sstevel@tonic-gate if ((e = mod_install(&modlinkage)) != 0)
4170Sstevel@tonic-gate mutex_destroy(&gld_device_list.gld_devlock);
4180Sstevel@tonic-gate
4190Sstevel@tonic-gate return (e);
4200Sstevel@tonic-gate }
4210Sstevel@tonic-gate
4220Sstevel@tonic-gate int
_fini(void)4230Sstevel@tonic-gate _fini(void)
4240Sstevel@tonic-gate {
4250Sstevel@tonic-gate int e;
4260Sstevel@tonic-gate
4270Sstevel@tonic-gate if ((e = mod_remove(&modlinkage)) != 0)
4280Sstevel@tonic-gate return (e);
4290Sstevel@tonic-gate
4300Sstevel@tonic-gate ASSERT(gld_device_list.gld_next ==
4310Sstevel@tonic-gate (glddev_t *)&gld_device_list.gld_next);
4320Sstevel@tonic-gate ASSERT(gld_device_list.gld_prev ==
4330Sstevel@tonic-gate (glddev_t *)&gld_device_list.gld_next);
4340Sstevel@tonic-gate mutex_destroy(&gld_device_list.gld_devlock);
4350Sstevel@tonic-gate
4360Sstevel@tonic-gate return (e);
4370Sstevel@tonic-gate }
4380Sstevel@tonic-gate
4390Sstevel@tonic-gate int
_info(struct modinfo * modinfop)4400Sstevel@tonic-gate _info(struct modinfo *modinfop)
4410Sstevel@tonic-gate {
4420Sstevel@tonic-gate return (mod_info(&modlinkage, modinfop));
4430Sstevel@tonic-gate }
4440Sstevel@tonic-gate
4450Sstevel@tonic-gate /*
4460Sstevel@tonic-gate * GLD service routines
4470Sstevel@tonic-gate */
4480Sstevel@tonic-gate
4490Sstevel@tonic-gate /* So this gld binary maybe can be forward compatible with future v2 drivers */
4500Sstevel@tonic-gate #define GLD_MAC_RESERVED (16 * sizeof (caddr_t))
4510Sstevel@tonic-gate
4520Sstevel@tonic-gate /*ARGSUSED*/
4530Sstevel@tonic-gate gld_mac_info_t *
gld_mac_alloc(dev_info_t * devinfo)4540Sstevel@tonic-gate gld_mac_alloc(dev_info_t *devinfo)
4550Sstevel@tonic-gate {
4560Sstevel@tonic-gate gld_mac_info_t *macinfo;
4570Sstevel@tonic-gate
4580Sstevel@tonic-gate macinfo = kmem_zalloc(sizeof (gld_mac_info_t) + GLD_MAC_RESERVED,
4590Sstevel@tonic-gate KM_SLEEP);
4600Sstevel@tonic-gate
4610Sstevel@tonic-gate /*
4620Sstevel@tonic-gate * The setting of gldm_driver_version will not be documented or allowed
4630Sstevel@tonic-gate * until a future release.
4640Sstevel@tonic-gate */
4650Sstevel@tonic-gate macinfo->gldm_driver_version = GLD_VERSION_200;
4660Sstevel@tonic-gate
4670Sstevel@tonic-gate /*
4680Sstevel@tonic-gate * GLD's version. This also is undocumented for now, but will be
4690Sstevel@tonic-gate * available if needed in the future.
4700Sstevel@tonic-gate */
4710Sstevel@tonic-gate macinfo->gldm_GLD_version = GLD_VERSION;
4720Sstevel@tonic-gate
4730Sstevel@tonic-gate return (macinfo);
4740Sstevel@tonic-gate }
4750Sstevel@tonic-gate
4760Sstevel@tonic-gate /*
4770Sstevel@tonic-gate * gld_mac_free must be called after the driver has removed interrupts
4780Sstevel@tonic-gate * and completely stopped calling gld_recv() and gld_sched(). At that
4790Sstevel@tonic-gate * point the interrupt routine is guaranteed by the system to have been
4800Sstevel@tonic-gate * exited and the maclock is no longer needed. Of course, it is
4810Sstevel@tonic-gate * expected (required) that (assuming gld_register() succeeded),
4820Sstevel@tonic-gate * gld_unregister() was called before gld_mac_free().
4830Sstevel@tonic-gate */
4840Sstevel@tonic-gate void
gld_mac_free(gld_mac_info_t * macinfo)4850Sstevel@tonic-gate gld_mac_free(gld_mac_info_t *macinfo)
4860Sstevel@tonic-gate {
4870Sstevel@tonic-gate ASSERT(macinfo);
4880Sstevel@tonic-gate ASSERT(macinfo->gldm_GLD_version == GLD_VERSION);
4890Sstevel@tonic-gate
4900Sstevel@tonic-gate /*
4910Sstevel@tonic-gate * Assert that if we made it through gld_register, then we must
4920Sstevel@tonic-gate * have unregistered.
4930Sstevel@tonic-gate */
4940Sstevel@tonic-gate ASSERT(!GLDM_LOCK_INITED(macinfo) ||
4950Sstevel@tonic-gate (macinfo->gldm_GLD_flags & GLD_UNREGISTERED));
4960Sstevel@tonic-gate
4970Sstevel@tonic-gate GLDM_LOCK_DESTROY(macinfo);
4980Sstevel@tonic-gate
4990Sstevel@tonic-gate kmem_free(macinfo, sizeof (gld_mac_info_t) + GLD_MAC_RESERVED);
5000Sstevel@tonic-gate }
5010Sstevel@tonic-gate
5020Sstevel@tonic-gate /*
5030Sstevel@tonic-gate * gld_register -- called once per device instance (PPA)
5040Sstevel@tonic-gate *
5050Sstevel@tonic-gate * During its attach routine, a real device driver will register with GLD
5060Sstevel@tonic-gate * so that later opens and dl_attach_reqs will work. The arguments are the
5070Sstevel@tonic-gate * devinfo pointer, the device name, and a macinfo structure describing the
5080Sstevel@tonic-gate * physical device instance.
5090Sstevel@tonic-gate */
5100Sstevel@tonic-gate int
gld_register(dev_info_t * devinfo,char * devname,gld_mac_info_t * macinfo)5110Sstevel@tonic-gate gld_register(dev_info_t *devinfo, char *devname, gld_mac_info_t *macinfo)
5120Sstevel@tonic-gate {
5130Sstevel@tonic-gate int mediatype;
5140Sstevel@tonic-gate int major = ddi_name_to_major(devname), i;
5150Sstevel@tonic-gate glddev_t *glddev;
5160Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
5170Sstevel@tonic-gate char minordev[32];
5180Sstevel@tonic-gate char pbuf[3*GLD_MAX_ADDRLEN];
5190Sstevel@tonic-gate gld_interface_t *ifp;
5200Sstevel@tonic-gate
5210Sstevel@tonic-gate ASSERT(devinfo != NULL);
5220Sstevel@tonic-gate ASSERT(macinfo != NULL);
5230Sstevel@tonic-gate
5240Sstevel@tonic-gate if (macinfo->gldm_driver_version != GLD_VERSION)
5250Sstevel@tonic-gate return (DDI_FAILURE);
5260Sstevel@tonic-gate
5270Sstevel@tonic-gate mediatype = macinfo->gldm_type;
5280Sstevel@tonic-gate
5290Sstevel@tonic-gate /*
5300Sstevel@tonic-gate * Entry points should be ready for us.
5310Sstevel@tonic-gate * ioctl is optional.
5320Sstevel@tonic-gate * set_multicast and get_stats are optional in v0.
5330Sstevel@tonic-gate * intr is only required if you add an interrupt.
5340Sstevel@tonic-gate */
5350Sstevel@tonic-gate ASSERT(macinfo->gldm_reset != NULL);
5360Sstevel@tonic-gate ASSERT(macinfo->gldm_start != NULL);
5370Sstevel@tonic-gate ASSERT(macinfo->gldm_stop != NULL);
5380Sstevel@tonic-gate ASSERT(macinfo->gldm_set_mac_addr != NULL);
5390Sstevel@tonic-gate ASSERT(macinfo->gldm_set_promiscuous != NULL);
5400Sstevel@tonic-gate ASSERT(macinfo->gldm_send != NULL);
5410Sstevel@tonic-gate
5420Sstevel@tonic-gate ASSERT(macinfo->gldm_maxpkt >= macinfo->gldm_minpkt);
5430Sstevel@tonic-gate ASSERT(macinfo->gldm_GLD_version == GLD_VERSION);
5440Sstevel@tonic-gate ASSERT(macinfo->gldm_broadcast_addr != NULL);
5450Sstevel@tonic-gate ASSERT(macinfo->gldm_vendor_addr != NULL);
5460Sstevel@tonic-gate ASSERT(macinfo->gldm_ident != NULL);
5470Sstevel@tonic-gate
5480Sstevel@tonic-gate if (macinfo->gldm_addrlen > GLD_MAX_ADDRLEN) {
5490Sstevel@tonic-gate cmn_err(CE_WARN, "GLD: %s driver gldm_addrlen %d > %d not sup"
5500Sstevel@tonic-gate "ported", devname, macinfo->gldm_addrlen, GLD_MAX_ADDRLEN);
5510Sstevel@tonic-gate return (DDI_FAILURE);
5520Sstevel@tonic-gate }
5530Sstevel@tonic-gate
5540Sstevel@tonic-gate /*
5550Sstevel@tonic-gate * GLD only functions properly with saplen == -2
5560Sstevel@tonic-gate */
5570Sstevel@tonic-gate if (macinfo->gldm_saplen != -2) {
5580Sstevel@tonic-gate cmn_err(CE_WARN, "GLD: %s driver gldm_saplen %d != -2 "
5590Sstevel@tonic-gate "not supported", devname, macinfo->gldm_saplen);
5600Sstevel@tonic-gate return (DDI_FAILURE);
5610Sstevel@tonic-gate }
5620Sstevel@tonic-gate
5630Sstevel@tonic-gate /* see gld_rsrv() */
5640Sstevel@tonic-gate if (ddi_getprop(DDI_DEV_T_NONE, devinfo, 0, "fast_recv", 0))
5650Sstevel@tonic-gate macinfo->gldm_options |= GLDOPT_FAST_RECV;
5660Sstevel@tonic-gate
5670Sstevel@tonic-gate mutex_enter(&gld_device_list.gld_devlock);
5680Sstevel@tonic-gate glddev = gld_devlookup(major);
5690Sstevel@tonic-gate
5700Sstevel@tonic-gate /*
5710Sstevel@tonic-gate * Allocate per-driver (major) data structure if necessary
5720Sstevel@tonic-gate */
5730Sstevel@tonic-gate if (glddev == NULL) {
5740Sstevel@tonic-gate /* first occurrence of this device name (major number) */
5755903Ssowmini glddev = GLD_GETSTRUCT(glddev_t, 1);
5760Sstevel@tonic-gate if (glddev == NULL) {
5770Sstevel@tonic-gate mutex_exit(&gld_device_list.gld_devlock);
5780Sstevel@tonic-gate return (DDI_FAILURE);
5790Sstevel@tonic-gate }
5800Sstevel@tonic-gate (void) strncpy(glddev->gld_name, devname,
5810Sstevel@tonic-gate sizeof (glddev->gld_name) - 1);
5820Sstevel@tonic-gate glddev->gld_major = major;
5830Sstevel@tonic-gate glddev->gld_nextminor = GLD_MIN_CLONE_MINOR;
5840Sstevel@tonic-gate glddev->gld_mac_next = glddev->gld_mac_prev =
5855903Ssowmini (gld_mac_info_t *)&glddev->gld_mac_next;
5860Sstevel@tonic-gate glddev->gld_str_next = glddev->gld_str_prev =
5875903Ssowmini (gld_t *)&glddev->gld_str_next;
5880Sstevel@tonic-gate mutex_init(&glddev->gld_devlock, NULL, MUTEX_DRIVER, NULL);
5890Sstevel@tonic-gate
5900Sstevel@tonic-gate /* allow increase of number of supported multicast addrs */
5910Sstevel@tonic-gate glddev->gld_multisize = ddi_getprop(DDI_DEV_T_NONE,
5920Sstevel@tonic-gate devinfo, 0, "multisize", GLD_MAX_MULTICAST);
5930Sstevel@tonic-gate
5940Sstevel@tonic-gate /*
5950Sstevel@tonic-gate * Optionally restrict DLPI provider style
5960Sstevel@tonic-gate *
5970Sstevel@tonic-gate * -1 - don't create style 1 nodes
5980Sstevel@tonic-gate * -2 - don't create style 2 nodes
5990Sstevel@tonic-gate */
6000Sstevel@tonic-gate glddev->gld_styles = ddi_getprop(DDI_DEV_T_NONE, devinfo, 0,
6010Sstevel@tonic-gate "gld-provider-styles", 0);
6020Sstevel@tonic-gate
6030Sstevel@tonic-gate /* Stuff that's needed before any PPA gets attached */
6040Sstevel@tonic-gate glddev->gld_type = macinfo->gldm_type;
6050Sstevel@tonic-gate glddev->gld_minsdu = macinfo->gldm_minpkt;
6060Sstevel@tonic-gate glddev->gld_saplen = macinfo->gldm_saplen;
6070Sstevel@tonic-gate glddev->gld_addrlen = macinfo->gldm_addrlen;
6080Sstevel@tonic-gate glddev->gld_broadcast = kmem_zalloc(macinfo->gldm_addrlen,
6090Sstevel@tonic-gate KM_SLEEP);
6100Sstevel@tonic-gate bcopy(macinfo->gldm_broadcast_addr,
6110Sstevel@tonic-gate glddev->gld_broadcast, macinfo->gldm_addrlen);
6120Sstevel@tonic-gate glddev->gld_maxsdu = macinfo->gldm_maxpkt;
6130Sstevel@tonic-gate gldinsque(glddev, gld_device_list.gld_prev);
6140Sstevel@tonic-gate }
6150Sstevel@tonic-gate glddev->gld_ndevice++;
6160Sstevel@tonic-gate /* Now glddev can't go away until we unregister this mac (or fail) */
6170Sstevel@tonic-gate mutex_exit(&gld_device_list.gld_devlock);
6180Sstevel@tonic-gate
6190Sstevel@tonic-gate /*
6200Sstevel@tonic-gate * Per-instance initialization
6210Sstevel@tonic-gate */
6220Sstevel@tonic-gate
6230Sstevel@tonic-gate /*
6240Sstevel@tonic-gate * Initialize per-mac structure that is private to GLD.
6250Sstevel@tonic-gate * Set up interface pointer. These are device class specific pointers
6260Sstevel@tonic-gate * used to handle FDDI/TR/ETHER/IPoIB specific packets.
6270Sstevel@tonic-gate */
6280Sstevel@tonic-gate for (i = 0; i < sizeof (interfaces)/sizeof (*interfaces); i++) {
6290Sstevel@tonic-gate if (mediatype != interfaces[i].mac_type)
6300Sstevel@tonic-gate continue;
6310Sstevel@tonic-gate
6320Sstevel@tonic-gate macinfo->gldm_mac_pvt = kmem_zalloc(sizeof (gld_mac_pvt_t),
6330Sstevel@tonic-gate KM_SLEEP);
6340Sstevel@tonic-gate ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep = ifp =
6350Sstevel@tonic-gate &interfaces[i];
6360Sstevel@tonic-gate break;
6370Sstevel@tonic-gate }
6380Sstevel@tonic-gate
6390Sstevel@tonic-gate if (ifp == NULL) {
6400Sstevel@tonic-gate cmn_err(CE_WARN, "GLD: this version does not support %s driver "
6410Sstevel@tonic-gate "of type %d", devname, mediatype);
6420Sstevel@tonic-gate goto failure;
6430Sstevel@tonic-gate }
6440Sstevel@tonic-gate
6450Sstevel@tonic-gate /*
6460Sstevel@tonic-gate * Driver can only register MTU within legal media range.
6470Sstevel@tonic-gate */
6480Sstevel@tonic-gate if (macinfo->gldm_maxpkt > ifp->mtu_size) {
6490Sstevel@tonic-gate cmn_err(CE_WARN, "GLD: oversize MTU is specified by driver %s",
6500Sstevel@tonic-gate devname);
6510Sstevel@tonic-gate goto failure;
6520Sstevel@tonic-gate }
6530Sstevel@tonic-gate
6540Sstevel@tonic-gate /*
6555895Syz147064 * Correct margin size if it is not set.
6565895Syz147064 */
6575895Syz147064 if (VLAN_CAPABLE(macinfo) && (macinfo->gldm_margin == 0))
6585895Syz147064 macinfo->gldm_margin = VTAG_SIZE;
6595895Syz147064
6605895Syz147064 /*
6610Sstevel@tonic-gate * For now, only Infiniband drivers can use MDT. Do not add
6620Sstevel@tonic-gate * support for Ethernet, FDDI or TR.
6630Sstevel@tonic-gate */
6640Sstevel@tonic-gate if (macinfo->gldm_mdt_pre != NULL) {
6650Sstevel@tonic-gate if (mediatype != DL_IB) {
6660Sstevel@tonic-gate cmn_err(CE_WARN, "GLD: MDT not supported for %s "
6670Sstevel@tonic-gate "driver of type %d", devname, mediatype);
6680Sstevel@tonic-gate goto failure;
6690Sstevel@tonic-gate }
6700Sstevel@tonic-gate
6710Sstevel@tonic-gate /*
6720Sstevel@tonic-gate * Validate entry points.
6730Sstevel@tonic-gate */
6740Sstevel@tonic-gate if ((macinfo->gldm_mdt_send == NULL) ||
6750Sstevel@tonic-gate (macinfo->gldm_mdt_post == NULL)) {
6760Sstevel@tonic-gate cmn_err(CE_WARN, "GLD: invalid MDT entry points for "
6770Sstevel@tonic-gate "%s driver of type %d", devname, mediatype);
6780Sstevel@tonic-gate goto failure;
6790Sstevel@tonic-gate }
6800Sstevel@tonic-gate macinfo->gldm_options |= GLDOPT_MDT;
6810Sstevel@tonic-gate }
6820Sstevel@tonic-gate
6830Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
6840Sstevel@tonic-gate mac_pvt->major_dev = glddev;
6850Sstevel@tonic-gate
6860Sstevel@tonic-gate mac_pvt->curr_macaddr = kmem_zalloc(macinfo->gldm_addrlen, KM_SLEEP);
6870Sstevel@tonic-gate /*
6880Sstevel@tonic-gate * XXX Do bit-reversed devices store gldm_vendor in canonical
6890Sstevel@tonic-gate * format or in wire format? Also gldm_broadcast. For now
6900Sstevel@tonic-gate * we are assuming canonical, but I'm not sure that makes the
6910Sstevel@tonic-gate * most sense for ease of driver implementation.
6920Sstevel@tonic-gate */
6930Sstevel@tonic-gate bcopy(macinfo->gldm_vendor_addr, mac_pvt->curr_macaddr,
6940Sstevel@tonic-gate macinfo->gldm_addrlen);
6950Sstevel@tonic-gate mac_pvt->statistics = kmem_zalloc(sizeof (struct gld_stats), KM_SLEEP);
6960Sstevel@tonic-gate
6970Sstevel@tonic-gate /*
6980Sstevel@tonic-gate * The available set of notifications is those generatable by GLD
6990Sstevel@tonic-gate * itself, plus those corresponding to the capabilities of the MAC
7000Sstevel@tonic-gate * driver, intersected with those supported by gld_notify_ind() above.
7010Sstevel@tonic-gate */
7020Sstevel@tonic-gate mac_pvt->notifications = gld_internal_notes;
7030Sstevel@tonic-gate if (macinfo->gldm_capabilities & GLD_CAP_LINKSTATE)
7040Sstevel@tonic-gate mac_pvt->notifications |= gld_linkstate_notes;
7050Sstevel@tonic-gate mac_pvt->notifications &= gld_supported_notes;
7060Sstevel@tonic-gate
7070Sstevel@tonic-gate GLDM_LOCK_INIT(macinfo);
7080Sstevel@tonic-gate
7090Sstevel@tonic-gate ddi_set_driver_private(devinfo, macinfo);
7100Sstevel@tonic-gate
7110Sstevel@tonic-gate /*
7120Sstevel@tonic-gate * Now atomically get a PPA and put ourselves on the mac list.
7130Sstevel@tonic-gate */
7140Sstevel@tonic-gate mutex_enter(&glddev->gld_devlock);
7150Sstevel@tonic-gate
7160Sstevel@tonic-gate #ifdef DEBUG
7170Sstevel@tonic-gate if (macinfo->gldm_ppa != ddi_get_instance(devinfo))
7180Sstevel@tonic-gate cmn_err(CE_WARN, "%s%d instance != ppa %d",
7190Sstevel@tonic-gate ddi_driver_name(devinfo), ddi_get_instance(devinfo),
7200Sstevel@tonic-gate macinfo->gldm_ppa);
7210Sstevel@tonic-gate #endif
7220Sstevel@tonic-gate
7230Sstevel@tonic-gate /*
7240Sstevel@tonic-gate * Create style 2 node (gated by gld-provider-styles property).
7250Sstevel@tonic-gate *
7260Sstevel@tonic-gate * NOTE: When the CLONE_DEV flag is specified to
7270Sstevel@tonic-gate * ddi_create_minor_node() the minor number argument is
7280Sstevel@tonic-gate * immaterial. Opens of that node will go via the clone
7290Sstevel@tonic-gate * driver and gld_open() will always be passed a dev_t with
7300Sstevel@tonic-gate * minor of zero.
7310Sstevel@tonic-gate */
7320Sstevel@tonic-gate if (glddev->gld_styles != -2) {
7330Sstevel@tonic-gate if (ddi_create_minor_node(devinfo, glddev->gld_name, S_IFCHR,
7340Sstevel@tonic-gate 0, DDI_NT_NET, CLONE_DEV) == DDI_FAILURE) {
7350Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
7360Sstevel@tonic-gate goto late_failure;
7370Sstevel@tonic-gate }
7380Sstevel@tonic-gate }
7390Sstevel@tonic-gate
7400Sstevel@tonic-gate /*
7410Sstevel@tonic-gate * Create style 1 node (gated by gld-provider-styles property)
7420Sstevel@tonic-gate */
7430Sstevel@tonic-gate if (glddev->gld_styles != -1) {
7440Sstevel@tonic-gate (void) sprintf(minordev, "%s%d", glddev->gld_name,
7450Sstevel@tonic-gate macinfo->gldm_ppa);
7460Sstevel@tonic-gate if (ddi_create_minor_node(devinfo, minordev, S_IFCHR,
7470Sstevel@tonic-gate GLD_STYLE1_PPA_TO_MINOR(macinfo->gldm_ppa), DDI_NT_NET,
7480Sstevel@tonic-gate 0) != DDI_SUCCESS) {
7490Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
7500Sstevel@tonic-gate goto late_failure;
7510Sstevel@tonic-gate }
7520Sstevel@tonic-gate }
7530Sstevel@tonic-gate
7540Sstevel@tonic-gate /* add ourselves to this major device's linked list of instances */
7550Sstevel@tonic-gate gldinsque(macinfo, glddev->gld_mac_prev);
7560Sstevel@tonic-gate
7570Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
7580Sstevel@tonic-gate
7590Sstevel@tonic-gate /*
7600Sstevel@tonic-gate * Unfortunately we need the ppa before we call gld_initstats();
7610Sstevel@tonic-gate * otherwise we would like to do this just above the mutex_enter
7620Sstevel@tonic-gate * above. In which case we could have set MAC_READY inside the
7630Sstevel@tonic-gate * mutex and we wouldn't have needed to check it in open and
7640Sstevel@tonic-gate * DL_ATTACH. We wouldn't like to do the initstats/kstat_create
7650Sstevel@tonic-gate * inside the mutex because it might get taken in our kstat_update
7660Sstevel@tonic-gate * routine and cause a deadlock with kstat_chain_lock.
7670Sstevel@tonic-gate */
7680Sstevel@tonic-gate
7690Sstevel@tonic-gate /* gld_initstats() calls (*ifp->init)() */
7700Sstevel@tonic-gate if (gld_initstats(macinfo) != GLD_SUCCESS) {
7710Sstevel@tonic-gate mutex_enter(&glddev->gld_devlock);
7720Sstevel@tonic-gate gldremque(macinfo);
7730Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
7740Sstevel@tonic-gate goto late_failure;
7750Sstevel@tonic-gate }
7760Sstevel@tonic-gate
7770Sstevel@tonic-gate /*
7780Sstevel@tonic-gate * Need to indicate we are NOW ready to process interrupts;
7790Sstevel@tonic-gate * any interrupt before this is set is for someone else.
7800Sstevel@tonic-gate * This flag is also now used to tell open, et. al. that this
7810Sstevel@tonic-gate * mac is now fully ready and available for use.
7820Sstevel@tonic-gate */
7830Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
7840Sstevel@tonic-gate macinfo->gldm_GLD_flags |= GLD_MAC_READY;
7850Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
7860Sstevel@tonic-gate
7870Sstevel@tonic-gate /* log local ethernet address -- XXX not DDI compliant */
7880Sstevel@tonic-gate if (macinfo->gldm_addrlen == sizeof (struct ether_addr))
7890Sstevel@tonic-gate (void) localetheraddr(
7900Sstevel@tonic-gate (struct ether_addr *)macinfo->gldm_vendor_addr, NULL);
7910Sstevel@tonic-gate
7920Sstevel@tonic-gate /* now put announcement into the message buffer */
7930Sstevel@tonic-gate cmn_err(CE_CONT, "!%s%d: %s: type \"%s\" mac address %s\n",
7940Sstevel@tonic-gate glddev->gld_name,
7950Sstevel@tonic-gate macinfo->gldm_ppa, macinfo->gldm_ident,
7960Sstevel@tonic-gate mac_pvt->interfacep->mac_string,
7970Sstevel@tonic-gate gld_macaddr_sprintf(pbuf, macinfo->gldm_vendor_addr,
7980Sstevel@tonic-gate macinfo->gldm_addrlen));
7990Sstevel@tonic-gate
8000Sstevel@tonic-gate ddi_report_dev(devinfo);
8010Sstevel@tonic-gate return (DDI_SUCCESS);
8020Sstevel@tonic-gate
8030Sstevel@tonic-gate late_failure:
8040Sstevel@tonic-gate ddi_remove_minor_node(devinfo, NULL);
8050Sstevel@tonic-gate GLDM_LOCK_DESTROY(macinfo);
8060Sstevel@tonic-gate if (mac_pvt->curr_macaddr != NULL)
8075903Ssowmini kmem_free(mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
8080Sstevel@tonic-gate if (mac_pvt->statistics != NULL)
8095903Ssowmini kmem_free(mac_pvt->statistics, sizeof (struct gld_stats));
8100Sstevel@tonic-gate kmem_free(macinfo->gldm_mac_pvt, sizeof (gld_mac_pvt_t));
8110Sstevel@tonic-gate macinfo->gldm_mac_pvt = NULL;
8120Sstevel@tonic-gate
8130Sstevel@tonic-gate failure:
8140Sstevel@tonic-gate mutex_enter(&gld_device_list.gld_devlock);
8150Sstevel@tonic-gate glddev->gld_ndevice--;
8160Sstevel@tonic-gate /*
8170Sstevel@tonic-gate * Note that just because this goes to zero here does not necessarily
8180Sstevel@tonic-gate * mean that we were the one who added the glddev above. It's
8190Sstevel@tonic-gate * possible that the first mac unattached while were were in here
8200Sstevel@tonic-gate * failing to attach the second mac. But we're now the last.
8210Sstevel@tonic-gate */
8220Sstevel@tonic-gate if (glddev->gld_ndevice == 0) {
8230Sstevel@tonic-gate /* There should be no macinfos left */
8240Sstevel@tonic-gate ASSERT(glddev->gld_mac_next ==
8250Sstevel@tonic-gate (gld_mac_info_t *)&glddev->gld_mac_next);
8260Sstevel@tonic-gate ASSERT(glddev->gld_mac_prev ==
8270Sstevel@tonic-gate (gld_mac_info_t *)&glddev->gld_mac_next);
8280Sstevel@tonic-gate
8290Sstevel@tonic-gate /*
8300Sstevel@tonic-gate * There should be no DL_UNATTACHED streams: the system
8310Sstevel@tonic-gate * should not have detached the "first" devinfo which has
8320Sstevel@tonic-gate * all the open style 2 streams.
8330Sstevel@tonic-gate *
8340Sstevel@tonic-gate * XXX This is not clear. See gld_getinfo and Bug 1165519
8350Sstevel@tonic-gate */
8360Sstevel@tonic-gate ASSERT(glddev->gld_str_next == (gld_t *)&glddev->gld_str_next);
8370Sstevel@tonic-gate ASSERT(glddev->gld_str_prev == (gld_t *)&glddev->gld_str_next);
8380Sstevel@tonic-gate
8390Sstevel@tonic-gate gldremque(glddev);
8400Sstevel@tonic-gate mutex_destroy(&glddev->gld_devlock);
8410Sstevel@tonic-gate if (glddev->gld_broadcast != NULL)
8420Sstevel@tonic-gate kmem_free(glddev->gld_broadcast, glddev->gld_addrlen);
8430Sstevel@tonic-gate kmem_free(glddev, sizeof (glddev_t));
8440Sstevel@tonic-gate }
8450Sstevel@tonic-gate mutex_exit(&gld_device_list.gld_devlock);
8460Sstevel@tonic-gate
8470Sstevel@tonic-gate return (DDI_FAILURE);
8480Sstevel@tonic-gate }
8490Sstevel@tonic-gate
8500Sstevel@tonic-gate /*
8510Sstevel@tonic-gate * gld_unregister (macinfo)
8520Sstevel@tonic-gate * remove the macinfo structure from local structures
8530Sstevel@tonic-gate * this is cleanup for a driver to be unloaded
8540Sstevel@tonic-gate */
8550Sstevel@tonic-gate int
gld_unregister(gld_mac_info_t * macinfo)8560Sstevel@tonic-gate gld_unregister(gld_mac_info_t *macinfo)
8570Sstevel@tonic-gate {
8580Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
8590Sstevel@tonic-gate glddev_t *glddev = mac_pvt->major_dev;
8600Sstevel@tonic-gate gld_interface_t *ifp;
8610Sstevel@tonic-gate int multisize = sizeof (gld_mcast_t) * glddev->gld_multisize;
8620Sstevel@tonic-gate
8630Sstevel@tonic-gate mutex_enter(&glddev->gld_devlock);
8640Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
8650Sstevel@tonic-gate
8660Sstevel@tonic-gate if (mac_pvt->nvlan > 0) {
8670Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
8680Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
8690Sstevel@tonic-gate return (DDI_FAILURE);
8700Sstevel@tonic-gate }
8710Sstevel@tonic-gate
8720Sstevel@tonic-gate #ifdef GLD_DEBUG
8730Sstevel@tonic-gate {
8740Sstevel@tonic-gate int i;
8750Sstevel@tonic-gate
8760Sstevel@tonic-gate for (i = 0; i < VLAN_HASHSZ; i++) {
8770Sstevel@tonic-gate if ((mac_pvt->vlan_hash[i] != NULL))
8780Sstevel@tonic-gate cmn_err(CE_PANIC,
8790Sstevel@tonic-gate "%s, line %d: "
8800Sstevel@tonic-gate "mac_pvt->vlan_hash[%d] != NULL",
8810Sstevel@tonic-gate __FILE__, __LINE__, i);
8820Sstevel@tonic-gate }
8830Sstevel@tonic-gate }
8840Sstevel@tonic-gate #endif
8850Sstevel@tonic-gate
8860Sstevel@tonic-gate /* Delete this mac */
8870Sstevel@tonic-gate gldremque(macinfo);
8880Sstevel@tonic-gate
8890Sstevel@tonic-gate /* Disallow further entries to gld_recv() and gld_sched() */
8900Sstevel@tonic-gate macinfo->gldm_GLD_flags |= GLD_UNREGISTERED;
8910Sstevel@tonic-gate
8920Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
8930Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
8940Sstevel@tonic-gate
8950Sstevel@tonic-gate ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
8960Sstevel@tonic-gate (*ifp->uninit)(macinfo);
8970Sstevel@tonic-gate
8980Sstevel@tonic-gate ASSERT(mac_pvt->kstatp);
8990Sstevel@tonic-gate kstat_delete(mac_pvt->kstatp);
9000Sstevel@tonic-gate
9010Sstevel@tonic-gate ASSERT(GLDM_LOCK_INITED(macinfo));
9020Sstevel@tonic-gate kmem_free(mac_pvt->curr_macaddr, macinfo->gldm_addrlen);
9030Sstevel@tonic-gate kmem_free(mac_pvt->statistics, sizeof (struct gld_stats));
9040Sstevel@tonic-gate
9050Sstevel@tonic-gate if (mac_pvt->mcast_table != NULL)
9060Sstevel@tonic-gate kmem_free(mac_pvt->mcast_table, multisize);
9070Sstevel@tonic-gate kmem_free(macinfo->gldm_mac_pvt, sizeof (gld_mac_pvt_t));
9080Sstevel@tonic-gate macinfo->gldm_mac_pvt = (caddr_t)NULL;
9090Sstevel@tonic-gate
9100Sstevel@tonic-gate /* We now have one fewer instance for this major device */
9110Sstevel@tonic-gate mutex_enter(&gld_device_list.gld_devlock);
9120Sstevel@tonic-gate glddev->gld_ndevice--;
9130Sstevel@tonic-gate if (glddev->gld_ndevice == 0) {
9140Sstevel@tonic-gate /* There should be no macinfos left */
9150Sstevel@tonic-gate ASSERT(glddev->gld_mac_next ==
9160Sstevel@tonic-gate (gld_mac_info_t *)&glddev->gld_mac_next);
9170Sstevel@tonic-gate ASSERT(glddev->gld_mac_prev ==
9180Sstevel@tonic-gate (gld_mac_info_t *)&glddev->gld_mac_next);
9190Sstevel@tonic-gate
9200Sstevel@tonic-gate /*
9210Sstevel@tonic-gate * There should be no DL_UNATTACHED streams: the system
9220Sstevel@tonic-gate * should not have detached the "first" devinfo which has
9230Sstevel@tonic-gate * all the open style 2 streams.
9240Sstevel@tonic-gate *
9250Sstevel@tonic-gate * XXX This is not clear. See gld_getinfo and Bug 1165519
9260Sstevel@tonic-gate */
9270Sstevel@tonic-gate ASSERT(glddev->gld_str_next == (gld_t *)&glddev->gld_str_next);
9280Sstevel@tonic-gate ASSERT(glddev->gld_str_prev == (gld_t *)&glddev->gld_str_next);
9290Sstevel@tonic-gate
9300Sstevel@tonic-gate ddi_remove_minor_node(macinfo->gldm_devinfo, NULL);
9310Sstevel@tonic-gate gldremque(glddev);
9320Sstevel@tonic-gate mutex_destroy(&glddev->gld_devlock);
9330Sstevel@tonic-gate if (glddev->gld_broadcast != NULL)
9340Sstevel@tonic-gate kmem_free(glddev->gld_broadcast, glddev->gld_addrlen);
9350Sstevel@tonic-gate kmem_free(glddev, sizeof (glddev_t));
9360Sstevel@tonic-gate }
9370Sstevel@tonic-gate mutex_exit(&gld_device_list.gld_devlock);
9380Sstevel@tonic-gate
9390Sstevel@tonic-gate return (DDI_SUCCESS);
9400Sstevel@tonic-gate }
9410Sstevel@tonic-gate
9420Sstevel@tonic-gate /*
9430Sstevel@tonic-gate * gld_initstats
9440Sstevel@tonic-gate * called from gld_register
9450Sstevel@tonic-gate */
9460Sstevel@tonic-gate static int
gld_initstats(gld_mac_info_t * macinfo)9470Sstevel@tonic-gate gld_initstats(gld_mac_info_t *macinfo)
9480Sstevel@tonic-gate {
9490Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
9500Sstevel@tonic-gate struct gldkstats *sp;
9510Sstevel@tonic-gate glddev_t *glddev;
9520Sstevel@tonic-gate kstat_t *ksp;
9530Sstevel@tonic-gate gld_interface_t *ifp;
9540Sstevel@tonic-gate
9550Sstevel@tonic-gate glddev = mac_pvt->major_dev;
9560Sstevel@tonic-gate
9570Sstevel@tonic-gate if ((ksp = kstat_create(glddev->gld_name, macinfo->gldm_ppa,
9580Sstevel@tonic-gate NULL, "net", KSTAT_TYPE_NAMED,
9590Sstevel@tonic-gate sizeof (struct gldkstats) / sizeof (kstat_named_t), 0)) == NULL) {
9600Sstevel@tonic-gate cmn_err(CE_WARN,
9610Sstevel@tonic-gate "GLD: failed to create kstat structure for %s%d",
9620Sstevel@tonic-gate glddev->gld_name, macinfo->gldm_ppa);
9630Sstevel@tonic-gate return (GLD_FAILURE);
9640Sstevel@tonic-gate }
9650Sstevel@tonic-gate mac_pvt->kstatp = ksp;
9660Sstevel@tonic-gate
9670Sstevel@tonic-gate ksp->ks_update = gld_update_kstat;
9680Sstevel@tonic-gate ksp->ks_private = (void *)macinfo;
9690Sstevel@tonic-gate
9700Sstevel@tonic-gate sp = ksp->ks_data;
9710Sstevel@tonic-gate kstat_named_init(&sp->glds_pktrcv, "ipackets", KSTAT_DATA_UINT32);
9720Sstevel@tonic-gate kstat_named_init(&sp->glds_pktxmt, "opackets", KSTAT_DATA_UINT32);
9730Sstevel@tonic-gate kstat_named_init(&sp->glds_errrcv, "ierrors", KSTAT_DATA_ULONG);
9740Sstevel@tonic-gate kstat_named_init(&sp->glds_errxmt, "oerrors", KSTAT_DATA_ULONG);
9750Sstevel@tonic-gate kstat_named_init(&sp->glds_bytexmt, "obytes", KSTAT_DATA_UINT32);
9760Sstevel@tonic-gate kstat_named_init(&sp->glds_bytercv, "rbytes", KSTAT_DATA_UINT32);
9770Sstevel@tonic-gate kstat_named_init(&sp->glds_multixmt, "multixmt", KSTAT_DATA_ULONG);
9780Sstevel@tonic-gate kstat_named_init(&sp->glds_multircv, "multircv", KSTAT_DATA_ULONG);
9790Sstevel@tonic-gate kstat_named_init(&sp->glds_brdcstxmt, "brdcstxmt", KSTAT_DATA_ULONG);
9800Sstevel@tonic-gate kstat_named_init(&sp->glds_brdcstrcv, "brdcstrcv", KSTAT_DATA_ULONG);
9810Sstevel@tonic-gate kstat_named_init(&sp->glds_blocked, "blocked", KSTAT_DATA_ULONG);
9820Sstevel@tonic-gate kstat_named_init(&sp->glds_noxmtbuf, "noxmtbuf", KSTAT_DATA_ULONG);
9830Sstevel@tonic-gate kstat_named_init(&sp->glds_norcvbuf, "norcvbuf", KSTAT_DATA_ULONG);
9840Sstevel@tonic-gate kstat_named_init(&sp->glds_xmtretry, "xmtretry", KSTAT_DATA_ULONG);
9850Sstevel@tonic-gate kstat_named_init(&sp->glds_intr, "intr", KSTAT_DATA_ULONG);
9860Sstevel@tonic-gate kstat_named_init(&sp->glds_pktrcv64, "ipackets64", KSTAT_DATA_UINT64);
9870Sstevel@tonic-gate kstat_named_init(&sp->glds_pktxmt64, "opackets64", KSTAT_DATA_UINT64);
9880Sstevel@tonic-gate kstat_named_init(&sp->glds_bytexmt64, "obytes64", KSTAT_DATA_UINT64);
9890Sstevel@tonic-gate kstat_named_init(&sp->glds_bytercv64, "rbytes64", KSTAT_DATA_UINT64);
9900Sstevel@tonic-gate kstat_named_init(&sp->glds_unknowns, "unknowns", KSTAT_DATA_ULONG);
9910Sstevel@tonic-gate kstat_named_init(&sp->glds_speed, "ifspeed", KSTAT_DATA_UINT64);
9920Sstevel@tonic-gate kstat_named_init(&sp->glds_media, "media", KSTAT_DATA_CHAR);
9930Sstevel@tonic-gate kstat_named_init(&sp->glds_prom, "promisc", KSTAT_DATA_CHAR);
9940Sstevel@tonic-gate
9950Sstevel@tonic-gate kstat_named_init(&sp->glds_overflow, "oflo", KSTAT_DATA_ULONG);
9960Sstevel@tonic-gate kstat_named_init(&sp->glds_underflow, "uflo", KSTAT_DATA_ULONG);
9970Sstevel@tonic-gate kstat_named_init(&sp->glds_missed, "missed", KSTAT_DATA_ULONG);
9980Sstevel@tonic-gate
9990Sstevel@tonic-gate kstat_named_init(&sp->glds_xmtbadinterp, "xmt_badinterp",
10000Sstevel@tonic-gate KSTAT_DATA_UINT32);
10010Sstevel@tonic-gate kstat_named_init(&sp->glds_rcvbadinterp, "rcv_badinterp",
10020Sstevel@tonic-gate KSTAT_DATA_UINT32);
10030Sstevel@tonic-gate
10040Sstevel@tonic-gate ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
10050Sstevel@tonic-gate
10060Sstevel@tonic-gate (*ifp->init)(macinfo);
10070Sstevel@tonic-gate
10080Sstevel@tonic-gate kstat_install(ksp);
10090Sstevel@tonic-gate
10100Sstevel@tonic-gate return (GLD_SUCCESS);
10110Sstevel@tonic-gate }
10120Sstevel@tonic-gate
10130Sstevel@tonic-gate /* called from kstat mechanism, and from wsrv's get_statistics_req */
10140Sstevel@tonic-gate static int
gld_update_kstat(kstat_t * ksp,int rw)10150Sstevel@tonic-gate gld_update_kstat(kstat_t *ksp, int rw)
10160Sstevel@tonic-gate {
10170Sstevel@tonic-gate gld_mac_info_t *macinfo;
10180Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
10190Sstevel@tonic-gate struct gldkstats *gsp;
10200Sstevel@tonic-gate struct gld_stats *stats;
10210Sstevel@tonic-gate
10220Sstevel@tonic-gate if (rw == KSTAT_WRITE)
10230Sstevel@tonic-gate return (EACCES);
10240Sstevel@tonic-gate
10250Sstevel@tonic-gate macinfo = (gld_mac_info_t *)ksp->ks_private;
10260Sstevel@tonic-gate ASSERT(macinfo != NULL);
10270Sstevel@tonic-gate
10280Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
10290Sstevel@tonic-gate
10300Sstevel@tonic-gate if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY)) {
10310Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
10320Sstevel@tonic-gate return (EIO); /* this one's not ready yet */
10330Sstevel@tonic-gate }
10340Sstevel@tonic-gate
10350Sstevel@tonic-gate if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
10360Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
10370Sstevel@tonic-gate return (EIO); /* this one's not ready any more */
10380Sstevel@tonic-gate }
10390Sstevel@tonic-gate
10400Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
10410Sstevel@tonic-gate gsp = mac_pvt->kstatp->ks_data;
10420Sstevel@tonic-gate ASSERT(gsp);
10430Sstevel@tonic-gate stats = mac_pvt->statistics;
10440Sstevel@tonic-gate
10450Sstevel@tonic-gate if (macinfo->gldm_get_stats)
10460Sstevel@tonic-gate (void) (*macinfo->gldm_get_stats)(macinfo, stats);
10470Sstevel@tonic-gate
10480Sstevel@tonic-gate gsp->glds_pktxmt.value.ui32 = stats->glds_pktxmt64 & 0xffffffff;
10490Sstevel@tonic-gate gsp->glds_bytexmt.value.ui32 = stats->glds_bytexmt64 & 0xffffffff;
10500Sstevel@tonic-gate gsp->glds_multixmt.value.ul = stats->glds_multixmt;
10510Sstevel@tonic-gate gsp->glds_brdcstxmt.value.ul = stats->glds_brdcstxmt;
10520Sstevel@tonic-gate gsp->glds_noxmtbuf.value.ul = stats->glds_noxmtbuf; /* 0 for now */
10530Sstevel@tonic-gate gsp->glds_xmtretry.value.ul = stats->glds_xmtretry;
10540Sstevel@tonic-gate
10550Sstevel@tonic-gate gsp->glds_pktxmt64.value.ui64 = stats->glds_pktxmt64;
10560Sstevel@tonic-gate gsp->glds_bytexmt64.value.ui64 = stats->glds_bytexmt64;
10570Sstevel@tonic-gate gsp->glds_xmtbadinterp.value.ui32 = stats->glds_xmtbadinterp;
10580Sstevel@tonic-gate
10590Sstevel@tonic-gate gsp->glds_pktrcv.value.ui32 = stats->glds_pktrcv64 & 0xffffffff;
10600Sstevel@tonic-gate gsp->glds_errxmt.value.ul = stats->glds_errxmt;
10610Sstevel@tonic-gate gsp->glds_errrcv.value.ul = stats->glds_errrcv;
10620Sstevel@tonic-gate gsp->glds_bytercv.value.ui32 = stats->glds_bytercv64 & 0xffffffff;
10630Sstevel@tonic-gate gsp->glds_multircv.value.ul = stats->glds_multircv;
10640Sstevel@tonic-gate gsp->glds_brdcstrcv.value.ul = stats->glds_brdcstrcv;
10650Sstevel@tonic-gate gsp->glds_blocked.value.ul = stats->glds_blocked;
10660Sstevel@tonic-gate gsp->glds_overflow.value.ul = stats->glds_overflow;
10670Sstevel@tonic-gate gsp->glds_underflow.value.ul = stats->glds_underflow;
10680Sstevel@tonic-gate gsp->glds_missed.value.ul = stats->glds_missed;
10690Sstevel@tonic-gate gsp->glds_norcvbuf.value.ul = stats->glds_norcvbuf +
10700Sstevel@tonic-gate stats->glds_gldnorcvbuf;
10710Sstevel@tonic-gate gsp->glds_intr.value.ul = stats->glds_intr;
10720Sstevel@tonic-gate
10730Sstevel@tonic-gate gsp->glds_speed.value.ui64 = stats->glds_speed;
10740Sstevel@tonic-gate gsp->glds_unknowns.value.ul = stats->glds_unknowns;
10750Sstevel@tonic-gate gsp->glds_pktrcv64.value.ui64 = stats->glds_pktrcv64;
10760Sstevel@tonic-gate gsp->glds_bytercv64.value.ui64 = stats->glds_bytercv64;
10770Sstevel@tonic-gate gsp->glds_rcvbadinterp.value.ui32 = stats->glds_rcvbadinterp;
10780Sstevel@tonic-gate
10790Sstevel@tonic-gate if (mac_pvt->nprom)
10800Sstevel@tonic-gate (void) strcpy(gsp->glds_prom.value.c, "phys");
10810Sstevel@tonic-gate else if (mac_pvt->nprom_multi)
10820Sstevel@tonic-gate (void) strcpy(gsp->glds_prom.value.c, "multi");
10830Sstevel@tonic-gate else
10840Sstevel@tonic-gate (void) strcpy(gsp->glds_prom.value.c, "off");
10850Sstevel@tonic-gate
10860Sstevel@tonic-gate (void) strcpy(gsp->glds_media.value.c, gld_media[
10870Sstevel@tonic-gate stats->glds_media < sizeof (gld_media) / sizeof (gld_media[0])
10880Sstevel@tonic-gate ? stats->glds_media : 0]);
10890Sstevel@tonic-gate
10900Sstevel@tonic-gate switch (macinfo->gldm_type) {
10910Sstevel@tonic-gate case DL_ETHER:
10920Sstevel@tonic-gate gsp->glds_frame.value.ul = stats->glds_frame;
10930Sstevel@tonic-gate gsp->glds_crc.value.ul = stats->glds_crc;
10940Sstevel@tonic-gate gsp->glds_collisions.value.ul = stats->glds_collisions;
10950Sstevel@tonic-gate gsp->glds_excoll.value.ul = stats->glds_excoll;
10960Sstevel@tonic-gate gsp->glds_defer.value.ul = stats->glds_defer;
10970Sstevel@tonic-gate gsp->glds_short.value.ul = stats->glds_short;
10980Sstevel@tonic-gate gsp->glds_xmtlatecoll.value.ul = stats->glds_xmtlatecoll;
10990Sstevel@tonic-gate gsp->glds_nocarrier.value.ul = stats->glds_nocarrier;
11000Sstevel@tonic-gate gsp->glds_dot3_first_coll.value.ui32 =
11010Sstevel@tonic-gate stats->glds_dot3_first_coll;
11020Sstevel@tonic-gate gsp->glds_dot3_multi_coll.value.ui32 =
11030Sstevel@tonic-gate stats->glds_dot3_multi_coll;
11040Sstevel@tonic-gate gsp->glds_dot3_sqe_error.value.ui32 =
11050Sstevel@tonic-gate stats->glds_dot3_sqe_error;
11060Sstevel@tonic-gate gsp->glds_dot3_mac_xmt_error.value.ui32 =
11070Sstevel@tonic-gate stats->glds_dot3_mac_xmt_error;
11080Sstevel@tonic-gate gsp->glds_dot3_mac_rcv_error.value.ui32 =
11090Sstevel@tonic-gate stats->glds_dot3_mac_rcv_error;
11100Sstevel@tonic-gate gsp->glds_dot3_frame_too_long.value.ui32 =
11110Sstevel@tonic-gate stats->glds_dot3_frame_too_long;
11120Sstevel@tonic-gate (void) strcpy(gsp->glds_duplex.value.c, gld_duplex[
11130Sstevel@tonic-gate stats->glds_duplex <
11140Sstevel@tonic-gate sizeof (gld_duplex) / sizeof (gld_duplex[0]) ?
11150Sstevel@tonic-gate stats->glds_duplex : 0]);
11160Sstevel@tonic-gate break;
11170Sstevel@tonic-gate case DL_TPR:
11180Sstevel@tonic-gate gsp->glds_dot5_line_error.value.ui32 =
11190Sstevel@tonic-gate stats->glds_dot5_line_error;
11200Sstevel@tonic-gate gsp->glds_dot5_burst_error.value.ui32 =
11210Sstevel@tonic-gate stats->glds_dot5_burst_error;
11220Sstevel@tonic-gate gsp->glds_dot5_signal_loss.value.ui32 =
11230Sstevel@tonic-gate stats->glds_dot5_signal_loss;
11240Sstevel@tonic-gate gsp->glds_dot5_ace_error.value.ui32 =
11250Sstevel@tonic-gate stats->glds_dot5_ace_error;
11260Sstevel@tonic-gate gsp->glds_dot5_internal_error.value.ui32 =
11270Sstevel@tonic-gate stats->glds_dot5_internal_error;
11280Sstevel@tonic-gate gsp->glds_dot5_lost_frame_error.value.ui32 =
11290Sstevel@tonic-gate stats->glds_dot5_lost_frame_error;
11300Sstevel@tonic-gate gsp->glds_dot5_frame_copied_error.value.ui32 =
11310Sstevel@tonic-gate stats->glds_dot5_frame_copied_error;
11320Sstevel@tonic-gate gsp->glds_dot5_token_error.value.ui32 =
11330Sstevel@tonic-gate stats->glds_dot5_token_error;
11340Sstevel@tonic-gate gsp->glds_dot5_freq_error.value.ui32 =
11350Sstevel@tonic-gate stats->glds_dot5_freq_error;
11360Sstevel@tonic-gate break;
11370Sstevel@tonic-gate case DL_FDDI:
11380Sstevel@tonic-gate gsp->glds_fddi_mac_error.value.ui32 =
11390Sstevel@tonic-gate stats->glds_fddi_mac_error;
11400Sstevel@tonic-gate gsp->glds_fddi_mac_lost.value.ui32 =
11410Sstevel@tonic-gate stats->glds_fddi_mac_lost;
11420Sstevel@tonic-gate gsp->glds_fddi_mac_token.value.ui32 =
11430Sstevel@tonic-gate stats->glds_fddi_mac_token;
11440Sstevel@tonic-gate gsp->glds_fddi_mac_tvx_expired.value.ui32 =
11450Sstevel@tonic-gate stats->glds_fddi_mac_tvx_expired;
11460Sstevel@tonic-gate gsp->glds_fddi_mac_late.value.ui32 =
11470Sstevel@tonic-gate stats->glds_fddi_mac_late;
11480Sstevel@tonic-gate gsp->glds_fddi_mac_ring_op.value.ui32 =
11490Sstevel@tonic-gate stats->glds_fddi_mac_ring_op;
11500Sstevel@tonic-gate break;
11510Sstevel@tonic-gate case DL_IB:
11520Sstevel@tonic-gate break;
11530Sstevel@tonic-gate default:
11540Sstevel@tonic-gate break;
11550Sstevel@tonic-gate }
11560Sstevel@tonic-gate
11570Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
11580Sstevel@tonic-gate
11590Sstevel@tonic-gate #ifdef GLD_DEBUG
11600Sstevel@tonic-gate gld_check_assertions();
11610Sstevel@tonic-gate if (gld_debug & GLDRDE)
11620Sstevel@tonic-gate gld_sr_dump(macinfo);
11630Sstevel@tonic-gate #endif
11640Sstevel@tonic-gate
11650Sstevel@tonic-gate return (0);
11660Sstevel@tonic-gate }
11670Sstevel@tonic-gate
11680Sstevel@tonic-gate static int
gld_init_vlan_stats(gld_vlan_t * vlan)11690Sstevel@tonic-gate gld_init_vlan_stats(gld_vlan_t *vlan)
11700Sstevel@tonic-gate {
11710Sstevel@tonic-gate gld_mac_info_t *mac = vlan->gldv_mac;
11720Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)mac->gldm_mac_pvt;
11730Sstevel@tonic-gate struct gldkstats *sp;
11740Sstevel@tonic-gate glddev_t *glddev;
11750Sstevel@tonic-gate kstat_t *ksp;
11760Sstevel@tonic-gate char *name;
11770Sstevel@tonic-gate int instance;
11780Sstevel@tonic-gate
11790Sstevel@tonic-gate glddev = mac_pvt->major_dev;
11800Sstevel@tonic-gate name = glddev->gld_name;
11810Sstevel@tonic-gate instance = (vlan->gldv_id * GLD_VLAN_SCALE) + mac->gldm_ppa;
11820Sstevel@tonic-gate
11830Sstevel@tonic-gate if ((ksp = kstat_create(name, instance,
11840Sstevel@tonic-gate NULL, "net", KSTAT_TYPE_NAMED,
11850Sstevel@tonic-gate sizeof (struct gldkstats) / sizeof (kstat_named_t), 0)) == NULL) {
11860Sstevel@tonic-gate cmn_err(CE_WARN,
11870Sstevel@tonic-gate "GLD: failed to create kstat structure for %s%d",
11880Sstevel@tonic-gate name, instance);
11890Sstevel@tonic-gate return (GLD_FAILURE);
11900Sstevel@tonic-gate }
11910Sstevel@tonic-gate
11920Sstevel@tonic-gate vlan->gldv_kstatp = ksp;
11930Sstevel@tonic-gate
11940Sstevel@tonic-gate ksp->ks_update = gld_update_vlan_kstat;
11950Sstevel@tonic-gate ksp->ks_private = (void *)vlan;
11960Sstevel@tonic-gate
11970Sstevel@tonic-gate sp = ksp->ks_data;
11980Sstevel@tonic-gate kstat_named_init(&sp->glds_pktrcv, "ipackets", KSTAT_DATA_UINT32);
11990Sstevel@tonic-gate kstat_named_init(&sp->glds_pktxmt, "opackets", KSTAT_DATA_UINT32);
12000Sstevel@tonic-gate kstat_named_init(&sp->glds_errrcv, "ierrors", KSTAT_DATA_ULONG);
12010Sstevel@tonic-gate kstat_named_init(&sp->glds_errxmt, "oerrors", KSTAT_DATA_ULONG);
12020Sstevel@tonic-gate kstat_named_init(&sp->glds_bytexmt, "obytes", KSTAT_DATA_UINT32);
12030Sstevel@tonic-gate kstat_named_init(&sp->glds_bytercv, "rbytes", KSTAT_DATA_UINT32);
12040Sstevel@tonic-gate kstat_named_init(&sp->glds_multixmt, "multixmt", KSTAT_DATA_ULONG);
12050Sstevel@tonic-gate kstat_named_init(&sp->glds_multircv, "multircv", KSTAT_DATA_ULONG);
12060Sstevel@tonic-gate kstat_named_init(&sp->glds_brdcstxmt, "brdcstxmt", KSTAT_DATA_ULONG);
12070Sstevel@tonic-gate kstat_named_init(&sp->glds_brdcstrcv, "brdcstrcv", KSTAT_DATA_ULONG);
12080Sstevel@tonic-gate kstat_named_init(&sp->glds_blocked, "blocked", KSTAT_DATA_ULONG);
12090Sstevel@tonic-gate kstat_named_init(&sp->glds_noxmtbuf, "noxmtbuf", KSTAT_DATA_ULONG);
12100Sstevel@tonic-gate kstat_named_init(&sp->glds_norcvbuf, "norcvbuf", KSTAT_DATA_ULONG);
12110Sstevel@tonic-gate kstat_named_init(&sp->glds_xmtretry, "xmtretry", KSTAT_DATA_ULONG);
12120Sstevel@tonic-gate kstat_named_init(&sp->glds_intr, "intr", KSTAT_DATA_ULONG);
12130Sstevel@tonic-gate kstat_named_init(&sp->glds_pktrcv64, "ipackets64", KSTAT_DATA_UINT64);
12140Sstevel@tonic-gate kstat_named_init(&sp->glds_pktxmt64, "opackets64", KSTAT_DATA_UINT64);
12150Sstevel@tonic-gate kstat_named_init(&sp->glds_bytexmt64, "obytes64", KSTAT_DATA_UINT64);
12160Sstevel@tonic-gate kstat_named_init(&sp->glds_bytercv64, "rbytes64", KSTAT_DATA_UINT64);
12170Sstevel@tonic-gate kstat_named_init(&sp->glds_unknowns, "unknowns", KSTAT_DATA_ULONG);
12180Sstevel@tonic-gate kstat_named_init(&sp->glds_speed, "ifspeed", KSTAT_DATA_UINT64);
12190Sstevel@tonic-gate kstat_named_init(&sp->glds_media, "media", KSTAT_DATA_CHAR);
12200Sstevel@tonic-gate kstat_named_init(&sp->glds_prom, "promisc", KSTAT_DATA_CHAR);
12210Sstevel@tonic-gate
12220Sstevel@tonic-gate kstat_named_init(&sp->glds_overflow, "oflo", KSTAT_DATA_ULONG);
12230Sstevel@tonic-gate kstat_named_init(&sp->glds_underflow, "uflo", KSTAT_DATA_ULONG);
12240Sstevel@tonic-gate kstat_named_init(&sp->glds_missed, "missed", KSTAT_DATA_ULONG);
12250Sstevel@tonic-gate
12260Sstevel@tonic-gate kstat_named_init(&sp->glds_xmtbadinterp, "xmt_badinterp",
12270Sstevel@tonic-gate KSTAT_DATA_UINT32);
12280Sstevel@tonic-gate kstat_named_init(&sp->glds_rcvbadinterp, "rcv_badinterp",
12290Sstevel@tonic-gate KSTAT_DATA_UINT32);
12300Sstevel@tonic-gate
12310Sstevel@tonic-gate kstat_install(ksp);
12320Sstevel@tonic-gate return (GLD_SUCCESS);
12330Sstevel@tonic-gate }
12340Sstevel@tonic-gate
12350Sstevel@tonic-gate static int
gld_update_vlan_kstat(kstat_t * ksp,int rw)12360Sstevel@tonic-gate gld_update_vlan_kstat(kstat_t *ksp, int rw)
12370Sstevel@tonic-gate {
12380Sstevel@tonic-gate gld_vlan_t *vlan;
12390Sstevel@tonic-gate gld_mac_info_t *macinfo;
12400Sstevel@tonic-gate struct gldkstats *gsp;
12410Sstevel@tonic-gate struct gld_stats *stats;
12422163Syz147064 gld_mac_pvt_t *mac_pvt;
12432163Syz147064 uint32_t media;
12440Sstevel@tonic-gate
12450Sstevel@tonic-gate if (rw == KSTAT_WRITE)
12460Sstevel@tonic-gate return (EACCES);
12470Sstevel@tonic-gate
12480Sstevel@tonic-gate vlan = (gld_vlan_t *)ksp->ks_private;
12490Sstevel@tonic-gate ASSERT(vlan != NULL);
12500Sstevel@tonic-gate
12510Sstevel@tonic-gate macinfo = vlan->gldv_mac;
12520Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
12530Sstevel@tonic-gate
12542163Syz147064 mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
12552163Syz147064
12560Sstevel@tonic-gate gsp = vlan->gldv_kstatp->ks_data;
12570Sstevel@tonic-gate ASSERT(gsp);
12580Sstevel@tonic-gate stats = vlan->gldv_stats;
12590Sstevel@tonic-gate
12600Sstevel@tonic-gate gsp->glds_pktxmt.value.ui32 = stats->glds_pktxmt64 & 0xffffffff;
12610Sstevel@tonic-gate gsp->glds_bytexmt.value.ui32 = stats->glds_bytexmt64 & 0xffffffff;
12620Sstevel@tonic-gate gsp->glds_errxmt.value.ul = stats->glds_errxmt;
12630Sstevel@tonic-gate gsp->glds_multixmt.value.ul = stats->glds_multixmt;
12640Sstevel@tonic-gate gsp->glds_brdcstxmt.value.ul = stats->glds_brdcstxmt;
12650Sstevel@tonic-gate gsp->glds_noxmtbuf.value.ul = stats->glds_noxmtbuf;
12660Sstevel@tonic-gate gsp->glds_xmtretry.value.ul = stats->glds_xmtretry;
12670Sstevel@tonic-gate gsp->glds_pktxmt64.value.ui64 = stats->glds_pktxmt64;
12680Sstevel@tonic-gate gsp->glds_bytexmt64.value.ui64 = stats->glds_bytexmt64;
12690Sstevel@tonic-gate
12700Sstevel@tonic-gate gsp->glds_pktrcv.value.ui32 = stats->glds_pktrcv64 & 0xffffffff;
12710Sstevel@tonic-gate gsp->glds_bytercv.value.ui32 = stats->glds_bytercv64 & 0xffffffff;
12720Sstevel@tonic-gate gsp->glds_errrcv.value.ul = stats->glds_errrcv;
12730Sstevel@tonic-gate gsp->glds_multircv.value.ul = stats->glds_multircv;
12740Sstevel@tonic-gate gsp->glds_brdcstrcv.value.ul = stats->glds_brdcstrcv;
12750Sstevel@tonic-gate gsp->glds_blocked.value.ul = stats->glds_blocked;
12760Sstevel@tonic-gate gsp->glds_pktrcv64.value.ui64 = stats->glds_pktrcv64;
12770Sstevel@tonic-gate gsp->glds_bytercv64.value.ui64 = stats->glds_bytercv64;
12782163Syz147064 gsp->glds_unknowns.value.ul = stats->glds_unknowns;
12792163Syz147064 gsp->glds_xmtbadinterp.value.ui32 = stats->glds_xmtbadinterp;
12802163Syz147064 gsp->glds_rcvbadinterp.value.ui32 = stats->glds_rcvbadinterp;
12812163Syz147064
12822163Syz147064 gsp->glds_speed.value.ui64 = mac_pvt->statistics->glds_speed;
12832163Syz147064 media = mac_pvt->statistics->glds_media;
12842163Syz147064 (void) strcpy(gsp->glds_media.value.c,
12852163Syz147064 gld_media[media < sizeof (gld_media) / sizeof (gld_media[0]) ?
12862163Syz147064 media : 0]);
12870Sstevel@tonic-gate
12880Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
12890Sstevel@tonic-gate return (0);
12900Sstevel@tonic-gate }
12910Sstevel@tonic-gate
12920Sstevel@tonic-gate /*
12930Sstevel@tonic-gate * The device dependent driver specifies gld_getinfo as its getinfo routine.
12940Sstevel@tonic-gate */
12950Sstevel@tonic-gate /*ARGSUSED*/
12960Sstevel@tonic-gate int
gld_getinfo(dev_info_t * dip,ddi_info_cmd_t cmd,void * arg,void ** resultp)12970Sstevel@tonic-gate gld_getinfo(dev_info_t *dip, ddi_info_cmd_t cmd, void *arg, void **resultp)
12980Sstevel@tonic-gate {
12990Sstevel@tonic-gate dev_info_t *devinfo;
13000Sstevel@tonic-gate minor_t minor = getminor((dev_t)arg);
13010Sstevel@tonic-gate int rc = DDI_FAILURE;
13020Sstevel@tonic-gate
13030Sstevel@tonic-gate switch (cmd) {
13040Sstevel@tonic-gate case DDI_INFO_DEVT2DEVINFO:
13050Sstevel@tonic-gate if ((devinfo = gld_finddevinfo((dev_t)arg)) != NULL) {
13060Sstevel@tonic-gate *(dev_info_t **)resultp = devinfo;
13070Sstevel@tonic-gate rc = DDI_SUCCESS;
13080Sstevel@tonic-gate }
13090Sstevel@tonic-gate break;
13100Sstevel@tonic-gate case DDI_INFO_DEVT2INSTANCE:
13110Sstevel@tonic-gate /* Need static mapping for deferred attach */
13120Sstevel@tonic-gate if (minor == GLD_USE_STYLE2) {
13130Sstevel@tonic-gate /*
13140Sstevel@tonic-gate * Style 2: this minor number does not correspond to
13150Sstevel@tonic-gate * any particular instance number.
13160Sstevel@tonic-gate */
13170Sstevel@tonic-gate rc = DDI_FAILURE;
13180Sstevel@tonic-gate } else if (minor <= GLD_MAX_STYLE1_MINOR) {
13190Sstevel@tonic-gate /* Style 1: calculate the PPA from the minor */
13201717Swesolows *resultp = (void *)(uintptr_t)
13211717Swesolows GLD_STYLE1_MINOR_TO_PPA(minor);
13220Sstevel@tonic-gate rc = DDI_SUCCESS;
13230Sstevel@tonic-gate } else {
13240Sstevel@tonic-gate /* Clone: look for it. Not a static mapping */
13250Sstevel@tonic-gate if ((devinfo = gld_finddevinfo((dev_t)arg)) != NULL) {
13261717Swesolows *resultp = (void *)(uintptr_t)
13271717Swesolows ddi_get_instance(devinfo);
13280Sstevel@tonic-gate rc = DDI_SUCCESS;
13290Sstevel@tonic-gate }
13300Sstevel@tonic-gate }
13310Sstevel@tonic-gate break;
13320Sstevel@tonic-gate }
13330Sstevel@tonic-gate
13340Sstevel@tonic-gate return (rc);
13350Sstevel@tonic-gate }
13360Sstevel@tonic-gate
13370Sstevel@tonic-gate /* called from gld_getinfo */
13380Sstevel@tonic-gate dev_info_t *
gld_finddevinfo(dev_t dev)13390Sstevel@tonic-gate gld_finddevinfo(dev_t dev)
13400Sstevel@tonic-gate {
13410Sstevel@tonic-gate minor_t minor = getminor(dev);
13420Sstevel@tonic-gate glddev_t *device;
13430Sstevel@tonic-gate gld_mac_info_t *mac;
13440Sstevel@tonic-gate gld_vlan_t *vlan;
13450Sstevel@tonic-gate gld_t *str;
13460Sstevel@tonic-gate dev_info_t *devinfo = NULL;
13470Sstevel@tonic-gate int i;
13480Sstevel@tonic-gate
13490Sstevel@tonic-gate if (minor == GLD_USE_STYLE2) {
13500Sstevel@tonic-gate /*
13510Sstevel@tonic-gate * Style 2: this minor number does not correspond to
13520Sstevel@tonic-gate * any particular instance number.
13530Sstevel@tonic-gate *
13540Sstevel@tonic-gate * XXX We don't know what to say. See Bug 1165519.
13550Sstevel@tonic-gate */
13560Sstevel@tonic-gate return (NULL);
13570Sstevel@tonic-gate }
13580Sstevel@tonic-gate
13590Sstevel@tonic-gate mutex_enter(&gld_device_list.gld_devlock); /* hold the device */
13600Sstevel@tonic-gate
13610Sstevel@tonic-gate device = gld_devlookup(getmajor(dev));
13620Sstevel@tonic-gate if (device == NULL) {
13630Sstevel@tonic-gate /* There are no attached instances of this device */
13640Sstevel@tonic-gate mutex_exit(&gld_device_list.gld_devlock);
13650Sstevel@tonic-gate return (NULL);
13660Sstevel@tonic-gate }
13670Sstevel@tonic-gate
13680Sstevel@tonic-gate /*
13690Sstevel@tonic-gate * Search all attached macs and streams.
13700Sstevel@tonic-gate *
13710Sstevel@tonic-gate * XXX We don't bother checking the DL_UNATTACHED streams since
13720Sstevel@tonic-gate * we don't know what devinfo we should report back even if we
13730Sstevel@tonic-gate * found the minor. Maybe we should associate streams that are
13740Sstevel@tonic-gate * not currently attached to a PPA with the "first" devinfo node
13750Sstevel@tonic-gate * of the major device to attach -- the one that created the
13760Sstevel@tonic-gate * minor node for the generic device.
13770Sstevel@tonic-gate */
13780Sstevel@tonic-gate mutex_enter(&device->gld_devlock);
13790Sstevel@tonic-gate
13800Sstevel@tonic-gate for (mac = device->gld_mac_next;
13810Sstevel@tonic-gate mac != (gld_mac_info_t *)&device->gld_mac_next;
13820Sstevel@tonic-gate mac = mac->gldm_next) {
13830Sstevel@tonic-gate gld_mac_pvt_t *pvt = (gld_mac_pvt_t *)mac->gldm_mac_pvt;
13840Sstevel@tonic-gate
13850Sstevel@tonic-gate if (!(mac->gldm_GLD_flags & GLD_MAC_READY))
13860Sstevel@tonic-gate continue; /* this one's not ready yet */
13870Sstevel@tonic-gate if (minor <= GLD_MAX_STYLE1_MINOR) {
13880Sstevel@tonic-gate /* Style 1 -- look for the corresponding PPA */
13890Sstevel@tonic-gate if (minor == GLD_STYLE1_PPA_TO_MINOR(mac->gldm_ppa)) {
13900Sstevel@tonic-gate devinfo = mac->gldm_devinfo;
13910Sstevel@tonic-gate goto out; /* found it! */
13920Sstevel@tonic-gate } else
13930Sstevel@tonic-gate continue; /* not this PPA */
13940Sstevel@tonic-gate }
13950Sstevel@tonic-gate
13960Sstevel@tonic-gate /* We are looking for a clone */
13970Sstevel@tonic-gate for (i = 0; i < VLAN_HASHSZ; i++) {
13980Sstevel@tonic-gate for (vlan = pvt->vlan_hash[i];
13990Sstevel@tonic-gate vlan != NULL; vlan = vlan->gldv_next) {
14000Sstevel@tonic-gate for (str = vlan->gldv_str_next;
14010Sstevel@tonic-gate str != (gld_t *)&vlan->gldv_str_next;
14020Sstevel@tonic-gate str = str->gld_next) {
14030Sstevel@tonic-gate ASSERT(str->gld_mac_info == mac);
14040Sstevel@tonic-gate if (minor == str->gld_minor) {
14050Sstevel@tonic-gate devinfo = mac->gldm_devinfo;
14060Sstevel@tonic-gate goto out;
14070Sstevel@tonic-gate }
14080Sstevel@tonic-gate }
14090Sstevel@tonic-gate }
14100Sstevel@tonic-gate }
14110Sstevel@tonic-gate }
14120Sstevel@tonic-gate out:
14130Sstevel@tonic-gate mutex_exit(&device->gld_devlock);
14140Sstevel@tonic-gate mutex_exit(&gld_device_list.gld_devlock);
14150Sstevel@tonic-gate return (devinfo);
14160Sstevel@tonic-gate }
14170Sstevel@tonic-gate
14180Sstevel@tonic-gate /*
14190Sstevel@tonic-gate * STREAMS open routine. The device dependent driver specifies this as its
14200Sstevel@tonic-gate * open entry point.
14210Sstevel@tonic-gate */
14220Sstevel@tonic-gate /*ARGSUSED2*/
14230Sstevel@tonic-gate int
gld_open(queue_t * q,dev_t * dev,int flag,int sflag,cred_t * cred)14240Sstevel@tonic-gate gld_open(queue_t *q, dev_t *dev, int flag, int sflag, cred_t *cred)
14250Sstevel@tonic-gate {
14260Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
14270Sstevel@tonic-gate gld_t *gld;
14280Sstevel@tonic-gate glddev_t *glddev;
14290Sstevel@tonic-gate gld_mac_info_t *macinfo;
14300Sstevel@tonic-gate minor_t minor = getminor(*dev);
14310Sstevel@tonic-gate gld_vlan_t *vlan;
14320Sstevel@tonic-gate t_uscalar_t ppa;
14330Sstevel@tonic-gate
14340Sstevel@tonic-gate ASSERT(q != NULL);
14350Sstevel@tonic-gate
14360Sstevel@tonic-gate if (minor > GLD_MAX_STYLE1_MINOR)
14370Sstevel@tonic-gate return (ENXIO);
14380Sstevel@tonic-gate
14390Sstevel@tonic-gate ASSERT(q->q_ptr == NULL); /* Clone device gives us a fresh Q */
14400Sstevel@tonic-gate
14410Sstevel@tonic-gate /* Find our per-major glddev_t structure */
14420Sstevel@tonic-gate mutex_enter(&gld_device_list.gld_devlock);
14430Sstevel@tonic-gate glddev = gld_devlookup(getmajor(*dev));
14440Sstevel@tonic-gate
14450Sstevel@tonic-gate /*
14460Sstevel@tonic-gate * This glddev will hang around since detach (and therefore
14470Sstevel@tonic-gate * gld_unregister) can't run while we're here in the open routine.
14480Sstevel@tonic-gate */
14490Sstevel@tonic-gate mutex_exit(&gld_device_list.gld_devlock);
14500Sstevel@tonic-gate
14510Sstevel@tonic-gate if (glddev == NULL)
14520Sstevel@tonic-gate return (ENXIO);
14530Sstevel@tonic-gate
14540Sstevel@tonic-gate #ifdef GLD_DEBUG
14550Sstevel@tonic-gate if (gld_debug & GLDPROT) {
14560Sstevel@tonic-gate if (minor == GLD_USE_STYLE2)
14570Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_open(%p, Style 2)", (void *)q);
14580Sstevel@tonic-gate else
14590Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_open(%p, Style 1, minor = %d)",
14600Sstevel@tonic-gate (void *)q, minor);
14610Sstevel@tonic-gate }
14620Sstevel@tonic-gate #endif
14630Sstevel@tonic-gate
14640Sstevel@tonic-gate /*
14650Sstevel@tonic-gate * get a per-stream structure and link things together so we
14660Sstevel@tonic-gate * can easily find them later.
14670Sstevel@tonic-gate */
14680Sstevel@tonic-gate gld = kmem_zalloc(sizeof (gld_t), KM_SLEEP);
14690Sstevel@tonic-gate
14700Sstevel@tonic-gate /*
14710Sstevel@tonic-gate * fill in the structure and state info
14720Sstevel@tonic-gate */
14730Sstevel@tonic-gate gld->gld_qptr = q;
14740Sstevel@tonic-gate gld->gld_device = glddev;
14750Sstevel@tonic-gate gld->gld_state = DL_UNATTACHED;
14760Sstevel@tonic-gate
14770Sstevel@tonic-gate /*
14780Sstevel@tonic-gate * we must atomically find a free minor number and add the stream
14790Sstevel@tonic-gate * to a list, because gld_findminor has to traverse the lists to
14800Sstevel@tonic-gate * determine which minor numbers are free.
14810Sstevel@tonic-gate */
14820Sstevel@tonic-gate mutex_enter(&glddev->gld_devlock);
14830Sstevel@tonic-gate
14840Sstevel@tonic-gate /* find a free minor device number for the clone */
14850Sstevel@tonic-gate gld->gld_minor = gld_findminor(glddev);
14860Sstevel@tonic-gate if (gld->gld_minor == 0) {
14870Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
14880Sstevel@tonic-gate kmem_free(gld, sizeof (gld_t));
14890Sstevel@tonic-gate return (ENOSR);
14900Sstevel@tonic-gate }
14910Sstevel@tonic-gate
14920Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
14930Sstevel@tonic-gate if (gld_debug & GLDPROT)
14940Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_open() gld ptr: %p minor: %d",
14950Sstevel@tonic-gate (void *)gld, gld->gld_minor);
14960Sstevel@tonic-gate #endif
14970Sstevel@tonic-gate
14980Sstevel@tonic-gate if (minor == GLD_USE_STYLE2) {
14990Sstevel@tonic-gate gld->gld_style = DL_STYLE2;
15000Sstevel@tonic-gate *dev = makedevice(getmajor(*dev), gld->gld_minor);
15010Sstevel@tonic-gate WR(q)->q_ptr = q->q_ptr = (caddr_t)gld;
15020Sstevel@tonic-gate gldinsque(gld, glddev->gld_str_prev);
15030Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
15040Sstevel@tonic-gate if (gld_debug & GLDPROT)
15050Sstevel@tonic-gate cmn_err(CE_NOTE, "GLDstruct added to device list");
15060Sstevel@tonic-gate #endif
15070Sstevel@tonic-gate (void) qassociate(q, -1);
15080Sstevel@tonic-gate goto done;
15090Sstevel@tonic-gate }
15100Sstevel@tonic-gate
15110Sstevel@tonic-gate gld->gld_style = DL_STYLE1;
15120Sstevel@tonic-gate
15130Sstevel@tonic-gate /* the PPA is actually 1 less than the minordev */
15140Sstevel@tonic-gate ppa = GLD_STYLE1_MINOR_TO_PPA(minor);
15150Sstevel@tonic-gate
15160Sstevel@tonic-gate for (macinfo = glddev->gld_mac_next;
15170Sstevel@tonic-gate macinfo != (gld_mac_info_t *)(&glddev->gld_mac_next);
15180Sstevel@tonic-gate macinfo = macinfo->gldm_next) {
15190Sstevel@tonic-gate ASSERT(macinfo != NULL);
15200Sstevel@tonic-gate if (macinfo->gldm_ppa != ppa)
15210Sstevel@tonic-gate continue;
15220Sstevel@tonic-gate
15230Sstevel@tonic-gate if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY))
15240Sstevel@tonic-gate continue; /* this one's not ready yet */
15250Sstevel@tonic-gate
15260Sstevel@tonic-gate /*
15270Sstevel@tonic-gate * we found the correct PPA
15280Sstevel@tonic-gate */
15290Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
15300Sstevel@tonic-gate
15310Sstevel@tonic-gate gld->gld_mac_info = macinfo;
15320Sstevel@tonic-gate
15330Sstevel@tonic-gate if (macinfo->gldm_send_tagged != NULL)
15340Sstevel@tonic-gate gld->gld_send = macinfo->gldm_send_tagged;
15350Sstevel@tonic-gate else
15360Sstevel@tonic-gate gld->gld_send = macinfo->gldm_send;
15370Sstevel@tonic-gate
15380Sstevel@tonic-gate /* now ready for action */
15390Sstevel@tonic-gate gld->gld_state = DL_UNBOUND;
15400Sstevel@tonic-gate
15410Sstevel@tonic-gate if ((vlan = gld_get_vlan(macinfo, VLAN_VID_NONE)) == NULL) {
15420Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
15430Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
15440Sstevel@tonic-gate kmem_free(gld, sizeof (gld_t));
15450Sstevel@tonic-gate return (EIO);
15460Sstevel@tonic-gate }
15470Sstevel@tonic-gate
15480Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
15490Sstevel@tonic-gate if (!mac_pvt->started) {
15500Sstevel@tonic-gate if (gld_start_mac(macinfo) != GLD_SUCCESS) {
15511521Syz147064 gld_rem_vlan(vlan);
15520Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
15530Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
15540Sstevel@tonic-gate kmem_free(gld, sizeof (gld_t));
15550Sstevel@tonic-gate return (EIO);
15560Sstevel@tonic-gate }
15570Sstevel@tonic-gate }
15580Sstevel@tonic-gate
15590Sstevel@tonic-gate gld->gld_vlan = vlan;
15600Sstevel@tonic-gate vlan->gldv_nstreams++;
15610Sstevel@tonic-gate gldinsque(gld, vlan->gldv_str_prev);
15620Sstevel@tonic-gate *dev = makedevice(getmajor(*dev), gld->gld_minor);
15630Sstevel@tonic-gate WR(q)->q_ptr = q->q_ptr = (caddr_t)gld;
15640Sstevel@tonic-gate
15650Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
15660Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
15670Sstevel@tonic-gate if (gld_debug & GLDPROT)
15680Sstevel@tonic-gate cmn_err(CE_NOTE,
15690Sstevel@tonic-gate "GLDstruct added to instance list");
15700Sstevel@tonic-gate #endif
15710Sstevel@tonic-gate break;
15720Sstevel@tonic-gate }
15730Sstevel@tonic-gate
15740Sstevel@tonic-gate if (gld->gld_state == DL_UNATTACHED) {
15750Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
15760Sstevel@tonic-gate kmem_free(gld, sizeof (gld_t));
15770Sstevel@tonic-gate return (ENXIO);
15780Sstevel@tonic-gate }
15790Sstevel@tonic-gate
15800Sstevel@tonic-gate done:
15810Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
15820Sstevel@tonic-gate noenable(WR(q)); /* We'll do the qenables manually */
15830Sstevel@tonic-gate qprocson(q); /* start the queues running */
15840Sstevel@tonic-gate qenable(WR(q));
15850Sstevel@tonic-gate return (0);
15860Sstevel@tonic-gate }
15870Sstevel@tonic-gate
15880Sstevel@tonic-gate /*
15890Sstevel@tonic-gate * normal stream close call checks current status and cleans up
15900Sstevel@tonic-gate * data structures that were dynamically allocated
15910Sstevel@tonic-gate */
15920Sstevel@tonic-gate /*ARGSUSED1*/
15930Sstevel@tonic-gate int
gld_close(queue_t * q,int flag,cred_t * cred)15940Sstevel@tonic-gate gld_close(queue_t *q, int flag, cred_t *cred)
15950Sstevel@tonic-gate {
15960Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
15970Sstevel@tonic-gate glddev_t *glddev = gld->gld_device;
15980Sstevel@tonic-gate
15990Sstevel@tonic-gate ASSERT(q);
16000Sstevel@tonic-gate ASSERT(gld);
16010Sstevel@tonic-gate
16020Sstevel@tonic-gate #ifdef GLD_DEBUG
16030Sstevel@tonic-gate if (gld_debug & GLDPROT) {
16040Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_close(%p, Style %d)",
16050Sstevel@tonic-gate (void *)q, (gld->gld_style & 0x1) + 1);
16060Sstevel@tonic-gate }
16070Sstevel@tonic-gate #endif
16080Sstevel@tonic-gate
16090Sstevel@tonic-gate /* Hold all device streams lists still while we check for a macinfo */
16100Sstevel@tonic-gate mutex_enter(&glddev->gld_devlock);
16110Sstevel@tonic-gate
16120Sstevel@tonic-gate if (gld->gld_mac_info != NULL) {
16130Sstevel@tonic-gate /* If there's a macinfo, block recv while we change state */
16140Sstevel@tonic-gate GLDM_LOCK(gld->gld_mac_info, RW_WRITER);
16150Sstevel@tonic-gate gld->gld_flags |= GLD_STR_CLOSING; /* no more rcv putnexts */
16160Sstevel@tonic-gate GLDM_UNLOCK(gld->gld_mac_info);
16170Sstevel@tonic-gate } else {
16180Sstevel@tonic-gate /* no mac DL_ATTACHED right now */
16190Sstevel@tonic-gate gld->gld_flags |= GLD_STR_CLOSING;
16200Sstevel@tonic-gate }
16210Sstevel@tonic-gate
16220Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
16230Sstevel@tonic-gate
16240Sstevel@tonic-gate /*
16250Sstevel@tonic-gate * qprocsoff before we call gld_unbind/gldunattach, so that
16260Sstevel@tonic-gate * we know wsrv isn't in there trying to undo what we're doing.
16270Sstevel@tonic-gate */
16280Sstevel@tonic-gate qprocsoff(q);
16290Sstevel@tonic-gate
16300Sstevel@tonic-gate ASSERT(gld->gld_wput_count == 0);
16310Sstevel@tonic-gate gld->gld_wput_count = 0; /* just in case */
16320Sstevel@tonic-gate
16330Sstevel@tonic-gate if (gld->gld_state == DL_IDLE) {
16340Sstevel@tonic-gate /* Need to unbind */
16350Sstevel@tonic-gate ASSERT(gld->gld_mac_info != NULL);
16360Sstevel@tonic-gate (void) gld_unbind(WR(q), NULL);
16370Sstevel@tonic-gate }
16380Sstevel@tonic-gate
16390Sstevel@tonic-gate if (gld->gld_state == DL_UNBOUND) {
16400Sstevel@tonic-gate /*
16410Sstevel@tonic-gate * Need to unattach
16420Sstevel@tonic-gate * For style 2 stream, gldunattach also
16430Sstevel@tonic-gate * associate queue with NULL dip
16440Sstevel@tonic-gate */
16450Sstevel@tonic-gate ASSERT(gld->gld_mac_info != NULL);
16460Sstevel@tonic-gate (void) gldunattach(WR(q), NULL);
16470Sstevel@tonic-gate }
16480Sstevel@tonic-gate
16490Sstevel@tonic-gate /* disassociate the stream from the device */
16500Sstevel@tonic-gate q->q_ptr = WR(q)->q_ptr = NULL;
16510Sstevel@tonic-gate
16520Sstevel@tonic-gate /*
16530Sstevel@tonic-gate * Since we unattached above (if necessary), we know that we're
16540Sstevel@tonic-gate * on the per-major list of unattached streams, rather than a
16550Sstevel@tonic-gate * per-PPA list. So we know we should hold the devlock.
16560Sstevel@tonic-gate */
16570Sstevel@tonic-gate mutex_enter(&glddev->gld_devlock);
16580Sstevel@tonic-gate gldremque(gld); /* remove from Style 2 list */
16590Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
16600Sstevel@tonic-gate
16610Sstevel@tonic-gate kmem_free(gld, sizeof (gld_t));
16620Sstevel@tonic-gate
16630Sstevel@tonic-gate return (0);
16640Sstevel@tonic-gate }
16650Sstevel@tonic-gate
16660Sstevel@tonic-gate /*
16670Sstevel@tonic-gate * gld_rsrv (q)
16680Sstevel@tonic-gate * simple read service procedure
16690Sstevel@tonic-gate * purpose is to avoid the time it takes for packets
16700Sstevel@tonic-gate * to move through IP so we can get them off the board
16710Sstevel@tonic-gate * as fast as possible due to limited PC resources.
16720Sstevel@tonic-gate *
16730Sstevel@tonic-gate * This is not normally used in the current implementation. It
16740Sstevel@tonic-gate * can be selected with the undocumented property "fast_recv".
16750Sstevel@tonic-gate * If that property is set, gld_recv will send the packet
16760Sstevel@tonic-gate * upstream with a putq() rather than a putnext(), thus causing
16770Sstevel@tonic-gate * this routine to be scheduled.
16780Sstevel@tonic-gate */
16790Sstevel@tonic-gate int
gld_rsrv(queue_t * q)16800Sstevel@tonic-gate gld_rsrv(queue_t *q)
16810Sstevel@tonic-gate {
16820Sstevel@tonic-gate mblk_t *mp;
16830Sstevel@tonic-gate
16840Sstevel@tonic-gate while ((mp = getq(q)) != NULL) {
16850Sstevel@tonic-gate if (canputnext(q)) {
16860Sstevel@tonic-gate putnext(q, mp);
16870Sstevel@tonic-gate } else {
16880Sstevel@tonic-gate freemsg(mp);
16890Sstevel@tonic-gate }
16900Sstevel@tonic-gate }
16910Sstevel@tonic-gate return (0);
16920Sstevel@tonic-gate }
16930Sstevel@tonic-gate
16940Sstevel@tonic-gate /*
16950Sstevel@tonic-gate * gld_wput (q, mp)
16960Sstevel@tonic-gate * general gld stream write put routine. Receives fastpath data from upper
16970Sstevel@tonic-gate * modules and processes it immediately. ioctl and M_PROTO/M_PCPROTO are
16980Sstevel@tonic-gate * queued for later processing by the service procedure.
16990Sstevel@tonic-gate */
17000Sstevel@tonic-gate
17010Sstevel@tonic-gate int
gld_wput(queue_t * q,mblk_t * mp)17020Sstevel@tonic-gate gld_wput(queue_t *q, mblk_t *mp)
17030Sstevel@tonic-gate {
17040Sstevel@tonic-gate gld_t *gld = (gld_t *)(q->q_ptr);
17050Sstevel@tonic-gate int rc;
17060Sstevel@tonic-gate boolean_t multidata = B_TRUE;
17072760Sdg199075 uint32_t upri;
17080Sstevel@tonic-gate
17090Sstevel@tonic-gate #ifdef GLD_DEBUG
17100Sstevel@tonic-gate if (gld_debug & GLDTRACE)
17110Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_wput(%p %p): type %x",
17120Sstevel@tonic-gate (void *)q, (void *)mp, DB_TYPE(mp));
17130Sstevel@tonic-gate #endif
17140Sstevel@tonic-gate switch (DB_TYPE(mp)) {
17150Sstevel@tonic-gate
17160Sstevel@tonic-gate case M_DATA:
17170Sstevel@tonic-gate /* fast data / raw support */
17180Sstevel@tonic-gate /* we must be DL_ATTACHED and DL_BOUND to do this */
17190Sstevel@tonic-gate /* Tricky to access memory without taking the mutex */
17200Sstevel@tonic-gate if ((gld->gld_flags & (GLD_RAW | GLD_FAST)) == 0 ||
17210Sstevel@tonic-gate gld->gld_state != DL_IDLE) {
17220Sstevel@tonic-gate merror(q, mp, EPROTO);
17230Sstevel@tonic-gate break;
17240Sstevel@tonic-gate }
17252760Sdg199075 /*
17262760Sdg199075 * Cleanup MBLK_VTAG in case it is set by other
17272760Sdg199075 * modules. MBLK_VTAG is used to save the vtag information.
17282760Sdg199075 */
17292760Sdg199075 GLD_CLEAR_MBLK_VTAG(mp);
17300Sstevel@tonic-gate multidata = B_FALSE;
17310Sstevel@tonic-gate /* LINTED: E_CASE_FALLTHRU */
17320Sstevel@tonic-gate case M_MULTIDATA:
17330Sstevel@tonic-gate /* Only call gld_start() directly if nothing queued ahead */
17340Sstevel@tonic-gate /* No guarantees about ordering with different threads */
17350Sstevel@tonic-gate if (q->q_first)
17360Sstevel@tonic-gate goto use_wsrv;
17370Sstevel@tonic-gate
17380Sstevel@tonic-gate /*
17390Sstevel@tonic-gate * This can happen if wsrv has taken off the last mblk but
17400Sstevel@tonic-gate * is still processing it.
17410Sstevel@tonic-gate */
17420Sstevel@tonic-gate membar_consumer();
17430Sstevel@tonic-gate if (gld->gld_in_wsrv)
17440Sstevel@tonic-gate goto use_wsrv;
17450Sstevel@tonic-gate
17460Sstevel@tonic-gate /*
17470Sstevel@tonic-gate * Keep a count of current wput calls to start.
17480Sstevel@tonic-gate * Nonzero count delays any attempted DL_UNBIND.
17490Sstevel@tonic-gate * See comments above gld_start().
17500Sstevel@tonic-gate */
17510Sstevel@tonic-gate atomic_add_32((uint32_t *)&gld->gld_wput_count, 1);
17520Sstevel@tonic-gate membar_enter();
17530Sstevel@tonic-gate
17540Sstevel@tonic-gate /* Recheck state now wput_count is set to prevent DL_UNBIND */
17550Sstevel@tonic-gate /* If this Q is in process of DL_UNBIND, don't call start */
17560Sstevel@tonic-gate if (gld->gld_state != DL_IDLE || gld->gld_in_unbind) {
17570Sstevel@tonic-gate /* Extremely unlikely */
17580Sstevel@tonic-gate atomic_add_32((uint32_t *)&gld->gld_wput_count, -1);
17590Sstevel@tonic-gate goto use_wsrv;
17600Sstevel@tonic-gate }
17610Sstevel@tonic-gate
17622760Sdg199075 /*
17632760Sdg199075 * Get the priority value. Note that in raw mode, the
17642760Sdg199075 * per-packet priority value kept in b_band is ignored.
17652760Sdg199075 */
17662760Sdg199075 upri = (gld->gld_flags & GLD_RAW) ? gld->gld_upri :
17672760Sdg199075 UPRI(gld, mp->b_band);
17682760Sdg199075
17690Sstevel@tonic-gate rc = (multidata) ? gld_start_mdt(q, mp, GLD_WPUT) :
17702760Sdg199075 gld_start(q, mp, GLD_WPUT, upri);
17710Sstevel@tonic-gate
17720Sstevel@tonic-gate /* Allow DL_UNBIND again */
17730Sstevel@tonic-gate membar_exit();
17740Sstevel@tonic-gate atomic_add_32((uint32_t *)&gld->gld_wput_count, -1);
17750Sstevel@tonic-gate
17760Sstevel@tonic-gate if (rc == GLD_NORESOURCES)
17770Sstevel@tonic-gate qenable(q);
17780Sstevel@tonic-gate break; /* Done with this packet */
17790Sstevel@tonic-gate
17800Sstevel@tonic-gate use_wsrv:
17810Sstevel@tonic-gate /* Q not empty, in DL_DETACH, or start gave NORESOURCES */
17820Sstevel@tonic-gate (void) putq(q, mp);
17830Sstevel@tonic-gate qenable(q);
17840Sstevel@tonic-gate break;
17850Sstevel@tonic-gate
17860Sstevel@tonic-gate case M_IOCTL:
17870Sstevel@tonic-gate /* ioctl relies on wsrv single threading per queue */
17880Sstevel@tonic-gate (void) putq(q, mp);
17890Sstevel@tonic-gate qenable(q);
17900Sstevel@tonic-gate break;
17910Sstevel@tonic-gate
17920Sstevel@tonic-gate case M_CTL:
17930Sstevel@tonic-gate (void) putq(q, mp);
17940Sstevel@tonic-gate qenable(q);
17950Sstevel@tonic-gate break;
17960Sstevel@tonic-gate
17970Sstevel@tonic-gate case M_FLUSH: /* canonical flush handling */
17980Sstevel@tonic-gate /* XXX Should these be FLUSHALL? */
17990Sstevel@tonic-gate if (*mp->b_rptr & FLUSHW)
18000Sstevel@tonic-gate flushq(q, 0);
18010Sstevel@tonic-gate if (*mp->b_rptr & FLUSHR) {
18020Sstevel@tonic-gate flushq(RD(q), 0);
18030Sstevel@tonic-gate *mp->b_rptr &= ~FLUSHW;
18040Sstevel@tonic-gate qreply(q, mp);
18050Sstevel@tonic-gate } else
18060Sstevel@tonic-gate freemsg(mp);
18070Sstevel@tonic-gate break;
18080Sstevel@tonic-gate
18090Sstevel@tonic-gate case M_PROTO:
18100Sstevel@tonic-gate case M_PCPROTO:
18110Sstevel@tonic-gate /* these rely on wsrv single threading per queue */
18120Sstevel@tonic-gate (void) putq(q, mp);
18130Sstevel@tonic-gate qenable(q);
18140Sstevel@tonic-gate break;
18150Sstevel@tonic-gate
18160Sstevel@tonic-gate default:
18170Sstevel@tonic-gate #ifdef GLD_DEBUG
18180Sstevel@tonic-gate if (gld_debug & GLDETRACE)
18190Sstevel@tonic-gate cmn_err(CE_WARN,
18200Sstevel@tonic-gate "gld: Unexpected packet type from queue: 0x%x",
18210Sstevel@tonic-gate DB_TYPE(mp));
18220Sstevel@tonic-gate #endif
18230Sstevel@tonic-gate freemsg(mp);
18240Sstevel@tonic-gate }
18250Sstevel@tonic-gate return (0);
18260Sstevel@tonic-gate }
18270Sstevel@tonic-gate
18280Sstevel@tonic-gate /*
18290Sstevel@tonic-gate * gld_wsrv - Incoming messages are processed according to the DLPI protocol
18300Sstevel@tonic-gate * specification.
18310Sstevel@tonic-gate *
18320Sstevel@tonic-gate * wsrv is single-threaded per Q. We make use of this to avoid taking the
18330Sstevel@tonic-gate * lock for reading data items that are only ever written by us.
18340Sstevel@tonic-gate */
18350Sstevel@tonic-gate
18360Sstevel@tonic-gate int
gld_wsrv(queue_t * q)18370Sstevel@tonic-gate gld_wsrv(queue_t *q)
18380Sstevel@tonic-gate {
18390Sstevel@tonic-gate mblk_t *mp;
18400Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
18410Sstevel@tonic-gate gld_mac_info_t *macinfo;
18420Sstevel@tonic-gate union DL_primitives *prim;
18430Sstevel@tonic-gate int err;
18440Sstevel@tonic-gate boolean_t multidata;
18452760Sdg199075 uint32_t upri;
18460Sstevel@tonic-gate
18470Sstevel@tonic-gate #ifdef GLD_DEBUG
18480Sstevel@tonic-gate if (gld_debug & GLDTRACE)
18490Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_wsrv(%p)", (void *)q);
18500Sstevel@tonic-gate #endif
18510Sstevel@tonic-gate
18520Sstevel@tonic-gate ASSERT(!gld->gld_in_wsrv);
18530Sstevel@tonic-gate
18540Sstevel@tonic-gate gld->gld_xwait = B_FALSE; /* We are now going to process this Q */
18550Sstevel@tonic-gate
18560Sstevel@tonic-gate if (q->q_first == NULL)
18570Sstevel@tonic-gate return (0);
18580Sstevel@tonic-gate
18590Sstevel@tonic-gate macinfo = gld->gld_mac_info;
18600Sstevel@tonic-gate
18610Sstevel@tonic-gate /*
18620Sstevel@tonic-gate * Help wput avoid a call to gld_start if there might be a message
18630Sstevel@tonic-gate * previously queued by that thread being processed here.
18640Sstevel@tonic-gate */
18650Sstevel@tonic-gate gld->gld_in_wsrv = B_TRUE;
18660Sstevel@tonic-gate membar_enter();
18670Sstevel@tonic-gate
18680Sstevel@tonic-gate while ((mp = getq(q)) != NULL) {
18690Sstevel@tonic-gate switch (DB_TYPE(mp)) {
18700Sstevel@tonic-gate case M_DATA:
18710Sstevel@tonic-gate case M_MULTIDATA:
18720Sstevel@tonic-gate multidata = (DB_TYPE(mp) == M_MULTIDATA);
18730Sstevel@tonic-gate
18740Sstevel@tonic-gate /*
18750Sstevel@tonic-gate * retry of a previously processed UNITDATA_REQ
18760Sstevel@tonic-gate * or is a RAW or FAST message from above.
18770Sstevel@tonic-gate */
18780Sstevel@tonic-gate if (macinfo == NULL) {
18790Sstevel@tonic-gate /* No longer attached to a PPA, drop packet */
18800Sstevel@tonic-gate freemsg(mp);
18810Sstevel@tonic-gate break;
18820Sstevel@tonic-gate }
18830Sstevel@tonic-gate
18840Sstevel@tonic-gate gld->gld_sched_ran = B_FALSE;
18850Sstevel@tonic-gate membar_enter();
18862760Sdg199075
18872760Sdg199075 /*
18882760Sdg199075 * Get the priority value. Note that in raw mode, the
18892760Sdg199075 * per-packet priority value kept in b_band is ignored.
18902760Sdg199075 */
18912760Sdg199075 upri = (gld->gld_flags & GLD_RAW) ? gld->gld_upri :
18922760Sdg199075 UPRI(gld, mp->b_band);
18932760Sdg199075
18940Sstevel@tonic-gate err = (multidata) ? gld_start_mdt(q, mp, GLD_WSRV) :
18952760Sdg199075 gld_start(q, mp, GLD_WSRV, upri);
18960Sstevel@tonic-gate if (err == GLD_NORESOURCES) {
18970Sstevel@tonic-gate /* gld_sched will qenable us later */
18980Sstevel@tonic-gate gld->gld_xwait = B_TRUE; /* want qenable */
18990Sstevel@tonic-gate membar_enter();
19000Sstevel@tonic-gate /*
19010Sstevel@tonic-gate * v2: we're not holding the lock; it's
19020Sstevel@tonic-gate * possible that the driver could have already
19030Sstevel@tonic-gate * called gld_sched (following up on its
19040Sstevel@tonic-gate * return of GLD_NORESOURCES), before we got a
19050Sstevel@tonic-gate * chance to do the putbq() and set gld_xwait.
19060Sstevel@tonic-gate * So if we saw a call to gld_sched that
19070Sstevel@tonic-gate * examined this queue, since our call to
19080Sstevel@tonic-gate * gld_start() above, then it's possible we've
19090Sstevel@tonic-gate * already seen the only call to gld_sched()
19100Sstevel@tonic-gate * we're ever going to see. So we better retry
19110Sstevel@tonic-gate * transmitting this packet right now.
19120Sstevel@tonic-gate */
19130Sstevel@tonic-gate if (gld->gld_sched_ran) {
19140Sstevel@tonic-gate #ifdef GLD_DEBUG
19150Sstevel@tonic-gate if (gld_debug & GLDTRACE)
19160Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_wsrv: "
19170Sstevel@tonic-gate "sched was called");
19180Sstevel@tonic-gate #endif
19190Sstevel@tonic-gate break; /* try again right now */
19200Sstevel@tonic-gate }
19210Sstevel@tonic-gate gld->gld_in_wsrv = B_FALSE;
19220Sstevel@tonic-gate return (0);
19230Sstevel@tonic-gate }
19240Sstevel@tonic-gate break;
19250Sstevel@tonic-gate
19260Sstevel@tonic-gate case M_IOCTL:
19270Sstevel@tonic-gate (void) gld_ioctl(q, mp);
19280Sstevel@tonic-gate break;
19290Sstevel@tonic-gate
19300Sstevel@tonic-gate case M_CTL:
19310Sstevel@tonic-gate if (macinfo == NULL) {
19320Sstevel@tonic-gate freemsg(mp);
19330Sstevel@tonic-gate break;
19340Sstevel@tonic-gate }
19350Sstevel@tonic-gate
19360Sstevel@tonic-gate if (macinfo->gldm_mctl != NULL) {
19370Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
19380Sstevel@tonic-gate (void) (*macinfo->gldm_mctl) (macinfo, q, mp);
19390Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
19400Sstevel@tonic-gate } else {
19410Sstevel@tonic-gate /* This driver doesn't recognize, just drop */
19420Sstevel@tonic-gate freemsg(mp);
19430Sstevel@tonic-gate }
19440Sstevel@tonic-gate break;
19450Sstevel@tonic-gate
19460Sstevel@tonic-gate case M_PROTO: /* Will be an DLPI message of some type */
19470Sstevel@tonic-gate case M_PCPROTO:
19480Sstevel@tonic-gate if ((err = gld_cmds(q, mp)) != GLDE_OK) {
19490Sstevel@tonic-gate if (err == GLDE_RETRY) {
19500Sstevel@tonic-gate gld->gld_in_wsrv = B_FALSE;
19510Sstevel@tonic-gate return (0); /* quit while we're ahead */
19520Sstevel@tonic-gate }
19530Sstevel@tonic-gate prim = (union DL_primitives *)mp->b_rptr;
19540Sstevel@tonic-gate dlerrorack(q, mp, prim->dl_primitive, err, 0);
19550Sstevel@tonic-gate }
19560Sstevel@tonic-gate break;
19570Sstevel@tonic-gate
19580Sstevel@tonic-gate default:
19590Sstevel@tonic-gate /* This should never happen */
19600Sstevel@tonic-gate #ifdef GLD_DEBUG
19610Sstevel@tonic-gate if (gld_debug & GLDERRS)
19620Sstevel@tonic-gate cmn_err(CE_WARN,
19630Sstevel@tonic-gate "gld_wsrv: db_type(%x) not supported",
19640Sstevel@tonic-gate mp->b_datap->db_type);
19650Sstevel@tonic-gate #endif
19660Sstevel@tonic-gate freemsg(mp); /* unknown types are discarded */
19670Sstevel@tonic-gate break;
19680Sstevel@tonic-gate }
19690Sstevel@tonic-gate }
19700Sstevel@tonic-gate
19710Sstevel@tonic-gate membar_exit();
19720Sstevel@tonic-gate gld->gld_in_wsrv = B_FALSE;
19730Sstevel@tonic-gate return (0);
19740Sstevel@tonic-gate }
19750Sstevel@tonic-gate
19760Sstevel@tonic-gate /*
19770Sstevel@tonic-gate * gld_start() can get called from gld_wput(), gld_wsrv(), or gld_unitdata().
19780Sstevel@tonic-gate *
19790Sstevel@tonic-gate * We only come directly from wput() in the GLD_FAST (fastpath) or RAW case.
19800Sstevel@tonic-gate *
19810Sstevel@tonic-gate * In particular, we must avoid calling gld_precv*() if we came from wput().
19820Sstevel@tonic-gate * gld_precv*() is where we, on the transmit side, loop back our outgoing
19830Sstevel@tonic-gate * packets to the receive side if we are in physical promiscuous mode.
19840Sstevel@tonic-gate * Since the receive side holds a lock across its call to the upstream
19850Sstevel@tonic-gate * putnext, and that upstream module could well have looped back to our
19860Sstevel@tonic-gate * wput() routine on the same thread, we cannot call gld_precv* from here
19870Sstevel@tonic-gate * for fear of causing a recursive lock entry in our receive code.
19880Sstevel@tonic-gate *
19890Sstevel@tonic-gate * There is a problem here when coming from gld_wput(). While wput
19900Sstevel@tonic-gate * only comes here if the queue is attached to a PPA and bound to a SAP
19910Sstevel@tonic-gate * and there are no messages on the queue ahead of the M_DATA that could
19920Sstevel@tonic-gate * change that, it is theoretically possible that another thread could
19930Sstevel@tonic-gate * now wput a DL_UNBIND and a DL_DETACH message, and the wsrv() routine
19940Sstevel@tonic-gate * could wake up and process them, before we finish processing this
19950Sstevel@tonic-gate * send of the M_DATA. This can only possibly happen on a Style 2 RAW or
19960Sstevel@tonic-gate * FAST (fastpath) stream: non RAW/FAST streams always go through wsrv(),
19970Sstevel@tonic-gate * and Style 1 streams only DL_DETACH in the close routine, where
19980Sstevel@tonic-gate * qprocsoff() protects us. If this happens we could end up calling
19990Sstevel@tonic-gate * gldm_send() after we have detached the stream and possibly called
20000Sstevel@tonic-gate * gldm_stop(). Worse, once the number of attached streams goes to zero,
20010Sstevel@tonic-gate * detach/unregister could be called, and the macinfo could go away entirely.
20020Sstevel@tonic-gate *
20030Sstevel@tonic-gate * No one has ever seen this happen.
20040Sstevel@tonic-gate *
20050Sstevel@tonic-gate * It is some trouble to fix this, and we would rather not add any mutex
20060Sstevel@tonic-gate * logic into the wput() routine, which is supposed to be a "fast"
20070Sstevel@tonic-gate * path.
20080Sstevel@tonic-gate *
20090Sstevel@tonic-gate * What I've done is use an atomic counter to keep a count of the number
20100Sstevel@tonic-gate * of threads currently calling gld_start() from wput() on this stream.
20110Sstevel@tonic-gate * If DL_DETACH sees this as nonzero, it putbqs the request back onto
20120Sstevel@tonic-gate * the queue and qenables, hoping to have better luck next time. Since
20130Sstevel@tonic-gate * people shouldn't be trying to send after they've asked to DL_DETACH,
20140Sstevel@tonic-gate * hopefully very soon all the wput=>start threads should have returned
20150Sstevel@tonic-gate * and the DL_DETACH will succeed. It's hard to test this since the odds
20160Sstevel@tonic-gate * of the failure even trying to happen are so small. I probably could
20170Sstevel@tonic-gate * have ignored the whole issue and never been the worse for it.
20182760Sdg199075 *
20192760Sdg199075 * Because some GLDv2 Ethernet drivers do not allow the size of transmitted
20202760Sdg199075 * packet to be greater than ETHERMAX, we must first strip the VLAN tag
20212760Sdg199075 * from a tagged packet before passing it to the driver's gld_send() entry
20222760Sdg199075 * point function, and pass the VLAN tag as a separate argument. The
20232760Sdg199075 * gld_send() function may fail. In that case, the packet will need to be
20242760Sdg199075 * queued in order to be processed again in GLD's service routine. As the
20252760Sdg199075 * VTAG has already been stripped at that time, we save the VTAG information
20262760Sdg199075 * in (the unused fields of) dblk using GLD_SAVE_MBLK_VTAG(), so that the
20272760Sdg199075 * VTAG can also be queued and be able to be got when gld_start() is called
20282760Sdg199075 * next time from gld_wsrv().
20292760Sdg199075 *
20302760Sdg199075 * Some rules to use GLD_{CLEAR|SAVE}_MBLK_VTAG macros:
20312760Sdg199075 *
20322760Sdg199075 * - GLD_SAVE_MBLK_VTAG() must be called to save the VTAG information each time
20332760Sdg199075 * the message is queued by putbq().
20342760Sdg199075 *
20352760Sdg199075 * - GLD_CLEAR_MBLK_VTAG() must be called to clear the bogus VTAG information
20362760Sdg199075 * (if any) in dblk before the message is passed to the gld_start() function.
20370Sstevel@tonic-gate */
20380Sstevel@tonic-gate static int
gld_start(queue_t * q,mblk_t * mp,int caller,uint32_t upri)20390Sstevel@tonic-gate gld_start(queue_t *q, mblk_t *mp, int caller, uint32_t upri)
20400Sstevel@tonic-gate {
20410Sstevel@tonic-gate mblk_t *nmp;
20420Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
20430Sstevel@tonic-gate gld_mac_info_t *macinfo;
20440Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
20450Sstevel@tonic-gate int rc;
20460Sstevel@tonic-gate gld_interface_t *ifp;
20470Sstevel@tonic-gate pktinfo_t pktinfo;
20482760Sdg199075 uint32_t vtag, vid;
20492760Sdg199075 uint32_t raw_vtag = 0;
20500Sstevel@tonic-gate gld_vlan_t *vlan;
20512760Sdg199075 struct gld_stats *stats0, *stats = NULL;
20520Sstevel@tonic-gate
20530Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_DATA);
20540Sstevel@tonic-gate macinfo = gld->gld_mac_info;
20550Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
20560Sstevel@tonic-gate ifp = mac_pvt->interfacep;
20570Sstevel@tonic-gate vlan = (gld_vlan_t *)gld->gld_vlan;
20582760Sdg199075 vid = vlan->gldv_id;
20592760Sdg199075
20602760Sdg199075 /*
20612760Sdg199075 * If this interface is a VLAN, the kstats of corresponding
20622760Sdg199075 * "VLAN 0" should also be updated. Note that the gld_vlan_t
20632760Sdg199075 * structure for VLAN 0 might not exist if there are no DLPI
20642760Sdg199075 * consumers attaching on VLAN 0. Fortunately we can directly
20652760Sdg199075 * access VLAN 0's kstats from macinfo.
20662760Sdg199075 *
20672760Sdg199075 * Therefore, stats0 (VLAN 0's kstats) must always be
20682760Sdg199075 * updated, and stats must to be updated if it is not NULL.
20692760Sdg199075 */
20702760Sdg199075 stats0 = mac_pvt->statistics;
20712760Sdg199075 if (vid != VLAN_VID_NONE)
20722760Sdg199075 stats = vlan->gldv_stats;
20730Sstevel@tonic-gate
20740Sstevel@tonic-gate if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_TX) != 0) {
20750Sstevel@tonic-gate #ifdef GLD_DEBUG
20760Sstevel@tonic-gate if (gld_debug & GLDERRS)
20770Sstevel@tonic-gate cmn_err(CE_WARN,
20780Sstevel@tonic-gate "gld_start: failed to interpret outbound packet");
20790Sstevel@tonic-gate #endif
20802760Sdg199075 goto badarg;
20812760Sdg199075 }
20822760Sdg199075
20832760Sdg199075 vtag = VLAN_VID_NONE;
20842760Sdg199075 raw_vtag = GLD_GET_MBLK_VTAG(mp);
20852760Sdg199075 if (GLD_VTAG_TCI(raw_vtag) != 0) {
20862760Sdg199075 uint16_t raw_pri, raw_vid, evid;
20872760Sdg199075
20882760Sdg199075 /*
20892760Sdg199075 * Tagged packet.
20902760Sdg199075 */
20912760Sdg199075 raw_pri = GLD_VTAG_PRI(raw_vtag);
20922760Sdg199075 raw_vid = GLD_VTAG_VID(raw_vtag);
20932760Sdg199075 GLD_CLEAR_MBLK_VTAG(mp);
20942760Sdg199075
20952760Sdg199075 if (gld->gld_flags & GLD_RAW) {
20962760Sdg199075 /*
20972760Sdg199075 * In raw mode, we only expect untagged packets or
20982760Sdg199075 * special priority-tagged packets on a VLAN stream.
20992760Sdg199075 * Drop the packet if its VID is not zero.
21002760Sdg199075 */
21012760Sdg199075 if (vid != VLAN_VID_NONE && raw_vid != VLAN_VID_NONE)
21022760Sdg199075 goto badarg;
21032760Sdg199075
21042760Sdg199075 /*
21052760Sdg199075 * If it is raw mode, use the per-stream priority if
21062760Sdg199075 * the priority is not specified in the packet.
21072760Sdg199075 * Otherwise, ignore the priority bits in the packet.
21082760Sdg199075 */
21092760Sdg199075 upri = (raw_pri != 0) ? raw_pri : upri;
21102760Sdg199075 }
21112760Sdg199075
21122760Sdg199075 if (vid == VLAN_VID_NONE && vid != raw_vid) {
21132760Sdg199075 gld_vlan_t *tmp_vlan;
21142760Sdg199075
21152760Sdg199075 /*
21162760Sdg199075 * This link is a physical link but the packet is
21172760Sdg199075 * a VLAN tagged packet, the kstats of corresponding
21182760Sdg199075 * VLAN (if any) should also be updated.
21192760Sdg199075 */
21202760Sdg199075 tmp_vlan = gld_find_vlan(macinfo, raw_vid);
21212760Sdg199075 if (tmp_vlan != NULL)
21222760Sdg199075 stats = tmp_vlan->gldv_stats;
21232760Sdg199075 }
21242760Sdg199075
21252760Sdg199075 evid = (vid == VLAN_VID_NONE) ? raw_vid : vid;
21262760Sdg199075 if (evid != VLAN_VID_NONE || upri != 0)
21272760Sdg199075 vtag = GLD_MAKE_VTAG(upri, VLAN_CFI_ETHER, evid);
21282760Sdg199075 } else {
21292760Sdg199075 /*
21302760Sdg199075 * Untagged packet:
21312760Sdg199075 * Get vtag from the attached PPA of this stream.
21322760Sdg199075 */
21332760Sdg199075 if ((vid != VLAN_VID_NONE) ||
21342760Sdg199075 ((macinfo->gldm_type == DL_ETHER) && (upri != 0))) {
21352760Sdg199075 vtag = GLD_MAKE_VTAG(upri, VLAN_CFI_ETHER, vid);
21362760Sdg199075 }
21370Sstevel@tonic-gate }
21380Sstevel@tonic-gate
21390Sstevel@tonic-gate /*
21400Sstevel@tonic-gate * We're not holding the lock for this check. If the promiscuous
21410Sstevel@tonic-gate * state is in flux it doesn't matter much if we get this wrong.
21420Sstevel@tonic-gate */
21430Sstevel@tonic-gate if (mac_pvt->nprom > 0) {
21440Sstevel@tonic-gate /*
21450Sstevel@tonic-gate * We want to loopback to the receive side, but to avoid
21460Sstevel@tonic-gate * recursive lock entry: if we came from wput(), which
21470Sstevel@tonic-gate * could have looped back via IP from our own receive
21480Sstevel@tonic-gate * interrupt thread, we decline this request. wput()
21490Sstevel@tonic-gate * will then queue the packet for wsrv(). This means
21500Sstevel@tonic-gate * that when snoop is running we don't get the advantage
21510Sstevel@tonic-gate * of the wput() multithreaded direct entry to the
21520Sstevel@tonic-gate * driver's send routine.
21530Sstevel@tonic-gate */
21540Sstevel@tonic-gate if (caller == GLD_WPUT) {
21552760Sdg199075 GLD_SAVE_MBLK_VTAG(mp, raw_vtag);
21560Sstevel@tonic-gate (void) putbq(q, mp);
21570Sstevel@tonic-gate return (GLD_NORESOURCES);
21580Sstevel@tonic-gate }
21590Sstevel@tonic-gate if (macinfo->gldm_capabilities & GLD_CAP_ZEROCOPY)
21600Sstevel@tonic-gate nmp = dupmsg_noloan(mp);
21610Sstevel@tonic-gate else
21620Sstevel@tonic-gate nmp = dupmsg(mp);
21630Sstevel@tonic-gate } else
21640Sstevel@tonic-gate nmp = NULL; /* we need no loopback */
21650Sstevel@tonic-gate
21660Sstevel@tonic-gate if (ifp->hdr_size > 0 &&
21670Sstevel@tonic-gate pktinfo.pktLen > ifp->hdr_size + (vtag == 0 ? 0 : VTAG_SIZE) +
21680Sstevel@tonic-gate macinfo->gldm_maxpkt) {
21690Sstevel@tonic-gate if (nmp)
21700Sstevel@tonic-gate freemsg(nmp); /* free the duped message */
21710Sstevel@tonic-gate #ifdef GLD_DEBUG
21720Sstevel@tonic-gate if (gld_debug & GLDERRS)
21730Sstevel@tonic-gate cmn_err(CE_WARN,
21740Sstevel@tonic-gate "gld_start: oversize outbound packet, size %d,"
21750Sstevel@tonic-gate "max %d", pktinfo.pktLen,
21762760Sdg199075 ifp->hdr_size + (vtag == 0 ? 0 : VTAG_SIZE) +
21772760Sdg199075 macinfo->gldm_maxpkt);
21780Sstevel@tonic-gate #endif
21792760Sdg199075 goto badarg;
21800Sstevel@tonic-gate }
21810Sstevel@tonic-gate
21820Sstevel@tonic-gate rc = (*gld->gld_send)(macinfo, mp, vtag);
21830Sstevel@tonic-gate
21840Sstevel@tonic-gate if (rc != GLD_SUCCESS) {
21850Sstevel@tonic-gate if (rc == GLD_NORESOURCES) {
21862760Sdg199075 ATOMIC_BUMP(stats0, stats, glds_xmtretry, 1);
21872760Sdg199075 GLD_SAVE_MBLK_VTAG(mp, raw_vtag);
21880Sstevel@tonic-gate (void) putbq(q, mp);
21890Sstevel@tonic-gate } else {
21900Sstevel@tonic-gate /* transmit error; drop the packet */
21910Sstevel@tonic-gate freemsg(mp);
21920Sstevel@tonic-gate /* We're supposed to count failed attempts as well */
21932760Sdg199075 UPDATE_STATS(stats0, stats, pktinfo, 1);
21940Sstevel@tonic-gate #ifdef GLD_DEBUG
21950Sstevel@tonic-gate if (gld_debug & GLDERRS)
21960Sstevel@tonic-gate cmn_err(CE_WARN,
21970Sstevel@tonic-gate "gld_start: gldm_send failed %d", rc);
21980Sstevel@tonic-gate #endif
21990Sstevel@tonic-gate }
22000Sstevel@tonic-gate if (nmp)
22010Sstevel@tonic-gate freemsg(nmp); /* free the dupped message */
22020Sstevel@tonic-gate return (rc);
22030Sstevel@tonic-gate }
22040Sstevel@tonic-gate
22052760Sdg199075 UPDATE_STATS(stats0, stats, pktinfo, 1);
22060Sstevel@tonic-gate
22070Sstevel@tonic-gate /*
22080Sstevel@tonic-gate * Loopback case. The message needs to be returned back on
22092760Sdg199075 * the read side. This would silently fail if the dupmsg fails
22100Sstevel@tonic-gate * above. This is probably OK, if there is no memory to dup the
22110Sstevel@tonic-gate * block, then there isn't much we could do anyway.
22120Sstevel@tonic-gate */
22130Sstevel@tonic-gate if (nmp) {
22140Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
22152760Sdg199075 gld_precv(macinfo, nmp, vtag, stats);
22160Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
22170Sstevel@tonic-gate }
22180Sstevel@tonic-gate
22190Sstevel@tonic-gate return (GLD_SUCCESS);
22202760Sdg199075 badarg:
22212760Sdg199075 freemsg(mp);
22222760Sdg199075
22232760Sdg199075 ATOMIC_BUMP(stats0, stats, glds_xmtbadinterp, 1);
22242760Sdg199075 return (GLD_BADARG);
22250Sstevel@tonic-gate }
22260Sstevel@tonic-gate
22270Sstevel@tonic-gate /*
22280Sstevel@tonic-gate * With MDT V.2 a single message mp can have one header area and multiple
22290Sstevel@tonic-gate * payload areas. A packet is described by dl_pkt_info, and each packet can
22300Sstevel@tonic-gate * span multiple payload areas (currently with TCP, each packet will have one
22310Sstevel@tonic-gate * header and at the most two payload areas). MACs might have a limit on the
22320Sstevel@tonic-gate * number of payload segments (i.e. per packet scatter-gather limit), and
22330Sstevel@tonic-gate * MDT V.2 has a way of specifying that with mdt_span_limit; the MAC driver
22340Sstevel@tonic-gate * might also have a limit on the total number of payloads in a message, and
22350Sstevel@tonic-gate * that is specified by mdt_max_pld.
22360Sstevel@tonic-gate */
22370Sstevel@tonic-gate static int
gld_start_mdt(queue_t * q,mblk_t * mp,int caller)22380Sstevel@tonic-gate gld_start_mdt(queue_t *q, mblk_t *mp, int caller)
22390Sstevel@tonic-gate {
22400Sstevel@tonic-gate mblk_t *nextmp;
22410Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
22420Sstevel@tonic-gate gld_mac_info_t *macinfo = gld->gld_mac_info;
22430Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
22440Sstevel@tonic-gate int numpacks, mdtpacks;
22450Sstevel@tonic-gate gld_interface_t *ifp = mac_pvt->interfacep;
22460Sstevel@tonic-gate pktinfo_t pktinfo;
22470Sstevel@tonic-gate gld_vlan_t *vlan = (gld_vlan_t *)gld->gld_vlan;
22480Sstevel@tonic-gate boolean_t doloop = B_FALSE;
22490Sstevel@tonic-gate multidata_t *dlmdp;
22500Sstevel@tonic-gate pdescinfo_t pinfo;
22510Sstevel@tonic-gate pdesc_t *dl_pkt;
22520Sstevel@tonic-gate void *cookie;
22530Sstevel@tonic-gate uint_t totLen = 0;
22540Sstevel@tonic-gate
22550Sstevel@tonic-gate ASSERT(DB_TYPE(mp) == M_MULTIDATA);
22560Sstevel@tonic-gate
22570Sstevel@tonic-gate /*
22580Sstevel@tonic-gate * We're not holding the lock for this check. If the promiscuous
22590Sstevel@tonic-gate * state is in flux it doesn't matter much if we get this wrong.
22600Sstevel@tonic-gate */
22610Sstevel@tonic-gate if (mac_pvt->nprom > 0) {
22620Sstevel@tonic-gate /*
22630Sstevel@tonic-gate * We want to loopback to the receive side, but to avoid
22640Sstevel@tonic-gate * recursive lock entry: if we came from wput(), which
22650Sstevel@tonic-gate * could have looped back via IP from our own receive
22660Sstevel@tonic-gate * interrupt thread, we decline this request. wput()
22670Sstevel@tonic-gate * will then queue the packet for wsrv(). This means
22680Sstevel@tonic-gate * that when snoop is running we don't get the advantage
22690Sstevel@tonic-gate * of the wput() multithreaded direct entry to the
22700Sstevel@tonic-gate * driver's send routine.
22710Sstevel@tonic-gate */
22720Sstevel@tonic-gate if (caller == GLD_WPUT) {
22730Sstevel@tonic-gate (void) putbq(q, mp);
22740Sstevel@tonic-gate return (GLD_NORESOURCES);
22750Sstevel@tonic-gate }
22760Sstevel@tonic-gate doloop = B_TRUE;
22770Sstevel@tonic-gate
22780Sstevel@tonic-gate /*
22790Sstevel@tonic-gate * unlike the M_DATA case, we don't have to call
22800Sstevel@tonic-gate * dupmsg_noloan here because mmd_transform
22810Sstevel@tonic-gate * (called by gld_precv_mdt) will make a copy of
22820Sstevel@tonic-gate * each dblk.
22830Sstevel@tonic-gate */
22840Sstevel@tonic-gate }
22850Sstevel@tonic-gate
22860Sstevel@tonic-gate while (mp != NULL) {
22870Sstevel@tonic-gate /*
22880Sstevel@tonic-gate * The lower layer driver only gets a single multidata
22890Sstevel@tonic-gate * message; this also makes it easier to handle noresources.
22900Sstevel@tonic-gate */
22910Sstevel@tonic-gate nextmp = mp->b_cont;
22920Sstevel@tonic-gate mp->b_cont = NULL;
22930Sstevel@tonic-gate
22940Sstevel@tonic-gate /*
22950Sstevel@tonic-gate * Get number of packets in this message; if nothing
22960Sstevel@tonic-gate * to transmit, go to next message.
22970Sstevel@tonic-gate */
22980Sstevel@tonic-gate dlmdp = mmd_getmultidata(mp);
22990Sstevel@tonic-gate if ((mdtpacks = (int)mmd_getcnt(dlmdp, NULL, NULL)) == 0) {
23000Sstevel@tonic-gate freemsg(mp);
23010Sstevel@tonic-gate mp = nextmp;
23020Sstevel@tonic-gate continue;
23030Sstevel@tonic-gate }
23040Sstevel@tonic-gate
23050Sstevel@tonic-gate /*
23060Sstevel@tonic-gate * Run interpreter to populate media specific pktinfo fields.
23070Sstevel@tonic-gate * This collects per MDT message information like sap,
23080Sstevel@tonic-gate * broad/multicast etc.
23090Sstevel@tonic-gate */
23100Sstevel@tonic-gate (void) (*ifp->interpreter_mdt)(macinfo, mp, NULL, &pktinfo,
23110Sstevel@tonic-gate GLD_MDT_TX);
23120Sstevel@tonic-gate
23130Sstevel@tonic-gate numpacks = (*macinfo->gldm_mdt_pre)(macinfo, mp, &cookie);
23140Sstevel@tonic-gate
23150Sstevel@tonic-gate if (numpacks > 0) {
23160Sstevel@tonic-gate /*
23170Sstevel@tonic-gate * Driver indicates it can transmit at least 1, and
23180Sstevel@tonic-gate * possibly all, packets in MDT message.
23190Sstevel@tonic-gate */
23200Sstevel@tonic-gate int count = numpacks;
23210Sstevel@tonic-gate
23220Sstevel@tonic-gate for (dl_pkt = mmd_getfirstpdesc(dlmdp, &pinfo);
23230Sstevel@tonic-gate (dl_pkt != NULL);
23240Sstevel@tonic-gate dl_pkt = mmd_getnextpdesc(dl_pkt, &pinfo)) {
23250Sstevel@tonic-gate /*
23260Sstevel@tonic-gate * Format this packet by adding link header and
23270Sstevel@tonic-gate * adjusting pdescinfo to include it; get
23280Sstevel@tonic-gate * packet length.
23290Sstevel@tonic-gate */
23300Sstevel@tonic-gate (void) (*ifp->interpreter_mdt)(macinfo, NULL,
23310Sstevel@tonic-gate &pinfo, &pktinfo, GLD_MDT_TXPKT);
23320Sstevel@tonic-gate
23330Sstevel@tonic-gate totLen += pktinfo.pktLen;
23340Sstevel@tonic-gate
23350Sstevel@tonic-gate /*
23360Sstevel@tonic-gate * Loop back packet before handing to the
23370Sstevel@tonic-gate * driver.
23380Sstevel@tonic-gate */
23390Sstevel@tonic-gate if (doloop &&
23400Sstevel@tonic-gate mmd_adjpdesc(dl_pkt, &pinfo) != NULL) {
23410Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
23420Sstevel@tonic-gate gld_precv_mdt(macinfo, vlan, mp,
23430Sstevel@tonic-gate dl_pkt, &pktinfo);
23440Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
23450Sstevel@tonic-gate }
23460Sstevel@tonic-gate
23470Sstevel@tonic-gate /*
23480Sstevel@tonic-gate * And send off to driver.
23490Sstevel@tonic-gate */
23500Sstevel@tonic-gate (*macinfo->gldm_mdt_send)(macinfo, cookie,
23510Sstevel@tonic-gate &pinfo);
23520Sstevel@tonic-gate
23530Sstevel@tonic-gate /*
23540Sstevel@tonic-gate * Be careful not to invoke getnextpdesc if we
23550Sstevel@tonic-gate * already sent the last packet, since driver
23560Sstevel@tonic-gate * might have posted it to hardware causing a
23570Sstevel@tonic-gate * completion and freemsg() so the MDT data
23580Sstevel@tonic-gate * structures might not be valid anymore.
23590Sstevel@tonic-gate */
23600Sstevel@tonic-gate if (--count == 0)
23610Sstevel@tonic-gate break;
23620Sstevel@tonic-gate }
23630Sstevel@tonic-gate (*macinfo->gldm_mdt_post)(macinfo, mp, cookie);
23640Sstevel@tonic-gate pktinfo.pktLen = totLen;
23652760Sdg199075 UPDATE_STATS(vlan->gldv_stats, NULL, pktinfo, numpacks);
23660Sstevel@tonic-gate
23670Sstevel@tonic-gate /*
23680Sstevel@tonic-gate * In the noresources case (when driver indicates it
23690Sstevel@tonic-gate * can not transmit all packets in the MDT message),
23700Sstevel@tonic-gate * adjust to skip the first few packets on retrial.
23710Sstevel@tonic-gate */
23720Sstevel@tonic-gate if (numpacks != mdtpacks) {
23730Sstevel@tonic-gate /*
23740Sstevel@tonic-gate * Release already processed packet descriptors.
23750Sstevel@tonic-gate */
23760Sstevel@tonic-gate for (count = 0; count < numpacks; count++) {
23770Sstevel@tonic-gate dl_pkt = mmd_getfirstpdesc(dlmdp,
23780Sstevel@tonic-gate &pinfo);
23790Sstevel@tonic-gate mmd_rempdesc(dl_pkt);
23800Sstevel@tonic-gate }
23812760Sdg199075 ATOMIC_BUMP(vlan->gldv_stats, NULL,
23822760Sdg199075 glds_xmtretry, 1);
23830Sstevel@tonic-gate mp->b_cont = nextmp;
23840Sstevel@tonic-gate (void) putbq(q, mp);
23850Sstevel@tonic-gate return (GLD_NORESOURCES);
23860Sstevel@tonic-gate }
23870Sstevel@tonic-gate } else if (numpacks == 0) {
23880Sstevel@tonic-gate /*
23890Sstevel@tonic-gate * Driver indicates it can not transmit any packets
23900Sstevel@tonic-gate * currently and will request retrial later.
23910Sstevel@tonic-gate */
23922760Sdg199075 ATOMIC_BUMP(vlan->gldv_stats, NULL, glds_xmtretry, 1);
23930Sstevel@tonic-gate mp->b_cont = nextmp;
23940Sstevel@tonic-gate (void) putbq(q, mp);
23950Sstevel@tonic-gate return (GLD_NORESOURCES);
23960Sstevel@tonic-gate } else {
23970Sstevel@tonic-gate ASSERT(numpacks == -1);
23980Sstevel@tonic-gate /*
23990Sstevel@tonic-gate * We're supposed to count failed attempts as well.
24000Sstevel@tonic-gate */
24010Sstevel@tonic-gate dl_pkt = mmd_getfirstpdesc(dlmdp, &pinfo);
24020Sstevel@tonic-gate while (dl_pkt != NULL) {
24030Sstevel@tonic-gate /*
24040Sstevel@tonic-gate * Call interpreter to determine total packet
24050Sstevel@tonic-gate * bytes that are being dropped.
24060Sstevel@tonic-gate */
24070Sstevel@tonic-gate (void) (*ifp->interpreter_mdt)(macinfo, NULL,
24080Sstevel@tonic-gate &pinfo, &pktinfo, GLD_MDT_TXPKT);
24090Sstevel@tonic-gate
24100Sstevel@tonic-gate totLen += pktinfo.pktLen;
24110Sstevel@tonic-gate
24120Sstevel@tonic-gate dl_pkt = mmd_getnextpdesc(dl_pkt, &pinfo);
24130Sstevel@tonic-gate }
24140Sstevel@tonic-gate pktinfo.pktLen = totLen;
24152760Sdg199075 UPDATE_STATS(vlan->gldv_stats, NULL, pktinfo, mdtpacks);
24160Sstevel@tonic-gate
24170Sstevel@tonic-gate /*
24180Sstevel@tonic-gate * Transmit error; drop the message, move on
24190Sstevel@tonic-gate * to the next one.
24200Sstevel@tonic-gate */
24210Sstevel@tonic-gate freemsg(mp);
24220Sstevel@tonic-gate }
24230Sstevel@tonic-gate
24240Sstevel@tonic-gate /*
24250Sstevel@tonic-gate * Process the next multidata block, if there is one.
24260Sstevel@tonic-gate */
24270Sstevel@tonic-gate mp = nextmp;
24280Sstevel@tonic-gate }
24290Sstevel@tonic-gate
24300Sstevel@tonic-gate return (GLD_SUCCESS);
24310Sstevel@tonic-gate }
24320Sstevel@tonic-gate
24330Sstevel@tonic-gate /*
24340Sstevel@tonic-gate * gld_intr (macinfo)
24350Sstevel@tonic-gate */
24360Sstevel@tonic-gate uint_t
gld_intr(gld_mac_info_t * macinfo)24370Sstevel@tonic-gate gld_intr(gld_mac_info_t *macinfo)
24380Sstevel@tonic-gate {
24390Sstevel@tonic-gate ASSERT(macinfo != NULL);
24400Sstevel@tonic-gate
24410Sstevel@tonic-gate if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY))
24420Sstevel@tonic-gate return (DDI_INTR_UNCLAIMED);
24430Sstevel@tonic-gate
24440Sstevel@tonic-gate return ((*macinfo->gldm_intr)(macinfo));
24450Sstevel@tonic-gate }
24460Sstevel@tonic-gate
24470Sstevel@tonic-gate /*
24480Sstevel@tonic-gate * gld_sched (macinfo)
24490Sstevel@tonic-gate *
24500Sstevel@tonic-gate * This routine scans the streams that refer to a specific macinfo
24510Sstevel@tonic-gate * structure and causes the STREAMS scheduler to try to run them if
24520Sstevel@tonic-gate * they are marked as waiting for the transmit buffer.
24530Sstevel@tonic-gate */
24540Sstevel@tonic-gate void
gld_sched(gld_mac_info_t * macinfo)24550Sstevel@tonic-gate gld_sched(gld_mac_info_t *macinfo)
24560Sstevel@tonic-gate {
24570Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
24580Sstevel@tonic-gate gld_t *gld;
24590Sstevel@tonic-gate gld_vlan_t *vlan;
24600Sstevel@tonic-gate int i;
24610Sstevel@tonic-gate
24620Sstevel@tonic-gate ASSERT(macinfo != NULL);
24630Sstevel@tonic-gate
24640Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
24650Sstevel@tonic-gate
24660Sstevel@tonic-gate if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
24670Sstevel@tonic-gate /* We're probably being called from a leftover interrupt */
24680Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
24690Sstevel@tonic-gate return;
24700Sstevel@tonic-gate }
24710Sstevel@tonic-gate
24720Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
24730Sstevel@tonic-gate
24740Sstevel@tonic-gate for (i = 0; i < VLAN_HASHSZ; i++) {
24750Sstevel@tonic-gate for (vlan = mac_pvt->vlan_hash[i];
24760Sstevel@tonic-gate vlan != NULL; vlan = vlan->gldv_next) {
24770Sstevel@tonic-gate for (gld = vlan->gldv_str_next;
24780Sstevel@tonic-gate gld != (gld_t *)&vlan->gldv_str_next;
24790Sstevel@tonic-gate gld = gld->gld_next) {
24800Sstevel@tonic-gate ASSERT(gld->gld_mac_info == macinfo);
24810Sstevel@tonic-gate gld->gld_sched_ran = B_TRUE;
24820Sstevel@tonic-gate membar_enter();
24830Sstevel@tonic-gate if (gld->gld_xwait) {
24840Sstevel@tonic-gate gld->gld_xwait = B_FALSE;
24850Sstevel@tonic-gate qenable(WR(gld->gld_qptr));
24860Sstevel@tonic-gate }
24870Sstevel@tonic-gate }
24880Sstevel@tonic-gate }
24890Sstevel@tonic-gate }
24900Sstevel@tonic-gate
24910Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
24920Sstevel@tonic-gate }
24930Sstevel@tonic-gate
24940Sstevel@tonic-gate /*
24952760Sdg199075 * gld_precv (macinfo, mp, vtag, stats)
24960Sstevel@tonic-gate * called from gld_start to loopback a packet when in promiscuous mode
24972760Sdg199075 *
24982760Sdg199075 * VLAN 0's statistics need to be updated. If stats is not NULL,
24992760Sdg199075 * it needs to be updated as well.
25000Sstevel@tonic-gate */
25010Sstevel@tonic-gate static void
gld_precv(gld_mac_info_t * macinfo,mblk_t * mp,uint32_t vtag,struct gld_stats * stats)25022760Sdg199075 gld_precv(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag,
25032760Sdg199075 struct gld_stats *stats)
25040Sstevel@tonic-gate {
25050Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
25060Sstevel@tonic-gate gld_interface_t *ifp;
25070Sstevel@tonic-gate pktinfo_t pktinfo;
25080Sstevel@tonic-gate
25090Sstevel@tonic-gate ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
25100Sstevel@tonic-gate
25110Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
25120Sstevel@tonic-gate ifp = mac_pvt->interfacep;
25130Sstevel@tonic-gate
25140Sstevel@tonic-gate /*
25150Sstevel@tonic-gate * call the media specific packet interpreter routine
25160Sstevel@tonic-gate */
25170Sstevel@tonic-gate if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RXLOOP) != 0) {
25180Sstevel@tonic-gate freemsg(mp);
25192760Sdg199075 BUMP(mac_pvt->statistics, stats, glds_rcvbadinterp, 1);
25200Sstevel@tonic-gate #ifdef GLD_DEBUG
25210Sstevel@tonic-gate if (gld_debug & GLDERRS)
25220Sstevel@tonic-gate cmn_err(CE_WARN,
25230Sstevel@tonic-gate "gld_precv: interpreter failed");
25240Sstevel@tonic-gate #endif
25250Sstevel@tonic-gate return;
25260Sstevel@tonic-gate }
25270Sstevel@tonic-gate
25282760Sdg199075 /*
25292760Sdg199075 * Update the vtag information.
25302760Sdg199075 */
25312760Sdg199075 pktinfo.isTagged = (vtag != VLAN_VID_NONE);
25322760Sdg199075 pktinfo.vid = GLD_VTAG_VID(vtag);
25332760Sdg199075 pktinfo.cfi = GLD_VTAG_CFI(vtag);
25342760Sdg199075 pktinfo.user_pri = GLD_VTAG_PRI(vtag);
25352760Sdg199075
25362760Sdg199075 gld_sendup(macinfo, &pktinfo, mp, gld_paccept);
25370Sstevel@tonic-gate }
25380Sstevel@tonic-gate
25390Sstevel@tonic-gate /*
25402760Sdg199075 * Called from gld_start_mdt to loopback packet(s) when in promiscuous mode.
25412760Sdg199075 * Note that 'vlan' is always a physical link, because MDT can only be
25422760Sdg199075 * enabled on non-VLAN streams.
25430Sstevel@tonic-gate */
25442760Sdg199075 /*ARGSUSED*/
25450Sstevel@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)25460Sstevel@tonic-gate gld_precv_mdt(gld_mac_info_t *macinfo, gld_vlan_t *vlan, mblk_t *mp,
25470Sstevel@tonic-gate pdesc_t *dl_pkt, pktinfo_t *pktinfo)
25480Sstevel@tonic-gate {
25490Sstevel@tonic-gate mblk_t *adjmp;
25500Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
25510Sstevel@tonic-gate gld_interface_t *ifp = mac_pvt->interfacep;
25520Sstevel@tonic-gate
25530Sstevel@tonic-gate ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
25540Sstevel@tonic-gate
25550Sstevel@tonic-gate /*
25560Sstevel@tonic-gate * Get source/destination.
25570Sstevel@tonic-gate */
25580Sstevel@tonic-gate (void) (*ifp->interpreter_mdt)(macinfo, mp, NULL, pktinfo,
25590Sstevel@tonic-gate GLD_MDT_RXLOOP);
25600Sstevel@tonic-gate if ((adjmp = mmd_transform(dl_pkt)) != NULL)
25612760Sdg199075 gld_sendup(macinfo, pktinfo, adjmp, gld_paccept);
25620Sstevel@tonic-gate }
25630Sstevel@tonic-gate
25640Sstevel@tonic-gate /*
25650Sstevel@tonic-gate * gld_recv (macinfo, mp)
25660Sstevel@tonic-gate * called with an mac-level packet in a mblock; take the maclock,
25670Sstevel@tonic-gate * try the ip4q and ip6q hack, and otherwise call gld_sendup.
25680Sstevel@tonic-gate *
25690Sstevel@tonic-gate * V0 drivers already are holding the mutex when they call us.
25700Sstevel@tonic-gate */
25710Sstevel@tonic-gate void
gld_recv(gld_mac_info_t * macinfo,mblk_t * mp)25720Sstevel@tonic-gate gld_recv(gld_mac_info_t *macinfo, mblk_t *mp)
25730Sstevel@tonic-gate {
25740Sstevel@tonic-gate gld_recv_tagged(macinfo, mp, VLAN_VTAG_NONE);
25750Sstevel@tonic-gate }
25760Sstevel@tonic-gate
25770Sstevel@tonic-gate void
gld_recv_tagged(gld_mac_info_t * macinfo,mblk_t * mp,uint32_t vtag)25780Sstevel@tonic-gate gld_recv_tagged(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t vtag)
25790Sstevel@tonic-gate {
25800Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
25810Sstevel@tonic-gate char pbuf[3*GLD_MAX_ADDRLEN];
25820Sstevel@tonic-gate pktinfo_t pktinfo;
25830Sstevel@tonic-gate gld_interface_t *ifp;
25840Sstevel@tonic-gate queue_t *ipq = NULL;
25852760Sdg199075 gld_vlan_t *vlan = NULL, *vlan0 = NULL, *vlann = NULL;
25862760Sdg199075 struct gld_stats *stats0, *stats = NULL;
25870Sstevel@tonic-gate uint32_t vid;
25882760Sdg199075 int err;
25890Sstevel@tonic-gate
25900Sstevel@tonic-gate ASSERT(macinfo != NULL);
25910Sstevel@tonic-gate ASSERT(mp->b_datap->db_ref);
25920Sstevel@tonic-gate
25930Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_READER);
25940Sstevel@tonic-gate
25950Sstevel@tonic-gate if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
25960Sstevel@tonic-gate /* We're probably being called from a leftover interrupt */
25970Sstevel@tonic-gate freemsg(mp);
25980Sstevel@tonic-gate goto done;
25990Sstevel@tonic-gate }
26000Sstevel@tonic-gate
26012760Sdg199075 /*
26022760Sdg199075 * If this packet is a VLAN tagged packet, the kstats of corresponding
26032760Sdg199075 * "VLAN 0" should also be updated. We can directly access VLAN 0's
26042760Sdg199075 * kstats from macinfo.
26052760Sdg199075 *
26062760Sdg199075 * Further, the packets needs to be passed to VLAN 0 if there is
26072760Sdg199075 * any DLPI consumer on VLAN 0 who is interested in tagged packets
26082760Sdg199075 * (DL_PROMISC_SAP is on or is bounded to ETHERTYPE_VLAN SAP).
26092760Sdg199075 */
26102760Sdg199075 mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
26112760Sdg199075 stats0 = mac_pvt->statistics;
26122760Sdg199075
26130Sstevel@tonic-gate vid = GLD_VTAG_VID(vtag);
26142760Sdg199075 vlan0 = gld_find_vlan(macinfo, VLAN_VID_NONE);
26152760Sdg199075 if (vid != VLAN_VID_NONE) {
26162760Sdg199075 /*
26172760Sdg199075 * If there are no physical DLPI consumers interested in the
26182760Sdg199075 * VLAN packet, clear vlan0.
26192760Sdg199075 */
26202760Sdg199075 if ((vlan0 != NULL) && (vlan0->gldv_nvlan_sap == 0))
26212760Sdg199075 vlan0 = NULL;
26222760Sdg199075 /*
26232760Sdg199075 * vlann is the VLAN with the same VID as the VLAN packet.
26242760Sdg199075 */
26252760Sdg199075 vlann = gld_find_vlan(macinfo, vid);
26262760Sdg199075 if (vlann != NULL)
26272760Sdg199075 stats = vlann->gldv_stats;
26282760Sdg199075 }
26292760Sdg199075
26302760Sdg199075 vlan = (vid == VLAN_VID_NONE) ? vlan0 : vlann;
26312760Sdg199075
26322760Sdg199075 ifp = mac_pvt->interfacep;
26332760Sdg199075 err = (*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RXQUICK);
26342760Sdg199075
26352760Sdg199075 BUMP(stats0, stats, glds_bytercv64, pktinfo.pktLen);
26362760Sdg199075 BUMP(stats0, stats, glds_pktrcv64, 1);
26372760Sdg199075
26382760Sdg199075 if ((vlann == NULL) && (vlan0 == NULL)) {
26390Sstevel@tonic-gate freemsg(mp);
26400Sstevel@tonic-gate goto done;
26410Sstevel@tonic-gate }
26420Sstevel@tonic-gate
26430Sstevel@tonic-gate /*
26442760Sdg199075 * Check whether underlying media code supports the IPQ hack:
26452760Sdg199075 *
26462760Sdg199075 * - the interpreter could quickly parse the packet
26472760Sdg199075 * - the device type supports IPQ (ethernet and IPoIB)
26482760Sdg199075 * - there is one, and only one, IP stream bound (to this VLAN)
26492760Sdg199075 * - that stream is a "fastpath" stream
26502760Sdg199075 * - the packet is of type ETHERTYPE_IP or ETHERTYPE_IPV6
26512760Sdg199075 * - there are no streams in promiscuous mode (on this VLAN)
26522760Sdg199075 * - if this packet is tagged, there is no need to send this
26532760Sdg199075 * packet to physical streams
26540Sstevel@tonic-gate */
26552760Sdg199075 if ((err != 0) && ((vlan != NULL) && (vlan->gldv_nprom == 0)) &&
26562760Sdg199075 (vlan == vlan0 || vlan0 == NULL)) {
26570Sstevel@tonic-gate switch (pktinfo.ethertype) {
26580Sstevel@tonic-gate case ETHERTYPE_IP:
26590Sstevel@tonic-gate ipq = vlan->gldv_ipq;
26600Sstevel@tonic-gate break;
26610Sstevel@tonic-gate case ETHERTYPE_IPV6:
26620Sstevel@tonic-gate ipq = vlan->gldv_ipv6q;
26630Sstevel@tonic-gate break;
26640Sstevel@tonic-gate }
26650Sstevel@tonic-gate }
26660Sstevel@tonic-gate
26670Sstevel@tonic-gate /*
26680Sstevel@tonic-gate * Special case for IP; we can simply do the putnext here, if:
26692760Sdg199075 * o The IPQ hack is possible (ipq != NULL).
26700Sstevel@tonic-gate * o the packet is specifically for me, and therefore:
26710Sstevel@tonic-gate * - the packet is not multicast or broadcast (fastpath only
26720Sstevel@tonic-gate * wants unicast packets).
26730Sstevel@tonic-gate *
26740Sstevel@tonic-gate * o the stream is not asserting flow control.
26750Sstevel@tonic-gate */
26760Sstevel@tonic-gate if (ipq != NULL &&
26770Sstevel@tonic-gate pktinfo.isForMe &&
26780Sstevel@tonic-gate canputnext(ipq)) {
26790Sstevel@tonic-gate /*
26800Sstevel@tonic-gate * Skip the mac header. We know there is no LLC1/SNAP header
26810Sstevel@tonic-gate * in this packet
26820Sstevel@tonic-gate */
26830Sstevel@tonic-gate mp->b_rptr += pktinfo.macLen;
26840Sstevel@tonic-gate putnext(ipq, mp);
26850Sstevel@tonic-gate goto done;
26860Sstevel@tonic-gate }
26870Sstevel@tonic-gate
26880Sstevel@tonic-gate /*
26890Sstevel@tonic-gate * call the media specific packet interpreter routine
26900Sstevel@tonic-gate */
26910Sstevel@tonic-gate if ((*ifp->interpreter)(macinfo, mp, &pktinfo, GLD_RX) != 0) {
26922760Sdg199075 BUMP(stats0, stats, glds_rcvbadinterp, 1);
26930Sstevel@tonic-gate #ifdef GLD_DEBUG
26940Sstevel@tonic-gate if (gld_debug & GLDERRS)
26950Sstevel@tonic-gate cmn_err(CE_WARN,
26960Sstevel@tonic-gate "gld_recv_tagged: interpreter failed");
26970Sstevel@tonic-gate #endif
26980Sstevel@tonic-gate freemsg(mp);
26990Sstevel@tonic-gate goto done;
27000Sstevel@tonic-gate }
27010Sstevel@tonic-gate
27020Sstevel@tonic-gate /*
27030Sstevel@tonic-gate * This is safe even if vtag is VLAN_VTAG_NONE
27040Sstevel@tonic-gate */
27050Sstevel@tonic-gate pktinfo.vid = vid;
27060Sstevel@tonic-gate pktinfo.cfi = GLD_VTAG_CFI(vtag);
27070Sstevel@tonic-gate #ifdef GLD_DEBUG
27080Sstevel@tonic-gate if (pktinfo.cfi != VLAN_CFI_ETHER)
27090Sstevel@tonic-gate cmn_err(CE_WARN, "gld_recv_tagged: non-ETHER CFI");
27100Sstevel@tonic-gate #endif
27110Sstevel@tonic-gate pktinfo.user_pri = GLD_VTAG_PRI(vtag);
27122760Sdg199075 pktinfo.isTagged = (vtag != VLAN_VID_NONE);
27130Sstevel@tonic-gate
27140Sstevel@tonic-gate #ifdef GLD_DEBUG
27150Sstevel@tonic-gate if ((gld_debug & GLDRECV) &&
27160Sstevel@tonic-gate (!(gld_debug & GLDNOBR) ||
27170Sstevel@tonic-gate (!pktinfo.isBroadcast && !pktinfo.isMulticast))) {
27180Sstevel@tonic-gate char pbuf2[3*GLD_MAX_ADDRLEN];
27190Sstevel@tonic-gate
27200Sstevel@tonic-gate cmn_err(CE_CONT, "gld_recv_tagged: machdr=<%s -> %s>\n",
27210Sstevel@tonic-gate gld_macaddr_sprintf(pbuf, pktinfo.shost,
27220Sstevel@tonic-gate macinfo->gldm_addrlen), gld_macaddr_sprintf(pbuf2,
27230Sstevel@tonic-gate pktinfo.dhost, macinfo->gldm_addrlen));
27240Sstevel@tonic-gate cmn_err(CE_CONT, "gld_recv_tagged: VlanId %d UserPri %d\n",
27250Sstevel@tonic-gate pktinfo.vid,
27260Sstevel@tonic-gate pktinfo.user_pri);
27270Sstevel@tonic-gate cmn_err(CE_CONT, "gld_recv_tagged: ethertype: %4x Len: %4d "
27280Sstevel@tonic-gate "Hdr: %d,%d isMulticast: %s\n",
27290Sstevel@tonic-gate pktinfo.ethertype,
27300Sstevel@tonic-gate pktinfo.pktLen,
27310Sstevel@tonic-gate pktinfo.macLen,
27320Sstevel@tonic-gate pktinfo.hdrLen,
27330Sstevel@tonic-gate pktinfo.isMulticast ? "Y" : "N");
27340Sstevel@tonic-gate }
27350Sstevel@tonic-gate #endif
27360Sstevel@tonic-gate
27372760Sdg199075 gld_sendup(macinfo, &pktinfo, mp, gld_accept);
27380Sstevel@tonic-gate
27390Sstevel@tonic-gate done:
27400Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
27410Sstevel@tonic-gate }
27420Sstevel@tonic-gate
27430Sstevel@tonic-gate /* =================================================================== */
27440Sstevel@tonic-gate /* receive group: called from gld_recv and gld_precv* with maclock held */
27450Sstevel@tonic-gate /* =================================================================== */
27460Sstevel@tonic-gate
27470Sstevel@tonic-gate /*
27482760Sdg199075 * Search all the streams attached to the specified VLAN looking for
27492760Sdg199075 * those eligible to receive the packet.
27502760Sdg199075 * Note that in order to avoid an extra dupmsg(), if this is the first
27512760Sdg199075 * eligible stream, remember it (in fgldp) so that we can send up the
27522760Sdg199075 * message after this function.
27532760Sdg199075 *
27542760Sdg199075 * Return errno if fails. Currently the only error is ENOMEM.
27550Sstevel@tonic-gate */
27562760Sdg199075 static int
gld_sendup_vlan(gld_vlan_t * vlan,pktinfo_t * pktinfo,mblk_t * mp,int (* acceptfunc)(),void (* send)(),int (* cansend)(),gld_t ** fgldp)27572760Sdg199075 gld_sendup_vlan(gld_vlan_t *vlan, pktinfo_t *pktinfo, mblk_t *mp,
27582760Sdg199075 int (*acceptfunc)(), void (*send)(), int (*cansend)(), gld_t **fgldp)
27590Sstevel@tonic-gate {
27600Sstevel@tonic-gate mblk_t *nmp;
27612760Sdg199075 gld_t *gld;
27622760Sdg199075 int err = 0;
27632760Sdg199075
27640Sstevel@tonic-gate ASSERT(vlan != NULL);
27652760Sdg199075 for (gld = vlan->gldv_str_next; gld != (gld_t *)&vlan->gldv_str_next;
27662760Sdg199075 gld = gld->gld_next) {
27670Sstevel@tonic-gate #ifdef GLD_VERBOSE_DEBUG
2768*10223SPeter.Memishian@Sun.COM cmn_err(CE_NOTE, "gld_sendup_vlan: SAP: %4x QPTR: %p "
2769*10223SPeter.Memishian@Sun.COM "QSTATE: %s", gld->gld_sap, (void *)gld->gld_qptr,
2770*10223SPeter.Memishian@Sun.COM gld->gld_state == DL_IDLE ? "IDLE" : "NOT IDLE");
27710Sstevel@tonic-gate #endif
27720Sstevel@tonic-gate ASSERT(gld->gld_qptr != NULL);
27730Sstevel@tonic-gate ASSERT(gld->gld_state == DL_IDLE ||
27740Sstevel@tonic-gate gld->gld_state == DL_UNBOUND);
27750Sstevel@tonic-gate ASSERT(gld->gld_vlan == vlan);
27760Sstevel@tonic-gate
27770Sstevel@tonic-gate if (gld->gld_state != DL_IDLE)
27780Sstevel@tonic-gate continue; /* not eligible to receive */
27790Sstevel@tonic-gate if (gld->gld_flags & GLD_STR_CLOSING)
27800Sstevel@tonic-gate continue; /* not eligible to receive */
27810Sstevel@tonic-gate
27820Sstevel@tonic-gate #ifdef GLD_DEBUG
27830Sstevel@tonic-gate if ((gld_debug & GLDRECV) &&
27840Sstevel@tonic-gate (!(gld_debug & GLDNOBR) ||
27850Sstevel@tonic-gate (!pktinfo->isBroadcast && !pktinfo->isMulticast)))
27860Sstevel@tonic-gate cmn_err(CE_NOTE,
27870Sstevel@tonic-gate "gld_sendup: queue sap: %4x promis: %s %s %s",
27880Sstevel@tonic-gate gld->gld_sap,
27890Sstevel@tonic-gate gld->gld_flags & GLD_PROM_PHYS ? "phys " : " ",
27900Sstevel@tonic-gate gld->gld_flags & GLD_PROM_SAP ? "sap " : " ",
27910Sstevel@tonic-gate gld->gld_flags & GLD_PROM_MULT ? "multi" : " ");
27920Sstevel@tonic-gate #endif
27930Sstevel@tonic-gate
27940Sstevel@tonic-gate /*
27950Sstevel@tonic-gate * The accept function differs depending on whether this is
27960Sstevel@tonic-gate * a packet that we received from the wire or a loopback.
27970Sstevel@tonic-gate */
27980Sstevel@tonic-gate if ((*acceptfunc)(gld, pktinfo)) {
27990Sstevel@tonic-gate /* sap matches */
28002760Sdg199075 pktinfo->wasAccepted = 1; /* known protocol */
28010Sstevel@tonic-gate
28020Sstevel@tonic-gate if (!(*cansend)(gld->gld_qptr)) {
28030Sstevel@tonic-gate /*
28040Sstevel@tonic-gate * Upper stream is not accepting messages, i.e.
28050Sstevel@tonic-gate * it is flow controlled, therefore we will
28060Sstevel@tonic-gate * forgo sending the message up this stream.
28070Sstevel@tonic-gate */
28080Sstevel@tonic-gate #ifdef GLD_DEBUG
28090Sstevel@tonic-gate if (gld_debug & GLDETRACE)
28100Sstevel@tonic-gate cmn_err(CE_WARN,
28110Sstevel@tonic-gate "gld_sendup: canput failed");
28120Sstevel@tonic-gate #endif
28132760Sdg199075 BUMP(vlan->gldv_stats, NULL, glds_blocked, 1);
28140Sstevel@tonic-gate qenable(gld->gld_qptr);
28150Sstevel@tonic-gate continue;
28160Sstevel@tonic-gate }
28170Sstevel@tonic-gate
28180Sstevel@tonic-gate /*
28192760Sdg199075 * In order to avoid an extra dupmsg(), remember this
28202760Sdg199075 * gld if this is the first eligible stream.
28210Sstevel@tonic-gate */
28222760Sdg199075 if (*fgldp == NULL) {
28232760Sdg199075 *fgldp = gld;
28240Sstevel@tonic-gate continue;
28250Sstevel@tonic-gate }
28260Sstevel@tonic-gate
28270Sstevel@tonic-gate /* duplicate the packet for this stream */
28280Sstevel@tonic-gate nmp = dupmsg(mp);
28290Sstevel@tonic-gate if (nmp == NULL) {
28302760Sdg199075 BUMP(vlan->gldv_stats, NULL,
28312760Sdg199075 glds_gldnorcvbuf, 1);
28320Sstevel@tonic-gate #ifdef GLD_DEBUG
28330Sstevel@tonic-gate if (gld_debug & GLDERRS)
28340Sstevel@tonic-gate cmn_err(CE_WARN,
28350Sstevel@tonic-gate "gld_sendup: dupmsg failed");
28360Sstevel@tonic-gate #endif
28372760Sdg199075 /* couldn't get resources; drop it */
28382760Sdg199075 err = ENOMEM;
28392760Sdg199075 break;
28400Sstevel@tonic-gate }
28410Sstevel@tonic-gate /* pass the message up the stream */
28420Sstevel@tonic-gate gld_passon(gld, nmp, pktinfo, send);
28430Sstevel@tonic-gate }
28440Sstevel@tonic-gate }
28452760Sdg199075 return (err);
28462760Sdg199075 }
28472760Sdg199075
28482760Sdg199075 /*
28492760Sdg199075 * gld_sendup (macinfo, pktinfo, mp, acceptfunc)
28502760Sdg199075 * called with an ethernet packet in an mblk; must decide whether
28512760Sdg199075 * packet is for us and which streams to queue it to.
28522760Sdg199075 */
28532760Sdg199075 static void
gld_sendup(gld_mac_info_t * macinfo,pktinfo_t * pktinfo,mblk_t * mp,int (* acceptfunc)())28542760Sdg199075 gld_sendup(gld_mac_info_t *macinfo, pktinfo_t *pktinfo,
28552760Sdg199075 mblk_t *mp, int (*acceptfunc)())
28562760Sdg199075 {
28572760Sdg199075 gld_t *fgld = NULL;
28582760Sdg199075 void (*send)(queue_t *qp, mblk_t *mp);
28592760Sdg199075 int (*cansend)(queue_t *qp);
28602760Sdg199075 gld_vlan_t *vlan0, *vlann = NULL;
28612760Sdg199075 struct gld_stats *stats0, *stats = NULL;
28622760Sdg199075 int err = 0;
28632760Sdg199075
28642760Sdg199075 #ifdef GLD_DEBUG
28652760Sdg199075 if (gld_debug & GLDTRACE)
28662760Sdg199075 cmn_err(CE_NOTE, "gld_sendup(%p, %p)", (void *)mp,
28672760Sdg199075 (void *)macinfo);
28682760Sdg199075 #endif
28692760Sdg199075
28702760Sdg199075 ASSERT(mp != NULL);
28712760Sdg199075 ASSERT(macinfo != NULL);
28722760Sdg199075 ASSERT(pktinfo != NULL);
28732760Sdg199075 ASSERT(GLDM_LOCK_HELD(macinfo));
28742760Sdg199075
28752760Sdg199075 /*
28762760Sdg199075 * The tagged packets should also be looped back (transmit-side)
28772760Sdg199075 * or sent up (receive-side) to VLAN 0 if VLAN 0 is set to
28782760Sdg199075 * DL_PROMISC_SAP or there is any DLPI consumer bind to the
28792760Sdg199075 * ETHERTYPE_VLAN SAP. The kstats of VLAN 0 needs to be updated
28802760Sdg199075 * as well.
28812760Sdg199075 */
28822760Sdg199075 stats0 = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->statistics;
28832760Sdg199075 vlan0 = gld_find_vlan(macinfo, VLAN_VID_NONE);
28842760Sdg199075 if (pktinfo->vid != VLAN_VID_NONE) {
28852760Sdg199075 if ((vlan0 != NULL) && (vlan0->gldv_nvlan_sap == 0))
28862760Sdg199075 vlan0 = NULL;
28872760Sdg199075 vlann = gld_find_vlan(macinfo, pktinfo->vid);
28882760Sdg199075 if (vlann != NULL)
28892760Sdg199075 stats = vlann->gldv_stats;
28902760Sdg199075 }
28912760Sdg199075
28922760Sdg199075 ASSERT((vlan0 != NULL) || (vlann != NULL));
28932760Sdg199075
28942760Sdg199075 /*
28952760Sdg199075 * The "fast" in "GLDOPT_FAST_RECV" refers to the speed at which
28962760Sdg199075 * gld_recv returns to the caller's interrupt routine. The total
28972760Sdg199075 * network throughput would normally be lower when selecting this
28982760Sdg199075 * option, because we putq the messages and process them later,
28992760Sdg199075 * instead of sending them with putnext now. Some time critical
29002760Sdg199075 * device might need this, so it's here but undocumented.
29012760Sdg199075 */
29022760Sdg199075 if (macinfo->gldm_options & GLDOPT_FAST_RECV) {
29032760Sdg199075 send = (void (*)(queue_t *, mblk_t *))putq;
29042760Sdg199075 cansend = canput;
29052760Sdg199075 } else {
29062760Sdg199075 send = (void (*)(queue_t *, mblk_t *))putnext;
29072760Sdg199075 cansend = canputnext;
29082760Sdg199075 }
29092760Sdg199075
29102760Sdg199075 /*
29112760Sdg199075 * Send the packets for all eligible streams.
29122760Sdg199075 */
29132760Sdg199075 if (vlan0 != NULL) {
29142760Sdg199075 err = gld_sendup_vlan(vlan0, pktinfo, mp, acceptfunc, send,
29152760Sdg199075 cansend, &fgld);
29162760Sdg199075 }
29172760Sdg199075 if ((err == 0) && (vlann != NULL)) {
29182760Sdg199075 err = gld_sendup_vlan(vlann, pktinfo, mp, acceptfunc, send,
29192760Sdg199075 cansend, &fgld);
29202760Sdg199075 }
29210Sstevel@tonic-gate
29220Sstevel@tonic-gate ASSERT(mp);
29230Sstevel@tonic-gate /* send the original dup of the packet up the first stream found */
29240Sstevel@tonic-gate if (fgld)
29250Sstevel@tonic-gate gld_passon(fgld, mp, pktinfo, send);
29260Sstevel@tonic-gate else
29270Sstevel@tonic-gate freemsg(mp); /* no streams matched */
29280Sstevel@tonic-gate
29290Sstevel@tonic-gate /* We do not count looped back packets */
29300Sstevel@tonic-gate if (acceptfunc == gld_paccept)
29310Sstevel@tonic-gate return; /* transmit loopback case */
29320Sstevel@tonic-gate
29330Sstevel@tonic-gate if (pktinfo->isBroadcast)
29342760Sdg199075 BUMP(stats0, stats, glds_brdcstrcv, 1);
29350Sstevel@tonic-gate else if (pktinfo->isMulticast)
29362760Sdg199075 BUMP(stats0, stats, glds_multircv, 1);
29370Sstevel@tonic-gate
29380Sstevel@tonic-gate /* No stream accepted this packet */
29390Sstevel@tonic-gate if (!pktinfo->wasAccepted)
29402760Sdg199075 BUMP(stats0, stats, glds_unknowns, 1);
29410Sstevel@tonic-gate }
29420Sstevel@tonic-gate
29432760Sdg199075 #define GLD_IS_PHYS(gld) \
29442760Sdg199075 (((gld_vlan_t *)gld->gld_vlan)->gldv_id == VLAN_VID_NONE)
29452760Sdg199075
29460Sstevel@tonic-gate /*
29470Sstevel@tonic-gate * A packet matches a stream if:
29482760Sdg199075 * The stream's VLAN id is the same as the one in the packet.
29492760Sdg199075 * and the stream accepts EtherType encoded packets and the type matches
29502760Sdg199075 * or the stream accepts LLC packets and the packet is an LLC packet
29510Sstevel@tonic-gate */
29520Sstevel@tonic-gate #define MATCH(stream, pktinfo) \
29532760Sdg199075 ((((gld_vlan_t *)stream->gld_vlan)->gldv_id == pktinfo->vid) && \
29540Sstevel@tonic-gate ((stream->gld_ethertype && stream->gld_sap == pktinfo->ethertype) || \
29552760Sdg199075 (!stream->gld_ethertype && pktinfo->isLLC)))
29560Sstevel@tonic-gate
29570Sstevel@tonic-gate /*
29580Sstevel@tonic-gate * This function validates a packet for sending up a particular
29590Sstevel@tonic-gate * stream. The message header has been parsed and its characteristic
29600Sstevel@tonic-gate * are recorded in the pktinfo data structure. The streams stack info
29610Sstevel@tonic-gate * are presented in gld data structures.
29620Sstevel@tonic-gate */
29630Sstevel@tonic-gate static int
gld_accept(gld_t * gld,pktinfo_t * pktinfo)29640Sstevel@tonic-gate gld_accept(gld_t *gld, pktinfo_t *pktinfo)
29650Sstevel@tonic-gate {
29660Sstevel@tonic-gate /*
29670Sstevel@tonic-gate * if there is no match do not bother checking further.
29682760Sdg199075 * Note that it is okay to examine gld_vlan because
29692760Sdg199075 * macinfo->gldm_lock is held.
29702760Sdg199075 *
29712760Sdg199075 * Because all tagged packets have SAP value ETHERTYPE_VLAN,
29722760Sdg199075 * these packets will pass the SAP filter check if the stream
29732760Sdg199075 * is a ETHERTYPE_VLAN listener.
29740Sstevel@tonic-gate */
29752760Sdg199075 if ((!MATCH(gld, pktinfo) && !(gld->gld_flags & GLD_PROM_SAP) &&
29762760Sdg199075 !(GLD_IS_PHYS(gld) && gld->gld_sap == ETHERTYPE_VLAN &&
29772760Sdg199075 pktinfo->isTagged)))
29780Sstevel@tonic-gate return (0);
29790Sstevel@tonic-gate
29800Sstevel@tonic-gate /*
29810Sstevel@tonic-gate * We don't accept any packet from the hardware if we originated it.
29820Sstevel@tonic-gate * (Contrast gld_paccept, the send-loopback accept function.)
29830Sstevel@tonic-gate */
29840Sstevel@tonic-gate if (pktinfo->isLooped)
29850Sstevel@tonic-gate return (0);
29860Sstevel@tonic-gate
29870Sstevel@tonic-gate /*
29880Sstevel@tonic-gate * If the packet is broadcast or sent to us directly we will accept it.
29890Sstevel@tonic-gate * Also we will accept multicast packets requested by the stream.
29900Sstevel@tonic-gate */
29910Sstevel@tonic-gate if (pktinfo->isForMe || pktinfo->isBroadcast ||
29920Sstevel@tonic-gate gld_mcmatch(gld, pktinfo))
29930Sstevel@tonic-gate return (1);
29940Sstevel@tonic-gate
29950Sstevel@tonic-gate /*
29960Sstevel@tonic-gate * Finally, accept anything else if we're in promiscuous mode
29970Sstevel@tonic-gate */
29980Sstevel@tonic-gate if (gld->gld_flags & GLD_PROM_PHYS)
29990Sstevel@tonic-gate return (1);
30000Sstevel@tonic-gate
30010Sstevel@tonic-gate return (0);
30020Sstevel@tonic-gate }
30030Sstevel@tonic-gate
30040Sstevel@tonic-gate /*
30050Sstevel@tonic-gate * Return TRUE if the given multicast address is one
30060Sstevel@tonic-gate * of those that this particular Stream is interested in.
30070Sstevel@tonic-gate */
30080Sstevel@tonic-gate static int
gld_mcmatch(gld_t * gld,pktinfo_t * pktinfo)30090Sstevel@tonic-gate gld_mcmatch(gld_t *gld, pktinfo_t *pktinfo)
30100Sstevel@tonic-gate {
30110Sstevel@tonic-gate /*
30120Sstevel@tonic-gate * Return FALSE if not a multicast address.
30130Sstevel@tonic-gate */
30140Sstevel@tonic-gate if (!pktinfo->isMulticast)
30150Sstevel@tonic-gate return (0);
30160Sstevel@tonic-gate
30170Sstevel@tonic-gate /*
30180Sstevel@tonic-gate * Check if all multicasts have been enabled for this Stream
30190Sstevel@tonic-gate */
30200Sstevel@tonic-gate if (gld->gld_flags & GLD_PROM_MULT)
30210Sstevel@tonic-gate return (1);
30220Sstevel@tonic-gate
30230Sstevel@tonic-gate /*
30240Sstevel@tonic-gate * Return FALSE if no multicast addresses enabled for this Stream.
30250Sstevel@tonic-gate */
30260Sstevel@tonic-gate if (!gld->gld_mcast)
30270Sstevel@tonic-gate return (0);
30280Sstevel@tonic-gate
30290Sstevel@tonic-gate /*
30300Sstevel@tonic-gate * Otherwise, look for it in the table.
30310Sstevel@tonic-gate */
30320Sstevel@tonic-gate return (gld_multicast(pktinfo->dhost, gld));
30330Sstevel@tonic-gate }
30340Sstevel@tonic-gate
30350Sstevel@tonic-gate /*
30360Sstevel@tonic-gate * gld_multicast determines if the address is a multicast address for
30370Sstevel@tonic-gate * this stream.
30380Sstevel@tonic-gate */
30390Sstevel@tonic-gate static int
gld_multicast(unsigned char * macaddr,gld_t * gld)30400Sstevel@tonic-gate gld_multicast(unsigned char *macaddr, gld_t *gld)
30410Sstevel@tonic-gate {
30420Sstevel@tonic-gate int i;
30430Sstevel@tonic-gate
30440Sstevel@tonic-gate ASSERT(GLDM_LOCK_HELD(gld->gld_mac_info));
30450Sstevel@tonic-gate
30460Sstevel@tonic-gate if (!gld->gld_mcast)
30470Sstevel@tonic-gate return (0);
30480Sstevel@tonic-gate
30490Sstevel@tonic-gate for (i = 0; i < gld->gld_multicnt; i++) {
30500Sstevel@tonic-gate if (gld->gld_mcast[i]) {
30510Sstevel@tonic-gate ASSERT(gld->gld_mcast[i]->gldm_refcnt);
30520Sstevel@tonic-gate if (mac_eq(gld->gld_mcast[i]->gldm_addr, macaddr,
30530Sstevel@tonic-gate gld->gld_mac_info->gldm_addrlen))
30540Sstevel@tonic-gate return (1);
30550Sstevel@tonic-gate }
30560Sstevel@tonic-gate }
30570Sstevel@tonic-gate
30580Sstevel@tonic-gate return (0);
30590Sstevel@tonic-gate }
30600Sstevel@tonic-gate
30610Sstevel@tonic-gate /*
30620Sstevel@tonic-gate * accept function for looped back packets
30630Sstevel@tonic-gate */
30640Sstevel@tonic-gate static int
gld_paccept(gld_t * gld,pktinfo_t * pktinfo)30650Sstevel@tonic-gate gld_paccept(gld_t *gld, pktinfo_t *pktinfo)
30660Sstevel@tonic-gate {
30672760Sdg199075 /*
30682760Sdg199075 * Note that it is okay to examine gld_vlan because macinfo->gldm_lock
30692760Sdg199075 * is held.
30702760Sdg199075 *
30712760Sdg199075 * If a stream is a ETHERTYPE_VLAN listener, it must
30722760Sdg199075 * accept all tagged packets as those packets have SAP value
30732760Sdg199075 * ETHERTYPE_VLAN.
30742760Sdg199075 */
30750Sstevel@tonic-gate return (gld->gld_flags & GLD_PROM_PHYS &&
30762760Sdg199075 (MATCH(gld, pktinfo) || gld->gld_flags & GLD_PROM_SAP ||
30772760Sdg199075 (GLD_IS_PHYS(gld) && gld->gld_sap == ETHERTYPE_VLAN &&
30782760Sdg199075 pktinfo->isTagged)));
30792760Sdg199075
30800Sstevel@tonic-gate }
30810Sstevel@tonic-gate
30820Sstevel@tonic-gate static void
gld_passon(gld_t * gld,mblk_t * mp,pktinfo_t * pktinfo,void (* send)(queue_t * qp,mblk_t * mp))30830Sstevel@tonic-gate gld_passon(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo,
30840Sstevel@tonic-gate void (*send)(queue_t *qp, mblk_t *mp))
30850Sstevel@tonic-gate {
30862760Sdg199075 boolean_t is_phys = GLD_IS_PHYS(gld);
30870Sstevel@tonic-gate int skiplen;
30882760Sdg199075 boolean_t addtag = B_FALSE;
30892760Sdg199075 uint32_t vtag = 0;
30900Sstevel@tonic-gate
30910Sstevel@tonic-gate #ifdef GLD_DEBUG
30920Sstevel@tonic-gate if (gld_debug & GLDTRACE)
30930Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_passon(%p, %p, %p)", (void *)gld,
30940Sstevel@tonic-gate (void *)mp, (void *)pktinfo);
30950Sstevel@tonic-gate
30960Sstevel@tonic-gate if ((gld_debug & GLDRECV) && (!(gld_debug & GLDNOBR) ||
30970Sstevel@tonic-gate (!pktinfo->isBroadcast && !pktinfo->isMulticast)))
30980Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_passon: q: %p mblk: %p minor: %d sap: %x",
30990Sstevel@tonic-gate (void *)gld->gld_qptr->q_next, (void *)mp, gld->gld_minor,
31000Sstevel@tonic-gate gld->gld_sap);
31010Sstevel@tonic-gate #endif
31020Sstevel@tonic-gate /*
31030Sstevel@tonic-gate * Figure out how much of the packet header to throw away.
31040Sstevel@tonic-gate *
31050Sstevel@tonic-gate * Normal DLPI (non RAW/FAST) streams also want the
31060Sstevel@tonic-gate * DL_UNITDATA_IND M_PROTO message block prepended to the M_DATA.
31070Sstevel@tonic-gate */
31080Sstevel@tonic-gate if (gld->gld_flags & GLD_RAW) {
31092760Sdg199075 /*
31102760Sdg199075 * The packet will be tagged in the following cases:
31112760Sdg199075 * - if priority is not 0
31122760Sdg199075 * - a tagged packet sent on a physical link
31132760Sdg199075 */
31142760Sdg199075 if ((pktinfo->isTagged && is_phys) || (pktinfo->user_pri != 0))
31152760Sdg199075 addtag = B_TRUE;
31160Sstevel@tonic-gate skiplen = 0;
31170Sstevel@tonic-gate } else {
31182760Sdg199075 /*
31192760Sdg199075 * The packet will be tagged if it meets all below conditions:
31202760Sdg199075 * - this is a physical stream
31212760Sdg199075 * - this packet is tagged packet
31222760Sdg199075 * - the stream is either a DL_PROMISC_SAP listener or a
31232760Sdg199075 * ETHERTYPE_VLAN listener
31242760Sdg199075 */
31252760Sdg199075 if (is_phys && pktinfo->isTagged &&
31262760Sdg199075 ((gld->gld_sap == ETHERTYPE_VLAN) ||
31272760Sdg199075 (gld->gld_flags & GLD_PROM_SAP))) {
31282760Sdg199075 addtag = B_TRUE;
31292760Sdg199075 }
31302760Sdg199075
31310Sstevel@tonic-gate skiplen = pktinfo->macLen; /* skip mac header */
31320Sstevel@tonic-gate if (gld->gld_ethertype)
31330Sstevel@tonic-gate skiplen += pktinfo->hdrLen; /* skip any extra */
31340Sstevel@tonic-gate }
31350Sstevel@tonic-gate if (skiplen >= pktinfo->pktLen) {
31360Sstevel@tonic-gate /*
31370Sstevel@tonic-gate * If the interpreter did its job right, then it cannot be
31380Sstevel@tonic-gate * asking us to skip more bytes than are in the packet!
31390Sstevel@tonic-gate * However, there could be zero data bytes left after the
31400Sstevel@tonic-gate * amount to skip. DLPI specifies that passed M_DATA blocks
31410Sstevel@tonic-gate * should contain at least one byte of data, so if we have
31420Sstevel@tonic-gate * none we just drop it.
31430Sstevel@tonic-gate */
31440Sstevel@tonic-gate ASSERT(!(skiplen > pktinfo->pktLen));
31450Sstevel@tonic-gate freemsg(mp);
31460Sstevel@tonic-gate return;
31470Sstevel@tonic-gate }
31480Sstevel@tonic-gate
31492760Sdg199075 if (addtag) {
31502760Sdg199075 mblk_t *savemp = mp;
31512760Sdg199075
31522760Sdg199075 vtag = GLD_MAKE_VTAG(pktinfo->user_pri, pktinfo->cfi,
31532760Sdg199075 is_phys ? pktinfo->vid : VLAN_VID_NONE);
31542760Sdg199075 if ((mp = gld_insert_vtag_ether(mp, vtag)) == NULL) {
31552760Sdg199075 freemsg(savemp);
31562760Sdg199075 return;
31572760Sdg199075 }
31582760Sdg199075 }
31592760Sdg199075
31600Sstevel@tonic-gate /*
31610Sstevel@tonic-gate * Skip over the header(s), taking care to possibly handle message
31620Sstevel@tonic-gate * fragments shorter than the amount we need to skip. Hopefully
31630Sstevel@tonic-gate * the driver will put the entire packet, or at least the entire
31640Sstevel@tonic-gate * header, into a single message block. But we handle it if not.
31650Sstevel@tonic-gate */
31660Sstevel@tonic-gate while (skiplen >= MBLKL(mp)) {
31672760Sdg199075 mblk_t *savemp = mp;
31680Sstevel@tonic-gate skiplen -= MBLKL(mp);
31690Sstevel@tonic-gate mp = mp->b_cont;
31700Sstevel@tonic-gate ASSERT(mp != NULL); /* because skiplen < pktinfo->pktLen */
31712760Sdg199075 freeb(savemp);
31720Sstevel@tonic-gate }
31730Sstevel@tonic-gate mp->b_rptr += skiplen;
31740Sstevel@tonic-gate
31750Sstevel@tonic-gate /* Add M_PROTO if necessary, and pass upstream */
31760Sstevel@tonic-gate if (((gld->gld_flags & GLD_FAST) && !pktinfo->isMulticast &&
31770Sstevel@tonic-gate !pktinfo->isBroadcast) || (gld->gld_flags & GLD_RAW)) {
31780Sstevel@tonic-gate /* RAW/FAST: just send up the M_DATA */
31790Sstevel@tonic-gate (*send)(gld->gld_qptr, mp);
31800Sstevel@tonic-gate } else {
31810Sstevel@tonic-gate /* everybody else wants to see a unitdata_ind structure */
31822760Sdg199075 mp = gld_addudind(gld, mp, pktinfo, addtag);
31830Sstevel@tonic-gate if (mp)
31840Sstevel@tonic-gate (*send)(gld->gld_qptr, mp);
31850Sstevel@tonic-gate /* if it failed, gld_addudind already bumped statistic */
31860Sstevel@tonic-gate }
31870Sstevel@tonic-gate }
31880Sstevel@tonic-gate
31890Sstevel@tonic-gate /*
31900Sstevel@tonic-gate * gld_addudind(gld, mp, pktinfo)
31910Sstevel@tonic-gate * format a DL_UNITDATA_IND message to be sent upstream to the user
31920Sstevel@tonic-gate */
31930Sstevel@tonic-gate static mblk_t *
gld_addudind(gld_t * gld,mblk_t * mp,pktinfo_t * pktinfo,boolean_t tagged)31942760Sdg199075 gld_addudind(gld_t *gld, mblk_t *mp, pktinfo_t *pktinfo, boolean_t tagged)
31950Sstevel@tonic-gate {
31960Sstevel@tonic-gate gld_mac_info_t *macinfo = gld->gld_mac_info;
31970Sstevel@tonic-gate gld_vlan_t *vlan = (gld_vlan_t *)gld->gld_vlan;
31980Sstevel@tonic-gate dl_unitdata_ind_t *dludindp;
31990Sstevel@tonic-gate mblk_t *nmp;
32000Sstevel@tonic-gate int size;
32010Sstevel@tonic-gate int type;
32020Sstevel@tonic-gate
32030Sstevel@tonic-gate #ifdef GLD_DEBUG
32040Sstevel@tonic-gate if (gld_debug & GLDTRACE)
32050Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_addudind(%p, %p, %p)", (void *)gld,
32060Sstevel@tonic-gate (void *)mp, (void *)pktinfo);
32070Sstevel@tonic-gate #endif
32080Sstevel@tonic-gate ASSERT(macinfo != NULL);
32090Sstevel@tonic-gate
32100Sstevel@tonic-gate /*
32110Sstevel@tonic-gate * Allocate the DL_UNITDATA_IND M_PROTO header, if allocation fails
32120Sstevel@tonic-gate * might as well discard since we can't go further
32130Sstevel@tonic-gate */
32140Sstevel@tonic-gate size = sizeof (dl_unitdata_ind_t) +
32150Sstevel@tonic-gate 2 * (macinfo->gldm_addrlen + abs(macinfo->gldm_saplen));
32160Sstevel@tonic-gate if ((nmp = allocb(size, BPRI_MED)) == NULL) {
32170Sstevel@tonic-gate freemsg(mp);
32182760Sdg199075 BUMP(vlan->gldv_stats, NULL, glds_gldnorcvbuf, 1);
32190Sstevel@tonic-gate #ifdef GLD_DEBUG
32200Sstevel@tonic-gate if (gld_debug & GLDERRS)
32210Sstevel@tonic-gate cmn_err(CE_WARN,
32220Sstevel@tonic-gate "gld_addudind: allocb failed");
32230Sstevel@tonic-gate #endif
32240Sstevel@tonic-gate return ((mblk_t *)NULL);
32250Sstevel@tonic-gate }
32260Sstevel@tonic-gate DB_TYPE(nmp) = M_PROTO;
32270Sstevel@tonic-gate nmp->b_rptr = nmp->b_datap->db_lim - size;
32280Sstevel@tonic-gate
32292760Sdg199075 if (tagged)
32302760Sdg199075 type = ETHERTYPE_VLAN;
32312760Sdg199075 else
32322760Sdg199075 type = (gld->gld_ethertype) ? pktinfo->ethertype : 0;
32332760Sdg199075
32340Sstevel@tonic-gate
32350Sstevel@tonic-gate /*
32360Sstevel@tonic-gate * now setup the DL_UNITDATA_IND header
32370Sstevel@tonic-gate *
32380Sstevel@tonic-gate * XXX This looks broken if the saps aren't two bytes.
32390Sstevel@tonic-gate */
32400Sstevel@tonic-gate dludindp = (dl_unitdata_ind_t *)nmp->b_rptr;
32410Sstevel@tonic-gate dludindp->dl_primitive = DL_UNITDATA_IND;
32420Sstevel@tonic-gate dludindp->dl_src_addr_length =
32430Sstevel@tonic-gate dludindp->dl_dest_addr_length = macinfo->gldm_addrlen +
32445903Ssowmini abs(macinfo->gldm_saplen);
32450Sstevel@tonic-gate dludindp->dl_dest_addr_offset = sizeof (dl_unitdata_ind_t);
32460Sstevel@tonic-gate dludindp->dl_src_addr_offset = dludindp->dl_dest_addr_offset +
32475903Ssowmini dludindp->dl_dest_addr_length;
32480Sstevel@tonic-gate
32490Sstevel@tonic-gate dludindp->dl_group_address = (pktinfo->isMulticast ||
32505903Ssowmini pktinfo->isBroadcast);
32510Sstevel@tonic-gate
32520Sstevel@tonic-gate nmp->b_wptr = nmp->b_rptr + dludindp->dl_dest_addr_offset;
32530Sstevel@tonic-gate
32540Sstevel@tonic-gate mac_copy(pktinfo->dhost, nmp->b_wptr, macinfo->gldm_addrlen);
32550Sstevel@tonic-gate nmp->b_wptr += macinfo->gldm_addrlen;
32560Sstevel@tonic-gate
32570Sstevel@tonic-gate ASSERT(macinfo->gldm_saplen == -2); /* XXX following code assumes */
32580Sstevel@tonic-gate *(ushort_t *)(nmp->b_wptr) = type;
32590Sstevel@tonic-gate nmp->b_wptr += abs(macinfo->gldm_saplen);
32600Sstevel@tonic-gate
32610Sstevel@tonic-gate ASSERT(nmp->b_wptr == nmp->b_rptr + dludindp->dl_src_addr_offset);
32620Sstevel@tonic-gate
32630Sstevel@tonic-gate mac_copy(pktinfo->shost, nmp->b_wptr, macinfo->gldm_addrlen);
32640Sstevel@tonic-gate nmp->b_wptr += macinfo->gldm_addrlen;
32650Sstevel@tonic-gate
32660Sstevel@tonic-gate *(ushort_t *)(nmp->b_wptr) = type;
32670Sstevel@tonic-gate nmp->b_wptr += abs(macinfo->gldm_saplen);
32680Sstevel@tonic-gate
32690Sstevel@tonic-gate if (pktinfo->nosource)
32700Sstevel@tonic-gate dludindp->dl_src_addr_offset = dludindp->dl_src_addr_length = 0;
32710Sstevel@tonic-gate linkb(nmp, mp);
32720Sstevel@tonic-gate return (nmp);
32730Sstevel@tonic-gate }
32740Sstevel@tonic-gate
32750Sstevel@tonic-gate /* ======================================================= */
32760Sstevel@tonic-gate /* wsrv group: called from wsrv, single threaded per queue */
32770Sstevel@tonic-gate /* ======================================================= */
32780Sstevel@tonic-gate
32790Sstevel@tonic-gate /*
32800Sstevel@tonic-gate * We go to some trouble to avoid taking the same lock during normal
32810Sstevel@tonic-gate * transmit processing as we do during normal receive processing.
32820Sstevel@tonic-gate *
32830Sstevel@tonic-gate * Elements of the per-instance macinfo and per-stream gld_t structures
32840Sstevel@tonic-gate * are for the most part protected by the GLDM_LOCK rwlock/mutex.
32850Sstevel@tonic-gate * (Elements of the gld_mac_pvt_t structure are considered part of the
32860Sstevel@tonic-gate * macinfo structure for purposes of this discussion).
32870Sstevel@tonic-gate *
32880Sstevel@tonic-gate * However, it is more complicated than that:
32890Sstevel@tonic-gate *
32900Sstevel@tonic-gate * Elements of the macinfo structure that are set before the macinfo
32910Sstevel@tonic-gate * structure is added to its device list by gld_register(), and never
32920Sstevel@tonic-gate * thereafter modified, are accessed without requiring taking the lock.
32930Sstevel@tonic-gate * A similar rule applies to those elements of the gld_t structure that
32940Sstevel@tonic-gate * are written by gld_open() before the stream is added to any list.
32950Sstevel@tonic-gate *
32960Sstevel@tonic-gate * Most other elements of the macinfo structure may only be read or
32970Sstevel@tonic-gate * written while holding the maclock.
32980Sstevel@tonic-gate *
32990Sstevel@tonic-gate * Most writable elements of the gld_t structure are written only
33000Sstevel@tonic-gate * within the single-threaded domain of wsrv() and subsidiaries.
33010Sstevel@tonic-gate * (This domain includes open/close while qprocs are not on.)
33020Sstevel@tonic-gate * The maclock need not be taken while within that domain
33030Sstevel@tonic-gate * simply to read those elements. Writing to them, even within
33040Sstevel@tonic-gate * that domain, or reading from it outside that domain, requires
33050Sstevel@tonic-gate * holding the maclock. Exception: if the stream is not
33060Sstevel@tonic-gate * presently attached to a PPA, there is no associated macinfo,
33070Sstevel@tonic-gate * and no maclock need be taken.
33080Sstevel@tonic-gate *
33090Sstevel@tonic-gate * The curr_macaddr element of the mac private structure is also
33100Sstevel@tonic-gate * protected by the GLDM_LOCK rwlock/mutex, like most other members
33110Sstevel@tonic-gate * of that structure. However, there are a few instances in the
33120Sstevel@tonic-gate * transmit path where we choose to forgo lock protection when
33130Sstevel@tonic-gate * reading this variable. This is to avoid lock contention between
33140Sstevel@tonic-gate * threads executing the DL_UNITDATA_REQ case and receive threads.
33150Sstevel@tonic-gate * In doing so we will take a small risk or a few corrupted packets
33160Sstevel@tonic-gate * during the short an rare times when someone is changing the interface's
33170Sstevel@tonic-gate * physical address. We consider the small cost in this rare case to be
33180Sstevel@tonic-gate * worth the benefit of reduced lock contention under normal operating
33190Sstevel@tonic-gate * conditions. The risk/cost is small because:
33200Sstevel@tonic-gate * 1. there is no guarantee at this layer of uncorrupted delivery.
33210Sstevel@tonic-gate * 2. the physaddr doesn't change very often - no performance hit.
33220Sstevel@tonic-gate * 3. if the physaddr changes, other stuff is going to be screwed
33230Sstevel@tonic-gate * up for a while anyway, while other sites refigure ARP, etc.,
33240Sstevel@tonic-gate * so losing a couple of packets is the least of our worries.
33250Sstevel@tonic-gate *
33260Sstevel@tonic-gate * The list of streams associated with a macinfo is protected by
33270Sstevel@tonic-gate * two locks: the per-macinfo maclock, and the per-major-device
33280Sstevel@tonic-gate * gld_devlock. Both must be held to modify the list, but either
33290Sstevel@tonic-gate * may be held to protect the list during reading/traversing. This
33300Sstevel@tonic-gate * allows independent locking for multiple instances in the receive
33310Sstevel@tonic-gate * path (using macinfo), while facilitating routines that must search
33320Sstevel@tonic-gate * the entire set of streams associated with a major device, such as
33330Sstevel@tonic-gate * gld_findminor(), gld_finddevinfo(), close(). The "nstreams"
33340Sstevel@tonic-gate * macinfo element, and the gld_mac_info gld_t element, are similarly
33350Sstevel@tonic-gate * protected, since they change at exactly the same time macinfo
33360Sstevel@tonic-gate * streams list does.
33370Sstevel@tonic-gate *
33380Sstevel@tonic-gate * The list of macinfo structures associated with a major device
33390Sstevel@tonic-gate * structure is protected by the gld_devlock, as is the per-major
33400Sstevel@tonic-gate * list of Style 2 streams in the DL_UNATTACHED state.
33410Sstevel@tonic-gate *
33420Sstevel@tonic-gate * The list of major devices is kept on a module-global list
33430Sstevel@tonic-gate * gld_device_list, which has its own lock to protect the list.
33440Sstevel@tonic-gate *
33450Sstevel@tonic-gate * When it is necessary to hold more than one lock at a time, they
33460Sstevel@tonic-gate * are acquired in this "outside in" order:
33470Sstevel@tonic-gate * gld_device_list.gld_devlock
33480Sstevel@tonic-gate * glddev->gld_devlock
33490Sstevel@tonic-gate * GLDM_LOCK(macinfo)
33500Sstevel@tonic-gate *
33510Sstevel@tonic-gate * Finally, there are some "volatile" elements of the gld_t structure
33520Sstevel@tonic-gate * used for synchronization between various routines that don't share
33530Sstevel@tonic-gate * the same mutexes. See the routines for details. These are:
33540Sstevel@tonic-gate * gld_xwait between gld_wsrv() and gld_sched()
33550Sstevel@tonic-gate * gld_sched_ran between gld_wsrv() and gld_sched()
33560Sstevel@tonic-gate * gld_in_unbind between gld_wput() and wsrv's gld_unbind()
33570Sstevel@tonic-gate * gld_wput_count between gld_wput() and wsrv's gld_unbind()
33580Sstevel@tonic-gate * gld_in_wsrv between gld_wput() and gld_wsrv()
33590Sstevel@tonic-gate * (used in conjunction with q->q_first)
33600Sstevel@tonic-gate */
33610Sstevel@tonic-gate
33620Sstevel@tonic-gate /*
33630Sstevel@tonic-gate * gld_ioctl (q, mp)
33640Sstevel@tonic-gate * handles all ioctl requests passed downstream. This routine is
33650Sstevel@tonic-gate * passed a pointer to the message block with the ioctl request in it, and a
33660Sstevel@tonic-gate * pointer to the queue so it can respond to the ioctl request with an ack.
33670Sstevel@tonic-gate */
33680Sstevel@tonic-gate int
gld_ioctl(queue_t * q,mblk_t * mp)33690Sstevel@tonic-gate gld_ioctl(queue_t *q, mblk_t *mp)
33700Sstevel@tonic-gate {
33710Sstevel@tonic-gate struct iocblk *iocp;
33720Sstevel@tonic-gate gld_t *gld;
33730Sstevel@tonic-gate gld_mac_info_t *macinfo;
33740Sstevel@tonic-gate
33750Sstevel@tonic-gate #ifdef GLD_DEBUG
33760Sstevel@tonic-gate if (gld_debug & GLDTRACE)
33770Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_ioctl(%p %p)", (void *)q, (void *)mp);
33780Sstevel@tonic-gate #endif
33790Sstevel@tonic-gate gld = (gld_t *)q->q_ptr;
33800Sstevel@tonic-gate iocp = (struct iocblk *)mp->b_rptr;
33810Sstevel@tonic-gate switch (iocp->ioc_cmd) {
33820Sstevel@tonic-gate case DLIOCRAW: /* raw M_DATA mode */
33830Sstevel@tonic-gate gld->gld_flags |= GLD_RAW;
33840Sstevel@tonic-gate DB_TYPE(mp) = M_IOCACK;
33850Sstevel@tonic-gate qreply(q, mp);
33860Sstevel@tonic-gate break;
33870Sstevel@tonic-gate
33880Sstevel@tonic-gate case DL_IOC_HDR_INFO: /* fastpath */
33892760Sdg199075 /*
33902760Sdg199075 * DL_IOC_HDR_INFO should only come from IP. The one
33912760Sdg199075 * initiated from user-land should not be allowed.
33922760Sdg199075 */
33932760Sdg199075 if ((gld_global_options & GLD_OPT_NO_FASTPATH) ||
33942760Sdg199075 (iocp->ioc_cr != kcred)) {
33950Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
33960Sstevel@tonic-gate break;
33970Sstevel@tonic-gate }
33980Sstevel@tonic-gate gld_fastpath(gld, q, mp);
33990Sstevel@tonic-gate break;
34000Sstevel@tonic-gate
34015895Syz147064 case DLIOCMARGININFO: { /* margin size */
34025895Syz147064 int err;
34035895Syz147064
34045895Syz147064 if ((macinfo = gld->gld_mac_info) == NULL) {
34055895Syz147064 miocnak(q, mp, 0, EINVAL);
34065895Syz147064 break;
34075895Syz147064 }
34085895Syz147064
34095895Syz147064 if ((err = miocpullup(mp, sizeof (uint32_t))) != 0) {
34105895Syz147064 miocnak(q, mp, 0, err);
34115895Syz147064 break;
34125895Syz147064 }
34135895Syz147064
34145895Syz147064 *((uint32_t *)mp->b_cont->b_rptr) = macinfo->gldm_margin;
34155895Syz147064 miocack(q, mp, sizeof (uint32_t), 0);
34165895Syz147064 break;
34175895Syz147064 }
34180Sstevel@tonic-gate default:
34190Sstevel@tonic-gate macinfo = gld->gld_mac_info;
34200Sstevel@tonic-gate if (macinfo == NULL || macinfo->gldm_ioctl == NULL) {
34210Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
34220Sstevel@tonic-gate break;
34230Sstevel@tonic-gate }
34240Sstevel@tonic-gate
34250Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
34260Sstevel@tonic-gate (void) (*macinfo->gldm_ioctl) (macinfo, q, mp);
34270Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
34280Sstevel@tonic-gate break;
34290Sstevel@tonic-gate }
34300Sstevel@tonic-gate return (0);
34310Sstevel@tonic-gate }
34320Sstevel@tonic-gate
34330Sstevel@tonic-gate /*
34340Sstevel@tonic-gate * Since the rules for "fastpath" mode don't seem to be documented
34350Sstevel@tonic-gate * anywhere, I will describe GLD's rules for fastpath users here:
34360Sstevel@tonic-gate *
34370Sstevel@tonic-gate * Once in this mode you remain there until close.
34380Sstevel@tonic-gate * If you unbind/rebind you should get a new header using DL_IOC_HDR_INFO.
34390Sstevel@tonic-gate * You must be bound (DL_IDLE) to transmit.
34400Sstevel@tonic-gate * There are other rules not listed above.
34410Sstevel@tonic-gate */
34420Sstevel@tonic-gate static void
gld_fastpath(gld_t * gld,queue_t * q,mblk_t * mp)34430Sstevel@tonic-gate gld_fastpath(gld_t *gld, queue_t *q, mblk_t *mp)
34440Sstevel@tonic-gate {
34450Sstevel@tonic-gate gld_interface_t *ifp;
34460Sstevel@tonic-gate gld_mac_info_t *macinfo;
34470Sstevel@tonic-gate dl_unitdata_req_t *dludp;
34480Sstevel@tonic-gate mblk_t *nmp;
34490Sstevel@tonic-gate t_scalar_t off, len;
34500Sstevel@tonic-gate uint_t maclen;
34510Sstevel@tonic-gate int error;
34520Sstevel@tonic-gate
34530Sstevel@tonic-gate if (gld->gld_state != DL_IDLE) {
34540Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
34550Sstevel@tonic-gate return;
34560Sstevel@tonic-gate }
34570Sstevel@tonic-gate
34580Sstevel@tonic-gate macinfo = gld->gld_mac_info;
34590Sstevel@tonic-gate ASSERT(macinfo != NULL);
34600Sstevel@tonic-gate maclen = macinfo->gldm_addrlen + abs(macinfo->gldm_saplen);
34610Sstevel@tonic-gate
34620Sstevel@tonic-gate error = miocpullup(mp, sizeof (dl_unitdata_req_t) + maclen);
34630Sstevel@tonic-gate if (error != 0) {
34640Sstevel@tonic-gate miocnak(q, mp, 0, error);
34650Sstevel@tonic-gate return;
34660Sstevel@tonic-gate }
34670Sstevel@tonic-gate
34680Sstevel@tonic-gate dludp = (dl_unitdata_req_t *)mp->b_cont->b_rptr;
34690Sstevel@tonic-gate off = dludp->dl_dest_addr_offset;
34700Sstevel@tonic-gate len = dludp->dl_dest_addr_length;
34710Sstevel@tonic-gate if (dludp->dl_primitive != DL_UNITDATA_REQ ||
34720Sstevel@tonic-gate !MBLKIN(mp->b_cont, off, len) || len != maclen) {
34730Sstevel@tonic-gate miocnak(q, mp, 0, EINVAL);
34740Sstevel@tonic-gate return;
34750Sstevel@tonic-gate }
34760Sstevel@tonic-gate
34770Sstevel@tonic-gate /*
34780Sstevel@tonic-gate * We take his fastpath request as a declaration that he will accept
34790Sstevel@tonic-gate * M_DATA messages from us, whether or not we are willing to accept
34800Sstevel@tonic-gate * them from him. This allows us to have fastpath in one direction
34810Sstevel@tonic-gate * (flow upstream) even on media with Source Routing, where we are
34820Sstevel@tonic-gate * unable to provide a fixed MAC header to be prepended to downstream
34830Sstevel@tonic-gate * flowing packets. So we set GLD_FAST whether or not we decide to
34840Sstevel@tonic-gate * allow him to send M_DATA down to us.
34850Sstevel@tonic-gate */
34860Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
34870Sstevel@tonic-gate gld->gld_flags |= GLD_FAST;
34880Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
34890Sstevel@tonic-gate
34900Sstevel@tonic-gate ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
34910Sstevel@tonic-gate
34920Sstevel@tonic-gate /* This will fail for Source Routing media */
34930Sstevel@tonic-gate /* Also on Ethernet on 802.2 SAPs */
34940Sstevel@tonic-gate if ((nmp = (*ifp->mkfastpath)(gld, mp)) == NULL) {
34950Sstevel@tonic-gate miocnak(q, mp, 0, ENOMEM);
34960Sstevel@tonic-gate return;
34970Sstevel@tonic-gate }
34980Sstevel@tonic-gate
34990Sstevel@tonic-gate /*
35000Sstevel@tonic-gate * Link new mblk in after the "request" mblks.
35010Sstevel@tonic-gate */
35020Sstevel@tonic-gate linkb(mp, nmp);
35030Sstevel@tonic-gate miocack(q, mp, msgdsize(mp->b_cont), 0);
35040Sstevel@tonic-gate }
35050Sstevel@tonic-gate
35060Sstevel@tonic-gate /*
35070Sstevel@tonic-gate * gld_cmds (q, mp)
35080Sstevel@tonic-gate * process the DL commands as defined in dlpi.h
35090Sstevel@tonic-gate * note that the primitives return status which is passed back
35100Sstevel@tonic-gate * to the service procedure. If the value is GLDE_RETRY, then
35110Sstevel@tonic-gate * it is assumed that processing must stop and the primitive has
35120Sstevel@tonic-gate * been put back onto the queue. If the value is any other error,
35130Sstevel@tonic-gate * then an error ack is generated by the service procedure.
35140Sstevel@tonic-gate */
35150Sstevel@tonic-gate static int
gld_cmds(queue_t * q,mblk_t * mp)35160Sstevel@tonic-gate gld_cmds(queue_t *q, mblk_t *mp)
35170Sstevel@tonic-gate {
35180Sstevel@tonic-gate union DL_primitives *dlp = (union DL_primitives *)mp->b_rptr;
35190Sstevel@tonic-gate gld_t *gld = (gld_t *)(q->q_ptr);
35200Sstevel@tonic-gate int result = DL_BADPRIM;
35210Sstevel@tonic-gate int mblkl = MBLKL(mp);
35220Sstevel@tonic-gate t_uscalar_t dlreq;
35230Sstevel@tonic-gate
35240Sstevel@tonic-gate /* Make sure we have at least dlp->dl_primitive */
35250Sstevel@tonic-gate if (mblkl < sizeof (dlp->dl_primitive))
35260Sstevel@tonic-gate return (DL_BADPRIM);
35270Sstevel@tonic-gate
35280Sstevel@tonic-gate dlreq = dlp->dl_primitive;
35290Sstevel@tonic-gate #ifdef GLD_DEBUG
35300Sstevel@tonic-gate if (gld_debug & GLDTRACE)
35310Sstevel@tonic-gate cmn_err(CE_NOTE,
35320Sstevel@tonic-gate "gld_cmds(%p, %p):dlp=%p, dlp->dl_primitive=%d",
35330Sstevel@tonic-gate (void *)q, (void *)mp, (void *)dlp, dlreq);
35340Sstevel@tonic-gate #endif
35350Sstevel@tonic-gate
35360Sstevel@tonic-gate switch (dlreq) {
35370Sstevel@tonic-gate case DL_UDQOS_REQ:
35380Sstevel@tonic-gate if (mblkl < DL_UDQOS_REQ_SIZE)
35390Sstevel@tonic-gate break;
35400Sstevel@tonic-gate result = gld_udqos(q, mp);
35410Sstevel@tonic-gate break;
35420Sstevel@tonic-gate
35430Sstevel@tonic-gate case DL_BIND_REQ:
35440Sstevel@tonic-gate if (mblkl < DL_BIND_REQ_SIZE)
35450Sstevel@tonic-gate break;
35460Sstevel@tonic-gate result = gld_bind(q, mp);
35470Sstevel@tonic-gate break;
35480Sstevel@tonic-gate
35490Sstevel@tonic-gate case DL_UNBIND_REQ:
35500Sstevel@tonic-gate if (mblkl < DL_UNBIND_REQ_SIZE)
35510Sstevel@tonic-gate break;
35520Sstevel@tonic-gate result = gld_unbind(q, mp);
35530Sstevel@tonic-gate break;
35540Sstevel@tonic-gate
35550Sstevel@tonic-gate case DL_UNITDATA_REQ:
35560Sstevel@tonic-gate if (mblkl < DL_UNITDATA_REQ_SIZE)
35570Sstevel@tonic-gate break;
35580Sstevel@tonic-gate result = gld_unitdata(q, mp);
35590Sstevel@tonic-gate break;
35600Sstevel@tonic-gate
35610Sstevel@tonic-gate case DL_INFO_REQ:
35620Sstevel@tonic-gate if (mblkl < DL_INFO_REQ_SIZE)
35630Sstevel@tonic-gate break;
35640Sstevel@tonic-gate result = gld_inforeq(q, mp);
35650Sstevel@tonic-gate break;
35660Sstevel@tonic-gate
35670Sstevel@tonic-gate case DL_ATTACH_REQ:
35680Sstevel@tonic-gate if (mblkl < DL_ATTACH_REQ_SIZE)
35690Sstevel@tonic-gate break;
35700Sstevel@tonic-gate if (gld->gld_style == DL_STYLE2)
35710Sstevel@tonic-gate result = gldattach(q, mp);
35720Sstevel@tonic-gate else
35730Sstevel@tonic-gate result = DL_NOTSUPPORTED;
35740Sstevel@tonic-gate break;
35750Sstevel@tonic-gate
35760Sstevel@tonic-gate case DL_DETACH_REQ:
35770Sstevel@tonic-gate if (mblkl < DL_DETACH_REQ_SIZE)
35780Sstevel@tonic-gate break;
35790Sstevel@tonic-gate if (gld->gld_style == DL_STYLE2)
35800Sstevel@tonic-gate result = gldunattach(q, mp);
35810Sstevel@tonic-gate else
35820Sstevel@tonic-gate result = DL_NOTSUPPORTED;
35830Sstevel@tonic-gate break;
35840Sstevel@tonic-gate
35850Sstevel@tonic-gate case DL_ENABMULTI_REQ:
35860Sstevel@tonic-gate if (mblkl < DL_ENABMULTI_REQ_SIZE)
35870Sstevel@tonic-gate break;
35880Sstevel@tonic-gate result = gld_enable_multi(q, mp);
35890Sstevel@tonic-gate break;
35900Sstevel@tonic-gate
35910Sstevel@tonic-gate case DL_DISABMULTI_REQ:
35920Sstevel@tonic-gate if (mblkl < DL_DISABMULTI_REQ_SIZE)
35930Sstevel@tonic-gate break;
35940Sstevel@tonic-gate result = gld_disable_multi(q, mp);
35950Sstevel@tonic-gate break;
35960Sstevel@tonic-gate
35970Sstevel@tonic-gate case DL_PHYS_ADDR_REQ:
35980Sstevel@tonic-gate if (mblkl < DL_PHYS_ADDR_REQ_SIZE)
35990Sstevel@tonic-gate break;
36000Sstevel@tonic-gate result = gld_physaddr(q, mp);
36010Sstevel@tonic-gate break;
36020Sstevel@tonic-gate
36030Sstevel@tonic-gate case DL_SET_PHYS_ADDR_REQ:
36040Sstevel@tonic-gate if (mblkl < DL_SET_PHYS_ADDR_REQ_SIZE)
36050Sstevel@tonic-gate break;
36060Sstevel@tonic-gate result = gld_setaddr(q, mp);
36070Sstevel@tonic-gate break;
36080Sstevel@tonic-gate
36090Sstevel@tonic-gate case DL_PROMISCON_REQ:
36100Sstevel@tonic-gate if (mblkl < DL_PROMISCON_REQ_SIZE)
36110Sstevel@tonic-gate break;
36120Sstevel@tonic-gate result = gld_promisc(q, mp, dlreq, B_TRUE);
36130Sstevel@tonic-gate break;
36140Sstevel@tonic-gate
36150Sstevel@tonic-gate case DL_PROMISCOFF_REQ:
36160Sstevel@tonic-gate if (mblkl < DL_PROMISCOFF_REQ_SIZE)
36170Sstevel@tonic-gate break;
36180Sstevel@tonic-gate result = gld_promisc(q, mp, dlreq, B_FALSE);
36190Sstevel@tonic-gate break;
36200Sstevel@tonic-gate
36210Sstevel@tonic-gate case DL_GET_STATISTICS_REQ:
36220Sstevel@tonic-gate if (mblkl < DL_GET_STATISTICS_REQ_SIZE)
36230Sstevel@tonic-gate break;
36240Sstevel@tonic-gate result = gld_get_statistics(q, mp);
36250Sstevel@tonic-gate break;
36260Sstevel@tonic-gate
36270Sstevel@tonic-gate case DL_CAPABILITY_REQ:
36280Sstevel@tonic-gate if (mblkl < DL_CAPABILITY_REQ_SIZE)
36290Sstevel@tonic-gate break;
36300Sstevel@tonic-gate result = gld_cap(q, mp);
36310Sstevel@tonic-gate break;
36320Sstevel@tonic-gate
36330Sstevel@tonic-gate case DL_NOTIFY_REQ:
36340Sstevel@tonic-gate if (mblkl < DL_NOTIFY_REQ_SIZE)
36350Sstevel@tonic-gate break;
36360Sstevel@tonic-gate result = gld_notify_req(q, mp);
36370Sstevel@tonic-gate break;
36380Sstevel@tonic-gate
36390Sstevel@tonic-gate case DL_XID_REQ:
36400Sstevel@tonic-gate case DL_XID_RES:
36410Sstevel@tonic-gate case DL_TEST_REQ:
36420Sstevel@tonic-gate case DL_TEST_RES:
36430Sstevel@tonic-gate case DL_CONTROL_REQ:
364456Smeem case DL_PASSIVE_REQ:
36450Sstevel@tonic-gate result = DL_NOTSUPPORTED;
36460Sstevel@tonic-gate break;
36470Sstevel@tonic-gate
36480Sstevel@tonic-gate default:
36490Sstevel@tonic-gate #ifdef GLD_DEBUG
36500Sstevel@tonic-gate if (gld_debug & GLDERRS)
36510Sstevel@tonic-gate cmn_err(CE_WARN,
36520Sstevel@tonic-gate "gld_cmds: unknown M_PROTO message: %d",
36530Sstevel@tonic-gate dlreq);
36540Sstevel@tonic-gate #endif
36550Sstevel@tonic-gate result = DL_BADPRIM;
36560Sstevel@tonic-gate }
36570Sstevel@tonic-gate
36580Sstevel@tonic-gate return (result);
36590Sstevel@tonic-gate }
36600Sstevel@tonic-gate
36610Sstevel@tonic-gate static int
gld_cap(queue_t * q,mblk_t * mp)36620Sstevel@tonic-gate gld_cap(queue_t *q, mblk_t *mp)
36630Sstevel@tonic-gate {
36640Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
36650Sstevel@tonic-gate dl_capability_req_t *dlp = (dl_capability_req_t *)mp->b_rptr;
36660Sstevel@tonic-gate
36670Sstevel@tonic-gate if (gld->gld_state == DL_UNATTACHED)
36680Sstevel@tonic-gate return (DL_OUTSTATE);
36690Sstevel@tonic-gate
36700Sstevel@tonic-gate if (dlp->dl_sub_length == 0)
36710Sstevel@tonic-gate return (gld_cap_ack(q, mp));
36720Sstevel@tonic-gate
36730Sstevel@tonic-gate return (gld_cap_enable(q, mp));
36740Sstevel@tonic-gate }
36750Sstevel@tonic-gate
36760Sstevel@tonic-gate static int
gld_cap_ack(queue_t * q,mblk_t * mp)36770Sstevel@tonic-gate gld_cap_ack(queue_t *q, mblk_t *mp)
36780Sstevel@tonic-gate {
36790Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
36800Sstevel@tonic-gate gld_mac_info_t *macinfo = gld->gld_mac_info;
36810Sstevel@tonic-gate gld_interface_t *ifp;
36820Sstevel@tonic-gate dl_capability_ack_t *dlap;
36830Sstevel@tonic-gate dl_capability_sub_t *dlsp;
36840Sstevel@tonic-gate size_t size = sizeof (dl_capability_ack_t);
36850Sstevel@tonic-gate size_t subsize = 0;
36860Sstevel@tonic-gate
36870Sstevel@tonic-gate ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
36880Sstevel@tonic-gate
36890Sstevel@tonic-gate if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_ANY)
36900Sstevel@tonic-gate subsize += sizeof (dl_capability_sub_t) +
36910Sstevel@tonic-gate sizeof (dl_capab_hcksum_t);
36920Sstevel@tonic-gate if (macinfo->gldm_capabilities & GLD_CAP_ZEROCOPY)
36930Sstevel@tonic-gate subsize += sizeof (dl_capability_sub_t) +
36940Sstevel@tonic-gate sizeof (dl_capab_zerocopy_t);
36950Sstevel@tonic-gate if (macinfo->gldm_options & GLDOPT_MDT)
36960Sstevel@tonic-gate subsize += (sizeof (dl_capability_sub_t) +
36970Sstevel@tonic-gate sizeof (dl_capab_mdt_t));
36980Sstevel@tonic-gate
36990Sstevel@tonic-gate if ((mp = mexchange(q, mp, size + subsize, M_PROTO,
37000Sstevel@tonic-gate DL_CAPABILITY_ACK)) == NULL)
37010Sstevel@tonic-gate return (GLDE_OK);
37020Sstevel@tonic-gate
37030Sstevel@tonic-gate dlap = (dl_capability_ack_t *)mp->b_rptr;
37040Sstevel@tonic-gate dlap->dl_sub_offset = 0;
37050Sstevel@tonic-gate if ((dlap->dl_sub_length = subsize) != 0)
37060Sstevel@tonic-gate dlap->dl_sub_offset = sizeof (dl_capability_ack_t);
37070Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)&dlap[1];
37080Sstevel@tonic-gate
37090Sstevel@tonic-gate if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_ANY) {
37100Sstevel@tonic-gate dl_capab_hcksum_t *dlhp = (dl_capab_hcksum_t *)&dlsp[1];
37110Sstevel@tonic-gate
37120Sstevel@tonic-gate dlsp->dl_cap = DL_CAPAB_HCKSUM;
37130Sstevel@tonic-gate dlsp->dl_length = sizeof (dl_capab_hcksum_t);
37140Sstevel@tonic-gate
37150Sstevel@tonic-gate dlhp->hcksum_version = HCKSUM_VERSION_1;
37160Sstevel@tonic-gate
37170Sstevel@tonic-gate dlhp->hcksum_txflags = 0;
37180Sstevel@tonic-gate if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_PARTIAL)
37190Sstevel@tonic-gate dlhp->hcksum_txflags |= HCKSUM_INET_PARTIAL;
37200Sstevel@tonic-gate if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_FULL_V4)
37210Sstevel@tonic-gate dlhp->hcksum_txflags |= HCKSUM_INET_FULL_V4;
3722741Smasputra if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_FULL_V6)
3723741Smasputra dlhp->hcksum_txflags |= HCKSUM_INET_FULL_V6;
37240Sstevel@tonic-gate if (macinfo->gldm_capabilities & GLD_CAP_CKSUM_IPHDR)
37250Sstevel@tonic-gate dlhp->hcksum_txflags |= HCKSUM_IPHDRCKSUM;
37260Sstevel@tonic-gate
37270Sstevel@tonic-gate dlcapabsetqid(&(dlhp->hcksum_mid), RD(q));
37280Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)&dlhp[1];
37290Sstevel@tonic-gate }
37300Sstevel@tonic-gate
37310Sstevel@tonic-gate if (macinfo->gldm_capabilities & GLD_CAP_ZEROCOPY) {
37320Sstevel@tonic-gate dl_capab_zerocopy_t *dlzp = (dl_capab_zerocopy_t *)&dlsp[1];
37330Sstevel@tonic-gate
37340Sstevel@tonic-gate dlsp->dl_cap = DL_CAPAB_ZEROCOPY;
37350Sstevel@tonic-gate dlsp->dl_length = sizeof (dl_capab_zerocopy_t);
37360Sstevel@tonic-gate dlzp->zerocopy_version = ZEROCOPY_VERSION_1;
37370Sstevel@tonic-gate dlzp->zerocopy_flags = DL_CAPAB_VMSAFE_MEM;
37380Sstevel@tonic-gate
37390Sstevel@tonic-gate dlcapabsetqid(&(dlzp->zerocopy_mid), RD(q));
37400Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)&dlzp[1];
37410Sstevel@tonic-gate }
37420Sstevel@tonic-gate
37430Sstevel@tonic-gate if (macinfo->gldm_options & GLDOPT_MDT) {
37440Sstevel@tonic-gate dl_capab_mdt_t *dlmp = (dl_capab_mdt_t *)&dlsp[1];
37450Sstevel@tonic-gate
37460Sstevel@tonic-gate dlsp->dl_cap = DL_CAPAB_MDT;
37470Sstevel@tonic-gate dlsp->dl_length = sizeof (dl_capab_mdt_t);
37480Sstevel@tonic-gate
37490Sstevel@tonic-gate dlmp->mdt_version = MDT_VERSION_2;
37500Sstevel@tonic-gate dlmp->mdt_max_pld = macinfo->gldm_mdt_segs;
37510Sstevel@tonic-gate dlmp->mdt_span_limit = macinfo->gldm_mdt_sgl;
37520Sstevel@tonic-gate dlcapabsetqid(&dlmp->mdt_mid, OTHERQ(q));
37530Sstevel@tonic-gate dlmp->mdt_flags = DL_CAPAB_MDT_ENABLE;
37540Sstevel@tonic-gate dlmp->mdt_hdr_head = ifp->hdr_size;
37550Sstevel@tonic-gate dlmp->mdt_hdr_tail = 0;
37560Sstevel@tonic-gate }
37570Sstevel@tonic-gate
37580Sstevel@tonic-gate qreply(q, mp);
37590Sstevel@tonic-gate return (GLDE_OK);
37600Sstevel@tonic-gate }
37610Sstevel@tonic-gate
37620Sstevel@tonic-gate static int
gld_cap_enable(queue_t * q,mblk_t * mp)37630Sstevel@tonic-gate gld_cap_enable(queue_t *q, mblk_t *mp)
37640Sstevel@tonic-gate {
37650Sstevel@tonic-gate dl_capability_req_t *dlp;
37660Sstevel@tonic-gate dl_capability_sub_t *dlsp;
37670Sstevel@tonic-gate dl_capab_hcksum_t *dlhp;
37680Sstevel@tonic-gate offset_t off;
37690Sstevel@tonic-gate size_t len;
37700Sstevel@tonic-gate size_t size;
37710Sstevel@tonic-gate offset_t end;
37720Sstevel@tonic-gate
37730Sstevel@tonic-gate dlp = (dl_capability_req_t *)mp->b_rptr;
37740Sstevel@tonic-gate dlp->dl_primitive = DL_CAPABILITY_ACK;
37750Sstevel@tonic-gate
37760Sstevel@tonic-gate off = dlp->dl_sub_offset;
37770Sstevel@tonic-gate len = dlp->dl_sub_length;
37780Sstevel@tonic-gate
37790Sstevel@tonic-gate if (!MBLKIN(mp, off, len))
37800Sstevel@tonic-gate return (DL_BADPRIM);
37810Sstevel@tonic-gate
37820Sstevel@tonic-gate end = off + len;
37830Sstevel@tonic-gate while (off < end) {
37840Sstevel@tonic-gate dlsp = (dl_capability_sub_t *)(mp->b_rptr + off);
37850Sstevel@tonic-gate size = sizeof (dl_capability_sub_t) + dlsp->dl_length;
37860Sstevel@tonic-gate if (off + size > end)
37870Sstevel@tonic-gate return (DL_BADPRIM);
37880Sstevel@tonic-gate
37890Sstevel@tonic-gate switch (dlsp->dl_cap) {
37900Sstevel@tonic-gate case DL_CAPAB_HCKSUM:
37910Sstevel@tonic-gate dlhp = (dl_capab_hcksum_t *)&dlsp[1];
37920Sstevel@tonic-gate /* nothing useful we can do with the contents */
37930Sstevel@tonic-gate dlcapabsetqid(&(dlhp->hcksum_mid), RD(q));
37940Sstevel@tonic-gate break;
37950Sstevel@tonic-gate default:
37960Sstevel@tonic-gate break;
37970Sstevel@tonic-gate }
37980Sstevel@tonic-gate
37990Sstevel@tonic-gate off += size;
38000Sstevel@tonic-gate }
38010Sstevel@tonic-gate
38020Sstevel@tonic-gate qreply(q, mp);
38030Sstevel@tonic-gate return (GLDE_OK);
38040Sstevel@tonic-gate }
38050Sstevel@tonic-gate
38060Sstevel@tonic-gate /*
38070Sstevel@tonic-gate * Send a copy of the DL_NOTIFY_IND message <mp> to each stream that has
38080Sstevel@tonic-gate * requested the specific <notification> that the message carries AND is
38090Sstevel@tonic-gate * eligible and ready to receive the notification immediately.
38100Sstevel@tonic-gate *
38110Sstevel@tonic-gate * This routine ignores flow control. Notifications will be sent regardless.
38120Sstevel@tonic-gate *
38130Sstevel@tonic-gate * In all cases, the original message passed in is freed at the end of
38140Sstevel@tonic-gate * the routine.
38150Sstevel@tonic-gate */
38160Sstevel@tonic-gate static void
gld_notify_qs(gld_mac_info_t * macinfo,mblk_t * mp,uint32_t notification)38170Sstevel@tonic-gate gld_notify_qs(gld_mac_info_t *macinfo, mblk_t *mp, uint32_t notification)
38180Sstevel@tonic-gate {
38190Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
38200Sstevel@tonic-gate gld_vlan_t *vlan;
38210Sstevel@tonic-gate gld_t *gld;
38220Sstevel@tonic-gate mblk_t *nmp;
38230Sstevel@tonic-gate int i;
38240Sstevel@tonic-gate
38250Sstevel@tonic-gate ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
38260Sstevel@tonic-gate
38270Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
38280Sstevel@tonic-gate
38290Sstevel@tonic-gate /*
38300Sstevel@tonic-gate * Search all the streams attached to this macinfo looking
38310Sstevel@tonic-gate * for those eligible to receive the present notification.
38320Sstevel@tonic-gate */
38330Sstevel@tonic-gate for (i = 0; i < VLAN_HASHSZ; i++) {
38340Sstevel@tonic-gate for (vlan = mac_pvt->vlan_hash[i];
38350Sstevel@tonic-gate vlan != NULL; vlan = vlan->gldv_next) {
38360Sstevel@tonic-gate for (gld = vlan->gldv_str_next;
38370Sstevel@tonic-gate gld != (gld_t *)&vlan->gldv_str_next;
38380Sstevel@tonic-gate gld = gld->gld_next) {
38390Sstevel@tonic-gate ASSERT(gld->gld_qptr != NULL);
38400Sstevel@tonic-gate ASSERT(gld->gld_state == DL_IDLE ||
38410Sstevel@tonic-gate gld->gld_state == DL_UNBOUND);
38420Sstevel@tonic-gate ASSERT(gld->gld_mac_info == macinfo);
38430Sstevel@tonic-gate
38440Sstevel@tonic-gate if (gld->gld_flags & GLD_STR_CLOSING)
38450Sstevel@tonic-gate continue; /* not eligible - skip */
38460Sstevel@tonic-gate if (!(notification & gld->gld_notifications))
38470Sstevel@tonic-gate continue; /* not wanted - skip */
38480Sstevel@tonic-gate if ((nmp = dupmsg(mp)) == NULL)
38490Sstevel@tonic-gate continue; /* can't copy - skip */
38500Sstevel@tonic-gate
38510Sstevel@tonic-gate /*
38520Sstevel@tonic-gate * All OK; send dup'd notification up this
38530Sstevel@tonic-gate * stream
38540Sstevel@tonic-gate */
38550Sstevel@tonic-gate qreply(WR(gld->gld_qptr), nmp);
38560Sstevel@tonic-gate }
38570Sstevel@tonic-gate }
38580Sstevel@tonic-gate }
38590Sstevel@tonic-gate
38600Sstevel@tonic-gate /*
38610Sstevel@tonic-gate * Drop the original message block now
38620Sstevel@tonic-gate */
38630Sstevel@tonic-gate freemsg(mp);
38640Sstevel@tonic-gate }
38650Sstevel@tonic-gate
38660Sstevel@tonic-gate /*
38670Sstevel@tonic-gate * For each (understood) bit in the <notifications> argument, contruct
38680Sstevel@tonic-gate * a DL_NOTIFY_IND message and send it to the specified <q>, or to all
38690Sstevel@tonic-gate * eligible queues if <q> is NULL.
38700Sstevel@tonic-gate */
38710Sstevel@tonic-gate static void
gld_notify_ind(gld_mac_info_t * macinfo,uint32_t notifications,queue_t * q)38720Sstevel@tonic-gate gld_notify_ind(gld_mac_info_t *macinfo, uint32_t notifications, queue_t *q)
38730Sstevel@tonic-gate {
38740Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
38750Sstevel@tonic-gate dl_notify_ind_t *dlnip;
38760Sstevel@tonic-gate struct gld_stats *stats;
38770Sstevel@tonic-gate mblk_t *mp;
38780Sstevel@tonic-gate size_t size;
38790Sstevel@tonic-gate uint32_t bit;
38800Sstevel@tonic-gate
38810Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
38820Sstevel@tonic-gate
38830Sstevel@tonic-gate /*
38840Sstevel@tonic-gate * The following cases shouldn't happen, but just in case the
38850Sstevel@tonic-gate * MAC driver calls gld_linkstate() at an inappropriate time, we
38860Sstevel@tonic-gate * check anyway ...
38870Sstevel@tonic-gate */
38880Sstevel@tonic-gate if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY)) {
38890Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
38900Sstevel@tonic-gate return; /* not ready yet */
38910Sstevel@tonic-gate }
38920Sstevel@tonic-gate
38930Sstevel@tonic-gate if (macinfo->gldm_GLD_flags & GLD_UNREGISTERED) {
38940Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
38950Sstevel@tonic-gate return; /* not ready anymore */
38960Sstevel@tonic-gate }
38970Sstevel@tonic-gate
38980Sstevel@tonic-gate /*
38990Sstevel@tonic-gate * Make sure the kstats are up to date, 'cos we use some of
39000Sstevel@tonic-gate * the kstat values below, specifically the link speed ...
39010Sstevel@tonic-gate */
39020Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
39030Sstevel@tonic-gate stats = mac_pvt->statistics;
39040Sstevel@tonic-gate if (macinfo->gldm_get_stats)
39050Sstevel@tonic-gate (void) (*macinfo->gldm_get_stats)(macinfo, stats);
39060Sstevel@tonic-gate
39070Sstevel@tonic-gate for (bit = 1; notifications != 0; bit <<= 1) {
39080Sstevel@tonic-gate if ((notifications & bit) == 0)
39090Sstevel@tonic-gate continue;
39100Sstevel@tonic-gate notifications &= ~bit;
39110Sstevel@tonic-gate
39120Sstevel@tonic-gate size = DL_NOTIFY_IND_SIZE;
39130Sstevel@tonic-gate if (bit == DL_NOTE_PHYS_ADDR)
39140Sstevel@tonic-gate size += macinfo->gldm_addrlen;
39150Sstevel@tonic-gate if ((mp = allocb(size, BPRI_MED)) == NULL)
39160Sstevel@tonic-gate continue;
39170Sstevel@tonic-gate
39180Sstevel@tonic-gate mp->b_datap->db_type = M_PROTO;
39190Sstevel@tonic-gate mp->b_wptr = mp->b_rptr + size;
39200Sstevel@tonic-gate dlnip = (dl_notify_ind_t *)mp->b_rptr;
39210Sstevel@tonic-gate dlnip->dl_primitive = DL_NOTIFY_IND;
39220Sstevel@tonic-gate dlnip->dl_notification = 0;
39230Sstevel@tonic-gate dlnip->dl_data = 0;
39240Sstevel@tonic-gate dlnip->dl_addr_length = 0;
39250Sstevel@tonic-gate dlnip->dl_addr_offset = 0;
39260Sstevel@tonic-gate
39270Sstevel@tonic-gate switch (bit) {
39280Sstevel@tonic-gate case DL_NOTE_PROMISC_ON_PHYS:
39290Sstevel@tonic-gate case DL_NOTE_PROMISC_OFF_PHYS:
39300Sstevel@tonic-gate if (mac_pvt->nprom != 0)
39310Sstevel@tonic-gate dlnip->dl_notification = bit;
39320Sstevel@tonic-gate break;
39330Sstevel@tonic-gate
39340Sstevel@tonic-gate case DL_NOTE_LINK_DOWN:
39350Sstevel@tonic-gate if (macinfo->gldm_linkstate == GLD_LINKSTATE_DOWN)
39360Sstevel@tonic-gate dlnip->dl_notification = bit;
39370Sstevel@tonic-gate break;
39380Sstevel@tonic-gate
39390Sstevel@tonic-gate case DL_NOTE_LINK_UP:
39400Sstevel@tonic-gate if (macinfo->gldm_linkstate == GLD_LINKSTATE_UP)
39410Sstevel@tonic-gate dlnip->dl_notification = bit;
39420Sstevel@tonic-gate break;
39430Sstevel@tonic-gate
39440Sstevel@tonic-gate case DL_NOTE_SPEED:
39450Sstevel@tonic-gate /*
39460Sstevel@tonic-gate * Conversion required here:
39470Sstevel@tonic-gate * GLD keeps the speed in bit/s in a uint64
39480Sstevel@tonic-gate * DLPI wants it in kb/s in a uint32
39490Sstevel@tonic-gate * Fortunately this is still big enough for 10Gb/s!
39500Sstevel@tonic-gate */
39510Sstevel@tonic-gate dlnip->dl_notification = bit;
39520Sstevel@tonic-gate dlnip->dl_data = stats->glds_speed/1000ULL;
39530Sstevel@tonic-gate break;
39540Sstevel@tonic-gate
39550Sstevel@tonic-gate case DL_NOTE_PHYS_ADDR:
39560Sstevel@tonic-gate dlnip->dl_notification = bit;
39570Sstevel@tonic-gate dlnip->dl_data = DL_CURR_PHYS_ADDR;
39580Sstevel@tonic-gate dlnip->dl_addr_offset = sizeof (dl_notify_ind_t);
39590Sstevel@tonic-gate dlnip->dl_addr_length = macinfo->gldm_addrlen +
39600Sstevel@tonic-gate abs(macinfo->gldm_saplen);
39610Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
39620Sstevel@tonic-gate mac_copy(mac_pvt->curr_macaddr,
39630Sstevel@tonic-gate mp->b_rptr + sizeof (dl_notify_ind_t),
39640Sstevel@tonic-gate macinfo->gldm_addrlen);
39650Sstevel@tonic-gate break;
39660Sstevel@tonic-gate
39670Sstevel@tonic-gate default:
39680Sstevel@tonic-gate break;
39690Sstevel@tonic-gate }
39700Sstevel@tonic-gate
39710Sstevel@tonic-gate if (dlnip->dl_notification == 0)
39720Sstevel@tonic-gate freemsg(mp);
39730Sstevel@tonic-gate else if (q != NULL)
39740Sstevel@tonic-gate qreply(q, mp);
39750Sstevel@tonic-gate else
39760Sstevel@tonic-gate gld_notify_qs(macinfo, mp, bit);
39770Sstevel@tonic-gate }
39780Sstevel@tonic-gate
39790Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
39800Sstevel@tonic-gate }
39810Sstevel@tonic-gate
39820Sstevel@tonic-gate /*
39830Sstevel@tonic-gate * gld_notify_req - handle a DL_NOTIFY_REQ message
39840Sstevel@tonic-gate */
39850Sstevel@tonic-gate static int
gld_notify_req(queue_t * q,mblk_t * mp)39860Sstevel@tonic-gate gld_notify_req(queue_t *q, mblk_t *mp)
39870Sstevel@tonic-gate {
39880Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
39890Sstevel@tonic-gate gld_mac_info_t *macinfo;
39900Sstevel@tonic-gate gld_mac_pvt_t *pvt;
39910Sstevel@tonic-gate dl_notify_req_t *dlnrp;
39920Sstevel@tonic-gate dl_notify_ack_t *dlnap;
39930Sstevel@tonic-gate
39940Sstevel@tonic-gate ASSERT(gld != NULL);
39950Sstevel@tonic-gate ASSERT(gld->gld_qptr == RD(q));
39960Sstevel@tonic-gate
39970Sstevel@tonic-gate dlnrp = (dl_notify_req_t *)mp->b_rptr;
39980Sstevel@tonic-gate
39990Sstevel@tonic-gate #ifdef GLD_DEBUG
40000Sstevel@tonic-gate if (gld_debug & GLDTRACE)
40010Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_notify_req(%p %p)",
40025903Ssowmini (void *)q, (void *)mp);
40030Sstevel@tonic-gate #endif
40040Sstevel@tonic-gate
40050Sstevel@tonic-gate if (gld->gld_state == DL_UNATTACHED) {
40060Sstevel@tonic-gate #ifdef GLD_DEBUG
40070Sstevel@tonic-gate if (gld_debug & GLDERRS)
40080Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_notify_req: wrong state (%d)",
40095903Ssowmini gld->gld_state);
40100Sstevel@tonic-gate #endif
40110Sstevel@tonic-gate return (DL_OUTSTATE);
40120Sstevel@tonic-gate }
40130Sstevel@tonic-gate
40140Sstevel@tonic-gate /*
40150Sstevel@tonic-gate * Remember what notifications are required by this stream
40160Sstevel@tonic-gate */
40170Sstevel@tonic-gate macinfo = gld->gld_mac_info;
40180Sstevel@tonic-gate pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
40190Sstevel@tonic-gate
40200Sstevel@tonic-gate gld->gld_notifications = dlnrp->dl_notifications & pvt->notifications;
40210Sstevel@tonic-gate
40220Sstevel@tonic-gate /*
40230Sstevel@tonic-gate * The return DL_NOTIFY_ACK carries the bitset of notifications
40240Sstevel@tonic-gate * that this driver can provide, independently of which ones have
40250Sstevel@tonic-gate * previously been or are now being requested.
40260Sstevel@tonic-gate */
40270Sstevel@tonic-gate if ((mp = mexchange(q, mp, sizeof (dl_notify_ack_t), M_PCPROTO,
40280Sstevel@tonic-gate DL_NOTIFY_ACK)) == NULL)
40290Sstevel@tonic-gate return (DL_SYSERR);
40300Sstevel@tonic-gate
40310Sstevel@tonic-gate dlnap = (dl_notify_ack_t *)mp->b_rptr;
40320Sstevel@tonic-gate dlnap->dl_notifications = pvt->notifications;
40330Sstevel@tonic-gate qreply(q, mp);
40340Sstevel@tonic-gate
40350Sstevel@tonic-gate /*
40360Sstevel@tonic-gate * A side effect of a DL_NOTIFY_REQ is that after the DL_NOTIFY_ACK
40370Sstevel@tonic-gate * reply, the the requestor gets zero or more DL_NOTIFY_IND messages
40380Sstevel@tonic-gate * that provide the current status.
40390Sstevel@tonic-gate */
40400Sstevel@tonic-gate gld_notify_ind(macinfo, gld->gld_notifications, q);
40410Sstevel@tonic-gate
40420Sstevel@tonic-gate return (GLDE_OK);
40430Sstevel@tonic-gate }
40440Sstevel@tonic-gate
40450Sstevel@tonic-gate /*
40460Sstevel@tonic-gate * gld_linkstate()
40470Sstevel@tonic-gate * Called by driver to tell GLD the state of the physical link.
40480Sstevel@tonic-gate * As a side effect, sends a DL_NOTE_LINK_UP or DL_NOTE_LINK_DOWN
40490Sstevel@tonic-gate * notification to each client that has previously requested such
40500Sstevel@tonic-gate * notifications
40510Sstevel@tonic-gate */
40520Sstevel@tonic-gate void
gld_linkstate(gld_mac_info_t * macinfo,int32_t newstate)40530Sstevel@tonic-gate gld_linkstate(gld_mac_info_t *macinfo, int32_t newstate)
40540Sstevel@tonic-gate {
40550Sstevel@tonic-gate uint32_t notification;
40560Sstevel@tonic-gate
40570Sstevel@tonic-gate switch (newstate) {
40580Sstevel@tonic-gate default:
40590Sstevel@tonic-gate return;
40600Sstevel@tonic-gate
40610Sstevel@tonic-gate case GLD_LINKSTATE_DOWN:
40620Sstevel@tonic-gate notification = DL_NOTE_LINK_DOWN;
40630Sstevel@tonic-gate break;
40640Sstevel@tonic-gate
40650Sstevel@tonic-gate case GLD_LINKSTATE_UP:
40660Sstevel@tonic-gate notification = DL_NOTE_LINK_UP | DL_NOTE_SPEED;
40670Sstevel@tonic-gate break;
40680Sstevel@tonic-gate
40690Sstevel@tonic-gate case GLD_LINKSTATE_UNKNOWN:
40700Sstevel@tonic-gate notification = 0;
40710Sstevel@tonic-gate break;
40720Sstevel@tonic-gate }
40730Sstevel@tonic-gate
40740Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
40750Sstevel@tonic-gate if (macinfo->gldm_linkstate == newstate)
40760Sstevel@tonic-gate notification = 0;
40770Sstevel@tonic-gate else
40780Sstevel@tonic-gate macinfo->gldm_linkstate = newstate;
40790Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
40800Sstevel@tonic-gate
40810Sstevel@tonic-gate if (notification)
40820Sstevel@tonic-gate gld_notify_ind(macinfo, notification, NULL);
40830Sstevel@tonic-gate }
40840Sstevel@tonic-gate
40850Sstevel@tonic-gate /*
40860Sstevel@tonic-gate * gld_udqos - set the current QoS parameters (priority only at the moment).
40870Sstevel@tonic-gate */
40880Sstevel@tonic-gate static int
gld_udqos(queue_t * q,mblk_t * mp)40890Sstevel@tonic-gate gld_udqos(queue_t *q, mblk_t *mp)
40900Sstevel@tonic-gate {
40910Sstevel@tonic-gate dl_udqos_req_t *dlp;
40920Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
40930Sstevel@tonic-gate int off;
40940Sstevel@tonic-gate int len;
40950Sstevel@tonic-gate dl_qos_cl_sel1_t *selp;
40960Sstevel@tonic-gate
40970Sstevel@tonic-gate ASSERT(gld);
40980Sstevel@tonic-gate ASSERT(gld->gld_qptr == RD(q));
40990Sstevel@tonic-gate
41000Sstevel@tonic-gate #ifdef GLD_DEBUG
41010Sstevel@tonic-gate if (gld_debug & GLDTRACE)
41020Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_udqos(%p %p)", (void *)q, (void *)mp);
41030Sstevel@tonic-gate #endif
41040Sstevel@tonic-gate
41050Sstevel@tonic-gate if (gld->gld_state != DL_IDLE) {
41060Sstevel@tonic-gate #ifdef GLD_DEBUG
41070Sstevel@tonic-gate if (gld_debug & GLDERRS)
41080Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_udqos: wrong state (%d)",
41090Sstevel@tonic-gate gld->gld_state);
41100Sstevel@tonic-gate #endif
41110Sstevel@tonic-gate return (DL_OUTSTATE);
41120Sstevel@tonic-gate }
41130Sstevel@tonic-gate
41140Sstevel@tonic-gate dlp = (dl_udqos_req_t *)mp->b_rptr;
41150Sstevel@tonic-gate off = dlp->dl_qos_offset;
41160Sstevel@tonic-gate len = dlp->dl_qos_length;
41170Sstevel@tonic-gate
41180Sstevel@tonic-gate if (len != sizeof (dl_qos_cl_sel1_t) || !MBLKIN(mp, off, len))
41190Sstevel@tonic-gate return (DL_BADQOSTYPE);
41200Sstevel@tonic-gate
41210Sstevel@tonic-gate selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + off);
41220Sstevel@tonic-gate if (selp->dl_qos_type != DL_QOS_CL_SEL1)
41230Sstevel@tonic-gate return (DL_BADQOSTYPE);
41240Sstevel@tonic-gate
41250Sstevel@tonic-gate if (selp->dl_trans_delay != 0 &&
41260Sstevel@tonic-gate selp->dl_trans_delay != DL_QOS_DONT_CARE)
41270Sstevel@tonic-gate return (DL_BADQOSPARAM);
41280Sstevel@tonic-gate if (selp->dl_protection != 0 &&
41290Sstevel@tonic-gate selp->dl_protection != DL_QOS_DONT_CARE)
41300Sstevel@tonic-gate return (DL_BADQOSPARAM);
41310Sstevel@tonic-gate if (selp->dl_residual_error != 0 &&
41320Sstevel@tonic-gate selp->dl_residual_error != DL_QOS_DONT_CARE)
41330Sstevel@tonic-gate return (DL_BADQOSPARAM);
41340Sstevel@tonic-gate if (selp->dl_priority < 0 || selp->dl_priority > 7)
41350Sstevel@tonic-gate return (DL_BADQOSPARAM);
41360Sstevel@tonic-gate
41370Sstevel@tonic-gate gld->gld_upri = selp->dl_priority;
41380Sstevel@tonic-gate
41390Sstevel@tonic-gate dlokack(q, mp, DL_UDQOS_REQ);
41400Sstevel@tonic-gate return (GLDE_OK);
41410Sstevel@tonic-gate }
41420Sstevel@tonic-gate
41430Sstevel@tonic-gate static mblk_t *
gld_bindack(queue_t * q,mblk_t * mp)41440Sstevel@tonic-gate gld_bindack(queue_t *q, mblk_t *mp)
41450Sstevel@tonic-gate {
41460Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
41470Sstevel@tonic-gate gld_mac_info_t *macinfo = gld->gld_mac_info;
41480Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
41490Sstevel@tonic-gate dl_bind_ack_t *dlp;
41500Sstevel@tonic-gate size_t size;
41510Sstevel@tonic-gate t_uscalar_t addrlen;
41520Sstevel@tonic-gate uchar_t *sapp;
41530Sstevel@tonic-gate
41540Sstevel@tonic-gate addrlen = macinfo->gldm_addrlen + abs(macinfo->gldm_saplen);
41550Sstevel@tonic-gate size = sizeof (dl_bind_ack_t) + addrlen;
41560Sstevel@tonic-gate if ((mp = mexchange(q, mp, size, M_PCPROTO, DL_BIND_ACK)) == NULL)
41570Sstevel@tonic-gate return (NULL);
41580Sstevel@tonic-gate
41590Sstevel@tonic-gate dlp = (dl_bind_ack_t *)mp->b_rptr;
41600Sstevel@tonic-gate dlp->dl_sap = gld->gld_sap;
41610Sstevel@tonic-gate dlp->dl_addr_length = addrlen;
41620Sstevel@tonic-gate dlp->dl_addr_offset = sizeof (dl_bind_ack_t);
41630Sstevel@tonic-gate dlp->dl_max_conind = 0;
41640Sstevel@tonic-gate dlp->dl_xidtest_flg = 0;
41650Sstevel@tonic-gate
41660Sstevel@tonic-gate mac_copy(mac_pvt->curr_macaddr, (uchar_t *)&dlp[1],
41670Sstevel@tonic-gate macinfo->gldm_addrlen);
41680Sstevel@tonic-gate sapp = mp->b_rptr + dlp->dl_addr_offset + macinfo->gldm_addrlen;
41690Sstevel@tonic-gate *(ushort_t *)sapp = gld->gld_sap;
41700Sstevel@tonic-gate
41710Sstevel@tonic-gate return (mp);
41720Sstevel@tonic-gate }
41730Sstevel@tonic-gate
41740Sstevel@tonic-gate /*
41750Sstevel@tonic-gate * gld_bind - determine if a SAP is already allocated and whether it is legal
41760Sstevel@tonic-gate * to do the bind at this time
41770Sstevel@tonic-gate */
41780Sstevel@tonic-gate static int
gld_bind(queue_t * q,mblk_t * mp)41790Sstevel@tonic-gate gld_bind(queue_t *q, mblk_t *mp)
41800Sstevel@tonic-gate {
41810Sstevel@tonic-gate ulong_t sap;
41820Sstevel@tonic-gate dl_bind_req_t *dlp;
41830Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
41840Sstevel@tonic-gate gld_mac_info_t *macinfo = gld->gld_mac_info;
41850Sstevel@tonic-gate
41860Sstevel@tonic-gate ASSERT(gld);
41870Sstevel@tonic-gate ASSERT(gld->gld_qptr == RD(q));
41880Sstevel@tonic-gate
41890Sstevel@tonic-gate #ifdef GLD_DEBUG
41900Sstevel@tonic-gate if (gld_debug & GLDTRACE)
41910Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_bind(%p %p)", (void *)q, (void *)mp);
41920Sstevel@tonic-gate #endif
41930Sstevel@tonic-gate
41940Sstevel@tonic-gate dlp = (dl_bind_req_t *)mp->b_rptr;
41950Sstevel@tonic-gate sap = dlp->dl_sap;
41960Sstevel@tonic-gate
41970Sstevel@tonic-gate #ifdef GLD_DEBUG
41980Sstevel@tonic-gate if (gld_debug & GLDPROT)
41990Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_bind: lsap=%lx", sap);
42000Sstevel@tonic-gate #endif
42010Sstevel@tonic-gate
42020Sstevel@tonic-gate if (gld->gld_state != DL_UNBOUND) {
42030Sstevel@tonic-gate #ifdef GLD_DEBUG
42040Sstevel@tonic-gate if (gld_debug & GLDERRS)
42050Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_bind: bound or not attached (%d)",
42065903Ssowmini gld->gld_state);
42070Sstevel@tonic-gate #endif
42080Sstevel@tonic-gate return (DL_OUTSTATE);
42090Sstevel@tonic-gate }
42100Sstevel@tonic-gate ASSERT(macinfo);
42110Sstevel@tonic-gate
42120Sstevel@tonic-gate if (dlp->dl_service_mode != DL_CLDLS) {
42130Sstevel@tonic-gate return (DL_UNSUPPORTED);
42140Sstevel@tonic-gate }
42150Sstevel@tonic-gate if (dlp->dl_xidtest_flg & (DL_AUTO_XID | DL_AUTO_TEST)) {
42160Sstevel@tonic-gate return (DL_NOAUTO);
42170Sstevel@tonic-gate }
42180Sstevel@tonic-gate
42190Sstevel@tonic-gate /*
42200Sstevel@tonic-gate * Check sap validity and decide whether this stream accepts
42210Sstevel@tonic-gate * IEEE 802.2 (LLC) packets.
42220Sstevel@tonic-gate */
42230Sstevel@tonic-gate if (sap > ETHERTYPE_MAX)
42240Sstevel@tonic-gate return (DL_BADSAP);
42250Sstevel@tonic-gate
42260Sstevel@tonic-gate /*
42270Sstevel@tonic-gate * Decide whether the SAP value selects EtherType encoding/decoding.
42280Sstevel@tonic-gate * For compatibility with monolithic ethernet drivers, the range of
42290Sstevel@tonic-gate * SAP values is different for DL_ETHER media.
42300Sstevel@tonic-gate */
42310Sstevel@tonic-gate switch (macinfo->gldm_type) {
42320Sstevel@tonic-gate case DL_ETHER:
42330Sstevel@tonic-gate gld->gld_ethertype = (sap > ETHERMTU);
42340Sstevel@tonic-gate break;
42350Sstevel@tonic-gate default:
42360Sstevel@tonic-gate gld->gld_ethertype = (sap > GLD_MAX_802_SAP);
42370Sstevel@tonic-gate break;
42380Sstevel@tonic-gate }
42390Sstevel@tonic-gate
42400Sstevel@tonic-gate /* if we get to here, then the SAP is legal enough */
42410Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
42420Sstevel@tonic-gate gld->gld_state = DL_IDLE; /* bound and ready */
42430Sstevel@tonic-gate gld->gld_sap = sap;
42442760Sdg199075 if ((macinfo->gldm_type == DL_ETHER) && (sap == ETHERTYPE_VLAN))
42452760Sdg199075 ((gld_vlan_t *)gld->gld_vlan)->gldv_nvlan_sap++;
42460Sstevel@tonic-gate gld_set_ipq(gld);
42470Sstevel@tonic-gate
42480Sstevel@tonic-gate #ifdef GLD_DEBUG
42490Sstevel@tonic-gate if (gld_debug & GLDPROT)
42500Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_bind: ok - sap = %d", gld->gld_sap);
42510Sstevel@tonic-gate #endif
42520Sstevel@tonic-gate
42530Sstevel@tonic-gate /* ACK the BIND */
42540Sstevel@tonic-gate mp = gld_bindack(q, mp);
42550Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
42560Sstevel@tonic-gate
42570Sstevel@tonic-gate if (mp != NULL) {
42580Sstevel@tonic-gate qreply(q, mp);
42590Sstevel@tonic-gate return (GLDE_OK);
42600Sstevel@tonic-gate }
42610Sstevel@tonic-gate
42620Sstevel@tonic-gate return (DL_SYSERR);
42630Sstevel@tonic-gate }
42640Sstevel@tonic-gate
42650Sstevel@tonic-gate /*
42660Sstevel@tonic-gate * gld_unbind - perform an unbind of an LSAP or ether type on the stream.
42670Sstevel@tonic-gate * The stream is still open and can be re-bound.
42680Sstevel@tonic-gate */
42690Sstevel@tonic-gate static int
gld_unbind(queue_t * q,mblk_t * mp)42700Sstevel@tonic-gate gld_unbind(queue_t *q, mblk_t *mp)
42710Sstevel@tonic-gate {
42720Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
42730Sstevel@tonic-gate gld_mac_info_t *macinfo = gld->gld_mac_info;
42740Sstevel@tonic-gate
42750Sstevel@tonic-gate ASSERT(gld);
42760Sstevel@tonic-gate
42770Sstevel@tonic-gate #ifdef GLD_DEBUG
42780Sstevel@tonic-gate if (gld_debug & GLDTRACE)
42790Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_unbind(%p %p)", (void *)q, (void *)mp);
42800Sstevel@tonic-gate #endif
42810Sstevel@tonic-gate
42820Sstevel@tonic-gate if (gld->gld_state != DL_IDLE) {
42830Sstevel@tonic-gate #ifdef GLD_DEBUG
42840Sstevel@tonic-gate if (gld_debug & GLDERRS)
42850Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_unbind: wrong state (%d)",
42865903Ssowmini gld->gld_state);
42870Sstevel@tonic-gate #endif
42880Sstevel@tonic-gate return (DL_OUTSTATE);
42890Sstevel@tonic-gate }
42900Sstevel@tonic-gate ASSERT(macinfo);
42910Sstevel@tonic-gate
42920Sstevel@tonic-gate /*
42930Sstevel@tonic-gate * Avoid unbinding (DL_UNBIND_REQ) while FAST/RAW is inside wput.
42940Sstevel@tonic-gate * See comments above gld_start().
42950Sstevel@tonic-gate */
42960Sstevel@tonic-gate gld->gld_in_unbind = B_TRUE; /* disallow wput=>start */
42970Sstevel@tonic-gate membar_enter();
42980Sstevel@tonic-gate if (gld->gld_wput_count != 0) {
42990Sstevel@tonic-gate gld->gld_in_unbind = B_FALSE;
43000Sstevel@tonic-gate ASSERT(mp); /* we didn't come from close */
43010Sstevel@tonic-gate #ifdef GLD_DEBUG
43020Sstevel@tonic-gate if (gld_debug & GLDETRACE)
43030Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_unbind: defer for wput");
43040Sstevel@tonic-gate #endif
43050Sstevel@tonic-gate (void) putbq(q, mp);
43060Sstevel@tonic-gate qenable(q); /* try again soon */
43070Sstevel@tonic-gate return (GLDE_RETRY);
43080Sstevel@tonic-gate }
43090Sstevel@tonic-gate
43100Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
43112760Sdg199075 if ((macinfo->gldm_type == DL_ETHER) &&
43122760Sdg199075 (gld->gld_sap == ETHERTYPE_VLAN)) {
43132760Sdg199075 ((gld_vlan_t *)gld->gld_vlan)->gldv_nvlan_sap--;
43142760Sdg199075 }
43150Sstevel@tonic-gate gld->gld_state = DL_UNBOUND;
43160Sstevel@tonic-gate gld->gld_sap = 0;
43170Sstevel@tonic-gate gld_set_ipq(gld);
43180Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
43190Sstevel@tonic-gate
43200Sstevel@tonic-gate membar_exit();
43210Sstevel@tonic-gate gld->gld_in_unbind = B_FALSE;
43220Sstevel@tonic-gate
43230Sstevel@tonic-gate /* mp is NULL if we came from close */
43240Sstevel@tonic-gate if (mp) {
43250Sstevel@tonic-gate gld_flushqueue(q); /* flush the queues */
43260Sstevel@tonic-gate dlokack(q, mp, DL_UNBIND_REQ);
43270Sstevel@tonic-gate }
43280Sstevel@tonic-gate return (GLDE_OK);
43290Sstevel@tonic-gate }
43300Sstevel@tonic-gate
43310Sstevel@tonic-gate /*
43320Sstevel@tonic-gate * gld_inforeq - generate the response to an info request
43330Sstevel@tonic-gate */
43340Sstevel@tonic-gate static int
gld_inforeq(queue_t * q,mblk_t * mp)43350Sstevel@tonic-gate gld_inforeq(queue_t *q, mblk_t *mp)
43360Sstevel@tonic-gate {
43370Sstevel@tonic-gate gld_t *gld;
43380Sstevel@tonic-gate dl_info_ack_t *dlp;
43390Sstevel@tonic-gate int bufsize;
43400Sstevel@tonic-gate glddev_t *glddev;
43410Sstevel@tonic-gate gld_mac_info_t *macinfo;
43420Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
43430Sstevel@tonic-gate int sel_offset = 0;
43440Sstevel@tonic-gate int range_offset = 0;
43450Sstevel@tonic-gate int addr_offset;
43460Sstevel@tonic-gate int addr_length;
43470Sstevel@tonic-gate int sap_length;
43480Sstevel@tonic-gate int brdcst_offset;
43490Sstevel@tonic-gate int brdcst_length;
43500Sstevel@tonic-gate uchar_t *sapp;
43510Sstevel@tonic-gate
43520Sstevel@tonic-gate #ifdef GLD_DEBUG
43530Sstevel@tonic-gate if (gld_debug & GLDTRACE)
43540Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_inforeq(%p %p)", (void *)q, (void *)mp);
43550Sstevel@tonic-gate #endif
43560Sstevel@tonic-gate gld = (gld_t *)q->q_ptr;
43570Sstevel@tonic-gate ASSERT(gld);
43580Sstevel@tonic-gate glddev = gld->gld_device;
43590Sstevel@tonic-gate ASSERT(glddev);
43600Sstevel@tonic-gate
43610Sstevel@tonic-gate if (gld->gld_state == DL_IDLE || gld->gld_state == DL_UNBOUND) {
43620Sstevel@tonic-gate macinfo = gld->gld_mac_info;
43630Sstevel@tonic-gate ASSERT(macinfo != NULL);
43640Sstevel@tonic-gate
43650Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
43660Sstevel@tonic-gate
43670Sstevel@tonic-gate addr_length = macinfo->gldm_addrlen;
43680Sstevel@tonic-gate sap_length = macinfo->gldm_saplen;
43690Sstevel@tonic-gate brdcst_length = macinfo->gldm_addrlen;
43700Sstevel@tonic-gate } else {
43710Sstevel@tonic-gate addr_length = glddev->gld_addrlen;
43720Sstevel@tonic-gate sap_length = glddev->gld_saplen;
43730Sstevel@tonic-gate brdcst_length = glddev->gld_addrlen;
43740Sstevel@tonic-gate }
43750Sstevel@tonic-gate
43760Sstevel@tonic-gate bufsize = sizeof (dl_info_ack_t);
43770Sstevel@tonic-gate
43780Sstevel@tonic-gate addr_offset = bufsize;
43790Sstevel@tonic-gate bufsize += addr_length;
43800Sstevel@tonic-gate bufsize += abs(sap_length);
43810Sstevel@tonic-gate
43820Sstevel@tonic-gate brdcst_offset = bufsize;
43830Sstevel@tonic-gate bufsize += brdcst_length;
43840Sstevel@tonic-gate
43852760Sdg199075 if (((gld_vlan_t *)gld->gld_vlan) != NULL) {
43860Sstevel@tonic-gate sel_offset = P2ROUNDUP(bufsize, sizeof (int64_t));
43870Sstevel@tonic-gate bufsize = sel_offset + sizeof (dl_qos_cl_sel1_t);
43880Sstevel@tonic-gate
43890Sstevel@tonic-gate range_offset = P2ROUNDUP(bufsize, sizeof (int64_t));
43900Sstevel@tonic-gate bufsize = range_offset + sizeof (dl_qos_cl_range1_t);
43910Sstevel@tonic-gate }
43920Sstevel@tonic-gate
43930Sstevel@tonic-gate if ((mp = mexchange(q, mp, bufsize, M_PCPROTO, DL_INFO_ACK)) == NULL)
43940Sstevel@tonic-gate return (GLDE_OK); /* nothing more to be done */
43950Sstevel@tonic-gate
43960Sstevel@tonic-gate bzero(mp->b_rptr, bufsize);
43970Sstevel@tonic-gate
43980Sstevel@tonic-gate dlp = (dl_info_ack_t *)mp->b_rptr;
43990Sstevel@tonic-gate dlp->dl_primitive = DL_INFO_ACK;
44000Sstevel@tonic-gate dlp->dl_version = DL_VERSION_2;
44010Sstevel@tonic-gate dlp->dl_service_mode = DL_CLDLS;
44020Sstevel@tonic-gate dlp->dl_current_state = gld->gld_state;
44030Sstevel@tonic-gate dlp->dl_provider_style = gld->gld_style;
44040Sstevel@tonic-gate
44050Sstevel@tonic-gate if (sel_offset != 0) {
44060Sstevel@tonic-gate dl_qos_cl_sel1_t *selp;
44070Sstevel@tonic-gate dl_qos_cl_range1_t *rangep;
44080Sstevel@tonic-gate
44090Sstevel@tonic-gate ASSERT(range_offset != 0);
44100Sstevel@tonic-gate
44110Sstevel@tonic-gate dlp->dl_qos_offset = sel_offset;
44120Sstevel@tonic-gate dlp->dl_qos_length = sizeof (dl_qos_cl_sel1_t);
44130Sstevel@tonic-gate dlp->dl_qos_range_offset = range_offset;
44140Sstevel@tonic-gate dlp->dl_qos_range_length = sizeof (dl_qos_cl_range1_t);
44150Sstevel@tonic-gate
44160Sstevel@tonic-gate selp = (dl_qos_cl_sel1_t *)(mp->b_rptr + sel_offset);
44170Sstevel@tonic-gate selp->dl_qos_type = DL_QOS_CL_SEL1;
44180Sstevel@tonic-gate selp->dl_priority = gld->gld_upri;
44190Sstevel@tonic-gate
44200Sstevel@tonic-gate rangep = (dl_qos_cl_range1_t *)(mp->b_rptr + range_offset);
44210Sstevel@tonic-gate rangep->dl_qos_type = DL_QOS_CL_RANGE1;
44220Sstevel@tonic-gate rangep->dl_priority.dl_min = 0;
44230Sstevel@tonic-gate rangep->dl_priority.dl_max = 7;
44240Sstevel@tonic-gate }
44250Sstevel@tonic-gate
44260Sstevel@tonic-gate if (gld->gld_state == DL_IDLE || gld->gld_state == DL_UNBOUND) {
44270Sstevel@tonic-gate dlp->dl_min_sdu = macinfo->gldm_minpkt;
44280Sstevel@tonic-gate dlp->dl_max_sdu = macinfo->gldm_maxpkt;
44290Sstevel@tonic-gate dlp->dl_mac_type = macinfo->gldm_type;
44300Sstevel@tonic-gate dlp->dl_addr_length = addr_length + abs(sap_length);
44310Sstevel@tonic-gate dlp->dl_sap_length = sap_length;
44320Sstevel@tonic-gate
44330Sstevel@tonic-gate if (gld->gld_state == DL_IDLE) {
44340Sstevel@tonic-gate /*
44350Sstevel@tonic-gate * If we are bound to a non-LLC SAP on any medium
44360Sstevel@tonic-gate * other than Ethernet, then we need room for a
44370Sstevel@tonic-gate * SNAP header. So we have to adjust the MTU size
44380Sstevel@tonic-gate * accordingly. XXX I suppose this should be done
44390Sstevel@tonic-gate * in gldutil.c, but it seems likely that this will
44400Sstevel@tonic-gate * always be true for everything GLD supports but
44410Sstevel@tonic-gate * Ethernet. Check this if you add another medium.
44420Sstevel@tonic-gate */
44430Sstevel@tonic-gate if ((macinfo->gldm_type == DL_TPR ||
44440Sstevel@tonic-gate macinfo->gldm_type == DL_FDDI) &&
44450Sstevel@tonic-gate gld->gld_ethertype)
44460Sstevel@tonic-gate dlp->dl_max_sdu -= LLC_SNAP_HDR_LEN;
44470Sstevel@tonic-gate
44480Sstevel@tonic-gate /* copy macaddr and sap */
44490Sstevel@tonic-gate dlp->dl_addr_offset = addr_offset;
44500Sstevel@tonic-gate
44510Sstevel@tonic-gate mac_copy(mac_pvt->curr_macaddr, mp->b_rptr +
44520Sstevel@tonic-gate addr_offset, macinfo->gldm_addrlen);
44530Sstevel@tonic-gate sapp = mp->b_rptr + addr_offset +
44540Sstevel@tonic-gate macinfo->gldm_addrlen;
44550Sstevel@tonic-gate *(ushort_t *)sapp = gld->gld_sap;
44560Sstevel@tonic-gate } else {
44570Sstevel@tonic-gate dlp->dl_addr_offset = 0;
44580Sstevel@tonic-gate }
44590Sstevel@tonic-gate
44600Sstevel@tonic-gate /* copy broadcast addr */
44610Sstevel@tonic-gate dlp->dl_brdcst_addr_length = macinfo->gldm_addrlen;
44620Sstevel@tonic-gate dlp->dl_brdcst_addr_offset = brdcst_offset;
44630Sstevel@tonic-gate mac_copy((caddr_t)macinfo->gldm_broadcast_addr,
44640Sstevel@tonic-gate mp->b_rptr + brdcst_offset, brdcst_length);
44650Sstevel@tonic-gate } else {
44660Sstevel@tonic-gate /*
44670Sstevel@tonic-gate * No PPA is attached.
44680Sstevel@tonic-gate * The best we can do is use the values provided
44690Sstevel@tonic-gate * by the first mac that called gld_register.
44700Sstevel@tonic-gate */
44710Sstevel@tonic-gate dlp->dl_min_sdu = glddev->gld_minsdu;
44720Sstevel@tonic-gate dlp->dl_max_sdu = glddev->gld_maxsdu;
44730Sstevel@tonic-gate dlp->dl_mac_type = glddev->gld_type;
44740Sstevel@tonic-gate dlp->dl_addr_length = addr_length + abs(sap_length);
44750Sstevel@tonic-gate dlp->dl_sap_length = sap_length;
44760Sstevel@tonic-gate dlp->dl_addr_offset = 0;
44770Sstevel@tonic-gate dlp->dl_brdcst_addr_offset = brdcst_offset;
44780Sstevel@tonic-gate dlp->dl_brdcst_addr_length = brdcst_length;
44790Sstevel@tonic-gate mac_copy((caddr_t)glddev->gld_broadcast,
44800Sstevel@tonic-gate mp->b_rptr + brdcst_offset, brdcst_length);
44810Sstevel@tonic-gate }
44820Sstevel@tonic-gate qreply(q, mp);
44830Sstevel@tonic-gate return (GLDE_OK);
44840Sstevel@tonic-gate }
44850Sstevel@tonic-gate
44860Sstevel@tonic-gate /*
44870Sstevel@tonic-gate * gld_unitdata (q, mp)
44880Sstevel@tonic-gate * send a datagram. Destination address/lsap is in M_PROTO
44890Sstevel@tonic-gate * message (first mblock), data is in remainder of message.
44900Sstevel@tonic-gate *
44910Sstevel@tonic-gate */
44920Sstevel@tonic-gate static int
gld_unitdata(queue_t * q,mblk_t * mp)44930Sstevel@tonic-gate gld_unitdata(queue_t *q, mblk_t *mp)
44940Sstevel@tonic-gate {
44950Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
44960Sstevel@tonic-gate dl_unitdata_req_t *dlp = (dl_unitdata_req_t *)mp->b_rptr;
44970Sstevel@tonic-gate gld_mac_info_t *macinfo = gld->gld_mac_info;
44980Sstevel@tonic-gate size_t msglen;
44990Sstevel@tonic-gate mblk_t *nmp;
45000Sstevel@tonic-gate gld_interface_t *ifp;
45010Sstevel@tonic-gate uint32_t start;
45020Sstevel@tonic-gate uint32_t stuff;
45030Sstevel@tonic-gate uint32_t end;
45040Sstevel@tonic-gate uint32_t value;
45050Sstevel@tonic-gate uint32_t flags;
45060Sstevel@tonic-gate uint32_t upri;
45070Sstevel@tonic-gate
45080Sstevel@tonic-gate #ifdef GLD_DEBUG
45090Sstevel@tonic-gate if (gld_debug & GLDTRACE)
45100Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_unitdata(%p %p)", (void *)q, (void *)mp);
45110Sstevel@tonic-gate #endif
45120Sstevel@tonic-gate
45130Sstevel@tonic-gate if (gld->gld_state != DL_IDLE) {
45140Sstevel@tonic-gate #ifdef GLD_DEBUG
45150Sstevel@tonic-gate if (gld_debug & GLDERRS)
45160Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_unitdata: wrong state (%d)",
45175903Ssowmini gld->gld_state);
45180Sstevel@tonic-gate #endif
45190Sstevel@tonic-gate dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
45200Sstevel@tonic-gate dlp->dl_dest_addr_length, DL_OUTSTATE, 0);
45210Sstevel@tonic-gate return (GLDE_OK);
45220Sstevel@tonic-gate }
45230Sstevel@tonic-gate ASSERT(macinfo != NULL);
45240Sstevel@tonic-gate
45250Sstevel@tonic-gate if (!MBLKIN(mp, dlp->dl_dest_addr_offset, dlp->dl_dest_addr_length) ||
45260Sstevel@tonic-gate dlp->dl_dest_addr_length !=
45270Sstevel@tonic-gate macinfo->gldm_addrlen + abs(macinfo->gldm_saplen)) {
45280Sstevel@tonic-gate dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
45290Sstevel@tonic-gate dlp->dl_dest_addr_length, DL_BADADDR, 0);
45300Sstevel@tonic-gate return (GLDE_OK);
45310Sstevel@tonic-gate }
45320Sstevel@tonic-gate
45330Sstevel@tonic-gate upri = dlp->dl_priority.dl_max;
45340Sstevel@tonic-gate
45350Sstevel@tonic-gate msglen = msgdsize(mp);
45360Sstevel@tonic-gate if (msglen == 0 || msglen > macinfo->gldm_maxpkt) {
45370Sstevel@tonic-gate #ifdef GLD_DEBUG
45380Sstevel@tonic-gate if (gld_debug & GLDERRS)
45390Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_unitdata: bad msglen (%d)",
45405903Ssowmini (int)msglen);
45410Sstevel@tonic-gate #endif
45420Sstevel@tonic-gate dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
45430Sstevel@tonic-gate dlp->dl_dest_addr_length, DL_BADDATA, 0);
45440Sstevel@tonic-gate return (GLDE_OK);
45450Sstevel@tonic-gate }
45460Sstevel@tonic-gate
45470Sstevel@tonic-gate ASSERT(mp->b_cont != NULL); /* because msgdsize(mp) is nonzero */
45480Sstevel@tonic-gate
45490Sstevel@tonic-gate ifp = ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->interfacep;
45500Sstevel@tonic-gate
45510Sstevel@tonic-gate /* grab any checksum information that may be present */
45520Sstevel@tonic-gate hcksum_retrieve(mp->b_cont, NULL, NULL, &start, &stuff, &end,
45530Sstevel@tonic-gate &value, &flags);
45540Sstevel@tonic-gate
45550Sstevel@tonic-gate /*
45560Sstevel@tonic-gate * Prepend a valid header for transmission
45570Sstevel@tonic-gate */
45580Sstevel@tonic-gate if ((nmp = (*ifp->mkunitdata)(gld, mp)) == NULL) {
45590Sstevel@tonic-gate #ifdef GLD_DEBUG
45600Sstevel@tonic-gate if (gld_debug & GLDERRS)
45610Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_unitdata: mkunitdata failed.");
45620Sstevel@tonic-gate #endif
45630Sstevel@tonic-gate dluderrorind(q, mp, mp->b_rptr + dlp->dl_dest_addr_offset,
45640Sstevel@tonic-gate dlp->dl_dest_addr_length, DL_SYSERR, ENOSR);
45650Sstevel@tonic-gate return (GLDE_OK);
45660Sstevel@tonic-gate }
45670Sstevel@tonic-gate
45680Sstevel@tonic-gate /* apply any checksum information to the first block in the chain */
45690Sstevel@tonic-gate (void) hcksum_assoc(nmp, NULL, NULL, start, stuff, end, value,
45700Sstevel@tonic-gate flags, 0);
45710Sstevel@tonic-gate
45722760Sdg199075 GLD_CLEAR_MBLK_VTAG(nmp);
45730Sstevel@tonic-gate if (gld_start(q, nmp, GLD_WSRV, upri) == GLD_NORESOURCES) {
45740Sstevel@tonic-gate qenable(q);
45750Sstevel@tonic-gate return (GLDE_RETRY);
45760Sstevel@tonic-gate }
45770Sstevel@tonic-gate
45780Sstevel@tonic-gate return (GLDE_OK);
45790Sstevel@tonic-gate }
45800Sstevel@tonic-gate
45810Sstevel@tonic-gate /*
45820Sstevel@tonic-gate * gldattach(q, mp)
45830Sstevel@tonic-gate * DLPI DL_ATTACH_REQ
45840Sstevel@tonic-gate * this attaches the stream to a PPA
45850Sstevel@tonic-gate */
45860Sstevel@tonic-gate static int
gldattach(queue_t * q,mblk_t * mp)45870Sstevel@tonic-gate gldattach(queue_t *q, mblk_t *mp)
45880Sstevel@tonic-gate {
45890Sstevel@tonic-gate dl_attach_req_t *at;
45900Sstevel@tonic-gate gld_mac_info_t *macinfo;
45910Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
45920Sstevel@tonic-gate glddev_t *glddev;
45930Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
45940Sstevel@tonic-gate uint32_t ppa;
45950Sstevel@tonic-gate uint32_t vid;
45960Sstevel@tonic-gate gld_vlan_t *vlan;
45970Sstevel@tonic-gate
45980Sstevel@tonic-gate at = (dl_attach_req_t *)mp->b_rptr;
45990Sstevel@tonic-gate
46000Sstevel@tonic-gate if (gld->gld_state != DL_UNATTACHED)
46010Sstevel@tonic-gate return (DL_OUTSTATE);
46020Sstevel@tonic-gate
46030Sstevel@tonic-gate ASSERT(!gld->gld_mac_info);
46040Sstevel@tonic-gate
46050Sstevel@tonic-gate ppa = at->dl_ppa % GLD_VLAN_SCALE; /* 0 .. 999 */
46060Sstevel@tonic-gate vid = at->dl_ppa / GLD_VLAN_SCALE; /* 0 .. 4094 */
46070Sstevel@tonic-gate if (vid > VLAN_VID_MAX)
46080Sstevel@tonic-gate return (DL_BADPPA);
46090Sstevel@tonic-gate
46100Sstevel@tonic-gate glddev = gld->gld_device;
46110Sstevel@tonic-gate mutex_enter(&glddev->gld_devlock);
46120Sstevel@tonic-gate for (macinfo = glddev->gld_mac_next;
46130Sstevel@tonic-gate macinfo != (gld_mac_info_t *)&glddev->gld_mac_next;
46140Sstevel@tonic-gate macinfo = macinfo->gldm_next) {
46150Sstevel@tonic-gate int inst;
46160Sstevel@tonic-gate
46170Sstevel@tonic-gate ASSERT(macinfo != NULL);
46180Sstevel@tonic-gate if (macinfo->gldm_ppa != ppa)
46190Sstevel@tonic-gate continue;
46200Sstevel@tonic-gate
46210Sstevel@tonic-gate if (!(macinfo->gldm_GLD_flags & GLD_MAC_READY))
46220Sstevel@tonic-gate continue; /* this one's not ready yet */
46230Sstevel@tonic-gate
46240Sstevel@tonic-gate /*
46250Sstevel@tonic-gate * VLAN sanity check
46260Sstevel@tonic-gate */
46270Sstevel@tonic-gate if (vid != VLAN_VID_NONE && !VLAN_CAPABLE(macinfo)) {
46280Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
46290Sstevel@tonic-gate return (DL_BADPPA);
46300Sstevel@tonic-gate }
46310Sstevel@tonic-gate
46320Sstevel@tonic-gate /*
46330Sstevel@tonic-gate * We found the correct PPA, hold the instance
46340Sstevel@tonic-gate */
46350Sstevel@tonic-gate inst = ddi_get_instance(macinfo->gldm_devinfo);
46360Sstevel@tonic-gate if (inst == -1 || qassociate(q, inst) != 0) {
46370Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
46380Sstevel@tonic-gate return (DL_BADPPA);
46390Sstevel@tonic-gate }
46400Sstevel@tonic-gate
46410Sstevel@tonic-gate /* Take the stream off the per-driver-class list */
46420Sstevel@tonic-gate gldremque(gld);
46430Sstevel@tonic-gate
46440Sstevel@tonic-gate /*
46450Sstevel@tonic-gate * We must hold the lock to prevent multiple calls
46460Sstevel@tonic-gate * to the reset and start routines.
46470Sstevel@tonic-gate */
46480Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
46490Sstevel@tonic-gate
46500Sstevel@tonic-gate gld->gld_mac_info = macinfo;
46510Sstevel@tonic-gate
46520Sstevel@tonic-gate if (macinfo->gldm_send_tagged != NULL)
46530Sstevel@tonic-gate gld->gld_send = macinfo->gldm_send_tagged;
46540Sstevel@tonic-gate else
46550Sstevel@tonic-gate gld->gld_send = macinfo->gldm_send;
46560Sstevel@tonic-gate
46570Sstevel@tonic-gate if ((vlan = gld_get_vlan(macinfo, vid)) == NULL) {
46580Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
46590Sstevel@tonic-gate gldinsque(gld, glddev->gld_str_prev);
46600Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
46610Sstevel@tonic-gate (void) qassociate(q, -1);
46620Sstevel@tonic-gate return (DL_BADPPA);
46630Sstevel@tonic-gate }
46640Sstevel@tonic-gate
46650Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
46660Sstevel@tonic-gate if (!mac_pvt->started) {
46670Sstevel@tonic-gate if (gld_start_mac(macinfo) != GLD_SUCCESS) {
46680Sstevel@tonic-gate gld_rem_vlan(vlan);
46690Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
46700Sstevel@tonic-gate gldinsque(gld, glddev->gld_str_prev);
46710Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
46720Sstevel@tonic-gate dlerrorack(q, mp, DL_ATTACH_REQ, DL_SYSERR,
46730Sstevel@tonic-gate EIO);
46740Sstevel@tonic-gate (void) qassociate(q, -1);
46750Sstevel@tonic-gate return (GLDE_OK);
46760Sstevel@tonic-gate }
46770Sstevel@tonic-gate }
46780Sstevel@tonic-gate
46790Sstevel@tonic-gate gld->gld_vlan = vlan;
46800Sstevel@tonic-gate vlan->gldv_nstreams++;
46810Sstevel@tonic-gate gldinsque(gld, vlan->gldv_str_prev);
46820Sstevel@tonic-gate gld->gld_state = DL_UNBOUND;
46830Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
46840Sstevel@tonic-gate
46850Sstevel@tonic-gate #ifdef GLD_DEBUG
46860Sstevel@tonic-gate if (gld_debug & GLDPROT) {
46870Sstevel@tonic-gate cmn_err(CE_NOTE, "gldattach(%p, %p, PPA = %d)",
46880Sstevel@tonic-gate (void *)q, (void *)mp, macinfo->gldm_ppa);
46890Sstevel@tonic-gate }
46900Sstevel@tonic-gate #endif
46910Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
46920Sstevel@tonic-gate dlokack(q, mp, DL_ATTACH_REQ);
46930Sstevel@tonic-gate return (GLDE_OK);
46940Sstevel@tonic-gate }
46950Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
46960Sstevel@tonic-gate return (DL_BADPPA);
46970Sstevel@tonic-gate }
46980Sstevel@tonic-gate
46990Sstevel@tonic-gate /*
47000Sstevel@tonic-gate * gldunattach(q, mp)
47010Sstevel@tonic-gate * DLPI DL_DETACH_REQ
47020Sstevel@tonic-gate * detaches the mac layer from the stream
47030Sstevel@tonic-gate */
47040Sstevel@tonic-gate int
gldunattach(queue_t * q,mblk_t * mp)47050Sstevel@tonic-gate gldunattach(queue_t *q, mblk_t *mp)
47060Sstevel@tonic-gate {
47070Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
47080Sstevel@tonic-gate glddev_t *glddev = gld->gld_device;
47090Sstevel@tonic-gate gld_mac_info_t *macinfo = gld->gld_mac_info;
47100Sstevel@tonic-gate int state = gld->gld_state;
47110Sstevel@tonic-gate int i;
47120Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
47130Sstevel@tonic-gate gld_vlan_t *vlan;
47140Sstevel@tonic-gate boolean_t phys_off;
47150Sstevel@tonic-gate boolean_t mult_off;
47160Sstevel@tonic-gate int op = GLD_MAC_PROMISC_NOOP;
47170Sstevel@tonic-gate
47180Sstevel@tonic-gate if (state != DL_UNBOUND)
47190Sstevel@tonic-gate return (DL_OUTSTATE);
47200Sstevel@tonic-gate
47210Sstevel@tonic-gate ASSERT(macinfo != NULL);
47220Sstevel@tonic-gate ASSERT(gld->gld_sap == 0);
47230Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
47240Sstevel@tonic-gate
47250Sstevel@tonic-gate #ifdef GLD_DEBUG
47260Sstevel@tonic-gate if (gld_debug & GLDPROT) {
47270Sstevel@tonic-gate cmn_err(CE_NOTE, "gldunattach(%p, %p, PPA = %d)",
47280Sstevel@tonic-gate (void *)q, (void *)mp, macinfo->gldm_ppa);
47290Sstevel@tonic-gate }
47300Sstevel@tonic-gate #endif
47310Sstevel@tonic-gate
47320Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
47330Sstevel@tonic-gate
47340Sstevel@tonic-gate if (gld->gld_mcast) {
47350Sstevel@tonic-gate for (i = 0; i < gld->gld_multicnt; i++) {
47360Sstevel@tonic-gate gld_mcast_t *mcast;
47370Sstevel@tonic-gate
47380Sstevel@tonic-gate if ((mcast = gld->gld_mcast[i]) != NULL) {
47390Sstevel@tonic-gate ASSERT(mcast->gldm_refcnt);
47400Sstevel@tonic-gate gld_send_disable_multi(macinfo, mcast);
47410Sstevel@tonic-gate }
47420Sstevel@tonic-gate }
47430Sstevel@tonic-gate kmem_free(gld->gld_mcast,
47440Sstevel@tonic-gate sizeof (gld_mcast_t *) * gld->gld_multicnt);
47450Sstevel@tonic-gate gld->gld_mcast = NULL;
47460Sstevel@tonic-gate gld->gld_multicnt = 0;
47470Sstevel@tonic-gate }
47480Sstevel@tonic-gate
47490Sstevel@tonic-gate /* decide if we need to turn off any promiscuity */
47500Sstevel@tonic-gate phys_off = (gld->gld_flags & GLD_PROM_PHYS &&
47510Sstevel@tonic-gate --mac_pvt->nprom == 0);
47520Sstevel@tonic-gate mult_off = (gld->gld_flags & GLD_PROM_MULT &&
47530Sstevel@tonic-gate --mac_pvt->nprom_multi == 0);
47540Sstevel@tonic-gate
47550Sstevel@tonic-gate if (phys_off) {
47560Sstevel@tonic-gate op = (mac_pvt->nprom_multi == 0) ? GLD_MAC_PROMISC_NONE :
47570Sstevel@tonic-gate GLD_MAC_PROMISC_MULTI;
47580Sstevel@tonic-gate } else if (mult_off) {
47590Sstevel@tonic-gate op = (mac_pvt->nprom == 0) ? GLD_MAC_PROMISC_NONE :
47600Sstevel@tonic-gate GLD_MAC_PROMISC_NOOP; /* phys overrides multi */
47610Sstevel@tonic-gate }
47620Sstevel@tonic-gate
47630Sstevel@tonic-gate if (op != GLD_MAC_PROMISC_NOOP)
47640Sstevel@tonic-gate (void) (*macinfo->gldm_set_promiscuous)(macinfo, op);
47650Sstevel@tonic-gate
47662760Sdg199075 vlan = (gld_vlan_t *)gld->gld_vlan;
47672760Sdg199075 if (gld->gld_flags & GLD_PROM_PHYS)
47682760Sdg199075 vlan->gldv_nprom--;
47692760Sdg199075 if (gld->gld_flags & GLD_PROM_MULT)
47702760Sdg199075 vlan->gldv_nprom--;
47712760Sdg199075 if (gld->gld_flags & GLD_PROM_SAP) {
47722760Sdg199075 vlan->gldv_nprom--;
47732760Sdg199075 vlan->gldv_nvlan_sap--;
47742760Sdg199075 }
47752760Sdg199075
47762760Sdg199075 gld->gld_flags &= ~(GLD_PROM_PHYS | GLD_PROM_SAP | GLD_PROM_MULT);
47772760Sdg199075
47780Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
47790Sstevel@tonic-gate
47800Sstevel@tonic-gate if (phys_off)
47810Sstevel@tonic-gate gld_notify_ind(macinfo, DL_NOTE_PROMISC_OFF_PHYS, NULL);
47820Sstevel@tonic-gate
47830Sstevel@tonic-gate /*
47840Sstevel@tonic-gate * We need to hold both locks when modifying the mac stream list
47850Sstevel@tonic-gate * to protect findminor as well as everyone else.
47860Sstevel@tonic-gate */
47870Sstevel@tonic-gate mutex_enter(&glddev->gld_devlock);
47880Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
47890Sstevel@tonic-gate
47900Sstevel@tonic-gate /* disassociate this stream with its vlan and underlying mac */
47910Sstevel@tonic-gate gldremque(gld);
47920Sstevel@tonic-gate
47930Sstevel@tonic-gate if (--vlan->gldv_nstreams == 0) {
47940Sstevel@tonic-gate gld_rem_vlan(vlan);
47950Sstevel@tonic-gate gld->gld_vlan = NULL;
47960Sstevel@tonic-gate }
47970Sstevel@tonic-gate
47980Sstevel@tonic-gate gld->gld_mac_info = NULL;
47990Sstevel@tonic-gate gld->gld_state = DL_UNATTACHED;
48000Sstevel@tonic-gate
48010Sstevel@tonic-gate /* cleanup mac layer if last vlan */
48020Sstevel@tonic-gate if (mac_pvt->nvlan == 0) {
48030Sstevel@tonic-gate gld_stop_mac(macinfo);
48040Sstevel@tonic-gate macinfo->gldm_GLD_flags &= ~GLD_INTR_WAIT;
48050Sstevel@tonic-gate }
48060Sstevel@tonic-gate
48070Sstevel@tonic-gate /* make sure no references to this gld for gld_v0_sched */
48080Sstevel@tonic-gate if (mac_pvt->last_sched == gld)
48090Sstevel@tonic-gate mac_pvt->last_sched = NULL;
48100Sstevel@tonic-gate
48110Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
48120Sstevel@tonic-gate
48130Sstevel@tonic-gate /* put the stream on the unattached Style 2 list */
48140Sstevel@tonic-gate gldinsque(gld, glddev->gld_str_prev);
48150Sstevel@tonic-gate
48160Sstevel@tonic-gate mutex_exit(&glddev->gld_devlock);
48170Sstevel@tonic-gate
48180Sstevel@tonic-gate /* There will be no mp if we were called from close */
48190Sstevel@tonic-gate if (mp) {
48200Sstevel@tonic-gate dlokack(q, mp, DL_DETACH_REQ);
48210Sstevel@tonic-gate }
48220Sstevel@tonic-gate if (gld->gld_style == DL_STYLE2)
48230Sstevel@tonic-gate (void) qassociate(q, -1);
48240Sstevel@tonic-gate return (GLDE_OK);
48250Sstevel@tonic-gate }
48260Sstevel@tonic-gate
48270Sstevel@tonic-gate /*
48280Sstevel@tonic-gate * gld_enable_multi (q, mp)
48290Sstevel@tonic-gate * Enables multicast address on the stream. If the mac layer
48300Sstevel@tonic-gate * isn't enabled for this address, enable at that level as well.
48310Sstevel@tonic-gate */
48320Sstevel@tonic-gate static int
gld_enable_multi(queue_t * q,mblk_t * mp)48330Sstevel@tonic-gate gld_enable_multi(queue_t *q, mblk_t *mp)
48340Sstevel@tonic-gate {
48350Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
48360Sstevel@tonic-gate glddev_t *glddev;
48370Sstevel@tonic-gate gld_mac_info_t *macinfo = gld->gld_mac_info;
48380Sstevel@tonic-gate unsigned char *maddr;
48390Sstevel@tonic-gate dl_enabmulti_req_t *multi;
48400Sstevel@tonic-gate gld_mcast_t *mcast;
48410Sstevel@tonic-gate int i, rc;
48420Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
48430Sstevel@tonic-gate
48440Sstevel@tonic-gate #ifdef GLD_DEBUG
48450Sstevel@tonic-gate if (gld_debug & GLDPROT) {
48460Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_enable_multi(%p, %p)", (void *)q,
48470Sstevel@tonic-gate (void *)mp);
48480Sstevel@tonic-gate }
48490Sstevel@tonic-gate #endif
48500Sstevel@tonic-gate
48510Sstevel@tonic-gate if (gld->gld_state == DL_UNATTACHED)
48520Sstevel@tonic-gate return (DL_OUTSTATE);
48530Sstevel@tonic-gate
48540Sstevel@tonic-gate ASSERT(macinfo != NULL);
48550Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
48560Sstevel@tonic-gate
48570Sstevel@tonic-gate if (macinfo->gldm_set_multicast == NULL) {
48580Sstevel@tonic-gate return (DL_UNSUPPORTED);
48590Sstevel@tonic-gate }
48600Sstevel@tonic-gate
48610Sstevel@tonic-gate multi = (dl_enabmulti_req_t *)mp->b_rptr;
48620Sstevel@tonic-gate
48630Sstevel@tonic-gate if (!MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length) ||
48640Sstevel@tonic-gate multi->dl_addr_length != macinfo->gldm_addrlen)
48650Sstevel@tonic-gate return (DL_BADADDR);
48660Sstevel@tonic-gate
48670Sstevel@tonic-gate /* request appears to be valid */
48680Sstevel@tonic-gate
48690Sstevel@tonic-gate glddev = mac_pvt->major_dev;
48700Sstevel@tonic-gate ASSERT(glddev == gld->gld_device);
48710Sstevel@tonic-gate
48720Sstevel@tonic-gate maddr = mp->b_rptr + multi->dl_addr_offset;
48730Sstevel@tonic-gate
48740Sstevel@tonic-gate /*
48750Sstevel@tonic-gate * The multicast addresses live in a per-device table, along
48760Sstevel@tonic-gate * with a reference count. Each stream has a table that
48770Sstevel@tonic-gate * points to entries in the device table, with the reference
48780Sstevel@tonic-gate * count reflecting the number of streams pointing at it. If
48790Sstevel@tonic-gate * this multicast address is already in the per-device table,
48800Sstevel@tonic-gate * all we have to do is point at it.
48810Sstevel@tonic-gate */
48820Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
48830Sstevel@tonic-gate
48840Sstevel@tonic-gate /* does this address appear in current table? */
48850Sstevel@tonic-gate if (gld->gld_mcast == NULL) {
48860Sstevel@tonic-gate /* no mcast addresses -- allocate table */
48875903Ssowmini gld->gld_mcast = GLD_GETSTRUCT(gld_mcast_t *,
48885903Ssowmini glddev->gld_multisize);
48890Sstevel@tonic-gate if (gld->gld_mcast == NULL) {
48900Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
48910Sstevel@tonic-gate dlerrorack(q, mp, DL_ENABMULTI_REQ, DL_SYSERR, ENOSR);
48920Sstevel@tonic-gate return (GLDE_OK);
48930Sstevel@tonic-gate }
48940Sstevel@tonic-gate gld->gld_multicnt = glddev->gld_multisize;
48950Sstevel@tonic-gate } else {
48960Sstevel@tonic-gate for (i = 0; i < gld->gld_multicnt; i++) {
48970Sstevel@tonic-gate if (gld->gld_mcast[i] &&
48980Sstevel@tonic-gate mac_eq(gld->gld_mcast[i]->gldm_addr,
48995903Ssowmini maddr, macinfo->gldm_addrlen)) {
49000Sstevel@tonic-gate /* this is a match -- just succeed */
49010Sstevel@tonic-gate ASSERT(gld->gld_mcast[i]->gldm_refcnt);
49020Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
49030Sstevel@tonic-gate dlokack(q, mp, DL_ENABMULTI_REQ);
49040Sstevel@tonic-gate return (GLDE_OK);
49050Sstevel@tonic-gate }
49060Sstevel@tonic-gate }
49070Sstevel@tonic-gate }
49080Sstevel@tonic-gate
49090Sstevel@tonic-gate /*
49100Sstevel@tonic-gate * it wasn't in the stream so check to see if the mac layer has it
49110Sstevel@tonic-gate */
49120Sstevel@tonic-gate mcast = NULL;
49130Sstevel@tonic-gate if (mac_pvt->mcast_table == NULL) {
49145903Ssowmini mac_pvt->mcast_table = GLD_GETSTRUCT(gld_mcast_t,
49155903Ssowmini glddev->gld_multisize);
49160Sstevel@tonic-gate if (mac_pvt->mcast_table == NULL) {
49170Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
49180Sstevel@tonic-gate dlerrorack(q, mp, DL_ENABMULTI_REQ, DL_SYSERR, ENOSR);
49190Sstevel@tonic-gate return (GLDE_OK);
49200Sstevel@tonic-gate }
49210Sstevel@tonic-gate } else {
49220Sstevel@tonic-gate for (i = 0; i < glddev->gld_multisize; i++) {
49230Sstevel@tonic-gate if (mac_pvt->mcast_table[i].gldm_refcnt &&
49240Sstevel@tonic-gate mac_eq(mac_pvt->mcast_table[i].gldm_addr,
49250Sstevel@tonic-gate maddr, macinfo->gldm_addrlen)) {
49260Sstevel@tonic-gate mcast = &mac_pvt->mcast_table[i];
49270Sstevel@tonic-gate break;
49280Sstevel@tonic-gate }
49290Sstevel@tonic-gate }
49300Sstevel@tonic-gate }
49310Sstevel@tonic-gate if (mcast == NULL) {
49320Sstevel@tonic-gate /* not in mac layer -- find an empty mac slot to fill in */
49330Sstevel@tonic-gate for (i = 0; i < glddev->gld_multisize; i++) {
49340Sstevel@tonic-gate if (mac_pvt->mcast_table[i].gldm_refcnt == 0) {
49350Sstevel@tonic-gate mcast = &mac_pvt->mcast_table[i];
49360Sstevel@tonic-gate mac_copy(maddr, mcast->gldm_addr,
49370Sstevel@tonic-gate macinfo->gldm_addrlen);
49380Sstevel@tonic-gate break;
49390Sstevel@tonic-gate }
49400Sstevel@tonic-gate }
49410Sstevel@tonic-gate }
49420Sstevel@tonic-gate if (mcast == NULL) {
49430Sstevel@tonic-gate /* couldn't get a mac layer slot */
49440Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
49450Sstevel@tonic-gate return (DL_TOOMANY);
49460Sstevel@tonic-gate }
49470Sstevel@tonic-gate
49480Sstevel@tonic-gate /* now we have a mac layer slot in mcast -- get a stream slot */
49490Sstevel@tonic-gate for (i = 0; i < gld->gld_multicnt; i++) {
49500Sstevel@tonic-gate if (gld->gld_mcast[i] != NULL)
49510Sstevel@tonic-gate continue;
49520Sstevel@tonic-gate /* found an empty slot */
49530Sstevel@tonic-gate if (!mcast->gldm_refcnt) {
49540Sstevel@tonic-gate /* set mcast in hardware */
49550Sstevel@tonic-gate unsigned char cmaddr[GLD_MAX_ADDRLEN];
49560Sstevel@tonic-gate
49570Sstevel@tonic-gate ASSERT(sizeof (cmaddr) >= macinfo->gldm_addrlen);
49580Sstevel@tonic-gate cmac_copy(maddr, cmaddr,
49590Sstevel@tonic-gate macinfo->gldm_addrlen, macinfo);
49600Sstevel@tonic-gate
49610Sstevel@tonic-gate rc = (*macinfo->gldm_set_multicast)
49620Sstevel@tonic-gate (macinfo, cmaddr, GLD_MULTI_ENABLE);
49630Sstevel@tonic-gate if (rc == GLD_NOTSUPPORTED) {
49640Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
49650Sstevel@tonic-gate return (DL_NOTSUPPORTED);
49660Sstevel@tonic-gate } else if (rc == GLD_NORESOURCES) {
49670Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
49680Sstevel@tonic-gate return (DL_TOOMANY);
49690Sstevel@tonic-gate } else if (rc == GLD_BADARG) {
49700Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
49710Sstevel@tonic-gate return (DL_BADADDR);
49720Sstevel@tonic-gate } else if (rc == GLD_RETRY) {
49730Sstevel@tonic-gate /*
49740Sstevel@tonic-gate * The putbq and gld_xwait must be
49750Sstevel@tonic-gate * within the lock to prevent races
49760Sstevel@tonic-gate * with gld_sched.
49770Sstevel@tonic-gate */
49780Sstevel@tonic-gate (void) putbq(q, mp);
49790Sstevel@tonic-gate gld->gld_xwait = B_TRUE;
49800Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
49810Sstevel@tonic-gate return (GLDE_RETRY);
49820Sstevel@tonic-gate } else if (rc != GLD_SUCCESS) {
49830Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
49840Sstevel@tonic-gate dlerrorack(q, mp, DL_ENABMULTI_REQ,
49850Sstevel@tonic-gate DL_SYSERR, EIO);
49860Sstevel@tonic-gate return (GLDE_OK);
49870Sstevel@tonic-gate }
49880Sstevel@tonic-gate }
49890Sstevel@tonic-gate gld->gld_mcast[i] = mcast;
49900Sstevel@tonic-gate mcast->gldm_refcnt++;
49910Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
49920Sstevel@tonic-gate dlokack(q, mp, DL_ENABMULTI_REQ);
49930Sstevel@tonic-gate return (GLDE_OK);
49940Sstevel@tonic-gate }
49950Sstevel@tonic-gate
49960Sstevel@tonic-gate /* couldn't get a stream slot */
49970Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
49980Sstevel@tonic-gate return (DL_TOOMANY);
49990Sstevel@tonic-gate }
50000Sstevel@tonic-gate
50010Sstevel@tonic-gate
50020Sstevel@tonic-gate /*
50030Sstevel@tonic-gate * gld_disable_multi (q, mp)
50040Sstevel@tonic-gate * Disable the multicast address on the stream. If last
50050Sstevel@tonic-gate * reference for the mac layer, disable there as well.
50060Sstevel@tonic-gate */
50070Sstevel@tonic-gate static int
gld_disable_multi(queue_t * q,mblk_t * mp)50080Sstevel@tonic-gate gld_disable_multi(queue_t *q, mblk_t *mp)
50090Sstevel@tonic-gate {
50100Sstevel@tonic-gate gld_t *gld;
50110Sstevel@tonic-gate gld_mac_info_t *macinfo;
50120Sstevel@tonic-gate unsigned char *maddr;
50130Sstevel@tonic-gate dl_disabmulti_req_t *multi;
50140Sstevel@tonic-gate int i;
50150Sstevel@tonic-gate gld_mcast_t *mcast;
50160Sstevel@tonic-gate
50170Sstevel@tonic-gate #ifdef GLD_DEBUG
50180Sstevel@tonic-gate if (gld_debug & GLDPROT) {
50190Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_disable_multi(%p, %p)", (void *)q,
50200Sstevel@tonic-gate (void *)mp);
50210Sstevel@tonic-gate }
50220Sstevel@tonic-gate #endif
50230Sstevel@tonic-gate
50240Sstevel@tonic-gate gld = (gld_t *)q->q_ptr;
50250Sstevel@tonic-gate if (gld->gld_state == DL_UNATTACHED)
50260Sstevel@tonic-gate return (DL_OUTSTATE);
50270Sstevel@tonic-gate
50280Sstevel@tonic-gate macinfo = gld->gld_mac_info;
50290Sstevel@tonic-gate ASSERT(macinfo != NULL);
50300Sstevel@tonic-gate if (macinfo->gldm_set_multicast == NULL) {
50310Sstevel@tonic-gate return (DL_UNSUPPORTED);
50320Sstevel@tonic-gate }
50330Sstevel@tonic-gate
50340Sstevel@tonic-gate multi = (dl_disabmulti_req_t *)mp->b_rptr;
50350Sstevel@tonic-gate
50360Sstevel@tonic-gate if (!MBLKIN(mp, multi->dl_addr_offset, multi->dl_addr_length) ||
50370Sstevel@tonic-gate multi->dl_addr_length != macinfo->gldm_addrlen)
50380Sstevel@tonic-gate return (DL_BADADDR);
50390Sstevel@tonic-gate
50400Sstevel@tonic-gate maddr = mp->b_rptr + multi->dl_addr_offset;
50410Sstevel@tonic-gate
50420Sstevel@tonic-gate /* request appears to be valid */
50430Sstevel@tonic-gate /* does this address appear in current table? */
50440Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
50450Sstevel@tonic-gate if (gld->gld_mcast != NULL) {
50460Sstevel@tonic-gate for (i = 0; i < gld->gld_multicnt; i++)
50470Sstevel@tonic-gate if (((mcast = gld->gld_mcast[i]) != NULL) &&
50480Sstevel@tonic-gate mac_eq(mcast->gldm_addr,
50490Sstevel@tonic-gate maddr, macinfo->gldm_addrlen)) {
50500Sstevel@tonic-gate ASSERT(mcast->gldm_refcnt);
50510Sstevel@tonic-gate gld_send_disable_multi(macinfo, mcast);
50520Sstevel@tonic-gate gld->gld_mcast[i] = NULL;
50530Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
50540Sstevel@tonic-gate dlokack(q, mp, DL_DISABMULTI_REQ);
50550Sstevel@tonic-gate return (GLDE_OK);
50560Sstevel@tonic-gate }
50570Sstevel@tonic-gate }
50580Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
50590Sstevel@tonic-gate return (DL_NOTENAB); /* not an enabled address */
50600Sstevel@tonic-gate }
50610Sstevel@tonic-gate
50620Sstevel@tonic-gate /*
50630Sstevel@tonic-gate * gld_send_disable_multi(macinfo, mcast)
50640Sstevel@tonic-gate * this function is used to disable a multicast address if the reference
50650Sstevel@tonic-gate * count goes to zero. The disable request will then be forwarded to the
50660Sstevel@tonic-gate * lower stream.
50670Sstevel@tonic-gate */
50680Sstevel@tonic-gate static void
gld_send_disable_multi(gld_mac_info_t * macinfo,gld_mcast_t * mcast)50690Sstevel@tonic-gate gld_send_disable_multi(gld_mac_info_t *macinfo, gld_mcast_t *mcast)
50700Sstevel@tonic-gate {
50710Sstevel@tonic-gate ASSERT(macinfo != NULL);
50720Sstevel@tonic-gate ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
50730Sstevel@tonic-gate ASSERT(mcast != NULL);
50740Sstevel@tonic-gate ASSERT(mcast->gldm_refcnt);
50750Sstevel@tonic-gate
50760Sstevel@tonic-gate if (!mcast->gldm_refcnt) {
50770Sstevel@tonic-gate return; /* "cannot happen" */
50780Sstevel@tonic-gate }
50790Sstevel@tonic-gate
50800Sstevel@tonic-gate if (--mcast->gldm_refcnt > 0) {
50810Sstevel@tonic-gate return;
50820Sstevel@tonic-gate }
50830Sstevel@tonic-gate
50840Sstevel@tonic-gate /*
50850Sstevel@tonic-gate * This must be converted from canonical form to device form.
50860Sstevel@tonic-gate * The refcnt is now zero so we can trash the data.
50870Sstevel@tonic-gate */
50880Sstevel@tonic-gate if (macinfo->gldm_options & GLDOPT_CANONICAL_ADDR)
50890Sstevel@tonic-gate gld_bitreverse(mcast->gldm_addr, macinfo->gldm_addrlen);
50900Sstevel@tonic-gate
50910Sstevel@tonic-gate /* XXX Ought to check for GLD_NORESOURCES or GLD_FAILURE */
50920Sstevel@tonic-gate (void) (*macinfo->gldm_set_multicast)
50930Sstevel@tonic-gate (macinfo, mcast->gldm_addr, GLD_MULTI_DISABLE);
50940Sstevel@tonic-gate }
50950Sstevel@tonic-gate
50960Sstevel@tonic-gate /*
50970Sstevel@tonic-gate * gld_promisc (q, mp, req, on)
50980Sstevel@tonic-gate * enable or disable the use of promiscuous mode with the hardware
50990Sstevel@tonic-gate */
51000Sstevel@tonic-gate static int
gld_promisc(queue_t * q,mblk_t * mp,t_uscalar_t req,boolean_t on)51010Sstevel@tonic-gate gld_promisc(queue_t *q, mblk_t *mp, t_uscalar_t req, boolean_t on)
51020Sstevel@tonic-gate {
51030Sstevel@tonic-gate gld_t *gld;
51040Sstevel@tonic-gate gld_mac_info_t *macinfo;
51050Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
51060Sstevel@tonic-gate gld_vlan_t *vlan;
51070Sstevel@tonic-gate union DL_primitives *prim;
51080Sstevel@tonic-gate int macrc = GLD_SUCCESS;
51090Sstevel@tonic-gate int dlerr = GLDE_OK;
51100Sstevel@tonic-gate int op = GLD_MAC_PROMISC_NOOP;
51110Sstevel@tonic-gate
51120Sstevel@tonic-gate #ifdef GLD_DEBUG
51130Sstevel@tonic-gate if (gld_debug & GLDTRACE)
51140Sstevel@tonic-gate cmn_err(CE_NOTE, "gld_promisc(%p, %p, %d, %d)",
51150Sstevel@tonic-gate (void *)q, (void *)mp, req, on);
51160Sstevel@tonic-gate #endif
51170Sstevel@tonic-gate
51180Sstevel@tonic-gate ASSERT(mp != NULL);
51190Sstevel@tonic-gate prim = (union DL_primitives *)mp->b_rptr;
51200Sstevel@tonic-gate
51210Sstevel@tonic-gate /* XXX I think spec allows promisc in unattached state */
51220Sstevel@tonic-gate gld = (gld_t *)q->q_ptr;
51230Sstevel@tonic-gate if (gld->gld_state == DL_UNATTACHED)
51240Sstevel@tonic-gate return (DL_OUTSTATE);
51250Sstevel@tonic-gate
51260Sstevel@tonic-gate macinfo = gld->gld_mac_info;
51270Sstevel@tonic-gate ASSERT(macinfo != NULL);
51280Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
51290Sstevel@tonic-gate
51300Sstevel@tonic-gate vlan = (gld_vlan_t *)gld->gld_vlan;
51310Sstevel@tonic-gate ASSERT(vlan != NULL);
51320Sstevel@tonic-gate
51330Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
51340Sstevel@tonic-gate
51350Sstevel@tonic-gate /*
51360Sstevel@tonic-gate * Work out what request (if any) has to be made to the MAC layer
51370Sstevel@tonic-gate */
51380Sstevel@tonic-gate if (on) {
51390Sstevel@tonic-gate switch (prim->promiscon_req.dl_level) {
51400Sstevel@tonic-gate default:
51410Sstevel@tonic-gate dlerr = DL_UNSUPPORTED; /* this is an error */
51420Sstevel@tonic-gate break;
51430Sstevel@tonic-gate
51440Sstevel@tonic-gate case DL_PROMISC_PHYS:
51450Sstevel@tonic-gate if (mac_pvt->nprom == 0)
51460Sstevel@tonic-gate op = GLD_MAC_PROMISC_PHYS;
51470Sstevel@tonic-gate break;
51480Sstevel@tonic-gate
51490Sstevel@tonic-gate case DL_PROMISC_MULTI:
51500Sstevel@tonic-gate if (mac_pvt->nprom_multi == 0)
51510Sstevel@tonic-gate if (mac_pvt->nprom == 0)
51520Sstevel@tonic-gate op = GLD_MAC_PROMISC_MULTI;
51530Sstevel@tonic-gate break;
51540Sstevel@tonic-gate
51550Sstevel@tonic-gate case DL_PROMISC_SAP:
51560Sstevel@tonic-gate /* We can do this without reference to the MAC */
51570Sstevel@tonic-gate break;
51580Sstevel@tonic-gate }
51590Sstevel@tonic-gate } else {
51600Sstevel@tonic-gate switch (prim->promiscoff_req.dl_level) {
51610Sstevel@tonic-gate default:
51620Sstevel@tonic-gate dlerr = DL_UNSUPPORTED; /* this is an error */
51630Sstevel@tonic-gate break;
51640Sstevel@tonic-gate
51650Sstevel@tonic-gate case DL_PROMISC_PHYS:
51660Sstevel@tonic-gate if (!(gld->gld_flags & GLD_PROM_PHYS))
51670Sstevel@tonic-gate dlerr = DL_NOTENAB;
51680Sstevel@tonic-gate else if (mac_pvt->nprom == 1)
51690Sstevel@tonic-gate if (mac_pvt->nprom_multi)
51700Sstevel@tonic-gate op = GLD_MAC_PROMISC_MULTI;
51710Sstevel@tonic-gate else
51720Sstevel@tonic-gate op = GLD_MAC_PROMISC_NONE;
51730Sstevel@tonic-gate break;
51740Sstevel@tonic-gate
51750Sstevel@tonic-gate case DL_PROMISC_MULTI:
51760Sstevel@tonic-gate if (!(gld->gld_flags & GLD_PROM_MULT))
51770Sstevel@tonic-gate dlerr = DL_NOTENAB;
51780Sstevel@tonic-gate else if (mac_pvt->nprom_multi == 1)
51790Sstevel@tonic-gate if (mac_pvt->nprom == 0)
51800Sstevel@tonic-gate op = GLD_MAC_PROMISC_NONE;
51810Sstevel@tonic-gate break;
51820Sstevel@tonic-gate
51830Sstevel@tonic-gate case DL_PROMISC_SAP:
51840Sstevel@tonic-gate if (!(gld->gld_flags & GLD_PROM_SAP))
51850Sstevel@tonic-gate dlerr = DL_NOTENAB;
51860Sstevel@tonic-gate
51870Sstevel@tonic-gate /* We can do this without reference to the MAC */
51880Sstevel@tonic-gate break;
51890Sstevel@tonic-gate }
51900Sstevel@tonic-gate }
51910Sstevel@tonic-gate
51920Sstevel@tonic-gate /*
51930Sstevel@tonic-gate * The request was invalid in some way so no need to continue.
51940Sstevel@tonic-gate */
51950Sstevel@tonic-gate if (dlerr != GLDE_OK) {
51960Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
51970Sstevel@tonic-gate return (dlerr);
51980Sstevel@tonic-gate }
51990Sstevel@tonic-gate
52000Sstevel@tonic-gate /*
52010Sstevel@tonic-gate * Issue the request to the MAC layer, if required
52020Sstevel@tonic-gate */
52030Sstevel@tonic-gate if (op != GLD_MAC_PROMISC_NOOP) {
52040Sstevel@tonic-gate macrc = (*macinfo->gldm_set_promiscuous)(macinfo, op);
52050Sstevel@tonic-gate }
52060Sstevel@tonic-gate
52070Sstevel@tonic-gate /*
52080Sstevel@tonic-gate * On success, update the appropriate flags & refcounts
52090Sstevel@tonic-gate */
52100Sstevel@tonic-gate if (macrc == GLD_SUCCESS) {
52110Sstevel@tonic-gate if (on) {
52120Sstevel@tonic-gate switch (prim->promiscon_req.dl_level) {
52130Sstevel@tonic-gate case DL_PROMISC_PHYS:
52140Sstevel@tonic-gate mac_pvt->nprom++;
52152760Sdg199075 vlan->gldv_nprom++;
52160Sstevel@tonic-gate gld->gld_flags |= GLD_PROM_PHYS;
52170Sstevel@tonic-gate break;
52180Sstevel@tonic-gate
52190Sstevel@tonic-gate case DL_PROMISC_MULTI:
52200Sstevel@tonic-gate mac_pvt->nprom_multi++;
52212760Sdg199075 vlan->gldv_nprom++;
52220Sstevel@tonic-gate gld->gld_flags |= GLD_PROM_MULT;
52230Sstevel@tonic-gate break;
52240Sstevel@tonic-gate
52250Sstevel@tonic-gate case DL_PROMISC_SAP:
52260Sstevel@tonic-gate gld->gld_flags |= GLD_PROM_SAP;
52272760Sdg199075 vlan->gldv_nprom++;
52282760Sdg199075 vlan->gldv_nvlan_sap++;
52290Sstevel@tonic-gate break;
52300Sstevel@tonic-gate
52310Sstevel@tonic-gate default:
52320Sstevel@tonic-gate break;
52330Sstevel@tonic-gate }
52340Sstevel@tonic-gate } else {
52350Sstevel@tonic-gate switch (prim->promiscoff_req.dl_level) {
52360Sstevel@tonic-gate case DL_PROMISC_PHYS:
52370Sstevel@tonic-gate mac_pvt->nprom--;
52382760Sdg199075 vlan->gldv_nprom--;
52390Sstevel@tonic-gate gld->gld_flags &= ~GLD_PROM_PHYS;
52400Sstevel@tonic-gate break;
52410Sstevel@tonic-gate
52420Sstevel@tonic-gate case DL_PROMISC_MULTI:
52430Sstevel@tonic-gate mac_pvt->nprom_multi--;
52442760Sdg199075 vlan->gldv_nprom--;
52450Sstevel@tonic-gate gld->gld_flags &= ~GLD_PROM_MULT;
52460Sstevel@tonic-gate break;
52470Sstevel@tonic-gate
52480Sstevel@tonic-gate case DL_PROMISC_SAP:
52490Sstevel@tonic-gate gld->gld_flags &= ~GLD_PROM_SAP;
52502760Sdg199075 vlan->gldv_nvlan_sap--;
52512760Sdg199075 vlan->gldv_nprom--;
52520Sstevel@tonic-gate break;
52530Sstevel@tonic-gate
52540Sstevel@tonic-gate default:
52550Sstevel@tonic-gate break;
52560Sstevel@tonic-gate }
52570Sstevel@tonic-gate }
52580Sstevel@tonic-gate } else if (macrc == GLD_RETRY) {
52590Sstevel@tonic-gate /*
52600Sstevel@tonic-gate * The putbq and gld_xwait must be within the lock to
52610Sstevel@tonic-gate * prevent races with gld_sched.
52620Sstevel@tonic-gate */
52630Sstevel@tonic-gate (void) putbq(q, mp);
52640Sstevel@tonic-gate gld->gld_xwait = B_TRUE;
52650Sstevel@tonic-gate }
52660Sstevel@tonic-gate
52670Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
52680Sstevel@tonic-gate
52690Sstevel@tonic-gate /*
52700Sstevel@tonic-gate * Finally, decide how to reply.
52710Sstevel@tonic-gate *
52720Sstevel@tonic-gate * If <macrc> is not GLD_SUCCESS, the request was put to the MAC
52730Sstevel@tonic-gate * layer but failed. In such cases, we can return a DL_* error
52740Sstevel@tonic-gate * code and let the caller send an error-ack reply upstream, or
52750Sstevel@tonic-gate * we can send a reply here and then return GLDE_OK so that the
52760Sstevel@tonic-gate * caller doesn't also respond.
52770Sstevel@tonic-gate *
52780Sstevel@tonic-gate * If physical-promiscuous mode was (successfully) switched on or
52790Sstevel@tonic-gate * off, send a notification (DL_NOTIFY_IND) to anyone interested.
52800Sstevel@tonic-gate */
52810Sstevel@tonic-gate switch (macrc) {
52820Sstevel@tonic-gate case GLD_NOTSUPPORTED:
52830Sstevel@tonic-gate return (DL_NOTSUPPORTED);
52840Sstevel@tonic-gate
52850Sstevel@tonic-gate case GLD_NORESOURCES:
52860Sstevel@tonic-gate dlerrorack(q, mp, req, DL_SYSERR, ENOSR);
52870Sstevel@tonic-gate return (GLDE_OK);
52880Sstevel@tonic-gate
52890Sstevel@tonic-gate case GLD_RETRY:
52900Sstevel@tonic-gate return (GLDE_RETRY);
52910Sstevel@tonic-gate
52920Sstevel@tonic-gate default:
52930Sstevel@tonic-gate dlerrorack(q, mp, req, DL_SYSERR, EIO);
52940Sstevel@tonic-gate return (GLDE_OK);
52950Sstevel@tonic-gate
52960Sstevel@tonic-gate case GLD_SUCCESS:
52970Sstevel@tonic-gate dlokack(q, mp, req);
52980Sstevel@tonic-gate break;
52990Sstevel@tonic-gate }
53000Sstevel@tonic-gate
53010Sstevel@tonic-gate switch (op) {
53020Sstevel@tonic-gate case GLD_MAC_PROMISC_NOOP:
53030Sstevel@tonic-gate break;
53040Sstevel@tonic-gate
53050Sstevel@tonic-gate case GLD_MAC_PROMISC_PHYS:
53060Sstevel@tonic-gate gld_notify_ind(macinfo, DL_NOTE_PROMISC_ON_PHYS, NULL);
53070Sstevel@tonic-gate break;
53080Sstevel@tonic-gate
53090Sstevel@tonic-gate default:
53100Sstevel@tonic-gate gld_notify_ind(macinfo, DL_NOTE_PROMISC_OFF_PHYS, NULL);
53110Sstevel@tonic-gate break;
53120Sstevel@tonic-gate }
53130Sstevel@tonic-gate
53140Sstevel@tonic-gate return (GLDE_OK);
53150Sstevel@tonic-gate }
53160Sstevel@tonic-gate
53170Sstevel@tonic-gate /*
53180Sstevel@tonic-gate * gld_physaddr()
53190Sstevel@tonic-gate * get the current or factory physical address value
53200Sstevel@tonic-gate */
53210Sstevel@tonic-gate static int
gld_physaddr(queue_t * q,mblk_t * mp)53220Sstevel@tonic-gate gld_physaddr(queue_t *q, mblk_t *mp)
53230Sstevel@tonic-gate {
53240Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
53250Sstevel@tonic-gate gld_mac_info_t *macinfo;
53260Sstevel@tonic-gate union DL_primitives *prim = (union DL_primitives *)mp->b_rptr;
53270Sstevel@tonic-gate unsigned char addr[GLD_MAX_ADDRLEN];
53280Sstevel@tonic-gate
53290Sstevel@tonic-gate if (gld->gld_state == DL_UNATTACHED)
53300Sstevel@tonic-gate return (DL_OUTSTATE);
53310Sstevel@tonic-gate
53320Sstevel@tonic-gate macinfo = (gld_mac_info_t *)gld->gld_mac_info;
53330Sstevel@tonic-gate ASSERT(macinfo != NULL);
53340Sstevel@tonic-gate ASSERT(macinfo->gldm_addrlen <= GLD_MAX_ADDRLEN);
53350Sstevel@tonic-gate
53360Sstevel@tonic-gate switch (prim->physaddr_req.dl_addr_type) {
53370Sstevel@tonic-gate case DL_FACT_PHYS_ADDR:
53380Sstevel@tonic-gate mac_copy((caddr_t)macinfo->gldm_vendor_addr,
53390Sstevel@tonic-gate (caddr_t)addr, macinfo->gldm_addrlen);
53400Sstevel@tonic-gate break;
53410Sstevel@tonic-gate case DL_CURR_PHYS_ADDR:
53420Sstevel@tonic-gate /* make a copy so we don't hold the lock across qreply */
53430Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
53440Sstevel@tonic-gate mac_copy((caddr_t)
53450Sstevel@tonic-gate ((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)->curr_macaddr,
53460Sstevel@tonic-gate (caddr_t)addr, macinfo->gldm_addrlen);
53470Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
53480Sstevel@tonic-gate break;
53490Sstevel@tonic-gate default:
53500Sstevel@tonic-gate return (DL_BADPRIM);
53510Sstevel@tonic-gate }
53520Sstevel@tonic-gate dlphysaddrack(q, mp, (caddr_t)addr, macinfo->gldm_addrlen);
53530Sstevel@tonic-gate return (GLDE_OK);
53540Sstevel@tonic-gate }
53550Sstevel@tonic-gate
53560Sstevel@tonic-gate /*
53570Sstevel@tonic-gate * gld_setaddr()
53580Sstevel@tonic-gate * change the hardware's physical address to a user specified value
53590Sstevel@tonic-gate */
53600Sstevel@tonic-gate static int
gld_setaddr(queue_t * q,mblk_t * mp)53610Sstevel@tonic-gate gld_setaddr(queue_t *q, mblk_t *mp)
53620Sstevel@tonic-gate {
53630Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
53640Sstevel@tonic-gate gld_mac_info_t *macinfo;
53650Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
53660Sstevel@tonic-gate union DL_primitives *prim = (union DL_primitives *)mp->b_rptr;
53670Sstevel@tonic-gate unsigned char *addr;
53680Sstevel@tonic-gate unsigned char cmaddr[GLD_MAX_ADDRLEN];
53690Sstevel@tonic-gate int rc;
53700Sstevel@tonic-gate gld_vlan_t *vlan;
53710Sstevel@tonic-gate
53720Sstevel@tonic-gate if (gld->gld_state == DL_UNATTACHED)
53730Sstevel@tonic-gate return (DL_OUTSTATE);
53740Sstevel@tonic-gate
53750Sstevel@tonic-gate vlan = (gld_vlan_t *)gld->gld_vlan;
53760Sstevel@tonic-gate ASSERT(vlan != NULL);
53770Sstevel@tonic-gate
53780Sstevel@tonic-gate if (vlan->gldv_id != VLAN_VID_NONE)
53790Sstevel@tonic-gate return (DL_NOTSUPPORTED);
53800Sstevel@tonic-gate
53810Sstevel@tonic-gate macinfo = (gld_mac_info_t *)gld->gld_mac_info;
53820Sstevel@tonic-gate ASSERT(macinfo != NULL);
53830Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
53840Sstevel@tonic-gate
53850Sstevel@tonic-gate if (!MBLKIN(mp, prim->set_physaddr_req.dl_addr_offset,
53860Sstevel@tonic-gate prim->set_physaddr_req.dl_addr_length) ||
53870Sstevel@tonic-gate prim->set_physaddr_req.dl_addr_length != macinfo->gldm_addrlen)
53880Sstevel@tonic-gate return (DL_BADADDR);
53890Sstevel@tonic-gate
53900Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
53910Sstevel@tonic-gate
53920Sstevel@tonic-gate /* now do the set at the hardware level */
53930Sstevel@tonic-gate addr = mp->b_rptr + prim->set_physaddr_req.dl_addr_offset;
53940Sstevel@tonic-gate ASSERT(sizeof (cmaddr) >= macinfo->gldm_addrlen);
53950Sstevel@tonic-gate cmac_copy(addr, cmaddr, macinfo->gldm_addrlen, macinfo);
53960Sstevel@tonic-gate
53970Sstevel@tonic-gate rc = (*macinfo->gldm_set_mac_addr)(macinfo, cmaddr);
53980Sstevel@tonic-gate if (rc == GLD_SUCCESS)
53990Sstevel@tonic-gate mac_copy(addr, mac_pvt->curr_macaddr,
54000Sstevel@tonic-gate macinfo->gldm_addrlen);
54010Sstevel@tonic-gate
54020Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
54030Sstevel@tonic-gate
54040Sstevel@tonic-gate switch (rc) {
54050Sstevel@tonic-gate case GLD_SUCCESS:
54060Sstevel@tonic-gate break;
54070Sstevel@tonic-gate case GLD_NOTSUPPORTED:
54080Sstevel@tonic-gate return (DL_NOTSUPPORTED);
54090Sstevel@tonic-gate case GLD_BADARG:
54100Sstevel@tonic-gate return (DL_BADADDR);
54110Sstevel@tonic-gate case GLD_NORESOURCES:
54120Sstevel@tonic-gate dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, DL_SYSERR, ENOSR);
54130Sstevel@tonic-gate return (GLDE_OK);
54140Sstevel@tonic-gate default:
54150Sstevel@tonic-gate dlerrorack(q, mp, DL_SET_PHYS_ADDR_REQ, DL_SYSERR, EIO);
54160Sstevel@tonic-gate return (GLDE_OK);
54170Sstevel@tonic-gate }
54180Sstevel@tonic-gate
54190Sstevel@tonic-gate gld_notify_ind(macinfo, DL_NOTE_PHYS_ADDR, NULL);
54200Sstevel@tonic-gate
54210Sstevel@tonic-gate dlokack(q, mp, DL_SET_PHYS_ADDR_REQ);
54220Sstevel@tonic-gate return (GLDE_OK);
54230Sstevel@tonic-gate }
54240Sstevel@tonic-gate
54250Sstevel@tonic-gate int
gld_get_statistics(queue_t * q,mblk_t * mp)54260Sstevel@tonic-gate gld_get_statistics(queue_t *q, mblk_t *mp)
54270Sstevel@tonic-gate {
54280Sstevel@tonic-gate dl_get_statistics_ack_t *dlsp;
54290Sstevel@tonic-gate gld_t *gld = (gld_t *)q->q_ptr;
54300Sstevel@tonic-gate gld_mac_info_t *macinfo = gld->gld_mac_info;
54310Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt;
54320Sstevel@tonic-gate
54330Sstevel@tonic-gate if (gld->gld_state == DL_UNATTACHED)
54340Sstevel@tonic-gate return (DL_OUTSTATE);
54350Sstevel@tonic-gate
54360Sstevel@tonic-gate ASSERT(macinfo != NULL);
54370Sstevel@tonic-gate
54380Sstevel@tonic-gate mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
54390Sstevel@tonic-gate (void) gld_update_kstat(mac_pvt->kstatp, KSTAT_READ);
54400Sstevel@tonic-gate
54410Sstevel@tonic-gate mp = mexchange(q, mp, DL_GET_STATISTICS_ACK_SIZE +
54420Sstevel@tonic-gate sizeof (struct gldkstats), M_PCPROTO, DL_GET_STATISTICS_ACK);
54430Sstevel@tonic-gate
54440Sstevel@tonic-gate if (mp == NULL)
54450Sstevel@tonic-gate return (GLDE_OK); /* mexchange already sent merror */
54460Sstevel@tonic-gate
54470Sstevel@tonic-gate dlsp = (dl_get_statistics_ack_t *)mp->b_rptr;
54480Sstevel@tonic-gate dlsp->dl_primitive = DL_GET_STATISTICS_ACK;
54490Sstevel@tonic-gate dlsp->dl_stat_length = sizeof (struct gldkstats);
54500Sstevel@tonic-gate dlsp->dl_stat_offset = DL_GET_STATISTICS_ACK_SIZE;
54510Sstevel@tonic-gate
54520Sstevel@tonic-gate GLDM_LOCK(macinfo, RW_WRITER);
54530Sstevel@tonic-gate bcopy(mac_pvt->kstatp->ks_data,
54540Sstevel@tonic-gate (mp->b_rptr + DL_GET_STATISTICS_ACK_SIZE),
54550Sstevel@tonic-gate sizeof (struct gldkstats));
54560Sstevel@tonic-gate GLDM_UNLOCK(macinfo);
54570Sstevel@tonic-gate
54580Sstevel@tonic-gate qreply(q, mp);
54590Sstevel@tonic-gate return (GLDE_OK);
54600Sstevel@tonic-gate }
54610Sstevel@tonic-gate
54620Sstevel@tonic-gate /* =================================================== */
54630Sstevel@tonic-gate /* misc utilities, some requiring various mutexes held */
54640Sstevel@tonic-gate /* =================================================== */
54650Sstevel@tonic-gate
54660Sstevel@tonic-gate /*
54670Sstevel@tonic-gate * Initialize and start the driver.
54680Sstevel@tonic-gate */
54690Sstevel@tonic-gate static int
gld_start_mac(gld_mac_info_t * macinfo)54700Sstevel@tonic-gate gld_start_mac(gld_mac_info_t *macinfo)
54710Sstevel@tonic-gate {
54720Sstevel@tonic-gate int rc;
54730Sstevel@tonic-gate unsigned char cmaddr[GLD_MAX_ADDRLEN];
54740Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
54750Sstevel@tonic-gate
54760Sstevel@tonic-gate ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
54770Sstevel@tonic-gate ASSERT(!mac_pvt->started);
54780Sstevel@tonic-gate
54790Sstevel@tonic-gate rc = (*macinfo->gldm_reset)(macinfo);
54800Sstevel@tonic-gate if (rc != GLD_SUCCESS)
54810Sstevel@tonic-gate return (GLD_FAILURE);
54820Sstevel@tonic-gate
54830Sstevel@tonic-gate /* set the addr after we reset the device */
54840Sstevel@tonic-gate ASSERT(sizeof (cmaddr) >= macinfo->gldm_addrlen);
54850Sstevel@tonic-gate cmac_copy(((gld_mac_pvt_t *)macinfo->gldm_mac_pvt)
54860Sstevel@tonic-gate ->curr_macaddr, cmaddr, macinfo->gldm_addrlen, macinfo);
54870Sstevel@tonic-gate
54880Sstevel@tonic-gate rc = (*macinfo->gldm_set_mac_addr)(macinfo, cmaddr);
54890Sstevel@tonic-gate ASSERT(rc != GLD_BADARG); /* this address was good before */
54900Sstevel@tonic-gate if (rc != GLD_SUCCESS && rc != GLD_NOTSUPPORTED)
54910Sstevel@tonic-gate return (GLD_FAILURE);
54920Sstevel@tonic-gate
54930Sstevel@tonic-gate rc = (*macinfo->gldm_start)(macinfo);
54940Sstevel@tonic-gate if (rc != GLD_SUCCESS)
54950Sstevel@tonic-gate return (GLD_FAILURE);
54960Sstevel@tonic-gate
54970Sstevel@tonic-gate mac_pvt->started = B_TRUE;
54980Sstevel@tonic-gate return (GLD_SUCCESS);
54990Sstevel@tonic-gate }
55000Sstevel@tonic-gate
55010Sstevel@tonic-gate /*
55020Sstevel@tonic-gate * Stop the driver.
55030Sstevel@tonic-gate */
55040Sstevel@tonic-gate static void
gld_stop_mac(gld_mac_info_t * macinfo)55050Sstevel@tonic-gate gld_stop_mac(gld_mac_info_t *macinfo)
55060Sstevel@tonic-gate {
55070Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
55080Sstevel@tonic-gate
55090Sstevel@tonic-gate ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
55100Sstevel@tonic-gate ASSERT(mac_pvt->started);
55110Sstevel@tonic-gate
55120Sstevel@tonic-gate (void) (*macinfo->gldm_stop)(macinfo);
55130Sstevel@tonic-gate
55140Sstevel@tonic-gate mac_pvt->started = B_FALSE;
55150Sstevel@tonic-gate }
55160Sstevel@tonic-gate
55170Sstevel@tonic-gate
55180Sstevel@tonic-gate /*
55190Sstevel@tonic-gate * gld_set_ipq will set a pointer to the queue which is bound to the
55200Sstevel@tonic-gate * IP sap if:
55210Sstevel@tonic-gate * o the device type is ethernet or IPoIB.
55220Sstevel@tonic-gate * o there is no stream in SAP promiscuous mode.
55230Sstevel@tonic-gate * o there is exactly one stream bound to the IP sap.
55240Sstevel@tonic-gate * o the stream is in "fastpath" mode.
55250Sstevel@tonic-gate */
55260Sstevel@tonic-gate static void
gld_set_ipq(gld_t * gld)55270Sstevel@tonic-gate gld_set_ipq(gld_t *gld)
55280Sstevel@tonic-gate {
55290Sstevel@tonic-gate gld_vlan_t *vlan;
55300Sstevel@tonic-gate gld_mac_info_t *macinfo = gld->gld_mac_info;
55310Sstevel@tonic-gate gld_t *ip_gld = NULL;
55320Sstevel@tonic-gate uint_t ipq_candidates = 0;
55330Sstevel@tonic-gate gld_t *ipv6_gld = NULL;
55340Sstevel@tonic-gate uint_t ipv6q_candidates = 0;
55350Sstevel@tonic-gate
55360Sstevel@tonic-gate ASSERT(GLDM_LOCK_HELD_WRITE(macinfo));
55370Sstevel@tonic-gate
55380Sstevel@tonic-gate /* The ipq code in gld_recv() is intimate with ethernet/IPoIB */
55390Sstevel@tonic-gate if (((macinfo->gldm_type != DL_ETHER) &&
55400Sstevel@tonic-gate (macinfo->gldm_type != DL_IB)) ||
55410Sstevel@tonic-gate (gld_global_options & GLD_OPT_NO_IPQ))
55420Sstevel@tonic-gate return;
55430Sstevel@tonic-gate
55440Sstevel@tonic-gate vlan = (gld_vlan_t *)gld->gld_vlan;
55450Sstevel@tonic-gate ASSERT(vlan != NULL);
55460Sstevel@tonic-gate
55470Sstevel@tonic-gate /* clear down any previously defined ipqs */
55480Sstevel@tonic-gate vlan->gldv_ipq = NULL;
55490Sstevel@tonic-gate vlan->gldv_ipv6q = NULL;
55500Sstevel@tonic-gate
55510Sstevel@tonic-gate /* Try to find a single stream eligible to receive IP packets */
55520Sstevel@tonic-gate for (gld = vlan->gldv_str_next;
55530Sstevel@tonic-gate gld != (gld_t *)&vlan->gldv_str_next; gld = gld->gld_next) {
55540Sstevel@tonic-gate if (gld->gld_state != DL_IDLE)
55550Sstevel@tonic-gate continue; /* not eligible to receive */
55560Sstevel@tonic-gate if (gld->gld_flags & GLD_STR_CLOSING)
55570Sstevel@tonic-gate continue; /* not eligible to receive */
55580Sstevel@tonic-gate
55590Sstevel@tonic-gate if (gld->gld_sap == ETHERTYPE_IP) {
55600Sstevel@tonic-gate ip_gld = gld;
55610Sstevel@tonic-gate ipq_candidates++;
55620Sstevel@tonic-gate }
55630Sstevel@tonic-gate
55640Sstevel@tonic-gate if (gld->gld_sap == ETHERTYPE_IPV6) {
55650Sstevel@tonic-gate ipv6_gld = gld;
55660Sstevel@tonic-gate ipv6q_candidates++;
55670Sstevel@tonic-gate }
55680Sstevel@tonic-gate }
55690Sstevel@tonic-gate
55700Sstevel@tonic-gate if (ipq_candidates == 1) {
55710Sstevel@tonic-gate ASSERT(ip_gld != NULL);
55720Sstevel@tonic-gate
55730Sstevel@tonic-gate if (ip_gld->gld_flags & GLD_FAST) /* eligible for ipq */
55740Sstevel@tonic-gate vlan->gldv_ipq = ip_gld->gld_qptr;
55750Sstevel@tonic-gate }
55760Sstevel@tonic-gate
55770Sstevel@tonic-gate if (ipv6q_candidates == 1) {
55780Sstevel@tonic-gate ASSERT(ipv6_gld != NULL);
55790Sstevel@tonic-gate
55800Sstevel@tonic-gate if (ipv6_gld->gld_flags & GLD_FAST) /* eligible for ipq */
55810Sstevel@tonic-gate vlan->gldv_ipv6q = ipv6_gld->gld_qptr;
55820Sstevel@tonic-gate }
55830Sstevel@tonic-gate }
55840Sstevel@tonic-gate
55850Sstevel@tonic-gate /*
55860Sstevel@tonic-gate * gld_flushqueue (q)
55870Sstevel@tonic-gate * used by DLPI primitives that require flushing the queues.
55880Sstevel@tonic-gate * essentially, this is DL_UNBIND_REQ.
55890Sstevel@tonic-gate */
55900Sstevel@tonic-gate static void
gld_flushqueue(queue_t * q)55910Sstevel@tonic-gate gld_flushqueue(queue_t *q)
55920Sstevel@tonic-gate {
55930Sstevel@tonic-gate /* flush all data in both queues */
55940Sstevel@tonic-gate /* XXX Should these be FLUSHALL? */
55950Sstevel@tonic-gate flushq(q, FLUSHDATA);
55960Sstevel@tonic-gate flushq(WR(q), FLUSHDATA);
55970Sstevel@tonic-gate /* flush all the queues upstream */
55980Sstevel@tonic-gate (void) putctl1(q, M_FLUSH, FLUSHRW);
55990Sstevel@tonic-gate }
56000Sstevel@tonic-gate
56010Sstevel@tonic-gate /*
56020Sstevel@tonic-gate * gld_devlookup (major)
56030Sstevel@tonic-gate * search the device table for the device with specified
56040Sstevel@tonic-gate * major number and return a pointer to it if it exists
56050Sstevel@tonic-gate */
56060Sstevel@tonic-gate static glddev_t *
gld_devlookup(int major)56070Sstevel@tonic-gate gld_devlookup(int major)
56080Sstevel@tonic-gate {
56090Sstevel@tonic-gate struct glddevice *dev;
56100Sstevel@tonic-gate
56110Sstevel@tonic-gate ASSERT(mutex_owned(&gld_device_list.gld_devlock));
56120Sstevel@tonic-gate
56130Sstevel@tonic-gate for (dev = gld_device_list.gld_next;
56140Sstevel@tonic-gate dev != &gld_device_list;
56150Sstevel@tonic-gate dev = dev->gld_next) {
56160Sstevel@tonic-gate ASSERT(dev);
56170Sstevel@tonic-gate if (dev->gld_major == major)
56180Sstevel@tonic-gate return (dev);
56190Sstevel@tonic-gate }
56200Sstevel@tonic-gate return (NULL);
56210Sstevel@tonic-gate }
56220Sstevel@tonic-gate
56230Sstevel@tonic-gate /*
56240Sstevel@tonic-gate * gld_findminor(device)
56250Sstevel@tonic-gate * Returns a minor number currently unused by any stream in the current
56260Sstevel@tonic-gate * device class (major) list.
56270Sstevel@tonic-gate */
56280Sstevel@tonic-gate static int
gld_findminor(glddev_t * device)56290Sstevel@tonic-gate gld_findminor(glddev_t *device)
56300Sstevel@tonic-gate {
56310Sstevel@tonic-gate gld_t *next;
56320Sstevel@tonic-gate gld_mac_info_t *nextmac;
56330Sstevel@tonic-gate gld_vlan_t *nextvlan;
56340Sstevel@tonic-gate int minor;
56350Sstevel@tonic-gate int i;
56360Sstevel@tonic-gate
56370Sstevel@tonic-gate ASSERT(mutex_owned(&device->gld_devlock));
56380Sstevel@tonic-gate
56390Sstevel@tonic-gate /* The fast way */
56400Sstevel@tonic-gate if (device->gld_nextminor >= GLD_MIN_CLONE_MINOR &&
56410Sstevel@tonic-gate device->gld_nextminor <= GLD_MAX_CLONE_MINOR)
56420Sstevel@tonic-gate return (device->gld_nextminor++);
56430Sstevel@tonic-gate
56440Sstevel@tonic-gate /* The steady way */
56450Sstevel@tonic-gate for (minor = GLD_MIN_CLONE_MINOR; minor <= GLD_MAX_CLONE_MINOR;
56460Sstevel@tonic-gate minor++) {
56470Sstevel@tonic-gate /* Search all unattached streams */
56480Sstevel@tonic-gate for (next = device->gld_str_next;
56490Sstevel@tonic-gate next != (gld_t *)&device->gld_str_next;
56500Sstevel@tonic-gate next = next->gld_next) {
56510Sstevel@tonic-gate if (minor == next->gld_minor)
56520Sstevel@tonic-gate goto nextminor;
56530Sstevel@tonic-gate }
56540Sstevel@tonic-gate /* Search all attached streams; we don't need maclock because */
56550Sstevel@tonic-gate /* mac stream list is protected by devlock as well as maclock */
56560Sstevel@tonic-gate for (nextmac = device->gld_mac_next;
56570Sstevel@tonic-gate nextmac != (gld_mac_info_t *)&device->gld_mac_next;
56580Sstevel@tonic-gate nextmac = nextmac->gldm_next) {
56590Sstevel@tonic-gate gld_mac_pvt_t *pvt =
56600Sstevel@tonic-gate (gld_mac_pvt_t *)nextmac->gldm_mac_pvt;
56610Sstevel@tonic-gate
56620Sstevel@tonic-gate if (!(nextmac->gldm_GLD_flags & GLD_MAC_READY))
56630Sstevel@tonic-gate continue; /* this one's not ready yet */
56640Sstevel@tonic-gate
56650Sstevel@tonic-gate for (i = 0; i < VLAN_HASHSZ; i++) {
56660Sstevel@tonic-gate for (nextvlan = pvt->vlan_hash[i];
56670Sstevel@tonic-gate nextvlan != NULL;
56680Sstevel@tonic-gate nextvlan = nextvlan->gldv_next) {
56690Sstevel@tonic-gate for (next = nextvlan->gldv_str_next;
56700Sstevel@tonic-gate next !=
56710Sstevel@tonic-gate (gld_t *)&nextvlan->gldv_str_next;
56720Sstevel@tonic-gate next = next->gld_next) {
56730Sstevel@tonic-gate if (minor == next->gld_minor)
56740Sstevel@tonic-gate goto nextminor;
56750Sstevel@tonic-gate }
56760Sstevel@tonic-gate }
56770Sstevel@tonic-gate }
56780Sstevel@tonic-gate }
56790Sstevel@tonic-gate
56800Sstevel@tonic-gate return (minor);
56810Sstevel@tonic-gate nextminor:
56820Sstevel@tonic-gate /* don't need to do anything */
56830Sstevel@tonic-gate ;
56840Sstevel@tonic-gate }
56850Sstevel@tonic-gate cmn_err(CE_WARN, "GLD ran out of minor numbers for %s",
56865903Ssowmini device->gld_name);
56870Sstevel@tonic-gate return (0);
56880Sstevel@tonic-gate }
56890Sstevel@tonic-gate
56900Sstevel@tonic-gate /*
56910Sstevel@tonic-gate * version of insque/remque for use by this driver
56920Sstevel@tonic-gate */
56930Sstevel@tonic-gate struct qelem {
56940Sstevel@tonic-gate struct qelem *q_forw;
56950Sstevel@tonic-gate struct qelem *q_back;
56960Sstevel@tonic-gate /* rest of structure */
56970Sstevel@tonic-gate };
56980Sstevel@tonic-gate
56990Sstevel@tonic-gate static void
gldinsque(void * elem,void * pred)57000Sstevel@tonic-gate gldinsque(void *elem, void *pred)
57010Sstevel@tonic-gate {
57020Sstevel@tonic-gate struct qelem *pelem = elem;
57030Sstevel@tonic-gate struct qelem *ppred = pred;
57040Sstevel@tonic-gate struct qelem *pnext = ppred->q_forw;
57050Sstevel@tonic-gate
57060Sstevel@tonic-gate pelem->q_forw = pnext;
57070Sstevel@tonic-gate pelem->q_back = ppred;
57080Sstevel@tonic-gate ppred->q_forw = pelem;
57090Sstevel@tonic-gate pnext->q_back = pelem;
57100Sstevel@tonic-gate }
57110Sstevel@tonic-gate
57120Sstevel@tonic-gate static void
gldremque(void * arg)57130Sstevel@tonic-gate gldremque(void *arg)
57140Sstevel@tonic-gate {
57150Sstevel@tonic-gate struct qelem *pelem = arg;
57160Sstevel@tonic-gate struct qelem *elem = arg;
57170Sstevel@tonic-gate
57180Sstevel@tonic-gate pelem->q_forw->q_back = pelem->q_back;
57190Sstevel@tonic-gate pelem->q_back->q_forw = pelem->q_forw;
57200Sstevel@tonic-gate elem->q_back = elem->q_forw = NULL;
57210Sstevel@tonic-gate }
57220Sstevel@tonic-gate
57230Sstevel@tonic-gate static gld_vlan_t *
gld_add_vlan(gld_mac_info_t * macinfo,uint32_t vid)57240Sstevel@tonic-gate gld_add_vlan(gld_mac_info_t *macinfo, uint32_t vid)
57250Sstevel@tonic-gate {
57260Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
57270Sstevel@tonic-gate gld_vlan_t **pp;
57280Sstevel@tonic-gate gld_vlan_t *p;
57290Sstevel@tonic-gate
57300Sstevel@tonic-gate pp = &(mac_pvt->vlan_hash[vid % VLAN_HASHSZ]);
57310Sstevel@tonic-gate while ((p = *pp) != NULL) {
57320Sstevel@tonic-gate ASSERT(p->gldv_id != vid);
57330Sstevel@tonic-gate pp = &(p->gldv_next);
57340Sstevel@tonic-gate }
57350Sstevel@tonic-gate
57360Sstevel@tonic-gate if ((p = kmem_zalloc(sizeof (gld_vlan_t), KM_NOSLEEP)) == NULL)
57370Sstevel@tonic-gate return (NULL);
57380Sstevel@tonic-gate
57390Sstevel@tonic-gate p->gldv_mac = macinfo;
57400Sstevel@tonic-gate p->gldv_id = vid;
57410Sstevel@tonic-gate
57420Sstevel@tonic-gate if (vid == VLAN_VID_NONE) {
57430Sstevel@tonic-gate p->gldv_ptag = VLAN_VTAG_NONE;
57440Sstevel@tonic-gate p->gldv_stats = mac_pvt->statistics;
57450Sstevel@tonic-gate p->gldv_kstatp = NULL;
57460Sstevel@tonic-gate } else {
57470Sstevel@tonic-gate p->gldv_ptag = GLD_MK_PTAG(VLAN_CFI_ETHER, vid);
57480Sstevel@tonic-gate p->gldv_stats = kmem_zalloc(sizeof (struct gld_stats),
57490Sstevel@tonic-gate KM_SLEEP);
57500Sstevel@tonic-gate
57510Sstevel@tonic-gate if (gld_init_vlan_stats(p) != GLD_SUCCESS) {
57520Sstevel@tonic-gate kmem_free(p->gldv_stats, sizeof (struct gld_stats));
57530Sstevel@tonic-gate kmem_free(p, sizeof (gld_vlan_t));
57540Sstevel@tonic-gate return (NULL);
57550Sstevel@tonic-gate }
57560Sstevel@tonic-gate }
57570Sstevel@tonic-gate
57580Sstevel@tonic-gate p->gldv_str_next = p->gldv_str_prev = (gld_t *)&p->gldv_str_next;
57590Sstevel@tonic-gate mac_pvt->nvlan++;
57600Sstevel@tonic-gate *pp = p;
57610Sstevel@tonic-gate
57620Sstevel@tonic-gate return (p);
57630Sstevel@tonic-gate }
57640Sstevel@tonic-gate
57650Sstevel@tonic-gate static void
gld_rem_vlan(gld_vlan_t * vlan)57660Sstevel@tonic-gate gld_rem_vlan(gld_vlan_t *vlan)
57670Sstevel@tonic-gate {
57680Sstevel@tonic-gate gld_mac_info_t *macinfo = vlan->gldv_mac;
57690Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
57700Sstevel@tonic-gate gld_vlan_t **pp;
57710Sstevel@tonic-gate gld_vlan_t *p;
57720Sstevel@tonic-gate
57730Sstevel@tonic-gate pp = &(mac_pvt->vlan_hash[vlan->gldv_id % VLAN_HASHSZ]);
57740Sstevel@tonic-gate while ((p = *pp) != NULL) {
57750Sstevel@tonic-gate if (p->gldv_id == vlan->gldv_id)
57760Sstevel@tonic-gate break;
57770Sstevel@tonic-gate pp = &(p->gldv_next);
57780Sstevel@tonic-gate }
57790Sstevel@tonic-gate ASSERT(p != NULL);
57800Sstevel@tonic-gate
57810Sstevel@tonic-gate *pp = p->gldv_next;
57820Sstevel@tonic-gate mac_pvt->nvlan--;
57830Sstevel@tonic-gate if (p->gldv_id != VLAN_VID_NONE) {
57840Sstevel@tonic-gate ASSERT(p->gldv_kstatp != NULL);
57850Sstevel@tonic-gate kstat_delete(p->gldv_kstatp);
57860Sstevel@tonic-gate kmem_free(p->gldv_stats, sizeof (struct gld_stats));
57870Sstevel@tonic-gate }
57880Sstevel@tonic-gate kmem_free(p, sizeof (gld_vlan_t));
57890Sstevel@tonic-gate }
57900Sstevel@tonic-gate
57910Sstevel@tonic-gate gld_vlan_t *
gld_find_vlan(gld_mac_info_t * macinfo,uint32_t vid)57920Sstevel@tonic-gate gld_find_vlan(gld_mac_info_t *macinfo, uint32_t vid)
57930Sstevel@tonic-gate {
57940Sstevel@tonic-gate gld_mac_pvt_t *mac_pvt = (gld_mac_pvt_t *)macinfo->gldm_mac_pvt;
57950Sstevel@tonic-gate gld_vlan_t *p;
57960Sstevel@tonic-gate
57970Sstevel@tonic-gate p = mac_pvt->vlan_hash[vid % VLAN_HASHSZ];
57980Sstevel@tonic-gate while (p != NULL) {
57990Sstevel@tonic-gate if (p->gldv_id == vid)
58000Sstevel@tonic-gate return (p);
58010Sstevel@tonic-gate p = p->gldv_next;
58020Sstevel@tonic-gate }
58030Sstevel@tonic-gate return (NULL);
58040Sstevel@tonic-gate }
58050Sstevel@tonic-gate
58060Sstevel@tonic-gate gld_vlan_t *
gld_get_vlan(gld_mac_info_t * macinfo,uint32_t vid)58070Sstevel@tonic-gate gld_get_vlan(gld_mac_info_t *macinfo, uint32_t vid)
58080Sstevel@tonic-gate {
58090Sstevel@tonic-gate gld_vlan_t *vlan;
58100Sstevel@tonic-gate
58110Sstevel@tonic-gate if ((vlan = gld_find_vlan(macinfo, vid)) == NULL)
58120Sstevel@tonic-gate vlan = gld_add_vlan(macinfo, vid);
58130Sstevel@tonic-gate
58140Sstevel@tonic-gate return (vlan);
58150Sstevel@tonic-gate }
58160Sstevel@tonic-gate
58170Sstevel@tonic-gate /*
58180Sstevel@tonic-gate * gld_bitrevcopy()
58190Sstevel@tonic-gate * This is essentially bcopy, with the ability to bit reverse the
58200Sstevel@tonic-gate * the source bytes. The MAC addresses bytes as transmitted by FDDI
58210Sstevel@tonic-gate * interfaces are bit reversed.
58220Sstevel@tonic-gate */
58230Sstevel@tonic-gate void
gld_bitrevcopy(caddr_t src,caddr_t target,size_t n)58240Sstevel@tonic-gate gld_bitrevcopy(caddr_t src, caddr_t target, size_t n)
58250Sstevel@tonic-gate {
58260Sstevel@tonic-gate while (n--)
58270Sstevel@tonic-gate *target++ = bit_rev[(uchar_t)*src++];
58280Sstevel@tonic-gate }
58290Sstevel@tonic-gate
58300Sstevel@tonic-gate /*
58310Sstevel@tonic-gate * gld_bitreverse()
58320Sstevel@tonic-gate * Convert the bit order by swaping all the bits, using a
58330Sstevel@tonic-gate * lookup table.
58340Sstevel@tonic-gate */
58350Sstevel@tonic-gate void
gld_bitreverse(uchar_t * rptr,size_t n)58360Sstevel@tonic-gate gld_bitreverse(uchar_t *rptr, size_t n)
58370Sstevel@tonic-gate {
58380Sstevel@tonic-gate while (n--) {
58390Sstevel@tonic-gate *rptr = bit_rev[*rptr];
58400Sstevel@tonic-gate rptr++;
58410Sstevel@tonic-gate }
58420Sstevel@tonic-gate }
58430Sstevel@tonic-gate
58440Sstevel@tonic-gate char *
gld_macaddr_sprintf(char * etherbuf,unsigned char * ap,int len)58450Sstevel@tonic-gate gld_macaddr_sprintf(char *etherbuf, unsigned char *ap, int len)
58460Sstevel@tonic-gate {
58470Sstevel@tonic-gate int i;
58480Sstevel@tonic-gate char *cp = etherbuf;
58490Sstevel@tonic-gate static char digits[] = "0123456789abcdef";
58500Sstevel@tonic-gate
58510Sstevel@tonic-gate for (i = 0; i < len; i++) {
58520Sstevel@tonic-gate *cp++ = digits[*ap >> 4];
58530Sstevel@tonic-gate *cp++ = digits[*ap++ & 0xf];
58540Sstevel@tonic-gate *cp++ = ':';
58550Sstevel@tonic-gate }
58560Sstevel@tonic-gate *--cp = 0;
58570Sstevel@tonic-gate return (etherbuf);
58580Sstevel@tonic-gate }
58590Sstevel@tonic-gate
58600Sstevel@tonic-gate #ifdef GLD_DEBUG
58610Sstevel@tonic-gate static void
gld_check_assertions()58620Sstevel@tonic-gate gld_check_assertions()
58630Sstevel@tonic-gate {
58640Sstevel@tonic-gate glddev_t *dev;
58650Sstevel@tonic-gate gld_mac_info_t *mac;
58660Sstevel@tonic-gate gld_t *str;
58670Sstevel@tonic-gate gld_vlan_t *vlan;
58680Sstevel@tonic-gate int i;
58690Sstevel@tonic-gate
58700Sstevel@tonic-gate mutex_enter(&gld_device_list.gld_devlock);
58710Sstevel@tonic-gate
58720Sstevel@tonic-gate for (dev = gld_device_list.gld_next;
58730Sstevel@tonic-gate dev != (glddev_t *)&gld_device_list.gld_next;
58740Sstevel@tonic-gate dev = dev->gld_next) {
58750Sstevel@tonic-gate mutex_enter(&dev->gld_devlock);
58760Sstevel@tonic-gate ASSERT(dev->gld_broadcast != NULL);
58770Sstevel@tonic-gate for (str = dev->gld_str_next;
58780Sstevel@tonic-gate str != (gld_t *)&dev->gld_str_next;
58790Sstevel@tonic-gate str = str->gld_next) {
58800Sstevel@tonic-gate ASSERT(str->gld_device == dev);
58810Sstevel@tonic-gate ASSERT(str->gld_mac_info == NULL);
58820Sstevel@tonic-gate ASSERT(str->gld_qptr != NULL);
58830Sstevel@tonic-gate ASSERT(str->gld_minor >= GLD_MIN_CLONE_MINOR);
58840Sstevel@tonic-gate ASSERT(str->gld_multicnt == 0);
58850Sstevel@tonic-gate ASSERT(str->gld_mcast == NULL);
58860Sstevel@tonic-gate ASSERT(!(str->gld_flags &
58870Sstevel@tonic-gate (GLD_PROM_PHYS|GLD_PROM_MULT|GLD_PROM_SAP)));
58880Sstevel@tonic-gate ASSERT(str->gld_sap == 0);
58890Sstevel@tonic-gate ASSERT(str->gld_state == DL_UNATTACHED);
58900Sstevel@tonic-gate }
58910Sstevel@tonic-gate for (mac = dev->gld_mac_next;
58920Sstevel@tonic-gate mac != (gld_mac_info_t *)&dev->gld_mac_next;
58930Sstevel@tonic-gate mac = mac->gldm_next) {
58940Sstevel@tonic-gate int nvlan = 0;
58950Sstevel@tonic-gate gld_mac_pvt_t *pvt = (gld_mac_pvt_t *)mac->gldm_mac_pvt;
58960Sstevel@tonic-gate
58970Sstevel@tonic-gate if (!(mac->gldm_GLD_flags & GLD_MAC_READY))
58980Sstevel@tonic-gate continue; /* this one's not ready yet */
58990Sstevel@tonic-gate
59000Sstevel@tonic-gate GLDM_LOCK(mac, RW_WRITER);
59010Sstevel@tonic-gate ASSERT(mac->gldm_devinfo != NULL);
59020Sstevel@tonic-gate ASSERT(mac->gldm_mac_pvt != NULL);
59030Sstevel@tonic-gate ASSERT(pvt->interfacep != NULL);
59040Sstevel@tonic-gate ASSERT(pvt->kstatp != NULL);
59050Sstevel@tonic-gate ASSERT(pvt->statistics != NULL);
59060Sstevel@tonic-gate ASSERT(pvt->major_dev == dev);
59070Sstevel@tonic-gate
59080Sstevel@tonic-gate for (i = 0; i < VLAN_HASHSZ; i++) {
59090Sstevel@tonic-gate for (vlan = pvt->vlan_hash[i];
59100Sstevel@tonic-gate vlan != NULL; vlan = vlan->gldv_next) {
59110Sstevel@tonic-gate int nstr = 0;
59120Sstevel@tonic-gate
59130Sstevel@tonic-gate ASSERT(vlan->gldv_mac == mac);
59140Sstevel@tonic-gate
59150Sstevel@tonic-gate for (str = vlan->gldv_str_next;
59160Sstevel@tonic-gate str !=
59170Sstevel@tonic-gate (gld_t *)&vlan->gldv_str_next;
59180Sstevel@tonic-gate str = str->gld_next) {
59190Sstevel@tonic-gate ASSERT(str->gld_device == dev);
59200Sstevel@tonic-gate ASSERT(str->gld_mac_info ==
59210Sstevel@tonic-gate mac);
59220Sstevel@tonic-gate ASSERT(str->gld_qptr != NULL);
59230Sstevel@tonic-gate ASSERT(str->gld_minor >=
59240Sstevel@tonic-gate GLD_MIN_CLONE_MINOR);
59250Sstevel@tonic-gate ASSERT(
59260Sstevel@tonic-gate str->gld_multicnt == 0 ||
59270Sstevel@tonic-gate str->gld_mcast);
59280Sstevel@tonic-gate nstr++;
59290Sstevel@tonic-gate }
59300Sstevel@tonic-gate ASSERT(vlan->gldv_nstreams == nstr);
59310Sstevel@tonic-gate nvlan++;
59320Sstevel@tonic-gate }
59330Sstevel@tonic-gate }
59340Sstevel@tonic-gate ASSERT(pvt->nvlan == nvlan);
59350Sstevel@tonic-gate GLDM_UNLOCK(mac);
59360Sstevel@tonic-gate }
59370Sstevel@tonic-gate mutex_exit(&dev->gld_devlock);
59380Sstevel@tonic-gate }
59390Sstevel@tonic-gate mutex_exit(&gld_device_list.gld_devlock);
59400Sstevel@tonic-gate }
59410Sstevel@tonic-gate #endif
5942