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