11991Sheppo /* 21991Sheppo * CDDL HEADER START 31991Sheppo * 41991Sheppo * The contents of this file are subject to the terms of the 51991Sheppo * Common Development and Distribution License (the "License"). 61991Sheppo * You may not use this file except in compliance with the License. 71991Sheppo * 81991Sheppo * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 91991Sheppo * or http://www.opensolaris.org/os/licensing. 101991Sheppo * See the License for the specific language governing permissions 111991Sheppo * and limitations under the License. 121991Sheppo * 131991Sheppo * When distributing Covered Code, include this CDDL HEADER in each 141991Sheppo * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 151991Sheppo * If applicable, add the following below this CDDL HEADER, with the 161991Sheppo * fields enclosed by brackets "[]" replaced with your own identifying 171991Sheppo * information: Portions Copyright [yyyy] [name of copyright owner] 181991Sheppo * 191991Sheppo * CDDL HEADER END 201991Sheppo */ 211991Sheppo 221991Sheppo /* 235935Ssb155480 * Copyright 2008 Sun Microsystems, Inc. All rights reserved. 241991Sheppo * Use is subject to license terms. 251991Sheppo */ 261991Sheppo 271991Sheppo #include <sys/types.h> 281991Sheppo #include <sys/errno.h> 297529SSriharsha.Basavapatna@Sun.COM #include <sys/sysmacros.h> 301991Sheppo #include <sys/param.h> 311991Sheppo #include <sys/stream.h> 324647Sraghuram #include <sys/strsubr.h> 331991Sheppo #include <sys/kmem.h> 341991Sheppo #include <sys/conf.h> 351991Sheppo #include <sys/devops.h> 361991Sheppo #include <sys/ksynch.h> 371991Sheppo #include <sys/stat.h> 381991Sheppo #include <sys/modctl.h> 391991Sheppo #include <sys/debug.h> 401991Sheppo #include <sys/ethernet.h> 411991Sheppo #include <sys/ddi.h> 421991Sheppo #include <sys/sunddi.h> 431991Sheppo #include <sys/strsun.h> 441991Sheppo #include <sys/note.h> 451991Sheppo #include <sys/mac.h> 462311Sseb #include <sys/mac_ether.h> 471991Sheppo #include <sys/ldc.h> 481991Sheppo #include <sys/mach_descrip.h> 491991Sheppo #include <sys/mdeg.h> 504647Sraghuram #include <net/if.h> 514647Sraghuram #include <sys/vnet.h> 521991Sheppo #include <sys/vio_mailbox.h> 531991Sheppo #include <sys/vio_common.h> 541991Sheppo #include <sys/vnet_common.h> 552336Snarayan #include <sys/vnet_mailbox.h> 562336Snarayan #include <sys/vio_util.h> 571991Sheppo #include <sys/vnet_gen.h> 585935Ssb155480 #include <sys/atomic.h> 594647Sraghuram #include <sys/callb.h> 604647Sraghuram #include <sys/sdt.h> 614647Sraghuram #include <sys/intr.h> 624647Sraghuram #include <sys/pattr.h> 636419Ssb155480 #include <sys/vlan.h> 641991Sheppo 651991Sheppo /* 661991Sheppo * Implementation of the mac functionality for vnet using the 671991Sheppo * generic(default) transport layer of sun4v Logical Domain Channels(LDC). 681991Sheppo */ 691991Sheppo 701991Sheppo /* 711991Sheppo * Function prototypes. 721991Sheppo */ 731991Sheppo /* vgen proxy entry points */ 746495Sspeer int vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip, 756495Sspeer const uint8_t *macaddr, void **vgenhdl); 762336Snarayan int vgen_uninit(void *arg); 776495Sspeer int vgen_dds_tx(void *arg, void *dmsg); 781991Sheppo static int vgen_start(void *arg); 791991Sheppo static void vgen_stop(void *arg); 801991Sheppo static mblk_t *vgen_tx(void *arg, mblk_t *mp); 811991Sheppo static int vgen_multicst(void *arg, boolean_t add, 821991Sheppo const uint8_t *mca); 831991Sheppo static int vgen_promisc(void *arg, boolean_t on); 841991Sheppo static int vgen_unicst(void *arg, const uint8_t *mca); 852311Sseb static int vgen_stat(void *arg, uint_t stat, uint64_t *val); 861991Sheppo static void vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp); 871991Sheppo 881991Sheppo /* vgen internal functions */ 896419Ssb155480 static int vgen_read_mdprops(vgen_t *vgenp); 906419Ssb155480 static void vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 916419Ssb155480 static void vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp, 926419Ssb155480 mde_cookie_t node); 937529SSriharsha.Basavapatna@Sun.COM static void vgen_mtu_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node, 947529SSriharsha.Basavapatna@Sun.COM uint32_t *mtu); 951991Sheppo static void vgen_detach_ports(vgen_t *vgenp); 961991Sheppo static void vgen_port_detach(vgen_port_t *portp); 971991Sheppo static void vgen_port_list_insert(vgen_port_t *portp); 981991Sheppo static void vgen_port_list_remove(vgen_port_t *portp); 991991Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp, 1001991Sheppo int port_num); 1011991Sheppo static int vgen_mdeg_reg(vgen_t *vgenp); 1021991Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp); 1031991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 1046419Ssb155480 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp); 1051991Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 1066419Ssb155480 static int vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp, 1076419Ssb155480 mde_cookie_t mdex); 1081991Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 1096419Ssb155480 static int vgen_port_attach(vgen_port_t *portp); 1106419Ssb155480 static void vgen_port_detach_mdeg(vgen_port_t *portp); 1111991Sheppo static void vgen_port_detach_mdeg(vgen_port_t *portp); 1121991Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, 1131991Sheppo mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex); 1142311Sseb static uint64_t vgen_port_stat(vgen_port_t *portp, uint_t stat); 1151991Sheppo 1161991Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id); 1171991Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp); 1181991Sheppo static int vgen_alloc_tx_ring(vgen_ldc_t *ldcp); 1191991Sheppo static void vgen_free_tx_ring(vgen_ldc_t *ldcp); 1201991Sheppo static void vgen_init_ports(vgen_t *vgenp); 1211991Sheppo static void vgen_port_init(vgen_port_t *portp); 1221991Sheppo static void vgen_uninit_ports(vgen_t *vgenp); 1231991Sheppo static void vgen_port_uninit(vgen_port_t *portp); 1241991Sheppo static void vgen_init_ldcs(vgen_port_t *portp); 1251991Sheppo static void vgen_uninit_ldcs(vgen_port_t *portp); 1261991Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp); 1271991Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp); 1281991Sheppo static int vgen_init_tbufs(vgen_ldc_t *ldcp); 1291991Sheppo static void vgen_uninit_tbufs(vgen_ldc_t *ldcp); 1301991Sheppo static void vgen_clobber_tbufs(vgen_ldc_t *ldcp); 1311991Sheppo static void vgen_clobber_rxds(vgen_ldc_t *ldcp); 1322311Sseb static uint64_t vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat); 1331991Sheppo static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg); 1341991Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp); 1355935Ssb155480 static int vgen_ldcsend(void *arg, mblk_t *mp); 1365935Ssb155480 static void vgen_ldcsend_pkt(void *arg, mblk_t *mp); 1375935Ssb155480 static int vgen_ldcsend_dring(void *arg, mblk_t *mp); 1381991Sheppo static void vgen_reclaim(vgen_ldc_t *ldcp); 1391991Sheppo static void vgen_reclaim_dring(vgen_ldc_t *ldcp); 1401991Sheppo static int vgen_num_txpending(vgen_ldc_t *ldcp); 1411991Sheppo static int vgen_tx_dring_full(vgen_ldc_t *ldcp); 1421991Sheppo static int vgen_ldc_txtimeout(vgen_ldc_t *ldcp); 1431991Sheppo static void vgen_ldc_watchdog(void *arg); 1441991Sheppo 1451991Sheppo /* vgen handshake functions */ 1461991Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp); 1471991Sheppo static int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen, 1481991Sheppo boolean_t caller_holds_lock); 1491991Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp); 1501991Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp); 1511991Sheppo static int vgen_send_dring_reg(vgen_ldc_t *ldcp); 1521991Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp); 1532336Snarayan static int vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end); 1541991Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp); 1551991Sheppo static int vgen_handshake_phase2(vgen_ldc_t *ldcp); 1561991Sheppo static void vgen_handshake_reset(vgen_ldc_t *ldcp); 1571991Sheppo static void vgen_reset_hphase(vgen_ldc_t *ldcp); 1581991Sheppo static void vgen_handshake(vgen_ldc_t *ldcp); 1591991Sheppo static int vgen_handshake_done(vgen_ldc_t *ldcp); 1601991Sheppo static void vgen_handshake_retry(vgen_ldc_t *ldcp); 1612793Slm66018 static int vgen_handle_version_negotiate(vgen_ldc_t *ldcp, 1621991Sheppo vio_msg_tag_t *tagp); 1632793Slm66018 static int vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1642793Slm66018 static int vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1652793Slm66018 static int vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1662793Slm66018 static int vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1672793Slm66018 static int vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1685935Ssb155480 static void vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen); 1695935Ssb155480 static void vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen); 1704647Sraghuram static int vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1714647Sraghuram static int vgen_handle_dring_data_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1724647Sraghuram static int vgen_process_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1734647Sraghuram static int vgen_handle_dring_data_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1744647Sraghuram static int vgen_handle_dring_data_nack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1752793Slm66018 static int vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 1762336Snarayan uint32_t start, int32_t end, uint8_t pstate); 1775935Ssb155480 static int vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 1785935Ssb155480 uint32_t msglen); 1791991Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1806495Sspeer static void vgen_handle_evt_up(vgen_ldc_t *ldcp); 1816495Sspeer static void vgen_handle_evt_reset(vgen_ldc_t *ldcp); 1821991Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1835935Ssb155480 static int vgen_check_datamsg_seq(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1841991Sheppo static caddr_t vgen_print_ethaddr(uint8_t *a, char *ebuf); 1851991Sheppo static void vgen_hwatchdog(void *arg); 1861991Sheppo static void vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint); 1871991Sheppo static void vgen_print_hparams(vgen_hparams_t *hp); 1881991Sheppo static void vgen_print_ldcinfo(vgen_ldc_t *ldcp); 1894647Sraghuram static void vgen_stop_rcv_thread(vgen_ldc_t *ldcp); 1904647Sraghuram static void vgen_ldc_rcv_worker(void *arg); 1914647Sraghuram static void vgen_handle_evt_read(vgen_ldc_t *ldcp); 1925935Ssb155480 static void vgen_rx(vgen_ldc_t *ldcp, mblk_t *bp); 1935935Ssb155480 static void vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp); 1945935Ssb155480 static void vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp); 1951991Sheppo 1966419Ssb155480 /* VLAN routines */ 1976419Ssb155480 static void vgen_vlan_read_ids(void *arg, int type, md_t *mdp, 1986419Ssb155480 mde_cookie_t node, uint16_t *pvidp, uint16_t **vidspp, 1996419Ssb155480 uint16_t *nvidsp, uint16_t *default_idp); 2006419Ssb155480 static void vgen_vlan_create_hash(vgen_port_t *portp); 2016419Ssb155480 static void vgen_vlan_destroy_hash(vgen_port_t *portp); 2026419Ssb155480 static void vgen_vlan_add_ids(vgen_port_t *portp); 2036419Ssb155480 static void vgen_vlan_remove_ids(vgen_port_t *portp); 2046419Ssb155480 static boolean_t vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid); 2056419Ssb155480 static boolean_t vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp, 2066419Ssb155480 uint16_t *vidp); 2076419Ssb155480 static mblk_t *vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp, 2086419Ssb155480 boolean_t is_tagged, uint16_t vid); 2096419Ssb155480 static void vgen_vlan_unaware_port_reset(vgen_port_t *portp); 2106419Ssb155480 static void vgen_reset_vlan_unaware_ports(vgen_t *vgenp); 2116495Sspeer static int vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 2126495Sspeer 2136495Sspeer /* externs */ 2146495Sspeer extern void vnet_dds_rx(void *arg, void *dmsg); 2157529SSriharsha.Basavapatna@Sun.COM extern int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu); 2166419Ssb155480 2171991Sheppo /* 2181991Sheppo * The handshake process consists of 5 phases defined below, with VH_PHASE0 2191991Sheppo * being the pre-handshake phase and VH_DONE is the phase to indicate 2201991Sheppo * successful completion of all phases. 2211991Sheppo * Each phase may have one to several handshake states which are required 2221991Sheppo * to complete successfully to move to the next phase. 2231991Sheppo * Refer to the functions vgen_handshake() and vgen_handshake_done() for 2241991Sheppo * more details. 2251991Sheppo */ 2261991Sheppo /* handshake phases */ 2271991Sheppo enum { VH_PHASE0, VH_PHASE1, VH_PHASE2, VH_PHASE3, VH_DONE = 0x80 }; 2281991Sheppo 2291991Sheppo /* handshake states */ 2301991Sheppo enum { 2311991Sheppo 2321991Sheppo VER_INFO_SENT = 0x1, 2331991Sheppo VER_ACK_RCVD = 0x2, 2341991Sheppo VER_INFO_RCVD = 0x4, 2351991Sheppo VER_ACK_SENT = 0x8, 2361991Sheppo VER_NEGOTIATED = (VER_ACK_RCVD | VER_ACK_SENT), 2371991Sheppo 2381991Sheppo ATTR_INFO_SENT = 0x10, 2391991Sheppo ATTR_ACK_RCVD = 0x20, 2401991Sheppo ATTR_INFO_RCVD = 0x40, 2411991Sheppo ATTR_ACK_SENT = 0x80, 2421991Sheppo ATTR_INFO_EXCHANGED = (ATTR_ACK_RCVD | ATTR_ACK_SENT), 2431991Sheppo 2441991Sheppo DRING_INFO_SENT = 0x100, 2451991Sheppo DRING_ACK_RCVD = 0x200, 2461991Sheppo DRING_INFO_RCVD = 0x400, 2471991Sheppo DRING_ACK_SENT = 0x800, 2481991Sheppo DRING_INFO_EXCHANGED = (DRING_ACK_RCVD | DRING_ACK_SENT), 2491991Sheppo 2501991Sheppo RDX_INFO_SENT = 0x1000, 2511991Sheppo RDX_ACK_RCVD = 0x2000, 2521991Sheppo RDX_INFO_RCVD = 0x4000, 2531991Sheppo RDX_ACK_SENT = 0x8000, 2541991Sheppo RDX_EXCHANGED = (RDX_ACK_RCVD | RDX_ACK_SENT) 2551991Sheppo 2561991Sheppo }; 2571991Sheppo 2585935Ssb155480 #define VGEN_PRI_ETH_DEFINED(vgenp) ((vgenp)->pri_num_types != 0) 2595935Ssb155480 2601991Sheppo #define LDC_LOCK(ldcp) \ 2611991Sheppo mutex_enter(&((ldcp)->cblock));\ 2624647Sraghuram mutex_enter(&((ldcp)->rxlock));\ 2634647Sraghuram mutex_enter(&((ldcp)->wrlock));\ 2641991Sheppo mutex_enter(&((ldcp)->txlock));\ 2651991Sheppo mutex_enter(&((ldcp)->tclock)); 2661991Sheppo #define LDC_UNLOCK(ldcp) \ 2671991Sheppo mutex_exit(&((ldcp)->tclock));\ 2681991Sheppo mutex_exit(&((ldcp)->txlock));\ 2694647Sraghuram mutex_exit(&((ldcp)->wrlock));\ 2704647Sraghuram mutex_exit(&((ldcp)->rxlock));\ 2711991Sheppo mutex_exit(&((ldcp)->cblock)); 2721991Sheppo 2736419Ssb155480 #define VGEN_VER_EQ(ldcp, major, minor) \ 2746419Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \ 2756419Ssb155480 (ldcp)->local_hparams.ver_minor == (minor)) 2766419Ssb155480 2776419Ssb155480 #define VGEN_VER_LT(ldcp, major, minor) \ 2786419Ssb155480 (((ldcp)->local_hparams.ver_major < (major)) || \ 2796419Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \ 2806419Ssb155480 (ldcp)->local_hparams.ver_minor < (minor))) 2816419Ssb155480 2826419Ssb155480 #define VGEN_VER_GTEQ(ldcp, major, minor) \ 2836419Ssb155480 (((ldcp)->local_hparams.ver_major > (major)) || \ 2846419Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \ 2856419Ssb155480 (ldcp)->local_hparams.ver_minor >= (minor))) 2866419Ssb155480 2871991Sheppo static struct ether_addr etherbroadcastaddr = { 2881991Sheppo 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2891991Sheppo }; 2901991Sheppo /* 2911991Sheppo * MIB II broadcast/multicast packets 2921991Sheppo */ 2931991Sheppo #define IS_BROADCAST(ehp) \ 2941991Sheppo (ether_cmp(&ehp->ether_dhost, ðerbroadcastaddr) == 0) 2951991Sheppo #define IS_MULTICAST(ehp) \ 2961991Sheppo ((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1) 2971991Sheppo 2981991Sheppo /* 2991991Sheppo * Property names 3001991Sheppo */ 3011991Sheppo static char macaddr_propname[] = "mac-address"; 3021991Sheppo static char rmacaddr_propname[] = "remote-mac-address"; 3031991Sheppo static char channel_propname[] = "channel-endpoint"; 3041991Sheppo static char reg_propname[] = "reg"; 3051991Sheppo static char port_propname[] = "port"; 3061991Sheppo static char swport_propname[] = "switch-port"; 3071991Sheppo static char id_propname[] = "id"; 3085935Ssb155480 static char vdev_propname[] = "virtual-device"; 3095935Ssb155480 static char vnet_propname[] = "network"; 3105935Ssb155480 static char pri_types_propname[] = "priority-ether-types"; 3116419Ssb155480 static char vgen_pvid_propname[] = "port-vlan-id"; 3126419Ssb155480 static char vgen_vid_propname[] = "vlan-id"; 3136419Ssb155480 static char vgen_dvid_propname[] = "default-vlan-id"; 3146419Ssb155480 static char port_pvid_propname[] = "remote-port-vlan-id"; 3156419Ssb155480 static char port_vid_propname[] = "remote-vlan-id"; 3167529SSriharsha.Basavapatna@Sun.COM static char vgen_mtu_propname[] = "mtu"; 3171991Sheppo 3181991Sheppo /* versions supported - in decreasing order */ 3197529SSriharsha.Basavapatna@Sun.COM static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 4} }; 3201991Sheppo 3211991Sheppo /* Tunables */ 3225171Ssb155480 uint32_t vgen_hwd_interval = 5; /* handshake watchdog freq in sec */ 3233297Ssb155480 uint32_t vgen_max_hretries = VNET_NUM_HANDSHAKES; /* # of handshake retries */ 3241991Sheppo uint32_t vgen_ldcwr_retries = 10; /* max # of ldc_write() retries */ 3252109Slm66018 uint32_t vgen_ldcup_retries = 5; /* max # of ldc_up() retries */ 3262336Snarayan uint32_t vgen_recv_delay = 1; /* delay when rx descr not ready */ 3272336Snarayan uint32_t vgen_recv_retries = 10; /* retry when rx descr not ready */ 3285022Sraghuram uint32_t vgen_tx_retries = 0x4; /* retry when tx descr not available */ 3295022Sraghuram uint32_t vgen_tx_delay = 0x30; /* delay when tx descr not available */ 3301991Sheppo 3314647Sraghuram int vgen_rcv_thread_enabled = 1; /* Enable Recieve thread */ 3324647Sraghuram 3334647Sraghuram /* 3344647Sraghuram * max # of packets accumulated prior to sending them up. It is best 3354647Sraghuram * to keep this at 60% of the number of recieve buffers. 3364647Sraghuram */ 3374647Sraghuram uint32_t vgen_chain_len = (VGEN_NRBUFS * 0.6); 3384647Sraghuram 3394647Sraghuram /* 3407529SSriharsha.Basavapatna@Sun.COM * Internal tunables for receive buffer pools, that is, the size and number of 3417529SSriharsha.Basavapatna@Sun.COM * mblks for each pool. At least 3 sizes must be specified if these are used. 3427529SSriharsha.Basavapatna@Sun.COM * The sizes must be specified in increasing order. Non-zero value of the first 3437529SSriharsha.Basavapatna@Sun.COM * size will be used as a hint to use these values instead of the algorithm 3447529SSriharsha.Basavapatna@Sun.COM * that determines the sizes based on MTU. 3454647Sraghuram */ 3467529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz1 = 0; 3477529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz2 = 0; 3487529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz3 = 0; 3497529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz4 = 0; 3504647Sraghuram 3514647Sraghuram uint32_t vgen_nrbufs1 = VGEN_NRBUFS; 3524647Sraghuram uint32_t vgen_nrbufs2 = VGEN_NRBUFS; 3534647Sraghuram uint32_t vgen_nrbufs3 = VGEN_NRBUFS; 3547529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_nrbufs4 = VGEN_NRBUFS; 3554647Sraghuram 3565935Ssb155480 /* 3575935Ssb155480 * In the absence of "priority-ether-types" property in MD, the following 3585935Ssb155480 * internal tunable can be set to specify a single priority ethertype. 3595935Ssb155480 */ 3605935Ssb155480 uint64_t vgen_pri_eth_type = 0; 3615935Ssb155480 3625935Ssb155480 /* 3635935Ssb155480 * Number of transmit priority buffers that are preallocated per device. 3645935Ssb155480 * This number is chosen to be a small value to throttle transmission 3655935Ssb155480 * of priority packets. Note: Must be a power of 2 for vio_create_mblks(). 3665935Ssb155480 */ 3675935Ssb155480 uint32_t vgen_pri_tx_nmblks = 64; 3685935Ssb155480 3696419Ssb155480 uint32_t vgen_vlan_nchains = 4; /* # of chains in vlan id hash table */ 3706419Ssb155480 3711991Sheppo #ifdef DEBUG 3721991Sheppo /* flags to simulate error conditions for debugging */ 3731991Sheppo int vgen_trigger_txtimeout = 0; 3741991Sheppo int vgen_trigger_rxlost = 0; 3751991Sheppo #endif 3761991Sheppo 3776419Ssb155480 /* 3786419Ssb155480 * Matching criteria passed to the MDEG to register interest 3796419Ssb155480 * in changes to 'virtual-device' nodes (i.e. vnet nodes) identified 3806419Ssb155480 * by their 'name' and 'cfg-handle' properties. 3816419Ssb155480 */ 3826419Ssb155480 static md_prop_match_t vdev_prop_match[] = { 3836419Ssb155480 { MDET_PROP_STR, "name" }, 3846419Ssb155480 { MDET_PROP_VAL, "cfg-handle" }, 3856419Ssb155480 { MDET_LIST_END, NULL } 3866419Ssb155480 }; 3876419Ssb155480 3886419Ssb155480 static mdeg_node_match_t vdev_match = { "virtual-device", 3896419Ssb155480 vdev_prop_match }; 3906419Ssb155480 3911991Sheppo /* MD update matching structure */ 3921991Sheppo static md_prop_match_t vport_prop_match[] = { 3931991Sheppo { MDET_PROP_VAL, "id" }, 3941991Sheppo { MDET_LIST_END, NULL } 3951991Sheppo }; 3961991Sheppo 3971991Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port", 3981991Sheppo vport_prop_match }; 3991991Sheppo 4001991Sheppo /* template for matching a particular vnet instance */ 4011991Sheppo static mdeg_prop_spec_t vgen_prop_template[] = { 4021991Sheppo { MDET_PROP_STR, "name", "network" }, 4031991Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 4041991Sheppo { MDET_LIST_END, NULL, NULL } 4051991Sheppo }; 4061991Sheppo 4071991Sheppo #define VGEN_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val) 4081991Sheppo 4096419Ssb155480 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp); 4101991Sheppo 4112311Sseb static mac_callbacks_t vgen_m_callbacks = { 4122311Sseb 0, 4132311Sseb vgen_stat, 4142311Sseb vgen_start, 4152311Sseb vgen_stop, 4162311Sseb vgen_promisc, 4172311Sseb vgen_multicst, 4182311Sseb vgen_unicst, 4192311Sseb vgen_tx, 4202311Sseb NULL, 4212311Sseb NULL, 4222311Sseb NULL 4232311Sseb }; 4242311Sseb 4251991Sheppo /* externs */ 4264647Sraghuram extern pri_t maxclsyspri; 4274647Sraghuram extern proc_t p0; 4281991Sheppo extern uint32_t vnet_ntxds; 4291991Sheppo extern uint32_t vnet_ldcwd_interval; 4301991Sheppo extern uint32_t vnet_ldcwd_txtimeout; 4312410Slm66018 extern uint32_t vnet_ldc_mtu; 4322336Snarayan extern uint32_t vnet_nrbufs; 4336419Ssb155480 extern uint32_t vnet_ethermtu; 4346419Ssb155480 extern uint16_t vnet_default_vlan_id; 4357529SSriharsha.Basavapatna@Sun.COM extern boolean_t vnet_jumbo_rxpools; 4361991Sheppo 4371991Sheppo #ifdef DEBUG 4381991Sheppo 4394647Sraghuram extern int vnet_dbglevel; 4404647Sraghuram static void debug_printf(const char *fname, vgen_t *vgenp, 4414647Sraghuram vgen_ldc_t *ldcp, const char *fmt, ...); 4424647Sraghuram 4434647Sraghuram /* -1 for all LDCs info, or ldc_id for a specific LDC info */ 4444647Sraghuram int vgendbg_ldcid = -1; 4451991Sheppo 4461991Sheppo /* simulate handshake error conditions for debug */ 4471991Sheppo uint32_t vgen_hdbg; 4481991Sheppo #define HDBG_VERSION 0x1 4491991Sheppo #define HDBG_TIMEOUT 0x2 4501991Sheppo #define HDBG_BAD_SID 0x4 4511991Sheppo #define HDBG_OUT_STATE 0x8 4521991Sheppo 4531991Sheppo #endif 4541991Sheppo 4551991Sheppo /* 4561991Sheppo * vgen_init() is called by an instance of vnet driver to initialize the 4571991Sheppo * corresponding generic proxy transport layer. The arguments passed by vnet 4581991Sheppo * are - an opaque pointer to the vnet instance, pointers to dev_info_t and 4596495Sspeer * the mac address of the vnet device, and a pointer to vgen_t is passed 4606495Sspeer * back as a handle to vnet. 4611991Sheppo */ 4621991Sheppo int 4636495Sspeer vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip, 4646495Sspeer const uint8_t *macaddr, void **vgenhdl) 4651991Sheppo { 4661991Sheppo vgen_t *vgenp; 4671991Sheppo int instance; 4685935Ssb155480 int rv; 4691991Sheppo 4702311Sseb if ((vnetp == NULL) || (vnetdip == NULL)) 4711991Sheppo return (DDI_FAILURE); 4721991Sheppo 4731991Sheppo instance = ddi_get_instance(vnetdip); 4741991Sheppo 4755373Sraghuram DBG1(NULL, NULL, "vnet(%d): enter\n", instance); 4761991Sheppo 4771991Sheppo vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP); 4781991Sheppo 4791991Sheppo vgenp->vnetp = vnetp; 4806495Sspeer vgenp->instance = instance; 4816495Sspeer vgenp->regprop = regprop; 4821991Sheppo vgenp->vnetdip = vnetdip; 4831991Sheppo bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL); 4841991Sheppo 4851991Sheppo /* allocate multicast table */ 4861991Sheppo vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE * 4871991Sheppo sizeof (struct ether_addr), KM_SLEEP); 4881991Sheppo vgenp->mccount = 0; 4891991Sheppo vgenp->mcsize = VGEN_INIT_MCTAB_SIZE; 4901991Sheppo 4911991Sheppo mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL); 4925641Swentaoy rw_init(&vgenp->vgenports.rwlock, NULL, RW_DRIVER, NULL); 4931991Sheppo 4945935Ssb155480 rv = vgen_read_mdprops(vgenp); 4955935Ssb155480 if (rv != 0) { 4965935Ssb155480 goto vgen_init_fail; 4975935Ssb155480 } 4985935Ssb155480 4991991Sheppo /* register with MD event generator */ 5005935Ssb155480 rv = vgen_mdeg_reg(vgenp); 5015935Ssb155480 if (rv != DDI_SUCCESS) { 5025935Ssb155480 goto vgen_init_fail; 5031991Sheppo } 5041991Sheppo 5056495Sspeer *vgenhdl = (void *)vgenp; 5061991Sheppo 5075373Sraghuram DBG1(NULL, NULL, "vnet(%d): exit\n", instance); 5081991Sheppo return (DDI_SUCCESS); 5095935Ssb155480 5105935Ssb155480 vgen_init_fail: 5115935Ssb155480 rw_destroy(&vgenp->vgenports.rwlock); 5125935Ssb155480 mutex_destroy(&vgenp->lock); 5135935Ssb155480 kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE * 5145935Ssb155480 sizeof (struct ether_addr)); 5155935Ssb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) { 5165935Ssb155480 kmem_free(vgenp->pri_types, 5175935Ssb155480 sizeof (uint16_t) * vgenp->pri_num_types); 5185935Ssb155480 (void) vio_destroy_mblks(vgenp->pri_tx_vmp); 5195935Ssb155480 } 5205935Ssb155480 KMEM_FREE(vgenp); 5215935Ssb155480 return (DDI_FAILURE); 5221991Sheppo } 5231991Sheppo 5241991Sheppo /* 5251991Sheppo * Called by vnet to undo the initializations done by vgen_init(). 5261991Sheppo * The handle provided by generic transport during vgen_init() is the argument. 5271991Sheppo */ 5282336Snarayan int 5291991Sheppo vgen_uninit(void *arg) 5301991Sheppo { 5315935Ssb155480 vgen_t *vgenp = (vgen_t *)arg; 5325935Ssb155480 vio_mblk_pool_t *rp; 5335935Ssb155480 vio_mblk_pool_t *nrp; 5342336Snarayan 5352336Snarayan if (vgenp == NULL) { 5362336Snarayan return (DDI_FAILURE); 5372336Snarayan } 5381991Sheppo 5394647Sraghuram DBG1(vgenp, NULL, "enter\n"); 5401991Sheppo 5411991Sheppo /* unregister with MD event generator */ 5421991Sheppo vgen_mdeg_unreg(vgenp); 5431991Sheppo 5441991Sheppo mutex_enter(&vgenp->lock); 5451991Sheppo 5461991Sheppo /* detach all ports from the device */ 5471991Sheppo vgen_detach_ports(vgenp); 5481991Sheppo 5492336Snarayan /* 5502336Snarayan * free any pending rx mblk pools, 5512336Snarayan * that couldn't be freed previously during channel detach. 5522336Snarayan */ 5532336Snarayan rp = vgenp->rmp; 5542336Snarayan while (rp != NULL) { 5552336Snarayan nrp = vgenp->rmp = rp->nextp; 5562336Snarayan if (vio_destroy_mblks(rp)) { 5572336Snarayan vgenp->rmp = rp; 5582336Snarayan mutex_exit(&vgenp->lock); 5592336Snarayan return (DDI_FAILURE); 5602336Snarayan } 5612336Snarayan rp = nrp; 5622336Snarayan } 5632336Snarayan 5641991Sheppo /* free multicast table */ 5651991Sheppo kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr)); 5661991Sheppo 5675935Ssb155480 /* free pri_types table */ 5685935Ssb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) { 5695935Ssb155480 kmem_free(vgenp->pri_types, 5705935Ssb155480 sizeof (uint16_t) * vgenp->pri_num_types); 5715935Ssb155480 (void) vio_destroy_mblks(vgenp->pri_tx_vmp); 5725935Ssb155480 } 5735935Ssb155480 5741991Sheppo mutex_exit(&vgenp->lock); 5751991Sheppo 5765641Swentaoy rw_destroy(&vgenp->vgenports.rwlock); 5771991Sheppo mutex_destroy(&vgenp->lock); 5781991Sheppo 579*7572SWentao.Yang@Sun.COM DBG1(vgenp, NULL, "exit\n"); 5801991Sheppo KMEM_FREE(vgenp); 5811991Sheppo 5822336Snarayan return (DDI_SUCCESS); 5831991Sheppo } 5841991Sheppo 5851991Sheppo /* enable transmit/receive for the device */ 5862311Sseb int 5871991Sheppo vgen_start(void *arg) 5881991Sheppo { 5896495Sspeer vgen_port_t *portp = (vgen_port_t *)arg; 5906495Sspeer vgen_t *vgenp = portp->vgenp; 5911991Sheppo 5924647Sraghuram DBG1(vgenp, NULL, "enter\n"); 5936495Sspeer mutex_enter(&portp->lock); 5946495Sspeer vgen_port_init(portp); 5956495Sspeer portp->flags |= VGEN_STARTED; 5966495Sspeer mutex_exit(&portp->lock); 5974647Sraghuram DBG1(vgenp, NULL, "exit\n"); 5986495Sspeer 5991991Sheppo return (DDI_SUCCESS); 6001991Sheppo } 6011991Sheppo 6021991Sheppo /* stop transmit/receive */ 6032311Sseb void 6041991Sheppo vgen_stop(void *arg) 6051991Sheppo { 6066495Sspeer vgen_port_t *portp = (vgen_port_t *)arg; 6076495Sspeer vgen_t *vgenp = portp->vgenp; 6081991Sheppo 6094647Sraghuram DBG1(vgenp, NULL, "enter\n"); 6101991Sheppo 6116495Sspeer mutex_enter(&portp->lock); 6126495Sspeer vgen_port_uninit(portp); 6136495Sspeer portp->flags &= ~(VGEN_STARTED); 6146495Sspeer mutex_exit(&portp->lock); 6154647Sraghuram DBG1(vgenp, NULL, "exit\n"); 6166495Sspeer 6171991Sheppo } 6181991Sheppo 6191991Sheppo /* vgen transmit function */ 6201991Sheppo static mblk_t * 6211991Sheppo vgen_tx(void *arg, mblk_t *mp) 6221991Sheppo { 6235022Sraghuram int i; 6241991Sheppo vgen_port_t *portp; 6255022Sraghuram int status = VGEN_FAILURE; 6261991Sheppo 6271991Sheppo portp = (vgen_port_t *)arg; 6285022Sraghuram /* 6295022Sraghuram * Retry so that we avoid reporting a failure 6305022Sraghuram * to the upper layer. Returning a failure may cause the 6315022Sraghuram * upper layer to go into single threaded mode there by 6325022Sraghuram * causing performance degradation, especially for a large 6335022Sraghuram * number of connections. 6345022Sraghuram */ 6355022Sraghuram for (i = 0; i < vgen_tx_retries; ) { 6365022Sraghuram status = vgen_portsend(portp, mp); 6375022Sraghuram if (status == VGEN_SUCCESS) { 6385022Sraghuram break; 6395022Sraghuram } 6405022Sraghuram if (++i < vgen_tx_retries) 6415022Sraghuram delay(drv_usectohz(vgen_tx_delay)); 6425022Sraghuram } 6431991Sheppo if (status != VGEN_SUCCESS) { 6441991Sheppo /* failure */ 6451991Sheppo return (mp); 6461991Sheppo } 6471991Sheppo /* success */ 6481991Sheppo return (NULL); 6491991Sheppo } 6501991Sheppo 6516419Ssb155480 /* 6526419Ssb155480 * This function provides any necessary tagging/untagging of the frames 6536419Ssb155480 * that are being transmitted over the port. It first verifies the vlan 6546419Ssb155480 * membership of the destination(port) and drops the packet if the 6556419Ssb155480 * destination doesn't belong to the given vlan. 6566419Ssb155480 * 6576419Ssb155480 * Arguments: 6586419Ssb155480 * portp: port over which the frames should be transmitted 6596419Ssb155480 * mp: frame to be transmitted 6606419Ssb155480 * is_tagged: 6616419Ssb155480 * B_TRUE: indicates frame header contains the vlan tag already. 6626419Ssb155480 * B_FALSE: indicates frame is untagged. 6636419Ssb155480 * vid: vlan in which the frame should be transmitted. 6646419Ssb155480 * 6656419Ssb155480 * Returns: 6666419Ssb155480 * Sucess: frame(mblk_t *) after doing the necessary tag/untag. 6676419Ssb155480 * Failure: NULL 6686419Ssb155480 */ 6696419Ssb155480 static mblk_t * 6706419Ssb155480 vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp, boolean_t is_tagged, 6716419Ssb155480 uint16_t vid) 6726419Ssb155480 { 6736419Ssb155480 vgen_t *vgenp; 6746419Ssb155480 boolean_t dst_tagged; 6756419Ssb155480 int rv; 6766419Ssb155480 6776419Ssb155480 vgenp = portp->vgenp; 6786419Ssb155480 6796419Ssb155480 /* 6806419Ssb155480 * If the packet is going to a vnet: 6816419Ssb155480 * Check if the destination vnet is in the same vlan. 6826419Ssb155480 * Check the frame header if tag or untag is needed. 6836419Ssb155480 * 6846419Ssb155480 * We do not check the above conditions if the packet is going to vsw: 6856419Ssb155480 * vsw must be present implicitly in all the vlans that a vnet device 6866419Ssb155480 * is configured into; even if vsw itself is not assigned to those 6876419Ssb155480 * vlans as an interface. For instance, the packet might be destined 6886419Ssb155480 * to another vnet(indirectly through vsw) or to an external host 6896419Ssb155480 * which is in the same vlan as this vnet and vsw itself may not be 6906419Ssb155480 * present in that vlan. Similarly packets going to vsw must be 6916419Ssb155480 * always tagged(unless in the default-vlan) if not already tagged, 6926419Ssb155480 * as we do not know the final destination. This is needed because 6936419Ssb155480 * vsw must always invoke its switching function only after tagging 6946419Ssb155480 * the packet; otherwise after switching function determines the 6956419Ssb155480 * destination we cannot figure out if the destination belongs to the 6966419Ssb155480 * the same vlan that the frame originated from and if it needs tag/ 6976419Ssb155480 * untag. Note that vsw will tag the packet itself when it receives 6986419Ssb155480 * it over the channel from a client if needed. However, that is 6996419Ssb155480 * needed only in the case of vlan unaware clients such as obp or 7006419Ssb155480 * earlier versions of vnet. 7016419Ssb155480 * 7026419Ssb155480 */ 7036419Ssb155480 if (portp != vgenp->vsw_portp) { 7046419Ssb155480 /* 7056419Ssb155480 * Packet going to a vnet. Check if the destination vnet is in 7066419Ssb155480 * the same vlan. Then check the frame header if tag/untag is 7076419Ssb155480 * needed. 7086419Ssb155480 */ 7096419Ssb155480 rv = vgen_vlan_lookup(portp->vlan_hashp, vid); 7106419Ssb155480 if (rv == B_FALSE) { 7116419Ssb155480 /* drop the packet */ 7126419Ssb155480 freemsg(mp); 7136419Ssb155480 return (NULL); 7146419Ssb155480 } 7156419Ssb155480 7166419Ssb155480 /* is the destination tagged or untagged in this vlan? */ 7176419Ssb155480 (vid == portp->pvid) ? (dst_tagged = B_FALSE) : 7186419Ssb155480 (dst_tagged = B_TRUE); 7196419Ssb155480 7206419Ssb155480 if (is_tagged == dst_tagged) { 7216419Ssb155480 /* no tagging/untagging needed */ 7226419Ssb155480 return (mp); 7236419Ssb155480 } 7246419Ssb155480 7256419Ssb155480 if (is_tagged == B_TRUE) { 7266419Ssb155480 /* frame is tagged; destination needs untagged */ 7276419Ssb155480 mp = vnet_vlan_remove_tag(mp); 7286419Ssb155480 return (mp); 7296419Ssb155480 } 7306419Ssb155480 7316419Ssb155480 /* (is_tagged == B_FALSE): fallthru to tag tx packet: */ 7326419Ssb155480 } 7336419Ssb155480 7346419Ssb155480 /* 7356419Ssb155480 * Packet going to a vnet needs tagging. 7366419Ssb155480 * OR 7376419Ssb155480 * If the packet is going to vsw, then it must be tagged in all cases: 7386419Ssb155480 * unknown unicast, broadcast/multicast or to vsw interface. 7396419Ssb155480 */ 7406419Ssb155480 7416419Ssb155480 if (is_tagged == B_FALSE) { 7426419Ssb155480 mp = vnet_vlan_insert_tag(mp, vid); 7436419Ssb155480 } 7446419Ssb155480 7456419Ssb155480 return (mp); 7466419Ssb155480 } 7476419Ssb155480 7481991Sheppo /* transmit packets over the given port */ 7491991Sheppo static int 7501991Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp) 7511991Sheppo { 7526419Ssb155480 vgen_ldclist_t *ldclp; 7536419Ssb155480 vgen_ldc_t *ldcp; 7546419Ssb155480 int status; 7556419Ssb155480 int rv = VGEN_SUCCESS; 7566495Sspeer vgen_t *vgenp = portp->vgenp; 7576495Sspeer vnet_t *vnetp = vgenp->vnetp; 7586419Ssb155480 boolean_t is_tagged; 7596495Sspeer boolean_t dec_refcnt = B_FALSE; 7606419Ssb155480 uint16_t vlan_id; 7616419Ssb155480 struct ether_header *ehp; 7626419Ssb155480 7636495Sspeer if (portp->use_vsw_port) { 7646495Sspeer (void) atomic_inc_32(&vgenp->vsw_port_refcnt); 7656495Sspeer portp = portp->vgenp->vsw_portp; 7666495Sspeer dec_refcnt = B_TRUE; 7676495Sspeer } 7686495Sspeer if (portp == NULL) { 7696495Sspeer return (VGEN_FAILURE); 7706495Sspeer } 7716419Ssb155480 7726419Ssb155480 /* 7736419Ssb155480 * Determine the vlan id that the frame belongs to. 7746419Ssb155480 */ 7756419Ssb155480 ehp = (struct ether_header *)mp->b_rptr; 7766419Ssb155480 is_tagged = vgen_frame_lookup_vid(vnetp, ehp, &vlan_id); 7776419Ssb155480 7786419Ssb155480 if (vlan_id == vnetp->default_vlan_id) { 7796419Ssb155480 7806419Ssb155480 /* Frames in default vlan must be untagged */ 7816419Ssb155480 ASSERT(is_tagged == B_FALSE); 7826419Ssb155480 7836419Ssb155480 /* 7846419Ssb155480 * If the destination is a vnet-port verify it belongs to the 7856419Ssb155480 * default vlan; otherwise drop the packet. We do not need 7866419Ssb155480 * this check for vsw-port, as it should implicitly belong to 7876419Ssb155480 * this vlan; see comments in vgen_vlan_frame_fixtag(). 7886419Ssb155480 */ 7896419Ssb155480 if (portp != vgenp->vsw_portp && 7906419Ssb155480 portp->pvid != vnetp->default_vlan_id) { 7916419Ssb155480 freemsg(mp); 7926495Sspeer goto portsend_ret; 7936419Ssb155480 } 7946419Ssb155480 7956419Ssb155480 } else { /* frame not in default-vlan */ 7966419Ssb155480 7976419Ssb155480 mp = vgen_vlan_frame_fixtag(portp, mp, is_tagged, vlan_id); 7986419Ssb155480 if (mp == NULL) { 7996495Sspeer goto portsend_ret; 8006419Ssb155480 } 8016419Ssb155480 8026419Ssb155480 } 8031991Sheppo 8041991Sheppo ldclp = &portp->ldclist; 8051991Sheppo READ_ENTER(&ldclp->rwlock); 8061991Sheppo /* 8072336Snarayan * NOTE: for now, we will assume we have a single channel. 8081991Sheppo */ 8091991Sheppo if (ldclp->headp == NULL) { 8101991Sheppo RW_EXIT(&ldclp->rwlock); 8116495Sspeer rv = VGEN_FAILURE; 8126495Sspeer goto portsend_ret; 8131991Sheppo } 8141991Sheppo ldcp = ldclp->headp; 8151991Sheppo 8165935Ssb155480 status = ldcp->tx(ldcp, mp); 8175022Sraghuram 8181991Sheppo RW_EXIT(&ldclp->rwlock); 8191991Sheppo 8205022Sraghuram if (status != VGEN_TX_SUCCESS) { 8215022Sraghuram rv = VGEN_FAILURE; 8225022Sraghuram } 8236495Sspeer 8246495Sspeer portsend_ret: 8256495Sspeer if (dec_refcnt == B_TRUE) { 8266495Sspeer (void) atomic_dec_32(&vgenp->vsw_port_refcnt); 8276495Sspeer } 8285022Sraghuram return (rv); 8291991Sheppo } 8301991Sheppo 8315935Ssb155480 /* 8325935Ssb155480 * Wrapper function to transmit normal and/or priority frames over the channel. 8335935Ssb155480 */ 8341991Sheppo static int 8355935Ssb155480 vgen_ldcsend(void *arg, mblk_t *mp) 8365935Ssb155480 { 8375935Ssb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 8385935Ssb155480 int status; 8395935Ssb155480 struct ether_header *ehp; 8405935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 8415935Ssb155480 uint32_t num_types; 8425935Ssb155480 uint16_t *types; 8435935Ssb155480 int i; 8445935Ssb155480 8455935Ssb155480 ASSERT(VGEN_PRI_ETH_DEFINED(vgenp)); 8465935Ssb155480 8475935Ssb155480 num_types = vgenp->pri_num_types; 8485935Ssb155480 types = vgenp->pri_types; 8495935Ssb155480 ehp = (struct ether_header *)mp->b_rptr; 8505935Ssb155480 8515935Ssb155480 for (i = 0; i < num_types; i++) { 8525935Ssb155480 8535935Ssb155480 if (ehp->ether_type == types[i]) { 8545935Ssb155480 /* priority frame, use pri tx function */ 8555935Ssb155480 vgen_ldcsend_pkt(ldcp, mp); 8565935Ssb155480 return (VGEN_SUCCESS); 8575935Ssb155480 } 8585935Ssb155480 8595935Ssb155480 } 8605935Ssb155480 8615935Ssb155480 status = vgen_ldcsend_dring(ldcp, mp); 8625935Ssb155480 8635935Ssb155480 return (status); 8645935Ssb155480 } 8655935Ssb155480 8665935Ssb155480 /* 8675935Ssb155480 * This functions handles ldc channel reset while in the context 8685935Ssb155480 * of transmit routines: vgen_ldcsend_pkt() or vgen_ldcsend_dring(). 8695935Ssb155480 */ 8705935Ssb155480 static void 8715935Ssb155480 vgen_ldcsend_process_reset(vgen_ldc_t *ldcp) 8725935Ssb155480 { 8735935Ssb155480 ldc_status_t istatus; 8745935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 8755935Ssb155480 8765935Ssb155480 if (mutex_tryenter(&ldcp->cblock)) { 8775935Ssb155480 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 8785935Ssb155480 DWARN(vgenp, ldcp, "ldc_status() error\n"); 8795935Ssb155480 } else { 8805935Ssb155480 ldcp->ldc_status = istatus; 8815935Ssb155480 } 8825935Ssb155480 if (ldcp->ldc_status != LDC_UP) { 8836495Sspeer vgen_handle_evt_reset(ldcp); 8845935Ssb155480 } 8855935Ssb155480 mutex_exit(&ldcp->cblock); 8865935Ssb155480 } 8875935Ssb155480 } 8885935Ssb155480 8895935Ssb155480 /* 8905935Ssb155480 * This function transmits the frame in the payload of a raw data 8915935Ssb155480 * (VIO_PKT_DATA) message. Thus, it provides an Out-Of-Band path to 8925935Ssb155480 * send special frames with high priorities, without going through 8935935Ssb155480 * the normal data path which uses descriptor ring mechanism. 8945935Ssb155480 */ 8955935Ssb155480 static void 8965935Ssb155480 vgen_ldcsend_pkt(void *arg, mblk_t *mp) 8971991Sheppo { 8985935Ssb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 8995935Ssb155480 vio_raw_data_msg_t *pkt; 9005935Ssb155480 mblk_t *bp; 9015935Ssb155480 mblk_t *nmp = NULL; 9025935Ssb155480 caddr_t dst; 9035935Ssb155480 uint32_t mblksz; 9045935Ssb155480 uint32_t size; 9055935Ssb155480 uint32_t nbytes; 9065935Ssb155480 int rv; 9075935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 9085935Ssb155480 vgen_stats_t *statsp = &ldcp->stats; 9095935Ssb155480 9105935Ssb155480 /* drop the packet if ldc is not up or handshake is not done */ 9115935Ssb155480 if (ldcp->ldc_status != LDC_UP) { 9125935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 9135935Ssb155480 DWARN(vgenp, ldcp, "status(%d), dropping packet\n", 9145935Ssb155480 ldcp->ldc_status); 9155935Ssb155480 goto send_pkt_exit; 9165935Ssb155480 } 9175935Ssb155480 9185935Ssb155480 if (ldcp->hphase != VH_DONE) { 9195935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 9205935Ssb155480 DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n", 9215935Ssb155480 ldcp->hphase); 9225935Ssb155480 goto send_pkt_exit; 9235935Ssb155480 } 9245935Ssb155480 9255935Ssb155480 size = msgsize(mp); 9265935Ssb155480 9275935Ssb155480 /* frame size bigger than available payload len of raw data msg ? */ 9285935Ssb155480 if (size > (size_t)(ldcp->msglen - VIO_PKT_DATA_HDRSIZE)) { 9295935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 9305935Ssb155480 DWARN(vgenp, ldcp, "invalid size(%d)\n", size); 9315935Ssb155480 goto send_pkt_exit; 9325935Ssb155480 } 9335935Ssb155480 9345935Ssb155480 if (size < ETHERMIN) 9355935Ssb155480 size = ETHERMIN; 9365935Ssb155480 9375935Ssb155480 /* alloc space for a raw data message */ 9385935Ssb155480 nmp = vio_allocb(vgenp->pri_tx_vmp); 9395935Ssb155480 if (nmp == NULL) { 9405935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 9415935Ssb155480 DWARN(vgenp, ldcp, "vio_allocb failed\n"); 9425935Ssb155480 goto send_pkt_exit; 9435935Ssb155480 } 9445935Ssb155480 pkt = (vio_raw_data_msg_t *)nmp->b_rptr; 9455935Ssb155480 9465935Ssb155480 /* copy frame into the payload of raw data message */ 9475935Ssb155480 dst = (caddr_t)pkt->data; 9485935Ssb155480 for (bp = mp; bp != NULL; bp = bp->b_cont) { 9495935Ssb155480 mblksz = MBLKL(bp); 9505935Ssb155480 bcopy(bp->b_rptr, dst, mblksz); 9515935Ssb155480 dst += mblksz; 9525935Ssb155480 } 9535935Ssb155480 9545935Ssb155480 /* setup the raw data msg */ 9555935Ssb155480 pkt->tag.vio_msgtype = VIO_TYPE_DATA; 9565935Ssb155480 pkt->tag.vio_subtype = VIO_SUBTYPE_INFO; 9575935Ssb155480 pkt->tag.vio_subtype_env = VIO_PKT_DATA; 9585935Ssb155480 pkt->tag.vio_sid = ldcp->local_sid; 9595935Ssb155480 nbytes = VIO_PKT_DATA_HDRSIZE + size; 9605935Ssb155480 9615935Ssb155480 /* send the msg over ldc */ 9625935Ssb155480 rv = vgen_sendmsg(ldcp, (caddr_t)pkt, nbytes, B_FALSE); 9635935Ssb155480 if (rv != VGEN_SUCCESS) { 9645935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 9655935Ssb155480 DWARN(vgenp, ldcp, "Error sending priority frame\n"); 9665935Ssb155480 if (rv == ECONNRESET) { 9675935Ssb155480 vgen_ldcsend_process_reset(ldcp); 9685935Ssb155480 } 9695935Ssb155480 goto send_pkt_exit; 9705935Ssb155480 } 9715935Ssb155480 9725935Ssb155480 /* update stats */ 9735935Ssb155480 (void) atomic_inc_64(&statsp->tx_pri_packets); 9745935Ssb155480 (void) atomic_add_64(&statsp->tx_pri_bytes, size); 9755935Ssb155480 9765935Ssb155480 send_pkt_exit: 9775935Ssb155480 if (nmp != NULL) 9785935Ssb155480 freemsg(nmp); 9795935Ssb155480 freemsg(mp); 9805935Ssb155480 } 9815935Ssb155480 9825935Ssb155480 /* 9835935Ssb155480 * This function transmits normal (non-priority) data frames over 9845935Ssb155480 * the channel. It queues the frame into the transmit descriptor ring 9855935Ssb155480 * and sends a VIO_DRING_DATA message if needed, to wake up the 9865935Ssb155480 * peer to (re)start processing. 9875935Ssb155480 */ 9885935Ssb155480 static int 9895935Ssb155480 vgen_ldcsend_dring(void *arg, mblk_t *mp) 9905935Ssb155480 { 9915935Ssb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 9921991Sheppo vgen_private_desc_t *tbufp; 9934647Sraghuram vgen_private_desc_t *rtbufp; 9944647Sraghuram vnet_public_desc_t *rtxdp; 9951991Sheppo vgen_private_desc_t *ntbufp; 9961991Sheppo vnet_public_desc_t *txdp; 9974647Sraghuram vio_dring_entry_hdr_t *hdrp; 9981991Sheppo vgen_stats_t *statsp; 9991991Sheppo struct ether_header *ehp; 10006419Ssb155480 boolean_t is_bcast = B_FALSE; 10016419Ssb155480 boolean_t is_mcast = B_FALSE; 10026419Ssb155480 size_t mblksz; 10036419Ssb155480 caddr_t dst; 10046419Ssb155480 mblk_t *bp; 10056419Ssb155480 size_t size; 10066419Ssb155480 int rv = 0; 10076419Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 10086419Ssb155480 vgen_hparams_t *lp = &ldcp->local_hparams; 10094647Sraghuram 10105373Sraghuram statsp = &ldcp->stats; 10112109Slm66018 size = msgsize(mp); 10122109Slm66018 10134647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 10144647Sraghuram 10152109Slm66018 if (ldcp->ldc_status != LDC_UP) { 10164647Sraghuram DWARN(vgenp, ldcp, "status(%d), dropping packet\n", 10174647Sraghuram ldcp->ldc_status); 10182109Slm66018 /* retry ldc_up() if needed */ 10192109Slm66018 if (ldcp->flags & CHANNEL_STARTED) 10202109Slm66018 (void) ldc_up(ldcp->ldc_handle); 10215935Ssb155480 goto send_dring_exit; 10221991Sheppo } 10231991Sheppo 10244647Sraghuram /* drop the packet if ldc is not up or handshake is not done */ 10252109Slm66018 if (ldcp->hphase != VH_DONE) { 10264647Sraghuram DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n", 10274647Sraghuram ldcp->hphase); 10285935Ssb155480 goto send_dring_exit; 10292109Slm66018 } 10302109Slm66018 10316419Ssb155480 if (size > (size_t)lp->mtu) { 10324647Sraghuram DWARN(vgenp, ldcp, "invalid size(%d)\n", size); 10335935Ssb155480 goto send_dring_exit; 10341991Sheppo } 10354647Sraghuram if (size < ETHERMIN) 10364647Sraghuram size = ETHERMIN; 10374647Sraghuram 10384647Sraghuram ehp = (struct ether_header *)mp->b_rptr; 10394647Sraghuram is_bcast = IS_BROADCAST(ehp); 10404647Sraghuram is_mcast = IS_MULTICAST(ehp); 10414647Sraghuram 10424647Sraghuram mutex_enter(&ldcp->txlock); 10431991Sheppo /* 10441991Sheppo * allocate a descriptor 10451991Sheppo */ 10461991Sheppo tbufp = ldcp->next_tbufp; 10471991Sheppo ntbufp = NEXTTBUF(ldcp, tbufp); 10482336Snarayan if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */ 10491991Sheppo 10501991Sheppo mutex_enter(&ldcp->tclock); 10514647Sraghuram /* Try reclaiming now */ 10524647Sraghuram vgen_reclaim_dring(ldcp); 10534647Sraghuram ldcp->reclaim_lbolt = ddi_get_lbolt(); 10544647Sraghuram 10552336Snarayan if (ntbufp == ldcp->cur_tbufp) { 10564647Sraghuram /* Now we are really out of tbuf/txds */ 10571991Sheppo ldcp->need_resched = B_TRUE; 10582336Snarayan mutex_exit(&ldcp->tclock); 10592336Snarayan 10602336Snarayan statsp->tx_no_desc++; 10612336Snarayan mutex_exit(&ldcp->txlock); 10622336Snarayan 10632336Snarayan return (VGEN_TX_NORESOURCES); 10642336Snarayan } 10651991Sheppo mutex_exit(&ldcp->tclock); 10661991Sheppo } 10674647Sraghuram /* update next available tbuf in the ring and update tx index */ 10684647Sraghuram ldcp->next_tbufp = ntbufp; 10694647Sraghuram INCR_TXI(ldcp->next_txi, ldcp); 10704647Sraghuram 10714647Sraghuram /* Mark the buffer busy before releasing the lock */ 10724647Sraghuram tbufp->flags = VGEN_PRIV_DESC_BUSY; 10734647Sraghuram mutex_exit(&ldcp->txlock); 10742109Slm66018 10752109Slm66018 /* copy data into pre-allocated transmit buffer */ 10762336Snarayan dst = tbufp->datap + VNET_IPALIGN; 10772336Snarayan for (bp = mp; bp != NULL; bp = bp->b_cont) { 10782336Snarayan mblksz = MBLKL(bp); 10792336Snarayan bcopy(bp->b_rptr, dst, mblksz); 10802336Snarayan dst += mblksz; 10811991Sheppo } 10821991Sheppo 10832109Slm66018 tbufp->datalen = size; 10841991Sheppo 10851991Sheppo /* initialize the corresponding public descriptor (txd) */ 10861991Sheppo txdp = tbufp->descp; 10871991Sheppo hdrp = &txdp->hdr; 10882109Slm66018 txdp->nbytes = size; 10892109Slm66018 txdp->ncookies = tbufp->ncookies; 10901991Sheppo bcopy((tbufp->memcookie), (txdp->memcookie), 10914650Sraghuram tbufp->ncookies * sizeof (ldc_mem_cookie_t)); 10924647Sraghuram 10934647Sraghuram mutex_enter(&ldcp->wrlock); 10944647Sraghuram /* 10954647Sraghuram * If the flags not set to BUSY, it implies that the clobber 10964647Sraghuram * was done while we were copying the data. In such case, 10974647Sraghuram * discard the packet and return. 10984647Sraghuram */ 10994647Sraghuram if (tbufp->flags != VGEN_PRIV_DESC_BUSY) { 11004647Sraghuram statsp->oerrors++; 11014647Sraghuram mutex_exit(&ldcp->wrlock); 11025935Ssb155480 goto send_dring_exit; 11034647Sraghuram } 11042336Snarayan hdrp->dstate = VIO_DESC_READY; 11051991Sheppo 11061991Sheppo /* update stats */ 11071991Sheppo statsp->opackets++; 11082109Slm66018 statsp->obytes += size; 11091991Sheppo if (is_bcast) 11101991Sheppo statsp->brdcstxmt++; 11111991Sheppo else if (is_mcast) 11121991Sheppo statsp->multixmt++; 11131991Sheppo 11144647Sraghuram /* send dring datamsg to the peer */ 11154647Sraghuram if (ldcp->resched_peer) { 11164647Sraghuram 11174647Sraghuram rtbufp = &ldcp->tbufp[ldcp->resched_peer_txi]; 11184647Sraghuram rtxdp = rtbufp->descp; 11194647Sraghuram 11204647Sraghuram if (rtxdp->hdr.dstate == VIO_DESC_READY) { 11214647Sraghuram 11224647Sraghuram rv = vgen_send_dring_data(ldcp, 11234647Sraghuram (uint32_t)ldcp->resched_peer_txi, -1); 11244647Sraghuram if (rv != 0) { 11254647Sraghuram /* error: drop the packet */ 11264647Sraghuram DWARN(vgenp, ldcp, "vgen_send_dring_data " 11274650Sraghuram "failed: rv(%d) len(%d)\n", 11284650Sraghuram ldcp->ldc_id, rv, size); 11294647Sraghuram statsp->oerrors++; 11304647Sraghuram } else { 11314647Sraghuram ldcp->resched_peer = B_FALSE; 11324647Sraghuram } 11334647Sraghuram 11344647Sraghuram } 11354647Sraghuram 11364647Sraghuram } 11374647Sraghuram 11384647Sraghuram mutex_exit(&ldcp->wrlock); 11394647Sraghuram 11405935Ssb155480 send_dring_exit: 11412793Slm66018 if (rv == ECONNRESET) { 11425935Ssb155480 vgen_ldcsend_process_reset(ldcp); 11432793Slm66018 } 11442109Slm66018 freemsg(mp); 11454647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 11462109Slm66018 return (VGEN_TX_SUCCESS); 11471991Sheppo } 11481991Sheppo 11491991Sheppo /* enable/disable a multicast address */ 11502311Sseb int 11511991Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca) 11521991Sheppo { 11531991Sheppo vgen_t *vgenp; 11541991Sheppo vnet_mcast_msg_t mcastmsg; 11551991Sheppo vio_msg_tag_t *tagp; 11561991Sheppo vgen_port_t *portp; 11571991Sheppo vgen_portlist_t *plistp; 11581991Sheppo vgen_ldc_t *ldcp; 11591991Sheppo vgen_ldclist_t *ldclp; 11601991Sheppo struct ether_addr *addrp; 11613653Snarayan int rv = DDI_FAILURE; 11621991Sheppo uint32_t i; 11631991Sheppo 11646495Sspeer portp = (vgen_port_t *)arg; 11656495Sspeer vgenp = portp->vgenp; 11666495Sspeer 11676495Sspeer if (portp != vgenp->vsw_portp) { 11686495Sspeer return (DDI_SUCCESS); 11696495Sspeer } 11706495Sspeer 11711991Sheppo addrp = (struct ether_addr *)mca; 11721991Sheppo tagp = &mcastmsg.tag; 11731991Sheppo bzero(&mcastmsg, sizeof (mcastmsg)); 11741991Sheppo 11751991Sheppo mutex_enter(&vgenp->lock); 11761991Sheppo 11771991Sheppo plistp = &(vgenp->vgenports); 11781991Sheppo 11791991Sheppo READ_ENTER(&plistp->rwlock); 11801991Sheppo 11811991Sheppo portp = vgenp->vsw_portp; 11821991Sheppo if (portp == NULL) { 11831991Sheppo RW_EXIT(&plistp->rwlock); 11843653Snarayan mutex_exit(&vgenp->lock); 11853653Snarayan return (rv); 11861991Sheppo } 11871991Sheppo ldclp = &portp->ldclist; 11881991Sheppo 11891991Sheppo READ_ENTER(&ldclp->rwlock); 11901991Sheppo 11911991Sheppo ldcp = ldclp->headp; 11923653Snarayan if (ldcp == NULL) 11931991Sheppo goto vgen_mcast_exit; 11941991Sheppo 11951991Sheppo mutex_enter(&ldcp->cblock); 11961991Sheppo 11971991Sheppo if (ldcp->hphase == VH_DONE) { 11981991Sheppo /* 11991991Sheppo * If handshake is done, send a msg to vsw to add/remove 12005171Ssb155480 * the multicast address. Otherwise, we just update this 12015171Ssb155480 * mcast address in our table and the table will be sync'd 12025171Ssb155480 * with vsw when handshake completes. 12031991Sheppo */ 12041991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 12051991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 12061991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 12071991Sheppo tagp->vio_sid = ldcp->local_sid; 12081991Sheppo bcopy(mca, &(mcastmsg.mca), ETHERADDRL); 12091991Sheppo mcastmsg.set = add; 12101991Sheppo mcastmsg.count = 1; 12113653Snarayan if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg), 12123653Snarayan B_FALSE) != VGEN_SUCCESS) { 12134647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 12143653Snarayan mutex_exit(&ldcp->cblock); 12153653Snarayan goto vgen_mcast_exit; 12161991Sheppo } 12171991Sheppo } 12181991Sheppo 12191991Sheppo mutex_exit(&ldcp->cblock); 12201991Sheppo 12211991Sheppo if (add) { 12221991Sheppo 12231991Sheppo /* expand multicast table if necessary */ 12241991Sheppo if (vgenp->mccount >= vgenp->mcsize) { 12251991Sheppo struct ether_addr *newtab; 12261991Sheppo uint32_t newsize; 12271991Sheppo 12281991Sheppo 12291991Sheppo newsize = vgenp->mcsize * 2; 12301991Sheppo 12311991Sheppo newtab = kmem_zalloc(newsize * 12321991Sheppo sizeof (struct ether_addr), KM_NOSLEEP); 12333653Snarayan if (newtab == NULL) 12343653Snarayan goto vgen_mcast_exit; 12351991Sheppo bcopy(vgenp->mctab, newtab, vgenp->mcsize * 12361991Sheppo sizeof (struct ether_addr)); 12371991Sheppo kmem_free(vgenp->mctab, 12381991Sheppo vgenp->mcsize * sizeof (struct ether_addr)); 12391991Sheppo 12401991Sheppo vgenp->mctab = newtab; 12411991Sheppo vgenp->mcsize = newsize; 12421991Sheppo } 12431991Sheppo 12441991Sheppo /* add address to the table */ 12451991Sheppo vgenp->mctab[vgenp->mccount++] = *addrp; 12461991Sheppo 12471991Sheppo } else { 12481991Sheppo 12491991Sheppo /* delete address from the table */ 12501991Sheppo for (i = 0; i < vgenp->mccount; i++) { 12511991Sheppo if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) { 12521991Sheppo 12531991Sheppo /* 12541991Sheppo * If there's more than one address in this 12551991Sheppo * table, delete the unwanted one by moving 12561991Sheppo * the last one in the list over top of it; 12571991Sheppo * otherwise, just remove it. 12581991Sheppo */ 12591991Sheppo if (vgenp->mccount > 1) { 12601991Sheppo vgenp->mctab[i] = 12614650Sraghuram vgenp->mctab[vgenp->mccount-1]; 12621991Sheppo } 12631991Sheppo vgenp->mccount--; 12641991Sheppo break; 12651991Sheppo } 12661991Sheppo } 12671991Sheppo } 12681991Sheppo 12693653Snarayan rv = DDI_SUCCESS; 12703653Snarayan 12713653Snarayan vgen_mcast_exit: 12721991Sheppo RW_EXIT(&ldclp->rwlock); 12731991Sheppo RW_EXIT(&plistp->rwlock); 12741991Sheppo 12751991Sheppo mutex_exit(&vgenp->lock); 12763653Snarayan return (rv); 12771991Sheppo } 12781991Sheppo 12791991Sheppo /* set or clear promiscuous mode on the device */ 12801991Sheppo static int 12811991Sheppo vgen_promisc(void *arg, boolean_t on) 12821991Sheppo { 12831991Sheppo _NOTE(ARGUNUSED(arg, on)) 12841991Sheppo return (DDI_SUCCESS); 12851991Sheppo } 12861991Sheppo 12871991Sheppo /* set the unicast mac address of the device */ 12881991Sheppo static int 12891991Sheppo vgen_unicst(void *arg, const uint8_t *mca) 12901991Sheppo { 12911991Sheppo _NOTE(ARGUNUSED(arg, mca)) 12921991Sheppo return (DDI_SUCCESS); 12931991Sheppo } 12941991Sheppo 12951991Sheppo /* get device statistics */ 12962311Sseb int 12972311Sseb vgen_stat(void *arg, uint_t stat, uint64_t *val) 12981991Sheppo { 12996495Sspeer vgen_port_t *portp = (vgen_port_t *)arg; 13006495Sspeer 13016495Sspeer *val = vgen_port_stat(portp, stat); 13021991Sheppo 13032311Sseb return (0); 13041991Sheppo } 13051991Sheppo 13061991Sheppo static void 13071991Sheppo vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp) 13081991Sheppo { 13091991Sheppo _NOTE(ARGUNUSED(arg, wq, mp)) 13101991Sheppo } 13111991Sheppo 13121991Sheppo /* vgen internal functions */ 13131991Sheppo /* detach all ports from the device */ 13141991Sheppo static void 13151991Sheppo vgen_detach_ports(vgen_t *vgenp) 13161991Sheppo { 13171991Sheppo vgen_port_t *portp; 13181991Sheppo vgen_portlist_t *plistp; 13191991Sheppo 13201991Sheppo plistp = &(vgenp->vgenports); 13211991Sheppo WRITE_ENTER(&plistp->rwlock); 13221991Sheppo 13231991Sheppo while ((portp = plistp->headp) != NULL) { 13241991Sheppo vgen_port_detach(portp); 13251991Sheppo } 13261991Sheppo 13271991Sheppo RW_EXIT(&plistp->rwlock); 13281991Sheppo } 13291991Sheppo 13301991Sheppo /* 13311991Sheppo * detach the given port. 13321991Sheppo */ 13331991Sheppo static void 13341991Sheppo vgen_port_detach(vgen_port_t *portp) 13351991Sheppo { 13361991Sheppo vgen_t *vgenp; 13371991Sheppo vgen_ldclist_t *ldclp; 13381991Sheppo int port_num; 13391991Sheppo 13401991Sheppo vgenp = portp->vgenp; 13411991Sheppo port_num = portp->port_num; 13421991Sheppo 13434647Sraghuram DBG1(vgenp, NULL, "port(%d):enter\n", port_num); 13441991Sheppo 13456495Sspeer /* 13466495Sspeer * If this port is connected to the vswitch, then 13476495Sspeer * potentially there could be ports that may be using 13486495Sspeer * this port to transmit packets. To address this do 13496495Sspeer * the following: 13506495Sspeer * - First set vgenp->vsw_portp to NULL, so that 13516495Sspeer * its not used after that. 13526495Sspeer * - Then wait for the refcnt to go down to 0. 13536495Sspeer * - Now we can safely detach this port. 13546495Sspeer */ 13556495Sspeer if (vgenp->vsw_portp == portp) { 13566495Sspeer vgenp->vsw_portp = NULL; 13576495Sspeer while (vgenp->vsw_port_refcnt > 0) { 13586495Sspeer delay(drv_usectohz(vgen_tx_delay)); 13596495Sspeer } 13606495Sspeer (void) atomic_swap_32(&vgenp->vsw_port_refcnt, 0); 13616495Sspeer } 13626495Sspeer 13636495Sspeer if (portp->vhp != NULL) { 13646495Sspeer vio_net_resource_unreg(portp->vhp); 13656495Sspeer portp->vhp = NULL; 13666495Sspeer } 13676495Sspeer 13686419Ssb155480 vgen_vlan_destroy_hash(portp); 13696419Ssb155480 13701991Sheppo /* remove it from port list */ 13711991Sheppo vgen_port_list_remove(portp); 13721991Sheppo 13731991Sheppo /* detach channels from this port */ 13741991Sheppo ldclp = &portp->ldclist; 13751991Sheppo WRITE_ENTER(&ldclp->rwlock); 13761991Sheppo while (ldclp->headp) { 13771991Sheppo vgen_ldc_detach(ldclp->headp); 13781991Sheppo } 13791991Sheppo RW_EXIT(&ldclp->rwlock); 13805641Swentaoy rw_destroy(&ldclp->rwlock); 13811991Sheppo 13826419Ssb155480 if (portp->num_ldcs != 0) { 13836419Ssb155480 kmem_free(portp->ldc_ids, portp->num_ldcs * sizeof (uint64_t)); 13846419Ssb155480 portp->num_ldcs = 0; 13856419Ssb155480 } 13866419Ssb155480 13876495Sspeer mutex_destroy(&portp->lock); 13881991Sheppo KMEM_FREE(portp); 13891991Sheppo 13904647Sraghuram DBG1(vgenp, NULL, "port(%d):exit\n", port_num); 13911991Sheppo } 13921991Sheppo 13931991Sheppo /* add a port to port list */ 13941991Sheppo static void 13951991Sheppo vgen_port_list_insert(vgen_port_t *portp) 13961991Sheppo { 13971991Sheppo vgen_portlist_t *plistp; 13981991Sheppo vgen_t *vgenp; 13991991Sheppo 14001991Sheppo vgenp = portp->vgenp; 14011991Sheppo plistp = &(vgenp->vgenports); 14021991Sheppo 14031991Sheppo if (plistp->headp == NULL) { 14041991Sheppo plistp->headp = portp; 14051991Sheppo } else { 14061991Sheppo plistp->tailp->nextp = portp; 14071991Sheppo } 14081991Sheppo plistp->tailp = portp; 14091991Sheppo portp->nextp = NULL; 14101991Sheppo } 14111991Sheppo 14121991Sheppo /* remove a port from port list */ 14131991Sheppo static void 14141991Sheppo vgen_port_list_remove(vgen_port_t *portp) 14151991Sheppo { 14161991Sheppo vgen_port_t *prevp; 14171991Sheppo vgen_port_t *nextp; 14181991Sheppo vgen_portlist_t *plistp; 14191991Sheppo vgen_t *vgenp; 14201991Sheppo 14211991Sheppo vgenp = portp->vgenp; 14221991Sheppo 14231991Sheppo plistp = &(vgenp->vgenports); 14241991Sheppo 14251991Sheppo if (plistp->headp == NULL) 14261991Sheppo return; 14271991Sheppo 14281991Sheppo if (portp == plistp->headp) { 14291991Sheppo plistp->headp = portp->nextp; 14301991Sheppo if (portp == plistp->tailp) 14311991Sheppo plistp->tailp = plistp->headp; 14321991Sheppo } else { 14334650Sraghuram for (prevp = plistp->headp; 14344650Sraghuram ((nextp = prevp->nextp) != NULL) && (nextp != portp); 14354650Sraghuram prevp = nextp) 14364650Sraghuram ; 14371991Sheppo if (nextp == portp) { 14381991Sheppo prevp->nextp = portp->nextp; 14391991Sheppo } 14401991Sheppo if (portp == plistp->tailp) 14411991Sheppo plistp->tailp = prevp; 14421991Sheppo } 14431991Sheppo } 14441991Sheppo 14451991Sheppo /* lookup a port in the list based on port_num */ 14461991Sheppo static vgen_port_t * 14471991Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num) 14481991Sheppo { 14491991Sheppo vgen_port_t *portp = NULL; 14501991Sheppo 14511991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 14521991Sheppo if (portp->port_num == port_num) { 14531991Sheppo break; 14541991Sheppo } 14551991Sheppo } 14561991Sheppo 14571991Sheppo return (portp); 14581991Sheppo } 14591991Sheppo 14601991Sheppo /* enable ports for transmit/receive */ 14611991Sheppo static void 14621991Sheppo vgen_init_ports(vgen_t *vgenp) 14631991Sheppo { 14641991Sheppo vgen_port_t *portp; 14651991Sheppo vgen_portlist_t *plistp; 14661991Sheppo 14671991Sheppo plistp = &(vgenp->vgenports); 14681991Sheppo READ_ENTER(&plistp->rwlock); 14691991Sheppo 14701991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 14711991Sheppo vgen_port_init(portp); 14721991Sheppo } 14731991Sheppo 14741991Sheppo RW_EXIT(&plistp->rwlock); 14751991Sheppo } 14761991Sheppo 14771991Sheppo static void 14781991Sheppo vgen_port_init(vgen_port_t *portp) 14791991Sheppo { 14806419Ssb155480 /* Add the port to the specified vlans */ 14816419Ssb155480 vgen_vlan_add_ids(portp); 14821991Sheppo 14831991Sheppo /* Bring up the channels of this port */ 14841991Sheppo vgen_init_ldcs(portp); 14851991Sheppo } 14861991Sheppo 14871991Sheppo /* disable transmit/receive on ports */ 14881991Sheppo static void 14891991Sheppo vgen_uninit_ports(vgen_t *vgenp) 14901991Sheppo { 14911991Sheppo vgen_port_t *portp; 14921991Sheppo vgen_portlist_t *plistp; 14931991Sheppo 14941991Sheppo plistp = &(vgenp->vgenports); 14951991Sheppo READ_ENTER(&plistp->rwlock); 14961991Sheppo 14971991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 14981991Sheppo vgen_port_uninit(portp); 14991991Sheppo } 15001991Sheppo 15011991Sheppo RW_EXIT(&plistp->rwlock); 15021991Sheppo } 15031991Sheppo 15041991Sheppo static void 15051991Sheppo vgen_port_uninit(vgen_port_t *portp) 15061991Sheppo { 15071991Sheppo vgen_uninit_ldcs(portp); 15086419Ssb155480 15096419Ssb155480 /* remove the port from vlans it has been assigned to */ 15106419Ssb155480 vgen_vlan_remove_ids(portp); 15111991Sheppo } 15121991Sheppo 15135935Ssb155480 /* 15145935Ssb155480 * Scan the machine description for this instance of vnet 15155935Ssb155480 * and read its properties. Called only from vgen_init(). 15165935Ssb155480 * Returns: 0 on success, 1 on failure. 15175935Ssb155480 */ 15185935Ssb155480 static int 15195935Ssb155480 vgen_read_mdprops(vgen_t *vgenp) 15205935Ssb155480 { 15216419Ssb155480 vnet_t *vnetp = vgenp->vnetp; 15225935Ssb155480 md_t *mdp = NULL; 15235935Ssb155480 mde_cookie_t rootnode; 15245935Ssb155480 mde_cookie_t *listp = NULL; 15255935Ssb155480 uint64_t cfgh; 15265935Ssb155480 char *name; 15275935Ssb155480 int rv = 1; 15285935Ssb155480 int num_nodes = 0; 15295935Ssb155480 int num_devs = 0; 15305935Ssb155480 int listsz = 0; 15315935Ssb155480 int i; 15325935Ssb155480 15335935Ssb155480 if ((mdp = md_get_handle()) == NULL) { 15345935Ssb155480 return (rv); 15355935Ssb155480 } 15365935Ssb155480 15375935Ssb155480 num_nodes = md_node_count(mdp); 15385935Ssb155480 ASSERT(num_nodes > 0); 15395935Ssb155480 15405935Ssb155480 listsz = num_nodes * sizeof (mde_cookie_t); 15415935Ssb155480 listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP); 15425935Ssb155480 15435935Ssb155480 rootnode = md_root_node(mdp); 15445935Ssb155480 15455935Ssb155480 /* search for all "virtual_device" nodes */ 15465935Ssb155480 num_devs = md_scan_dag(mdp, rootnode, 15475935Ssb155480 md_find_name(mdp, vdev_propname), 15485935Ssb155480 md_find_name(mdp, "fwd"), listp); 15495935Ssb155480 if (num_devs <= 0) { 15505935Ssb155480 goto vgen_readmd_exit; 15515935Ssb155480 } 15525935Ssb155480 15535935Ssb155480 /* 15545935Ssb155480 * Now loop through the list of virtual-devices looking for 15555935Ssb155480 * devices with name "network" and for each such device compare 15565935Ssb155480 * its instance with what we have from the 'reg' property to 15575935Ssb155480 * find the right node in MD and then read all its properties. 15585935Ssb155480 */ 15595935Ssb155480 for (i = 0; i < num_devs; i++) { 15605935Ssb155480 15615935Ssb155480 if (md_get_prop_str(mdp, listp[i], "name", &name) != 0) { 15625935Ssb155480 goto vgen_readmd_exit; 15635935Ssb155480 } 15645935Ssb155480 15655935Ssb155480 /* is this a "network" device? */ 15665935Ssb155480 if (strcmp(name, vnet_propname) != 0) 15675935Ssb155480 continue; 15685935Ssb155480 15695935Ssb155480 if (md_get_prop_val(mdp, listp[i], "cfg-handle", &cfgh) != 0) { 15705935Ssb155480 goto vgen_readmd_exit; 15715935Ssb155480 } 15725935Ssb155480 15735935Ssb155480 /* is this the required instance of vnet? */ 15746495Sspeer if (vgenp->regprop != cfgh) 15755935Ssb155480 continue; 15765935Ssb155480 15777529SSriharsha.Basavapatna@Sun.COM /* 15787529SSriharsha.Basavapatna@Sun.COM * Read the mtu. Note that we set the mtu of vnet device within 15797529SSriharsha.Basavapatna@Sun.COM * this routine itself, after validating the range. 15807529SSriharsha.Basavapatna@Sun.COM */ 15817529SSriharsha.Basavapatna@Sun.COM vgen_mtu_read(vgenp, mdp, listp[i], &vnetp->mtu); 15827529SSriharsha.Basavapatna@Sun.COM if (vnetp->mtu < ETHERMTU || vnetp->mtu > VNET_MAX_MTU) { 15837529SSriharsha.Basavapatna@Sun.COM vnetp->mtu = ETHERMTU; 15847529SSriharsha.Basavapatna@Sun.COM } 15857529SSriharsha.Basavapatna@Sun.COM vgenp->max_frame_size = vnetp->mtu + 15867529SSriharsha.Basavapatna@Sun.COM sizeof (struct ether_header) + VLAN_TAGSZ; 15877529SSriharsha.Basavapatna@Sun.COM 15887529SSriharsha.Basavapatna@Sun.COM /* read priority ether types */ 15895935Ssb155480 vgen_read_pri_eth_types(vgenp, mdp, listp[i]); 15906419Ssb155480 15916419Ssb155480 /* read vlan id properties of this vnet instance */ 15926419Ssb155480 vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, listp[i], 15936419Ssb155480 &vnetp->pvid, &vnetp->vids, &vnetp->nvids, 15946419Ssb155480 &vnetp->default_vlan_id); 15956419Ssb155480 15965935Ssb155480 rv = 0; 15975935Ssb155480 break; 15985935Ssb155480 } 15995935Ssb155480 16005935Ssb155480 vgen_readmd_exit: 16015935Ssb155480 16025935Ssb155480 kmem_free(listp, listsz); 16035935Ssb155480 (void) md_fini_handle(mdp); 16045935Ssb155480 return (rv); 16055935Ssb155480 } 16065935Ssb155480 16075935Ssb155480 /* 16086419Ssb155480 * Read vlan id properties of the given MD node. 16096419Ssb155480 * Arguments: 16106419Ssb155480 * arg: device argument(vnet device or a port) 16116419Ssb155480 * type: type of arg; VGEN_LOCAL(vnet device) or VGEN_PEER(port) 16126419Ssb155480 * mdp: machine description 16136419Ssb155480 * node: md node cookie 16146419Ssb155480 * 16156419Ssb155480 * Returns: 16166419Ssb155480 * pvidp: port-vlan-id of the node 16176419Ssb155480 * vidspp: list of vlan-ids of the node 16186419Ssb155480 * nvidsp: # of vlan-ids in the list 16196419Ssb155480 * default_idp: default-vlan-id of the node(if node is vnet device) 16206419Ssb155480 */ 16216419Ssb155480 static void 16226419Ssb155480 vgen_vlan_read_ids(void *arg, int type, md_t *mdp, mde_cookie_t node, 16236419Ssb155480 uint16_t *pvidp, uint16_t **vidspp, uint16_t *nvidsp, 16246419Ssb155480 uint16_t *default_idp) 16256419Ssb155480 { 16266419Ssb155480 vgen_t *vgenp; 16276419Ssb155480 vnet_t *vnetp; 16286419Ssb155480 vgen_port_t *portp; 16296419Ssb155480 char *pvid_propname; 16306419Ssb155480 char *vid_propname; 16316419Ssb155480 uint_t nvids; 16326419Ssb155480 uint32_t vids_size; 16336419Ssb155480 int rv; 16346419Ssb155480 int i; 16356419Ssb155480 uint64_t *data; 16366419Ssb155480 uint64_t val; 16376419Ssb155480 int size; 16386419Ssb155480 int inst; 16396419Ssb155480 16406419Ssb155480 if (type == VGEN_LOCAL) { 16416419Ssb155480 16426419Ssb155480 vgenp = (vgen_t *)arg; 16436419Ssb155480 vnetp = vgenp->vnetp; 16446419Ssb155480 pvid_propname = vgen_pvid_propname; 16456419Ssb155480 vid_propname = vgen_vid_propname; 16466419Ssb155480 inst = vnetp->instance; 16476419Ssb155480 16486419Ssb155480 } else if (type == VGEN_PEER) { 16496419Ssb155480 16506419Ssb155480 portp = (vgen_port_t *)arg; 16516419Ssb155480 vgenp = portp->vgenp; 16526419Ssb155480 vnetp = vgenp->vnetp; 16536419Ssb155480 pvid_propname = port_pvid_propname; 16546419Ssb155480 vid_propname = port_vid_propname; 16556419Ssb155480 inst = portp->port_num; 16566419Ssb155480 16576419Ssb155480 } else { 16586419Ssb155480 return; 16596419Ssb155480 } 16606419Ssb155480 16616419Ssb155480 if (type == VGEN_LOCAL && default_idp != NULL) { 16626419Ssb155480 rv = md_get_prop_val(mdp, node, vgen_dvid_propname, &val); 16636419Ssb155480 if (rv != 0) { 16646419Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found", 16656419Ssb155480 vgen_dvid_propname); 16666419Ssb155480 16676419Ssb155480 *default_idp = vnet_default_vlan_id; 16686419Ssb155480 } else { 16696419Ssb155480 *default_idp = val & 0xFFF; 16706419Ssb155480 DBG2(vgenp, NULL, "%s(%d): (%d)\n", vgen_dvid_propname, 16716419Ssb155480 inst, *default_idp); 16726419Ssb155480 } 16736419Ssb155480 } 16746419Ssb155480 16756419Ssb155480 rv = md_get_prop_val(mdp, node, pvid_propname, &val); 16766419Ssb155480 if (rv != 0) { 16776419Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found", pvid_propname); 16786419Ssb155480 *pvidp = vnet_default_vlan_id; 16796419Ssb155480 } else { 16806419Ssb155480 16816419Ssb155480 *pvidp = val & 0xFFF; 16826419Ssb155480 DBG2(vgenp, NULL, "%s(%d): (%d)\n", 16836419Ssb155480 pvid_propname, inst, *pvidp); 16846419Ssb155480 } 16856419Ssb155480 16866419Ssb155480 rv = md_get_prop_data(mdp, node, vid_propname, (uint8_t **)&data, 16876419Ssb155480 &size); 16886419Ssb155480 if (rv != 0) { 16896419Ssb155480 DBG2(vgenp, NULL, "prop(%s) not found", vid_propname); 16906419Ssb155480 size = 0; 16916419Ssb155480 } else { 16926419Ssb155480 size /= sizeof (uint64_t); 16936419Ssb155480 } 16946419Ssb155480 nvids = size; 16956419Ssb155480 16966419Ssb155480 if (nvids != 0) { 16976419Ssb155480 DBG2(vgenp, NULL, "%s(%d): ", vid_propname, inst); 16986419Ssb155480 vids_size = sizeof (uint16_t) * nvids; 16996419Ssb155480 *vidspp = kmem_zalloc(vids_size, KM_SLEEP); 17006419Ssb155480 for (i = 0; i < nvids; i++) { 17016419Ssb155480 (*vidspp)[i] = data[i] & 0xFFFF; 17026419Ssb155480 DBG2(vgenp, NULL, " %d ", (*vidspp)[i]); 17036419Ssb155480 } 17046419Ssb155480 DBG2(vgenp, NULL, "\n"); 17056419Ssb155480 } 17066419Ssb155480 17076419Ssb155480 *nvidsp = nvids; 17086419Ssb155480 } 17096419Ssb155480 17106419Ssb155480 /* 17116419Ssb155480 * Create a vlan id hash table for the given port. 17126419Ssb155480 */ 17136419Ssb155480 static void 17146419Ssb155480 vgen_vlan_create_hash(vgen_port_t *portp) 17156419Ssb155480 { 17166419Ssb155480 char hashname[MAXNAMELEN]; 17176419Ssb155480 17186419Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "port%d-vlan-hash", 17196419Ssb155480 portp->port_num); 17206419Ssb155480 17216419Ssb155480 portp->vlan_nchains = vgen_vlan_nchains; 17226419Ssb155480 portp->vlan_hashp = mod_hash_create_idhash(hashname, 17236419Ssb155480 portp->vlan_nchains, mod_hash_null_valdtor); 17246419Ssb155480 } 17256419Ssb155480 17266419Ssb155480 /* 17276419Ssb155480 * Destroy the vlan id hash table in the given port. 17286419Ssb155480 */ 17296419Ssb155480 static void 17306419Ssb155480 vgen_vlan_destroy_hash(vgen_port_t *portp) 17316419Ssb155480 { 17326419Ssb155480 if (portp->vlan_hashp != NULL) { 17336419Ssb155480 mod_hash_destroy_hash(portp->vlan_hashp); 17346419Ssb155480 portp->vlan_hashp = NULL; 17356419Ssb155480 portp->vlan_nchains = 0; 17366419Ssb155480 } 17376419Ssb155480 } 17386419Ssb155480 17396419Ssb155480 /* 17406419Ssb155480 * Add a port to the vlans specified in its port properites. 17416419Ssb155480 */ 17426419Ssb155480 static void 17436419Ssb155480 vgen_vlan_add_ids(vgen_port_t *portp) 17446419Ssb155480 { 17456419Ssb155480 int rv; 17466419Ssb155480 int i; 17476419Ssb155480 17486419Ssb155480 rv = mod_hash_insert(portp->vlan_hashp, 17496419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid), 17506419Ssb155480 (mod_hash_val_t)B_TRUE); 17516419Ssb155480 ASSERT(rv == 0); 17526419Ssb155480 17536419Ssb155480 for (i = 0; i < portp->nvids; i++) { 17546419Ssb155480 rv = mod_hash_insert(portp->vlan_hashp, 17556419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]), 17566419Ssb155480 (mod_hash_val_t)B_TRUE); 17576419Ssb155480 ASSERT(rv == 0); 17586419Ssb155480 } 17596419Ssb155480 } 17606419Ssb155480 17616419Ssb155480 /* 17626419Ssb155480 * Remove a port from the vlans it has been assigned to. 17636419Ssb155480 */ 17646419Ssb155480 static void 17656419Ssb155480 vgen_vlan_remove_ids(vgen_port_t *portp) 17666419Ssb155480 { 17676419Ssb155480 int rv; 17686419Ssb155480 int i; 17696419Ssb155480 mod_hash_val_t vp; 17706419Ssb155480 17716419Ssb155480 rv = mod_hash_remove(portp->vlan_hashp, 17726419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid), 17736419Ssb155480 (mod_hash_val_t *)&vp); 17746419Ssb155480 ASSERT(rv == 0); 17756419Ssb155480 17766419Ssb155480 for (i = 0; i < portp->nvids; i++) { 17776419Ssb155480 rv = mod_hash_remove(portp->vlan_hashp, 17786419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]), 17796419Ssb155480 (mod_hash_val_t *)&vp); 17806419Ssb155480 ASSERT(rv == 0); 17816419Ssb155480 } 17826419Ssb155480 } 17836419Ssb155480 17846419Ssb155480 /* 17856419Ssb155480 * Lookup the vlan id of the given tx frame. If it is a vlan-tagged frame, 17866419Ssb155480 * then the vlan-id is available in the tag; otherwise, its vlan id is 17876419Ssb155480 * implicitly obtained from the port-vlan-id of the vnet device. 17886419Ssb155480 * The vlan id determined is returned in vidp. 17896419Ssb155480 * Returns: B_TRUE if it is a tagged frame; B_FALSE if it is untagged. 17906419Ssb155480 */ 17916419Ssb155480 static boolean_t 17926419Ssb155480 vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp, uint16_t *vidp) 17936419Ssb155480 { 17946419Ssb155480 struct ether_vlan_header *evhp; 17956419Ssb155480 17966419Ssb155480 /* If it's a tagged frame, get the vlan id from vlan header */ 17976419Ssb155480 if (ehp->ether_type == ETHERTYPE_VLAN) { 17986419Ssb155480 17996419Ssb155480 evhp = (struct ether_vlan_header *)ehp; 18006419Ssb155480 *vidp = VLAN_ID(ntohs(evhp->ether_tci)); 18016419Ssb155480 return (B_TRUE); 18026419Ssb155480 } 18036419Ssb155480 18046419Ssb155480 /* Untagged frame, vlan-id is the pvid of vnet device */ 18056419Ssb155480 *vidp = vnetp->pvid; 18066419Ssb155480 return (B_FALSE); 18076419Ssb155480 } 18086419Ssb155480 18096419Ssb155480 /* 18106419Ssb155480 * Find the given vlan id in the hash table. 18116419Ssb155480 * Return: B_TRUE if the id is found; B_FALSE if not found. 18126419Ssb155480 */ 18136419Ssb155480 static boolean_t 18146419Ssb155480 vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid) 18156419Ssb155480 { 18166419Ssb155480 int rv; 18176419Ssb155480 mod_hash_val_t vp; 18186419Ssb155480 18196419Ssb155480 rv = mod_hash_find(vlan_hashp, VLAN_ID_KEY(vid), (mod_hash_val_t *)&vp); 18206419Ssb155480 18216419Ssb155480 if (rv != 0) 18226419Ssb155480 return (B_FALSE); 18236419Ssb155480 18246419Ssb155480 return (B_TRUE); 18256419Ssb155480 } 18266419Ssb155480 18276419Ssb155480 /* 18285935Ssb155480 * This function reads "priority-ether-types" property from md. This property 18295935Ssb155480 * is used to enable support for priority frames. Applications which need 18305935Ssb155480 * guaranteed and timely delivery of certain high priority frames to/from 18315935Ssb155480 * a vnet or vsw within ldoms, should configure this property by providing 18325935Ssb155480 * the ether type(s) for which the priority facility is needed. 18335935Ssb155480 * Normal data frames are delivered over a ldc channel using the descriptor 18345935Ssb155480 * ring mechanism which is constrained by factors such as descriptor ring size, 18355935Ssb155480 * the rate at which the ring is processed at the peer ldc end point, etc. 18365935Ssb155480 * The priority mechanism provides an Out-Of-Band path to send/receive frames 18375935Ssb155480 * as raw pkt data (VIO_PKT_DATA) messages over the channel, avoiding the 18385935Ssb155480 * descriptor ring path and enables a more reliable and timely delivery of 18395935Ssb155480 * frames to the peer. 18405935Ssb155480 */ 18415935Ssb155480 static void 18425935Ssb155480 vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp, mde_cookie_t node) 18435935Ssb155480 { 18445935Ssb155480 int rv; 18455935Ssb155480 uint16_t *types; 18465935Ssb155480 uint64_t *data; 18475935Ssb155480 int size; 18485935Ssb155480 int i; 18495935Ssb155480 size_t mblk_sz; 18505935Ssb155480 18515935Ssb155480 rv = md_get_prop_data(mdp, node, pri_types_propname, 18525935Ssb155480 (uint8_t **)&data, &size); 18535935Ssb155480 if (rv != 0) { 18545935Ssb155480 /* 18555935Ssb155480 * Property may not exist if we are running pre-ldoms1.1 f/w. 18565935Ssb155480 * Check if 'vgen_pri_eth_type' has been set in that case. 18575935Ssb155480 */ 18585935Ssb155480 if (vgen_pri_eth_type != 0) { 18595935Ssb155480 size = sizeof (vgen_pri_eth_type); 18605935Ssb155480 data = &vgen_pri_eth_type; 18615935Ssb155480 } else { 18626495Sspeer DBG2(vgenp, NULL, 18635935Ssb155480 "prop(%s) not found", pri_types_propname); 18645935Ssb155480 size = 0; 18655935Ssb155480 } 18665935Ssb155480 } 18675935Ssb155480 18685935Ssb155480 if (size == 0) { 18695935Ssb155480 vgenp->pri_num_types = 0; 18705935Ssb155480 return; 18715935Ssb155480 } 18725935Ssb155480 18735935Ssb155480 /* 18745935Ssb155480 * we have some priority-ether-types defined; 18755935Ssb155480 * allocate a table of these types and also 18765935Ssb155480 * allocate a pool of mblks to transmit these 18775935Ssb155480 * priority packets. 18785935Ssb155480 */ 18795935Ssb155480 size /= sizeof (uint64_t); 18805935Ssb155480 vgenp->pri_num_types = size; 18815935Ssb155480 vgenp->pri_types = kmem_zalloc(size * sizeof (uint16_t), KM_SLEEP); 18825935Ssb155480 for (i = 0, types = vgenp->pri_types; i < size; i++) { 18835935Ssb155480 types[i] = data[i] & 0xFFFF; 18845935Ssb155480 } 18856419Ssb155480 mblk_sz = (VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size + 7) & ~7; 18865935Ssb155480 (void) vio_create_mblks(vgen_pri_tx_nmblks, mblk_sz, 18875935Ssb155480 &vgenp->pri_tx_vmp); 18885935Ssb155480 } 18895935Ssb155480 18907529SSriharsha.Basavapatna@Sun.COM static void 18917529SSriharsha.Basavapatna@Sun.COM vgen_mtu_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node, uint32_t *mtu) 18927529SSriharsha.Basavapatna@Sun.COM { 18937529SSriharsha.Basavapatna@Sun.COM int rv; 18947529SSriharsha.Basavapatna@Sun.COM uint64_t val; 18957529SSriharsha.Basavapatna@Sun.COM char *mtu_propname; 18967529SSriharsha.Basavapatna@Sun.COM 18977529SSriharsha.Basavapatna@Sun.COM mtu_propname = vgen_mtu_propname; 18987529SSriharsha.Basavapatna@Sun.COM 18997529SSriharsha.Basavapatna@Sun.COM rv = md_get_prop_val(mdp, node, mtu_propname, &val); 19007529SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 19017529SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, NULL, "prop(%s) not found", mtu_propname); 19027529SSriharsha.Basavapatna@Sun.COM *mtu = vnet_ethermtu; 19037529SSriharsha.Basavapatna@Sun.COM } else { 19047529SSriharsha.Basavapatna@Sun.COM 19057529SSriharsha.Basavapatna@Sun.COM *mtu = val & 0xFFFF; 19067529SSriharsha.Basavapatna@Sun.COM DBG2(vgenp, NULL, "%s(%d): (%d)\n", mtu_propname, 19077529SSriharsha.Basavapatna@Sun.COM vgenp->instance, *mtu); 19087529SSriharsha.Basavapatna@Sun.COM } 19097529SSriharsha.Basavapatna@Sun.COM } 19107529SSriharsha.Basavapatna@Sun.COM 19111991Sheppo /* register with MD event generator */ 19121991Sheppo static int 19131991Sheppo vgen_mdeg_reg(vgen_t *vgenp) 19141991Sheppo { 19151991Sheppo mdeg_prop_spec_t *pspecp; 19161991Sheppo mdeg_node_spec_t *parentp; 19171991Sheppo uint_t templatesz; 19181991Sheppo int rv; 19196419Ssb155480 mdeg_handle_t dev_hdl = NULL; 19206419Ssb155480 mdeg_handle_t port_hdl = NULL; 19216419Ssb155480 19221991Sheppo templatesz = sizeof (vgen_prop_template); 19231991Sheppo pspecp = kmem_zalloc(templatesz, KM_NOSLEEP); 19241991Sheppo if (pspecp == NULL) { 19251991Sheppo return (DDI_FAILURE); 19261991Sheppo } 19271991Sheppo parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP); 19281991Sheppo if (parentp == NULL) { 19291991Sheppo kmem_free(pspecp, templatesz); 19301991Sheppo return (DDI_FAILURE); 19311991Sheppo } 19321991Sheppo 19331991Sheppo bcopy(vgen_prop_template, pspecp, templatesz); 19341991Sheppo 19351991Sheppo /* 19361991Sheppo * NOTE: The instance here refers to the value of "reg" property and 19371991Sheppo * not the dev_info instance (ddi_get_instance()) of vnet. 19381991Sheppo */ 19396419Ssb155480 VGEN_SET_MDEG_PROP_INST(pspecp, vgenp->regprop); 19401991Sheppo 19411991Sheppo parentp->namep = "virtual-device"; 19421991Sheppo parentp->specp = pspecp; 19431991Sheppo 19441991Sheppo /* save parentp in vgen_t */ 19451991Sheppo vgenp->mdeg_parentp = parentp; 19461991Sheppo 19476419Ssb155480 /* 19486419Ssb155480 * Register an interest in 'virtual-device' nodes with a 19496419Ssb155480 * 'name' property of 'network' 19506419Ssb155480 */ 19516419Ssb155480 rv = mdeg_register(parentp, &vdev_match, vgen_mdeg_cb, vgenp, &dev_hdl); 19521991Sheppo if (rv != MDEG_SUCCESS) { 19534647Sraghuram DERR(vgenp, NULL, "mdeg_register failed\n"); 19546419Ssb155480 goto mdeg_reg_fail; 19556419Ssb155480 } 19566419Ssb155480 19576419Ssb155480 /* Register an interest in 'port' nodes */ 19586419Ssb155480 rv = mdeg_register(parentp, &vport_match, vgen_mdeg_port_cb, vgenp, 19596419Ssb155480 &port_hdl); 19606419Ssb155480 if (rv != MDEG_SUCCESS) { 19616419Ssb155480 DERR(vgenp, NULL, "mdeg_register failed\n"); 19626419Ssb155480 goto mdeg_reg_fail; 19631991Sheppo } 19641991Sheppo 19651991Sheppo /* save mdeg handle in vgen_t */ 19666419Ssb155480 vgenp->mdeg_dev_hdl = dev_hdl; 19676419Ssb155480 vgenp->mdeg_port_hdl = port_hdl; 19681991Sheppo 19691991Sheppo return (DDI_SUCCESS); 19706419Ssb155480 19716419Ssb155480 mdeg_reg_fail: 19726419Ssb155480 if (dev_hdl != NULL) { 19736419Ssb155480 (void) mdeg_unregister(dev_hdl); 19746419Ssb155480 } 19756419Ssb155480 KMEM_FREE(parentp); 19766419Ssb155480 kmem_free(pspecp, templatesz); 19776419Ssb155480 vgenp->mdeg_parentp = NULL; 19786419Ssb155480 return (DDI_FAILURE); 19791991Sheppo } 19801991Sheppo 19811991Sheppo /* unregister with MD event generator */ 19821991Sheppo static void 19831991Sheppo vgen_mdeg_unreg(vgen_t *vgenp) 19841991Sheppo { 19856419Ssb155480 (void) mdeg_unregister(vgenp->mdeg_dev_hdl); 19866419Ssb155480 (void) mdeg_unregister(vgenp->mdeg_port_hdl); 19873297Ssb155480 kmem_free(vgenp->mdeg_parentp->specp, sizeof (vgen_prop_template)); 19881991Sheppo KMEM_FREE(vgenp->mdeg_parentp); 19891991Sheppo vgenp->mdeg_parentp = NULL; 19906419Ssb155480 vgenp->mdeg_dev_hdl = NULL; 19916419Ssb155480 vgenp->mdeg_port_hdl = NULL; 19921991Sheppo } 19931991Sheppo 19946419Ssb155480 /* mdeg callback function for the port node */ 19951991Sheppo static int 19966419Ssb155480 vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp) 19971991Sheppo { 19981991Sheppo int idx; 19991991Sheppo int vsw_idx = -1; 20001991Sheppo uint64_t val; 20011991Sheppo vgen_t *vgenp; 20021991Sheppo 20031991Sheppo if ((resp == NULL) || (cb_argp == NULL)) { 20041991Sheppo return (MDEG_FAILURE); 20051991Sheppo } 20061991Sheppo 20071991Sheppo vgenp = (vgen_t *)cb_argp; 20084647Sraghuram DBG1(vgenp, NULL, "enter\n"); 20091991Sheppo 20101991Sheppo mutex_enter(&vgenp->lock); 20111991Sheppo 20124647Sraghuram DBG1(vgenp, NULL, "ports: removed(%x), " 20134647Sraghuram "added(%x), updated(%x)\n", resp->removed.nelem, 20144647Sraghuram resp->added.nelem, resp->match_curr.nelem); 20151991Sheppo 20161991Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 20171991Sheppo (void) vgen_remove_port(vgenp, resp->removed.mdp, 20181991Sheppo resp->removed.mdep[idx]); 20191991Sheppo } 20201991Sheppo 20211991Sheppo if (vgenp->vsw_portp == NULL) { 20221991Sheppo /* 20231991Sheppo * find vsw_port and add it first, because other ports need 20241991Sheppo * this when adding fdb entry (see vgen_port_init()). 20251991Sheppo */ 20261991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 20271991Sheppo if (!(md_get_prop_val(resp->added.mdp, 20281991Sheppo resp->added.mdep[idx], swport_propname, &val))) { 20291991Sheppo if (val == 0) { 20301991Sheppo /* 20311991Sheppo * This port is connected to the 20326419Ssb155480 * vsw on service domain. 20331991Sheppo */ 20341991Sheppo vsw_idx = idx; 20354663Szk194757 if (vgen_add_port(vgenp, 20361991Sheppo resp->added.mdp, 20374663Szk194757 resp->added.mdep[idx]) != 20384663Szk194757 DDI_SUCCESS) { 20394663Szk194757 cmn_err(CE_NOTE, "vnet%d Could " 20404663Szk194757 "not initialize virtual " 20414663Szk194757 "switch port.", 20426495Sspeer vgenp->instance); 20434663Szk194757 mutex_exit(&vgenp->lock); 20444663Szk194757 return (MDEG_FAILURE); 20454663Szk194757 } 20461991Sheppo break; 20471991Sheppo } 20481991Sheppo } 20491991Sheppo } 20504666Szk194757 if (vsw_idx == -1) { 20514647Sraghuram DWARN(vgenp, NULL, "can't find vsw_port\n"); 20524663Szk194757 mutex_exit(&vgenp->lock); 20531991Sheppo return (MDEG_FAILURE); 20541991Sheppo } 20551991Sheppo } 20561991Sheppo 20571991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 20581991Sheppo if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */ 20591991Sheppo continue; 20604663Szk194757 20614663Szk194757 /* If this port can't be added just skip it. */ 20621991Sheppo (void) vgen_add_port(vgenp, resp->added.mdp, 20631991Sheppo resp->added.mdep[idx]); 20641991Sheppo } 20651991Sheppo 20661991Sheppo for (idx = 0; idx < resp->match_curr.nelem; idx++) { 20671991Sheppo (void) vgen_update_port(vgenp, resp->match_curr.mdp, 20681991Sheppo resp->match_curr.mdep[idx], 20691991Sheppo resp->match_prev.mdp, 20701991Sheppo resp->match_prev.mdep[idx]); 20711991Sheppo } 20721991Sheppo 20731991Sheppo mutex_exit(&vgenp->lock); 20744647Sraghuram DBG1(vgenp, NULL, "exit\n"); 20751991Sheppo return (MDEG_SUCCESS); 20761991Sheppo } 20771991Sheppo 20786419Ssb155480 /* mdeg callback function for the vnet node */ 20796419Ssb155480 static int 20806419Ssb155480 vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 20816419Ssb155480 { 20826419Ssb155480 vgen_t *vgenp; 20836419Ssb155480 vnet_t *vnetp; 20846419Ssb155480 md_t *mdp; 20856419Ssb155480 mde_cookie_t node; 20866419Ssb155480 uint64_t inst; 20876419Ssb155480 char *node_name = NULL; 20886419Ssb155480 20896419Ssb155480 if ((resp == NULL) || (cb_argp == NULL)) { 20906419Ssb155480 return (MDEG_FAILURE); 20916419Ssb155480 } 20926419Ssb155480 20936419Ssb155480 vgenp = (vgen_t *)cb_argp; 20946419Ssb155480 vnetp = vgenp->vnetp; 20956419Ssb155480 2096*7572SWentao.Yang@Sun.COM DBG1(vgenp, NULL, "added %d : removed %d : curr matched %d" 20976419Ssb155480 " : prev matched %d", resp->added.nelem, resp->removed.nelem, 20986419Ssb155480 resp->match_curr.nelem, resp->match_prev.nelem); 20996419Ssb155480 21006419Ssb155480 mutex_enter(&vgenp->lock); 21016419Ssb155480 21026419Ssb155480 /* 21036419Ssb155480 * We get an initial callback for this node as 'added' after 21046419Ssb155480 * registering with mdeg. Note that we would have already gathered 21056419Ssb155480 * information about this vnet node by walking MD earlier during attach 21066419Ssb155480 * (in vgen_read_mdprops()). So, there is a window where the properties 21076419Ssb155480 * of this node might have changed when we get this initial 'added' 21086419Ssb155480 * callback. We handle this as if an update occured and invoke the same 21096419Ssb155480 * function which handles updates to the properties of this vnet-node 21106419Ssb155480 * if any. A non-zero 'match' value indicates that the MD has been 21116419Ssb155480 * updated and that a 'network' node is present which may or may not 21126419Ssb155480 * have been updated. It is up to the clients to examine their own 21136419Ssb155480 * nodes and determine if they have changed. 21146419Ssb155480 */ 21156419Ssb155480 if (resp->added.nelem != 0) { 21166419Ssb155480 21176419Ssb155480 if (resp->added.nelem != 1) { 21186419Ssb155480 cmn_err(CE_NOTE, "!vnet%d: number of nodes added " 21196419Ssb155480 "invalid: %d\n", vnetp->instance, 21206419Ssb155480 resp->added.nelem); 21216419Ssb155480 goto vgen_mdeg_cb_err; 21226419Ssb155480 } 21236419Ssb155480 21246419Ssb155480 mdp = resp->added.mdp; 21256419Ssb155480 node = resp->added.mdep[0]; 21266419Ssb155480 21276419Ssb155480 } else if (resp->match_curr.nelem != 0) { 21286419Ssb155480 21296419Ssb155480 if (resp->match_curr.nelem != 1) { 21306419Ssb155480 cmn_err(CE_NOTE, "!vnet%d: number of nodes updated " 21316419Ssb155480 "invalid: %d\n", vnetp->instance, 21326419Ssb155480 resp->match_curr.nelem); 21336419Ssb155480 goto vgen_mdeg_cb_err; 21346419Ssb155480 } 21356419Ssb155480 21366419Ssb155480 mdp = resp->match_curr.mdp; 21376419Ssb155480 node = resp->match_curr.mdep[0]; 21386419Ssb155480 21396419Ssb155480 } else { 21406419Ssb155480 goto vgen_mdeg_cb_err; 21416419Ssb155480 } 21426419Ssb155480 21436419Ssb155480 /* Validate name and instance */ 21446419Ssb155480 if (md_get_prop_str(mdp, node, "name", &node_name) != 0) { 21456419Ssb155480 DERR(vgenp, NULL, "unable to get node name\n"); 21466419Ssb155480 goto vgen_mdeg_cb_err; 21476419Ssb155480 } 21486419Ssb155480 21496419Ssb155480 /* is this a virtual-network device? */ 21506419Ssb155480 if (strcmp(node_name, vnet_propname) != 0) { 21516419Ssb155480 DERR(vgenp, NULL, "%s: Invalid node name: %s\n", node_name); 21526419Ssb155480 goto vgen_mdeg_cb_err; 21536419Ssb155480 } 21546419Ssb155480 21556419Ssb155480 if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) { 21566419Ssb155480 DERR(vgenp, NULL, "prop(cfg-handle) not found\n"); 21576419Ssb155480 goto vgen_mdeg_cb_err; 21586419Ssb155480 } 21596419Ssb155480 21606495Sspeer /* is this the right instance of vnet? */ 21616419Ssb155480 if (inst != vgenp->regprop) { 21626419Ssb155480 DERR(vgenp, NULL, "Invalid cfg-handle: %lx\n", inst); 21636419Ssb155480 goto vgen_mdeg_cb_err; 21646419Ssb155480 } 21656419Ssb155480 21666419Ssb155480 vgen_update_md_prop(vgenp, mdp, node); 21676419Ssb155480 21686419Ssb155480 mutex_exit(&vgenp->lock); 21696419Ssb155480 return (MDEG_SUCCESS); 21706419Ssb155480 21716419Ssb155480 vgen_mdeg_cb_err: 21726419Ssb155480 mutex_exit(&vgenp->lock); 21736419Ssb155480 return (MDEG_FAILURE); 21746419Ssb155480 } 21756419Ssb155480 21766419Ssb155480 /* 21776419Ssb155480 * Check to see if the relevant properties in the specified node have 21786419Ssb155480 * changed, and if so take the appropriate action. 21796419Ssb155480 */ 21806419Ssb155480 static void 21816419Ssb155480 vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 21826419Ssb155480 { 21836419Ssb155480 uint16_t pvid; 21846419Ssb155480 uint16_t *vids; 21856419Ssb155480 uint16_t nvids; 21866419Ssb155480 vnet_t *vnetp = vgenp->vnetp; 21877529SSriharsha.Basavapatna@Sun.COM uint32_t mtu; 21887529SSriharsha.Basavapatna@Sun.COM enum { MD_init = 0x1, 21897529SSriharsha.Basavapatna@Sun.COM MD_vlans = 0x2, 21907529SSriharsha.Basavapatna@Sun.COM MD_mtu = 0x4 } updated; 21917529SSriharsha.Basavapatna@Sun.COM int rv; 21927529SSriharsha.Basavapatna@Sun.COM 21937529SSriharsha.Basavapatna@Sun.COM updated = MD_init; 21946419Ssb155480 21956419Ssb155480 /* Read the vlan ids */ 21966419Ssb155480 vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, mdex, &pvid, &vids, 21976419Ssb155480 &nvids, NULL); 21986419Ssb155480 21996419Ssb155480 /* Determine if there are any vlan id updates */ 22006419Ssb155480 if ((pvid != vnetp->pvid) || /* pvid changed? */ 22016419Ssb155480 (nvids != vnetp->nvids) || /* # of vids changed? */ 22026419Ssb155480 ((nvids != 0) && (vnetp->nvids != 0) && /* vids changed? */ 22036419Ssb155480 bcmp(vids, vnetp->vids, sizeof (uint16_t) * nvids))) { 22047529SSriharsha.Basavapatna@Sun.COM updated |= MD_vlans; 22057529SSriharsha.Basavapatna@Sun.COM } 22067529SSriharsha.Basavapatna@Sun.COM 22077529SSriharsha.Basavapatna@Sun.COM /* Read mtu */ 22087529SSriharsha.Basavapatna@Sun.COM vgen_mtu_read(vgenp, mdp, mdex, &mtu); 22097529SSriharsha.Basavapatna@Sun.COM if (mtu != vnetp->mtu) { 22107529SSriharsha.Basavapatna@Sun.COM if (mtu >= ETHERMTU && mtu <= VNET_MAX_MTU) { 22117529SSriharsha.Basavapatna@Sun.COM updated |= MD_mtu; 22127529SSriharsha.Basavapatna@Sun.COM } else { 22137529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu update" 22147529SSriharsha.Basavapatna@Sun.COM " as the specified value:%d is invalid\n", 22157529SSriharsha.Basavapatna@Sun.COM vnetp->instance, mtu); 22167529SSriharsha.Basavapatna@Sun.COM } 22177529SSriharsha.Basavapatna@Sun.COM } 22187529SSriharsha.Basavapatna@Sun.COM 22197529SSriharsha.Basavapatna@Sun.COM /* Now process the updated props */ 22207529SSriharsha.Basavapatna@Sun.COM 22217529SSriharsha.Basavapatna@Sun.COM if (updated & MD_vlans) { 22227529SSriharsha.Basavapatna@Sun.COM 22237529SSriharsha.Basavapatna@Sun.COM /* save the new vlan ids */ 22247529SSriharsha.Basavapatna@Sun.COM vnetp->pvid = pvid; 22257529SSriharsha.Basavapatna@Sun.COM if (vnetp->nvids != 0) { 22267529SSriharsha.Basavapatna@Sun.COM kmem_free(vnetp->vids, 22277529SSriharsha.Basavapatna@Sun.COM sizeof (uint16_t) * vnetp->nvids); 22287529SSriharsha.Basavapatna@Sun.COM vnetp->nvids = 0; 22297529SSriharsha.Basavapatna@Sun.COM } 22307529SSriharsha.Basavapatna@Sun.COM if (nvids != 0) { 22317529SSriharsha.Basavapatna@Sun.COM vnetp->nvids = nvids; 22327529SSriharsha.Basavapatna@Sun.COM vnetp->vids = vids; 22337529SSriharsha.Basavapatna@Sun.COM } 22347529SSriharsha.Basavapatna@Sun.COM 22357529SSriharsha.Basavapatna@Sun.COM /* reset vlan-unaware peers (ver < 1.3) and restart handshake */ 22367529SSriharsha.Basavapatna@Sun.COM vgen_reset_vlan_unaware_ports(vgenp); 22377529SSriharsha.Basavapatna@Sun.COM 22387529SSriharsha.Basavapatna@Sun.COM } else { 22397529SSriharsha.Basavapatna@Sun.COM 22406419Ssb155480 if (nvids != 0) { 22416419Ssb155480 kmem_free(vids, sizeof (uint16_t) * nvids); 22426419Ssb155480 } 22437529SSriharsha.Basavapatna@Sun.COM } 22447529SSriharsha.Basavapatna@Sun.COM 22457529SSriharsha.Basavapatna@Sun.COM if (updated & MD_mtu) { 22467529SSriharsha.Basavapatna@Sun.COM 22477529SSriharsha.Basavapatna@Sun.COM DBG2(vgenp, NULL, "curr_mtu(%d) new_mtu(%d)\n", 22487529SSriharsha.Basavapatna@Sun.COM vnetp->mtu, mtu); 22497529SSriharsha.Basavapatna@Sun.COM 22507529SSriharsha.Basavapatna@Sun.COM rv = vnet_mtu_update(vnetp, mtu); 22517529SSriharsha.Basavapatna@Sun.COM if (rv == 0) { 22527529SSriharsha.Basavapatna@Sun.COM vgenp->max_frame_size = mtu + 22537529SSriharsha.Basavapatna@Sun.COM sizeof (struct ether_header) + VLAN_TAGSZ; 22547529SSriharsha.Basavapatna@Sun.COM } 22557529SSriharsha.Basavapatna@Sun.COM } 22566419Ssb155480 } 22576419Ssb155480 22581991Sheppo /* add a new port to the device */ 22591991Sheppo static int 22601991Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 22611991Sheppo { 22626419Ssb155480 vgen_port_t *portp; 22636419Ssb155480 int rv; 22646419Ssb155480 22656419Ssb155480 portp = kmem_zalloc(sizeof (vgen_port_t), KM_SLEEP); 22666419Ssb155480 22676419Ssb155480 rv = vgen_port_read_props(portp, vgenp, mdp, mdex); 22686419Ssb155480 if (rv != DDI_SUCCESS) { 22696419Ssb155480 KMEM_FREE(portp); 22706419Ssb155480 return (DDI_FAILURE); 22716419Ssb155480 } 22726419Ssb155480 22736419Ssb155480 rv = vgen_port_attach(portp); 22746419Ssb155480 if (rv != DDI_SUCCESS) { 22756419Ssb155480 return (DDI_FAILURE); 22766419Ssb155480 } 22776419Ssb155480 22786419Ssb155480 return (DDI_SUCCESS); 22796419Ssb155480 } 22806419Ssb155480 22816419Ssb155480 /* read properties of the port from its md node */ 22826419Ssb155480 static int 22836419Ssb155480 vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp, 22846419Ssb155480 mde_cookie_t mdex) 22856419Ssb155480 { 22866419Ssb155480 uint64_t port_num; 22876419Ssb155480 uint64_t *ldc_ids; 22886419Ssb155480 uint64_t macaddr; 22896419Ssb155480 uint64_t val; 22906419Ssb155480 int num_ldcs; 22916419Ssb155480 int i; 22926419Ssb155480 int addrsz; 22936419Ssb155480 int num_nodes = 0; 22946419Ssb155480 int listsz = 0; 22956419Ssb155480 mde_cookie_t *listp = NULL; 22966419Ssb155480 uint8_t *addrp; 22971991Sheppo struct ether_addr ea; 22981991Sheppo 22991991Sheppo /* read "id" property to get the port number */ 23001991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 23014647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 23021991Sheppo return (DDI_FAILURE); 23031991Sheppo } 23041991Sheppo 23051991Sheppo /* 23061991Sheppo * Find the channel endpoint node(s) under this port node. 23071991Sheppo */ 23081991Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) { 23094647Sraghuram DWARN(vgenp, NULL, "invalid number of nodes found (%d)", 23104647Sraghuram num_nodes); 23111991Sheppo return (DDI_FAILURE); 23121991Sheppo } 23131991Sheppo 23141991Sheppo /* allocate space for node list */ 23151991Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 23161991Sheppo listp = kmem_zalloc(listsz, KM_NOSLEEP); 23171991Sheppo if (listp == NULL) 23181991Sheppo return (DDI_FAILURE); 23191991Sheppo 23201991Sheppo num_ldcs = md_scan_dag(mdp, mdex, 23214650Sraghuram md_find_name(mdp, channel_propname), 23224650Sraghuram md_find_name(mdp, "fwd"), listp); 23231991Sheppo 23241991Sheppo if (num_ldcs <= 0) { 23254647Sraghuram DWARN(vgenp, NULL, "can't find %s nodes", channel_propname); 23261991Sheppo kmem_free(listp, listsz); 23271991Sheppo return (DDI_FAILURE); 23281991Sheppo } 23291991Sheppo 23304647Sraghuram DBG2(vgenp, NULL, "num_ldcs %d", num_ldcs); 23311991Sheppo 23321991Sheppo ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP); 23331991Sheppo if (ldc_ids == NULL) { 23341991Sheppo kmem_free(listp, listsz); 23351991Sheppo return (DDI_FAILURE); 23361991Sheppo } 23371991Sheppo 23381991Sheppo for (i = 0; i < num_ldcs; i++) { 23391991Sheppo /* read channel ids */ 23401991Sheppo if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) { 23414647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", 23424647Sraghuram id_propname); 23431991Sheppo kmem_free(listp, listsz); 23441991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 23451991Sheppo return (DDI_FAILURE); 23461991Sheppo } 23474647Sraghuram DBG2(vgenp, NULL, "ldc_id 0x%llx", ldc_ids[i]); 23481991Sheppo } 23491991Sheppo 23501991Sheppo kmem_free(listp, listsz); 23511991Sheppo 23521991Sheppo if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp, 23531991Sheppo &addrsz)) { 23544647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", rmacaddr_propname); 23551991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 23561991Sheppo return (DDI_FAILURE); 23571991Sheppo } 23581991Sheppo 23591991Sheppo if (addrsz < ETHERADDRL) { 23604647Sraghuram DWARN(vgenp, NULL, "invalid address size (%d)\n", addrsz); 23611991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 23621991Sheppo return (DDI_FAILURE); 23631991Sheppo } 23641991Sheppo 23651991Sheppo macaddr = *((uint64_t *)addrp); 23661991Sheppo 23674647Sraghuram DBG2(vgenp, NULL, "remote mac address 0x%llx\n", macaddr); 23681991Sheppo 23691991Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 23701991Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF; 23711991Sheppo macaddr >>= 8; 23721991Sheppo } 23731991Sheppo 23741991Sheppo if (vgenp->vsw_portp == NULL) { 23751991Sheppo if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) { 23761991Sheppo if (val == 0) { 23776495Sspeer (void) atomic_swap_32( 23786495Sspeer &vgenp->vsw_port_refcnt, 0); 23796419Ssb155480 /* This port is connected to the vsw */ 23806419Ssb155480 vgenp->vsw_portp = portp; 23811991Sheppo } 23821991Sheppo } 23831991Sheppo } 23846419Ssb155480 23856419Ssb155480 /* now update all properties into the port */ 23866419Ssb155480 portp->vgenp = vgenp; 23876419Ssb155480 portp->port_num = port_num; 23886419Ssb155480 ether_copy(&ea, &portp->macaddr); 23896419Ssb155480 portp->ldc_ids = kmem_zalloc(sizeof (uint64_t) * num_ldcs, KM_SLEEP); 23906419Ssb155480 bcopy(ldc_ids, portp->ldc_ids, sizeof (uint64_t) * num_ldcs); 23916419Ssb155480 portp->num_ldcs = num_ldcs; 23926419Ssb155480 23936419Ssb155480 /* read vlan id properties of this port node */ 23946419Ssb155480 vgen_vlan_read_ids(portp, VGEN_PEER, mdp, mdex, &portp->pvid, 23956419Ssb155480 &portp->vids, &portp->nvids, NULL); 23961991Sheppo 23971991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 23981991Sheppo 23996419Ssb155480 return (DDI_SUCCESS); 24001991Sheppo } 24011991Sheppo 24021991Sheppo /* remove a port from the device */ 24031991Sheppo static int 24041991Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 24051991Sheppo { 24061991Sheppo uint64_t port_num; 24071991Sheppo vgen_port_t *portp; 24081991Sheppo vgen_portlist_t *plistp; 24091991Sheppo 24101991Sheppo /* read "id" property to get the port number */ 24111991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 24124647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 24131991Sheppo return (DDI_FAILURE); 24141991Sheppo } 24151991Sheppo 24161991Sheppo plistp = &(vgenp->vgenports); 24171991Sheppo 24181991Sheppo WRITE_ENTER(&plistp->rwlock); 24191991Sheppo portp = vgen_port_lookup(plistp, (int)port_num); 24201991Sheppo if (portp == NULL) { 24214647Sraghuram DWARN(vgenp, NULL, "can't find port(%lx)\n", port_num); 24221991Sheppo RW_EXIT(&plistp->rwlock); 24231991Sheppo return (DDI_FAILURE); 24241991Sheppo } 24251991Sheppo 24261991Sheppo vgen_port_detach_mdeg(portp); 24271991Sheppo RW_EXIT(&plistp->rwlock); 24281991Sheppo 24291991Sheppo return (DDI_SUCCESS); 24301991Sheppo } 24311991Sheppo 24321991Sheppo /* attach a port to the device based on mdeg data */ 24331991Sheppo static int 24346419Ssb155480 vgen_port_attach(vgen_port_t *portp) 24351991Sheppo { 24361991Sheppo int i; 24376419Ssb155480 vgen_portlist_t *plistp; 24386419Ssb155480 vgen_t *vgenp; 24396419Ssb155480 uint64_t *ldcids; 24406419Ssb155480 uint32_t num_ldcs; 24416495Sspeer mac_register_t *macp; 24426495Sspeer vio_net_res_type_t type; 24436495Sspeer int rv; 24446419Ssb155480 24456419Ssb155480 ASSERT(portp != NULL); 24466419Ssb155480 24476419Ssb155480 vgenp = portp->vgenp; 24486419Ssb155480 ldcids = portp->ldc_ids; 24496419Ssb155480 num_ldcs = portp->num_ldcs; 24501991Sheppo 24514647Sraghuram DBG1(vgenp, NULL, "port_num(%d)\n", portp->port_num); 24521991Sheppo 24536495Sspeer mutex_init(&portp->lock, NULL, MUTEX_DRIVER, NULL); 24546419Ssb155480 rw_init(&portp->ldclist.rwlock, NULL, RW_DRIVER, NULL); 24551991Sheppo portp->ldclist.headp = NULL; 24566419Ssb155480 24576419Ssb155480 for (i = 0; i < num_ldcs; i++) { 24584647Sraghuram DBG2(vgenp, NULL, "ldcid (%lx)\n", ldcids[i]); 24594663Szk194757 if (vgen_ldc_attach(portp, ldcids[i]) == DDI_FAILURE) { 24604663Szk194757 vgen_port_detach(portp); 24614663Szk194757 return (DDI_FAILURE); 24624663Szk194757 } 24631991Sheppo } 24641991Sheppo 24656419Ssb155480 /* create vlan id hash table */ 24666419Ssb155480 vgen_vlan_create_hash(portp); 24676419Ssb155480 24686495Sspeer if (portp == vgenp->vsw_portp) { 24696495Sspeer /* This port is connected to the switch port */ 24706495Sspeer vgenp->vsw_portp = portp; 24716495Sspeer (void) atomic_swap_32(&portp->use_vsw_port, B_FALSE); 24726495Sspeer type = VIO_NET_RES_LDC_SERVICE; 24736495Sspeer } else { 24746495Sspeer (void) atomic_swap_32(&portp->use_vsw_port, B_TRUE); 24756495Sspeer type = VIO_NET_RES_LDC_GUEST; 24766495Sspeer } 24776495Sspeer 24786495Sspeer if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 24796495Sspeer vgen_port_detach(portp); 24806495Sspeer return (DDI_FAILURE); 24816495Sspeer } 24826495Sspeer macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 24836495Sspeer macp->m_driver = portp; 24846495Sspeer macp->m_dip = vgenp->vnetdip; 24856495Sspeer macp->m_src_addr = (uint8_t *)&(vgenp->macaddr); 24866495Sspeer macp->m_callbacks = &vgen_m_callbacks; 24876495Sspeer macp->m_min_sdu = 0; 24886495Sspeer macp->m_max_sdu = ETHERMTU; 24896495Sspeer 24906495Sspeer mutex_enter(&portp->lock); 24916495Sspeer rv = vio_net_resource_reg(macp, type, vgenp->macaddr, 24926495Sspeer portp->macaddr, &portp->vhp, &portp->vcb); 24936495Sspeer mutex_exit(&portp->lock); 24946495Sspeer mac_free(macp); 24956495Sspeer 24966495Sspeer if (rv == 0) { 24976495Sspeer /* link it into the list of ports */ 24986495Sspeer plistp = &(vgenp->vgenports); 24996495Sspeer WRITE_ENTER(&plistp->rwlock); 25006495Sspeer vgen_port_list_insert(portp); 25016495Sspeer RW_EXIT(&plistp->rwlock); 25026495Sspeer } else { 25036495Sspeer DERR(vgenp, NULL, "vio_net_resource_reg failed for portp=0x%p", 25046495Sspeer portp); 25056495Sspeer vgen_port_detach(portp); 25061991Sheppo } 25071991Sheppo 25084647Sraghuram DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num); 25091991Sheppo return (DDI_SUCCESS); 25101991Sheppo } 25111991Sheppo 25121991Sheppo /* detach a port from the device based on mdeg data */ 25131991Sheppo static void 25141991Sheppo vgen_port_detach_mdeg(vgen_port_t *portp) 25151991Sheppo { 25161991Sheppo vgen_t *vgenp = portp->vgenp; 25171991Sheppo 25184647Sraghuram DBG1(vgenp, NULL, "enter: port_num(%d)\n", portp->port_num); 25196495Sspeer 25206495Sspeer mutex_enter(&portp->lock); 25216495Sspeer 25221991Sheppo /* stop the port if needed */ 25236495Sspeer if (portp->flags & VGEN_STARTED) { 25241991Sheppo vgen_port_uninit(portp); 25251991Sheppo } 25266495Sspeer 25276495Sspeer mutex_exit(&portp->lock); 25281991Sheppo vgen_port_detach(portp); 25291991Sheppo 25304647Sraghuram DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num); 25311991Sheppo } 25321991Sheppo 25331991Sheppo static int 25341991Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex, 25351991Sheppo md_t *prev_mdp, mde_cookie_t prev_mdex) 25361991Sheppo { 25376419Ssb155480 uint64_t cport_num; 25386419Ssb155480 uint64_t pport_num; 25396419Ssb155480 vgen_portlist_t *plistp; 25406419Ssb155480 vgen_port_t *portp; 25416419Ssb155480 boolean_t updated_vlans = B_FALSE; 25426419Ssb155480 uint16_t pvid; 25436419Ssb155480 uint16_t *vids; 25446419Ssb155480 uint16_t nvids; 25456419Ssb155480 25466419Ssb155480 /* 25476419Ssb155480 * For now, we get port updates only if vlan ids changed. 25486419Ssb155480 * We read the port num and do some sanity check. 25496419Ssb155480 */ 25506419Ssb155480 if (md_get_prop_val(curr_mdp, curr_mdex, id_propname, &cport_num)) { 25516419Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 25526419Ssb155480 return (DDI_FAILURE); 25536419Ssb155480 } 25546419Ssb155480 25556419Ssb155480 if (md_get_prop_val(prev_mdp, prev_mdex, id_propname, &pport_num)) { 25566419Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 25576419Ssb155480 return (DDI_FAILURE); 25586419Ssb155480 } 25596419Ssb155480 if (cport_num != pport_num) 25606419Ssb155480 return (DDI_FAILURE); 25616419Ssb155480 25626419Ssb155480 plistp = &(vgenp->vgenports); 25636419Ssb155480 25646419Ssb155480 READ_ENTER(&plistp->rwlock); 25656419Ssb155480 25666419Ssb155480 portp = vgen_port_lookup(plistp, (int)cport_num); 25676419Ssb155480 if (portp == NULL) { 25686419Ssb155480 DWARN(vgenp, NULL, "can't find port(%lx)\n", cport_num); 25696419Ssb155480 RW_EXIT(&plistp->rwlock); 25706419Ssb155480 return (DDI_FAILURE); 25716419Ssb155480 } 25726419Ssb155480 25736419Ssb155480 /* Read the vlan ids */ 25746419Ssb155480 vgen_vlan_read_ids(portp, VGEN_PEER, curr_mdp, curr_mdex, &pvid, &vids, 25756419Ssb155480 &nvids, NULL); 25766419Ssb155480 25776419Ssb155480 /* Determine if there are any vlan id updates */ 25786419Ssb155480 if ((pvid != portp->pvid) || /* pvid changed? */ 25796419Ssb155480 (nvids != portp->nvids) || /* # of vids changed? */ 25806419Ssb155480 ((nvids != 0) && (portp->nvids != 0) && /* vids changed? */ 25816419Ssb155480 bcmp(vids, portp->vids, sizeof (uint16_t) * nvids))) { 25826419Ssb155480 updated_vlans = B_TRUE; 25836419Ssb155480 } 25846419Ssb155480 25856419Ssb155480 if (updated_vlans == B_FALSE) { 25866419Ssb155480 RW_EXIT(&plistp->rwlock); 25876419Ssb155480 return (DDI_FAILURE); 25886419Ssb155480 } 25896419Ssb155480 25906419Ssb155480 /* remove the port from vlans it has been assigned to */ 25916419Ssb155480 vgen_vlan_remove_ids(portp); 25926419Ssb155480 25936419Ssb155480 /* save the new vlan ids */ 25946419Ssb155480 portp->pvid = pvid; 25956419Ssb155480 if (portp->nvids != 0) { 25966419Ssb155480 kmem_free(portp->vids, sizeof (uint16_t) * portp->nvids); 25976419Ssb155480 portp->nvids = 0; 25986419Ssb155480 } 25996419Ssb155480 if (nvids != 0) { 26006419Ssb155480 portp->vids = kmem_zalloc(sizeof (uint16_t) * nvids, KM_SLEEP); 26016419Ssb155480 bcopy(vids, portp->vids, sizeof (uint16_t) * nvids); 26026419Ssb155480 portp->nvids = nvids; 26036419Ssb155480 kmem_free(vids, sizeof (uint16_t) * nvids); 26046419Ssb155480 } 26056419Ssb155480 26066419Ssb155480 /* add port to the new vlans */ 26076419Ssb155480 vgen_vlan_add_ids(portp); 26086419Ssb155480 26096419Ssb155480 /* reset the port if it is vlan unaware (ver < 1.3) */ 26106419Ssb155480 vgen_vlan_unaware_port_reset(portp); 26116419Ssb155480 26126419Ssb155480 RW_EXIT(&plistp->rwlock); 26136419Ssb155480 26141991Sheppo return (DDI_SUCCESS); 26151991Sheppo } 26161991Sheppo 26171991Sheppo static uint64_t 26182311Sseb vgen_port_stat(vgen_port_t *portp, uint_t stat) 26191991Sheppo { 26201991Sheppo vgen_ldclist_t *ldclp; 26211991Sheppo vgen_ldc_t *ldcp; 26221991Sheppo uint64_t val; 26231991Sheppo 26241991Sheppo val = 0; 26251991Sheppo ldclp = &portp->ldclist; 26261991Sheppo 26271991Sheppo READ_ENTER(&ldclp->rwlock); 26281991Sheppo for (ldcp = ldclp->headp; ldcp != NULL; ldcp = ldcp->nextp) { 26291991Sheppo val += vgen_ldc_stat(ldcp, stat); 26301991Sheppo } 26311991Sheppo RW_EXIT(&ldclp->rwlock); 26321991Sheppo 26331991Sheppo return (val); 26341991Sheppo } 26351991Sheppo 26367529SSriharsha.Basavapatna@Sun.COM /* allocate receive resources */ 26377529SSriharsha.Basavapatna@Sun.COM static int 26387529SSriharsha.Basavapatna@Sun.COM vgen_init_multipools(vgen_ldc_t *ldcp) 26397529SSriharsha.Basavapatna@Sun.COM { 26407529SSriharsha.Basavapatna@Sun.COM size_t data_sz; 26417529SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp); 26427529SSriharsha.Basavapatna@Sun.COM int status; 26437529SSriharsha.Basavapatna@Sun.COM uint32_t sz1 = 0; 26447529SSriharsha.Basavapatna@Sun.COM uint32_t sz2 = 0; 26457529SSriharsha.Basavapatna@Sun.COM uint32_t sz3 = 0; 26467529SSriharsha.Basavapatna@Sun.COM uint32_t sz4 = 0; 26477529SSriharsha.Basavapatna@Sun.COM 26487529SSriharsha.Basavapatna@Sun.COM /* 26497529SSriharsha.Basavapatna@Sun.COM * We round up the mtu specified to be a multiple of 2K. 26507529SSriharsha.Basavapatna@Sun.COM * We then create rx pools based on the rounded up size. 26517529SSriharsha.Basavapatna@Sun.COM */ 26527529SSriharsha.Basavapatna@Sun.COM data_sz = vgenp->max_frame_size + VNET_IPALIGN + VNET_LDCALIGN; 26537529SSriharsha.Basavapatna@Sun.COM data_sz = VNET_ROUNDUP_2K(data_sz); 26547529SSriharsha.Basavapatna@Sun.COM 26557529SSriharsha.Basavapatna@Sun.COM /* 26567529SSriharsha.Basavapatna@Sun.COM * If pool sizes are specified, use them. Note that the presence of 26577529SSriharsha.Basavapatna@Sun.COM * the first tunable will be used as a hint. 26587529SSriharsha.Basavapatna@Sun.COM */ 26597529SSriharsha.Basavapatna@Sun.COM if (vgen_rbufsz1 != 0) { 26607529SSriharsha.Basavapatna@Sun.COM 26617529SSriharsha.Basavapatna@Sun.COM sz1 = vgen_rbufsz1; 26627529SSriharsha.Basavapatna@Sun.COM sz2 = vgen_rbufsz2; 26637529SSriharsha.Basavapatna@Sun.COM sz3 = vgen_rbufsz3; 26647529SSriharsha.Basavapatna@Sun.COM sz4 = vgen_rbufsz4; 26657529SSriharsha.Basavapatna@Sun.COM 26667529SSriharsha.Basavapatna@Sun.COM if (sz4 == 0) { /* need 3 pools */ 26677529SSriharsha.Basavapatna@Sun.COM 26687529SSriharsha.Basavapatna@Sun.COM ldcp->max_rxpool_size = sz3; 26697529SSriharsha.Basavapatna@Sun.COM status = vio_init_multipools(&ldcp->vmp, 26707529SSriharsha.Basavapatna@Sun.COM VGEN_NUM_VMPOOLS, sz1, sz2, sz3, vgen_nrbufs1, 26717529SSriharsha.Basavapatna@Sun.COM vgen_nrbufs2, vgen_nrbufs3); 26727529SSriharsha.Basavapatna@Sun.COM 26737529SSriharsha.Basavapatna@Sun.COM } else { 26747529SSriharsha.Basavapatna@Sun.COM 26757529SSriharsha.Basavapatna@Sun.COM ldcp->max_rxpool_size = sz4; 26767529SSriharsha.Basavapatna@Sun.COM status = vio_init_multipools(&ldcp->vmp, 26777529SSriharsha.Basavapatna@Sun.COM VGEN_NUM_VMPOOLS + 1, sz1, sz2, sz3, sz4, 26787529SSriharsha.Basavapatna@Sun.COM vgen_nrbufs1, vgen_nrbufs2, vgen_nrbufs3, 26797529SSriharsha.Basavapatna@Sun.COM vgen_nrbufs4); 26807529SSriharsha.Basavapatna@Sun.COM } 26817529SSriharsha.Basavapatna@Sun.COM return (status); 26827529SSriharsha.Basavapatna@Sun.COM } 26837529SSriharsha.Basavapatna@Sun.COM 26847529SSriharsha.Basavapatna@Sun.COM /* 26857529SSriharsha.Basavapatna@Sun.COM * Pool sizes are not specified. We select the pool sizes based on the 26867529SSriharsha.Basavapatna@Sun.COM * mtu if vnet_jumbo_rxpools is enabled. 26877529SSriharsha.Basavapatna@Sun.COM */ 26887529SSriharsha.Basavapatna@Sun.COM if (vnet_jumbo_rxpools == B_FALSE || data_sz == VNET_2K) { 26897529SSriharsha.Basavapatna@Sun.COM /* 26907529SSriharsha.Basavapatna@Sun.COM * Receive buffer pool allocation based on mtu is disabled. 26917529SSriharsha.Basavapatna@Sun.COM * Use the default mechanism of standard size pool allocation. 26927529SSriharsha.Basavapatna@Sun.COM */ 26937529SSriharsha.Basavapatna@Sun.COM sz1 = VGEN_DBLK_SZ_128; 26947529SSriharsha.Basavapatna@Sun.COM sz2 = VGEN_DBLK_SZ_256; 26957529SSriharsha.Basavapatna@Sun.COM sz3 = VGEN_DBLK_SZ_2048; 26967529SSriharsha.Basavapatna@Sun.COM ldcp->max_rxpool_size = sz3; 26977529SSriharsha.Basavapatna@Sun.COM 26987529SSriharsha.Basavapatna@Sun.COM status = vio_init_multipools(&ldcp->vmp, VGEN_NUM_VMPOOLS, 26997529SSriharsha.Basavapatna@Sun.COM sz1, sz2, sz3, 27007529SSriharsha.Basavapatna@Sun.COM vgen_nrbufs1, vgen_nrbufs2, vgen_nrbufs3); 27017529SSriharsha.Basavapatna@Sun.COM 27027529SSriharsha.Basavapatna@Sun.COM return (status); 27037529SSriharsha.Basavapatna@Sun.COM } 27047529SSriharsha.Basavapatna@Sun.COM 27057529SSriharsha.Basavapatna@Sun.COM switch (data_sz) { 27067529SSriharsha.Basavapatna@Sun.COM 27077529SSriharsha.Basavapatna@Sun.COM case VNET_4K: 27087529SSriharsha.Basavapatna@Sun.COM 27097529SSriharsha.Basavapatna@Sun.COM sz1 = VGEN_DBLK_SZ_128; 27107529SSriharsha.Basavapatna@Sun.COM sz2 = VGEN_DBLK_SZ_256; 27117529SSriharsha.Basavapatna@Sun.COM sz3 = VGEN_DBLK_SZ_2048; 27127529SSriharsha.Basavapatna@Sun.COM sz4 = sz3 << 1; /* 4K */ 27137529SSriharsha.Basavapatna@Sun.COM ldcp->max_rxpool_size = sz4; 27147529SSriharsha.Basavapatna@Sun.COM 27157529SSriharsha.Basavapatna@Sun.COM status = vio_init_multipools(&ldcp->vmp, VGEN_NUM_VMPOOLS + 1, 27167529SSriharsha.Basavapatna@Sun.COM sz1, sz2, sz3, sz4, 27177529SSriharsha.Basavapatna@Sun.COM vgen_nrbufs1, vgen_nrbufs2, vgen_nrbufs3, vgen_nrbufs4); 27187529SSriharsha.Basavapatna@Sun.COM break; 27197529SSriharsha.Basavapatna@Sun.COM 27207529SSriharsha.Basavapatna@Sun.COM default: /* data_sz: 4K+ to 16K */ 27217529SSriharsha.Basavapatna@Sun.COM 27227529SSriharsha.Basavapatna@Sun.COM sz1 = VGEN_DBLK_SZ_256; 27237529SSriharsha.Basavapatna@Sun.COM sz2 = VGEN_DBLK_SZ_2048; 27247529SSriharsha.Basavapatna@Sun.COM sz3 = data_sz >> 1; /* Jumbo-size/2 */ 27257529SSriharsha.Basavapatna@Sun.COM sz4 = data_sz; /* Jumbo-size */ 27267529SSriharsha.Basavapatna@Sun.COM ldcp->max_rxpool_size = sz4; 27277529SSriharsha.Basavapatna@Sun.COM 27287529SSriharsha.Basavapatna@Sun.COM status = vio_init_multipools(&ldcp->vmp, VGEN_NUM_VMPOOLS + 1, 27297529SSriharsha.Basavapatna@Sun.COM sz1, sz2, sz3, sz4, 27307529SSriharsha.Basavapatna@Sun.COM vgen_nrbufs1, vgen_nrbufs2, vgen_nrbufs3, vgen_nrbufs4); 27317529SSriharsha.Basavapatna@Sun.COM break; 27327529SSriharsha.Basavapatna@Sun.COM 27337529SSriharsha.Basavapatna@Sun.COM } 27347529SSriharsha.Basavapatna@Sun.COM 27357529SSriharsha.Basavapatna@Sun.COM return (status); 27367529SSriharsha.Basavapatna@Sun.COM } 27377529SSriharsha.Basavapatna@Sun.COM 27381991Sheppo /* attach the channel corresponding to the given ldc_id to the port */ 27391991Sheppo static int 27401991Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id) 27411991Sheppo { 27421991Sheppo vgen_t *vgenp; 27431991Sheppo vgen_ldclist_t *ldclp; 27441991Sheppo vgen_ldc_t *ldcp, **prev_ldcp; 27451991Sheppo ldc_attr_t attr; 27461991Sheppo int status; 27471991Sheppo ldc_status_t istatus; 27485373Sraghuram char kname[MAXNAMELEN]; 27495373Sraghuram int instance; 27504647Sraghuram enum {AST_init = 0x0, AST_ldc_alloc = 0x1, 27514647Sraghuram AST_mutex_init = 0x2, AST_ldc_init = 0x4, 27524647Sraghuram AST_ldc_reg_cb = 0x8, AST_alloc_tx_ring = 0x10, 27535935Ssb155480 AST_create_rxmblks = 0x20, 27545935Ssb155480 AST_create_rcv_thread = 0x40} attach_state; 27551991Sheppo 27561991Sheppo attach_state = AST_init; 27571991Sheppo vgenp = portp->vgenp; 27581991Sheppo ldclp = &portp->ldclist; 27591991Sheppo 27601991Sheppo ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP); 27611991Sheppo if (ldcp == NULL) { 27621991Sheppo goto ldc_attach_failed; 27631991Sheppo } 27641991Sheppo ldcp->ldc_id = ldc_id; 27651991Sheppo ldcp->portp = portp; 27661991Sheppo 27671991Sheppo attach_state |= AST_ldc_alloc; 27681991Sheppo 27691991Sheppo mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL); 27701991Sheppo mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL); 27711991Sheppo mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL); 27724647Sraghuram mutex_init(&ldcp->wrlock, NULL, MUTEX_DRIVER, NULL); 27734647Sraghuram mutex_init(&ldcp->rxlock, NULL, MUTEX_DRIVER, NULL); 27741991Sheppo 27751991Sheppo attach_state |= AST_mutex_init; 27761991Sheppo 27771991Sheppo attr.devclass = LDC_DEV_NT; 27786495Sspeer attr.instance = vgenp->instance; 27791991Sheppo attr.mode = LDC_MODE_UNRELIABLE; 27802410Slm66018 attr.mtu = vnet_ldc_mtu; 27811991Sheppo status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle); 27821991Sheppo if (status != 0) { 27834647Sraghuram DWARN(vgenp, ldcp, "ldc_init failed,rv (%d)\n", status); 27841991Sheppo goto ldc_attach_failed; 27851991Sheppo } 27861991Sheppo attach_state |= AST_ldc_init; 27871991Sheppo 27884647Sraghuram if (vgen_rcv_thread_enabled) { 27894647Sraghuram ldcp->rcv_thr_flags = 0; 27904647Sraghuram 27914647Sraghuram mutex_init(&ldcp->rcv_thr_lock, NULL, MUTEX_DRIVER, NULL); 27924647Sraghuram cv_init(&ldcp->rcv_thr_cv, NULL, CV_DRIVER, NULL); 27934647Sraghuram ldcp->rcv_thread = thread_create(NULL, 2 * DEFAULTSTKSZ, 27944647Sraghuram vgen_ldc_rcv_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri); 27954647Sraghuram 27964647Sraghuram attach_state |= AST_create_rcv_thread; 27974647Sraghuram if (ldcp->rcv_thread == NULL) { 27984647Sraghuram DWARN(vgenp, ldcp, "Failed to create worker thread"); 27994647Sraghuram goto ldc_attach_failed; 28004647Sraghuram } 28014647Sraghuram } 28024647Sraghuram 28031991Sheppo status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp); 28041991Sheppo if (status != 0) { 28054647Sraghuram DWARN(vgenp, ldcp, "ldc_reg_callback failed, rv (%d)\n", 28064647Sraghuram status); 28071991Sheppo goto ldc_attach_failed; 28081991Sheppo } 28095935Ssb155480 /* 28105935Ssb155480 * allocate a message for ldc_read()s, big enough to hold ctrl and 28115935Ssb155480 * data msgs, including raw data msgs used to recv priority frames. 28125935Ssb155480 */ 28136419Ssb155480 ldcp->msglen = VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size; 28145935Ssb155480 ldcp->ldcmsg = kmem_alloc(ldcp->msglen, KM_SLEEP); 28151991Sheppo attach_state |= AST_ldc_reg_cb; 28161991Sheppo 28171991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 28181991Sheppo ASSERT(istatus == LDC_INIT); 28191991Sheppo ldcp->ldc_status = istatus; 28201991Sheppo 28211991Sheppo /* allocate transmit resources */ 28221991Sheppo status = vgen_alloc_tx_ring(ldcp); 28231991Sheppo if (status != 0) { 28241991Sheppo goto ldc_attach_failed; 28251991Sheppo } 28261991Sheppo attach_state |= AST_alloc_tx_ring; 28271991Sheppo 28282336Snarayan /* allocate receive resources */ 28297529SSriharsha.Basavapatna@Sun.COM status = vgen_init_multipools(ldcp); 28302336Snarayan if (status != 0) { 28312336Snarayan goto ldc_attach_failed; 28322336Snarayan } 28332336Snarayan attach_state |= AST_create_rxmblks; 28342336Snarayan 28351991Sheppo /* Setup kstats for the channel */ 28366495Sspeer instance = vgenp->instance; 28375373Sraghuram (void) sprintf(kname, "vnetldc0x%lx", ldcp->ldc_id); 28385373Sraghuram ldcp->ksp = vgen_setup_kstats("vnet", instance, kname, &ldcp->stats); 28395373Sraghuram if (ldcp->ksp == NULL) { 28401991Sheppo goto ldc_attach_failed; 28411991Sheppo } 28421991Sheppo 28431991Sheppo /* initialize vgen_versions supported */ 28441991Sheppo bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions)); 28455935Ssb155480 vgen_reset_vnet_proto_ops(ldcp); 28461991Sheppo 28471991Sheppo /* link it into the list of channels for this port */ 28481991Sheppo WRITE_ENTER(&ldclp->rwlock); 28491991Sheppo prev_ldcp = (vgen_ldc_t **)(&ldclp->headp); 28501991Sheppo ldcp->nextp = *prev_ldcp; 28511991Sheppo *prev_ldcp = ldcp; 28521991Sheppo RW_EXIT(&ldclp->rwlock); 28531991Sheppo 28541991Sheppo ldcp->flags |= CHANNEL_ATTACHED; 28551991Sheppo return (DDI_SUCCESS); 28561991Sheppo 28571991Sheppo ldc_attach_failed: 28584647Sraghuram if (attach_state & AST_ldc_reg_cb) { 28594647Sraghuram (void) ldc_unreg_callback(ldcp->ldc_handle); 28605935Ssb155480 kmem_free(ldcp->ldcmsg, ldcp->msglen); 28614647Sraghuram } 28624647Sraghuram if (attach_state & AST_create_rcv_thread) { 28634647Sraghuram if (ldcp->rcv_thread != NULL) { 28644647Sraghuram vgen_stop_rcv_thread(ldcp); 28654647Sraghuram } 28664647Sraghuram mutex_destroy(&ldcp->rcv_thr_lock); 28674647Sraghuram cv_destroy(&ldcp->rcv_thr_cv); 28684647Sraghuram } 28692336Snarayan if (attach_state & AST_create_rxmblks) { 28704647Sraghuram vio_mblk_pool_t *fvmp = NULL; 28714647Sraghuram 28724647Sraghuram vio_destroy_multipools(&ldcp->vmp, &fvmp); 28734647Sraghuram ASSERT(fvmp == NULL); 28742336Snarayan } 28751991Sheppo if (attach_state & AST_alloc_tx_ring) { 28761991Sheppo vgen_free_tx_ring(ldcp); 28771991Sheppo } 28781991Sheppo if (attach_state & AST_ldc_init) { 28791991Sheppo (void) ldc_fini(ldcp->ldc_handle); 28801991Sheppo } 28811991Sheppo if (attach_state & AST_mutex_init) { 28821991Sheppo mutex_destroy(&ldcp->tclock); 28831991Sheppo mutex_destroy(&ldcp->txlock); 28841991Sheppo mutex_destroy(&ldcp->cblock); 28854647Sraghuram mutex_destroy(&ldcp->wrlock); 28864647Sraghuram mutex_destroy(&ldcp->rxlock); 28871991Sheppo } 28881991Sheppo if (attach_state & AST_ldc_alloc) { 28891991Sheppo KMEM_FREE(ldcp); 28901991Sheppo } 28911991Sheppo return (DDI_FAILURE); 28921991Sheppo } 28931991Sheppo 28941991Sheppo /* detach a channel from the port */ 28951991Sheppo static void 28961991Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp) 28971991Sheppo { 28981991Sheppo vgen_port_t *portp; 28991991Sheppo vgen_t *vgenp; 29001991Sheppo vgen_ldc_t *pldcp; 29011991Sheppo vgen_ldc_t **prev_ldcp; 29021991Sheppo vgen_ldclist_t *ldclp; 29031991Sheppo 29041991Sheppo portp = ldcp->portp; 29051991Sheppo vgenp = portp->vgenp; 29061991Sheppo ldclp = &portp->ldclist; 29071991Sheppo 29081991Sheppo prev_ldcp = (vgen_ldc_t **)&ldclp->headp; 29091991Sheppo for (; (pldcp = *prev_ldcp) != NULL; prev_ldcp = &pldcp->nextp) { 29101991Sheppo if (pldcp == ldcp) { 29111991Sheppo break; 29121991Sheppo } 29131991Sheppo } 29141991Sheppo 29151991Sheppo if (pldcp == NULL) { 29161991Sheppo /* invalid ldcp? */ 29171991Sheppo return; 29181991Sheppo } 29191991Sheppo 29201991Sheppo if (ldcp->ldc_status != LDC_INIT) { 29214647Sraghuram DWARN(vgenp, ldcp, "ldc_status is not INIT\n"); 29221991Sheppo } 29231991Sheppo 29241991Sheppo if (ldcp->flags & CHANNEL_ATTACHED) { 29251991Sheppo ldcp->flags &= ~(CHANNEL_ATTACHED); 29261991Sheppo 29274647Sraghuram (void) ldc_unreg_callback(ldcp->ldc_handle); 29284647Sraghuram if (ldcp->rcv_thread != NULL) { 29294647Sraghuram /* First stop the receive thread */ 29304647Sraghuram vgen_stop_rcv_thread(ldcp); 29314647Sraghuram mutex_destroy(&ldcp->rcv_thr_lock); 29324647Sraghuram cv_destroy(&ldcp->rcv_thr_cv); 29334647Sraghuram } 29345935Ssb155480 kmem_free(ldcp->ldcmsg, ldcp->msglen); 29354647Sraghuram 29365373Sraghuram vgen_destroy_kstats(ldcp->ksp); 29375373Sraghuram ldcp->ksp = NULL; 29385373Sraghuram 29394647Sraghuram /* 29404647Sraghuram * if we cannot reclaim all mblks, put this 29414647Sraghuram * on the list of pools(vgenp->rmp) to be reclaimed when the 29424647Sraghuram * device gets detached (see vgen_uninit()). 29434647Sraghuram */ 29444647Sraghuram vio_destroy_multipools(&ldcp->vmp, &vgenp->rmp); 29452336Snarayan 29461991Sheppo /* free transmit resources */ 29471991Sheppo vgen_free_tx_ring(ldcp); 29482336Snarayan 29491991Sheppo (void) ldc_fini(ldcp->ldc_handle); 29501991Sheppo mutex_destroy(&ldcp->tclock); 29511991Sheppo mutex_destroy(&ldcp->txlock); 29521991Sheppo mutex_destroy(&ldcp->cblock); 29534647Sraghuram mutex_destroy(&ldcp->wrlock); 29544647Sraghuram mutex_destroy(&ldcp->rxlock); 29551991Sheppo 29561991Sheppo /* unlink it from the list */ 29571991Sheppo *prev_ldcp = ldcp->nextp; 29581991Sheppo KMEM_FREE(ldcp); 29591991Sheppo } 29601991Sheppo } 29611991Sheppo 29621991Sheppo /* 29631991Sheppo * This function allocates transmit resources for the channel. 29641991Sheppo * The resources consist of a transmit descriptor ring and an associated 29651991Sheppo * transmit buffer ring. 29661991Sheppo */ 29671991Sheppo static int 29681991Sheppo vgen_alloc_tx_ring(vgen_ldc_t *ldcp) 29691991Sheppo { 29701991Sheppo void *tbufp; 29711991Sheppo ldc_mem_info_t minfo; 29721991Sheppo uint32_t txdsize; 29731991Sheppo uint32_t tbufsize; 29741991Sheppo int status; 29754647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 29761991Sheppo 29771991Sheppo ldcp->num_txds = vnet_ntxds; 29781991Sheppo txdsize = sizeof (vnet_public_desc_t); 29791991Sheppo tbufsize = sizeof (vgen_private_desc_t); 29801991Sheppo 29811991Sheppo /* allocate transmit buffer ring */ 29821991Sheppo tbufp = kmem_zalloc(ldcp->num_txds * tbufsize, KM_NOSLEEP); 29831991Sheppo if (tbufp == NULL) { 29841991Sheppo return (DDI_FAILURE); 29851991Sheppo } 29861991Sheppo 29871991Sheppo /* create transmit descriptor ring */ 29881991Sheppo status = ldc_mem_dring_create(ldcp->num_txds, txdsize, 29891991Sheppo &ldcp->tx_dhandle); 29901991Sheppo if (status) { 29914647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_create() failed\n"); 29921991Sheppo kmem_free(tbufp, ldcp->num_txds * tbufsize); 29931991Sheppo return (DDI_FAILURE); 29941991Sheppo } 29951991Sheppo 29961991Sheppo /* get the addr of descripror ring */ 29971991Sheppo status = ldc_mem_dring_info(ldcp->tx_dhandle, &minfo); 29981991Sheppo if (status) { 29994647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_info() failed\n"); 30001991Sheppo kmem_free(tbufp, ldcp->num_txds * tbufsize); 30011991Sheppo (void) ldc_mem_dring_destroy(ldcp->tx_dhandle); 30021991Sheppo ldcp->tbufp = NULL; 30031991Sheppo return (DDI_FAILURE); 30041991Sheppo } 30051991Sheppo ldcp->txdp = (vnet_public_desc_t *)(minfo.vaddr); 30061991Sheppo ldcp->tbufp = tbufp; 30071991Sheppo 30081991Sheppo ldcp->txdendp = &((ldcp->txdp)[ldcp->num_txds]); 30091991Sheppo ldcp->tbufendp = &((ldcp->tbufp)[ldcp->num_txds]); 30101991Sheppo 30111991Sheppo return (DDI_SUCCESS); 30121991Sheppo } 30131991Sheppo 30141991Sheppo /* Free transmit resources for the channel */ 30151991Sheppo static void 30161991Sheppo vgen_free_tx_ring(vgen_ldc_t *ldcp) 30171991Sheppo { 30181991Sheppo int tbufsize = sizeof (vgen_private_desc_t); 30191991Sheppo 30201991Sheppo /* free transmit descriptor ring */ 30211991Sheppo (void) ldc_mem_dring_destroy(ldcp->tx_dhandle); 30221991Sheppo 30231991Sheppo /* free transmit buffer ring */ 30241991Sheppo kmem_free(ldcp->tbufp, ldcp->num_txds * tbufsize); 30251991Sheppo ldcp->txdp = ldcp->txdendp = NULL; 30261991Sheppo ldcp->tbufp = ldcp->tbufendp = NULL; 30271991Sheppo } 30281991Sheppo 30291991Sheppo /* enable transmit/receive on the channels for the port */ 30301991Sheppo static void 30311991Sheppo vgen_init_ldcs(vgen_port_t *portp) 30321991Sheppo { 30331991Sheppo vgen_ldclist_t *ldclp = &portp->ldclist; 30341991Sheppo vgen_ldc_t *ldcp; 30351991Sheppo 30361991Sheppo READ_ENTER(&ldclp->rwlock); 30371991Sheppo ldcp = ldclp->headp; 30381991Sheppo for (; ldcp != NULL; ldcp = ldcp->nextp) { 30391991Sheppo (void) vgen_ldc_init(ldcp); 30401991Sheppo } 30411991Sheppo RW_EXIT(&ldclp->rwlock); 30421991Sheppo } 30431991Sheppo 30441991Sheppo /* stop transmit/receive on the channels for the port */ 30451991Sheppo static void 30461991Sheppo vgen_uninit_ldcs(vgen_port_t *portp) 30471991Sheppo { 30481991Sheppo vgen_ldclist_t *ldclp = &portp->ldclist; 30491991Sheppo vgen_ldc_t *ldcp; 30501991Sheppo 30511991Sheppo READ_ENTER(&ldclp->rwlock); 30521991Sheppo ldcp = ldclp->headp; 30531991Sheppo for (; ldcp != NULL; ldcp = ldcp->nextp) { 30541991Sheppo vgen_ldc_uninit(ldcp); 30551991Sheppo } 30561991Sheppo RW_EXIT(&ldclp->rwlock); 30571991Sheppo } 30581991Sheppo 30591991Sheppo /* enable transmit/receive on the channel */ 30601991Sheppo static int 30611991Sheppo vgen_ldc_init(vgen_ldc_t *ldcp) 30621991Sheppo { 30634647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 30641991Sheppo ldc_status_t istatus; 30651991Sheppo int rv; 30662109Slm66018 uint32_t retries = 0; 30674647Sraghuram enum { ST_init = 0x0, ST_ldc_open = 0x1, 30684647Sraghuram ST_init_tbufs = 0x2, ST_cb_enable = 0x4} init_state; 30691991Sheppo init_state = ST_init; 30701991Sheppo 30714647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 30721991Sheppo LDC_LOCK(ldcp); 30731991Sheppo 30741991Sheppo rv = ldc_open(ldcp->ldc_handle); 30751991Sheppo if (rv != 0) { 30764647Sraghuram DWARN(vgenp, ldcp, "ldc_open failed: rv(%d)\n", rv); 30771991Sheppo goto ldcinit_failed; 30781991Sheppo } 30791991Sheppo init_state |= ST_ldc_open; 30801991Sheppo 30811991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 30821991Sheppo if (istatus != LDC_OPEN && istatus != LDC_READY) { 30834647Sraghuram DWARN(vgenp, ldcp, "status(%d) is not OPEN/READY\n", istatus); 30841991Sheppo goto ldcinit_failed; 30851991Sheppo } 30861991Sheppo ldcp->ldc_status = istatus; 30871991Sheppo 30881991Sheppo rv = vgen_init_tbufs(ldcp); 30891991Sheppo if (rv != 0) { 30904647Sraghuram DWARN(vgenp, ldcp, "vgen_init_tbufs() failed\n"); 30911991Sheppo goto ldcinit_failed; 30921991Sheppo } 30931991Sheppo init_state |= ST_init_tbufs; 30941991Sheppo 30952748Slm66018 rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_ENABLE); 30962748Slm66018 if (rv != 0) { 30974647Sraghuram DWARN(vgenp, ldcp, "ldc_set_cb_mode failed: rv(%d)\n", rv); 30982748Slm66018 goto ldcinit_failed; 30992748Slm66018 } 31002748Slm66018 31012748Slm66018 init_state |= ST_cb_enable; 31022748Slm66018 31032109Slm66018 do { 31042109Slm66018 rv = ldc_up(ldcp->ldc_handle); 31052109Slm66018 if ((rv != 0) && (rv == EWOULDBLOCK)) { 31064647Sraghuram DBG2(vgenp, ldcp, "ldc_up err rv(%d)\n", rv); 31072109Slm66018 drv_usecwait(VGEN_LDC_UP_DELAY); 31082109Slm66018 } 31092109Slm66018 if (retries++ >= vgen_ldcup_retries) 31102109Slm66018 break; 31112109Slm66018 } while (rv == EWOULDBLOCK); 31121991Sheppo 31131991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 31142793Slm66018 if (istatus == LDC_UP) { 31154647Sraghuram DWARN(vgenp, ldcp, "status(%d) is UP\n", istatus); 31161991Sheppo } 31172793Slm66018 31181991Sheppo ldcp->ldc_status = istatus; 31191991Sheppo 31201991Sheppo /* initialize transmit watchdog timeout */ 31211991Sheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp, 31221991Sheppo drv_usectohz(vnet_ldcwd_interval * 1000)); 31231991Sheppo 31242793Slm66018 ldcp->hphase = -1; 31251991Sheppo ldcp->flags |= CHANNEL_STARTED; 31261991Sheppo 31272793Slm66018 /* if channel is already UP - start handshake */ 31282793Slm66018 if (istatus == LDC_UP) { 31292793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 31302793Slm66018 if (ldcp->portp != vgenp->vsw_portp) { 31312793Slm66018 /* 31326495Sspeer * As the channel is up, use this port from now on. 31332793Slm66018 */ 31346495Sspeer (void) atomic_swap_32( 31356495Sspeer &ldcp->portp->use_vsw_port, B_FALSE); 31362793Slm66018 } 31372793Slm66018 31382793Slm66018 /* Initialize local session id */ 31392793Slm66018 ldcp->local_sid = ddi_get_lbolt(); 31402793Slm66018 31412793Slm66018 /* clear peer session id */ 31422793Slm66018 ldcp->peer_sid = 0; 31432793Slm66018 ldcp->hretries = 0; 31442793Slm66018 31452793Slm66018 /* Initiate Handshake process with peer ldc endpoint */ 31462793Slm66018 vgen_reset_hphase(ldcp); 31472793Slm66018 31482793Slm66018 mutex_exit(&ldcp->tclock); 31492793Slm66018 mutex_exit(&ldcp->txlock); 31504647Sraghuram mutex_exit(&ldcp->wrlock); 31515708Sraghuram mutex_exit(&ldcp->rxlock); 31522793Slm66018 vgen_handshake(vh_nextphase(ldcp)); 31532793Slm66018 mutex_exit(&ldcp->cblock); 31542793Slm66018 } else { 31552793Slm66018 LDC_UNLOCK(ldcp); 31562793Slm66018 } 31572793Slm66018 31581991Sheppo return (DDI_SUCCESS); 31591991Sheppo 31601991Sheppo ldcinit_failed: 31612748Slm66018 if (init_state & ST_cb_enable) { 31622748Slm66018 (void) ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE); 31632748Slm66018 } 31641991Sheppo if (init_state & ST_init_tbufs) { 31651991Sheppo vgen_uninit_tbufs(ldcp); 31661991Sheppo } 31671991Sheppo if (init_state & ST_ldc_open) { 31681991Sheppo (void) ldc_close(ldcp->ldc_handle); 31691991Sheppo } 31701991Sheppo LDC_UNLOCK(ldcp); 31714647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 31721991Sheppo return (DDI_FAILURE); 31731991Sheppo } 31741991Sheppo 31751991Sheppo /* stop transmit/receive on the channel */ 31761991Sheppo static void 31771991Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp) 31781991Sheppo { 31794647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 31801991Sheppo int rv; 31811991Sheppo 31824647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 31831991Sheppo LDC_LOCK(ldcp); 31841991Sheppo 31851991Sheppo if ((ldcp->flags & CHANNEL_STARTED) == 0) { 31861991Sheppo LDC_UNLOCK(ldcp); 31874647Sraghuram DWARN(vgenp, ldcp, "CHANNEL_STARTED flag is not set\n"); 31881991Sheppo return; 31891991Sheppo } 31901991Sheppo 31911991Sheppo /* disable further callbacks */ 31921991Sheppo rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE); 31931991Sheppo if (rv != 0) { 31944647Sraghuram DWARN(vgenp, ldcp, "ldc_set_cb_mode failed\n"); 31951991Sheppo } 31961991Sheppo 31976495Sspeer if (vgenp->vsw_portp == ldcp->portp) { 31986495Sspeer vio_net_report_err_t rep_err = 31996495Sspeer ldcp->portp->vcb.vio_net_report_err; 32006495Sspeer rep_err(ldcp->portp->vhp, VIO_NET_RES_DOWN); 32016495Sspeer } 32026495Sspeer 32033653Snarayan /* 32043653Snarayan * clear handshake done bit and wait for pending tx and cb to finish. 32053653Snarayan * release locks before untimeout(9F) is invoked to cancel timeouts. 32063653Snarayan */ 32071991Sheppo ldcp->hphase &= ~(VH_DONE); 32081991Sheppo LDC_UNLOCK(ldcp); 32093653Snarayan 32103653Snarayan /* cancel handshake watchdog timeout */ 32113653Snarayan if (ldcp->htid) { 32123653Snarayan (void) untimeout(ldcp->htid); 32133653Snarayan ldcp->htid = 0; 32143653Snarayan } 32153653Snarayan 3216*7572SWentao.Yang@Sun.COM if (ldcp->cancel_htid) { 3217*7572SWentao.Yang@Sun.COM (void) untimeout(ldcp->cancel_htid); 3218*7572SWentao.Yang@Sun.COM ldcp->cancel_htid = 0; 3219*7572SWentao.Yang@Sun.COM } 3220*7572SWentao.Yang@Sun.COM 32213653Snarayan /* cancel transmit watchdog timeout */ 32221991Sheppo if (ldcp->wd_tid) { 32231991Sheppo (void) untimeout(ldcp->wd_tid); 32241991Sheppo ldcp->wd_tid = 0; 32251991Sheppo } 32261991Sheppo 32273653Snarayan drv_usecwait(1000); 32283653Snarayan 32293653Snarayan /* acquire locks again; any pending transmits and callbacks are done */ 32303653Snarayan LDC_LOCK(ldcp); 32313653Snarayan 32323653Snarayan vgen_reset_hphase(ldcp); 32333653Snarayan 32341991Sheppo vgen_uninit_tbufs(ldcp); 32351991Sheppo 32361991Sheppo rv = ldc_close(ldcp->ldc_handle); 32371991Sheppo if (rv != 0) { 32384647Sraghuram DWARN(vgenp, ldcp, "ldc_close err\n"); 32391991Sheppo } 32401991Sheppo ldcp->ldc_status = LDC_INIT; 32411991Sheppo ldcp->flags &= ~(CHANNEL_STARTED); 32421991Sheppo 32431991Sheppo LDC_UNLOCK(ldcp); 32441991Sheppo 32454647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 32461991Sheppo } 32471991Sheppo 32481991Sheppo /* Initialize the transmit buffer ring for the channel */ 32491991Sheppo static int 32501991Sheppo vgen_init_tbufs(vgen_ldc_t *ldcp) 32511991Sheppo { 32521991Sheppo vgen_private_desc_t *tbufp; 32531991Sheppo vnet_public_desc_t *txdp; 32541991Sheppo vio_dring_entry_hdr_t *hdrp; 32551991Sheppo int i; 32561991Sheppo int rv; 32572109Slm66018 caddr_t datap = NULL; 32582109Slm66018 int ci; 32592109Slm66018 uint32_t ncookies; 32606419Ssb155480 size_t data_sz; 32616419Ssb155480 vgen_t *vgenp; 32626419Ssb155480 32636419Ssb155480 vgenp = LDC_TO_VGEN(ldcp); 32641991Sheppo 32651991Sheppo bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds)); 32661991Sheppo bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds)); 32671991Sheppo 32687529SSriharsha.Basavapatna@Sun.COM /* 32697529SSriharsha.Basavapatna@Sun.COM * In order to ensure that the number of ldc cookies per descriptor is 32707529SSriharsha.Basavapatna@Sun.COM * limited to be within the default MAX_COOKIES (2), we take the steps 32717529SSriharsha.Basavapatna@Sun.COM * outlined below: 32727529SSriharsha.Basavapatna@Sun.COM * 32737529SSriharsha.Basavapatna@Sun.COM * Align the entire data buffer area to 8K and carve out per descriptor 32747529SSriharsha.Basavapatna@Sun.COM * data buffers starting from this 8K aligned base address. 32757529SSriharsha.Basavapatna@Sun.COM * 32767529SSriharsha.Basavapatna@Sun.COM * We round up the mtu specified to be a multiple of 2K or 4K. 32777529SSriharsha.Basavapatna@Sun.COM * For sizes up to 12K we round up the size to the next 2K. 32787529SSriharsha.Basavapatna@Sun.COM * For sizes > 12K we round up to the next 4K (otherwise sizes such as 32797529SSriharsha.Basavapatna@Sun.COM * 14K could end up needing 3 cookies, with the buffer spread across 32807529SSriharsha.Basavapatna@Sun.COM * 3 8K pages: 8K+6K, 2K+8K+2K, 6K+8K, ...). 32817529SSriharsha.Basavapatna@Sun.COM */ 32826419Ssb155480 data_sz = vgenp->max_frame_size + VNET_IPALIGN + VNET_LDCALIGN; 32837529SSriharsha.Basavapatna@Sun.COM if (data_sz <= VNET_12K) { 32847529SSriharsha.Basavapatna@Sun.COM data_sz = VNET_ROUNDUP_2K(data_sz); 32857529SSriharsha.Basavapatna@Sun.COM } else { 32867529SSriharsha.Basavapatna@Sun.COM data_sz = VNET_ROUNDUP_4K(data_sz); 32877529SSriharsha.Basavapatna@Sun.COM } 32887529SSriharsha.Basavapatna@Sun.COM 32897529SSriharsha.Basavapatna@Sun.COM /* allocate extra 8K bytes for alignment */ 32907529SSriharsha.Basavapatna@Sun.COM ldcp->tx_data_sz = (data_sz * ldcp->num_txds) + VNET_8K; 32916419Ssb155480 datap = kmem_zalloc(ldcp->tx_data_sz, KM_SLEEP); 32922109Slm66018 ldcp->tx_datap = datap; 32932109Slm66018 32947529SSriharsha.Basavapatna@Sun.COM 32957529SSriharsha.Basavapatna@Sun.COM /* align the starting address of the data area to 8K */ 32967529SSriharsha.Basavapatna@Sun.COM datap = (caddr_t)VNET_ROUNDUP_8K((uintptr_t)datap); 32977529SSriharsha.Basavapatna@Sun.COM 32981991Sheppo /* 32992109Slm66018 * for each private descriptor, allocate a ldc mem_handle which is 33001991Sheppo * required to map the data during transmit, set the flags 33011991Sheppo * to free (available for use by transmit routine). 33021991Sheppo */ 33031991Sheppo 33041991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 33052109Slm66018 33061991Sheppo tbufp = &(ldcp->tbufp[i]); 33071991Sheppo rv = ldc_mem_alloc_handle(ldcp->ldc_handle, 33084650Sraghuram &(tbufp->memhandle)); 33091991Sheppo if (rv) { 33101991Sheppo tbufp->memhandle = 0; 33111991Sheppo goto init_tbufs_failed; 33121991Sheppo } 33132109Slm66018 33142109Slm66018 /* 33152109Slm66018 * bind ldc memhandle to the corresponding transmit buffer. 33162109Slm66018 */ 33172109Slm66018 ci = ncookies = 0; 33182109Slm66018 rv = ldc_mem_bind_handle(tbufp->memhandle, 33196419Ssb155480 (caddr_t)datap, data_sz, LDC_SHADOW_MAP, 33202109Slm66018 LDC_MEM_R, &(tbufp->memcookie[ci]), &ncookies); 33212109Slm66018 if (rv != 0) { 33222109Slm66018 goto init_tbufs_failed; 33232109Slm66018 } 33242109Slm66018 33252109Slm66018 /* 33262109Slm66018 * successful in binding the handle to tx data buffer. 33272109Slm66018 * set datap in the private descr to this buffer. 33282109Slm66018 */ 33292109Slm66018 tbufp->datap = datap; 33302109Slm66018 33312109Slm66018 if ((ncookies == 0) || 33324650Sraghuram (ncookies > MAX_COOKIES)) { 33332109Slm66018 goto init_tbufs_failed; 33342109Slm66018 } 33352109Slm66018 33362109Slm66018 for (ci = 1; ci < ncookies; ci++) { 33372109Slm66018 rv = ldc_mem_nextcookie(tbufp->memhandle, 33384650Sraghuram &(tbufp->memcookie[ci])); 33392109Slm66018 if (rv != 0) { 33402109Slm66018 goto init_tbufs_failed; 33412109Slm66018 } 33422109Slm66018 } 33432109Slm66018 33442109Slm66018 tbufp->ncookies = ncookies; 33456419Ssb155480 datap += data_sz; 33462109Slm66018 33471991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 33481991Sheppo txdp = &(ldcp->txdp[i]); 33491991Sheppo hdrp = &txdp->hdr; 33501991Sheppo hdrp->dstate = VIO_DESC_FREE; 33511991Sheppo hdrp->ack = B_FALSE; 33521991Sheppo tbufp->descp = txdp; 33532109Slm66018 33541991Sheppo } 33551991Sheppo 33561991Sheppo /* reset tbuf walking pointers */ 33571991Sheppo ldcp->next_tbufp = ldcp->tbufp; 33581991Sheppo ldcp->cur_tbufp = ldcp->tbufp; 33591991Sheppo 33601991Sheppo /* initialize tx seqnum and index */ 33611991Sheppo ldcp->next_txseq = VNET_ISS; 33621991Sheppo ldcp->next_txi = 0; 33631991Sheppo 33642336Snarayan ldcp->resched_peer = B_TRUE; 33654647Sraghuram ldcp->resched_peer_txi = 0; 33662336Snarayan 33671991Sheppo return (DDI_SUCCESS); 33681991Sheppo 33691991Sheppo init_tbufs_failed:; 33701991Sheppo vgen_uninit_tbufs(ldcp); 33711991Sheppo return (DDI_FAILURE); 33721991Sheppo } 33731991Sheppo 33741991Sheppo /* Uninitialize transmit buffer ring for the channel */ 33751991Sheppo static void 33761991Sheppo vgen_uninit_tbufs(vgen_ldc_t *ldcp) 33771991Sheppo { 33781991Sheppo vgen_private_desc_t *tbufp = ldcp->tbufp; 33791991Sheppo int i; 33801991Sheppo 33811991Sheppo /* for each tbuf (priv_desc), free ldc mem_handle */ 33821991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 33831991Sheppo 33841991Sheppo tbufp = &(ldcp->tbufp[i]); 33851991Sheppo 33862109Slm66018 if (tbufp->datap) { /* if bound to a ldc memhandle */ 33871991Sheppo (void) ldc_mem_unbind_handle(tbufp->memhandle); 33882109Slm66018 tbufp->datap = NULL; 33891991Sheppo } 33901991Sheppo if (tbufp->memhandle) { 33911991Sheppo (void) ldc_mem_free_handle(tbufp->memhandle); 33921991Sheppo tbufp->memhandle = 0; 33931991Sheppo } 33941991Sheppo } 33951991Sheppo 33962109Slm66018 if (ldcp->tx_datap) { 33972109Slm66018 /* prealloc'd tx data buffer */ 33986419Ssb155480 kmem_free(ldcp->tx_datap, ldcp->tx_data_sz); 33992109Slm66018 ldcp->tx_datap = NULL; 34006419Ssb155480 ldcp->tx_data_sz = 0; 34012109Slm66018 } 34022109Slm66018 34032748Slm66018 bzero(ldcp->tbufp, sizeof (vgen_private_desc_t) * (ldcp->num_txds)); 34042748Slm66018 bzero(ldcp->txdp, sizeof (vnet_public_desc_t) * (ldcp->num_txds)); 34051991Sheppo } 34061991Sheppo 34071991Sheppo /* clobber tx descriptor ring */ 34081991Sheppo static void 34091991Sheppo vgen_clobber_tbufs(vgen_ldc_t *ldcp) 34101991Sheppo { 34111991Sheppo vnet_public_desc_t *txdp; 34121991Sheppo vgen_private_desc_t *tbufp; 34134647Sraghuram vio_dring_entry_hdr_t *hdrp; 34144647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 34151991Sheppo int i; 34161991Sheppo #ifdef DEBUG 34171991Sheppo int ndone = 0; 34181991Sheppo #endif 34191991Sheppo 34201991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 34211991Sheppo 34221991Sheppo tbufp = &(ldcp->tbufp[i]); 34231991Sheppo txdp = tbufp->descp; 34241991Sheppo hdrp = &txdp->hdr; 34251991Sheppo 34261991Sheppo if (tbufp->flags & VGEN_PRIV_DESC_BUSY) { 34271991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 34281991Sheppo #ifdef DEBUG 34291991Sheppo if (hdrp->dstate == VIO_DESC_DONE) 34301991Sheppo ndone++; 34311991Sheppo #endif 34321991Sheppo hdrp->dstate = VIO_DESC_FREE; 34331991Sheppo hdrp->ack = B_FALSE; 34341991Sheppo } 34351991Sheppo } 34361991Sheppo /* reset tbuf walking pointers */ 34371991Sheppo ldcp->next_tbufp = ldcp->tbufp; 34381991Sheppo ldcp->cur_tbufp = ldcp->tbufp; 34391991Sheppo 34401991Sheppo /* reset tx seqnum and index */ 34411991Sheppo ldcp->next_txseq = VNET_ISS; 34421991Sheppo ldcp->next_txi = 0; 34432336Snarayan 34442336Snarayan ldcp->resched_peer = B_TRUE; 34454647Sraghuram ldcp->resched_peer_txi = 0; 34464647Sraghuram 34474647Sraghuram DBG2(vgenp, ldcp, "num descrs done (%d)\n", ndone); 34481991Sheppo } 34491991Sheppo 34501991Sheppo /* clobber receive descriptor ring */ 34511991Sheppo static void 34521991Sheppo vgen_clobber_rxds(vgen_ldc_t *ldcp) 34531991Sheppo { 34541991Sheppo ldcp->rx_dhandle = 0; 34551991Sheppo bzero(&ldcp->rx_dcookie, sizeof (ldcp->rx_dcookie)); 34561991Sheppo ldcp->rxdp = NULL; 34571991Sheppo ldcp->next_rxi = 0; 34581991Sheppo ldcp->num_rxds = 0; 34591991Sheppo ldcp->next_rxseq = VNET_ISS; 34601991Sheppo } 34611991Sheppo 34621991Sheppo /* initialize receive descriptor ring */ 34631991Sheppo static int 34641991Sheppo vgen_init_rxds(vgen_ldc_t *ldcp, uint32_t num_desc, uint32_t desc_size, 34651991Sheppo ldc_mem_cookie_t *dcookie, uint32_t ncookies) 34661991Sheppo { 34671991Sheppo int rv; 34681991Sheppo ldc_mem_info_t minfo; 34691991Sheppo 34701991Sheppo rv = ldc_mem_dring_map(ldcp->ldc_handle, dcookie, ncookies, num_desc, 34716845Sha137994 desc_size, LDC_DIRECT_MAP, &(ldcp->rx_dhandle)); 34721991Sheppo if (rv != 0) { 34731991Sheppo return (DDI_FAILURE); 34741991Sheppo } 34751991Sheppo 34761991Sheppo /* 34771991Sheppo * sucessfully mapped, now try to 34781991Sheppo * get info about the mapped dring 34791991Sheppo */ 34801991Sheppo rv = ldc_mem_dring_info(ldcp->rx_dhandle, &minfo); 34811991Sheppo if (rv != 0) { 34821991Sheppo (void) ldc_mem_dring_unmap(ldcp->rx_dhandle); 34831991Sheppo return (DDI_FAILURE); 34841991Sheppo } 34851991Sheppo 34861991Sheppo /* 34871991Sheppo * save ring address, number of descriptors. 34881991Sheppo */ 34891991Sheppo ldcp->rxdp = (vnet_public_desc_t *)(minfo.vaddr); 34901991Sheppo bcopy(dcookie, &(ldcp->rx_dcookie), sizeof (*dcookie)); 34911991Sheppo ldcp->num_rxdcookies = ncookies; 34921991Sheppo ldcp->num_rxds = num_desc; 34931991Sheppo ldcp->next_rxi = 0; 34941991Sheppo ldcp->next_rxseq = VNET_ISS; 34956845Sha137994 ldcp->dring_mtype = minfo.mtype; 34961991Sheppo 34971991Sheppo return (DDI_SUCCESS); 34981991Sheppo } 34991991Sheppo 35001991Sheppo /* get channel statistics */ 35011991Sheppo static uint64_t 35022311Sseb vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat) 35031991Sheppo { 35041991Sheppo vgen_stats_t *statsp; 35051991Sheppo uint64_t val; 35061991Sheppo 35071991Sheppo val = 0; 35085373Sraghuram statsp = &ldcp->stats; 35091991Sheppo switch (stat) { 35101991Sheppo 35111991Sheppo case MAC_STAT_MULTIRCV: 35121991Sheppo val = statsp->multircv; 35131991Sheppo break; 35141991Sheppo 35151991Sheppo case MAC_STAT_BRDCSTRCV: 35161991Sheppo val = statsp->brdcstrcv; 35171991Sheppo break; 35181991Sheppo 35191991Sheppo case MAC_STAT_MULTIXMT: 35201991Sheppo val = statsp->multixmt; 35211991Sheppo break; 35221991Sheppo 35231991Sheppo case MAC_STAT_BRDCSTXMT: 35241991Sheppo val = statsp->brdcstxmt; 35251991Sheppo break; 35261991Sheppo 35271991Sheppo case MAC_STAT_NORCVBUF: 35281991Sheppo val = statsp->norcvbuf; 35291991Sheppo break; 35301991Sheppo 35311991Sheppo case MAC_STAT_IERRORS: 35321991Sheppo val = statsp->ierrors; 35331991Sheppo break; 35341991Sheppo 35351991Sheppo case MAC_STAT_NOXMTBUF: 35361991Sheppo val = statsp->noxmtbuf; 35371991Sheppo break; 35381991Sheppo 35391991Sheppo case MAC_STAT_OERRORS: 35401991Sheppo val = statsp->oerrors; 35411991Sheppo break; 35421991Sheppo 35431991Sheppo case MAC_STAT_COLLISIONS: 35441991Sheppo break; 35451991Sheppo 35461991Sheppo case MAC_STAT_RBYTES: 35471991Sheppo val = statsp->rbytes; 35481991Sheppo break; 35491991Sheppo 35501991Sheppo case MAC_STAT_IPACKETS: 35511991Sheppo val = statsp->ipackets; 35521991Sheppo break; 35531991Sheppo 35541991Sheppo case MAC_STAT_OBYTES: 35551991Sheppo val = statsp->obytes; 35561991Sheppo break; 35571991Sheppo 35581991Sheppo case MAC_STAT_OPACKETS: 35591991Sheppo val = statsp->opackets; 35601991Sheppo break; 35611991Sheppo 35621991Sheppo /* stats not relevant to ldc, return 0 */ 35631991Sheppo case MAC_STAT_IFSPEED: 35642311Sseb case ETHER_STAT_ALIGN_ERRORS: 35652311Sseb case ETHER_STAT_FCS_ERRORS: 35662311Sseb case ETHER_STAT_FIRST_COLLISIONS: 35672311Sseb case ETHER_STAT_MULTI_COLLISIONS: 35682311Sseb case ETHER_STAT_DEFER_XMTS: 35692311Sseb case ETHER_STAT_TX_LATE_COLLISIONS: 35702311Sseb case ETHER_STAT_EX_COLLISIONS: 35712311Sseb case ETHER_STAT_MACXMT_ERRORS: 35722311Sseb case ETHER_STAT_CARRIER_ERRORS: 35732311Sseb case ETHER_STAT_TOOLONG_ERRORS: 35742311Sseb case ETHER_STAT_XCVR_ADDR: 35752311Sseb case ETHER_STAT_XCVR_ID: 35762311Sseb case ETHER_STAT_XCVR_INUSE: 35772311Sseb case ETHER_STAT_CAP_1000FDX: 35782311Sseb case ETHER_STAT_CAP_1000HDX: 35792311Sseb case ETHER_STAT_CAP_100FDX: 35802311Sseb case ETHER_STAT_CAP_100HDX: 35812311Sseb case ETHER_STAT_CAP_10FDX: 35822311Sseb case ETHER_STAT_CAP_10HDX: 35832311Sseb case ETHER_STAT_CAP_ASMPAUSE: 35842311Sseb case ETHER_STAT_CAP_PAUSE: 35852311Sseb case ETHER_STAT_CAP_AUTONEG: 35862311Sseb case ETHER_STAT_ADV_CAP_1000FDX: 35872311Sseb case ETHER_STAT_ADV_CAP_1000HDX: 35882311Sseb case ETHER_STAT_ADV_CAP_100FDX: 35892311Sseb case ETHER_STAT_ADV_CAP_100HDX: 35902311Sseb case ETHER_STAT_ADV_CAP_10FDX: 35912311Sseb case ETHER_STAT_ADV_CAP_10HDX: 35922311Sseb case ETHER_STAT_ADV_CAP_ASMPAUSE: 35932311Sseb case ETHER_STAT_ADV_CAP_PAUSE: 35942311Sseb case ETHER_STAT_ADV_CAP_AUTONEG: 35952311Sseb case ETHER_STAT_LP_CAP_1000FDX: 35962311Sseb case ETHER_STAT_LP_CAP_1000HDX: 35972311Sseb case ETHER_STAT_LP_CAP_100FDX: 35982311Sseb case ETHER_STAT_LP_CAP_100HDX: 35992311Sseb case ETHER_STAT_LP_CAP_10FDX: 36002311Sseb case ETHER_STAT_LP_CAP_10HDX: 36012311Sseb case ETHER_STAT_LP_CAP_ASMPAUSE: 36022311Sseb case ETHER_STAT_LP_CAP_PAUSE: 36032311Sseb case ETHER_STAT_LP_CAP_AUTONEG: 36042311Sseb case ETHER_STAT_LINK_ASMPAUSE: 36052311Sseb case ETHER_STAT_LINK_PAUSE: 36062311Sseb case ETHER_STAT_LINK_AUTONEG: 36072311Sseb case ETHER_STAT_LINK_DUPLEX: 36081991Sheppo default: 36091991Sheppo val = 0; 36101991Sheppo break; 36111991Sheppo 36121991Sheppo } 36131991Sheppo return (val); 36141991Sheppo } 36151991Sheppo 36162793Slm66018 /* 36176495Sspeer * LDC channel is UP, start handshake process with peer. 36182793Slm66018 */ 36192793Slm66018 static void 36206495Sspeer vgen_handle_evt_up(vgen_ldc_t *ldcp) 36212793Slm66018 { 36222793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 36234647Sraghuram 36244647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 36252793Slm66018 36262793Slm66018 ASSERT(MUTEX_HELD(&ldcp->cblock)); 36272793Slm66018 36282793Slm66018 if (ldcp->portp != vgenp->vsw_portp) { 36292793Slm66018 /* 36306495Sspeer * As the channel is up, use this port from now on. 36312793Slm66018 */ 36326495Sspeer (void) atomic_swap_32(&ldcp->portp->use_vsw_port, B_FALSE); 36332793Slm66018 } 36342793Slm66018 36352793Slm66018 /* Initialize local session id */ 36362793Slm66018 ldcp->local_sid = ddi_get_lbolt(); 36372793Slm66018 36382793Slm66018 /* clear peer session id */ 36392793Slm66018 ldcp->peer_sid = 0; 36402793Slm66018 ldcp->hretries = 0; 36412793Slm66018 36422793Slm66018 if (ldcp->hphase != VH_PHASE0) { 36432793Slm66018 vgen_handshake_reset(ldcp); 36442793Slm66018 } 36452793Slm66018 36462793Slm66018 /* Initiate Handshake process with peer ldc endpoint */ 36472793Slm66018 vgen_handshake(vh_nextphase(ldcp)); 36482793Slm66018 36494647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 36502793Slm66018 } 36512793Slm66018 36522793Slm66018 /* 36532793Slm66018 * LDC channel is Reset, terminate connection with peer and try to 36542793Slm66018 * bring the channel up again. 36552793Slm66018 */ 36562793Slm66018 static void 36576495Sspeer vgen_handle_evt_reset(vgen_ldc_t *ldcp) 36582793Slm66018 { 36592793Slm66018 ldc_status_t istatus; 36602793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 36612793Slm66018 int rv; 36622793Slm66018 36634647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 36642793Slm66018 36652793Slm66018 ASSERT(MUTEX_HELD(&ldcp->cblock)); 36662793Slm66018 36672793Slm66018 if ((ldcp->portp != vgenp->vsw_portp) && 36684650Sraghuram (vgenp->vsw_portp != NULL)) { 36692793Slm66018 /* 36706495Sspeer * As the channel is down, use the switch port until 36716495Sspeer * the channel becomes ready to be used. 36722793Slm66018 */ 36736495Sspeer (void) atomic_swap_32(&ldcp->portp->use_vsw_port, B_TRUE); 36746495Sspeer } 36756495Sspeer 36766495Sspeer if (vgenp->vsw_portp == ldcp->portp) { 36776495Sspeer vio_net_report_err_t rep_err = 36786495Sspeer ldcp->portp->vcb.vio_net_report_err; 36796495Sspeer 36806495Sspeer /* Post a reset message */ 36816495Sspeer rep_err(ldcp->portp->vhp, VIO_NET_RES_DOWN); 36822793Slm66018 } 36832793Slm66018 36842793Slm66018 if (ldcp->hphase != VH_PHASE0) { 36852793Slm66018 vgen_handshake_reset(ldcp); 36862793Slm66018 } 36872793Slm66018 36882793Slm66018 /* try to bring the channel up */ 36892793Slm66018 rv = ldc_up(ldcp->ldc_handle); 36902793Slm66018 if (rv != 0) { 36914647Sraghuram DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv); 36922793Slm66018 } 36932793Slm66018 36942793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 36954647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 36962793Slm66018 } else { 36972793Slm66018 ldcp->ldc_status = istatus; 36982793Slm66018 } 36992793Slm66018 37002793Slm66018 /* if channel is already UP - restart handshake */ 37012793Slm66018 if (ldcp->ldc_status == LDC_UP) { 37026495Sspeer vgen_handle_evt_up(ldcp); 37032793Slm66018 } 37042793Slm66018 37054647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 37062793Slm66018 } 37072793Slm66018 37081991Sheppo /* Interrupt handler for the channel */ 37091991Sheppo static uint_t 37101991Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg) 37111991Sheppo { 37121991Sheppo _NOTE(ARGUNUSED(event)) 37131991Sheppo vgen_ldc_t *ldcp; 37141991Sheppo vgen_t *vgenp; 37151991Sheppo ldc_status_t istatus; 37161991Sheppo vgen_stats_t *statsp; 3717*7572SWentao.Yang@Sun.COM timeout_id_t cancel_htid = 0; 3718*7572SWentao.Yang@Sun.COM uint_t ret = LDC_SUCCESS; 37191991Sheppo 37201991Sheppo ldcp = (vgen_ldc_t *)arg; 37211991Sheppo vgenp = LDC_TO_VGEN(ldcp); 37225373Sraghuram statsp = &ldcp->stats; 37231991Sheppo 37244647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 37251991Sheppo 37261991Sheppo mutex_enter(&ldcp->cblock); 37271991Sheppo statsp->callbacks++; 37281991Sheppo if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) { 37294647Sraghuram DWARN(vgenp, ldcp, "status(%d) is LDC_INIT\n", 37304647Sraghuram ldcp->ldc_status); 37311991Sheppo mutex_exit(&ldcp->cblock); 37321991Sheppo return (LDC_SUCCESS); 37331991Sheppo } 37341991Sheppo 37352793Slm66018 /* 3736*7572SWentao.Yang@Sun.COM * cache cancel_htid before the events specific 3737*7572SWentao.Yang@Sun.COM * code may overwrite it. Do not clear ldcp->cancel_htid 3738*7572SWentao.Yang@Sun.COM * as it is also used to indicate the timer to quit immediately. 3739*7572SWentao.Yang@Sun.COM */ 3740*7572SWentao.Yang@Sun.COM cancel_htid = ldcp->cancel_htid; 3741*7572SWentao.Yang@Sun.COM 3742*7572SWentao.Yang@Sun.COM /* 37432793Slm66018 * NOTE: not using switch() as event could be triggered by 37442793Slm66018 * a state change and a read request. Also the ordering of the 37452793Slm66018 * check for the event types is deliberate. 37462793Slm66018 */ 37472793Slm66018 if (event & LDC_EVT_UP) { 37482793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 37494647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 37505708Sraghuram /* status couldn't be determined */ 3751*7572SWentao.Yang@Sun.COM ret = LDC_FAILURE; 3752*7572SWentao.Yang@Sun.COM goto ldc_cb_ret; 37532793Slm66018 } 37545708Sraghuram ldcp->ldc_status = istatus; 37555708Sraghuram if (ldcp->ldc_status != LDC_UP) { 37565708Sraghuram DWARN(vgenp, ldcp, "LDC_EVT_UP received " 37575708Sraghuram " but ldc status is not UP(0x%x)\n", 37585708Sraghuram ldcp->ldc_status); 37595708Sraghuram /* spurious interrupt, return success */ 3760*7572SWentao.Yang@Sun.COM goto ldc_cb_ret; 37615708Sraghuram } 37624647Sraghuram DWARN(vgenp, ldcp, "event(%lx) UP, status(%d)\n", 37634647Sraghuram event, ldcp->ldc_status); 37642793Slm66018 37656495Sspeer vgen_handle_evt_up(ldcp); 37662793Slm66018 37672793Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0); 37682793Slm66018 } 37692793Slm66018 37705708Sraghuram /* Handle RESET/DOWN before READ event */ 37715708Sraghuram if (event & (LDC_EVT_RESET | LDC_EVT_DOWN)) { 37725708Sraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 37735708Sraghuram DWARN(vgenp, ldcp, "ldc_status error\n"); 37745708Sraghuram /* status couldn't be determined */ 3775*7572SWentao.Yang@Sun.COM ret = LDC_FAILURE; 3776*7572SWentao.Yang@Sun.COM goto ldc_cb_ret; 37775708Sraghuram } 37785708Sraghuram ldcp->ldc_status = istatus; 37795708Sraghuram DWARN(vgenp, ldcp, "event(%lx) RESET/DOWN, status(%d)\n", 37805708Sraghuram event, ldcp->ldc_status); 37815708Sraghuram 37826495Sspeer vgen_handle_evt_reset(ldcp); 37835708Sraghuram 37845708Sraghuram /* 37855708Sraghuram * As the channel is down/reset, ignore READ event 37865708Sraghuram * but print a debug warning message. 37875708Sraghuram */ 37885708Sraghuram if (event & LDC_EVT_READ) { 37895708Sraghuram DWARN(vgenp, ldcp, 37905708Sraghuram "LDC_EVT_READ set along with RESET/DOWN\n"); 37915708Sraghuram event &= ~LDC_EVT_READ; 37925708Sraghuram } 37935708Sraghuram } 37945708Sraghuram 37952793Slm66018 if (event & LDC_EVT_READ) { 37964647Sraghuram DBG2(vgenp, ldcp, "event(%lx) READ, status(%d)\n", 37974647Sraghuram event, ldcp->ldc_status); 37982793Slm66018 37992793Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0); 38004647Sraghuram 38014647Sraghuram if (ldcp->rcv_thread != NULL) { 38024647Sraghuram /* 38034647Sraghuram * If the receive thread is enabled, then 38044647Sraghuram * wakeup the receive thread to process the 38054647Sraghuram * LDC messages. 38064647Sraghuram */ 38074647Sraghuram mutex_exit(&ldcp->cblock); 38084647Sraghuram mutex_enter(&ldcp->rcv_thr_lock); 38094647Sraghuram if (!(ldcp->rcv_thr_flags & VGEN_WTHR_DATARCVD)) { 38104647Sraghuram ldcp->rcv_thr_flags |= VGEN_WTHR_DATARCVD; 38114647Sraghuram cv_signal(&ldcp->rcv_thr_cv); 38124647Sraghuram } 38134647Sraghuram mutex_exit(&ldcp->rcv_thr_lock); 38144647Sraghuram mutex_enter(&ldcp->cblock); 38154647Sraghuram } else { 38164647Sraghuram vgen_handle_evt_read(ldcp); 38174647Sraghuram } 38182793Slm66018 } 3819*7572SWentao.Yang@Sun.COM 3820*7572SWentao.Yang@Sun.COM ldc_cb_ret: 3821*7572SWentao.Yang@Sun.COM /* 3822*7572SWentao.Yang@Sun.COM * Check to see if the status of cancel_htid has 3823*7572SWentao.Yang@Sun.COM * changed. If another timer needs to be cancelled, 3824*7572SWentao.Yang@Sun.COM * then let the next callback to clear it. 3825*7572SWentao.Yang@Sun.COM */ 3826*7572SWentao.Yang@Sun.COM if (cancel_htid == 0) { 3827*7572SWentao.Yang@Sun.COM cancel_htid = ldcp->cancel_htid; 3828*7572SWentao.Yang@Sun.COM } 38292793Slm66018 mutex_exit(&ldcp->cblock); 38304647Sraghuram 3831*7572SWentao.Yang@Sun.COM if (cancel_htid) { 38324647Sraghuram /* 38334647Sraghuram * Cancel handshake timer. 38344647Sraghuram * untimeout(9F) will not return until the pending callback is 38354647Sraghuram * cancelled or has run. No problems will result from calling 38364647Sraghuram * untimeout if the handler has already completed. 38374647Sraghuram * If the timeout handler did run, then it would just 38384647Sraghuram * return as cancel_htid is set. 38394647Sraghuram */ 3840*7572SWentao.Yang@Sun.COM DBG2(vgenp, ldcp, "calling cance_htid =0x%X \n", cancel_htid); 3841*7572SWentao.Yang@Sun.COM (void) untimeout(cancel_htid); 3842*7572SWentao.Yang@Sun.COM mutex_enter(&ldcp->cblock); 3843*7572SWentao.Yang@Sun.COM /* clear it only if its the same as the one we cancelled */ 3844*7572SWentao.Yang@Sun.COM if (ldcp->cancel_htid == cancel_htid) { 3845*7572SWentao.Yang@Sun.COM ldcp->cancel_htid = 0; 3846*7572SWentao.Yang@Sun.COM } 3847*7572SWentao.Yang@Sun.COM mutex_exit(&ldcp->cblock); 38484647Sraghuram } 38494647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 3850*7572SWentao.Yang@Sun.COM return (ret); 38514647Sraghuram } 38524647Sraghuram 38534647Sraghuram static void 38544647Sraghuram vgen_handle_evt_read(vgen_ldc_t *ldcp) 38554647Sraghuram { 38564647Sraghuram int rv; 38575935Ssb155480 uint64_t *ldcmsg; 38584647Sraghuram size_t msglen; 38594647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 38604647Sraghuram vio_msg_tag_t *tagp; 38614647Sraghuram ldc_status_t istatus; 38624647Sraghuram boolean_t has_data; 38634647Sraghuram 38644647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 38654647Sraghuram 38665935Ssb155480 ldcmsg = ldcp->ldcmsg; 38674647Sraghuram /* 38684647Sraghuram * If the receive thread is enabled, then the cblock 38694647Sraghuram * need to be acquired here. If not, the vgen_ldc_cb() 38704647Sraghuram * calls this function with cblock held already. 38714647Sraghuram */ 38724647Sraghuram if (ldcp->rcv_thread != NULL) { 38734647Sraghuram mutex_enter(&ldcp->cblock); 38744647Sraghuram } else { 38754647Sraghuram ASSERT(MUTEX_HELD(&ldcp->cblock)); 38764647Sraghuram } 38774647Sraghuram 38784647Sraghuram vgen_evt_read: 38791991Sheppo do { 38805935Ssb155480 msglen = ldcp->msglen; 38815935Ssb155480 rv = ldc_read(ldcp->ldc_handle, (caddr_t)ldcmsg, &msglen); 38821991Sheppo 38831991Sheppo if (rv != 0) { 38844647Sraghuram DWARN(vgenp, ldcp, "err rv(%d) len(%d)\n", 38854647Sraghuram rv, msglen); 38862793Slm66018 if (rv == ECONNRESET) 38874647Sraghuram goto vgen_evtread_error; 38881991Sheppo break; 38891991Sheppo } 38901991Sheppo if (msglen == 0) { 38914647Sraghuram DBG2(vgenp, ldcp, "ldc_read NODATA"); 38921991Sheppo break; 38931991Sheppo } 38944647Sraghuram DBG2(vgenp, ldcp, "ldc_read msglen(%d)", msglen); 38951991Sheppo 38961991Sheppo tagp = (vio_msg_tag_t *)ldcmsg; 38971991Sheppo 38981991Sheppo if (ldcp->peer_sid) { 38991991Sheppo /* 39001991Sheppo * check sid only after we have received peer's sid 39011991Sheppo * in the version negotiate msg. 39021991Sheppo */ 39031991Sheppo #ifdef DEBUG 39041991Sheppo if (vgen_hdbg & HDBG_BAD_SID) { 39051991Sheppo /* simulate bad sid condition */ 39061991Sheppo tagp->vio_sid = 0; 39071991Sheppo vgen_hdbg &= ~(HDBG_BAD_SID); 39081991Sheppo } 39091991Sheppo #endif 39102793Slm66018 rv = vgen_check_sid(ldcp, tagp); 39112793Slm66018 if (rv != VGEN_SUCCESS) { 39121991Sheppo /* 39131991Sheppo * If sid mismatch is detected, 39141991Sheppo * reset the channel. 39151991Sheppo */ 39161991Sheppo ldcp->need_ldc_reset = B_TRUE; 39174647Sraghuram goto vgen_evtread_error; 39181991Sheppo } 39191991Sheppo } 39201991Sheppo 39211991Sheppo switch (tagp->vio_msgtype) { 39221991Sheppo case VIO_TYPE_CTRL: 39232793Slm66018 rv = vgen_handle_ctrlmsg(ldcp, tagp); 39241991Sheppo break; 39251991Sheppo 39261991Sheppo case VIO_TYPE_DATA: 39275935Ssb155480 rv = vgen_handle_datamsg(ldcp, tagp, msglen); 39281991Sheppo break; 39291991Sheppo 39301991Sheppo case VIO_TYPE_ERR: 39311991Sheppo vgen_handle_errmsg(ldcp, tagp); 39321991Sheppo break; 39331991Sheppo 39341991Sheppo default: 39354647Sraghuram DWARN(vgenp, ldcp, "Unknown VIO_TYPE(%x)\n", 39364647Sraghuram tagp->vio_msgtype); 39371991Sheppo break; 39381991Sheppo } 39391991Sheppo 39404647Sraghuram /* 39414647Sraghuram * If an error is encountered, stop processing and 39424647Sraghuram * handle the error. 39434647Sraghuram */ 39444647Sraghuram if (rv != 0) { 39454647Sraghuram goto vgen_evtread_error; 39462793Slm66018 } 39472793Slm66018 39481991Sheppo } while (msglen); 39491991Sheppo 39504647Sraghuram /* check once more before exiting */ 39514647Sraghuram rv = ldc_chkq(ldcp->ldc_handle, &has_data); 39524647Sraghuram if ((rv == 0) && (has_data == B_TRUE)) { 39534647Sraghuram DTRACE_PROBE(vgen_chkq); 39544647Sraghuram goto vgen_evt_read; 39554647Sraghuram } 39564647Sraghuram 39574647Sraghuram vgen_evtread_error: 39584647Sraghuram if (rv == ECONNRESET) { 39594647Sraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 39604647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 39614647Sraghuram } else { 39624647Sraghuram ldcp->ldc_status = istatus; 39634647Sraghuram } 39646495Sspeer vgen_handle_evt_reset(ldcp); 39654647Sraghuram } else if (rv) { 39664647Sraghuram vgen_handshake_retry(ldcp); 39674647Sraghuram } 39684647Sraghuram 39694647Sraghuram /* 3970*7572SWentao.Yang@Sun.COM * If the receive thread is enabled, then cancel the 39714647Sraghuram * handshake timeout here. 39724647Sraghuram */ 39734647Sraghuram if (ldcp->rcv_thread != NULL) { 3974*7572SWentao.Yang@Sun.COM timeout_id_t cancel_htid = ldcp->cancel_htid; 3975*7572SWentao.Yang@Sun.COM 39764647Sraghuram mutex_exit(&ldcp->cblock); 3977*7572SWentao.Yang@Sun.COM if (cancel_htid) { 39784647Sraghuram /* 39794647Sraghuram * Cancel handshake timer. untimeout(9F) will 39804647Sraghuram * not return until the pending callback is cancelled 39814647Sraghuram * or has run. No problems will result from calling 39824647Sraghuram * untimeout if the handler has already completed. 39834647Sraghuram * If the timeout handler did run, then it would just 39844647Sraghuram * return as cancel_htid is set. 39854647Sraghuram */ 3986*7572SWentao.Yang@Sun.COM DBG2(vgenp, ldcp, "calling cance_htid =0x%X \n", 3987*7572SWentao.Yang@Sun.COM cancel_htid); 3988*7572SWentao.Yang@Sun.COM (void) untimeout(cancel_htid); 3989*7572SWentao.Yang@Sun.COM 3990*7572SWentao.Yang@Sun.COM /* 3991*7572SWentao.Yang@Sun.COM * clear it only if its the same as the one we 3992*7572SWentao.Yang@Sun.COM * cancelled 3993*7572SWentao.Yang@Sun.COM */ 3994*7572SWentao.Yang@Sun.COM mutex_enter(&ldcp->cblock); 3995*7572SWentao.Yang@Sun.COM if (ldcp->cancel_htid == cancel_htid) { 3996*7572SWentao.Yang@Sun.COM ldcp->cancel_htid = 0; 3997*7572SWentao.Yang@Sun.COM } 3998*7572SWentao.Yang@Sun.COM mutex_exit(&ldcp->cblock); 39994647Sraghuram } 40004647Sraghuram } 40014647Sraghuram 40024647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 40031991Sheppo } 40041991Sheppo 40051991Sheppo /* vgen handshake functions */ 40061991Sheppo 40071991Sheppo /* change the hphase for the channel to the next phase */ 40081991Sheppo static vgen_ldc_t * 40091991Sheppo vh_nextphase(vgen_ldc_t *ldcp) 40101991Sheppo { 40111991Sheppo if (ldcp->hphase == VH_PHASE3) { 40121991Sheppo ldcp->hphase = VH_DONE; 40131991Sheppo } else { 40141991Sheppo ldcp->hphase++; 40151991Sheppo } 40161991Sheppo return (ldcp); 40171991Sheppo } 40181991Sheppo 40191991Sheppo /* 40201991Sheppo * wrapper routine to send the given message over ldc using ldc_write(). 40211991Sheppo */ 40221991Sheppo static int 40231991Sheppo vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen, 40241991Sheppo boolean_t caller_holds_lock) 40251991Sheppo { 40265935Ssb155480 int rv; 40275935Ssb155480 size_t len; 40285935Ssb155480 uint32_t retries = 0; 40295935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 40305935Ssb155480 vio_msg_tag_t *tagp = (vio_msg_tag_t *)msg; 40315935Ssb155480 vio_dring_msg_t *dmsg; 40325935Ssb155480 vio_raw_data_msg_t *rmsg; 40335935Ssb155480 boolean_t data_msg = B_FALSE; 40341991Sheppo 40351991Sheppo len = msglen; 40361991Sheppo if ((len == 0) || (msg == NULL)) 40371991Sheppo return (VGEN_FAILURE); 40381991Sheppo 40391991Sheppo if (!caller_holds_lock) { 40404647Sraghuram mutex_enter(&ldcp->wrlock); 40411991Sheppo } 40421991Sheppo 40435935Ssb155480 if (tagp->vio_subtype == VIO_SUBTYPE_INFO) { 40445935Ssb155480 if (tagp->vio_subtype_env == VIO_DRING_DATA) { 40455935Ssb155480 dmsg = (vio_dring_msg_t *)tagp; 40465935Ssb155480 dmsg->seq_num = ldcp->next_txseq; 40475935Ssb155480 data_msg = B_TRUE; 40485935Ssb155480 } else if (tagp->vio_subtype_env == VIO_PKT_DATA) { 40495935Ssb155480 rmsg = (vio_raw_data_msg_t *)tagp; 40505935Ssb155480 rmsg->seq_num = ldcp->next_txseq; 40515935Ssb155480 data_msg = B_TRUE; 40525935Ssb155480 } 40535935Ssb155480 } 40545935Ssb155480 40551991Sheppo do { 40561991Sheppo len = msglen; 40571991Sheppo rv = ldc_write(ldcp->ldc_handle, (caddr_t)msg, &len); 40581991Sheppo if (retries++ >= vgen_ldcwr_retries) 40591991Sheppo break; 40601991Sheppo } while (rv == EWOULDBLOCK); 40611991Sheppo 40625935Ssb155480 if (rv == 0 && data_msg == B_TRUE) { 40635935Ssb155480 ldcp->next_txseq++; 40645935Ssb155480 } 40655935Ssb155480 40661991Sheppo if (!caller_holds_lock) { 40674647Sraghuram mutex_exit(&ldcp->wrlock); 40681991Sheppo } 40691991Sheppo 40702793Slm66018 if (rv != 0) { 40714647Sraghuram DWARN(vgenp, ldcp, "ldc_write failed: rv(%d)\n", 40724647Sraghuram rv, msglen); 40732793Slm66018 return (rv); 40742793Slm66018 } 40752793Slm66018 40762793Slm66018 if (len != msglen) { 40774647Sraghuram DWARN(vgenp, ldcp, "ldc_write failed: rv(%d) msglen (%d)\n", 40784647Sraghuram rv, msglen); 40791991Sheppo return (VGEN_FAILURE); 40801991Sheppo } 40812793Slm66018 40821991Sheppo return (VGEN_SUCCESS); 40831991Sheppo } 40841991Sheppo 40851991Sheppo /* send version negotiate message to the peer over ldc */ 40861991Sheppo static int 40871991Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp) 40881991Sheppo { 40894647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 40901991Sheppo vio_ver_msg_t vermsg; 40911991Sheppo vio_msg_tag_t *tagp = &vermsg.tag; 40921991Sheppo int rv; 40931991Sheppo 40941991Sheppo bzero(&vermsg, sizeof (vermsg)); 40951991Sheppo 40961991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 40971991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 40981991Sheppo tagp->vio_subtype_env = VIO_VER_INFO; 40991991Sheppo tagp->vio_sid = ldcp->local_sid; 41001991Sheppo 41011991Sheppo /* get version msg payload from ldcp->local */ 41021991Sheppo vermsg.ver_major = ldcp->local_hparams.ver_major; 41031991Sheppo vermsg.ver_minor = ldcp->local_hparams.ver_minor; 41041991Sheppo vermsg.dev_class = ldcp->local_hparams.dev_class; 41051991Sheppo 41061991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE); 41071991Sheppo if (rv != VGEN_SUCCESS) { 41084647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 41092793Slm66018 return (rv); 41101991Sheppo } 41111991Sheppo 41121991Sheppo ldcp->hstate |= VER_INFO_SENT; 41134647Sraghuram DBG2(vgenp, ldcp, "VER_INFO_SENT ver(%d,%d)\n", 41144647Sraghuram vermsg.ver_major, vermsg.ver_minor); 41151991Sheppo 41161991Sheppo return (VGEN_SUCCESS); 41171991Sheppo } 41181991Sheppo 41191991Sheppo /* send attr info message to the peer over ldc */ 41201991Sheppo static int 41211991Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp) 41221991Sheppo { 41234647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 41241991Sheppo vnet_attr_msg_t attrmsg; 41251991Sheppo vio_msg_tag_t *tagp = &attrmsg.tag; 41261991Sheppo int rv; 41271991Sheppo 41281991Sheppo bzero(&attrmsg, sizeof (attrmsg)); 41291991Sheppo 41301991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 41311991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 41321991Sheppo tagp->vio_subtype_env = VIO_ATTR_INFO; 41331991Sheppo tagp->vio_sid = ldcp->local_sid; 41341991Sheppo 41351991Sheppo /* get attr msg payload from ldcp->local */ 41361991Sheppo attrmsg.mtu = ldcp->local_hparams.mtu; 41371991Sheppo attrmsg.addr = ldcp->local_hparams.addr; 41381991Sheppo attrmsg.addr_type = ldcp->local_hparams.addr_type; 41391991Sheppo attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode; 41401991Sheppo attrmsg.ack_freq = ldcp->local_hparams.ack_freq; 41411991Sheppo 41421991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE); 41431991Sheppo if (rv != VGEN_SUCCESS) { 41444647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 41452793Slm66018 return (rv); 41461991Sheppo } 41471991Sheppo 41481991Sheppo ldcp->hstate |= ATTR_INFO_SENT; 41494647Sraghuram DBG2(vgenp, ldcp, "ATTR_INFO_SENT\n"); 41501991Sheppo 41511991Sheppo return (VGEN_SUCCESS); 41521991Sheppo } 41531991Sheppo 41541991Sheppo /* send descriptor ring register message to the peer over ldc */ 41551991Sheppo static int 41561991Sheppo vgen_send_dring_reg(vgen_ldc_t *ldcp) 41571991Sheppo { 41584647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 41591991Sheppo vio_dring_reg_msg_t msg; 41601991Sheppo vio_msg_tag_t *tagp = &msg.tag; 41611991Sheppo int rv; 41621991Sheppo 41631991Sheppo bzero(&msg, sizeof (msg)); 41641991Sheppo 41651991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 41661991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 41671991Sheppo tagp->vio_subtype_env = VIO_DRING_REG; 41681991Sheppo tagp->vio_sid = ldcp->local_sid; 41691991Sheppo 41701991Sheppo /* get dring info msg payload from ldcp->local */ 41711991Sheppo bcopy(&(ldcp->local_hparams.dring_cookie), (msg.cookie), 41724650Sraghuram sizeof (ldc_mem_cookie_t)); 41731991Sheppo msg.ncookies = ldcp->local_hparams.num_dcookies; 41741991Sheppo msg.num_descriptors = ldcp->local_hparams.num_desc; 41751991Sheppo msg.descriptor_size = ldcp->local_hparams.desc_size; 41761991Sheppo 41771991Sheppo /* 41781991Sheppo * dring_ident is set to 0. After mapping the dring, peer sets this 41791991Sheppo * value and sends it in the ack, which is saved in 41801991Sheppo * vgen_handle_dring_reg(). 41811991Sheppo */ 41821991Sheppo msg.dring_ident = 0; 41831991Sheppo 41841991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (msg), B_FALSE); 41851991Sheppo if (rv != VGEN_SUCCESS) { 41864647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 41872793Slm66018 return (rv); 41881991Sheppo } 41891991Sheppo 41901991Sheppo ldcp->hstate |= DRING_INFO_SENT; 41914647Sraghuram DBG2(vgenp, ldcp, "DRING_INFO_SENT \n"); 41921991Sheppo 41931991Sheppo return (VGEN_SUCCESS); 41941991Sheppo } 41951991Sheppo 41961991Sheppo static int 41971991Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp) 41981991Sheppo { 41994647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 42001991Sheppo vio_rdx_msg_t rdxmsg; 42011991Sheppo vio_msg_tag_t *tagp = &rdxmsg.tag; 42021991Sheppo int rv; 42031991Sheppo 42041991Sheppo bzero(&rdxmsg, sizeof (rdxmsg)); 42051991Sheppo 42061991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 42071991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 42081991Sheppo tagp->vio_subtype_env = VIO_RDX; 42091991Sheppo tagp->vio_sid = ldcp->local_sid; 42101991Sheppo 42111991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE); 42121991Sheppo if (rv != VGEN_SUCCESS) { 42134647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 42142793Slm66018 return (rv); 42151991Sheppo } 42161991Sheppo 42171991Sheppo ldcp->hstate |= RDX_INFO_SENT; 42184647Sraghuram DBG2(vgenp, ldcp, "RDX_INFO_SENT\n"); 42191991Sheppo 42201991Sheppo return (VGEN_SUCCESS); 42211991Sheppo } 42221991Sheppo 42231991Sheppo /* send descriptor ring data message to the peer over ldc */ 42241991Sheppo static int 42252336Snarayan vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end) 42261991Sheppo { 42274647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 42281991Sheppo vio_dring_msg_t dringmsg, *msgp = &dringmsg; 42291991Sheppo vio_msg_tag_t *tagp = &msgp->tag; 42305373Sraghuram vgen_stats_t *statsp = &ldcp->stats; 42311991Sheppo int rv; 42321991Sheppo 42331991Sheppo bzero(msgp, sizeof (*msgp)); 42341991Sheppo 42351991Sheppo tagp->vio_msgtype = VIO_TYPE_DATA; 42361991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 42371991Sheppo tagp->vio_subtype_env = VIO_DRING_DATA; 42381991Sheppo tagp->vio_sid = ldcp->local_sid; 42391991Sheppo 42401991Sheppo msgp->dring_ident = ldcp->local_hparams.dring_ident; 42411991Sheppo msgp->start_idx = start; 42421991Sheppo msgp->end_idx = end; 42431991Sheppo 42441991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (dringmsg), B_TRUE); 42451991Sheppo if (rv != VGEN_SUCCESS) { 42464647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 42472793Slm66018 return (rv); 42481991Sheppo } 42491991Sheppo 42505373Sraghuram statsp->dring_data_msgs++; 42512336Snarayan 42524647Sraghuram DBG2(vgenp, ldcp, "DRING_DATA_SENT \n"); 42531991Sheppo 42541991Sheppo return (VGEN_SUCCESS); 42551991Sheppo } 42561991Sheppo 42571991Sheppo /* send multicast addr info message to vsw */ 42581991Sheppo static int 42591991Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp) 42601991Sheppo { 42611991Sheppo vnet_mcast_msg_t mcastmsg; 42621991Sheppo vnet_mcast_msg_t *msgp; 42631991Sheppo vio_msg_tag_t *tagp; 42641991Sheppo vgen_t *vgenp; 42651991Sheppo struct ether_addr *mca; 42661991Sheppo int rv; 42671991Sheppo int i; 42681991Sheppo uint32_t size; 42691991Sheppo uint32_t mccount; 42701991Sheppo uint32_t n; 42711991Sheppo 42721991Sheppo msgp = &mcastmsg; 42731991Sheppo tagp = &msgp->tag; 42741991Sheppo vgenp = LDC_TO_VGEN(ldcp); 42751991Sheppo 42761991Sheppo mccount = vgenp->mccount; 42771991Sheppo i = 0; 42781991Sheppo 42791991Sheppo do { 42801991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 42811991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 42821991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 42831991Sheppo tagp->vio_sid = ldcp->local_sid; 42841991Sheppo 42851991Sheppo n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount); 42861991Sheppo size = n * sizeof (struct ether_addr); 42871991Sheppo 42881991Sheppo mca = &(vgenp->mctab[i]); 42891991Sheppo bcopy(mca, (msgp->mca), size); 42901991Sheppo msgp->set = B_TRUE; 42911991Sheppo msgp->count = n; 42921991Sheppo 42931991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), 42941991Sheppo B_FALSE); 42951991Sheppo if (rv != VGEN_SUCCESS) { 42964647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg err(%d)\n", rv); 42972793Slm66018 return (rv); 42981991Sheppo } 42991991Sheppo 43001991Sheppo mccount -= n; 43011991Sheppo i += n; 43021991Sheppo 43031991Sheppo } while (mccount); 43041991Sheppo 43051991Sheppo return (VGEN_SUCCESS); 43061991Sheppo } 43071991Sheppo 43081991Sheppo /* Initiate Phase 2 of handshake */ 43091991Sheppo static int 43101991Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp) 43111991Sheppo { 43121991Sheppo int rv; 43132793Slm66018 uint32_t ncookies = 0; 43144647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 43154647Sraghuram 43161991Sheppo #ifdef DEBUG 43171991Sheppo if (vgen_hdbg & HDBG_OUT_STATE) { 43181991Sheppo /* simulate out of state condition */ 43191991Sheppo vgen_hdbg &= ~(HDBG_OUT_STATE); 43201991Sheppo rv = vgen_send_rdx_info(ldcp); 43211991Sheppo return (rv); 43221991Sheppo } 43231991Sheppo if (vgen_hdbg & HDBG_TIMEOUT) { 43241991Sheppo /* simulate timeout condition */ 43251991Sheppo vgen_hdbg &= ~(HDBG_TIMEOUT); 43261991Sheppo return (VGEN_SUCCESS); 43271991Sheppo } 43281991Sheppo #endif 43292793Slm66018 rv = vgen_send_attr_info(ldcp); 43302793Slm66018 if (rv != VGEN_SUCCESS) { 43311991Sheppo return (rv); 43321991Sheppo } 43332793Slm66018 43342793Slm66018 /* Bind descriptor ring to the channel */ 43352793Slm66018 if (ldcp->num_txdcookies == 0) { 43362793Slm66018 rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->tx_dhandle, 43376845Sha137994 LDC_DIRECT_MAP | LDC_SHADOW_MAP, LDC_MEM_RW, 43386845Sha137994 &ldcp->tx_dcookie, &ncookies); 43392793Slm66018 if (rv != 0) { 43404647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_bind failed " 43414650Sraghuram "rv(%x)\n", rv); 43422793Slm66018 return (rv); 43432793Slm66018 } 43442793Slm66018 ASSERT(ncookies == 1); 43452793Slm66018 ldcp->num_txdcookies = ncookies; 43462793Slm66018 } 43472793Slm66018 43482793Slm66018 /* update local dring_info params */ 43492793Slm66018 bcopy(&(ldcp->tx_dcookie), &(ldcp->local_hparams.dring_cookie), 43504650Sraghuram sizeof (ldc_mem_cookie_t)); 43512793Slm66018 ldcp->local_hparams.num_dcookies = ldcp->num_txdcookies; 43522793Slm66018 ldcp->local_hparams.num_desc = ldcp->num_txds; 43532793Slm66018 ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t); 43542793Slm66018 43552793Slm66018 rv = vgen_send_dring_reg(ldcp); 43562793Slm66018 if (rv != VGEN_SUCCESS) { 43571991Sheppo return (rv); 43581991Sheppo } 43591991Sheppo 43601991Sheppo return (VGEN_SUCCESS); 43611991Sheppo } 43621991Sheppo 43631991Sheppo /* 43645935Ssb155480 * Set vnet-protocol-version dependent functions based on version. 43655935Ssb155480 */ 43665935Ssb155480 static void 43675935Ssb155480 vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp) 43685935Ssb155480 { 43695935Ssb155480 vgen_hparams_t *lp = &ldcp->local_hparams; 43705935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 43715935Ssb155480 43727529SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 4)) { 43736419Ssb155480 /* 43747529SSriharsha.Basavapatna@Sun.COM * If the version negotiated with peer is >= 1.4(Jumbo Frame 43757529SSriharsha.Basavapatna@Sun.COM * Support), set the mtu in our attributes to max_frame_size. 43766419Ssb155480 */ 43776419Ssb155480 lp->mtu = vgenp->max_frame_size; 43787529SSriharsha.Basavapatna@Sun.COM } else if (VGEN_VER_EQ(ldcp, 1, 3)) { 43797529SSriharsha.Basavapatna@Sun.COM /* 43807529SSriharsha.Basavapatna@Sun.COM * If the version negotiated with peer is == 1.3 (Vlan Tag 43817529SSriharsha.Basavapatna@Sun.COM * Support) set the attr.mtu to ETHERMAX + VLAN_TAGSZ. 43827529SSriharsha.Basavapatna@Sun.COM */ 43837529SSriharsha.Basavapatna@Sun.COM lp->mtu = ETHERMAX + VLAN_TAGSZ; 43846419Ssb155480 } else { 43856419Ssb155480 vgen_port_t *portp = ldcp->portp; 43866419Ssb155480 vnet_t *vnetp = vgenp->vnetp; 43876419Ssb155480 /* 43886419Ssb155480 * Pre-1.3 peers expect max frame size of ETHERMAX. 43896419Ssb155480 * We can negotiate that size with those peers provided the 43906419Ssb155480 * following conditions are true: 43916419Ssb155480 * - Only pvid is defined for our peer and there are no vids. 43926419Ssb155480 * - pvids are equal. 43936419Ssb155480 * If the above conditions are true, then we can send/recv only 43946419Ssb155480 * untagged frames of max size ETHERMAX. 43956419Ssb155480 */ 43967529SSriharsha.Basavapatna@Sun.COM if (portp->nvids == 0 && portp->pvid == vnetp->pvid) { 43976419Ssb155480 lp->mtu = ETHERMAX; 43986419Ssb155480 } 43996419Ssb155480 } 44006419Ssb155480 44016419Ssb155480 if (VGEN_VER_GTEQ(ldcp, 1, 2)) { 44026419Ssb155480 /* Versions >= 1.2 */ 44035935Ssb155480 44045935Ssb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) { 44055935Ssb155480 /* 44065935Ssb155480 * enable priority routines and pkt mode only if 44075935Ssb155480 * at least one pri-eth-type is specified in MD. 44085935Ssb155480 */ 44095935Ssb155480 44105935Ssb155480 ldcp->tx = vgen_ldcsend; 44115935Ssb155480 ldcp->rx_pktdata = vgen_handle_pkt_data; 44125935Ssb155480 44135935Ssb155480 /* set xfer mode for vgen_send_attr_info() */ 44145935Ssb155480 lp->xfer_mode = VIO_PKT_MODE | VIO_DRING_MODE_V1_2; 44155935Ssb155480 44165935Ssb155480 } else { 44175935Ssb155480 /* no priority eth types defined in MD */ 44185935Ssb155480 44195935Ssb155480 ldcp->tx = vgen_ldcsend_dring; 44205935Ssb155480 ldcp->rx_pktdata = vgen_handle_pkt_data_nop; 44215935Ssb155480 44225935Ssb155480 /* set xfer mode for vgen_send_attr_info() */ 44235935Ssb155480 lp->xfer_mode = VIO_DRING_MODE_V1_2; 44245935Ssb155480 44255935Ssb155480 } 44265935Ssb155480 } else { 44275935Ssb155480 /* Versions prior to 1.2 */ 44285935Ssb155480 44295935Ssb155480 vgen_reset_vnet_proto_ops(ldcp); 44305935Ssb155480 } 44315935Ssb155480 } 44325935Ssb155480 44335935Ssb155480 /* 44345935Ssb155480 * Reset vnet-protocol-version dependent functions to pre-v1.2. 44355935Ssb155480 */ 44365935Ssb155480 static void 44375935Ssb155480 vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp) 44385935Ssb155480 { 44395935Ssb155480 vgen_hparams_t *lp = &ldcp->local_hparams; 44405935Ssb155480 44415935Ssb155480 ldcp->tx = vgen_ldcsend_dring; 44425935Ssb155480 ldcp->rx_pktdata = vgen_handle_pkt_data_nop; 44435935Ssb155480 44445935Ssb155480 /* set xfer mode for vgen_send_attr_info() */ 44455935Ssb155480 lp->xfer_mode = VIO_DRING_MODE_V1_0; 44465935Ssb155480 } 44475935Ssb155480 44486419Ssb155480 static void 44496419Ssb155480 vgen_vlan_unaware_port_reset(vgen_port_t *portp) 44506419Ssb155480 { 44516419Ssb155480 vgen_ldclist_t *ldclp; 44526419Ssb155480 vgen_ldc_t *ldcp; 44536419Ssb155480 vgen_t *vgenp = portp->vgenp; 44546419Ssb155480 vnet_t *vnetp = vgenp->vnetp; 44556419Ssb155480 44566419Ssb155480 ldclp = &portp->ldclist; 44576419Ssb155480 44586419Ssb155480 READ_ENTER(&ldclp->rwlock); 44596419Ssb155480 44606419Ssb155480 /* 44616419Ssb155480 * NOTE: for now, we will assume we have a single channel. 44626419Ssb155480 */ 44636419Ssb155480 if (ldclp->headp == NULL) { 44646419Ssb155480 RW_EXIT(&ldclp->rwlock); 44656419Ssb155480 return; 44666419Ssb155480 } 44676419Ssb155480 ldcp = ldclp->headp; 44686419Ssb155480 44696419Ssb155480 mutex_enter(&ldcp->cblock); 44706419Ssb155480 44716419Ssb155480 /* 44726419Ssb155480 * If the peer is vlan_unaware(ver < 1.3), reset channel and terminate 44736419Ssb155480 * the connection. See comments in vgen_set_vnet_proto_ops(). 44746419Ssb155480 */ 44756419Ssb155480 if (ldcp->hphase == VH_DONE && VGEN_VER_LT(ldcp, 1, 3) && 44766419Ssb155480 (portp->nvids != 0 || portp->pvid != vnetp->pvid)) { 44776419Ssb155480 ldcp->need_ldc_reset = B_TRUE; 44786419Ssb155480 vgen_handshake_retry(ldcp); 44796419Ssb155480 } 44806419Ssb155480 44816419Ssb155480 mutex_exit(&ldcp->cblock); 44826419Ssb155480 44836419Ssb155480 RW_EXIT(&ldclp->rwlock); 44846419Ssb155480 } 44856419Ssb155480 44866419Ssb155480 static void 44876419Ssb155480 vgen_reset_vlan_unaware_ports(vgen_t *vgenp) 44886419Ssb155480 { 44896419Ssb155480 vgen_port_t *portp; 44906419Ssb155480 vgen_portlist_t *plistp; 44916419Ssb155480 44926419Ssb155480 plistp = &(vgenp->vgenports); 44936419Ssb155480 READ_ENTER(&plistp->rwlock); 44946419Ssb155480 44956419Ssb155480 for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 44966419Ssb155480 44976419Ssb155480 vgen_vlan_unaware_port_reset(portp); 44986419Ssb155480 44996419Ssb155480 } 45006419Ssb155480 45016419Ssb155480 RW_EXIT(&plistp->rwlock); 45026419Ssb155480 } 45036419Ssb155480 45045935Ssb155480 /* 45051991Sheppo * This function resets the handshake phase to VH_PHASE0(pre-handshake phase). 45061991Sheppo * This can happen after a channel comes up (status: LDC_UP) or 45071991Sheppo * when handshake gets terminated due to various conditions. 45081991Sheppo */ 45091991Sheppo static void 45101991Sheppo vgen_reset_hphase(vgen_ldc_t *ldcp) 45111991Sheppo { 45124647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 45131991Sheppo ldc_status_t istatus; 45142793Slm66018 int rv; 45151991Sheppo 45164647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 45171991Sheppo /* reset hstate and hphase */ 45181991Sheppo ldcp->hstate = 0; 45191991Sheppo ldcp->hphase = VH_PHASE0; 45201991Sheppo 45215935Ssb155480 vgen_reset_vnet_proto_ops(ldcp); 45225935Ssb155480 45233653Snarayan /* 45243653Snarayan * Save the id of pending handshake timer in cancel_htid. 45253653Snarayan * This will be checked in vgen_ldc_cb() and the handshake timer will 45263653Snarayan * be cancelled after releasing cblock. 45273653Snarayan */ 45281991Sheppo if (ldcp->htid) { 45293653Snarayan ldcp->cancel_htid = ldcp->htid; 45301991Sheppo ldcp->htid = 0; 45311991Sheppo } 45321991Sheppo 45331991Sheppo if (ldcp->local_hparams.dring_ready) { 45341991Sheppo ldcp->local_hparams.dring_ready = B_FALSE; 45352793Slm66018 } 45362793Slm66018 45372793Slm66018 /* Unbind tx descriptor ring from the channel */ 45382793Slm66018 if (ldcp->num_txdcookies) { 45392793Slm66018 rv = ldc_mem_dring_unbind(ldcp->tx_dhandle); 45402793Slm66018 if (rv != 0) { 45414647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_unbind failed\n"); 45422793Slm66018 } 45432793Slm66018 ldcp->num_txdcookies = 0; 45441991Sheppo } 45451991Sheppo 45461991Sheppo if (ldcp->peer_hparams.dring_ready) { 45471991Sheppo ldcp->peer_hparams.dring_ready = B_FALSE; 45481991Sheppo /* Unmap peer's dring */ 45491991Sheppo (void) ldc_mem_dring_unmap(ldcp->rx_dhandle); 45501991Sheppo vgen_clobber_rxds(ldcp); 45511991Sheppo } 45521991Sheppo 45531991Sheppo vgen_clobber_tbufs(ldcp); 45541991Sheppo 45551991Sheppo /* 45561991Sheppo * clear local handshake params and initialize. 45571991Sheppo */ 45581991Sheppo bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams)); 45591991Sheppo 45601991Sheppo /* set version to the highest version supported */ 45611991Sheppo ldcp->local_hparams.ver_major = 45624650Sraghuram ldcp->vgen_versions[0].ver_major; 45631991Sheppo ldcp->local_hparams.ver_minor = 45644650Sraghuram ldcp->vgen_versions[0].ver_minor; 45651991Sheppo ldcp->local_hparams.dev_class = VDEV_NETWORK; 45661991Sheppo 45671991Sheppo /* set attr_info params */ 45686419Ssb155480 ldcp->local_hparams.mtu = vgenp->max_frame_size; 45691991Sheppo ldcp->local_hparams.addr = 45705462Swentaoy vnet_macaddr_strtoul(vgenp->macaddr); 45711991Sheppo ldcp->local_hparams.addr_type = ADDR_TYPE_MAC; 45725935Ssb155480 ldcp->local_hparams.xfer_mode = VIO_DRING_MODE_V1_0; 45731991Sheppo ldcp->local_hparams.ack_freq = 0; /* don't need acks */ 45741991Sheppo 45751991Sheppo /* 45762793Slm66018 * Note: dring is created, but not bound yet. 45772793Slm66018 * local dring_info params will be updated when we bind the dring in 45782793Slm66018 * vgen_handshake_phase2(). 45791991Sheppo * dring_ident is set to 0. After mapping the dring, peer sets this 45801991Sheppo * value and sends it in the ack, which is saved in 45811991Sheppo * vgen_handle_dring_reg(). 45821991Sheppo */ 45831991Sheppo ldcp->local_hparams.dring_ident = 0; 45841991Sheppo 45851991Sheppo /* clear peer_hparams */ 45861991Sheppo bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams)); 45871991Sheppo 45881991Sheppo /* reset the channel if required */ 45891991Sheppo if (ldcp->need_ldc_reset) { 45904647Sraghuram DWARN(vgenp, ldcp, "Doing Channel Reset...\n"); 45911991Sheppo ldcp->need_ldc_reset = B_FALSE; 45922410Slm66018 (void) ldc_down(ldcp->ldc_handle); 45931991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 45944647Sraghuram DBG2(vgenp, ldcp, "Reset Done,ldc_status(%x)\n", istatus); 45951991Sheppo ldcp->ldc_status = istatus; 45962793Slm66018 45971991Sheppo /* clear sids */ 45981991Sheppo ldcp->local_sid = 0; 45991991Sheppo ldcp->peer_sid = 0; 46002793Slm66018 46012793Slm66018 /* try to bring the channel up */ 46022793Slm66018 rv = ldc_up(ldcp->ldc_handle); 46032793Slm66018 if (rv != 0) { 46044647Sraghuram DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv); 46052793Slm66018 } 46062793Slm66018 46072793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 46084647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 46092793Slm66018 } else { 46102793Slm66018 ldcp->ldc_status = istatus; 46112793Slm66018 } 46121991Sheppo } 46131991Sheppo } 46141991Sheppo 46151991Sheppo /* wrapper function for vgen_reset_hphase */ 46161991Sheppo static void 46171991Sheppo vgen_handshake_reset(vgen_ldc_t *ldcp) 46181991Sheppo { 46191991Sheppo ASSERT(MUTEX_HELD(&ldcp->cblock)); 46204647Sraghuram mutex_enter(&ldcp->rxlock); 46214647Sraghuram mutex_enter(&ldcp->wrlock); 46221991Sheppo mutex_enter(&ldcp->txlock); 46231991Sheppo mutex_enter(&ldcp->tclock); 46241991Sheppo 46251991Sheppo vgen_reset_hphase(ldcp); 46261991Sheppo 46271991Sheppo mutex_exit(&ldcp->tclock); 46281991Sheppo mutex_exit(&ldcp->txlock); 46294647Sraghuram mutex_exit(&ldcp->wrlock); 46304647Sraghuram mutex_exit(&ldcp->rxlock); 46311991Sheppo } 46321991Sheppo 46331991Sheppo /* 46341991Sheppo * Initiate handshake with the peer by sending various messages 46351991Sheppo * based on the handshake-phase that the channel is currently in. 46361991Sheppo */ 46371991Sheppo static void 46381991Sheppo vgen_handshake(vgen_ldc_t *ldcp) 46391991Sheppo { 46401991Sheppo uint32_t hphase = ldcp->hphase; 46411991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 46422793Slm66018 ldc_status_t istatus; 46432793Slm66018 int rv = 0; 46441991Sheppo 46451991Sheppo switch (hphase) { 46461991Sheppo 46471991Sheppo case VH_PHASE1: 46481991Sheppo 46491991Sheppo /* 46501991Sheppo * start timer, for entire handshake process, turn this timer 46511991Sheppo * off if all phases of handshake complete successfully and 46521991Sheppo * hphase goes to VH_DONE(below) or 46531991Sheppo * vgen_reset_hphase() gets called or 46541991Sheppo * channel is reset due to errors or 46551991Sheppo * vgen_ldc_uninit() is invoked(vgen_stop). 46561991Sheppo */ 4657*7572SWentao.Yang@Sun.COM ASSERT(ldcp->htid == 0); 46581991Sheppo ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp, 46595171Ssb155480 drv_usectohz(vgen_hwd_interval * MICROSEC)); 46601991Sheppo 46611991Sheppo /* Phase 1 involves negotiating the version */ 46622793Slm66018 rv = vgen_send_version_negotiate(ldcp); 46631991Sheppo break; 46641991Sheppo 46651991Sheppo case VH_PHASE2: 46662793Slm66018 rv = vgen_handshake_phase2(ldcp); 46671991Sheppo break; 46681991Sheppo 46691991Sheppo case VH_PHASE3: 46702793Slm66018 rv = vgen_send_rdx_info(ldcp); 46711991Sheppo break; 46721991Sheppo 46731991Sheppo case VH_DONE: 46743653Snarayan /* 46753653Snarayan * Save the id of pending handshake timer in cancel_htid. 46763653Snarayan * This will be checked in vgen_ldc_cb() and the handshake 46773653Snarayan * timer will be cancelled after releasing cblock. 46783653Snarayan */ 46791991Sheppo if (ldcp->htid) { 46803653Snarayan ldcp->cancel_htid = ldcp->htid; 46811991Sheppo ldcp->htid = 0; 46821991Sheppo } 46831991Sheppo ldcp->hretries = 0; 46844647Sraghuram DBG1(vgenp, ldcp, "Handshake Done\n"); 46851991Sheppo 46865171Ssb155480 if (ldcp->portp == vgenp->vsw_portp) { 46875171Ssb155480 /* 46885171Ssb155480 * If this channel(port) is connected to vsw, 46895171Ssb155480 * need to sync multicast table with vsw. 46905171Ssb155480 */ 46911991Sheppo mutex_exit(&ldcp->cblock); 46921991Sheppo 46931991Sheppo mutex_enter(&vgenp->lock); 46942793Slm66018 rv = vgen_send_mcast_info(ldcp); 46951991Sheppo mutex_exit(&vgenp->lock); 46961991Sheppo 46971991Sheppo mutex_enter(&ldcp->cblock); 46982793Slm66018 if (rv != VGEN_SUCCESS) 46992793Slm66018 break; 47001991Sheppo } 47012793Slm66018 47022793Slm66018 /* 47032793Slm66018 * Check if mac layer should be notified to restart 47042793Slm66018 * transmissions. This can happen if the channel got 47052793Slm66018 * reset and vgen_clobber_tbufs() is called, while 47062793Slm66018 * need_resched is set. 47072793Slm66018 */ 47082793Slm66018 mutex_enter(&ldcp->tclock); 47092793Slm66018 if (ldcp->need_resched) { 47106495Sspeer vio_net_tx_update_t vtx_update = 47116495Sspeer ldcp->portp->vcb.vio_net_tx_update; 47126495Sspeer 47132793Slm66018 ldcp->need_resched = B_FALSE; 47146495Sspeer vtx_update(ldcp->portp->vhp); 47152793Slm66018 } 47162793Slm66018 mutex_exit(&ldcp->tclock); 47172793Slm66018 47181991Sheppo break; 47191991Sheppo 47201991Sheppo default: 47211991Sheppo break; 47221991Sheppo } 47232793Slm66018 47242793Slm66018 if (rv == ECONNRESET) { 47252793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 47264647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 47272793Slm66018 } else { 47282793Slm66018 ldcp->ldc_status = istatus; 47292793Slm66018 } 47306495Sspeer vgen_handle_evt_reset(ldcp); 47312793Slm66018 } else if (rv) { 47322793Slm66018 vgen_handshake_reset(ldcp); 47332793Slm66018 } 47341991Sheppo } 47351991Sheppo 47361991Sheppo /* 47371991Sheppo * Check if the current handshake phase has completed successfully and 47381991Sheppo * return the status. 47391991Sheppo */ 47401991Sheppo static int 47411991Sheppo vgen_handshake_done(vgen_ldc_t *ldcp) 47421991Sheppo { 47434647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 47441991Sheppo uint32_t hphase = ldcp->hphase; 47451991Sheppo int status = 0; 47461991Sheppo 47471991Sheppo switch (hphase) { 47481991Sheppo 47491991Sheppo case VH_PHASE1: 47501991Sheppo /* 47511991Sheppo * Phase1 is done, if version negotiation 47521991Sheppo * completed successfully. 47531991Sheppo */ 47541991Sheppo status = ((ldcp->hstate & VER_NEGOTIATED) == 47554650Sraghuram VER_NEGOTIATED); 47561991Sheppo break; 47571991Sheppo 47581991Sheppo case VH_PHASE2: 47591991Sheppo /* 47601991Sheppo * Phase 2 is done, if attr info and dring info 47611991Sheppo * have been exchanged successfully. 47621991Sheppo */ 47631991Sheppo status = (((ldcp->hstate & ATTR_INFO_EXCHANGED) == 47644650Sraghuram ATTR_INFO_EXCHANGED) && 47654650Sraghuram ((ldcp->hstate & DRING_INFO_EXCHANGED) == 47664650Sraghuram DRING_INFO_EXCHANGED)); 47671991Sheppo break; 47681991Sheppo 47691991Sheppo case VH_PHASE3: 47701991Sheppo /* Phase 3 is done, if rdx msg has been exchanged */ 47711991Sheppo status = ((ldcp->hstate & RDX_EXCHANGED) == 47724650Sraghuram RDX_EXCHANGED); 47731991Sheppo break; 47741991Sheppo 47751991Sheppo default: 47761991Sheppo break; 47771991Sheppo } 47781991Sheppo 47791991Sheppo if (status == 0) { 47801991Sheppo return (VGEN_FAILURE); 47811991Sheppo } 47824647Sraghuram DBG2(vgenp, ldcp, "PHASE(%d)\n", hphase); 47831991Sheppo return (VGEN_SUCCESS); 47841991Sheppo } 47851991Sheppo 47861991Sheppo /* retry handshake on failure */ 47871991Sheppo static void 47881991Sheppo vgen_handshake_retry(vgen_ldc_t *ldcp) 47891991Sheppo { 47901991Sheppo /* reset handshake phase */ 47911991Sheppo vgen_handshake_reset(ldcp); 47923653Snarayan 47933653Snarayan /* handshake retry is specified and the channel is UP */ 47943653Snarayan if (vgen_max_hretries && (ldcp->ldc_status == LDC_UP)) { 47953653Snarayan if (ldcp->hretries++ < vgen_max_hretries) { 47963653Snarayan ldcp->local_sid = ddi_get_lbolt(); 47971991Sheppo vgen_handshake(vh_nextphase(ldcp)); 47983653Snarayan } 47991991Sheppo } 48001991Sheppo } 48011991Sheppo 48021991Sheppo /* 48031991Sheppo * Handle a version info msg from the peer or an ACK/NACK from the peer 48041991Sheppo * to a version info msg that we sent. 48051991Sheppo */ 48062793Slm66018 static int 48071991Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 48081991Sheppo { 48094647Sraghuram vgen_t *vgenp; 48101991Sheppo vio_ver_msg_t *vermsg = (vio_ver_msg_t *)tagp; 48111991Sheppo int ack = 0; 48121991Sheppo int failed = 0; 48131991Sheppo int idx; 48141991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 48152793Slm66018 int rv = 0; 48161991Sheppo 48174647Sraghuram vgenp = LDC_TO_VGEN(ldcp); 48184647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 48191991Sheppo switch (tagp->vio_subtype) { 48201991Sheppo case VIO_SUBTYPE_INFO: 48211991Sheppo 48221991Sheppo /* Cache sid of peer if this is the first time */ 48231991Sheppo if (ldcp->peer_sid == 0) { 48244647Sraghuram DBG2(vgenp, ldcp, "Caching peer_sid(%x)\n", 48254647Sraghuram tagp->vio_sid); 48261991Sheppo ldcp->peer_sid = tagp->vio_sid; 48271991Sheppo } 48281991Sheppo 48291991Sheppo if (ldcp->hphase != VH_PHASE1) { 48301991Sheppo /* 48311991Sheppo * If we are not already in VH_PHASE1, reset to 48321991Sheppo * pre-handshake state, and initiate handshake 48331991Sheppo * to the peer too. 48341991Sheppo */ 48351991Sheppo vgen_handshake_reset(ldcp); 48361991Sheppo vgen_handshake(vh_nextphase(ldcp)); 48371991Sheppo } 48381991Sheppo ldcp->hstate |= VER_INFO_RCVD; 48391991Sheppo 48401991Sheppo /* save peer's requested values */ 48411991Sheppo ldcp->peer_hparams.ver_major = vermsg->ver_major; 48421991Sheppo ldcp->peer_hparams.ver_minor = vermsg->ver_minor; 48431991Sheppo ldcp->peer_hparams.dev_class = vermsg->dev_class; 48441991Sheppo 48451991Sheppo if ((vermsg->dev_class != VDEV_NETWORK) && 48461991Sheppo (vermsg->dev_class != VDEV_NETWORK_SWITCH)) { 48471991Sheppo /* unsupported dev_class, send NACK */ 48481991Sheppo 48494647Sraghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n"); 48502793Slm66018 48511991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 48521991Sheppo tagp->vio_sid = ldcp->local_sid; 48531991Sheppo /* send reply msg back to peer */ 48542793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, 48551991Sheppo sizeof (*vermsg), B_FALSE); 48562793Slm66018 if (rv != VGEN_SUCCESS) { 48572793Slm66018 return (rv); 48582793Slm66018 } 48592793Slm66018 return (VGEN_FAILURE); 48601991Sheppo } 48611991Sheppo 48624647Sraghuram DBG2(vgenp, ldcp, "VER_INFO_RCVD, ver(%d,%d)\n", 48634647Sraghuram vermsg->ver_major, vermsg->ver_minor); 48641991Sheppo 48651991Sheppo idx = 0; 48661991Sheppo 48671991Sheppo for (;;) { 48681991Sheppo 48691991Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 48701991Sheppo 48711991Sheppo /* nack with next lower version */ 48721991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 48731991Sheppo vermsg->ver_major = versions[idx].ver_major; 48741991Sheppo vermsg->ver_minor = versions[idx].ver_minor; 48751991Sheppo break; 48761991Sheppo } 48771991Sheppo 48781991Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 48791991Sheppo 48801991Sheppo /* major version match - ACK version */ 48811991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 48821991Sheppo ack = 1; 48831991Sheppo 48841991Sheppo /* 48851991Sheppo * lower minor version to the one this endpt 48861991Sheppo * supports, if necessary 48871991Sheppo */ 48881991Sheppo if (vermsg->ver_minor > 48891991Sheppo versions[idx].ver_minor) { 48901991Sheppo vermsg->ver_minor = 48914650Sraghuram versions[idx].ver_minor; 48921991Sheppo ldcp->peer_hparams.ver_minor = 48934650Sraghuram versions[idx].ver_minor; 48941991Sheppo } 48951991Sheppo break; 48961991Sheppo } 48971991Sheppo 48981991Sheppo idx++; 48991991Sheppo 49001991Sheppo if (idx == VGEN_NUM_VER) { 49011991Sheppo 49021991Sheppo /* no version match - send NACK */ 49031991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 49041991Sheppo vermsg->ver_major = 0; 49051991Sheppo vermsg->ver_minor = 0; 49061991Sheppo failed = 1; 49071991Sheppo break; 49081991Sheppo } 49091991Sheppo 49101991Sheppo } 49111991Sheppo 49121991Sheppo tagp->vio_sid = ldcp->local_sid; 49131991Sheppo 49141991Sheppo /* send reply msg back to peer */ 49152793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg), 49162793Slm66018 B_FALSE); 49172793Slm66018 if (rv != VGEN_SUCCESS) { 49182793Slm66018 return (rv); 49191991Sheppo } 49201991Sheppo 49211991Sheppo if (ack) { 49221991Sheppo ldcp->hstate |= VER_ACK_SENT; 49234647Sraghuram DBG2(vgenp, ldcp, "VER_ACK_SENT, ver(%d,%d) \n", 49244647Sraghuram vermsg->ver_major, vermsg->ver_minor); 49251991Sheppo } 49261991Sheppo if (failed) { 49274647Sraghuram DWARN(vgenp, ldcp, "Negotiation Failed\n"); 49282793Slm66018 return (VGEN_FAILURE); 49291991Sheppo } 49301991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 49311991Sheppo 49321991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 49331991Sheppo 49341991Sheppo /* local and peer versions match? */ 49351991Sheppo ASSERT((ldcp->local_hparams.ver_major == 49364650Sraghuram ldcp->peer_hparams.ver_major) && 49374650Sraghuram (ldcp->local_hparams.ver_minor == 49384650Sraghuram ldcp->peer_hparams.ver_minor)); 49391991Sheppo 49405935Ssb155480 vgen_set_vnet_proto_ops(ldcp); 49415935Ssb155480 49421991Sheppo /* move to the next phase */ 49431991Sheppo vgen_handshake(vh_nextphase(ldcp)); 49441991Sheppo } 49451991Sheppo 49461991Sheppo break; 49471991Sheppo 49481991Sheppo case VIO_SUBTYPE_ACK: 49491991Sheppo 49501991Sheppo if (ldcp->hphase != VH_PHASE1) { 49511991Sheppo /* This should not happen. */ 49524647Sraghuram DWARN(vgenp, ldcp, "Invalid Phase(%u)\n", ldcp->hphase); 49532793Slm66018 return (VGEN_FAILURE); 49541991Sheppo } 49551991Sheppo 49561991Sheppo /* SUCCESS - we have agreed on a version */ 49571991Sheppo ldcp->local_hparams.ver_major = vermsg->ver_major; 49581991Sheppo ldcp->local_hparams.ver_minor = vermsg->ver_minor; 49591991Sheppo ldcp->hstate |= VER_ACK_RCVD; 49601991Sheppo 49614647Sraghuram DBG2(vgenp, ldcp, "VER_ACK_RCVD, ver(%d,%d) \n", 49624647Sraghuram vermsg->ver_major, vermsg->ver_minor); 49631991Sheppo 49641991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 49651991Sheppo 49661991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 49671991Sheppo 49681991Sheppo /* local and peer versions match? */ 49691991Sheppo ASSERT((ldcp->local_hparams.ver_major == 49704650Sraghuram ldcp->peer_hparams.ver_major) && 49714650Sraghuram (ldcp->local_hparams.ver_minor == 49724650Sraghuram ldcp->peer_hparams.ver_minor)); 49731991Sheppo 49745935Ssb155480 vgen_set_vnet_proto_ops(ldcp); 49755935Ssb155480 49761991Sheppo /* move to the next phase */ 49771991Sheppo vgen_handshake(vh_nextphase(ldcp)); 49781991Sheppo } 49791991Sheppo break; 49801991Sheppo 49811991Sheppo case VIO_SUBTYPE_NACK: 49821991Sheppo 49831991Sheppo if (ldcp->hphase != VH_PHASE1) { 49841991Sheppo /* This should not happen. */ 49854647Sraghuram DWARN(vgenp, ldcp, "VER_NACK_RCVD Invalid " 49864647Sraghuram "Phase(%u)\n", ldcp->hphase); 49872793Slm66018 return (VGEN_FAILURE); 49881991Sheppo } 49891991Sheppo 49904647Sraghuram DBG2(vgenp, ldcp, "VER_NACK_RCVD next ver(%d,%d)\n", 49914647Sraghuram vermsg->ver_major, vermsg->ver_minor); 49921991Sheppo 49931991Sheppo /* check if version in NACK is zero */ 49941991Sheppo if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) { 49951991Sheppo /* 49961991Sheppo * Version Negotiation has failed. 49971991Sheppo */ 49984647Sraghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n"); 49992793Slm66018 return (VGEN_FAILURE); 50001991Sheppo } 50011991Sheppo 50021991Sheppo idx = 0; 50031991Sheppo 50041991Sheppo for (;;) { 50051991Sheppo 50061991Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 50071991Sheppo /* select next lower version */ 50081991Sheppo 50091991Sheppo ldcp->local_hparams.ver_major = 50104650Sraghuram versions[idx].ver_major; 50111991Sheppo ldcp->local_hparams.ver_minor = 50124650Sraghuram versions[idx].ver_minor; 50131991Sheppo break; 50141991Sheppo } 50151991Sheppo 50161991Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 50171991Sheppo /* major version match */ 50181991Sheppo 50191991Sheppo ldcp->local_hparams.ver_major = 50204650Sraghuram versions[idx].ver_major; 50211991Sheppo 50221991Sheppo ldcp->local_hparams.ver_minor = 50234650Sraghuram versions[idx].ver_minor; 50241991Sheppo break; 50251991Sheppo } 50261991Sheppo 50271991Sheppo idx++; 50281991Sheppo 50291991Sheppo if (idx == VGEN_NUM_VER) { 50301991Sheppo /* 50311991Sheppo * no version match. 50321991Sheppo * Version Negotiation has failed. 50331991Sheppo */ 50344647Sraghuram DWARN(vgenp, ldcp, 50354647Sraghuram "Version Negotiation Failed\n"); 50362793Slm66018 return (VGEN_FAILURE); 50371991Sheppo } 50381991Sheppo 50391991Sheppo } 50401991Sheppo 50412793Slm66018 rv = vgen_send_version_negotiate(ldcp); 50422793Slm66018 if (rv != VGEN_SUCCESS) { 50432793Slm66018 return (rv); 50441991Sheppo } 50451991Sheppo 50461991Sheppo break; 50471991Sheppo } 50482793Slm66018 50494647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 50502793Slm66018 return (VGEN_SUCCESS); 50511991Sheppo } 50521991Sheppo 50531991Sheppo /* Check if the attributes are supported */ 50541991Sheppo static int 50551991Sheppo vgen_check_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg) 50561991Sheppo { 50575935Ssb155480 vgen_hparams_t *lp = &ldcp->local_hparams; 50585935Ssb155480 50597529SSriharsha.Basavapatna@Sun.COM if ((msg->addr_type != ADDR_TYPE_MAC) || 50605935Ssb155480 (msg->ack_freq > 64) || 50615935Ssb155480 (msg->xfer_mode != lp->xfer_mode)) { 50621991Sheppo return (VGEN_FAILURE); 50631991Sheppo } 50641991Sheppo 50657529SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_LT(ldcp, 1, 4)) { 50667529SSriharsha.Basavapatna@Sun.COM /* versions < 1.4, mtu must match */ 50677529SSriharsha.Basavapatna@Sun.COM if (msg->mtu != lp->mtu) { 50687529SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE); 50697529SSriharsha.Basavapatna@Sun.COM } 50707529SSriharsha.Basavapatna@Sun.COM } else { 50717529SSriharsha.Basavapatna@Sun.COM /* Ver >= 1.4, validate mtu of the peer is at least ETHERMAX */ 50727529SSriharsha.Basavapatna@Sun.COM if (msg->mtu < ETHERMAX) { 50737529SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE); 50747529SSriharsha.Basavapatna@Sun.COM } 50757529SSriharsha.Basavapatna@Sun.COM } 50767529SSriharsha.Basavapatna@Sun.COM 50771991Sheppo return (VGEN_SUCCESS); 50781991Sheppo } 50791991Sheppo 50801991Sheppo /* 50811991Sheppo * Handle an attribute info msg from the peer or an ACK/NACK from the peer 50821991Sheppo * to an attr info msg that we sent. 50831991Sheppo */ 50842793Slm66018 static int 50851991Sheppo vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 50861991Sheppo { 50877529SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp); 50887529SSriharsha.Basavapatna@Sun.COM vnet_attr_msg_t *msg = (vnet_attr_msg_t *)tagp; 50897529SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams; 50907529SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *rp = &ldcp->peer_hparams; 50917529SSriharsha.Basavapatna@Sun.COM int ack = 1; 50922793Slm66018 int rv = 0; 50937529SSriharsha.Basavapatna@Sun.COM uint32_t mtu; 50941991Sheppo 50954647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 50961991Sheppo if (ldcp->hphase != VH_PHASE2) { 50974647Sraghuram DWARN(vgenp, ldcp, "Rcvd ATTR_INFO subtype(%d)," 50984647Sraghuram " Invalid Phase(%u)\n", 50994647Sraghuram tagp->vio_subtype, ldcp->hphase); 51002793Slm66018 return (VGEN_FAILURE); 51011991Sheppo } 51021991Sheppo switch (tagp->vio_subtype) { 51031991Sheppo case VIO_SUBTYPE_INFO: 51041991Sheppo 51054647Sraghuram DBG2(vgenp, ldcp, "ATTR_INFO_RCVD \n"); 51061991Sheppo ldcp->hstate |= ATTR_INFO_RCVD; 51071991Sheppo 51081991Sheppo /* save peer's values */ 51097529SSriharsha.Basavapatna@Sun.COM rp->mtu = msg->mtu; 51107529SSriharsha.Basavapatna@Sun.COM rp->addr = msg->addr; 51117529SSriharsha.Basavapatna@Sun.COM rp->addr_type = msg->addr_type; 51127529SSriharsha.Basavapatna@Sun.COM rp->xfer_mode = msg->xfer_mode; 51137529SSriharsha.Basavapatna@Sun.COM rp->ack_freq = msg->ack_freq; 51147529SSriharsha.Basavapatna@Sun.COM 51157529SSriharsha.Basavapatna@Sun.COM rv = vgen_check_attr_info(ldcp, msg); 51167529SSriharsha.Basavapatna@Sun.COM if (rv == VGEN_FAILURE) { 51171991Sheppo /* unsupported attr, send NACK */ 51187529SSriharsha.Basavapatna@Sun.COM ack = 0; 51191991Sheppo } else { 51207529SSriharsha.Basavapatna@Sun.COM 51217529SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 4)) { 51227529SSriharsha.Basavapatna@Sun.COM 51237529SSriharsha.Basavapatna@Sun.COM /* 51247529SSriharsha.Basavapatna@Sun.COM * Versions >= 1.4: 51257529SSriharsha.Basavapatna@Sun.COM * The mtu is negotiated down to the 51267529SSriharsha.Basavapatna@Sun.COM * minimum of our mtu and peer's mtu. 51277529SSriharsha.Basavapatna@Sun.COM */ 51287529SSriharsha.Basavapatna@Sun.COM mtu = MIN(msg->mtu, vgenp->max_frame_size); 51297529SSriharsha.Basavapatna@Sun.COM 51307529SSriharsha.Basavapatna@Sun.COM /* 51317529SSriharsha.Basavapatna@Sun.COM * If we have received an ack for the attr info 51327529SSriharsha.Basavapatna@Sun.COM * that we sent, then check if the mtu computed 51337529SSriharsha.Basavapatna@Sun.COM * above matches the mtu that the peer had ack'd 51347529SSriharsha.Basavapatna@Sun.COM * (saved in local hparams). If they don't 51357529SSriharsha.Basavapatna@Sun.COM * match, we fail the handshake. 51367529SSriharsha.Basavapatna@Sun.COM */ 51377529SSriharsha.Basavapatna@Sun.COM if (ldcp->hstate & ATTR_ACK_RCVD) { 51387529SSriharsha.Basavapatna@Sun.COM if (mtu != lp->mtu) { 51397529SSriharsha.Basavapatna@Sun.COM /* send NACK */ 51407529SSriharsha.Basavapatna@Sun.COM ack = 0; 51417529SSriharsha.Basavapatna@Sun.COM } 51427529SSriharsha.Basavapatna@Sun.COM } else { 51437529SSriharsha.Basavapatna@Sun.COM /* 51447529SSriharsha.Basavapatna@Sun.COM * Save the mtu computed above in our 51457529SSriharsha.Basavapatna@Sun.COM * attr parameters, so it gets sent in 51467529SSriharsha.Basavapatna@Sun.COM * the attr info from us to the peer. 51477529SSriharsha.Basavapatna@Sun.COM */ 51487529SSriharsha.Basavapatna@Sun.COM lp->mtu = mtu; 51497529SSriharsha.Basavapatna@Sun.COM } 51507529SSriharsha.Basavapatna@Sun.COM 51517529SSriharsha.Basavapatna@Sun.COM /* save the MIN mtu in the msg to be replied */ 51527529SSriharsha.Basavapatna@Sun.COM msg->mtu = mtu; 51537529SSriharsha.Basavapatna@Sun.COM 51547529SSriharsha.Basavapatna@Sun.COM } 51557529SSriharsha.Basavapatna@Sun.COM } 51567529SSriharsha.Basavapatna@Sun.COM 51577529SSriharsha.Basavapatna@Sun.COM 51587529SSriharsha.Basavapatna@Sun.COM if (ack) { 51591991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 51607529SSriharsha.Basavapatna@Sun.COM } else { 51617529SSriharsha.Basavapatna@Sun.COM tagp->vio_subtype = VIO_SUBTYPE_NACK; 51621991Sheppo } 51631991Sheppo tagp->vio_sid = ldcp->local_sid; 51641991Sheppo 51651991Sheppo /* send reply msg back to peer */ 51667529SSriharsha.Basavapatna@Sun.COM rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg), 51672793Slm66018 B_FALSE); 51682793Slm66018 if (rv != VGEN_SUCCESS) { 51692793Slm66018 return (rv); 51701991Sheppo } 51711991Sheppo 51721991Sheppo if (ack) { 51731991Sheppo ldcp->hstate |= ATTR_ACK_SENT; 51744647Sraghuram DBG2(vgenp, ldcp, "ATTR_ACK_SENT \n"); 51751991Sheppo } else { 51761991Sheppo /* failed */ 51774647Sraghuram DWARN(vgenp, ldcp, "ATTR_NACK_SENT \n"); 51782793Slm66018 return (VGEN_FAILURE); 51791991Sheppo } 51801991Sheppo 51811991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 51821991Sheppo vgen_handshake(vh_nextphase(ldcp)); 51831991Sheppo } 51841991Sheppo 51851991Sheppo break; 51861991Sheppo 51871991Sheppo case VIO_SUBTYPE_ACK: 51881991Sheppo 51897529SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 4)) { 51907529SSriharsha.Basavapatna@Sun.COM /* 51917529SSriharsha.Basavapatna@Sun.COM * Versions >= 1.4: 51927529SSriharsha.Basavapatna@Sun.COM * The ack msg sent by the peer contains the minimum of 51937529SSriharsha.Basavapatna@Sun.COM * our mtu (that we had sent in our attr info) and the 51947529SSriharsha.Basavapatna@Sun.COM * peer's mtu. 51957529SSriharsha.Basavapatna@Sun.COM * 51967529SSriharsha.Basavapatna@Sun.COM * If we have sent an ack for the attr info msg from 51977529SSriharsha.Basavapatna@Sun.COM * the peer, check if the mtu that was computed then 51987529SSriharsha.Basavapatna@Sun.COM * (saved in local hparams) matches the mtu that the 51997529SSriharsha.Basavapatna@Sun.COM * peer has ack'd. If they don't match, we fail the 52007529SSriharsha.Basavapatna@Sun.COM * handshake. 52017529SSriharsha.Basavapatna@Sun.COM */ 52027529SSriharsha.Basavapatna@Sun.COM if (ldcp->hstate & ATTR_ACK_SENT) { 52037529SSriharsha.Basavapatna@Sun.COM if (lp->mtu != msg->mtu) { 52047529SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE); 52057529SSriharsha.Basavapatna@Sun.COM } 52067529SSriharsha.Basavapatna@Sun.COM } else { 52077529SSriharsha.Basavapatna@Sun.COM /* 52087529SSriharsha.Basavapatna@Sun.COM * If the mtu ack'd by the peer is > our mtu 52097529SSriharsha.Basavapatna@Sun.COM * fail handshake. Otherwise, save the mtu, so 52107529SSriharsha.Basavapatna@Sun.COM * we can validate it when we receive attr info 52117529SSriharsha.Basavapatna@Sun.COM * from our peer. 52127529SSriharsha.Basavapatna@Sun.COM */ 52137529SSriharsha.Basavapatna@Sun.COM if (msg->mtu > lp->mtu) { 52147529SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE); 52157529SSriharsha.Basavapatna@Sun.COM } 52167529SSriharsha.Basavapatna@Sun.COM if (msg->mtu <= lp->mtu) { 52177529SSriharsha.Basavapatna@Sun.COM lp->mtu = msg->mtu; 52187529SSriharsha.Basavapatna@Sun.COM } 52197529SSriharsha.Basavapatna@Sun.COM } 52207529SSriharsha.Basavapatna@Sun.COM } 52217529SSriharsha.Basavapatna@Sun.COM 52221991Sheppo ldcp->hstate |= ATTR_ACK_RCVD; 52231991Sheppo 52244647Sraghuram DBG2(vgenp, ldcp, "ATTR_ACK_RCVD \n"); 52251991Sheppo 52261991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 52271991Sheppo vgen_handshake(vh_nextphase(ldcp)); 52281991Sheppo } 52291991Sheppo break; 52301991Sheppo 52311991Sheppo case VIO_SUBTYPE_NACK: 52321991Sheppo 52334647Sraghuram DBG2(vgenp, ldcp, "ATTR_NACK_RCVD \n"); 52342793Slm66018 return (VGEN_FAILURE); 52351991Sheppo } 52364647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 52372793Slm66018 return (VGEN_SUCCESS); 52381991Sheppo } 52391991Sheppo 52401991Sheppo /* Check if the dring info msg is ok */ 52411991Sheppo static int 52421991Sheppo vgen_check_dring_reg(vio_dring_reg_msg_t *msg) 52431991Sheppo { 52441991Sheppo /* check if msg contents are ok */ 52451991Sheppo if ((msg->num_descriptors < 128) || (msg->descriptor_size < 52461991Sheppo sizeof (vnet_public_desc_t))) { 52471991Sheppo return (VGEN_FAILURE); 52481991Sheppo } 52491991Sheppo return (VGEN_SUCCESS); 52501991Sheppo } 52511991Sheppo 52521991Sheppo /* 52531991Sheppo * Handle a descriptor ring register msg from the peer or an ACK/NACK from 52541991Sheppo * the peer to a dring register msg that we sent. 52551991Sheppo */ 52562793Slm66018 static int 52571991Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 52581991Sheppo { 52591991Sheppo vio_dring_reg_msg_t *msg = (vio_dring_reg_msg_t *)tagp; 52601991Sheppo ldc_mem_cookie_t dcookie; 52614647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 52621991Sheppo int ack = 0; 52631991Sheppo int rv = 0; 52641991Sheppo 52654647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 52661991Sheppo if (ldcp->hphase < VH_PHASE2) { 52671991Sheppo /* dring_info can be rcvd in any of the phases after Phase1 */ 52684647Sraghuram DWARN(vgenp, ldcp, 52694647Sraghuram "Rcvd DRING_INFO Subtype (%d), Invalid Phase(%u)\n", 52704650Sraghuram tagp->vio_subtype, ldcp->hphase); 52712793Slm66018 return (VGEN_FAILURE); 52721991Sheppo } 52731991Sheppo switch (tagp->vio_subtype) { 52741991Sheppo case VIO_SUBTYPE_INFO: 52751991Sheppo 52764647Sraghuram DBG2(vgenp, ldcp, "DRING_INFO_RCVD \n"); 52771991Sheppo ldcp->hstate |= DRING_INFO_RCVD; 52781991Sheppo bcopy((msg->cookie), &dcookie, sizeof (dcookie)); 52791991Sheppo 52801991Sheppo ASSERT(msg->ncookies == 1); 52811991Sheppo 52821991Sheppo if (vgen_check_dring_reg(msg) == VGEN_SUCCESS) { 52831991Sheppo /* 52841991Sheppo * verified dring info msg to be ok, 52851991Sheppo * now try to map the remote dring. 52861991Sheppo */ 52871991Sheppo rv = vgen_init_rxds(ldcp, msg->num_descriptors, 52881991Sheppo msg->descriptor_size, &dcookie, 52891991Sheppo msg->ncookies); 52901991Sheppo if (rv == DDI_SUCCESS) { 52911991Sheppo /* now we can ack the peer */ 52921991Sheppo ack = 1; 52931991Sheppo } 52941991Sheppo } 52951991Sheppo if (ack == 0) { 52961991Sheppo /* failed, send NACK */ 52971991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 52981991Sheppo } else { 52991991Sheppo if (!(ldcp->peer_hparams.dring_ready)) { 53001991Sheppo 53011991Sheppo /* save peer's dring_info values */ 53021991Sheppo bcopy(&dcookie, 53031991Sheppo &(ldcp->peer_hparams.dring_cookie), 53041991Sheppo sizeof (dcookie)); 53051991Sheppo ldcp->peer_hparams.num_desc = 53064650Sraghuram msg->num_descriptors; 53071991Sheppo ldcp->peer_hparams.desc_size = 53084650Sraghuram msg->descriptor_size; 53091991Sheppo ldcp->peer_hparams.num_dcookies = 53104650Sraghuram msg->ncookies; 53111991Sheppo 53121991Sheppo /* set dring_ident for the peer */ 53131991Sheppo ldcp->peer_hparams.dring_ident = 53144650Sraghuram (uint64_t)ldcp->rxdp; 53151991Sheppo /* return the dring_ident in ack msg */ 53161991Sheppo msg->dring_ident = 53174650Sraghuram (uint64_t)ldcp->rxdp; 53181991Sheppo 53191991Sheppo ldcp->peer_hparams.dring_ready = B_TRUE; 53201991Sheppo } 53211991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 53221991Sheppo } 53231991Sheppo tagp->vio_sid = ldcp->local_sid; 53241991Sheppo /* send reply msg back to peer */ 53252793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg), 53262793Slm66018 B_FALSE); 53272793Slm66018 if (rv != VGEN_SUCCESS) { 53282793Slm66018 return (rv); 53291991Sheppo } 53301991Sheppo 53311991Sheppo if (ack) { 53321991Sheppo ldcp->hstate |= DRING_ACK_SENT; 53334647Sraghuram DBG2(vgenp, ldcp, "DRING_ACK_SENT"); 53341991Sheppo } else { 53354647Sraghuram DWARN(vgenp, ldcp, "DRING_NACK_SENT"); 53362793Slm66018 return (VGEN_FAILURE); 53371991Sheppo } 53381991Sheppo 53391991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 53401991Sheppo vgen_handshake(vh_nextphase(ldcp)); 53411991Sheppo } 53421991Sheppo 53431991Sheppo break; 53441991Sheppo 53451991Sheppo case VIO_SUBTYPE_ACK: 53461991Sheppo 53471991Sheppo ldcp->hstate |= DRING_ACK_RCVD; 53481991Sheppo 53494647Sraghuram DBG2(vgenp, ldcp, "DRING_ACK_RCVD"); 53501991Sheppo 53511991Sheppo if (!(ldcp->local_hparams.dring_ready)) { 53521991Sheppo /* local dring is now ready */ 53531991Sheppo ldcp->local_hparams.dring_ready = B_TRUE; 53541991Sheppo 53551991Sheppo /* save dring_ident acked by peer */ 53561991Sheppo ldcp->local_hparams.dring_ident = 53574650Sraghuram msg->dring_ident; 53581991Sheppo } 53591991Sheppo 53601991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 53611991Sheppo vgen_handshake(vh_nextphase(ldcp)); 53621991Sheppo } 53631991Sheppo 53641991Sheppo break; 53651991Sheppo 53661991Sheppo case VIO_SUBTYPE_NACK: 53671991Sheppo 53684647Sraghuram DBG2(vgenp, ldcp, "DRING_NACK_RCVD"); 53692793Slm66018 return (VGEN_FAILURE); 53701991Sheppo } 53714647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 53722793Slm66018 return (VGEN_SUCCESS); 53731991Sheppo } 53741991Sheppo 53751991Sheppo /* 53761991Sheppo * Handle a rdx info msg from the peer or an ACK/NACK 53771991Sheppo * from the peer to a rdx info msg that we sent. 53781991Sheppo */ 53792793Slm66018 static int 53801991Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 53811991Sheppo { 53822793Slm66018 int rv = 0; 53834647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 53844647Sraghuram 53854647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 53861991Sheppo if (ldcp->hphase != VH_PHASE3) { 53874647Sraghuram DWARN(vgenp, ldcp, 53884647Sraghuram "Rcvd RDX_INFO Subtype (%d), Invalid Phase(%u)\n", 53894650Sraghuram tagp->vio_subtype, ldcp->hphase); 53902793Slm66018 return (VGEN_FAILURE); 53911991Sheppo } 53921991Sheppo switch (tagp->vio_subtype) { 53931991Sheppo case VIO_SUBTYPE_INFO: 53941991Sheppo 53954647Sraghuram DBG2(vgenp, ldcp, "RDX_INFO_RCVD \n"); 53961991Sheppo ldcp->hstate |= RDX_INFO_RCVD; 53971991Sheppo 53981991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 53991991Sheppo tagp->vio_sid = ldcp->local_sid; 54001991Sheppo /* send reply msg back to peer */ 54012793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vio_rdx_msg_t), 54022793Slm66018 B_FALSE); 54032793Slm66018 if (rv != VGEN_SUCCESS) { 54042793Slm66018 return (rv); 54051991Sheppo } 54061991Sheppo 54071991Sheppo ldcp->hstate |= RDX_ACK_SENT; 54084647Sraghuram DBG2(vgenp, ldcp, "RDX_ACK_SENT \n"); 54091991Sheppo 54101991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 54111991Sheppo vgen_handshake(vh_nextphase(ldcp)); 54121991Sheppo } 54131991Sheppo 54141991Sheppo break; 54151991Sheppo 54161991Sheppo case VIO_SUBTYPE_ACK: 54171991Sheppo 54181991Sheppo ldcp->hstate |= RDX_ACK_RCVD; 54191991Sheppo 54204647Sraghuram DBG2(vgenp, ldcp, "RDX_ACK_RCVD \n"); 54211991Sheppo 54221991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 54231991Sheppo vgen_handshake(vh_nextphase(ldcp)); 54241991Sheppo } 54251991Sheppo break; 54261991Sheppo 54271991Sheppo case VIO_SUBTYPE_NACK: 54281991Sheppo 54294647Sraghuram DBG2(vgenp, ldcp, "RDX_NACK_RCVD \n"); 54302793Slm66018 return (VGEN_FAILURE); 54311991Sheppo } 54324647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 54332793Slm66018 return (VGEN_SUCCESS); 54341991Sheppo } 54351991Sheppo 54361991Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */ 54372793Slm66018 static int 54381991Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 54391991Sheppo { 54401991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 54411991Sheppo vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp; 54421991Sheppo struct ether_addr *addrp; 54431991Sheppo int count; 54441991Sheppo int i; 54451991Sheppo 54464647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 54471991Sheppo switch (tagp->vio_subtype) { 54481991Sheppo 54491991Sheppo case VIO_SUBTYPE_INFO: 54501991Sheppo 54511991Sheppo /* vnet shouldn't recv set mcast msg, only vsw handles it */ 54524647Sraghuram DWARN(vgenp, ldcp, "rcvd SET_MCAST_INFO \n"); 54531991Sheppo break; 54541991Sheppo 54551991Sheppo case VIO_SUBTYPE_ACK: 54561991Sheppo 54571991Sheppo /* success adding/removing multicast addr */ 54584647Sraghuram DBG1(vgenp, ldcp, "rcvd SET_MCAST_ACK \n"); 54591991Sheppo break; 54601991Sheppo 54611991Sheppo case VIO_SUBTYPE_NACK: 54621991Sheppo 54634647Sraghuram DWARN(vgenp, ldcp, "rcvd SET_MCAST_NACK \n"); 54641991Sheppo if (!(msgp->set)) { 54651991Sheppo /* multicast remove request failed */ 54661991Sheppo break; 54671991Sheppo } 54681991Sheppo 54691991Sheppo /* multicast add request failed */ 54701991Sheppo for (count = 0; count < msgp->count; count++) { 54711991Sheppo addrp = &(msgp->mca[count]); 54721991Sheppo 54731991Sheppo /* delete address from the table */ 54741991Sheppo for (i = 0; i < vgenp->mccount; i++) { 54751991Sheppo if (ether_cmp(addrp, 54761991Sheppo &(vgenp->mctab[i])) == 0) { 54771991Sheppo if (vgenp->mccount > 1) { 54784647Sraghuram int t = vgenp->mccount - 1; 54791991Sheppo vgenp->mctab[i] = 54804650Sraghuram vgenp->mctab[t]; 54811991Sheppo } 54821991Sheppo vgenp->mccount--; 54831991Sheppo break; 54841991Sheppo } 54851991Sheppo } 54861991Sheppo } 54871991Sheppo break; 54881991Sheppo 54891991Sheppo } 54904647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 54912793Slm66018 54922793Slm66018 return (VGEN_SUCCESS); 54931991Sheppo } 54941991Sheppo 54951991Sheppo /* handler for control messages received from the peer ldc end-point */ 54962793Slm66018 static int 54971991Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 54981991Sheppo { 54992793Slm66018 int rv = 0; 55004647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 55014647Sraghuram 55024647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 55031991Sheppo switch (tagp->vio_subtype_env) { 55041991Sheppo 55051991Sheppo case VIO_VER_INFO: 55062793Slm66018 rv = vgen_handle_version_negotiate(ldcp, tagp); 55071991Sheppo break; 55081991Sheppo 55091991Sheppo case VIO_ATTR_INFO: 55102793Slm66018 rv = vgen_handle_attr_info(ldcp, tagp); 55111991Sheppo break; 55121991Sheppo 55131991Sheppo case VIO_DRING_REG: 55142793Slm66018 rv = vgen_handle_dring_reg(ldcp, tagp); 55151991Sheppo break; 55161991Sheppo 55171991Sheppo case VIO_RDX: 55182793Slm66018 rv = vgen_handle_rdx_info(ldcp, tagp); 55191991Sheppo break; 55201991Sheppo 55211991Sheppo case VNET_MCAST_INFO: 55222793Slm66018 rv = vgen_handle_mcast_info(ldcp, tagp); 55231991Sheppo break; 55241991Sheppo 55256495Sspeer case VIO_DDS_INFO: 55266495Sspeer rv = vgen_dds_rx(ldcp, tagp); 55276495Sspeer break; 55281991Sheppo } 55292793Slm66018 55304647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 55312793Slm66018 return (rv); 55321991Sheppo } 55331991Sheppo 55341991Sheppo /* handler for data messages received from the peer ldc end-point */ 55352793Slm66018 static int 55365935Ssb155480 vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t msglen) 55371991Sheppo { 55382793Slm66018 int rv = 0; 55394647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 55404647Sraghuram 55414647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 55421991Sheppo 55431991Sheppo if (ldcp->hphase != VH_DONE) 55442793Slm66018 return (rv); 55455935Ssb155480 55465935Ssb155480 if (tagp->vio_subtype == VIO_SUBTYPE_INFO) { 55475935Ssb155480 rv = vgen_check_datamsg_seq(ldcp, tagp); 55485935Ssb155480 if (rv != 0) { 55495935Ssb155480 return (rv); 55505935Ssb155480 } 55515935Ssb155480 } 55525935Ssb155480 55531991Sheppo switch (tagp->vio_subtype_env) { 55541991Sheppo case VIO_DRING_DATA: 55554647Sraghuram rv = vgen_handle_dring_data(ldcp, tagp); 55561991Sheppo break; 55575935Ssb155480 55585935Ssb155480 case VIO_PKT_DATA: 55595935Ssb155480 ldcp->rx_pktdata((void *)ldcp, (void *)tagp, msglen); 55605935Ssb155480 break; 55611991Sheppo default: 55621991Sheppo break; 55631991Sheppo } 55641991Sheppo 55654647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 55662793Slm66018 return (rv); 55671991Sheppo } 55681991Sheppo 55695935Ssb155480 /* 55705935Ssb155480 * dummy pkt data handler function for vnet protocol version 1.0 55715935Ssb155480 */ 55725935Ssb155480 static void 55735935Ssb155480 vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen) 55745935Ssb155480 { 55755935Ssb155480 _NOTE(ARGUNUSED(arg1, arg2, msglen)) 55765935Ssb155480 } 55775935Ssb155480 55785935Ssb155480 /* 55795935Ssb155480 * This function handles raw pkt data messages received over the channel. 55805935Ssb155480 * Currently, only priority-eth-type frames are received through this mechanism. 55815935Ssb155480 * In this case, the frame(data) is present within the message itself which 55825935Ssb155480 * is copied into an mblk before sending it up the stack. 55835935Ssb155480 */ 55845935Ssb155480 static void 55855935Ssb155480 vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen) 55865935Ssb155480 { 55875935Ssb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg1; 55885935Ssb155480 vio_raw_data_msg_t *pkt = (vio_raw_data_msg_t *)arg2; 55895935Ssb155480 uint32_t size; 55905935Ssb155480 mblk_t *mp; 55915935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 55925935Ssb155480 vgen_stats_t *statsp = &ldcp->stats; 55936419Ssb155480 vgen_hparams_t *lp = &ldcp->local_hparams; 55946495Sspeer vio_net_rx_cb_t vrx_cb; 55955935Ssb155480 55965935Ssb155480 ASSERT(MUTEX_HELD(&ldcp->cblock)); 55975935Ssb155480 55985935Ssb155480 mutex_exit(&ldcp->cblock); 55995935Ssb155480 56005935Ssb155480 size = msglen - VIO_PKT_DATA_HDRSIZE; 56016419Ssb155480 if (size < ETHERMIN || size > lp->mtu) { 56025935Ssb155480 (void) atomic_inc_32(&statsp->rx_pri_fail); 56035935Ssb155480 goto exit; 56045935Ssb155480 } 56055935Ssb155480 56065935Ssb155480 mp = vio_multipool_allocb(&ldcp->vmp, size); 56075935Ssb155480 if (mp == NULL) { 56085935Ssb155480 mp = allocb(size, BPRI_MED); 56095935Ssb155480 if (mp == NULL) { 56105935Ssb155480 (void) atomic_inc_32(&statsp->rx_pri_fail); 56115935Ssb155480 DWARN(vgenp, ldcp, "allocb failure, " 56125935Ssb155480 "unable to process priority frame\n"); 56135935Ssb155480 goto exit; 56145935Ssb155480 } 56155935Ssb155480 } 56165935Ssb155480 56175935Ssb155480 /* copy the frame from the payload of raw data msg into the mblk */ 56185935Ssb155480 bcopy(pkt->data, mp->b_rptr, size); 56195935Ssb155480 mp->b_wptr = mp->b_rptr + size; 56205935Ssb155480 56215935Ssb155480 /* update stats */ 56225935Ssb155480 (void) atomic_inc_64(&statsp->rx_pri_packets); 56235935Ssb155480 (void) atomic_add_64(&statsp->rx_pri_bytes, size); 56245935Ssb155480 56256495Sspeer /* send up; call vrx_cb() as cblock is already released */ 56266495Sspeer vrx_cb = ldcp->portp->vcb.vio_net_rx_cb; 56276495Sspeer vrx_cb(ldcp->portp->vhp, mp); 56285935Ssb155480 56295935Ssb155480 exit: 56305935Ssb155480 mutex_enter(&ldcp->cblock); 56315935Ssb155480 } 56325935Ssb155480 56332793Slm66018 static int 56342336Snarayan vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t start, 56352336Snarayan int32_t end, uint8_t pstate) 56362336Snarayan { 56374647Sraghuram int rv = 0; 56384647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 56392336Snarayan vio_dring_msg_t *msgp = (vio_dring_msg_t *)tagp; 56402336Snarayan 56412336Snarayan tagp->vio_subtype = VIO_SUBTYPE_ACK; 56422336Snarayan tagp->vio_sid = ldcp->local_sid; 56432336Snarayan msgp->start_idx = start; 56442336Snarayan msgp->end_idx = end; 56452336Snarayan msgp->dring_process_state = pstate; 56462793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), B_FALSE); 56472793Slm66018 if (rv != VGEN_SUCCESS) { 56484647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 56492336Snarayan } 56502793Slm66018 return (rv); 56512336Snarayan } 56522336Snarayan 56532793Slm66018 static int 56544647Sraghuram vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 56551991Sheppo { 56562793Slm66018 int rv = 0; 56574647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 56584647Sraghuram 56594647Sraghuram 56604647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 56611991Sheppo switch (tagp->vio_subtype) { 56621991Sheppo 56631991Sheppo case VIO_SUBTYPE_INFO: 56641991Sheppo /* 56654647Sraghuram * To reduce the locking contention, release the 56664647Sraghuram * cblock here and re-acquire it once we are done 56674647Sraghuram * receiving packets. 56681991Sheppo */ 56694647Sraghuram mutex_exit(&ldcp->cblock); 56704647Sraghuram mutex_enter(&ldcp->rxlock); 56714647Sraghuram rv = vgen_handle_dring_data_info(ldcp, tagp); 56724647Sraghuram mutex_exit(&ldcp->rxlock); 56734647Sraghuram mutex_enter(&ldcp->cblock); 56744647Sraghuram break; 56754647Sraghuram 56764647Sraghuram case VIO_SUBTYPE_ACK: 56774647Sraghuram rv = vgen_handle_dring_data_ack(ldcp, tagp); 56784647Sraghuram break; 56794647Sraghuram 56804647Sraghuram case VIO_SUBTYPE_NACK: 56814647Sraghuram rv = vgen_handle_dring_data_nack(ldcp, tagp); 56824647Sraghuram break; 56834647Sraghuram } 56844647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 56854647Sraghuram return (rv); 56864647Sraghuram } 56874647Sraghuram 56884647Sraghuram static int 56894647Sraghuram vgen_handle_dring_data_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 56904647Sraghuram { 56914647Sraghuram uint32_t start; 56924647Sraghuram int32_t end; 56934647Sraghuram int rv = 0; 56944647Sraghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp; 56954647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 56964647Sraghuram #ifdef VGEN_HANDLE_LOST_PKTS 56975373Sraghuram vgen_stats_t *statsp = &ldcp->stats; 56984647Sraghuram uint32_t rxi; 56994647Sraghuram int n; 57004647Sraghuram #endif 57014647Sraghuram 57024647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 57034647Sraghuram 57044647Sraghuram start = dringmsg->start_idx; 57054647Sraghuram end = dringmsg->end_idx; 57064647Sraghuram /* 57074647Sraghuram * received a data msg, which contains the start and end 57084647Sraghuram * indices of the descriptors within the rx ring holding data, 57094647Sraghuram * the seq_num of data packet corresponding to the start index, 57104647Sraghuram * and the dring_ident. 57114647Sraghuram * We can now read the contents of each of these descriptors 57124647Sraghuram * and gather data from it. 57134647Sraghuram */ 57144647Sraghuram DBG1(vgenp, ldcp, "INFO: start(%d), end(%d)\n", 57154650Sraghuram start, end); 57164647Sraghuram 57174647Sraghuram /* validate rx start and end indeces */ 57184647Sraghuram if (!(CHECK_RXI(start, ldcp)) || ((end != -1) && 57194647Sraghuram !(CHECK_RXI(end, ldcp)))) { 57204647Sraghuram DWARN(vgenp, ldcp, "Invalid Rx start(%d) or end(%d)\n", 57214647Sraghuram start, end); 57224647Sraghuram /* drop the message if invalid index */ 57234647Sraghuram return (rv); 57244647Sraghuram } 57254647Sraghuram 57264647Sraghuram /* validate dring_ident */ 57274647Sraghuram if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) { 57284647Sraghuram DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n", 57294647Sraghuram dringmsg->dring_ident); 57304647Sraghuram /* invalid dring_ident, drop the msg */ 57314647Sraghuram return (rv); 57324647Sraghuram } 57331991Sheppo #ifdef DEBUG 57344647Sraghuram if (vgen_trigger_rxlost) { 57354647Sraghuram /* drop this msg to simulate lost pkts for debugging */ 57364647Sraghuram vgen_trigger_rxlost = 0; 57374647Sraghuram return (rv); 57384647Sraghuram } 57391991Sheppo #endif 57401991Sheppo 57411991Sheppo #ifdef VGEN_HANDLE_LOST_PKTS 57421991Sheppo 57434647Sraghuram /* receive start index doesn't match expected index */ 57444647Sraghuram if (ldcp->next_rxi != start) { 57454647Sraghuram DWARN(vgenp, ldcp, "next_rxi(%d) != start(%d)\n", 57464647Sraghuram ldcp->next_rxi, start); 57474647Sraghuram 57484647Sraghuram /* calculate the number of pkts lost */ 57494647Sraghuram if (start >= ldcp->next_rxi) { 57504647Sraghuram n = start - ldcp->next_rxi; 57514647Sraghuram } else { 57524647Sraghuram n = ldcp->num_rxds - (ldcp->next_rxi - start); 57534647Sraghuram } 57544647Sraghuram 57555935Ssb155480 statsp->rx_lost_pkts += n; 57565935Ssb155480 tagp->vio_subtype = VIO_SUBTYPE_NACK; 57575935Ssb155480 tagp->vio_sid = ldcp->local_sid; 57585935Ssb155480 /* indicate the range of lost descriptors */ 57595935Ssb155480 dringmsg->start_idx = ldcp->next_rxi; 57605935Ssb155480 rxi = start; 57615935Ssb155480 DECR_RXI(rxi, ldcp); 57625935Ssb155480 dringmsg->end_idx = rxi; 57635935Ssb155480 /* dring ident is left unchanged */ 57645935Ssb155480 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, 57655935Ssb155480 sizeof (*dringmsg), B_FALSE); 57665935Ssb155480 if (rv != VGEN_SUCCESS) { 57675935Ssb155480 DWARN(vgenp, ldcp, 57685935Ssb155480 "vgen_sendmsg failed, stype:NACK\n"); 57694647Sraghuram return (rv); 57701991Sheppo } 57711991Sheppo /* 57725935Ssb155480 * treat this range of descrs/pkts as dropped 57735935Ssb155480 * and set the new expected value of next_rxi 57745935Ssb155480 * and continue(below) to process from the new 57755935Ssb155480 * start index. 57761991Sheppo */ 57775935Ssb155480 ldcp->next_rxi = start; 57784647Sraghuram } 57794647Sraghuram 57804647Sraghuram #endif /* VGEN_HANDLE_LOST_PKTS */ 57814647Sraghuram 57824647Sraghuram /* Now receive messages */ 57834647Sraghuram rv = vgen_process_dring_data(ldcp, tagp); 57844647Sraghuram 57854647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 57864647Sraghuram return (rv); 57874647Sraghuram } 57884647Sraghuram 57894647Sraghuram static int 57904647Sraghuram vgen_process_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 57914647Sraghuram { 57924647Sraghuram boolean_t set_ack_start = B_FALSE; 57934647Sraghuram uint32_t start; 57944647Sraghuram uint32_t ack_end; 57954647Sraghuram uint32_t next_rxi; 57964647Sraghuram uint32_t rxi; 57974647Sraghuram int count = 0; 57984647Sraghuram int rv = 0; 57994647Sraghuram uint32_t retries = 0; 58004647Sraghuram vgen_stats_t *statsp; 58016845Sha137994 vnet_public_desc_t rxd; 58024647Sraghuram vio_dring_entry_hdr_t *hdrp; 58034647Sraghuram mblk_t *bp = NULL; 58044647Sraghuram mblk_t *bpt = NULL; 58054647Sraghuram uint32_t ack_start; 58064647Sraghuram boolean_t rxd_err = B_FALSE; 58074647Sraghuram mblk_t *mp = NULL; 58084647Sraghuram size_t nbytes; 58094647Sraghuram boolean_t ack_needed = B_FALSE; 58104647Sraghuram size_t nread; 58114647Sraghuram uint64_t off = 0; 58124647Sraghuram struct ether_header *ehp; 58134647Sraghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp; 58144647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 58157529SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams; 58164647Sraghuram 58174647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 58184647Sraghuram 58195373Sraghuram statsp = &ldcp->stats; 58204647Sraghuram start = dringmsg->start_idx; 58214647Sraghuram 58224647Sraghuram /* 58234647Sraghuram * start processing the descriptors from the specified 58244647Sraghuram * start index, up to the index a descriptor is not ready 58254647Sraghuram * to be processed or we process the entire descriptor ring 58264647Sraghuram * and wrap around upto the start index. 58274647Sraghuram */ 58284647Sraghuram 58294647Sraghuram /* need to set the start index of descriptors to be ack'd */ 58304647Sraghuram set_ack_start = B_TRUE; 58314647Sraghuram 58324647Sraghuram /* index upto which we have ack'd */ 58334647Sraghuram ack_end = start; 58344647Sraghuram DECR_RXI(ack_end, ldcp); 58354647Sraghuram 58364647Sraghuram next_rxi = rxi = start; 58374647Sraghuram do { 58384647Sraghuram vgen_recv_retry: 58396845Sha137994 rv = vnet_dring_entry_copy(&(ldcp->rxdp[rxi]), &rxd, 58406845Sha137994 ldcp->dring_mtype, ldcp->rx_dhandle, rxi, rxi); 58414647Sraghuram if (rv != 0) { 58424647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_acquire() failed" 58434647Sraghuram " rv(%d)\n", rv); 58444647Sraghuram statsp->ierrors++; 58454647Sraghuram return (rv); 58464647Sraghuram } 58474647Sraghuram 58486845Sha137994 hdrp = &rxd.hdr; 58494647Sraghuram 58504647Sraghuram if (hdrp->dstate != VIO_DESC_READY) { 58514647Sraghuram /* 58525935Ssb155480 * Before waiting and retry here, send up 58535935Ssb155480 * the packets that are received already 58544647Sraghuram */ 58554647Sraghuram if (bp != NULL) { 58564647Sraghuram DTRACE_PROBE1(vgen_rcv_msgs, int, count); 58575935Ssb155480 vgen_rx(ldcp, bp); 58584647Sraghuram count = 0; 58594647Sraghuram bp = bpt = NULL; 58604647Sraghuram } 58614647Sraghuram /* 58624647Sraghuram * descriptor is not ready. 58634647Sraghuram * retry descriptor acquire, stop processing 58644647Sraghuram * after max # retries. 58654647Sraghuram */ 58664647Sraghuram if (retries == vgen_recv_retries) 58674647Sraghuram break; 58684647Sraghuram retries++; 58694647Sraghuram drv_usecwait(vgen_recv_delay); 58704647Sraghuram goto vgen_recv_retry; 58714647Sraghuram } 58724647Sraghuram retries = 0; 58734647Sraghuram 58744647Sraghuram if (set_ack_start) { 58754647Sraghuram /* 58764647Sraghuram * initialize the start index of the range 58774647Sraghuram * of descriptors to be ack'd. 58784647Sraghuram */ 58794647Sraghuram ack_start = rxi; 58804647Sraghuram set_ack_start = B_FALSE; 58814647Sraghuram } 58824647Sraghuram 58836845Sha137994 if ((rxd.nbytes < ETHERMIN) || 58847529SSriharsha.Basavapatna@Sun.COM (rxd.nbytes > lp->mtu) || 58856845Sha137994 (rxd.ncookies == 0) || 58866845Sha137994 (rxd.ncookies > MAX_COOKIES)) { 58874647Sraghuram rxd_err = B_TRUE; 58884647Sraghuram } else { 58894647Sraghuram /* 58904647Sraghuram * Try to allocate an mblk from the free pool 58914647Sraghuram * of recv mblks for the channel. 58924647Sraghuram * If this fails, use allocb(). 58934647Sraghuram */ 58946845Sha137994 nbytes = (VNET_IPALIGN + rxd.nbytes + 7) & ~7; 58957529SSriharsha.Basavapatna@Sun.COM if (nbytes > ldcp->max_rxpool_size) { 58966845Sha137994 mp = allocb(VNET_IPALIGN + rxd.nbytes + 8, 58974647Sraghuram BPRI_MED); 58987529SSriharsha.Basavapatna@Sun.COM } else { 58997529SSriharsha.Basavapatna@Sun.COM mp = vio_multipool_allocb(&ldcp->vmp, nbytes); 59007529SSriharsha.Basavapatna@Sun.COM if (mp == NULL) { 59017529SSriharsha.Basavapatna@Sun.COM statsp->rx_vio_allocb_fail++; 59027529SSriharsha.Basavapatna@Sun.COM /* 59037529SSriharsha.Basavapatna@Sun.COM * Data buffer returned by allocb(9F) 59047529SSriharsha.Basavapatna@Sun.COM * is 8byte aligned. We allocate extra 59057529SSriharsha.Basavapatna@Sun.COM * 8 bytes to ensure size is multiple 59067529SSriharsha.Basavapatna@Sun.COM * of 8 bytes for ldc_mem_copy(). 59077529SSriharsha.Basavapatna@Sun.COM */ 59087529SSriharsha.Basavapatna@Sun.COM mp = allocb(VNET_IPALIGN + 59097529SSriharsha.Basavapatna@Sun.COM rxd.nbytes + 8, BPRI_MED); 59107529SSriharsha.Basavapatna@Sun.COM } 59111991Sheppo } 59124647Sraghuram } 59134647Sraghuram if ((rxd_err) || (mp == NULL)) { 59144647Sraghuram /* 59154647Sraghuram * rxd_err or allocb() failure, 59164647Sraghuram * drop this packet, get next. 59174647Sraghuram */ 59184647Sraghuram if (rxd_err) { 59192793Slm66018 statsp->ierrors++; 59204647Sraghuram rxd_err = B_FALSE; 59214647Sraghuram } else { 59224647Sraghuram statsp->rx_allocb_fail++; 59232793Slm66018 } 59242793Slm66018 59252793Slm66018 ack_needed = hdrp->ack; 59264647Sraghuram 59274647Sraghuram /* set descriptor done bit */ 59286845Sha137994 rv = vnet_dring_entry_set_dstate(&(ldcp->rxdp[rxi]), 59296845Sha137994 ldcp->dring_mtype, ldcp->rx_dhandle, rxi, rxi, 59306845Sha137994 VIO_DESC_DONE); 59312793Slm66018 if (rv != 0) { 59324647Sraghuram DWARN(vgenp, ldcp, 59336845Sha137994 "vnet_dring_entry_set_dstate err rv(%d)\n", 59346845Sha137994 rv); 59354647Sraghuram return (rv); 59362793Slm66018 } 59372336Snarayan 59382793Slm66018 if (ack_needed) { 59392793Slm66018 ack_needed = B_FALSE; 59401991Sheppo /* 59412336Snarayan * sender needs ack for this packet, 59422336Snarayan * ack pkts upto this index. 59431991Sheppo */ 59442336Snarayan ack_end = rxi; 59452336Snarayan 59462793Slm66018 rv = vgen_send_dring_ack(ldcp, tagp, 59474647Sraghuram ack_start, ack_end, 59484647Sraghuram VIO_DP_ACTIVE); 59492793Slm66018 if (rv != VGEN_SUCCESS) { 59502793Slm66018 goto error_ret; 59512793Slm66018 } 59522336Snarayan 59532336Snarayan /* need to set new ack start index */ 59542336Snarayan set_ack_start = B_TRUE; 59551991Sheppo } 59564647Sraghuram goto vgen_next_rxi; 59574647Sraghuram } 59584647Sraghuram 59594647Sraghuram nread = nbytes; 59604647Sraghuram rv = ldc_mem_copy(ldcp->ldc_handle, 59614647Sraghuram (caddr_t)mp->b_rptr, off, &nread, 59626845Sha137994 rxd.memcookie, rxd.ncookies, LDC_COPY_IN); 59634647Sraghuram 59644647Sraghuram /* if ldc_mem_copy() failed */ 59654647Sraghuram if (rv) { 59664647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_copy err rv(%d)\n", rv); 59674647Sraghuram statsp->ierrors++; 59684647Sraghuram freemsg(mp); 59694647Sraghuram goto error_ret; 59704647Sraghuram } 59714647Sraghuram 59724647Sraghuram ack_needed = hdrp->ack; 59736845Sha137994 59746845Sha137994 rv = vnet_dring_entry_set_dstate(&(ldcp->rxdp[rxi]), 59756845Sha137994 ldcp->dring_mtype, ldcp->rx_dhandle, rxi, rxi, 59766845Sha137994 VIO_DESC_DONE); 59774647Sraghuram if (rv != 0) { 59784647Sraghuram DWARN(vgenp, ldcp, 59796845Sha137994 "vnet_dring_entry_set_dstate err rv(%d)\n", rv); 59804647Sraghuram goto error_ret; 59814647Sraghuram } 59824647Sraghuram 59834647Sraghuram mp->b_rptr += VNET_IPALIGN; 59844647Sraghuram 59854647Sraghuram if (ack_needed) { 59864647Sraghuram ack_needed = B_FALSE; 59874647Sraghuram /* 59884647Sraghuram * sender needs ack for this packet, 59894647Sraghuram * ack pkts upto this index. 59904647Sraghuram */ 59914647Sraghuram ack_end = rxi; 59924647Sraghuram 59934647Sraghuram rv = vgen_send_dring_ack(ldcp, tagp, 59944647Sraghuram ack_start, ack_end, VIO_DP_ACTIVE); 59954647Sraghuram if (rv != VGEN_SUCCESS) { 59964647Sraghuram goto error_ret; 59971991Sheppo } 59981991Sheppo 59994647Sraghuram /* need to set new ack start index */ 60004647Sraghuram set_ack_start = B_TRUE; 60014647Sraghuram } 60024647Sraghuram 60034647Sraghuram if (nread != nbytes) { 60044647Sraghuram DWARN(vgenp, ldcp, 60054647Sraghuram "ldc_mem_copy nread(%lx), nbytes(%lx)\n", 60064647Sraghuram nread, nbytes); 60074647Sraghuram statsp->ierrors++; 60084647Sraghuram freemsg(mp); 60094647Sraghuram goto vgen_next_rxi; 60104647Sraghuram } 60114647Sraghuram 60124647Sraghuram /* point to the actual end of data */ 60136845Sha137994 mp->b_wptr = mp->b_rptr + rxd.nbytes; 60144647Sraghuram 60154647Sraghuram /* update stats */ 60164647Sraghuram statsp->ipackets++; 60176845Sha137994 statsp->rbytes += rxd.nbytes; 60184647Sraghuram ehp = (struct ether_header *)mp->b_rptr; 60194647Sraghuram if (IS_BROADCAST(ehp)) 60204647Sraghuram statsp->brdcstrcv++; 60214647Sraghuram else if (IS_MULTICAST(ehp)) 60224647Sraghuram statsp->multircv++; 60234647Sraghuram 60244647Sraghuram /* build a chain of received packets */ 60254647Sraghuram if (bp == NULL) { 60264647Sraghuram /* first pkt */ 60274647Sraghuram bp = mp; 60284647Sraghuram bpt = bp; 60294647Sraghuram bpt->b_next = NULL; 60304647Sraghuram } else { 60314647Sraghuram mp->b_next = NULL; 60324647Sraghuram bpt->b_next = mp; 60334647Sraghuram bpt = mp; 60344647Sraghuram } 60354647Sraghuram 60364647Sraghuram if (count++ > vgen_chain_len) { 60374647Sraghuram DTRACE_PROBE1(vgen_rcv_msgs, int, count); 60385935Ssb155480 vgen_rx(ldcp, bp); 60394647Sraghuram count = 0; 60404647Sraghuram bp = bpt = NULL; 60414647Sraghuram } 60422336Snarayan 60432336Snarayan vgen_next_rxi: 60444647Sraghuram /* update end index of range of descrs to be ack'd */ 60454647Sraghuram ack_end = rxi; 60464647Sraghuram 60474647Sraghuram /* update the next index to be processed */ 60484647Sraghuram INCR_RXI(next_rxi, ldcp); 60494647Sraghuram if (next_rxi == start) { 60502336Snarayan /* 60514647Sraghuram * processed the entire descriptor ring upto 60524647Sraghuram * the index at which we started. 60532336Snarayan */ 60542336Snarayan break; 60552336Snarayan } 60562336Snarayan 60574647Sraghuram rxi = next_rxi; 60584647Sraghuram 60594647Sraghuram _NOTE(CONSTCOND) 60604647Sraghuram } while (1); 60614647Sraghuram 60624647Sraghuram /* 60634647Sraghuram * send an ack message to peer indicating that we have stopped 60644647Sraghuram * processing descriptors. 60654647Sraghuram */ 60664647Sraghuram if (set_ack_start) { 60672336Snarayan /* 60684647Sraghuram * We have ack'd upto some index and we have not 60694647Sraghuram * processed any descriptors beyond that index. 60704647Sraghuram * Use the last ack'd index as both the start and 60714647Sraghuram * end of range of descrs being ack'd. 60724647Sraghuram * Note: This results in acking the last index twice 60734647Sraghuram * and should be harmless. 60742336Snarayan */ 60754647Sraghuram ack_start = ack_end; 60764647Sraghuram } 60774647Sraghuram 60784647Sraghuram rv = vgen_send_dring_ack(ldcp, tagp, ack_start, ack_end, 60794647Sraghuram VIO_DP_STOPPED); 60804647Sraghuram if (rv != VGEN_SUCCESS) { 60814647Sraghuram goto error_ret; 60824647Sraghuram } 60834647Sraghuram 60845935Ssb155480 /* save new recv index of next dring msg */ 60854647Sraghuram ldcp->next_rxi = next_rxi; 60864647Sraghuram 60874647Sraghuram error_ret: 60885935Ssb155480 /* send up packets received so far */ 60894647Sraghuram if (bp != NULL) { 60904647Sraghuram DTRACE_PROBE1(vgen_rcv_msgs, int, count); 60915935Ssb155480 vgen_rx(ldcp, bp); 60924647Sraghuram bp = bpt = NULL; 60934647Sraghuram } 60944647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 60954647Sraghuram return (rv); 60964647Sraghuram 60974647Sraghuram } 60984647Sraghuram 60994647Sraghuram static int 61004647Sraghuram vgen_handle_dring_data_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 61014647Sraghuram { 61024647Sraghuram int rv = 0; 61034647Sraghuram uint32_t start; 61044647Sraghuram int32_t end; 61054647Sraghuram uint32_t txi; 61064647Sraghuram boolean_t ready_txd = B_FALSE; 61074647Sraghuram vgen_stats_t *statsp; 61084647Sraghuram vgen_private_desc_t *tbufp; 61094647Sraghuram vnet_public_desc_t *txdp; 61104647Sraghuram vio_dring_entry_hdr_t *hdrp; 61114647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 61124647Sraghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp; 61134647Sraghuram 61144647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 61154647Sraghuram start = dringmsg->start_idx; 61164647Sraghuram end = dringmsg->end_idx; 61175373Sraghuram statsp = &ldcp->stats; 61184647Sraghuram 61194647Sraghuram /* 61204647Sraghuram * received an ack corresponding to a specific descriptor for 61214647Sraghuram * which we had set the ACK bit in the descriptor (during 61224647Sraghuram * transmit). This enables us to reclaim descriptors. 61234647Sraghuram */ 61244647Sraghuram 61254647Sraghuram DBG2(vgenp, ldcp, "ACK: start(%d), end(%d)\n", start, end); 61264647Sraghuram 61274647Sraghuram /* validate start and end indeces in the tx ack msg */ 61284647Sraghuram if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) { 61294647Sraghuram /* drop the message if invalid index */ 61304647Sraghuram DWARN(vgenp, ldcp, "Invalid Tx ack start(%d) or end(%d)\n", 61314647Sraghuram start, end); 61324647Sraghuram return (rv); 61334647Sraghuram } 61344647Sraghuram /* validate dring_ident */ 61354647Sraghuram if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) { 61364647Sraghuram /* invalid dring_ident, drop the msg */ 61374647Sraghuram DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n", 61384647Sraghuram dringmsg->dring_ident); 61394647Sraghuram return (rv); 61404647Sraghuram } 61414647Sraghuram statsp->dring_data_acks++; 61424647Sraghuram 61434647Sraghuram /* reclaim descriptors that are done */ 61444647Sraghuram vgen_reclaim(ldcp); 61454647Sraghuram 61464647Sraghuram if (dringmsg->dring_process_state != VIO_DP_STOPPED) { 61472336Snarayan /* 61484647Sraghuram * receiver continued processing descriptors after 61494647Sraghuram * sending us the ack. 61502336Snarayan */ 61514647Sraghuram return (rv); 61524647Sraghuram } 61534647Sraghuram 61544647Sraghuram statsp->dring_stopped_acks++; 61554647Sraghuram 61564647Sraghuram /* receiver stopped processing descriptors */ 61574647Sraghuram mutex_enter(&ldcp->wrlock); 61584647Sraghuram mutex_enter(&ldcp->tclock); 61594647Sraghuram 61604647Sraghuram /* 61614647Sraghuram * determine if there are any pending tx descriptors 61624647Sraghuram * ready to be processed by the receiver(peer) and if so, 61634647Sraghuram * send a message to the peer to restart receiving. 61644647Sraghuram */ 61654647Sraghuram ready_txd = B_FALSE; 61664647Sraghuram 61674647Sraghuram /* 61684647Sraghuram * using the end index of the descriptor range for which 61694647Sraghuram * we received the ack, check if the next descriptor is 61704647Sraghuram * ready. 61714647Sraghuram */ 61724647Sraghuram txi = end; 61734647Sraghuram INCR_TXI(txi, ldcp); 61744647Sraghuram tbufp = &ldcp->tbufp[txi]; 61754647Sraghuram txdp = tbufp->descp; 61764647Sraghuram hdrp = &txdp->hdr; 61774647Sraghuram if (hdrp->dstate == VIO_DESC_READY) { 61784647Sraghuram ready_txd = B_TRUE; 61794647Sraghuram } else { 61804647Sraghuram /* 61814647Sraghuram * descr next to the end of ack'd descr range is not 61824647Sraghuram * ready. 61834647Sraghuram * starting from the current reclaim index, check 61844647Sraghuram * if any descriptor is ready. 61854647Sraghuram */ 61864647Sraghuram 61874647Sraghuram txi = ldcp->cur_tbufp - ldcp->tbufp; 61882336Snarayan tbufp = &ldcp->tbufp[txi]; 61894647Sraghuram 61902336Snarayan txdp = tbufp->descp; 61912336Snarayan hdrp = &txdp->hdr; 61922336Snarayan if (hdrp->dstate == VIO_DESC_READY) { 61932336Snarayan ready_txd = B_TRUE; 61944647Sraghuram } 61954647Sraghuram 61964647Sraghuram } 61974647Sraghuram 61984647Sraghuram if (ready_txd) { 61994647Sraghuram /* 62004647Sraghuram * we have tx descriptor(s) ready to be 62014647Sraghuram * processed by the receiver. 62024647Sraghuram * send a message to the peer with the start index 62034647Sraghuram * of ready descriptors. 62044647Sraghuram */ 62054647Sraghuram rv = vgen_send_dring_data(ldcp, txi, -1); 62064647Sraghuram if (rv != VGEN_SUCCESS) { 62074647Sraghuram ldcp->resched_peer = B_TRUE; 62084647Sraghuram ldcp->resched_peer_txi = txi; 62094647Sraghuram mutex_exit(&ldcp->tclock); 62104647Sraghuram mutex_exit(&ldcp->wrlock); 62114647Sraghuram return (rv); 62122336Snarayan } 62134647Sraghuram } else { 62144647Sraghuram /* 62154647Sraghuram * no ready tx descriptors. set the flag to send a 62164647Sraghuram * message to peer when tx descriptors are ready in 62174647Sraghuram * transmit routine. 62184647Sraghuram */ 62194647Sraghuram ldcp->resched_peer = B_TRUE; 62204647Sraghuram ldcp->resched_peer_txi = ldcp->cur_tbufp - ldcp->tbufp; 62214647Sraghuram } 62224647Sraghuram 62234647Sraghuram mutex_exit(&ldcp->tclock); 62244647Sraghuram mutex_exit(&ldcp->wrlock); 62254647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 62264647Sraghuram return (rv); 62274647Sraghuram } 62284647Sraghuram 62294647Sraghuram static int 62304647Sraghuram vgen_handle_dring_data_nack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 62314647Sraghuram { 62324647Sraghuram int rv = 0; 62334647Sraghuram uint32_t start; 62344647Sraghuram int32_t end; 62354647Sraghuram uint32_t txi; 62364647Sraghuram vnet_public_desc_t *txdp; 62374647Sraghuram vio_dring_entry_hdr_t *hdrp; 62384647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 62394647Sraghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp; 62404647Sraghuram 62414647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 62424647Sraghuram start = dringmsg->start_idx; 62434647Sraghuram end = dringmsg->end_idx; 62444647Sraghuram 62454647Sraghuram /* 62464647Sraghuram * peer sent a NACK msg to indicate lost packets. 62474647Sraghuram * The start and end correspond to the range of descriptors 62484647Sraghuram * for which the peer didn't receive a dring data msg and so 62494647Sraghuram * didn't receive the corresponding data. 62504647Sraghuram */ 62514647Sraghuram DWARN(vgenp, ldcp, "NACK: start(%d), end(%d)\n", start, end); 62524647Sraghuram 62534647Sraghuram /* validate start and end indeces in the tx nack msg */ 62544647Sraghuram if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) { 62554647Sraghuram /* drop the message if invalid index */ 62564647Sraghuram DWARN(vgenp, ldcp, "Invalid Tx nack start(%d) or end(%d)\n", 62574647Sraghuram start, end); 62584647Sraghuram return (rv); 62594647Sraghuram } 62604647Sraghuram /* validate dring_ident */ 62614647Sraghuram if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) { 62624647Sraghuram /* invalid dring_ident, drop the msg */ 62634647Sraghuram DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n", 62644647Sraghuram dringmsg->dring_ident); 62654647Sraghuram return (rv); 62664647Sraghuram } 62674647Sraghuram mutex_enter(&ldcp->txlock); 62684647Sraghuram mutex_enter(&ldcp->tclock); 62694647Sraghuram 62704647Sraghuram if (ldcp->next_tbufp == ldcp->cur_tbufp) { 62714647Sraghuram /* no busy descriptors, bogus nack ? */ 62722336Snarayan mutex_exit(&ldcp->tclock); 62732336Snarayan mutex_exit(&ldcp->txlock); 62744647Sraghuram return (rv); 62754647Sraghuram } 62761991Sheppo 62774647Sraghuram /* we just mark the descrs as done so they can be reclaimed */ 62784647Sraghuram for (txi = start; txi <= end; ) { 62794647Sraghuram txdp = &(ldcp->txdp[txi]); 62804647Sraghuram hdrp = &txdp->hdr; 62814647Sraghuram if (hdrp->dstate == VIO_DESC_READY) 62824647Sraghuram hdrp->dstate = VIO_DESC_DONE; 62834647Sraghuram INCR_TXI(txi, ldcp); 62844647Sraghuram } 62854647Sraghuram mutex_exit(&ldcp->tclock); 62864647Sraghuram mutex_exit(&ldcp->txlock); 62874647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 62882793Slm66018 return (rv); 62891991Sheppo } 62901991Sheppo 62911991Sheppo static void 62921991Sheppo vgen_reclaim(vgen_ldc_t *ldcp) 62931991Sheppo { 62942336Snarayan mutex_enter(&ldcp->tclock); 62952336Snarayan 62961991Sheppo vgen_reclaim_dring(ldcp); 62971991Sheppo ldcp->reclaim_lbolt = ddi_get_lbolt(); 62982336Snarayan 62991991Sheppo mutex_exit(&ldcp->tclock); 63001991Sheppo } 63011991Sheppo 63021991Sheppo /* 63031991Sheppo * transmit reclaim function. starting from the current reclaim index 63041991Sheppo * look for descriptors marked DONE and reclaim the descriptor and the 63051991Sheppo * corresponding buffers (tbuf). 63061991Sheppo */ 63071991Sheppo static void 63081991Sheppo vgen_reclaim_dring(vgen_ldc_t *ldcp) 63091991Sheppo { 63105022Sraghuram int count = 0; 63111991Sheppo vnet_public_desc_t *txdp; 63121991Sheppo vgen_private_desc_t *tbufp; 63131991Sheppo vio_dring_entry_hdr_t *hdrp; 63141991Sheppo 63151991Sheppo #ifdef DEBUG 63161991Sheppo if (vgen_trigger_txtimeout) 63171991Sheppo return; 63181991Sheppo #endif 63191991Sheppo 63201991Sheppo tbufp = ldcp->cur_tbufp; 63211991Sheppo txdp = tbufp->descp; 63221991Sheppo hdrp = &txdp->hdr; 63231991Sheppo 63241991Sheppo while ((hdrp->dstate == VIO_DESC_DONE) && 63251991Sheppo (tbufp != ldcp->next_tbufp)) { 63261991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 63271991Sheppo hdrp->dstate = VIO_DESC_FREE; 63281991Sheppo hdrp->ack = B_FALSE; 63291991Sheppo 63301991Sheppo tbufp = NEXTTBUF(ldcp, tbufp); 63311991Sheppo txdp = tbufp->descp; 63321991Sheppo hdrp = &txdp->hdr; 63335022Sraghuram count++; 63341991Sheppo } 63351991Sheppo 63361991Sheppo ldcp->cur_tbufp = tbufp; 63371991Sheppo 63381991Sheppo /* 63391991Sheppo * Check if mac layer should be notified to restart transmissions 63401991Sheppo */ 63415022Sraghuram if ((ldcp->need_resched) && (count > 0)) { 63426495Sspeer vio_net_tx_update_t vtx_update = 63436495Sspeer ldcp->portp->vcb.vio_net_tx_update; 63446495Sspeer 63451991Sheppo ldcp->need_resched = B_FALSE; 63466495Sspeer vtx_update(ldcp->portp->vhp); 63471991Sheppo } 63481991Sheppo } 63491991Sheppo 63501991Sheppo /* return the number of pending transmits for the channel */ 63511991Sheppo static int 63521991Sheppo vgen_num_txpending(vgen_ldc_t *ldcp) 63531991Sheppo { 63541991Sheppo int n; 63551991Sheppo 63561991Sheppo if (ldcp->next_tbufp >= ldcp->cur_tbufp) { 63571991Sheppo n = ldcp->next_tbufp - ldcp->cur_tbufp; 63581991Sheppo } else { 63591991Sheppo /* cur_tbufp > next_tbufp */ 63601991Sheppo n = ldcp->num_txds - (ldcp->cur_tbufp - ldcp->next_tbufp); 63611991Sheppo } 63621991Sheppo 63631991Sheppo return (n); 63641991Sheppo } 63651991Sheppo 63661991Sheppo /* determine if the transmit descriptor ring is full */ 63671991Sheppo static int 63681991Sheppo vgen_tx_dring_full(vgen_ldc_t *ldcp) 63691991Sheppo { 63701991Sheppo vgen_private_desc_t *tbufp; 63711991Sheppo vgen_private_desc_t *ntbufp; 63721991Sheppo 63731991Sheppo tbufp = ldcp->next_tbufp; 63741991Sheppo ntbufp = NEXTTBUF(ldcp, tbufp); 63751991Sheppo if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */ 63761991Sheppo return (VGEN_SUCCESS); 63771991Sheppo } 63781991Sheppo return (VGEN_FAILURE); 63791991Sheppo } 63801991Sheppo 63811991Sheppo /* determine if timeout condition has occured */ 63821991Sheppo static int 63831991Sheppo vgen_ldc_txtimeout(vgen_ldc_t *ldcp) 63841991Sheppo { 63851991Sheppo if (((ddi_get_lbolt() - ldcp->reclaim_lbolt) > 63864650Sraghuram drv_usectohz(vnet_ldcwd_txtimeout * 1000)) && 63874650Sraghuram (vnet_ldcwd_txtimeout) && 63884650Sraghuram (vgen_tx_dring_full(ldcp) == VGEN_SUCCESS)) { 63891991Sheppo return (VGEN_SUCCESS); 63901991Sheppo } else { 63911991Sheppo return (VGEN_FAILURE); 63921991Sheppo } 63931991Sheppo } 63941991Sheppo 63951991Sheppo /* transmit watchdog timeout handler */ 63961991Sheppo static void 63971991Sheppo vgen_ldc_watchdog(void *arg) 63981991Sheppo { 63991991Sheppo vgen_ldc_t *ldcp; 64002336Snarayan vgen_t *vgenp; 64011991Sheppo int rv; 64021991Sheppo 64031991Sheppo ldcp = (vgen_ldc_t *)arg; 64042336Snarayan vgenp = LDC_TO_VGEN(ldcp); 64051991Sheppo 64061991Sheppo rv = vgen_ldc_txtimeout(ldcp); 64071991Sheppo if (rv == VGEN_SUCCESS) { 64084647Sraghuram DWARN(vgenp, ldcp, "transmit timeout\n"); 64091991Sheppo #ifdef DEBUG 64101991Sheppo if (vgen_trigger_txtimeout) { 64111991Sheppo /* tx timeout triggered for debugging */ 64121991Sheppo vgen_trigger_txtimeout = 0; 64131991Sheppo } 64141991Sheppo #endif 64151991Sheppo mutex_enter(&ldcp->cblock); 64162793Slm66018 ldcp->need_ldc_reset = B_TRUE; 64173653Snarayan vgen_handshake_retry(ldcp); 64181991Sheppo mutex_exit(&ldcp->cblock); 64191991Sheppo if (ldcp->need_resched) { 64206495Sspeer vio_net_tx_update_t vtx_update = 64216495Sspeer ldcp->portp->vcb.vio_net_tx_update; 64226495Sspeer 64231991Sheppo ldcp->need_resched = B_FALSE; 64246495Sspeer vtx_update(ldcp->portp->vhp); 64251991Sheppo } 64261991Sheppo } 64271991Sheppo 64281991Sheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp, 64291991Sheppo drv_usectohz(vnet_ldcwd_interval * 1000)); 64301991Sheppo } 64311991Sheppo 64321991Sheppo /* handler for error messages received from the peer ldc end-point */ 64331991Sheppo static void 64341991Sheppo vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 64351991Sheppo { 64361991Sheppo _NOTE(ARGUNUSED(ldcp, tagp)) 64371991Sheppo } 64381991Sheppo 64395935Ssb155480 static int 64405935Ssb155480 vgen_check_datamsg_seq(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 64415935Ssb155480 { 64425935Ssb155480 vio_raw_data_msg_t *rmsg; 64435935Ssb155480 vio_dring_msg_t *dmsg; 64445935Ssb155480 uint64_t seq_num; 64455935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 64465935Ssb155480 64475935Ssb155480 if (tagp->vio_subtype_env == VIO_DRING_DATA) { 64485935Ssb155480 dmsg = (vio_dring_msg_t *)tagp; 64495935Ssb155480 seq_num = dmsg->seq_num; 64505935Ssb155480 } else if (tagp->vio_subtype_env == VIO_PKT_DATA) { 64515935Ssb155480 rmsg = (vio_raw_data_msg_t *)tagp; 64525935Ssb155480 seq_num = rmsg->seq_num; 64535935Ssb155480 } else { 64545935Ssb155480 return (EINVAL); 64555935Ssb155480 } 64565935Ssb155480 64575935Ssb155480 if (seq_num != ldcp->next_rxseq) { 64585935Ssb155480 64595935Ssb155480 /* seqnums don't match */ 64605935Ssb155480 DWARN(vgenp, ldcp, 64615935Ssb155480 "next_rxseq(0x%lx) != seq_num(0x%lx)\n", 64625935Ssb155480 ldcp->next_rxseq, seq_num); 64635935Ssb155480 64645935Ssb155480 ldcp->need_ldc_reset = B_TRUE; 64655935Ssb155480 return (EINVAL); 64665935Ssb155480 64675935Ssb155480 } 64685935Ssb155480 64695935Ssb155480 ldcp->next_rxseq++; 64705935Ssb155480 64715935Ssb155480 return (0); 64725935Ssb155480 } 64735935Ssb155480 64741991Sheppo /* Check if the session id in the received message is valid */ 64751991Sheppo static int 64761991Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 64771991Sheppo { 64784647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 64794647Sraghuram 64801991Sheppo if (tagp->vio_sid != ldcp->peer_sid) { 64814647Sraghuram DWARN(vgenp, ldcp, "sid mismatch: expected(%x), rcvd(%x)\n", 64824647Sraghuram ldcp->peer_sid, tagp->vio_sid); 64831991Sheppo return (VGEN_FAILURE); 64841991Sheppo } 64851991Sheppo else 64861991Sheppo return (VGEN_SUCCESS); 64871991Sheppo } 64881991Sheppo 64891991Sheppo static caddr_t 64901991Sheppo vgen_print_ethaddr(uint8_t *a, char *ebuf) 64911991Sheppo { 64921991Sheppo (void) sprintf(ebuf, 64934650Sraghuram "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); 64941991Sheppo return (ebuf); 64951991Sheppo } 64961991Sheppo 64971991Sheppo /* Handshake watchdog timeout handler */ 64981991Sheppo static void 64991991Sheppo vgen_hwatchdog(void *arg) 65001991Sheppo { 65011991Sheppo vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 65024647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 65034647Sraghuram 65044647Sraghuram DWARN(vgenp, ldcp, 65054647Sraghuram "handshake timeout ldc(%lx) phase(%x) state(%x)\n", 65064647Sraghuram ldcp->hphase, ldcp->hstate); 65071991Sheppo 65081991Sheppo mutex_enter(&ldcp->cblock); 65093653Snarayan if (ldcp->cancel_htid) { 65103653Snarayan ldcp->cancel_htid = 0; 65113653Snarayan mutex_exit(&ldcp->cblock); 65123653Snarayan return; 65133653Snarayan } 65141991Sheppo ldcp->htid = 0; 65152841Snarayan ldcp->need_ldc_reset = B_TRUE; 65161991Sheppo vgen_handshake_retry(ldcp); 65171991Sheppo mutex_exit(&ldcp->cblock); 65181991Sheppo } 65191991Sheppo 65201991Sheppo static void 65211991Sheppo vgen_print_hparams(vgen_hparams_t *hp) 65221991Sheppo { 65231991Sheppo uint8_t addr[6]; 65241991Sheppo char ea[6]; 65251991Sheppo ldc_mem_cookie_t *dc; 65261991Sheppo 65271991Sheppo cmn_err(CE_CONT, "version_info:\n"); 65281991Sheppo cmn_err(CE_CONT, 65291991Sheppo "\tver_major: %d, ver_minor: %d, dev_class: %d\n", 65301991Sheppo hp->ver_major, hp->ver_minor, hp->dev_class); 65311991Sheppo 65325462Swentaoy vnet_macaddr_ultostr(hp->addr, addr); 65331991Sheppo cmn_err(CE_CONT, "attr_info:\n"); 65341991Sheppo cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu, 65351991Sheppo vgen_print_ethaddr(addr, ea)); 65361991Sheppo cmn_err(CE_CONT, 65371991Sheppo "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n", 65381991Sheppo hp->addr_type, hp->xfer_mode, hp->ack_freq); 65391991Sheppo 65401991Sheppo dc = &hp->dring_cookie; 65411991Sheppo cmn_err(CE_CONT, "dring_info:\n"); 65421991Sheppo cmn_err(CE_CONT, 65431991Sheppo "\tlength: %d, dsize: %d\n", hp->num_desc, hp->desc_size); 65441991Sheppo cmn_err(CE_CONT, 65451991Sheppo "\tldc_addr: 0x%lx, ldc_size: %ld\n", 65461991Sheppo dc->addr, dc->size); 65471991Sheppo cmn_err(CE_CONT, "\tdring_ident: 0x%lx\n", hp->dring_ident); 65481991Sheppo } 65491991Sheppo 65501991Sheppo static void 65511991Sheppo vgen_print_ldcinfo(vgen_ldc_t *ldcp) 65521991Sheppo { 65531991Sheppo vgen_hparams_t *hp; 65541991Sheppo 65551991Sheppo cmn_err(CE_CONT, "Channel Information:\n"); 65561991Sheppo cmn_err(CE_CONT, 65571991Sheppo "\tldc_id: 0x%lx, ldc_status: 0x%x\n", 65581991Sheppo ldcp->ldc_id, ldcp->ldc_status); 65591991Sheppo cmn_err(CE_CONT, 65601991Sheppo "\tlocal_sid: 0x%x, peer_sid: 0x%x\n", 65611991Sheppo ldcp->local_sid, ldcp->peer_sid); 65621991Sheppo cmn_err(CE_CONT, 65631991Sheppo "\thphase: 0x%x, hstate: 0x%x\n", 65641991Sheppo ldcp->hphase, ldcp->hstate); 65651991Sheppo 65661991Sheppo cmn_err(CE_CONT, "Local handshake params:\n"); 65671991Sheppo hp = &ldcp->local_hparams; 65681991Sheppo vgen_print_hparams(hp); 65691991Sheppo 65701991Sheppo cmn_err(CE_CONT, "Peer handshake params:\n"); 65711991Sheppo hp = &ldcp->peer_hparams; 65721991Sheppo vgen_print_hparams(hp); 65731991Sheppo } 65744647Sraghuram 65754647Sraghuram /* 65765935Ssb155480 * Send received packets up the stack. 65774647Sraghuram */ 65784647Sraghuram static void 65795935Ssb155480 vgen_rx(vgen_ldc_t *ldcp, mblk_t *bp) 65804647Sraghuram { 65816495Sspeer vio_net_rx_cb_t vrx_cb = ldcp->portp->vcb.vio_net_rx_cb; 65824647Sraghuram 65834647Sraghuram if (ldcp->rcv_thread != NULL) { 65845935Ssb155480 ASSERT(MUTEX_HELD(&ldcp->rxlock)); 65855935Ssb155480 mutex_exit(&ldcp->rxlock); 65864647Sraghuram } else { 65875935Ssb155480 ASSERT(MUTEX_HELD(&ldcp->cblock)); 65885935Ssb155480 mutex_exit(&ldcp->cblock); 65895935Ssb155480 } 65905935Ssb155480 65916495Sspeer vrx_cb(ldcp->portp->vhp, bp); 65925935Ssb155480 65934647Sraghuram if (ldcp->rcv_thread != NULL) { 65945935Ssb155480 mutex_enter(&ldcp->rxlock); 65955935Ssb155480 } else { 65965935Ssb155480 mutex_enter(&ldcp->cblock); 65975935Ssb155480 } 65984647Sraghuram } 65994647Sraghuram 66004647Sraghuram /* 66014647Sraghuram * vgen_ldc_rcv_worker -- A per LDC worker thread to receive data. 66024647Sraghuram * This thread is woken up by the LDC interrupt handler to process 66034647Sraghuram * LDC packets and receive data. 66044647Sraghuram */ 66054647Sraghuram static void 66064647Sraghuram vgen_ldc_rcv_worker(void *arg) 66074647Sraghuram { 66084647Sraghuram callb_cpr_t cprinfo; 66094647Sraghuram vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 66104647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 66114647Sraghuram 66124647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 66134647Sraghuram CALLB_CPR_INIT(&cprinfo, &ldcp->rcv_thr_lock, callb_generic_cpr, 66144650Sraghuram "vnet_rcv_thread"); 66154647Sraghuram mutex_enter(&ldcp->rcv_thr_lock); 66164647Sraghuram ldcp->rcv_thr_flags |= VGEN_WTHR_RUNNING; 66174647Sraghuram while (!(ldcp->rcv_thr_flags & VGEN_WTHR_STOP)) { 66184647Sraghuram 66194647Sraghuram CALLB_CPR_SAFE_BEGIN(&cprinfo); 66204647Sraghuram /* 66214647Sraghuram * Wait until the data is received or a stop 66224647Sraghuram * request is received. 66234647Sraghuram */ 66244647Sraghuram while (!(ldcp->rcv_thr_flags & 66254647Sraghuram (VGEN_WTHR_DATARCVD | VGEN_WTHR_STOP))) { 66264647Sraghuram cv_wait(&ldcp->rcv_thr_cv, &ldcp->rcv_thr_lock); 66274647Sraghuram } 66284647Sraghuram CALLB_CPR_SAFE_END(&cprinfo, &ldcp->rcv_thr_lock) 66294647Sraghuram 66304647Sraghuram /* 66314647Sraghuram * First process the stop request. 66324647Sraghuram */ 66334647Sraghuram if (ldcp->rcv_thr_flags & VGEN_WTHR_STOP) { 66344647Sraghuram DBG2(vgenp, ldcp, "stopped\n"); 66354647Sraghuram break; 66364647Sraghuram } 66374647Sraghuram ldcp->rcv_thr_flags &= ~VGEN_WTHR_DATARCVD; 66384647Sraghuram mutex_exit(&ldcp->rcv_thr_lock); 66394647Sraghuram DBG2(vgenp, ldcp, "calling vgen_handle_evt_read\n"); 66404647Sraghuram vgen_handle_evt_read(ldcp); 66414647Sraghuram mutex_enter(&ldcp->rcv_thr_lock); 66424647Sraghuram } 66434647Sraghuram 66444647Sraghuram /* 66454647Sraghuram * Update the run status and wakeup the thread that 66464647Sraghuram * has sent the stop request. 66474647Sraghuram */ 66484647Sraghuram ldcp->rcv_thr_flags &= ~VGEN_WTHR_RUNNING; 66494647Sraghuram cv_signal(&ldcp->rcv_thr_cv); 66504647Sraghuram CALLB_CPR_EXIT(&cprinfo); 66514647Sraghuram thread_exit(); 66524647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 66534647Sraghuram } 66544647Sraghuram 66554647Sraghuram /* vgen_stop_rcv_thread -- Co-ordinate with receive thread to stop it */ 66564647Sraghuram static void 66574647Sraghuram vgen_stop_rcv_thread(vgen_ldc_t *ldcp) 66584647Sraghuram { 66594647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 66604647Sraghuram 66614647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 66624647Sraghuram /* 66634647Sraghuram * Send a stop request by setting the stop flag and 66644647Sraghuram * wait until the receive thread stops. 66654647Sraghuram */ 66664647Sraghuram mutex_enter(&ldcp->rcv_thr_lock); 66674647Sraghuram if (ldcp->rcv_thr_flags & VGEN_WTHR_RUNNING) { 66684647Sraghuram ldcp->rcv_thr_flags |= VGEN_WTHR_STOP; 66694647Sraghuram cv_signal(&ldcp->rcv_thr_cv); 66704647Sraghuram DBG2(vgenp, ldcp, "waiting..."); 66714647Sraghuram while (ldcp->rcv_thr_flags & VGEN_WTHR_RUNNING) { 66724647Sraghuram cv_wait(&ldcp->rcv_thr_cv, &ldcp->rcv_thr_lock); 66734647Sraghuram } 66744647Sraghuram } 66754647Sraghuram mutex_exit(&ldcp->rcv_thr_lock); 66764647Sraghuram ldcp->rcv_thread = NULL; 66774647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 66784647Sraghuram } 66794647Sraghuram 66806495Sspeer /* 66816495Sspeer * vgen_dds_rx -- post DDS messages to vnet. 66826495Sspeer */ 66836495Sspeer static int 66846495Sspeer vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 66856495Sspeer { 66866495Sspeer vio_dds_msg_t *dmsg = (vio_dds_msg_t *)tagp; 66876495Sspeer vgen_t *vgenp = LDC_TO_VGEN(ldcp); 66886495Sspeer 66896495Sspeer if (dmsg->dds_class != DDS_VNET_NIU) { 66906495Sspeer DWARN(vgenp, ldcp, "Unknown DDS class, dropping"); 66916495Sspeer return (EBADMSG); 66926495Sspeer } 66936495Sspeer vnet_dds_rx(vgenp->vnetp, dmsg); 66946495Sspeer return (0); 66956495Sspeer } 66966495Sspeer 66976495Sspeer /* 66986495Sspeer * vgen_dds_tx -- an interface called by vnet to send DDS messages. 66996495Sspeer */ 67006495Sspeer int 67016495Sspeer vgen_dds_tx(void *arg, void *msg) 67026495Sspeer { 67036495Sspeer vgen_t *vgenp = arg; 67046495Sspeer vio_dds_msg_t *dmsg = msg; 67056495Sspeer vgen_portlist_t *plistp = &vgenp->vgenports; 67066495Sspeer vgen_ldc_t *ldcp; 67076495Sspeer vgen_ldclist_t *ldclp; 67086495Sspeer int rv = EIO; 67096495Sspeer 67106495Sspeer 67116495Sspeer READ_ENTER(&plistp->rwlock); 67126495Sspeer ldclp = &(vgenp->vsw_portp->ldclist); 67136495Sspeer READ_ENTER(&ldclp->rwlock); 67146495Sspeer ldcp = ldclp->headp; 67156495Sspeer if ((ldcp == NULL) || (ldcp->hphase != VH_DONE)) { 67166495Sspeer goto vgen_dsend_exit; 67176495Sspeer } 67186495Sspeer 67196495Sspeer dmsg->tag.vio_sid = ldcp->local_sid; 67206495Sspeer rv = vgen_sendmsg(ldcp, (caddr_t)dmsg, sizeof (vio_dds_msg_t), B_FALSE); 67216495Sspeer if (rv != VGEN_SUCCESS) { 67226495Sspeer rv = EIO; 67236495Sspeer } else { 67246495Sspeer rv = 0; 67256495Sspeer } 67266495Sspeer 67276495Sspeer vgen_dsend_exit: 67286495Sspeer RW_EXIT(&ldclp->rwlock); 67296495Sspeer RW_EXIT(&plistp->rwlock); 67306495Sspeer return (rv); 67316495Sspeer 67326495Sspeer } 67336495Sspeer 67344647Sraghuram #if DEBUG 67354647Sraghuram 67364647Sraghuram /* 67374647Sraghuram * Print debug messages - set to 0xf to enable all msgs 67384647Sraghuram */ 67394647Sraghuram static void 67404647Sraghuram debug_printf(const char *fname, vgen_t *vgenp, 67414647Sraghuram vgen_ldc_t *ldcp, const char *fmt, ...) 67424647Sraghuram { 67434647Sraghuram char buf[256]; 67444647Sraghuram char *bufp = buf; 67454647Sraghuram va_list ap; 67464647Sraghuram 67474647Sraghuram if ((vgenp != NULL) && (vgenp->vnetp != NULL)) { 67484647Sraghuram (void) sprintf(bufp, "vnet%d:", 67494650Sraghuram ((vnet_t *)(vgenp->vnetp))->instance); 67504647Sraghuram bufp += strlen(bufp); 67514647Sraghuram } 67524647Sraghuram if (ldcp != NULL) { 67534647Sraghuram (void) sprintf(bufp, "ldc(%ld):", ldcp->ldc_id); 67544647Sraghuram bufp += strlen(bufp); 67554647Sraghuram } 67564647Sraghuram (void) sprintf(bufp, "%s: ", fname); 67574647Sraghuram bufp += strlen(bufp); 67584647Sraghuram 67594647Sraghuram va_start(ap, fmt); 67604647Sraghuram (void) vsprintf(bufp, fmt, ap); 67614647Sraghuram va_end(ap); 67624647Sraghuram 67634647Sraghuram if ((ldcp == NULL) ||(vgendbg_ldcid == -1) || 67644647Sraghuram (vgendbg_ldcid == ldcp->ldc_id)) { 67654647Sraghuram cmn_err(CE_CONT, "%s\n", buf); 67664647Sraghuram } 67674647Sraghuram } 67684647Sraghuram #endif 6769