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 /* 238623SSriharsha.Basavapatna@Sun.COM * Copyright 2009 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> 458275SEric Cheng #include <sys/mac_provider.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); 76*9235SWentao.Yang@Sun.COM void vgen_uninit(void *arg); 776495Sspeer int vgen_dds_tx(void *arg, void *dmsg); 789217SWentao.Yang@Sun.COM void vgen_mod_init(void); 799217SWentao.Yang@Sun.COM int vgen_mod_cleanup(void); 809217SWentao.Yang@Sun.COM void vgen_mod_fini(void); 811991Sheppo static int vgen_start(void *arg); 821991Sheppo static void vgen_stop(void *arg); 831991Sheppo static mblk_t *vgen_tx(void *arg, mblk_t *mp); 841991Sheppo static int vgen_multicst(void *arg, boolean_t add, 851991Sheppo const uint8_t *mca); 861991Sheppo static int vgen_promisc(void *arg, boolean_t on); 871991Sheppo static int vgen_unicst(void *arg, const uint8_t *mca); 882311Sseb static int vgen_stat(void *arg, uint_t stat, uint64_t *val); 891991Sheppo static void vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp); 901991Sheppo 911991Sheppo /* vgen internal functions */ 926419Ssb155480 static int vgen_read_mdprops(vgen_t *vgenp); 936419Ssb155480 static void vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 946419Ssb155480 static void vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp, 956419Ssb155480 mde_cookie_t node); 967529SSriharsha.Basavapatna@Sun.COM static void vgen_mtu_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node, 977529SSriharsha.Basavapatna@Sun.COM uint32_t *mtu); 981991Sheppo static void vgen_detach_ports(vgen_t *vgenp); 991991Sheppo static void vgen_port_detach(vgen_port_t *portp); 1001991Sheppo static void vgen_port_list_insert(vgen_port_t *portp); 1011991Sheppo static void vgen_port_list_remove(vgen_port_t *portp); 1021991Sheppo static vgen_port_t *vgen_port_lookup(vgen_portlist_t *plistp, 1031991Sheppo int port_num); 1041991Sheppo static int vgen_mdeg_reg(vgen_t *vgenp); 1051991Sheppo static void vgen_mdeg_unreg(vgen_t *vgenp); 1061991Sheppo static int vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp); 1076419Ssb155480 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp); 1081991Sheppo static int vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 1096419Ssb155480 static int vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp, 1106419Ssb155480 mde_cookie_t mdex); 1111991Sheppo static int vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex); 1126419Ssb155480 static int vgen_port_attach(vgen_port_t *portp); 1136419Ssb155480 static void vgen_port_detach_mdeg(vgen_port_t *portp); 1141991Sheppo static void vgen_port_detach_mdeg(vgen_port_t *portp); 1151991Sheppo static int vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, 1161991Sheppo mde_cookie_t curr_mdex, md_t *prev_mdp, mde_cookie_t prev_mdex); 1172311Sseb static uint64_t vgen_port_stat(vgen_port_t *portp, uint_t stat); 1181991Sheppo 1191991Sheppo static int vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id); 1201991Sheppo static void vgen_ldc_detach(vgen_ldc_t *ldcp); 1211991Sheppo static int vgen_alloc_tx_ring(vgen_ldc_t *ldcp); 1221991Sheppo static void vgen_free_tx_ring(vgen_ldc_t *ldcp); 1231991Sheppo static void vgen_init_ports(vgen_t *vgenp); 1241991Sheppo static void vgen_port_init(vgen_port_t *portp); 1251991Sheppo static void vgen_uninit_ports(vgen_t *vgenp); 1261991Sheppo static void vgen_port_uninit(vgen_port_t *portp); 1271991Sheppo static void vgen_init_ldcs(vgen_port_t *portp); 1281991Sheppo static void vgen_uninit_ldcs(vgen_port_t *portp); 1291991Sheppo static int vgen_ldc_init(vgen_ldc_t *ldcp); 1301991Sheppo static void vgen_ldc_uninit(vgen_ldc_t *ldcp); 1311991Sheppo static int vgen_init_tbufs(vgen_ldc_t *ldcp); 1321991Sheppo static void vgen_uninit_tbufs(vgen_ldc_t *ldcp); 1331991Sheppo static void vgen_clobber_tbufs(vgen_ldc_t *ldcp); 1341991Sheppo static void vgen_clobber_rxds(vgen_ldc_t *ldcp); 1352311Sseb static uint64_t vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat); 1361991Sheppo static uint_t vgen_ldc_cb(uint64_t event, caddr_t arg); 1371991Sheppo static int vgen_portsend(vgen_port_t *portp, mblk_t *mp); 1385935Ssb155480 static int vgen_ldcsend(void *arg, mblk_t *mp); 1395935Ssb155480 static void vgen_ldcsend_pkt(void *arg, mblk_t *mp); 1405935Ssb155480 static int vgen_ldcsend_dring(void *arg, mblk_t *mp); 1411991Sheppo static void vgen_reclaim(vgen_ldc_t *ldcp); 1421991Sheppo static void vgen_reclaim_dring(vgen_ldc_t *ldcp); 1431991Sheppo static int vgen_num_txpending(vgen_ldc_t *ldcp); 1441991Sheppo static int vgen_tx_dring_full(vgen_ldc_t *ldcp); 1451991Sheppo static int vgen_ldc_txtimeout(vgen_ldc_t *ldcp); 1461991Sheppo static void vgen_ldc_watchdog(void *arg); 1471991Sheppo 1481991Sheppo /* vgen handshake functions */ 1491991Sheppo static vgen_ldc_t *vh_nextphase(vgen_ldc_t *ldcp); 1501991Sheppo static int vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen, 1511991Sheppo boolean_t caller_holds_lock); 1521991Sheppo static int vgen_send_version_negotiate(vgen_ldc_t *ldcp); 1531991Sheppo static int vgen_send_attr_info(vgen_ldc_t *ldcp); 1541991Sheppo static int vgen_send_dring_reg(vgen_ldc_t *ldcp); 1551991Sheppo static int vgen_send_rdx_info(vgen_ldc_t *ldcp); 1562336Snarayan static int vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end); 1571991Sheppo static int vgen_send_mcast_info(vgen_ldc_t *ldcp); 1581991Sheppo static int vgen_handshake_phase2(vgen_ldc_t *ldcp); 1591991Sheppo static void vgen_handshake_reset(vgen_ldc_t *ldcp); 1601991Sheppo static void vgen_reset_hphase(vgen_ldc_t *ldcp); 1611991Sheppo static void vgen_handshake(vgen_ldc_t *ldcp); 1621991Sheppo static int vgen_handshake_done(vgen_ldc_t *ldcp); 1631991Sheppo static void vgen_handshake_retry(vgen_ldc_t *ldcp); 1642793Slm66018 static int vgen_handle_version_negotiate(vgen_ldc_t *ldcp, 1651991Sheppo vio_msg_tag_t *tagp); 1662793Slm66018 static int vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1672793Slm66018 static int vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1682793Slm66018 static int vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1692793Slm66018 static int vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1702793Slm66018 static int vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1715935Ssb155480 static void vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen); 1725935Ssb155480 static void vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen); 1734647Sraghuram static int vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1744647Sraghuram static int vgen_handle_dring_data_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1754647Sraghuram static int vgen_process_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1764647Sraghuram static int vgen_handle_dring_data_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1774647Sraghuram static int vgen_handle_dring_data_nack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1782793Slm66018 static int vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 1792336Snarayan uint32_t start, int32_t end, uint8_t pstate); 1805935Ssb155480 static int vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, 1815935Ssb155480 uint32_t msglen); 1821991Sheppo static void vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1836495Sspeer static void vgen_handle_evt_up(vgen_ldc_t *ldcp); 1846495Sspeer static void vgen_handle_evt_reset(vgen_ldc_t *ldcp); 1851991Sheppo static int vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1865935Ssb155480 static int vgen_check_datamsg_seq(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 1871991Sheppo static caddr_t vgen_print_ethaddr(uint8_t *a, char *ebuf); 1881991Sheppo static void vgen_hwatchdog(void *arg); 1891991Sheppo static void vgen_print_attr_info(vgen_ldc_t *ldcp, int endpoint); 1901991Sheppo static void vgen_print_hparams(vgen_hparams_t *hp); 1911991Sheppo static void vgen_print_ldcinfo(vgen_ldc_t *ldcp); 1924647Sraghuram static void vgen_stop_rcv_thread(vgen_ldc_t *ldcp); 1938623SSriharsha.Basavapatna@Sun.COM static void vgen_drain_rcv_thread(vgen_ldc_t *ldcp); 1944647Sraghuram static void vgen_ldc_rcv_worker(void *arg); 1954647Sraghuram static void vgen_handle_evt_read(vgen_ldc_t *ldcp); 1965935Ssb155480 static void vgen_rx(vgen_ldc_t *ldcp, mblk_t *bp); 1975935Ssb155480 static void vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp); 1985935Ssb155480 static void vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp); 1991991Sheppo 2006419Ssb155480 /* VLAN routines */ 2016419Ssb155480 static void vgen_vlan_read_ids(void *arg, int type, md_t *mdp, 2026419Ssb155480 mde_cookie_t node, uint16_t *pvidp, uint16_t **vidspp, 2036419Ssb155480 uint16_t *nvidsp, uint16_t *default_idp); 2046419Ssb155480 static void vgen_vlan_create_hash(vgen_port_t *portp); 2056419Ssb155480 static void vgen_vlan_destroy_hash(vgen_port_t *portp); 2066419Ssb155480 static void vgen_vlan_add_ids(vgen_port_t *portp); 2076419Ssb155480 static void vgen_vlan_remove_ids(vgen_port_t *portp); 2086419Ssb155480 static boolean_t vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid); 2096419Ssb155480 static boolean_t vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp, 2106419Ssb155480 uint16_t *vidp); 2116419Ssb155480 static mblk_t *vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp, 2126419Ssb155480 boolean_t is_tagged, uint16_t vid); 2136419Ssb155480 static void vgen_vlan_unaware_port_reset(vgen_port_t *portp); 2146419Ssb155480 static void vgen_reset_vlan_unaware_ports(vgen_t *vgenp); 2156495Sspeer static int vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp); 2166495Sspeer 2176495Sspeer /* externs */ 2186495Sspeer extern void vnet_dds_rx(void *arg, void *dmsg); 2197529SSriharsha.Basavapatna@Sun.COM extern int vnet_mtu_update(vnet_t *vnetp, uint32_t mtu); 2206419Ssb155480 2211991Sheppo /* 2221991Sheppo * The handshake process consists of 5 phases defined below, with VH_PHASE0 2231991Sheppo * being the pre-handshake phase and VH_DONE is the phase to indicate 2241991Sheppo * successful completion of all phases. 2251991Sheppo * Each phase may have one to several handshake states which are required 2261991Sheppo * to complete successfully to move to the next phase. 2271991Sheppo * Refer to the functions vgen_handshake() and vgen_handshake_done() for 2281991Sheppo * more details. 2291991Sheppo */ 2301991Sheppo /* handshake phases */ 2311991Sheppo enum { VH_PHASE0, VH_PHASE1, VH_PHASE2, VH_PHASE3, VH_DONE = 0x80 }; 2321991Sheppo 2331991Sheppo /* handshake states */ 2341991Sheppo enum { 2351991Sheppo 2361991Sheppo VER_INFO_SENT = 0x1, 2371991Sheppo VER_ACK_RCVD = 0x2, 2381991Sheppo VER_INFO_RCVD = 0x4, 2391991Sheppo VER_ACK_SENT = 0x8, 2401991Sheppo VER_NEGOTIATED = (VER_ACK_RCVD | VER_ACK_SENT), 2411991Sheppo 2421991Sheppo ATTR_INFO_SENT = 0x10, 2431991Sheppo ATTR_ACK_RCVD = 0x20, 2441991Sheppo ATTR_INFO_RCVD = 0x40, 2451991Sheppo ATTR_ACK_SENT = 0x80, 2461991Sheppo ATTR_INFO_EXCHANGED = (ATTR_ACK_RCVD | ATTR_ACK_SENT), 2471991Sheppo 2481991Sheppo DRING_INFO_SENT = 0x100, 2491991Sheppo DRING_ACK_RCVD = 0x200, 2501991Sheppo DRING_INFO_RCVD = 0x400, 2511991Sheppo DRING_ACK_SENT = 0x800, 2521991Sheppo DRING_INFO_EXCHANGED = (DRING_ACK_RCVD | DRING_ACK_SENT), 2531991Sheppo 2541991Sheppo RDX_INFO_SENT = 0x1000, 2551991Sheppo RDX_ACK_RCVD = 0x2000, 2561991Sheppo RDX_INFO_RCVD = 0x4000, 2571991Sheppo RDX_ACK_SENT = 0x8000, 2581991Sheppo RDX_EXCHANGED = (RDX_ACK_RCVD | RDX_ACK_SENT) 2591991Sheppo 2601991Sheppo }; 2611991Sheppo 2625935Ssb155480 #define VGEN_PRI_ETH_DEFINED(vgenp) ((vgenp)->pri_num_types != 0) 2635935Ssb155480 2641991Sheppo #define LDC_LOCK(ldcp) \ 2651991Sheppo mutex_enter(&((ldcp)->cblock));\ 2664647Sraghuram mutex_enter(&((ldcp)->rxlock));\ 2674647Sraghuram mutex_enter(&((ldcp)->wrlock));\ 2681991Sheppo mutex_enter(&((ldcp)->txlock));\ 2691991Sheppo mutex_enter(&((ldcp)->tclock)); 2701991Sheppo #define LDC_UNLOCK(ldcp) \ 2711991Sheppo mutex_exit(&((ldcp)->tclock));\ 2721991Sheppo mutex_exit(&((ldcp)->txlock));\ 2734647Sraghuram mutex_exit(&((ldcp)->wrlock));\ 2744647Sraghuram mutex_exit(&((ldcp)->rxlock));\ 2751991Sheppo mutex_exit(&((ldcp)->cblock)); 2761991Sheppo 2776419Ssb155480 #define VGEN_VER_EQ(ldcp, major, minor) \ 2786419Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \ 2796419Ssb155480 (ldcp)->local_hparams.ver_minor == (minor)) 2806419Ssb155480 2816419Ssb155480 #define VGEN_VER_LT(ldcp, major, minor) \ 2826419Ssb155480 (((ldcp)->local_hparams.ver_major < (major)) || \ 2836419Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \ 2846419Ssb155480 (ldcp)->local_hparams.ver_minor < (minor))) 2856419Ssb155480 2866419Ssb155480 #define VGEN_VER_GTEQ(ldcp, major, minor) \ 2876419Ssb155480 (((ldcp)->local_hparams.ver_major > (major)) || \ 2886419Ssb155480 ((ldcp)->local_hparams.ver_major == (major) && \ 2896419Ssb155480 (ldcp)->local_hparams.ver_minor >= (minor))) 2906419Ssb155480 2911991Sheppo static struct ether_addr etherbroadcastaddr = { 2921991Sheppo 0xff, 0xff, 0xff, 0xff, 0xff, 0xff 2931991Sheppo }; 2941991Sheppo /* 2951991Sheppo * MIB II broadcast/multicast packets 2961991Sheppo */ 2971991Sheppo #define IS_BROADCAST(ehp) \ 2981991Sheppo (ether_cmp(&ehp->ether_dhost, ðerbroadcastaddr) == 0) 2991991Sheppo #define IS_MULTICAST(ehp) \ 3001991Sheppo ((ehp->ether_dhost.ether_addr_octet[0] & 01) == 1) 3011991Sheppo 3021991Sheppo /* 3031991Sheppo * Property names 3041991Sheppo */ 3051991Sheppo static char macaddr_propname[] = "mac-address"; 3061991Sheppo static char rmacaddr_propname[] = "remote-mac-address"; 3071991Sheppo static char channel_propname[] = "channel-endpoint"; 3081991Sheppo static char reg_propname[] = "reg"; 3091991Sheppo static char port_propname[] = "port"; 3101991Sheppo static char swport_propname[] = "switch-port"; 3111991Sheppo static char id_propname[] = "id"; 3125935Ssb155480 static char vdev_propname[] = "virtual-device"; 3135935Ssb155480 static char vnet_propname[] = "network"; 3145935Ssb155480 static char pri_types_propname[] = "priority-ether-types"; 3156419Ssb155480 static char vgen_pvid_propname[] = "port-vlan-id"; 3166419Ssb155480 static char vgen_vid_propname[] = "vlan-id"; 3176419Ssb155480 static char vgen_dvid_propname[] = "default-vlan-id"; 3186419Ssb155480 static char port_pvid_propname[] = "remote-port-vlan-id"; 3196419Ssb155480 static char port_vid_propname[] = "remote-vlan-id"; 3207529SSriharsha.Basavapatna@Sun.COM static char vgen_mtu_propname[] = "mtu"; 3211991Sheppo 3221991Sheppo /* versions supported - in decreasing order */ 3237529SSriharsha.Basavapatna@Sun.COM static vgen_ver_t vgen_versions[VGEN_NUM_VER] = { {1, 4} }; 3241991Sheppo 3251991Sheppo /* Tunables */ 3265171Ssb155480 uint32_t vgen_hwd_interval = 5; /* handshake watchdog freq in sec */ 3273297Ssb155480 uint32_t vgen_max_hretries = VNET_NUM_HANDSHAKES; /* # of handshake retries */ 3281991Sheppo uint32_t vgen_ldcwr_retries = 10; /* max # of ldc_write() retries */ 3292109Slm66018 uint32_t vgen_ldcup_retries = 5; /* max # of ldc_up() retries */ 3308623SSriharsha.Basavapatna@Sun.COM uint32_t vgen_ldccl_retries = 5; /* max # of ldc_close() retries */ 3312336Snarayan uint32_t vgen_recv_delay = 1; /* delay when rx descr not ready */ 3322336Snarayan uint32_t vgen_recv_retries = 10; /* retry when rx descr not ready */ 3335022Sraghuram uint32_t vgen_tx_retries = 0x4; /* retry when tx descr not available */ 3345022Sraghuram uint32_t vgen_tx_delay = 0x30; /* delay when tx descr not available */ 3351991Sheppo 3364647Sraghuram int vgen_rcv_thread_enabled = 1; /* Enable Recieve thread */ 3374647Sraghuram 3389217SWentao.Yang@Sun.COM static vio_mblk_pool_t *vgen_rx_poolp = NULL; 3399217SWentao.Yang@Sun.COM static krwlock_t vgen_rw; 3409217SWentao.Yang@Sun.COM 3414647Sraghuram /* 3424647Sraghuram * max # of packets accumulated prior to sending them up. It is best 3434647Sraghuram * to keep this at 60% of the number of recieve buffers. 3444647Sraghuram */ 3454647Sraghuram uint32_t vgen_chain_len = (VGEN_NRBUFS * 0.6); 3464647Sraghuram 3474647Sraghuram /* 3487529SSriharsha.Basavapatna@Sun.COM * Internal tunables for receive buffer pools, that is, the size and number of 3497529SSriharsha.Basavapatna@Sun.COM * mblks for each pool. At least 3 sizes must be specified if these are used. 3507529SSriharsha.Basavapatna@Sun.COM * The sizes must be specified in increasing order. Non-zero value of the first 3517529SSriharsha.Basavapatna@Sun.COM * size will be used as a hint to use these values instead of the algorithm 3527529SSriharsha.Basavapatna@Sun.COM * that determines the sizes based on MTU. 3534647Sraghuram */ 3547529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz1 = 0; 3557529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz2 = 0; 3567529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz3 = 0; 3577529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_rbufsz4 = 0; 3584647Sraghuram 3594647Sraghuram uint32_t vgen_nrbufs1 = VGEN_NRBUFS; 3604647Sraghuram uint32_t vgen_nrbufs2 = VGEN_NRBUFS; 3614647Sraghuram uint32_t vgen_nrbufs3 = VGEN_NRBUFS; 3627529SSriharsha.Basavapatna@Sun.COM uint32_t vgen_nrbufs4 = VGEN_NRBUFS; 3634647Sraghuram 3645935Ssb155480 /* 3655935Ssb155480 * In the absence of "priority-ether-types" property in MD, the following 3665935Ssb155480 * internal tunable can be set to specify a single priority ethertype. 3675935Ssb155480 */ 3685935Ssb155480 uint64_t vgen_pri_eth_type = 0; 3695935Ssb155480 3705935Ssb155480 /* 3715935Ssb155480 * Number of transmit priority buffers that are preallocated per device. 3725935Ssb155480 * This number is chosen to be a small value to throttle transmission 3735935Ssb155480 * of priority packets. Note: Must be a power of 2 for vio_create_mblks(). 3745935Ssb155480 */ 3755935Ssb155480 uint32_t vgen_pri_tx_nmblks = 64; 3765935Ssb155480 3776419Ssb155480 uint32_t vgen_vlan_nchains = 4; /* # of chains in vlan id hash table */ 3786419Ssb155480 3791991Sheppo #ifdef DEBUG 3801991Sheppo /* flags to simulate error conditions for debugging */ 3811991Sheppo int vgen_trigger_txtimeout = 0; 3821991Sheppo int vgen_trigger_rxlost = 0; 3831991Sheppo #endif 3841991Sheppo 3856419Ssb155480 /* 3866419Ssb155480 * Matching criteria passed to the MDEG to register interest 3876419Ssb155480 * in changes to 'virtual-device' nodes (i.e. vnet nodes) identified 3886419Ssb155480 * by their 'name' and 'cfg-handle' properties. 3896419Ssb155480 */ 3906419Ssb155480 static md_prop_match_t vdev_prop_match[] = { 3916419Ssb155480 { MDET_PROP_STR, "name" }, 3926419Ssb155480 { MDET_PROP_VAL, "cfg-handle" }, 3936419Ssb155480 { MDET_LIST_END, NULL } 3946419Ssb155480 }; 3956419Ssb155480 3966419Ssb155480 static mdeg_node_match_t vdev_match = { "virtual-device", 3976419Ssb155480 vdev_prop_match }; 3986419Ssb155480 3991991Sheppo /* MD update matching structure */ 4001991Sheppo static md_prop_match_t vport_prop_match[] = { 4011991Sheppo { MDET_PROP_VAL, "id" }, 4021991Sheppo { MDET_LIST_END, NULL } 4031991Sheppo }; 4041991Sheppo 4051991Sheppo static mdeg_node_match_t vport_match = { "virtual-device-port", 4061991Sheppo vport_prop_match }; 4071991Sheppo 4081991Sheppo /* template for matching a particular vnet instance */ 4091991Sheppo static mdeg_prop_spec_t vgen_prop_template[] = { 4101991Sheppo { MDET_PROP_STR, "name", "network" }, 4111991Sheppo { MDET_PROP_VAL, "cfg-handle", NULL }, 4121991Sheppo { MDET_LIST_END, NULL, NULL } 4131991Sheppo }; 4141991Sheppo 4151991Sheppo #define VGEN_SET_MDEG_PROP_INST(specp, val) (specp)[1].ps_val = (val) 4161991Sheppo 4176419Ssb155480 static int vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp); 4181991Sheppo 4192311Sseb static mac_callbacks_t vgen_m_callbacks = { 4202311Sseb 0, 4212311Sseb vgen_stat, 4222311Sseb vgen_start, 4232311Sseb vgen_stop, 4242311Sseb vgen_promisc, 4252311Sseb vgen_multicst, 4262311Sseb vgen_unicst, 4272311Sseb vgen_tx, 4282311Sseb NULL, 4292311Sseb NULL, 4302311Sseb NULL 4312311Sseb }; 4322311Sseb 4331991Sheppo /* externs */ 4344647Sraghuram extern pri_t maxclsyspri; 4354647Sraghuram extern proc_t p0; 4361991Sheppo extern uint32_t vnet_ntxds; 4371991Sheppo extern uint32_t vnet_ldcwd_interval; 4381991Sheppo extern uint32_t vnet_ldcwd_txtimeout; 4392410Slm66018 extern uint32_t vnet_ldc_mtu; 4402336Snarayan extern uint32_t vnet_nrbufs; 4416419Ssb155480 extern uint32_t vnet_ethermtu; 4426419Ssb155480 extern uint16_t vnet_default_vlan_id; 4437529SSriharsha.Basavapatna@Sun.COM extern boolean_t vnet_jumbo_rxpools; 4441991Sheppo 4451991Sheppo #ifdef DEBUG 4461991Sheppo 4474647Sraghuram extern int vnet_dbglevel; 4484647Sraghuram static void debug_printf(const char *fname, vgen_t *vgenp, 4494647Sraghuram vgen_ldc_t *ldcp, const char *fmt, ...); 4504647Sraghuram 4514647Sraghuram /* -1 for all LDCs info, or ldc_id for a specific LDC info */ 4524647Sraghuram int vgendbg_ldcid = -1; 4531991Sheppo 4541991Sheppo /* simulate handshake error conditions for debug */ 4551991Sheppo uint32_t vgen_hdbg; 4561991Sheppo #define HDBG_VERSION 0x1 4571991Sheppo #define HDBG_TIMEOUT 0x2 4581991Sheppo #define HDBG_BAD_SID 0x4 4591991Sheppo #define HDBG_OUT_STATE 0x8 4601991Sheppo 4611991Sheppo #endif 4621991Sheppo 4631991Sheppo /* 4641991Sheppo * vgen_init() is called by an instance of vnet driver to initialize the 4651991Sheppo * corresponding generic proxy transport layer. The arguments passed by vnet 4661991Sheppo * are - an opaque pointer to the vnet instance, pointers to dev_info_t and 4676495Sspeer * the mac address of the vnet device, and a pointer to vgen_t is passed 4686495Sspeer * back as a handle to vnet. 4691991Sheppo */ 4701991Sheppo int 4716495Sspeer vgen_init(void *vnetp, uint64_t regprop, dev_info_t *vnetdip, 4726495Sspeer const uint8_t *macaddr, void **vgenhdl) 4731991Sheppo { 4741991Sheppo vgen_t *vgenp; 4751991Sheppo int instance; 4765935Ssb155480 int rv; 4771991Sheppo 4782311Sseb if ((vnetp == NULL) || (vnetdip == NULL)) 4791991Sheppo return (DDI_FAILURE); 4801991Sheppo 4811991Sheppo instance = ddi_get_instance(vnetdip); 4821991Sheppo 4835373Sraghuram DBG1(NULL, NULL, "vnet(%d): enter\n", instance); 4841991Sheppo 4851991Sheppo vgenp = kmem_zalloc(sizeof (vgen_t), KM_SLEEP); 4861991Sheppo 4871991Sheppo vgenp->vnetp = vnetp; 4886495Sspeer vgenp->instance = instance; 4896495Sspeer vgenp->regprop = regprop; 4901991Sheppo vgenp->vnetdip = vnetdip; 4911991Sheppo bcopy(macaddr, &(vgenp->macaddr), ETHERADDRL); 4921991Sheppo 4931991Sheppo /* allocate multicast table */ 4941991Sheppo vgenp->mctab = kmem_zalloc(VGEN_INIT_MCTAB_SIZE * 4951991Sheppo sizeof (struct ether_addr), KM_SLEEP); 4961991Sheppo vgenp->mccount = 0; 4971991Sheppo vgenp->mcsize = VGEN_INIT_MCTAB_SIZE; 4981991Sheppo 4991991Sheppo mutex_init(&vgenp->lock, NULL, MUTEX_DRIVER, NULL); 5005641Swentaoy rw_init(&vgenp->vgenports.rwlock, NULL, RW_DRIVER, NULL); 5011991Sheppo 5025935Ssb155480 rv = vgen_read_mdprops(vgenp); 5035935Ssb155480 if (rv != 0) { 5045935Ssb155480 goto vgen_init_fail; 5055935Ssb155480 } 5065935Ssb155480 5071991Sheppo /* register with MD event generator */ 5085935Ssb155480 rv = vgen_mdeg_reg(vgenp); 5095935Ssb155480 if (rv != DDI_SUCCESS) { 5105935Ssb155480 goto vgen_init_fail; 5111991Sheppo } 5121991Sheppo 5136495Sspeer *vgenhdl = (void *)vgenp; 5141991Sheppo 5155373Sraghuram DBG1(NULL, NULL, "vnet(%d): exit\n", instance); 5161991Sheppo return (DDI_SUCCESS); 5175935Ssb155480 5185935Ssb155480 vgen_init_fail: 5195935Ssb155480 rw_destroy(&vgenp->vgenports.rwlock); 5205935Ssb155480 mutex_destroy(&vgenp->lock); 5215935Ssb155480 kmem_free(vgenp->mctab, VGEN_INIT_MCTAB_SIZE * 5225935Ssb155480 sizeof (struct ether_addr)); 5235935Ssb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) { 5245935Ssb155480 kmem_free(vgenp->pri_types, 5255935Ssb155480 sizeof (uint16_t) * vgenp->pri_num_types); 5265935Ssb155480 (void) vio_destroy_mblks(vgenp->pri_tx_vmp); 5275935Ssb155480 } 5285935Ssb155480 KMEM_FREE(vgenp); 5295935Ssb155480 return (DDI_FAILURE); 5301991Sheppo } 5311991Sheppo 5321991Sheppo /* 5331991Sheppo * Called by vnet to undo the initializations done by vgen_init(). 5341991Sheppo * The handle provided by generic transport during vgen_init() is the argument. 5351991Sheppo */ 536*9235SWentao.Yang@Sun.COM void 5371991Sheppo vgen_uninit(void *arg) 5381991Sheppo { 5395935Ssb155480 vgen_t *vgenp = (vgen_t *)arg; 5405935Ssb155480 vio_mblk_pool_t *rp; 5415935Ssb155480 vio_mblk_pool_t *nrp; 5422336Snarayan 5432336Snarayan if (vgenp == NULL) { 544*9235SWentao.Yang@Sun.COM return; 5452336Snarayan } 5461991Sheppo 5474647Sraghuram DBG1(vgenp, NULL, "enter\n"); 5481991Sheppo 5491991Sheppo /* unregister with MD event generator */ 5501991Sheppo vgen_mdeg_unreg(vgenp); 5511991Sheppo 5521991Sheppo mutex_enter(&vgenp->lock); 5531991Sheppo 5541991Sheppo /* detach all ports from the device */ 5551991Sheppo vgen_detach_ports(vgenp); 5561991Sheppo 5572336Snarayan /* 5582336Snarayan * free any pending rx mblk pools, 5592336Snarayan * that couldn't be freed previously during channel detach. 5602336Snarayan */ 5612336Snarayan rp = vgenp->rmp; 5622336Snarayan while (rp != NULL) { 5632336Snarayan nrp = vgenp->rmp = rp->nextp; 5642336Snarayan if (vio_destroy_mblks(rp)) { 5659217SWentao.Yang@Sun.COM WRITE_ENTER(&vgen_rw); 5669217SWentao.Yang@Sun.COM rp->nextp = vgen_rx_poolp; 5679217SWentao.Yang@Sun.COM vgen_rx_poolp = rp; 5689217SWentao.Yang@Sun.COM RW_EXIT(&vgen_rw); 5692336Snarayan } 5702336Snarayan rp = nrp; 5712336Snarayan } 5722336Snarayan 5731991Sheppo /* free multicast table */ 5741991Sheppo kmem_free(vgenp->mctab, vgenp->mcsize * sizeof (struct ether_addr)); 5751991Sheppo 5765935Ssb155480 /* free pri_types table */ 5775935Ssb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) { 5785935Ssb155480 kmem_free(vgenp->pri_types, 5795935Ssb155480 sizeof (uint16_t) * vgenp->pri_num_types); 5805935Ssb155480 (void) vio_destroy_mblks(vgenp->pri_tx_vmp); 5815935Ssb155480 } 5825935Ssb155480 5831991Sheppo mutex_exit(&vgenp->lock); 5841991Sheppo 5855641Swentaoy rw_destroy(&vgenp->vgenports.rwlock); 5861991Sheppo mutex_destroy(&vgenp->lock); 5871991Sheppo 5887572SWentao.Yang@Sun.COM DBG1(vgenp, NULL, "exit\n"); 5891991Sheppo KMEM_FREE(vgenp); 5901991Sheppo } 5911991Sheppo 5929217SWentao.Yang@Sun.COM /* 5939217SWentao.Yang@Sun.COM * module specific initialization common to all instances of vnet/vgen. 5949217SWentao.Yang@Sun.COM */ 5959217SWentao.Yang@Sun.COM void 5969217SWentao.Yang@Sun.COM vgen_mod_init(void) 5979217SWentao.Yang@Sun.COM { 5989217SWentao.Yang@Sun.COM rw_init(&vgen_rw, NULL, RW_DRIVER, NULL); 5999217SWentao.Yang@Sun.COM } 6009217SWentao.Yang@Sun.COM 6019217SWentao.Yang@Sun.COM /* 6029217SWentao.Yang@Sun.COM * module specific cleanup common to all instances of vnet/vgen. 6039217SWentao.Yang@Sun.COM */ 6049217SWentao.Yang@Sun.COM int 6059217SWentao.Yang@Sun.COM vgen_mod_cleanup(void) 6069217SWentao.Yang@Sun.COM { 6079217SWentao.Yang@Sun.COM vio_mblk_pool_t *poolp, *npoolp; 6089217SWentao.Yang@Sun.COM 6099217SWentao.Yang@Sun.COM /* 6109217SWentao.Yang@Sun.COM * If any rx mblk pools are still in use, return 6119217SWentao.Yang@Sun.COM * error and stop the module from unloading. 6129217SWentao.Yang@Sun.COM */ 6139217SWentao.Yang@Sun.COM WRITE_ENTER(&vgen_rw); 6149217SWentao.Yang@Sun.COM poolp = vgen_rx_poolp; 6159217SWentao.Yang@Sun.COM while (poolp != NULL) { 6169217SWentao.Yang@Sun.COM npoolp = vgen_rx_poolp = poolp->nextp; 6179217SWentao.Yang@Sun.COM if (vio_destroy_mblks(poolp) != 0) { 6189217SWentao.Yang@Sun.COM vgen_rx_poolp = poolp; 6199217SWentao.Yang@Sun.COM RW_EXIT(&vgen_rw); 6209217SWentao.Yang@Sun.COM return (EBUSY); 6219217SWentao.Yang@Sun.COM } 6229217SWentao.Yang@Sun.COM poolp = npoolp; 6239217SWentao.Yang@Sun.COM } 6249217SWentao.Yang@Sun.COM RW_EXIT(&vgen_rw); 6259217SWentao.Yang@Sun.COM 6269217SWentao.Yang@Sun.COM return (0); 6279217SWentao.Yang@Sun.COM } 6289217SWentao.Yang@Sun.COM 6299217SWentao.Yang@Sun.COM /* 6309217SWentao.Yang@Sun.COM * module specific uninitialization common to all instances of vnet/vgen. 6319217SWentao.Yang@Sun.COM */ 6329217SWentao.Yang@Sun.COM void 6339217SWentao.Yang@Sun.COM vgen_mod_fini(void) 6349217SWentao.Yang@Sun.COM { 6359217SWentao.Yang@Sun.COM rw_destroy(&vgen_rw); 6369217SWentao.Yang@Sun.COM } 6379217SWentao.Yang@Sun.COM 6381991Sheppo /* enable transmit/receive for the device */ 6392311Sseb int 6401991Sheppo vgen_start(void *arg) 6411991Sheppo { 6426495Sspeer vgen_port_t *portp = (vgen_port_t *)arg; 6436495Sspeer vgen_t *vgenp = portp->vgenp; 6441991Sheppo 6454647Sraghuram DBG1(vgenp, NULL, "enter\n"); 6466495Sspeer mutex_enter(&portp->lock); 6476495Sspeer vgen_port_init(portp); 6486495Sspeer portp->flags |= VGEN_STARTED; 6496495Sspeer mutex_exit(&portp->lock); 6504647Sraghuram DBG1(vgenp, NULL, "exit\n"); 6516495Sspeer 6521991Sheppo return (DDI_SUCCESS); 6531991Sheppo } 6541991Sheppo 6551991Sheppo /* stop transmit/receive */ 6562311Sseb void 6571991Sheppo vgen_stop(void *arg) 6581991Sheppo { 6596495Sspeer vgen_port_t *portp = (vgen_port_t *)arg; 6606495Sspeer vgen_t *vgenp = portp->vgenp; 6611991Sheppo 6624647Sraghuram DBG1(vgenp, NULL, "enter\n"); 6631991Sheppo 6646495Sspeer mutex_enter(&portp->lock); 6656495Sspeer vgen_port_uninit(portp); 6666495Sspeer portp->flags &= ~(VGEN_STARTED); 6676495Sspeer mutex_exit(&portp->lock); 6684647Sraghuram DBG1(vgenp, NULL, "exit\n"); 6696495Sspeer 6701991Sheppo } 6711991Sheppo 6721991Sheppo /* vgen transmit function */ 6731991Sheppo static mblk_t * 6741991Sheppo vgen_tx(void *arg, mblk_t *mp) 6751991Sheppo { 6765022Sraghuram int i; 6771991Sheppo vgen_port_t *portp; 6785022Sraghuram int status = VGEN_FAILURE; 6791991Sheppo 6801991Sheppo portp = (vgen_port_t *)arg; 6815022Sraghuram /* 6825022Sraghuram * Retry so that we avoid reporting a failure 6835022Sraghuram * to the upper layer. Returning a failure may cause the 6845022Sraghuram * upper layer to go into single threaded mode there by 6855022Sraghuram * causing performance degradation, especially for a large 6865022Sraghuram * number of connections. 6875022Sraghuram */ 6885022Sraghuram for (i = 0; i < vgen_tx_retries; ) { 6895022Sraghuram status = vgen_portsend(portp, mp); 6905022Sraghuram if (status == VGEN_SUCCESS) { 6915022Sraghuram break; 6925022Sraghuram } 6935022Sraghuram if (++i < vgen_tx_retries) 6945022Sraghuram delay(drv_usectohz(vgen_tx_delay)); 6955022Sraghuram } 6961991Sheppo if (status != VGEN_SUCCESS) { 6971991Sheppo /* failure */ 6981991Sheppo return (mp); 6991991Sheppo } 7001991Sheppo /* success */ 7011991Sheppo return (NULL); 7021991Sheppo } 7031991Sheppo 7046419Ssb155480 /* 7056419Ssb155480 * This function provides any necessary tagging/untagging of the frames 7066419Ssb155480 * that are being transmitted over the port. It first verifies the vlan 7076419Ssb155480 * membership of the destination(port) and drops the packet if the 7086419Ssb155480 * destination doesn't belong to the given vlan. 7096419Ssb155480 * 7106419Ssb155480 * Arguments: 7116419Ssb155480 * portp: port over which the frames should be transmitted 7126419Ssb155480 * mp: frame to be transmitted 7136419Ssb155480 * is_tagged: 7146419Ssb155480 * B_TRUE: indicates frame header contains the vlan tag already. 7156419Ssb155480 * B_FALSE: indicates frame is untagged. 7166419Ssb155480 * vid: vlan in which the frame should be transmitted. 7176419Ssb155480 * 7186419Ssb155480 * Returns: 7196419Ssb155480 * Sucess: frame(mblk_t *) after doing the necessary tag/untag. 7206419Ssb155480 * Failure: NULL 7216419Ssb155480 */ 7226419Ssb155480 static mblk_t * 7236419Ssb155480 vgen_vlan_frame_fixtag(vgen_port_t *portp, mblk_t *mp, boolean_t is_tagged, 7246419Ssb155480 uint16_t vid) 7256419Ssb155480 { 7266419Ssb155480 vgen_t *vgenp; 7276419Ssb155480 boolean_t dst_tagged; 7286419Ssb155480 int rv; 7296419Ssb155480 7306419Ssb155480 vgenp = portp->vgenp; 7316419Ssb155480 7326419Ssb155480 /* 7336419Ssb155480 * If the packet is going to a vnet: 7346419Ssb155480 * Check if the destination vnet is in the same vlan. 7356419Ssb155480 * Check the frame header if tag or untag is needed. 7366419Ssb155480 * 7376419Ssb155480 * We do not check the above conditions if the packet is going to vsw: 7386419Ssb155480 * vsw must be present implicitly in all the vlans that a vnet device 7396419Ssb155480 * is configured into; even if vsw itself is not assigned to those 7406419Ssb155480 * vlans as an interface. For instance, the packet might be destined 7416419Ssb155480 * to another vnet(indirectly through vsw) or to an external host 7426419Ssb155480 * which is in the same vlan as this vnet and vsw itself may not be 7436419Ssb155480 * present in that vlan. Similarly packets going to vsw must be 7446419Ssb155480 * always tagged(unless in the default-vlan) if not already tagged, 7456419Ssb155480 * as we do not know the final destination. This is needed because 7466419Ssb155480 * vsw must always invoke its switching function only after tagging 7476419Ssb155480 * the packet; otherwise after switching function determines the 7486419Ssb155480 * destination we cannot figure out if the destination belongs to the 7496419Ssb155480 * the same vlan that the frame originated from and if it needs tag/ 7506419Ssb155480 * untag. Note that vsw will tag the packet itself when it receives 7516419Ssb155480 * it over the channel from a client if needed. However, that is 7526419Ssb155480 * needed only in the case of vlan unaware clients such as obp or 7536419Ssb155480 * earlier versions of vnet. 7546419Ssb155480 * 7556419Ssb155480 */ 7566419Ssb155480 if (portp != vgenp->vsw_portp) { 7576419Ssb155480 /* 7586419Ssb155480 * Packet going to a vnet. Check if the destination vnet is in 7596419Ssb155480 * the same vlan. Then check the frame header if tag/untag is 7606419Ssb155480 * needed. 7616419Ssb155480 */ 7626419Ssb155480 rv = vgen_vlan_lookup(portp->vlan_hashp, vid); 7636419Ssb155480 if (rv == B_FALSE) { 7646419Ssb155480 /* drop the packet */ 7656419Ssb155480 freemsg(mp); 7666419Ssb155480 return (NULL); 7676419Ssb155480 } 7686419Ssb155480 7696419Ssb155480 /* is the destination tagged or untagged in this vlan? */ 7706419Ssb155480 (vid == portp->pvid) ? (dst_tagged = B_FALSE) : 7716419Ssb155480 (dst_tagged = B_TRUE); 7726419Ssb155480 7736419Ssb155480 if (is_tagged == dst_tagged) { 7746419Ssb155480 /* no tagging/untagging needed */ 7756419Ssb155480 return (mp); 7766419Ssb155480 } 7776419Ssb155480 7786419Ssb155480 if (is_tagged == B_TRUE) { 7796419Ssb155480 /* frame is tagged; destination needs untagged */ 7806419Ssb155480 mp = vnet_vlan_remove_tag(mp); 7816419Ssb155480 return (mp); 7826419Ssb155480 } 7836419Ssb155480 7846419Ssb155480 /* (is_tagged == B_FALSE): fallthru to tag tx packet: */ 7856419Ssb155480 } 7866419Ssb155480 7876419Ssb155480 /* 7886419Ssb155480 * Packet going to a vnet needs tagging. 7896419Ssb155480 * OR 7906419Ssb155480 * If the packet is going to vsw, then it must be tagged in all cases: 7916419Ssb155480 * unknown unicast, broadcast/multicast or to vsw interface. 7926419Ssb155480 */ 7936419Ssb155480 7946419Ssb155480 if (is_tagged == B_FALSE) { 7956419Ssb155480 mp = vnet_vlan_insert_tag(mp, vid); 7966419Ssb155480 } 7976419Ssb155480 7986419Ssb155480 return (mp); 7996419Ssb155480 } 8006419Ssb155480 8011991Sheppo /* transmit packets over the given port */ 8021991Sheppo static int 8031991Sheppo vgen_portsend(vgen_port_t *portp, mblk_t *mp) 8041991Sheppo { 8056419Ssb155480 vgen_ldclist_t *ldclp; 8066419Ssb155480 vgen_ldc_t *ldcp; 8076419Ssb155480 int status; 8086419Ssb155480 int rv = VGEN_SUCCESS; 8096495Sspeer vgen_t *vgenp = portp->vgenp; 8106495Sspeer vnet_t *vnetp = vgenp->vnetp; 8116419Ssb155480 boolean_t is_tagged; 8126495Sspeer boolean_t dec_refcnt = B_FALSE; 8136419Ssb155480 uint16_t vlan_id; 8146419Ssb155480 struct ether_header *ehp; 8156419Ssb155480 8166495Sspeer if (portp->use_vsw_port) { 8176495Sspeer (void) atomic_inc_32(&vgenp->vsw_port_refcnt); 8186495Sspeer portp = portp->vgenp->vsw_portp; 8196495Sspeer dec_refcnt = B_TRUE; 8206495Sspeer } 8216495Sspeer if (portp == NULL) { 8226495Sspeer return (VGEN_FAILURE); 8236495Sspeer } 8246419Ssb155480 8256419Ssb155480 /* 8266419Ssb155480 * Determine the vlan id that the frame belongs to. 8276419Ssb155480 */ 8286419Ssb155480 ehp = (struct ether_header *)mp->b_rptr; 8296419Ssb155480 is_tagged = vgen_frame_lookup_vid(vnetp, ehp, &vlan_id); 8306419Ssb155480 8316419Ssb155480 if (vlan_id == vnetp->default_vlan_id) { 8326419Ssb155480 8336419Ssb155480 /* Frames in default vlan must be untagged */ 8346419Ssb155480 ASSERT(is_tagged == B_FALSE); 8356419Ssb155480 8366419Ssb155480 /* 8376419Ssb155480 * If the destination is a vnet-port verify it belongs to the 8386419Ssb155480 * default vlan; otherwise drop the packet. We do not need 8396419Ssb155480 * this check for vsw-port, as it should implicitly belong to 8406419Ssb155480 * this vlan; see comments in vgen_vlan_frame_fixtag(). 8416419Ssb155480 */ 8426419Ssb155480 if (portp != vgenp->vsw_portp && 8436419Ssb155480 portp->pvid != vnetp->default_vlan_id) { 8446419Ssb155480 freemsg(mp); 8456495Sspeer goto portsend_ret; 8466419Ssb155480 } 8476419Ssb155480 8486419Ssb155480 } else { /* frame not in default-vlan */ 8496419Ssb155480 8506419Ssb155480 mp = vgen_vlan_frame_fixtag(portp, mp, is_tagged, vlan_id); 8516419Ssb155480 if (mp == NULL) { 8526495Sspeer goto portsend_ret; 8536419Ssb155480 } 8546419Ssb155480 8556419Ssb155480 } 8561991Sheppo 8571991Sheppo ldclp = &portp->ldclist; 8581991Sheppo READ_ENTER(&ldclp->rwlock); 8591991Sheppo /* 8602336Snarayan * NOTE: for now, we will assume we have a single channel. 8611991Sheppo */ 8621991Sheppo if (ldclp->headp == NULL) { 8631991Sheppo RW_EXIT(&ldclp->rwlock); 8646495Sspeer rv = VGEN_FAILURE; 8656495Sspeer goto portsend_ret; 8661991Sheppo } 8671991Sheppo ldcp = ldclp->headp; 8681991Sheppo 8695935Ssb155480 status = ldcp->tx(ldcp, mp); 8705022Sraghuram 8711991Sheppo RW_EXIT(&ldclp->rwlock); 8721991Sheppo 8735022Sraghuram if (status != VGEN_TX_SUCCESS) { 8745022Sraghuram rv = VGEN_FAILURE; 8755022Sraghuram } 8766495Sspeer 8776495Sspeer portsend_ret: 8786495Sspeer if (dec_refcnt == B_TRUE) { 8796495Sspeer (void) atomic_dec_32(&vgenp->vsw_port_refcnt); 8806495Sspeer } 8815022Sraghuram return (rv); 8821991Sheppo } 8831991Sheppo 8845935Ssb155480 /* 8855935Ssb155480 * Wrapper function to transmit normal and/or priority frames over the channel. 8865935Ssb155480 */ 8871991Sheppo static int 8885935Ssb155480 vgen_ldcsend(void *arg, mblk_t *mp) 8895935Ssb155480 { 8905935Ssb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 8915935Ssb155480 int status; 8925935Ssb155480 struct ether_header *ehp; 8935935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 8945935Ssb155480 uint32_t num_types; 8955935Ssb155480 uint16_t *types; 8965935Ssb155480 int i; 8975935Ssb155480 8985935Ssb155480 ASSERT(VGEN_PRI_ETH_DEFINED(vgenp)); 8995935Ssb155480 9005935Ssb155480 num_types = vgenp->pri_num_types; 9015935Ssb155480 types = vgenp->pri_types; 9025935Ssb155480 ehp = (struct ether_header *)mp->b_rptr; 9035935Ssb155480 9045935Ssb155480 for (i = 0; i < num_types; i++) { 9055935Ssb155480 9065935Ssb155480 if (ehp->ether_type == types[i]) { 9075935Ssb155480 /* priority frame, use pri tx function */ 9085935Ssb155480 vgen_ldcsend_pkt(ldcp, mp); 9095935Ssb155480 return (VGEN_SUCCESS); 9105935Ssb155480 } 9115935Ssb155480 9125935Ssb155480 } 9135935Ssb155480 9145935Ssb155480 status = vgen_ldcsend_dring(ldcp, mp); 9155935Ssb155480 9165935Ssb155480 return (status); 9175935Ssb155480 } 9185935Ssb155480 9195935Ssb155480 /* 9205935Ssb155480 * This functions handles ldc channel reset while in the context 9215935Ssb155480 * of transmit routines: vgen_ldcsend_pkt() or vgen_ldcsend_dring(). 9225935Ssb155480 */ 9235935Ssb155480 static void 9245935Ssb155480 vgen_ldcsend_process_reset(vgen_ldc_t *ldcp) 9255935Ssb155480 { 9265935Ssb155480 ldc_status_t istatus; 9275935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 9285935Ssb155480 9295935Ssb155480 if (mutex_tryenter(&ldcp->cblock)) { 9305935Ssb155480 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 9315935Ssb155480 DWARN(vgenp, ldcp, "ldc_status() error\n"); 9325935Ssb155480 } else { 9335935Ssb155480 ldcp->ldc_status = istatus; 9345935Ssb155480 } 9355935Ssb155480 if (ldcp->ldc_status != LDC_UP) { 9366495Sspeer vgen_handle_evt_reset(ldcp); 9375935Ssb155480 } 9385935Ssb155480 mutex_exit(&ldcp->cblock); 9395935Ssb155480 } 9405935Ssb155480 } 9415935Ssb155480 9425935Ssb155480 /* 9435935Ssb155480 * This function transmits the frame in the payload of a raw data 9445935Ssb155480 * (VIO_PKT_DATA) message. Thus, it provides an Out-Of-Band path to 9455935Ssb155480 * send special frames with high priorities, without going through 9465935Ssb155480 * the normal data path which uses descriptor ring mechanism. 9475935Ssb155480 */ 9485935Ssb155480 static void 9495935Ssb155480 vgen_ldcsend_pkt(void *arg, mblk_t *mp) 9501991Sheppo { 9515935Ssb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 9525935Ssb155480 vio_raw_data_msg_t *pkt; 9535935Ssb155480 mblk_t *bp; 9545935Ssb155480 mblk_t *nmp = NULL; 9555935Ssb155480 caddr_t dst; 9565935Ssb155480 uint32_t mblksz; 9575935Ssb155480 uint32_t size; 9585935Ssb155480 uint32_t nbytes; 9595935Ssb155480 int rv; 9605935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 9615935Ssb155480 vgen_stats_t *statsp = &ldcp->stats; 9625935Ssb155480 9635935Ssb155480 /* drop the packet if ldc is not up or handshake is not done */ 9645935Ssb155480 if (ldcp->ldc_status != LDC_UP) { 9655935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 9665935Ssb155480 DWARN(vgenp, ldcp, "status(%d), dropping packet\n", 9675935Ssb155480 ldcp->ldc_status); 9685935Ssb155480 goto send_pkt_exit; 9695935Ssb155480 } 9705935Ssb155480 9715935Ssb155480 if (ldcp->hphase != VH_DONE) { 9725935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 9735935Ssb155480 DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n", 9745935Ssb155480 ldcp->hphase); 9755935Ssb155480 goto send_pkt_exit; 9765935Ssb155480 } 9775935Ssb155480 9785935Ssb155480 size = msgsize(mp); 9795935Ssb155480 9805935Ssb155480 /* frame size bigger than available payload len of raw data msg ? */ 9815935Ssb155480 if (size > (size_t)(ldcp->msglen - VIO_PKT_DATA_HDRSIZE)) { 9825935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 9835935Ssb155480 DWARN(vgenp, ldcp, "invalid size(%d)\n", size); 9845935Ssb155480 goto send_pkt_exit; 9855935Ssb155480 } 9865935Ssb155480 9875935Ssb155480 if (size < ETHERMIN) 9885935Ssb155480 size = ETHERMIN; 9895935Ssb155480 9905935Ssb155480 /* alloc space for a raw data message */ 9915935Ssb155480 nmp = vio_allocb(vgenp->pri_tx_vmp); 9925935Ssb155480 if (nmp == NULL) { 9935935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 9945935Ssb155480 DWARN(vgenp, ldcp, "vio_allocb failed\n"); 9955935Ssb155480 goto send_pkt_exit; 9965935Ssb155480 } 9975935Ssb155480 pkt = (vio_raw_data_msg_t *)nmp->b_rptr; 9985935Ssb155480 9995935Ssb155480 /* copy frame into the payload of raw data message */ 10005935Ssb155480 dst = (caddr_t)pkt->data; 10015935Ssb155480 for (bp = mp; bp != NULL; bp = bp->b_cont) { 10025935Ssb155480 mblksz = MBLKL(bp); 10035935Ssb155480 bcopy(bp->b_rptr, dst, mblksz); 10045935Ssb155480 dst += mblksz; 10055935Ssb155480 } 10065935Ssb155480 10075935Ssb155480 /* setup the raw data msg */ 10085935Ssb155480 pkt->tag.vio_msgtype = VIO_TYPE_DATA; 10095935Ssb155480 pkt->tag.vio_subtype = VIO_SUBTYPE_INFO; 10105935Ssb155480 pkt->tag.vio_subtype_env = VIO_PKT_DATA; 10115935Ssb155480 pkt->tag.vio_sid = ldcp->local_sid; 10125935Ssb155480 nbytes = VIO_PKT_DATA_HDRSIZE + size; 10135935Ssb155480 10145935Ssb155480 /* send the msg over ldc */ 10155935Ssb155480 rv = vgen_sendmsg(ldcp, (caddr_t)pkt, nbytes, B_FALSE); 10165935Ssb155480 if (rv != VGEN_SUCCESS) { 10175935Ssb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 10185935Ssb155480 DWARN(vgenp, ldcp, "Error sending priority frame\n"); 10195935Ssb155480 if (rv == ECONNRESET) { 10205935Ssb155480 vgen_ldcsend_process_reset(ldcp); 10215935Ssb155480 } 10225935Ssb155480 goto send_pkt_exit; 10235935Ssb155480 } 10245935Ssb155480 10255935Ssb155480 /* update stats */ 10265935Ssb155480 (void) atomic_inc_64(&statsp->tx_pri_packets); 10275935Ssb155480 (void) atomic_add_64(&statsp->tx_pri_bytes, size); 10285935Ssb155480 10295935Ssb155480 send_pkt_exit: 10305935Ssb155480 if (nmp != NULL) 10315935Ssb155480 freemsg(nmp); 10325935Ssb155480 freemsg(mp); 10335935Ssb155480 } 10345935Ssb155480 10355935Ssb155480 /* 10365935Ssb155480 * This function transmits normal (non-priority) data frames over 10375935Ssb155480 * the channel. It queues the frame into the transmit descriptor ring 10385935Ssb155480 * and sends a VIO_DRING_DATA message if needed, to wake up the 10395935Ssb155480 * peer to (re)start processing. 10405935Ssb155480 */ 10415935Ssb155480 static int 10425935Ssb155480 vgen_ldcsend_dring(void *arg, mblk_t *mp) 10435935Ssb155480 { 10445935Ssb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 10451991Sheppo vgen_private_desc_t *tbufp; 10464647Sraghuram vgen_private_desc_t *rtbufp; 10474647Sraghuram vnet_public_desc_t *rtxdp; 10481991Sheppo vgen_private_desc_t *ntbufp; 10491991Sheppo vnet_public_desc_t *txdp; 10504647Sraghuram vio_dring_entry_hdr_t *hdrp; 10511991Sheppo vgen_stats_t *statsp; 10521991Sheppo struct ether_header *ehp; 10536419Ssb155480 boolean_t is_bcast = B_FALSE; 10546419Ssb155480 boolean_t is_mcast = B_FALSE; 10556419Ssb155480 size_t mblksz; 10566419Ssb155480 caddr_t dst; 10576419Ssb155480 mblk_t *bp; 10586419Ssb155480 size_t size; 10596419Ssb155480 int rv = 0; 10606419Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 10616419Ssb155480 vgen_hparams_t *lp = &ldcp->local_hparams; 10624647Sraghuram 10635373Sraghuram statsp = &ldcp->stats; 10642109Slm66018 size = msgsize(mp); 10652109Slm66018 10664647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 10674647Sraghuram 10682109Slm66018 if (ldcp->ldc_status != LDC_UP) { 10694647Sraghuram DWARN(vgenp, ldcp, "status(%d), dropping packet\n", 10704647Sraghuram ldcp->ldc_status); 10712109Slm66018 /* retry ldc_up() if needed */ 10722109Slm66018 if (ldcp->flags & CHANNEL_STARTED) 10732109Slm66018 (void) ldc_up(ldcp->ldc_handle); 10745935Ssb155480 goto send_dring_exit; 10751991Sheppo } 10761991Sheppo 10774647Sraghuram /* drop the packet if ldc is not up or handshake is not done */ 10782109Slm66018 if (ldcp->hphase != VH_DONE) { 10794647Sraghuram DWARN(vgenp, ldcp, "hphase(%x), dropping packet\n", 10804647Sraghuram ldcp->hphase); 10815935Ssb155480 goto send_dring_exit; 10822109Slm66018 } 10832109Slm66018 10846419Ssb155480 if (size > (size_t)lp->mtu) { 10854647Sraghuram DWARN(vgenp, ldcp, "invalid size(%d)\n", size); 10865935Ssb155480 goto send_dring_exit; 10871991Sheppo } 10884647Sraghuram if (size < ETHERMIN) 10894647Sraghuram size = ETHERMIN; 10904647Sraghuram 10914647Sraghuram ehp = (struct ether_header *)mp->b_rptr; 10924647Sraghuram is_bcast = IS_BROADCAST(ehp); 10934647Sraghuram is_mcast = IS_MULTICAST(ehp); 10944647Sraghuram 10954647Sraghuram mutex_enter(&ldcp->txlock); 10961991Sheppo /* 10971991Sheppo * allocate a descriptor 10981991Sheppo */ 10991991Sheppo tbufp = ldcp->next_tbufp; 11001991Sheppo ntbufp = NEXTTBUF(ldcp, tbufp); 11012336Snarayan if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */ 11021991Sheppo 11031991Sheppo mutex_enter(&ldcp->tclock); 11044647Sraghuram /* Try reclaiming now */ 11054647Sraghuram vgen_reclaim_dring(ldcp); 11064647Sraghuram ldcp->reclaim_lbolt = ddi_get_lbolt(); 11074647Sraghuram 11082336Snarayan if (ntbufp == ldcp->cur_tbufp) { 11094647Sraghuram /* Now we are really out of tbuf/txds */ 11101991Sheppo ldcp->need_resched = B_TRUE; 11112336Snarayan mutex_exit(&ldcp->tclock); 11122336Snarayan 11132336Snarayan statsp->tx_no_desc++; 11142336Snarayan mutex_exit(&ldcp->txlock); 11152336Snarayan 11162336Snarayan return (VGEN_TX_NORESOURCES); 11172336Snarayan } 11181991Sheppo mutex_exit(&ldcp->tclock); 11191991Sheppo } 11204647Sraghuram /* update next available tbuf in the ring and update tx index */ 11214647Sraghuram ldcp->next_tbufp = ntbufp; 11224647Sraghuram INCR_TXI(ldcp->next_txi, ldcp); 11234647Sraghuram 11244647Sraghuram /* Mark the buffer busy before releasing the lock */ 11254647Sraghuram tbufp->flags = VGEN_PRIV_DESC_BUSY; 11264647Sraghuram mutex_exit(&ldcp->txlock); 11272109Slm66018 11282109Slm66018 /* copy data into pre-allocated transmit buffer */ 11292336Snarayan dst = tbufp->datap + VNET_IPALIGN; 11302336Snarayan for (bp = mp; bp != NULL; bp = bp->b_cont) { 11312336Snarayan mblksz = MBLKL(bp); 11322336Snarayan bcopy(bp->b_rptr, dst, mblksz); 11332336Snarayan dst += mblksz; 11341991Sheppo } 11351991Sheppo 11362109Slm66018 tbufp->datalen = size; 11371991Sheppo 11381991Sheppo /* initialize the corresponding public descriptor (txd) */ 11391991Sheppo txdp = tbufp->descp; 11401991Sheppo hdrp = &txdp->hdr; 11412109Slm66018 txdp->nbytes = size; 11422109Slm66018 txdp->ncookies = tbufp->ncookies; 11431991Sheppo bcopy((tbufp->memcookie), (txdp->memcookie), 11444650Sraghuram tbufp->ncookies * sizeof (ldc_mem_cookie_t)); 11454647Sraghuram 11464647Sraghuram mutex_enter(&ldcp->wrlock); 11474647Sraghuram /* 11484647Sraghuram * If the flags not set to BUSY, it implies that the clobber 11494647Sraghuram * was done while we were copying the data. In such case, 11504647Sraghuram * discard the packet and return. 11514647Sraghuram */ 11524647Sraghuram if (tbufp->flags != VGEN_PRIV_DESC_BUSY) { 11534647Sraghuram statsp->oerrors++; 11544647Sraghuram mutex_exit(&ldcp->wrlock); 11555935Ssb155480 goto send_dring_exit; 11564647Sraghuram } 11572336Snarayan hdrp->dstate = VIO_DESC_READY; 11581991Sheppo 11591991Sheppo /* update stats */ 11601991Sheppo statsp->opackets++; 11612109Slm66018 statsp->obytes += size; 11621991Sheppo if (is_bcast) 11631991Sheppo statsp->brdcstxmt++; 11641991Sheppo else if (is_mcast) 11651991Sheppo statsp->multixmt++; 11661991Sheppo 11674647Sraghuram /* send dring datamsg to the peer */ 11684647Sraghuram if (ldcp->resched_peer) { 11694647Sraghuram 11704647Sraghuram rtbufp = &ldcp->tbufp[ldcp->resched_peer_txi]; 11714647Sraghuram rtxdp = rtbufp->descp; 11724647Sraghuram 11734647Sraghuram if (rtxdp->hdr.dstate == VIO_DESC_READY) { 11744647Sraghuram 11754647Sraghuram rv = vgen_send_dring_data(ldcp, 11764647Sraghuram (uint32_t)ldcp->resched_peer_txi, -1); 11774647Sraghuram if (rv != 0) { 11784647Sraghuram /* error: drop the packet */ 11794647Sraghuram DWARN(vgenp, ldcp, "vgen_send_dring_data " 11804650Sraghuram "failed: rv(%d) len(%d)\n", 11814650Sraghuram ldcp->ldc_id, rv, size); 11824647Sraghuram statsp->oerrors++; 11834647Sraghuram } else { 11844647Sraghuram ldcp->resched_peer = B_FALSE; 11854647Sraghuram } 11864647Sraghuram 11874647Sraghuram } 11884647Sraghuram 11894647Sraghuram } 11904647Sraghuram 11914647Sraghuram mutex_exit(&ldcp->wrlock); 11924647Sraghuram 11935935Ssb155480 send_dring_exit: 11942793Slm66018 if (rv == ECONNRESET) { 11955935Ssb155480 vgen_ldcsend_process_reset(ldcp); 11962793Slm66018 } 11972109Slm66018 freemsg(mp); 11984647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 11992109Slm66018 return (VGEN_TX_SUCCESS); 12001991Sheppo } 12011991Sheppo 12021991Sheppo /* enable/disable a multicast address */ 12032311Sseb int 12041991Sheppo vgen_multicst(void *arg, boolean_t add, const uint8_t *mca) 12051991Sheppo { 12061991Sheppo vgen_t *vgenp; 12071991Sheppo vnet_mcast_msg_t mcastmsg; 12081991Sheppo vio_msg_tag_t *tagp; 12091991Sheppo vgen_port_t *portp; 12101991Sheppo vgen_portlist_t *plistp; 12111991Sheppo vgen_ldc_t *ldcp; 12121991Sheppo vgen_ldclist_t *ldclp; 12131991Sheppo struct ether_addr *addrp; 12143653Snarayan int rv = DDI_FAILURE; 12151991Sheppo uint32_t i; 12161991Sheppo 12176495Sspeer portp = (vgen_port_t *)arg; 12186495Sspeer vgenp = portp->vgenp; 12196495Sspeer 12206495Sspeer if (portp != vgenp->vsw_portp) { 12216495Sspeer return (DDI_SUCCESS); 12226495Sspeer } 12236495Sspeer 12241991Sheppo addrp = (struct ether_addr *)mca; 12251991Sheppo tagp = &mcastmsg.tag; 12261991Sheppo bzero(&mcastmsg, sizeof (mcastmsg)); 12271991Sheppo 12281991Sheppo mutex_enter(&vgenp->lock); 12291991Sheppo 12301991Sheppo plistp = &(vgenp->vgenports); 12311991Sheppo 12321991Sheppo READ_ENTER(&plistp->rwlock); 12331991Sheppo 12341991Sheppo portp = vgenp->vsw_portp; 12351991Sheppo if (portp == NULL) { 12361991Sheppo RW_EXIT(&plistp->rwlock); 12373653Snarayan mutex_exit(&vgenp->lock); 12383653Snarayan return (rv); 12391991Sheppo } 12401991Sheppo ldclp = &portp->ldclist; 12411991Sheppo 12421991Sheppo READ_ENTER(&ldclp->rwlock); 12431991Sheppo 12441991Sheppo ldcp = ldclp->headp; 12453653Snarayan if (ldcp == NULL) 12461991Sheppo goto vgen_mcast_exit; 12471991Sheppo 12481991Sheppo mutex_enter(&ldcp->cblock); 12491991Sheppo 12501991Sheppo if (ldcp->hphase == VH_DONE) { 12511991Sheppo /* 12521991Sheppo * If handshake is done, send a msg to vsw to add/remove 12535171Ssb155480 * the multicast address. Otherwise, we just update this 12545171Ssb155480 * mcast address in our table and the table will be sync'd 12555171Ssb155480 * with vsw when handshake completes. 12561991Sheppo */ 12571991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 12581991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 12591991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 12601991Sheppo tagp->vio_sid = ldcp->local_sid; 12611991Sheppo bcopy(mca, &(mcastmsg.mca), ETHERADDRL); 12621991Sheppo mcastmsg.set = add; 12631991Sheppo mcastmsg.count = 1; 12643653Snarayan if (vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (mcastmsg), 12653653Snarayan B_FALSE) != VGEN_SUCCESS) { 12664647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 12673653Snarayan mutex_exit(&ldcp->cblock); 12683653Snarayan goto vgen_mcast_exit; 12691991Sheppo } 12701991Sheppo } 12711991Sheppo 12721991Sheppo mutex_exit(&ldcp->cblock); 12731991Sheppo 12741991Sheppo if (add) { 12751991Sheppo 12761991Sheppo /* expand multicast table if necessary */ 12771991Sheppo if (vgenp->mccount >= vgenp->mcsize) { 12781991Sheppo struct ether_addr *newtab; 12791991Sheppo uint32_t newsize; 12801991Sheppo 12811991Sheppo 12821991Sheppo newsize = vgenp->mcsize * 2; 12831991Sheppo 12841991Sheppo newtab = kmem_zalloc(newsize * 12851991Sheppo sizeof (struct ether_addr), KM_NOSLEEP); 12863653Snarayan if (newtab == NULL) 12873653Snarayan goto vgen_mcast_exit; 12881991Sheppo bcopy(vgenp->mctab, newtab, vgenp->mcsize * 12891991Sheppo sizeof (struct ether_addr)); 12901991Sheppo kmem_free(vgenp->mctab, 12911991Sheppo vgenp->mcsize * sizeof (struct ether_addr)); 12921991Sheppo 12931991Sheppo vgenp->mctab = newtab; 12941991Sheppo vgenp->mcsize = newsize; 12951991Sheppo } 12961991Sheppo 12971991Sheppo /* add address to the table */ 12981991Sheppo vgenp->mctab[vgenp->mccount++] = *addrp; 12991991Sheppo 13001991Sheppo } else { 13011991Sheppo 13021991Sheppo /* delete address from the table */ 13031991Sheppo for (i = 0; i < vgenp->mccount; i++) { 13041991Sheppo if (ether_cmp(addrp, &(vgenp->mctab[i])) == 0) { 13051991Sheppo 13061991Sheppo /* 13071991Sheppo * If there's more than one address in this 13081991Sheppo * table, delete the unwanted one by moving 13091991Sheppo * the last one in the list over top of it; 13101991Sheppo * otherwise, just remove it. 13111991Sheppo */ 13121991Sheppo if (vgenp->mccount > 1) { 13131991Sheppo vgenp->mctab[i] = 13144650Sraghuram vgenp->mctab[vgenp->mccount-1]; 13151991Sheppo } 13161991Sheppo vgenp->mccount--; 13171991Sheppo break; 13181991Sheppo } 13191991Sheppo } 13201991Sheppo } 13211991Sheppo 13223653Snarayan rv = DDI_SUCCESS; 13233653Snarayan 13243653Snarayan vgen_mcast_exit: 13251991Sheppo RW_EXIT(&ldclp->rwlock); 13261991Sheppo RW_EXIT(&plistp->rwlock); 13271991Sheppo 13281991Sheppo mutex_exit(&vgenp->lock); 13293653Snarayan return (rv); 13301991Sheppo } 13311991Sheppo 13321991Sheppo /* set or clear promiscuous mode on the device */ 13331991Sheppo static int 13341991Sheppo vgen_promisc(void *arg, boolean_t on) 13351991Sheppo { 13361991Sheppo _NOTE(ARGUNUSED(arg, on)) 13371991Sheppo return (DDI_SUCCESS); 13381991Sheppo } 13391991Sheppo 13401991Sheppo /* set the unicast mac address of the device */ 13411991Sheppo static int 13421991Sheppo vgen_unicst(void *arg, const uint8_t *mca) 13431991Sheppo { 13441991Sheppo _NOTE(ARGUNUSED(arg, mca)) 13451991Sheppo return (DDI_SUCCESS); 13461991Sheppo } 13471991Sheppo 13481991Sheppo /* get device statistics */ 13492311Sseb int 13502311Sseb vgen_stat(void *arg, uint_t stat, uint64_t *val) 13511991Sheppo { 13526495Sspeer vgen_port_t *portp = (vgen_port_t *)arg; 13536495Sspeer 13546495Sspeer *val = vgen_port_stat(portp, stat); 13551991Sheppo 13562311Sseb return (0); 13571991Sheppo } 13581991Sheppo 13591991Sheppo static void 13601991Sheppo vgen_ioctl(void *arg, queue_t *wq, mblk_t *mp) 13611991Sheppo { 13621991Sheppo _NOTE(ARGUNUSED(arg, wq, mp)) 13631991Sheppo } 13641991Sheppo 13651991Sheppo /* vgen internal functions */ 13661991Sheppo /* detach all ports from the device */ 13671991Sheppo static void 13681991Sheppo vgen_detach_ports(vgen_t *vgenp) 13691991Sheppo { 13701991Sheppo vgen_port_t *portp; 13711991Sheppo vgen_portlist_t *plistp; 13721991Sheppo 13731991Sheppo plistp = &(vgenp->vgenports); 13741991Sheppo WRITE_ENTER(&plistp->rwlock); 13751991Sheppo while ((portp = plistp->headp) != NULL) { 13761991Sheppo vgen_port_detach(portp); 13771991Sheppo } 13781991Sheppo RW_EXIT(&plistp->rwlock); 13791991Sheppo } 13801991Sheppo 13811991Sheppo /* 13821991Sheppo * detach the given port. 13831991Sheppo */ 13841991Sheppo static void 13851991Sheppo vgen_port_detach(vgen_port_t *portp) 13861991Sheppo { 13871991Sheppo vgen_t *vgenp; 13881991Sheppo vgen_ldclist_t *ldclp; 13891991Sheppo int port_num; 13901991Sheppo 13911991Sheppo vgenp = portp->vgenp; 13921991Sheppo port_num = portp->port_num; 13931991Sheppo 13944647Sraghuram DBG1(vgenp, NULL, "port(%d):enter\n", port_num); 13951991Sheppo 13966495Sspeer /* 13976495Sspeer * If this port is connected to the vswitch, then 13986495Sspeer * potentially there could be ports that may be using 13996495Sspeer * this port to transmit packets. To address this do 14006495Sspeer * the following: 14016495Sspeer * - First set vgenp->vsw_portp to NULL, so that 14026495Sspeer * its not used after that. 14036495Sspeer * - Then wait for the refcnt to go down to 0. 14046495Sspeer * - Now we can safely detach this port. 14056495Sspeer */ 14066495Sspeer if (vgenp->vsw_portp == portp) { 14076495Sspeer vgenp->vsw_portp = NULL; 14086495Sspeer while (vgenp->vsw_port_refcnt > 0) { 14096495Sspeer delay(drv_usectohz(vgen_tx_delay)); 14106495Sspeer } 14116495Sspeer (void) atomic_swap_32(&vgenp->vsw_port_refcnt, 0); 14126495Sspeer } 14136495Sspeer 14146495Sspeer if (portp->vhp != NULL) { 14156495Sspeer vio_net_resource_unreg(portp->vhp); 14166495Sspeer portp->vhp = NULL; 14176495Sspeer } 14186495Sspeer 14196419Ssb155480 vgen_vlan_destroy_hash(portp); 14206419Ssb155480 14211991Sheppo /* remove it from port list */ 14221991Sheppo vgen_port_list_remove(portp); 14231991Sheppo 14241991Sheppo /* detach channels from this port */ 14251991Sheppo ldclp = &portp->ldclist; 14261991Sheppo WRITE_ENTER(&ldclp->rwlock); 14271991Sheppo while (ldclp->headp) { 14281991Sheppo vgen_ldc_detach(ldclp->headp); 14291991Sheppo } 14301991Sheppo RW_EXIT(&ldclp->rwlock); 14315641Swentaoy rw_destroy(&ldclp->rwlock); 14321991Sheppo 14336419Ssb155480 if (portp->num_ldcs != 0) { 14346419Ssb155480 kmem_free(portp->ldc_ids, portp->num_ldcs * sizeof (uint64_t)); 14356419Ssb155480 portp->num_ldcs = 0; 14366419Ssb155480 } 14376419Ssb155480 14386495Sspeer mutex_destroy(&portp->lock); 14391991Sheppo KMEM_FREE(portp); 14401991Sheppo 14414647Sraghuram DBG1(vgenp, NULL, "port(%d):exit\n", port_num); 14421991Sheppo } 14431991Sheppo 14441991Sheppo /* add a port to port list */ 14451991Sheppo static void 14461991Sheppo vgen_port_list_insert(vgen_port_t *portp) 14471991Sheppo { 14481991Sheppo vgen_portlist_t *plistp; 14491991Sheppo vgen_t *vgenp; 14501991Sheppo 14511991Sheppo vgenp = portp->vgenp; 14521991Sheppo plistp = &(vgenp->vgenports); 14531991Sheppo 14541991Sheppo if (plistp->headp == NULL) { 14551991Sheppo plistp->headp = portp; 14561991Sheppo } else { 14571991Sheppo plistp->tailp->nextp = portp; 14581991Sheppo } 14591991Sheppo plistp->tailp = portp; 14601991Sheppo portp->nextp = NULL; 14611991Sheppo } 14621991Sheppo 14631991Sheppo /* remove a port from port list */ 14641991Sheppo static void 14651991Sheppo vgen_port_list_remove(vgen_port_t *portp) 14661991Sheppo { 14671991Sheppo vgen_port_t *prevp; 14681991Sheppo vgen_port_t *nextp; 14691991Sheppo vgen_portlist_t *plistp; 14701991Sheppo vgen_t *vgenp; 14711991Sheppo 14721991Sheppo vgenp = portp->vgenp; 14731991Sheppo 14741991Sheppo plistp = &(vgenp->vgenports); 14751991Sheppo 14761991Sheppo if (plistp->headp == NULL) 14771991Sheppo return; 14781991Sheppo 14791991Sheppo if (portp == plistp->headp) { 14801991Sheppo plistp->headp = portp->nextp; 14811991Sheppo if (portp == plistp->tailp) 14821991Sheppo plistp->tailp = plistp->headp; 14831991Sheppo } else { 14844650Sraghuram for (prevp = plistp->headp; 14854650Sraghuram ((nextp = prevp->nextp) != NULL) && (nextp != portp); 14864650Sraghuram prevp = nextp) 14874650Sraghuram ; 14881991Sheppo if (nextp == portp) { 14891991Sheppo prevp->nextp = portp->nextp; 14901991Sheppo } 14911991Sheppo if (portp == plistp->tailp) 14921991Sheppo plistp->tailp = prevp; 14931991Sheppo } 14941991Sheppo } 14951991Sheppo 14961991Sheppo /* lookup a port in the list based on port_num */ 14971991Sheppo static vgen_port_t * 14981991Sheppo vgen_port_lookup(vgen_portlist_t *plistp, int port_num) 14991991Sheppo { 15001991Sheppo vgen_port_t *portp = NULL; 15011991Sheppo 15021991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 15031991Sheppo if (portp->port_num == port_num) { 15041991Sheppo break; 15051991Sheppo } 15061991Sheppo } 15071991Sheppo 15081991Sheppo return (portp); 15091991Sheppo } 15101991Sheppo 15111991Sheppo /* enable ports for transmit/receive */ 15121991Sheppo static void 15131991Sheppo vgen_init_ports(vgen_t *vgenp) 15141991Sheppo { 15151991Sheppo vgen_port_t *portp; 15161991Sheppo vgen_portlist_t *plistp; 15171991Sheppo 15181991Sheppo plistp = &(vgenp->vgenports); 15191991Sheppo READ_ENTER(&plistp->rwlock); 15201991Sheppo 15211991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 15221991Sheppo vgen_port_init(portp); 15231991Sheppo } 15241991Sheppo 15251991Sheppo RW_EXIT(&plistp->rwlock); 15261991Sheppo } 15271991Sheppo 15281991Sheppo static void 15291991Sheppo vgen_port_init(vgen_port_t *portp) 15301991Sheppo { 15316419Ssb155480 /* Add the port to the specified vlans */ 15326419Ssb155480 vgen_vlan_add_ids(portp); 15331991Sheppo 15341991Sheppo /* Bring up the channels of this port */ 15351991Sheppo vgen_init_ldcs(portp); 15361991Sheppo } 15371991Sheppo 15381991Sheppo /* disable transmit/receive on ports */ 15391991Sheppo static void 15401991Sheppo vgen_uninit_ports(vgen_t *vgenp) 15411991Sheppo { 15421991Sheppo vgen_port_t *portp; 15431991Sheppo vgen_portlist_t *plistp; 15441991Sheppo 15451991Sheppo plistp = &(vgenp->vgenports); 15461991Sheppo READ_ENTER(&plistp->rwlock); 15471991Sheppo 15481991Sheppo for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 15491991Sheppo vgen_port_uninit(portp); 15501991Sheppo } 15511991Sheppo 15521991Sheppo RW_EXIT(&plistp->rwlock); 15531991Sheppo } 15541991Sheppo 15551991Sheppo static void 15561991Sheppo vgen_port_uninit(vgen_port_t *portp) 15571991Sheppo { 15581991Sheppo vgen_uninit_ldcs(portp); 15596419Ssb155480 15606419Ssb155480 /* remove the port from vlans it has been assigned to */ 15616419Ssb155480 vgen_vlan_remove_ids(portp); 15621991Sheppo } 15631991Sheppo 15645935Ssb155480 /* 15655935Ssb155480 * Scan the machine description for this instance of vnet 15665935Ssb155480 * and read its properties. Called only from vgen_init(). 15675935Ssb155480 * Returns: 0 on success, 1 on failure. 15685935Ssb155480 */ 15695935Ssb155480 static int 15705935Ssb155480 vgen_read_mdprops(vgen_t *vgenp) 15715935Ssb155480 { 15726419Ssb155480 vnet_t *vnetp = vgenp->vnetp; 15735935Ssb155480 md_t *mdp = NULL; 15745935Ssb155480 mde_cookie_t rootnode; 15755935Ssb155480 mde_cookie_t *listp = NULL; 15765935Ssb155480 uint64_t cfgh; 15775935Ssb155480 char *name; 15785935Ssb155480 int rv = 1; 15795935Ssb155480 int num_nodes = 0; 15805935Ssb155480 int num_devs = 0; 15815935Ssb155480 int listsz = 0; 15825935Ssb155480 int i; 15835935Ssb155480 15845935Ssb155480 if ((mdp = md_get_handle()) == NULL) { 15855935Ssb155480 return (rv); 15865935Ssb155480 } 15875935Ssb155480 15885935Ssb155480 num_nodes = md_node_count(mdp); 15895935Ssb155480 ASSERT(num_nodes > 0); 15905935Ssb155480 15915935Ssb155480 listsz = num_nodes * sizeof (mde_cookie_t); 15925935Ssb155480 listp = (mde_cookie_t *)kmem_zalloc(listsz, KM_SLEEP); 15935935Ssb155480 15945935Ssb155480 rootnode = md_root_node(mdp); 15955935Ssb155480 15965935Ssb155480 /* search for all "virtual_device" nodes */ 15975935Ssb155480 num_devs = md_scan_dag(mdp, rootnode, 15985935Ssb155480 md_find_name(mdp, vdev_propname), 15995935Ssb155480 md_find_name(mdp, "fwd"), listp); 16005935Ssb155480 if (num_devs <= 0) { 16015935Ssb155480 goto vgen_readmd_exit; 16025935Ssb155480 } 16035935Ssb155480 16045935Ssb155480 /* 16055935Ssb155480 * Now loop through the list of virtual-devices looking for 16065935Ssb155480 * devices with name "network" and for each such device compare 16075935Ssb155480 * its instance with what we have from the 'reg' property to 16085935Ssb155480 * find the right node in MD and then read all its properties. 16095935Ssb155480 */ 16105935Ssb155480 for (i = 0; i < num_devs; i++) { 16115935Ssb155480 16125935Ssb155480 if (md_get_prop_str(mdp, listp[i], "name", &name) != 0) { 16135935Ssb155480 goto vgen_readmd_exit; 16145935Ssb155480 } 16155935Ssb155480 16165935Ssb155480 /* is this a "network" device? */ 16175935Ssb155480 if (strcmp(name, vnet_propname) != 0) 16185935Ssb155480 continue; 16195935Ssb155480 16205935Ssb155480 if (md_get_prop_val(mdp, listp[i], "cfg-handle", &cfgh) != 0) { 16215935Ssb155480 goto vgen_readmd_exit; 16225935Ssb155480 } 16235935Ssb155480 16245935Ssb155480 /* is this the required instance of vnet? */ 16256495Sspeer if (vgenp->regprop != cfgh) 16265935Ssb155480 continue; 16275935Ssb155480 16287529SSriharsha.Basavapatna@Sun.COM /* 16297529SSriharsha.Basavapatna@Sun.COM * Read the mtu. Note that we set the mtu of vnet device within 16307529SSriharsha.Basavapatna@Sun.COM * this routine itself, after validating the range. 16317529SSriharsha.Basavapatna@Sun.COM */ 16327529SSriharsha.Basavapatna@Sun.COM vgen_mtu_read(vgenp, mdp, listp[i], &vnetp->mtu); 16337529SSriharsha.Basavapatna@Sun.COM if (vnetp->mtu < ETHERMTU || vnetp->mtu > VNET_MAX_MTU) { 16347529SSriharsha.Basavapatna@Sun.COM vnetp->mtu = ETHERMTU; 16357529SSriharsha.Basavapatna@Sun.COM } 16367529SSriharsha.Basavapatna@Sun.COM vgenp->max_frame_size = vnetp->mtu + 16377529SSriharsha.Basavapatna@Sun.COM sizeof (struct ether_header) + VLAN_TAGSZ; 16387529SSriharsha.Basavapatna@Sun.COM 16397529SSriharsha.Basavapatna@Sun.COM /* read priority ether types */ 16405935Ssb155480 vgen_read_pri_eth_types(vgenp, mdp, listp[i]); 16416419Ssb155480 16426419Ssb155480 /* read vlan id properties of this vnet instance */ 16436419Ssb155480 vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, listp[i], 16446419Ssb155480 &vnetp->pvid, &vnetp->vids, &vnetp->nvids, 16456419Ssb155480 &vnetp->default_vlan_id); 16466419Ssb155480 16475935Ssb155480 rv = 0; 16485935Ssb155480 break; 16495935Ssb155480 } 16505935Ssb155480 16515935Ssb155480 vgen_readmd_exit: 16525935Ssb155480 16535935Ssb155480 kmem_free(listp, listsz); 16545935Ssb155480 (void) md_fini_handle(mdp); 16555935Ssb155480 return (rv); 16565935Ssb155480 } 16575935Ssb155480 16585935Ssb155480 /* 16596419Ssb155480 * Read vlan id properties of the given MD node. 16606419Ssb155480 * Arguments: 16616419Ssb155480 * arg: device argument(vnet device or a port) 16626419Ssb155480 * type: type of arg; VGEN_LOCAL(vnet device) or VGEN_PEER(port) 16636419Ssb155480 * mdp: machine description 16646419Ssb155480 * node: md node cookie 16656419Ssb155480 * 16666419Ssb155480 * Returns: 16676419Ssb155480 * pvidp: port-vlan-id of the node 16686419Ssb155480 * vidspp: list of vlan-ids of the node 16696419Ssb155480 * nvidsp: # of vlan-ids in the list 16706419Ssb155480 * default_idp: default-vlan-id of the node(if node is vnet device) 16716419Ssb155480 */ 16726419Ssb155480 static void 16736419Ssb155480 vgen_vlan_read_ids(void *arg, int type, md_t *mdp, mde_cookie_t node, 16746419Ssb155480 uint16_t *pvidp, uint16_t **vidspp, uint16_t *nvidsp, 16756419Ssb155480 uint16_t *default_idp) 16766419Ssb155480 { 16776419Ssb155480 vgen_t *vgenp; 16786419Ssb155480 vnet_t *vnetp; 16796419Ssb155480 vgen_port_t *portp; 16806419Ssb155480 char *pvid_propname; 16816419Ssb155480 char *vid_propname; 16826419Ssb155480 uint_t nvids; 16836419Ssb155480 uint32_t vids_size; 16846419Ssb155480 int rv; 16856419Ssb155480 int i; 16866419Ssb155480 uint64_t *data; 16876419Ssb155480 uint64_t val; 16886419Ssb155480 int size; 16896419Ssb155480 int inst; 16906419Ssb155480 16916419Ssb155480 if (type == VGEN_LOCAL) { 16926419Ssb155480 16936419Ssb155480 vgenp = (vgen_t *)arg; 16946419Ssb155480 vnetp = vgenp->vnetp; 16956419Ssb155480 pvid_propname = vgen_pvid_propname; 16966419Ssb155480 vid_propname = vgen_vid_propname; 16976419Ssb155480 inst = vnetp->instance; 16986419Ssb155480 16996419Ssb155480 } else if (type == VGEN_PEER) { 17006419Ssb155480 17016419Ssb155480 portp = (vgen_port_t *)arg; 17026419Ssb155480 vgenp = portp->vgenp; 17036419Ssb155480 vnetp = vgenp->vnetp; 17046419Ssb155480 pvid_propname = port_pvid_propname; 17056419Ssb155480 vid_propname = port_vid_propname; 17066419Ssb155480 inst = portp->port_num; 17076419Ssb155480 17086419Ssb155480 } else { 17096419Ssb155480 return; 17106419Ssb155480 } 17116419Ssb155480 17126419Ssb155480 if (type == VGEN_LOCAL && default_idp != NULL) { 17136419Ssb155480 rv = md_get_prop_val(mdp, node, vgen_dvid_propname, &val); 17146419Ssb155480 if (rv != 0) { 17156419Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found", 17166419Ssb155480 vgen_dvid_propname); 17176419Ssb155480 17186419Ssb155480 *default_idp = vnet_default_vlan_id; 17196419Ssb155480 } else { 17206419Ssb155480 *default_idp = val & 0xFFF; 17216419Ssb155480 DBG2(vgenp, NULL, "%s(%d): (%d)\n", vgen_dvid_propname, 17226419Ssb155480 inst, *default_idp); 17236419Ssb155480 } 17246419Ssb155480 } 17256419Ssb155480 17266419Ssb155480 rv = md_get_prop_val(mdp, node, pvid_propname, &val); 17276419Ssb155480 if (rv != 0) { 17286419Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found", pvid_propname); 17296419Ssb155480 *pvidp = vnet_default_vlan_id; 17306419Ssb155480 } else { 17316419Ssb155480 17326419Ssb155480 *pvidp = val & 0xFFF; 17336419Ssb155480 DBG2(vgenp, NULL, "%s(%d): (%d)\n", 17346419Ssb155480 pvid_propname, inst, *pvidp); 17356419Ssb155480 } 17366419Ssb155480 17376419Ssb155480 rv = md_get_prop_data(mdp, node, vid_propname, (uint8_t **)&data, 17386419Ssb155480 &size); 17396419Ssb155480 if (rv != 0) { 17406419Ssb155480 DBG2(vgenp, NULL, "prop(%s) not found", vid_propname); 17416419Ssb155480 size = 0; 17426419Ssb155480 } else { 17436419Ssb155480 size /= sizeof (uint64_t); 17446419Ssb155480 } 17456419Ssb155480 nvids = size; 17466419Ssb155480 17476419Ssb155480 if (nvids != 0) { 17486419Ssb155480 DBG2(vgenp, NULL, "%s(%d): ", vid_propname, inst); 17496419Ssb155480 vids_size = sizeof (uint16_t) * nvids; 17506419Ssb155480 *vidspp = kmem_zalloc(vids_size, KM_SLEEP); 17516419Ssb155480 for (i = 0; i < nvids; i++) { 17526419Ssb155480 (*vidspp)[i] = data[i] & 0xFFFF; 17536419Ssb155480 DBG2(vgenp, NULL, " %d ", (*vidspp)[i]); 17546419Ssb155480 } 17556419Ssb155480 DBG2(vgenp, NULL, "\n"); 17566419Ssb155480 } 17576419Ssb155480 17586419Ssb155480 *nvidsp = nvids; 17596419Ssb155480 } 17606419Ssb155480 17616419Ssb155480 /* 17626419Ssb155480 * Create a vlan id hash table for the given port. 17636419Ssb155480 */ 17646419Ssb155480 static void 17656419Ssb155480 vgen_vlan_create_hash(vgen_port_t *portp) 17666419Ssb155480 { 17676419Ssb155480 char hashname[MAXNAMELEN]; 17686419Ssb155480 17696419Ssb155480 (void) snprintf(hashname, MAXNAMELEN, "port%d-vlan-hash", 17706419Ssb155480 portp->port_num); 17716419Ssb155480 17726419Ssb155480 portp->vlan_nchains = vgen_vlan_nchains; 17736419Ssb155480 portp->vlan_hashp = mod_hash_create_idhash(hashname, 17746419Ssb155480 portp->vlan_nchains, mod_hash_null_valdtor); 17756419Ssb155480 } 17766419Ssb155480 17776419Ssb155480 /* 17786419Ssb155480 * Destroy the vlan id hash table in the given port. 17796419Ssb155480 */ 17806419Ssb155480 static void 17816419Ssb155480 vgen_vlan_destroy_hash(vgen_port_t *portp) 17826419Ssb155480 { 17836419Ssb155480 if (portp->vlan_hashp != NULL) { 17846419Ssb155480 mod_hash_destroy_hash(portp->vlan_hashp); 17856419Ssb155480 portp->vlan_hashp = NULL; 17866419Ssb155480 portp->vlan_nchains = 0; 17876419Ssb155480 } 17886419Ssb155480 } 17896419Ssb155480 17906419Ssb155480 /* 17916419Ssb155480 * Add a port to the vlans specified in its port properites. 17926419Ssb155480 */ 17936419Ssb155480 static void 17946419Ssb155480 vgen_vlan_add_ids(vgen_port_t *portp) 17956419Ssb155480 { 17966419Ssb155480 int rv; 17976419Ssb155480 int i; 17986419Ssb155480 17996419Ssb155480 rv = mod_hash_insert(portp->vlan_hashp, 18006419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid), 18016419Ssb155480 (mod_hash_val_t)B_TRUE); 18026419Ssb155480 ASSERT(rv == 0); 18036419Ssb155480 18046419Ssb155480 for (i = 0; i < portp->nvids; i++) { 18056419Ssb155480 rv = mod_hash_insert(portp->vlan_hashp, 18066419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]), 18076419Ssb155480 (mod_hash_val_t)B_TRUE); 18086419Ssb155480 ASSERT(rv == 0); 18096419Ssb155480 } 18106419Ssb155480 } 18116419Ssb155480 18126419Ssb155480 /* 18136419Ssb155480 * Remove a port from the vlans it has been assigned to. 18146419Ssb155480 */ 18156419Ssb155480 static void 18166419Ssb155480 vgen_vlan_remove_ids(vgen_port_t *portp) 18176419Ssb155480 { 18186419Ssb155480 int rv; 18196419Ssb155480 int i; 18206419Ssb155480 mod_hash_val_t vp; 18216419Ssb155480 18226419Ssb155480 rv = mod_hash_remove(portp->vlan_hashp, 18236419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->pvid), 18246419Ssb155480 (mod_hash_val_t *)&vp); 18256419Ssb155480 ASSERT(rv == 0); 18266419Ssb155480 18276419Ssb155480 for (i = 0; i < portp->nvids; i++) { 18286419Ssb155480 rv = mod_hash_remove(portp->vlan_hashp, 18296419Ssb155480 (mod_hash_key_t)VLAN_ID_KEY(portp->vids[i]), 18306419Ssb155480 (mod_hash_val_t *)&vp); 18316419Ssb155480 ASSERT(rv == 0); 18326419Ssb155480 } 18336419Ssb155480 } 18346419Ssb155480 18356419Ssb155480 /* 18366419Ssb155480 * Lookup the vlan id of the given tx frame. If it is a vlan-tagged frame, 18376419Ssb155480 * then the vlan-id is available in the tag; otherwise, its vlan id is 18386419Ssb155480 * implicitly obtained from the port-vlan-id of the vnet device. 18396419Ssb155480 * The vlan id determined is returned in vidp. 18406419Ssb155480 * Returns: B_TRUE if it is a tagged frame; B_FALSE if it is untagged. 18416419Ssb155480 */ 18426419Ssb155480 static boolean_t 18436419Ssb155480 vgen_frame_lookup_vid(vnet_t *vnetp, struct ether_header *ehp, uint16_t *vidp) 18446419Ssb155480 { 18456419Ssb155480 struct ether_vlan_header *evhp; 18466419Ssb155480 18476419Ssb155480 /* If it's a tagged frame, get the vlan id from vlan header */ 18486419Ssb155480 if (ehp->ether_type == ETHERTYPE_VLAN) { 18496419Ssb155480 18506419Ssb155480 evhp = (struct ether_vlan_header *)ehp; 18516419Ssb155480 *vidp = VLAN_ID(ntohs(evhp->ether_tci)); 18526419Ssb155480 return (B_TRUE); 18536419Ssb155480 } 18546419Ssb155480 18556419Ssb155480 /* Untagged frame, vlan-id is the pvid of vnet device */ 18566419Ssb155480 *vidp = vnetp->pvid; 18576419Ssb155480 return (B_FALSE); 18586419Ssb155480 } 18596419Ssb155480 18606419Ssb155480 /* 18616419Ssb155480 * Find the given vlan id in the hash table. 18626419Ssb155480 * Return: B_TRUE if the id is found; B_FALSE if not found. 18636419Ssb155480 */ 18646419Ssb155480 static boolean_t 18656419Ssb155480 vgen_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid) 18666419Ssb155480 { 18676419Ssb155480 int rv; 18686419Ssb155480 mod_hash_val_t vp; 18696419Ssb155480 18706419Ssb155480 rv = mod_hash_find(vlan_hashp, VLAN_ID_KEY(vid), (mod_hash_val_t *)&vp); 18716419Ssb155480 18726419Ssb155480 if (rv != 0) 18736419Ssb155480 return (B_FALSE); 18746419Ssb155480 18756419Ssb155480 return (B_TRUE); 18766419Ssb155480 } 18776419Ssb155480 18786419Ssb155480 /* 18795935Ssb155480 * This function reads "priority-ether-types" property from md. This property 18805935Ssb155480 * is used to enable support for priority frames. Applications which need 18815935Ssb155480 * guaranteed and timely delivery of certain high priority frames to/from 18825935Ssb155480 * a vnet or vsw within ldoms, should configure this property by providing 18835935Ssb155480 * the ether type(s) for which the priority facility is needed. 18845935Ssb155480 * Normal data frames are delivered over a ldc channel using the descriptor 18855935Ssb155480 * ring mechanism which is constrained by factors such as descriptor ring size, 18865935Ssb155480 * the rate at which the ring is processed at the peer ldc end point, etc. 18875935Ssb155480 * The priority mechanism provides an Out-Of-Band path to send/receive frames 18885935Ssb155480 * as raw pkt data (VIO_PKT_DATA) messages over the channel, avoiding the 18895935Ssb155480 * descriptor ring path and enables a more reliable and timely delivery of 18905935Ssb155480 * frames to the peer. 18915935Ssb155480 */ 18925935Ssb155480 static void 18935935Ssb155480 vgen_read_pri_eth_types(vgen_t *vgenp, md_t *mdp, mde_cookie_t node) 18945935Ssb155480 { 18955935Ssb155480 int rv; 18965935Ssb155480 uint16_t *types; 18975935Ssb155480 uint64_t *data; 18985935Ssb155480 int size; 18995935Ssb155480 int i; 19005935Ssb155480 size_t mblk_sz; 19015935Ssb155480 19025935Ssb155480 rv = md_get_prop_data(mdp, node, pri_types_propname, 19035935Ssb155480 (uint8_t **)&data, &size); 19045935Ssb155480 if (rv != 0) { 19055935Ssb155480 /* 19065935Ssb155480 * Property may not exist if we are running pre-ldoms1.1 f/w. 19075935Ssb155480 * Check if 'vgen_pri_eth_type' has been set in that case. 19085935Ssb155480 */ 19095935Ssb155480 if (vgen_pri_eth_type != 0) { 19105935Ssb155480 size = sizeof (vgen_pri_eth_type); 19115935Ssb155480 data = &vgen_pri_eth_type; 19125935Ssb155480 } else { 19136495Sspeer DBG2(vgenp, NULL, 19145935Ssb155480 "prop(%s) not found", pri_types_propname); 19155935Ssb155480 size = 0; 19165935Ssb155480 } 19175935Ssb155480 } 19185935Ssb155480 19195935Ssb155480 if (size == 0) { 19205935Ssb155480 vgenp->pri_num_types = 0; 19215935Ssb155480 return; 19225935Ssb155480 } 19235935Ssb155480 19245935Ssb155480 /* 19255935Ssb155480 * we have some priority-ether-types defined; 19265935Ssb155480 * allocate a table of these types and also 19275935Ssb155480 * allocate a pool of mblks to transmit these 19285935Ssb155480 * priority packets. 19295935Ssb155480 */ 19305935Ssb155480 size /= sizeof (uint64_t); 19315935Ssb155480 vgenp->pri_num_types = size; 19325935Ssb155480 vgenp->pri_types = kmem_zalloc(size * sizeof (uint16_t), KM_SLEEP); 19335935Ssb155480 for (i = 0, types = vgenp->pri_types; i < size; i++) { 19345935Ssb155480 types[i] = data[i] & 0xFFFF; 19355935Ssb155480 } 19366419Ssb155480 mblk_sz = (VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size + 7) & ~7; 19375935Ssb155480 (void) vio_create_mblks(vgen_pri_tx_nmblks, mblk_sz, 19385935Ssb155480 &vgenp->pri_tx_vmp); 19395935Ssb155480 } 19405935Ssb155480 19417529SSriharsha.Basavapatna@Sun.COM static void 19427529SSriharsha.Basavapatna@Sun.COM vgen_mtu_read(vgen_t *vgenp, md_t *mdp, mde_cookie_t node, uint32_t *mtu) 19437529SSriharsha.Basavapatna@Sun.COM { 19447529SSriharsha.Basavapatna@Sun.COM int rv; 19457529SSriharsha.Basavapatna@Sun.COM uint64_t val; 19467529SSriharsha.Basavapatna@Sun.COM char *mtu_propname; 19477529SSriharsha.Basavapatna@Sun.COM 19487529SSriharsha.Basavapatna@Sun.COM mtu_propname = vgen_mtu_propname; 19497529SSriharsha.Basavapatna@Sun.COM 19507529SSriharsha.Basavapatna@Sun.COM rv = md_get_prop_val(mdp, node, mtu_propname, &val); 19517529SSriharsha.Basavapatna@Sun.COM if (rv != 0) { 19527529SSriharsha.Basavapatna@Sun.COM DWARN(vgenp, NULL, "prop(%s) not found", mtu_propname); 19537529SSriharsha.Basavapatna@Sun.COM *mtu = vnet_ethermtu; 19547529SSriharsha.Basavapatna@Sun.COM } else { 19557529SSriharsha.Basavapatna@Sun.COM 19567529SSriharsha.Basavapatna@Sun.COM *mtu = val & 0xFFFF; 19577529SSriharsha.Basavapatna@Sun.COM DBG2(vgenp, NULL, "%s(%d): (%d)\n", mtu_propname, 19587529SSriharsha.Basavapatna@Sun.COM vgenp->instance, *mtu); 19597529SSriharsha.Basavapatna@Sun.COM } 19607529SSriharsha.Basavapatna@Sun.COM } 19617529SSriharsha.Basavapatna@Sun.COM 19621991Sheppo /* register with MD event generator */ 19631991Sheppo static int 19641991Sheppo vgen_mdeg_reg(vgen_t *vgenp) 19651991Sheppo { 19661991Sheppo mdeg_prop_spec_t *pspecp; 19671991Sheppo mdeg_node_spec_t *parentp; 19681991Sheppo uint_t templatesz; 19691991Sheppo int rv; 19706419Ssb155480 mdeg_handle_t dev_hdl = NULL; 19716419Ssb155480 mdeg_handle_t port_hdl = NULL; 19726419Ssb155480 19731991Sheppo templatesz = sizeof (vgen_prop_template); 19741991Sheppo pspecp = kmem_zalloc(templatesz, KM_NOSLEEP); 19751991Sheppo if (pspecp == NULL) { 19761991Sheppo return (DDI_FAILURE); 19771991Sheppo } 19781991Sheppo parentp = kmem_zalloc(sizeof (mdeg_node_spec_t), KM_NOSLEEP); 19791991Sheppo if (parentp == NULL) { 19801991Sheppo kmem_free(pspecp, templatesz); 19811991Sheppo return (DDI_FAILURE); 19821991Sheppo } 19831991Sheppo 19841991Sheppo bcopy(vgen_prop_template, pspecp, templatesz); 19851991Sheppo 19861991Sheppo /* 19871991Sheppo * NOTE: The instance here refers to the value of "reg" property and 19881991Sheppo * not the dev_info instance (ddi_get_instance()) of vnet. 19891991Sheppo */ 19906419Ssb155480 VGEN_SET_MDEG_PROP_INST(pspecp, vgenp->regprop); 19911991Sheppo 19921991Sheppo parentp->namep = "virtual-device"; 19931991Sheppo parentp->specp = pspecp; 19941991Sheppo 19951991Sheppo /* save parentp in vgen_t */ 19961991Sheppo vgenp->mdeg_parentp = parentp; 19971991Sheppo 19986419Ssb155480 /* 19996419Ssb155480 * Register an interest in 'virtual-device' nodes with a 20006419Ssb155480 * 'name' property of 'network' 20016419Ssb155480 */ 20026419Ssb155480 rv = mdeg_register(parentp, &vdev_match, vgen_mdeg_cb, vgenp, &dev_hdl); 20031991Sheppo if (rv != MDEG_SUCCESS) { 20044647Sraghuram DERR(vgenp, NULL, "mdeg_register failed\n"); 20056419Ssb155480 goto mdeg_reg_fail; 20066419Ssb155480 } 20076419Ssb155480 20086419Ssb155480 /* Register an interest in 'port' nodes */ 20096419Ssb155480 rv = mdeg_register(parentp, &vport_match, vgen_mdeg_port_cb, vgenp, 20106419Ssb155480 &port_hdl); 20116419Ssb155480 if (rv != MDEG_SUCCESS) { 20126419Ssb155480 DERR(vgenp, NULL, "mdeg_register failed\n"); 20136419Ssb155480 goto mdeg_reg_fail; 20141991Sheppo } 20151991Sheppo 20161991Sheppo /* save mdeg handle in vgen_t */ 20176419Ssb155480 vgenp->mdeg_dev_hdl = dev_hdl; 20186419Ssb155480 vgenp->mdeg_port_hdl = port_hdl; 20191991Sheppo 20201991Sheppo return (DDI_SUCCESS); 20216419Ssb155480 20226419Ssb155480 mdeg_reg_fail: 20236419Ssb155480 if (dev_hdl != NULL) { 20246419Ssb155480 (void) mdeg_unregister(dev_hdl); 20256419Ssb155480 } 20266419Ssb155480 KMEM_FREE(parentp); 20276419Ssb155480 kmem_free(pspecp, templatesz); 20286419Ssb155480 vgenp->mdeg_parentp = NULL; 20296419Ssb155480 return (DDI_FAILURE); 20301991Sheppo } 20311991Sheppo 20321991Sheppo /* unregister with MD event generator */ 20331991Sheppo static void 20341991Sheppo vgen_mdeg_unreg(vgen_t *vgenp) 20351991Sheppo { 20366419Ssb155480 (void) mdeg_unregister(vgenp->mdeg_dev_hdl); 20376419Ssb155480 (void) mdeg_unregister(vgenp->mdeg_port_hdl); 20383297Ssb155480 kmem_free(vgenp->mdeg_parentp->specp, sizeof (vgen_prop_template)); 20391991Sheppo KMEM_FREE(vgenp->mdeg_parentp); 20401991Sheppo vgenp->mdeg_parentp = NULL; 20416419Ssb155480 vgenp->mdeg_dev_hdl = NULL; 20426419Ssb155480 vgenp->mdeg_port_hdl = NULL; 20431991Sheppo } 20441991Sheppo 20456419Ssb155480 /* mdeg callback function for the port node */ 20461991Sheppo static int 20476419Ssb155480 vgen_mdeg_port_cb(void *cb_argp, mdeg_result_t *resp) 20481991Sheppo { 20491991Sheppo int idx; 20501991Sheppo int vsw_idx = -1; 20511991Sheppo uint64_t val; 20521991Sheppo vgen_t *vgenp; 20531991Sheppo 20541991Sheppo if ((resp == NULL) || (cb_argp == NULL)) { 20551991Sheppo return (MDEG_FAILURE); 20561991Sheppo } 20571991Sheppo 20581991Sheppo vgenp = (vgen_t *)cb_argp; 20594647Sraghuram DBG1(vgenp, NULL, "enter\n"); 20601991Sheppo 20611991Sheppo mutex_enter(&vgenp->lock); 20621991Sheppo 20634647Sraghuram DBG1(vgenp, NULL, "ports: removed(%x), " 20644647Sraghuram "added(%x), updated(%x)\n", resp->removed.nelem, 20654647Sraghuram resp->added.nelem, resp->match_curr.nelem); 20661991Sheppo 20671991Sheppo for (idx = 0; idx < resp->removed.nelem; idx++) { 20681991Sheppo (void) vgen_remove_port(vgenp, resp->removed.mdp, 20691991Sheppo resp->removed.mdep[idx]); 20701991Sheppo } 20711991Sheppo 20721991Sheppo if (vgenp->vsw_portp == NULL) { 20731991Sheppo /* 20741991Sheppo * find vsw_port and add it first, because other ports need 20751991Sheppo * this when adding fdb entry (see vgen_port_init()). 20761991Sheppo */ 20771991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 20781991Sheppo if (!(md_get_prop_val(resp->added.mdp, 20791991Sheppo resp->added.mdep[idx], swport_propname, &val))) { 20801991Sheppo if (val == 0) { 20811991Sheppo /* 20821991Sheppo * This port is connected to the 20836419Ssb155480 * vsw on service domain. 20841991Sheppo */ 20851991Sheppo vsw_idx = idx; 20864663Szk194757 if (vgen_add_port(vgenp, 20871991Sheppo resp->added.mdp, 20884663Szk194757 resp->added.mdep[idx]) != 20894663Szk194757 DDI_SUCCESS) { 20904663Szk194757 cmn_err(CE_NOTE, "vnet%d Could " 20914663Szk194757 "not initialize virtual " 20924663Szk194757 "switch port.", 20936495Sspeer vgenp->instance); 20944663Szk194757 mutex_exit(&vgenp->lock); 20954663Szk194757 return (MDEG_FAILURE); 20964663Szk194757 } 20971991Sheppo break; 20981991Sheppo } 20991991Sheppo } 21001991Sheppo } 21014666Szk194757 if (vsw_idx == -1) { 21024647Sraghuram DWARN(vgenp, NULL, "can't find vsw_port\n"); 21034663Szk194757 mutex_exit(&vgenp->lock); 21041991Sheppo return (MDEG_FAILURE); 21051991Sheppo } 21061991Sheppo } 21071991Sheppo 21081991Sheppo for (idx = 0; idx < resp->added.nelem; idx++) { 21091991Sheppo if ((vsw_idx != -1) && (vsw_idx == idx)) /* skip vsw_port */ 21101991Sheppo continue; 21114663Szk194757 21124663Szk194757 /* If this port can't be added just skip it. */ 21131991Sheppo (void) vgen_add_port(vgenp, resp->added.mdp, 21141991Sheppo resp->added.mdep[idx]); 21151991Sheppo } 21161991Sheppo 21171991Sheppo for (idx = 0; idx < resp->match_curr.nelem; idx++) { 21181991Sheppo (void) vgen_update_port(vgenp, resp->match_curr.mdp, 21191991Sheppo resp->match_curr.mdep[idx], 21201991Sheppo resp->match_prev.mdp, 21211991Sheppo resp->match_prev.mdep[idx]); 21221991Sheppo } 21231991Sheppo 21241991Sheppo mutex_exit(&vgenp->lock); 21254647Sraghuram DBG1(vgenp, NULL, "exit\n"); 21261991Sheppo return (MDEG_SUCCESS); 21271991Sheppo } 21281991Sheppo 21296419Ssb155480 /* mdeg callback function for the vnet node */ 21306419Ssb155480 static int 21316419Ssb155480 vgen_mdeg_cb(void *cb_argp, mdeg_result_t *resp) 21326419Ssb155480 { 21336419Ssb155480 vgen_t *vgenp; 21346419Ssb155480 vnet_t *vnetp; 21356419Ssb155480 md_t *mdp; 21366419Ssb155480 mde_cookie_t node; 21376419Ssb155480 uint64_t inst; 21386419Ssb155480 char *node_name = NULL; 21396419Ssb155480 21406419Ssb155480 if ((resp == NULL) || (cb_argp == NULL)) { 21416419Ssb155480 return (MDEG_FAILURE); 21426419Ssb155480 } 21436419Ssb155480 21446419Ssb155480 vgenp = (vgen_t *)cb_argp; 21456419Ssb155480 vnetp = vgenp->vnetp; 21466419Ssb155480 21477572SWentao.Yang@Sun.COM DBG1(vgenp, NULL, "added %d : removed %d : curr matched %d" 21486419Ssb155480 " : prev matched %d", resp->added.nelem, resp->removed.nelem, 21496419Ssb155480 resp->match_curr.nelem, resp->match_prev.nelem); 21506419Ssb155480 21516419Ssb155480 mutex_enter(&vgenp->lock); 21526419Ssb155480 21536419Ssb155480 /* 21546419Ssb155480 * We get an initial callback for this node as 'added' after 21556419Ssb155480 * registering with mdeg. Note that we would have already gathered 21566419Ssb155480 * information about this vnet node by walking MD earlier during attach 21576419Ssb155480 * (in vgen_read_mdprops()). So, there is a window where the properties 21586419Ssb155480 * of this node might have changed when we get this initial 'added' 21596419Ssb155480 * callback. We handle this as if an update occured and invoke the same 21606419Ssb155480 * function which handles updates to the properties of this vnet-node 21616419Ssb155480 * if any. A non-zero 'match' value indicates that the MD has been 21626419Ssb155480 * updated and that a 'network' node is present which may or may not 21636419Ssb155480 * have been updated. It is up to the clients to examine their own 21646419Ssb155480 * nodes and determine if they have changed. 21656419Ssb155480 */ 21666419Ssb155480 if (resp->added.nelem != 0) { 21676419Ssb155480 21686419Ssb155480 if (resp->added.nelem != 1) { 21696419Ssb155480 cmn_err(CE_NOTE, "!vnet%d: number of nodes added " 21706419Ssb155480 "invalid: %d\n", vnetp->instance, 21716419Ssb155480 resp->added.nelem); 21726419Ssb155480 goto vgen_mdeg_cb_err; 21736419Ssb155480 } 21746419Ssb155480 21756419Ssb155480 mdp = resp->added.mdp; 21766419Ssb155480 node = resp->added.mdep[0]; 21776419Ssb155480 21786419Ssb155480 } else if (resp->match_curr.nelem != 0) { 21796419Ssb155480 21806419Ssb155480 if (resp->match_curr.nelem != 1) { 21816419Ssb155480 cmn_err(CE_NOTE, "!vnet%d: number of nodes updated " 21826419Ssb155480 "invalid: %d\n", vnetp->instance, 21836419Ssb155480 resp->match_curr.nelem); 21846419Ssb155480 goto vgen_mdeg_cb_err; 21856419Ssb155480 } 21866419Ssb155480 21876419Ssb155480 mdp = resp->match_curr.mdp; 21886419Ssb155480 node = resp->match_curr.mdep[0]; 21896419Ssb155480 21906419Ssb155480 } else { 21916419Ssb155480 goto vgen_mdeg_cb_err; 21926419Ssb155480 } 21936419Ssb155480 21946419Ssb155480 /* Validate name and instance */ 21956419Ssb155480 if (md_get_prop_str(mdp, node, "name", &node_name) != 0) { 21966419Ssb155480 DERR(vgenp, NULL, "unable to get node name\n"); 21976419Ssb155480 goto vgen_mdeg_cb_err; 21986419Ssb155480 } 21996419Ssb155480 22006419Ssb155480 /* is this a virtual-network device? */ 22016419Ssb155480 if (strcmp(node_name, vnet_propname) != 0) { 22026419Ssb155480 DERR(vgenp, NULL, "%s: Invalid node name: %s\n", node_name); 22036419Ssb155480 goto vgen_mdeg_cb_err; 22046419Ssb155480 } 22056419Ssb155480 22066419Ssb155480 if (md_get_prop_val(mdp, node, "cfg-handle", &inst)) { 22076419Ssb155480 DERR(vgenp, NULL, "prop(cfg-handle) not found\n"); 22086419Ssb155480 goto vgen_mdeg_cb_err; 22096419Ssb155480 } 22106419Ssb155480 22116495Sspeer /* is this the right instance of vnet? */ 22126419Ssb155480 if (inst != vgenp->regprop) { 22136419Ssb155480 DERR(vgenp, NULL, "Invalid cfg-handle: %lx\n", inst); 22146419Ssb155480 goto vgen_mdeg_cb_err; 22156419Ssb155480 } 22166419Ssb155480 22176419Ssb155480 vgen_update_md_prop(vgenp, mdp, node); 22186419Ssb155480 22196419Ssb155480 mutex_exit(&vgenp->lock); 22206419Ssb155480 return (MDEG_SUCCESS); 22216419Ssb155480 22226419Ssb155480 vgen_mdeg_cb_err: 22236419Ssb155480 mutex_exit(&vgenp->lock); 22246419Ssb155480 return (MDEG_FAILURE); 22256419Ssb155480 } 22266419Ssb155480 22276419Ssb155480 /* 22286419Ssb155480 * Check to see if the relevant properties in the specified node have 22296419Ssb155480 * changed, and if so take the appropriate action. 22306419Ssb155480 */ 22316419Ssb155480 static void 22326419Ssb155480 vgen_update_md_prop(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 22336419Ssb155480 { 22346419Ssb155480 uint16_t pvid; 22356419Ssb155480 uint16_t *vids; 22366419Ssb155480 uint16_t nvids; 22376419Ssb155480 vnet_t *vnetp = vgenp->vnetp; 22387529SSriharsha.Basavapatna@Sun.COM uint32_t mtu; 22397529SSriharsha.Basavapatna@Sun.COM enum { MD_init = 0x1, 22407529SSriharsha.Basavapatna@Sun.COM MD_vlans = 0x2, 22417529SSriharsha.Basavapatna@Sun.COM MD_mtu = 0x4 } updated; 22427529SSriharsha.Basavapatna@Sun.COM int rv; 22437529SSriharsha.Basavapatna@Sun.COM 22447529SSriharsha.Basavapatna@Sun.COM updated = MD_init; 22456419Ssb155480 22466419Ssb155480 /* Read the vlan ids */ 22476419Ssb155480 vgen_vlan_read_ids(vgenp, VGEN_LOCAL, mdp, mdex, &pvid, &vids, 22486419Ssb155480 &nvids, NULL); 22496419Ssb155480 22506419Ssb155480 /* Determine if there are any vlan id updates */ 22516419Ssb155480 if ((pvid != vnetp->pvid) || /* pvid changed? */ 22526419Ssb155480 (nvids != vnetp->nvids) || /* # of vids changed? */ 22536419Ssb155480 ((nvids != 0) && (vnetp->nvids != 0) && /* vids changed? */ 22546419Ssb155480 bcmp(vids, vnetp->vids, sizeof (uint16_t) * nvids))) { 22557529SSriharsha.Basavapatna@Sun.COM updated |= MD_vlans; 22567529SSriharsha.Basavapatna@Sun.COM } 22577529SSriharsha.Basavapatna@Sun.COM 22587529SSriharsha.Basavapatna@Sun.COM /* Read mtu */ 22597529SSriharsha.Basavapatna@Sun.COM vgen_mtu_read(vgenp, mdp, mdex, &mtu); 22607529SSriharsha.Basavapatna@Sun.COM if (mtu != vnetp->mtu) { 22617529SSriharsha.Basavapatna@Sun.COM if (mtu >= ETHERMTU && mtu <= VNET_MAX_MTU) { 22627529SSriharsha.Basavapatna@Sun.COM updated |= MD_mtu; 22637529SSriharsha.Basavapatna@Sun.COM } else { 22647529SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, "!vnet%d: Unable to process mtu update" 22657529SSriharsha.Basavapatna@Sun.COM " as the specified value:%d is invalid\n", 22667529SSriharsha.Basavapatna@Sun.COM vnetp->instance, mtu); 22677529SSriharsha.Basavapatna@Sun.COM } 22687529SSriharsha.Basavapatna@Sun.COM } 22697529SSriharsha.Basavapatna@Sun.COM 22707529SSriharsha.Basavapatna@Sun.COM /* Now process the updated props */ 22717529SSriharsha.Basavapatna@Sun.COM 22727529SSriharsha.Basavapatna@Sun.COM if (updated & MD_vlans) { 22737529SSriharsha.Basavapatna@Sun.COM 22747529SSriharsha.Basavapatna@Sun.COM /* save the new vlan ids */ 22757529SSriharsha.Basavapatna@Sun.COM vnetp->pvid = pvid; 22767529SSriharsha.Basavapatna@Sun.COM if (vnetp->nvids != 0) { 22777529SSriharsha.Basavapatna@Sun.COM kmem_free(vnetp->vids, 22787529SSriharsha.Basavapatna@Sun.COM sizeof (uint16_t) * vnetp->nvids); 22797529SSriharsha.Basavapatna@Sun.COM vnetp->nvids = 0; 22807529SSriharsha.Basavapatna@Sun.COM } 22817529SSriharsha.Basavapatna@Sun.COM if (nvids != 0) { 22827529SSriharsha.Basavapatna@Sun.COM vnetp->nvids = nvids; 22837529SSriharsha.Basavapatna@Sun.COM vnetp->vids = vids; 22847529SSriharsha.Basavapatna@Sun.COM } 22857529SSriharsha.Basavapatna@Sun.COM 22867529SSriharsha.Basavapatna@Sun.COM /* reset vlan-unaware peers (ver < 1.3) and restart handshake */ 22877529SSriharsha.Basavapatna@Sun.COM vgen_reset_vlan_unaware_ports(vgenp); 22887529SSriharsha.Basavapatna@Sun.COM 22897529SSriharsha.Basavapatna@Sun.COM } else { 22907529SSriharsha.Basavapatna@Sun.COM 22916419Ssb155480 if (nvids != 0) { 22926419Ssb155480 kmem_free(vids, sizeof (uint16_t) * nvids); 22936419Ssb155480 } 22947529SSriharsha.Basavapatna@Sun.COM } 22957529SSriharsha.Basavapatna@Sun.COM 22967529SSriharsha.Basavapatna@Sun.COM if (updated & MD_mtu) { 22977529SSriharsha.Basavapatna@Sun.COM 22987529SSriharsha.Basavapatna@Sun.COM DBG2(vgenp, NULL, "curr_mtu(%d) new_mtu(%d)\n", 22997529SSriharsha.Basavapatna@Sun.COM vnetp->mtu, mtu); 23007529SSriharsha.Basavapatna@Sun.COM 23017529SSriharsha.Basavapatna@Sun.COM rv = vnet_mtu_update(vnetp, mtu); 23027529SSriharsha.Basavapatna@Sun.COM if (rv == 0) { 23037529SSriharsha.Basavapatna@Sun.COM vgenp->max_frame_size = mtu + 23047529SSriharsha.Basavapatna@Sun.COM sizeof (struct ether_header) + VLAN_TAGSZ; 23057529SSriharsha.Basavapatna@Sun.COM } 23067529SSriharsha.Basavapatna@Sun.COM } 23076419Ssb155480 } 23086419Ssb155480 23091991Sheppo /* add a new port to the device */ 23101991Sheppo static int 23111991Sheppo vgen_add_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 23121991Sheppo { 23136419Ssb155480 vgen_port_t *portp; 23146419Ssb155480 int rv; 23156419Ssb155480 23166419Ssb155480 portp = kmem_zalloc(sizeof (vgen_port_t), KM_SLEEP); 23176419Ssb155480 23186419Ssb155480 rv = vgen_port_read_props(portp, vgenp, mdp, mdex); 23196419Ssb155480 if (rv != DDI_SUCCESS) { 23206419Ssb155480 KMEM_FREE(portp); 23216419Ssb155480 return (DDI_FAILURE); 23226419Ssb155480 } 23236419Ssb155480 23246419Ssb155480 rv = vgen_port_attach(portp); 23256419Ssb155480 if (rv != DDI_SUCCESS) { 23266419Ssb155480 return (DDI_FAILURE); 23276419Ssb155480 } 23286419Ssb155480 23296419Ssb155480 return (DDI_SUCCESS); 23306419Ssb155480 } 23316419Ssb155480 23326419Ssb155480 /* read properties of the port from its md node */ 23336419Ssb155480 static int 23346419Ssb155480 vgen_port_read_props(vgen_port_t *portp, vgen_t *vgenp, md_t *mdp, 23356419Ssb155480 mde_cookie_t mdex) 23366419Ssb155480 { 23376419Ssb155480 uint64_t port_num; 23386419Ssb155480 uint64_t *ldc_ids; 23396419Ssb155480 uint64_t macaddr; 23406419Ssb155480 uint64_t val; 23416419Ssb155480 int num_ldcs; 23426419Ssb155480 int i; 23436419Ssb155480 int addrsz; 23446419Ssb155480 int num_nodes = 0; 23456419Ssb155480 int listsz = 0; 23466419Ssb155480 mde_cookie_t *listp = NULL; 23476419Ssb155480 uint8_t *addrp; 23481991Sheppo struct ether_addr ea; 23491991Sheppo 23501991Sheppo /* read "id" property to get the port number */ 23511991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 23524647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 23531991Sheppo return (DDI_FAILURE); 23541991Sheppo } 23551991Sheppo 23561991Sheppo /* 23571991Sheppo * Find the channel endpoint node(s) under this port node. 23581991Sheppo */ 23591991Sheppo if ((num_nodes = md_node_count(mdp)) <= 0) { 23604647Sraghuram DWARN(vgenp, NULL, "invalid number of nodes found (%d)", 23614647Sraghuram num_nodes); 23621991Sheppo return (DDI_FAILURE); 23631991Sheppo } 23641991Sheppo 23651991Sheppo /* allocate space for node list */ 23661991Sheppo listsz = num_nodes * sizeof (mde_cookie_t); 23671991Sheppo listp = kmem_zalloc(listsz, KM_NOSLEEP); 23681991Sheppo if (listp == NULL) 23691991Sheppo return (DDI_FAILURE); 23701991Sheppo 23711991Sheppo num_ldcs = md_scan_dag(mdp, mdex, 23724650Sraghuram md_find_name(mdp, channel_propname), 23734650Sraghuram md_find_name(mdp, "fwd"), listp); 23741991Sheppo 23751991Sheppo if (num_ldcs <= 0) { 23764647Sraghuram DWARN(vgenp, NULL, "can't find %s nodes", channel_propname); 23771991Sheppo kmem_free(listp, listsz); 23781991Sheppo return (DDI_FAILURE); 23791991Sheppo } 23801991Sheppo 23814647Sraghuram DBG2(vgenp, NULL, "num_ldcs %d", num_ldcs); 23821991Sheppo 23831991Sheppo ldc_ids = kmem_zalloc(num_ldcs * sizeof (uint64_t), KM_NOSLEEP); 23841991Sheppo if (ldc_ids == NULL) { 23851991Sheppo kmem_free(listp, listsz); 23861991Sheppo return (DDI_FAILURE); 23871991Sheppo } 23881991Sheppo 23891991Sheppo for (i = 0; i < num_ldcs; i++) { 23901991Sheppo /* read channel ids */ 23911991Sheppo if (md_get_prop_val(mdp, listp[i], id_propname, &ldc_ids[i])) { 23924647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", 23934647Sraghuram id_propname); 23941991Sheppo kmem_free(listp, listsz); 23951991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 23961991Sheppo return (DDI_FAILURE); 23971991Sheppo } 23984647Sraghuram DBG2(vgenp, NULL, "ldc_id 0x%llx", ldc_ids[i]); 23991991Sheppo } 24001991Sheppo 24011991Sheppo kmem_free(listp, listsz); 24021991Sheppo 24031991Sheppo if (md_get_prop_data(mdp, mdex, rmacaddr_propname, &addrp, 24041991Sheppo &addrsz)) { 24054647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", rmacaddr_propname); 24061991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 24071991Sheppo return (DDI_FAILURE); 24081991Sheppo } 24091991Sheppo 24101991Sheppo if (addrsz < ETHERADDRL) { 24114647Sraghuram DWARN(vgenp, NULL, "invalid address size (%d)\n", addrsz); 24121991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 24131991Sheppo return (DDI_FAILURE); 24141991Sheppo } 24151991Sheppo 24161991Sheppo macaddr = *((uint64_t *)addrp); 24171991Sheppo 24184647Sraghuram DBG2(vgenp, NULL, "remote mac address 0x%llx\n", macaddr); 24191991Sheppo 24201991Sheppo for (i = ETHERADDRL - 1; i >= 0; i--) { 24211991Sheppo ea.ether_addr_octet[i] = macaddr & 0xFF; 24221991Sheppo macaddr >>= 8; 24231991Sheppo } 24241991Sheppo 24251991Sheppo if (vgenp->vsw_portp == NULL) { 24261991Sheppo if (!(md_get_prop_val(mdp, mdex, swport_propname, &val))) { 24271991Sheppo if (val == 0) { 24286495Sspeer (void) atomic_swap_32( 24296495Sspeer &vgenp->vsw_port_refcnt, 0); 24306419Ssb155480 /* This port is connected to the vsw */ 24316419Ssb155480 vgenp->vsw_portp = portp; 24321991Sheppo } 24331991Sheppo } 24341991Sheppo } 24356419Ssb155480 24366419Ssb155480 /* now update all properties into the port */ 24376419Ssb155480 portp->vgenp = vgenp; 24386419Ssb155480 portp->port_num = port_num; 24396419Ssb155480 ether_copy(&ea, &portp->macaddr); 24406419Ssb155480 portp->ldc_ids = kmem_zalloc(sizeof (uint64_t) * num_ldcs, KM_SLEEP); 24416419Ssb155480 bcopy(ldc_ids, portp->ldc_ids, sizeof (uint64_t) * num_ldcs); 24426419Ssb155480 portp->num_ldcs = num_ldcs; 24436419Ssb155480 24446419Ssb155480 /* read vlan id properties of this port node */ 24456419Ssb155480 vgen_vlan_read_ids(portp, VGEN_PEER, mdp, mdex, &portp->pvid, 24466419Ssb155480 &portp->vids, &portp->nvids, NULL); 24471991Sheppo 24481991Sheppo kmem_free(ldc_ids, num_ldcs * sizeof (uint64_t)); 24491991Sheppo 24506419Ssb155480 return (DDI_SUCCESS); 24511991Sheppo } 24521991Sheppo 24531991Sheppo /* remove a port from the device */ 24541991Sheppo static int 24551991Sheppo vgen_remove_port(vgen_t *vgenp, md_t *mdp, mde_cookie_t mdex) 24561991Sheppo { 24571991Sheppo uint64_t port_num; 24581991Sheppo vgen_port_t *portp; 24591991Sheppo vgen_portlist_t *plistp; 24601991Sheppo 24611991Sheppo /* read "id" property to get the port number */ 24621991Sheppo if (md_get_prop_val(mdp, mdex, id_propname, &port_num)) { 24634647Sraghuram DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 24641991Sheppo return (DDI_FAILURE); 24651991Sheppo } 24661991Sheppo 24671991Sheppo plistp = &(vgenp->vgenports); 24681991Sheppo 24691991Sheppo WRITE_ENTER(&plistp->rwlock); 24701991Sheppo portp = vgen_port_lookup(plistp, (int)port_num); 24711991Sheppo if (portp == NULL) { 24724647Sraghuram DWARN(vgenp, NULL, "can't find port(%lx)\n", port_num); 24731991Sheppo RW_EXIT(&plistp->rwlock); 24741991Sheppo return (DDI_FAILURE); 24751991Sheppo } 24761991Sheppo 24771991Sheppo vgen_port_detach_mdeg(portp); 24781991Sheppo RW_EXIT(&plistp->rwlock); 24791991Sheppo 24801991Sheppo return (DDI_SUCCESS); 24811991Sheppo } 24821991Sheppo 24831991Sheppo /* attach a port to the device based on mdeg data */ 24841991Sheppo static int 24856419Ssb155480 vgen_port_attach(vgen_port_t *portp) 24861991Sheppo { 24871991Sheppo int i; 24886419Ssb155480 vgen_portlist_t *plistp; 24896419Ssb155480 vgen_t *vgenp; 24906419Ssb155480 uint64_t *ldcids; 24916419Ssb155480 uint32_t num_ldcs; 24926495Sspeer mac_register_t *macp; 24936495Sspeer vio_net_res_type_t type; 24946495Sspeer int rv; 24956419Ssb155480 24966419Ssb155480 ASSERT(portp != NULL); 24976419Ssb155480 24986419Ssb155480 vgenp = portp->vgenp; 24996419Ssb155480 ldcids = portp->ldc_ids; 25006419Ssb155480 num_ldcs = portp->num_ldcs; 25011991Sheppo 25024647Sraghuram DBG1(vgenp, NULL, "port_num(%d)\n", portp->port_num); 25031991Sheppo 25046495Sspeer mutex_init(&portp->lock, NULL, MUTEX_DRIVER, NULL); 25056419Ssb155480 rw_init(&portp->ldclist.rwlock, NULL, RW_DRIVER, NULL); 25061991Sheppo portp->ldclist.headp = NULL; 25076419Ssb155480 25086419Ssb155480 for (i = 0; i < num_ldcs; i++) { 25094647Sraghuram DBG2(vgenp, NULL, "ldcid (%lx)\n", ldcids[i]); 25104663Szk194757 if (vgen_ldc_attach(portp, ldcids[i]) == DDI_FAILURE) { 25114663Szk194757 vgen_port_detach(portp); 25124663Szk194757 return (DDI_FAILURE); 25134663Szk194757 } 25141991Sheppo } 25151991Sheppo 25166419Ssb155480 /* create vlan id hash table */ 25176419Ssb155480 vgen_vlan_create_hash(portp); 25186419Ssb155480 25196495Sspeer if (portp == vgenp->vsw_portp) { 25206495Sspeer /* This port is connected to the switch port */ 25216495Sspeer vgenp->vsw_portp = portp; 25226495Sspeer (void) atomic_swap_32(&portp->use_vsw_port, B_FALSE); 25236495Sspeer type = VIO_NET_RES_LDC_SERVICE; 25246495Sspeer } else { 25256495Sspeer (void) atomic_swap_32(&portp->use_vsw_port, B_TRUE); 25266495Sspeer type = VIO_NET_RES_LDC_GUEST; 25276495Sspeer } 25286495Sspeer 25296495Sspeer if ((macp = mac_alloc(MAC_VERSION)) == NULL) { 25306495Sspeer vgen_port_detach(portp); 25316495Sspeer return (DDI_FAILURE); 25326495Sspeer } 25336495Sspeer macp->m_type_ident = MAC_PLUGIN_IDENT_ETHER; 25346495Sspeer macp->m_driver = portp; 25356495Sspeer macp->m_dip = vgenp->vnetdip; 25366495Sspeer macp->m_src_addr = (uint8_t *)&(vgenp->macaddr); 25376495Sspeer macp->m_callbacks = &vgen_m_callbacks; 25386495Sspeer macp->m_min_sdu = 0; 25396495Sspeer macp->m_max_sdu = ETHERMTU; 25406495Sspeer 25416495Sspeer mutex_enter(&portp->lock); 25426495Sspeer rv = vio_net_resource_reg(macp, type, vgenp->macaddr, 25436495Sspeer portp->macaddr, &portp->vhp, &portp->vcb); 25446495Sspeer mutex_exit(&portp->lock); 25456495Sspeer mac_free(macp); 25466495Sspeer 25476495Sspeer if (rv == 0) { 25486495Sspeer /* link it into the list of ports */ 25496495Sspeer plistp = &(vgenp->vgenports); 25506495Sspeer WRITE_ENTER(&plistp->rwlock); 25516495Sspeer vgen_port_list_insert(portp); 25526495Sspeer RW_EXIT(&plistp->rwlock); 25536495Sspeer } else { 25546495Sspeer DERR(vgenp, NULL, "vio_net_resource_reg failed for portp=0x%p", 25556495Sspeer portp); 25566495Sspeer vgen_port_detach(portp); 25571991Sheppo } 25581991Sheppo 25594647Sraghuram DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num); 25601991Sheppo return (DDI_SUCCESS); 25611991Sheppo } 25621991Sheppo 25631991Sheppo /* detach a port from the device based on mdeg data */ 25641991Sheppo static void 25651991Sheppo vgen_port_detach_mdeg(vgen_port_t *portp) 25661991Sheppo { 25671991Sheppo vgen_t *vgenp = portp->vgenp; 25681991Sheppo 25694647Sraghuram DBG1(vgenp, NULL, "enter: port_num(%d)\n", portp->port_num); 25706495Sspeer 25716495Sspeer mutex_enter(&portp->lock); 25726495Sspeer 25731991Sheppo /* stop the port if needed */ 25746495Sspeer if (portp->flags & VGEN_STARTED) { 25751991Sheppo vgen_port_uninit(portp); 25761991Sheppo } 25776495Sspeer 25786495Sspeer mutex_exit(&portp->lock); 25791991Sheppo vgen_port_detach(portp); 25801991Sheppo 25814647Sraghuram DBG1(vgenp, NULL, "exit: port_num(%d)\n", portp->port_num); 25821991Sheppo } 25831991Sheppo 25841991Sheppo static int 25851991Sheppo vgen_update_port(vgen_t *vgenp, md_t *curr_mdp, mde_cookie_t curr_mdex, 25861991Sheppo md_t *prev_mdp, mde_cookie_t prev_mdex) 25871991Sheppo { 25886419Ssb155480 uint64_t cport_num; 25896419Ssb155480 uint64_t pport_num; 25906419Ssb155480 vgen_portlist_t *plistp; 25916419Ssb155480 vgen_port_t *portp; 25926419Ssb155480 boolean_t updated_vlans = B_FALSE; 25936419Ssb155480 uint16_t pvid; 25946419Ssb155480 uint16_t *vids; 25956419Ssb155480 uint16_t nvids; 25966419Ssb155480 25976419Ssb155480 /* 25986419Ssb155480 * For now, we get port updates only if vlan ids changed. 25996419Ssb155480 * We read the port num and do some sanity check. 26006419Ssb155480 */ 26016419Ssb155480 if (md_get_prop_val(curr_mdp, curr_mdex, id_propname, &cport_num)) { 26026419Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 26036419Ssb155480 return (DDI_FAILURE); 26046419Ssb155480 } 26056419Ssb155480 26066419Ssb155480 if (md_get_prop_val(prev_mdp, prev_mdex, id_propname, &pport_num)) { 26076419Ssb155480 DWARN(vgenp, NULL, "prop(%s) not found\n", id_propname); 26086419Ssb155480 return (DDI_FAILURE); 26096419Ssb155480 } 26106419Ssb155480 if (cport_num != pport_num) 26116419Ssb155480 return (DDI_FAILURE); 26126419Ssb155480 26136419Ssb155480 plistp = &(vgenp->vgenports); 26146419Ssb155480 26156419Ssb155480 READ_ENTER(&plistp->rwlock); 26166419Ssb155480 26176419Ssb155480 portp = vgen_port_lookup(plistp, (int)cport_num); 26186419Ssb155480 if (portp == NULL) { 26196419Ssb155480 DWARN(vgenp, NULL, "can't find port(%lx)\n", cport_num); 26206419Ssb155480 RW_EXIT(&plistp->rwlock); 26216419Ssb155480 return (DDI_FAILURE); 26226419Ssb155480 } 26236419Ssb155480 26246419Ssb155480 /* Read the vlan ids */ 26256419Ssb155480 vgen_vlan_read_ids(portp, VGEN_PEER, curr_mdp, curr_mdex, &pvid, &vids, 26266419Ssb155480 &nvids, NULL); 26276419Ssb155480 26286419Ssb155480 /* Determine if there are any vlan id updates */ 26296419Ssb155480 if ((pvid != portp->pvid) || /* pvid changed? */ 26306419Ssb155480 (nvids != portp->nvids) || /* # of vids changed? */ 26316419Ssb155480 ((nvids != 0) && (portp->nvids != 0) && /* vids changed? */ 26326419Ssb155480 bcmp(vids, portp->vids, sizeof (uint16_t) * nvids))) { 26336419Ssb155480 updated_vlans = B_TRUE; 26346419Ssb155480 } 26356419Ssb155480 26366419Ssb155480 if (updated_vlans == B_FALSE) { 26376419Ssb155480 RW_EXIT(&plistp->rwlock); 26386419Ssb155480 return (DDI_FAILURE); 26396419Ssb155480 } 26406419Ssb155480 26416419Ssb155480 /* remove the port from vlans it has been assigned to */ 26426419Ssb155480 vgen_vlan_remove_ids(portp); 26436419Ssb155480 26446419Ssb155480 /* save the new vlan ids */ 26456419Ssb155480 portp->pvid = pvid; 26466419Ssb155480 if (portp->nvids != 0) { 26476419Ssb155480 kmem_free(portp->vids, sizeof (uint16_t) * portp->nvids); 26486419Ssb155480 portp->nvids = 0; 26496419Ssb155480 } 26506419Ssb155480 if (nvids != 0) { 26516419Ssb155480 portp->vids = kmem_zalloc(sizeof (uint16_t) * nvids, KM_SLEEP); 26526419Ssb155480 bcopy(vids, portp->vids, sizeof (uint16_t) * nvids); 26536419Ssb155480 portp->nvids = nvids; 26546419Ssb155480 kmem_free(vids, sizeof (uint16_t) * nvids); 26556419Ssb155480 } 26566419Ssb155480 26576419Ssb155480 /* add port to the new vlans */ 26586419Ssb155480 vgen_vlan_add_ids(portp); 26596419Ssb155480 26606419Ssb155480 /* reset the port if it is vlan unaware (ver < 1.3) */ 26616419Ssb155480 vgen_vlan_unaware_port_reset(portp); 26626419Ssb155480 26636419Ssb155480 RW_EXIT(&plistp->rwlock); 26646419Ssb155480 26651991Sheppo return (DDI_SUCCESS); 26661991Sheppo } 26671991Sheppo 26681991Sheppo static uint64_t 26692311Sseb vgen_port_stat(vgen_port_t *portp, uint_t stat) 26701991Sheppo { 26711991Sheppo vgen_ldclist_t *ldclp; 26721991Sheppo vgen_ldc_t *ldcp; 26731991Sheppo uint64_t val; 26741991Sheppo 26751991Sheppo val = 0; 26761991Sheppo ldclp = &portp->ldclist; 26771991Sheppo 26781991Sheppo READ_ENTER(&ldclp->rwlock); 26791991Sheppo for (ldcp = ldclp->headp; ldcp != NULL; ldcp = ldcp->nextp) { 26801991Sheppo val += vgen_ldc_stat(ldcp, stat); 26811991Sheppo } 26821991Sheppo RW_EXIT(&ldclp->rwlock); 26831991Sheppo 26841991Sheppo return (val); 26851991Sheppo } 26861991Sheppo 26877529SSriharsha.Basavapatna@Sun.COM /* allocate receive resources */ 26887529SSriharsha.Basavapatna@Sun.COM static int 26897529SSriharsha.Basavapatna@Sun.COM vgen_init_multipools(vgen_ldc_t *ldcp) 26907529SSriharsha.Basavapatna@Sun.COM { 26917529SSriharsha.Basavapatna@Sun.COM size_t data_sz; 26927529SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp); 26937529SSriharsha.Basavapatna@Sun.COM int status; 26947529SSriharsha.Basavapatna@Sun.COM uint32_t sz1 = 0; 26957529SSriharsha.Basavapatna@Sun.COM uint32_t sz2 = 0; 26967529SSriharsha.Basavapatna@Sun.COM uint32_t sz3 = 0; 26977529SSriharsha.Basavapatna@Sun.COM uint32_t sz4 = 0; 26987529SSriharsha.Basavapatna@Sun.COM 26997529SSriharsha.Basavapatna@Sun.COM /* 27007529SSriharsha.Basavapatna@Sun.COM * We round up the mtu specified to be a multiple of 2K. 27017529SSriharsha.Basavapatna@Sun.COM * We then create rx pools based on the rounded up size. 27027529SSriharsha.Basavapatna@Sun.COM */ 27037529SSriharsha.Basavapatna@Sun.COM data_sz = vgenp->max_frame_size + VNET_IPALIGN + VNET_LDCALIGN; 27047529SSriharsha.Basavapatna@Sun.COM data_sz = VNET_ROUNDUP_2K(data_sz); 27057529SSriharsha.Basavapatna@Sun.COM 27067529SSriharsha.Basavapatna@Sun.COM /* 27077529SSriharsha.Basavapatna@Sun.COM * If pool sizes are specified, use them. Note that the presence of 27087529SSriharsha.Basavapatna@Sun.COM * the first tunable will be used as a hint. 27097529SSriharsha.Basavapatna@Sun.COM */ 27107529SSriharsha.Basavapatna@Sun.COM if (vgen_rbufsz1 != 0) { 27117529SSriharsha.Basavapatna@Sun.COM 27127529SSriharsha.Basavapatna@Sun.COM sz1 = vgen_rbufsz1; 27137529SSriharsha.Basavapatna@Sun.COM sz2 = vgen_rbufsz2; 27147529SSriharsha.Basavapatna@Sun.COM sz3 = vgen_rbufsz3; 27157529SSriharsha.Basavapatna@Sun.COM sz4 = vgen_rbufsz4; 27167529SSriharsha.Basavapatna@Sun.COM 27177529SSriharsha.Basavapatna@Sun.COM if (sz4 == 0) { /* need 3 pools */ 27187529SSriharsha.Basavapatna@Sun.COM 27197529SSriharsha.Basavapatna@Sun.COM ldcp->max_rxpool_size = sz3; 27207529SSriharsha.Basavapatna@Sun.COM status = vio_init_multipools(&ldcp->vmp, 27217529SSriharsha.Basavapatna@Sun.COM VGEN_NUM_VMPOOLS, sz1, sz2, sz3, vgen_nrbufs1, 27227529SSriharsha.Basavapatna@Sun.COM vgen_nrbufs2, vgen_nrbufs3); 27237529SSriharsha.Basavapatna@Sun.COM 27247529SSriharsha.Basavapatna@Sun.COM } else { 27257529SSriharsha.Basavapatna@Sun.COM 27267529SSriharsha.Basavapatna@Sun.COM ldcp->max_rxpool_size = sz4; 27277529SSriharsha.Basavapatna@Sun.COM status = vio_init_multipools(&ldcp->vmp, 27287529SSriharsha.Basavapatna@Sun.COM VGEN_NUM_VMPOOLS + 1, sz1, sz2, sz3, sz4, 27297529SSriharsha.Basavapatna@Sun.COM vgen_nrbufs1, vgen_nrbufs2, vgen_nrbufs3, 27307529SSriharsha.Basavapatna@Sun.COM vgen_nrbufs4); 27317529SSriharsha.Basavapatna@Sun.COM } 27327529SSriharsha.Basavapatna@Sun.COM return (status); 27337529SSriharsha.Basavapatna@Sun.COM } 27347529SSriharsha.Basavapatna@Sun.COM 27357529SSriharsha.Basavapatna@Sun.COM /* 27367529SSriharsha.Basavapatna@Sun.COM * Pool sizes are not specified. We select the pool sizes based on the 27377529SSriharsha.Basavapatna@Sun.COM * mtu if vnet_jumbo_rxpools is enabled. 27387529SSriharsha.Basavapatna@Sun.COM */ 27397529SSriharsha.Basavapatna@Sun.COM if (vnet_jumbo_rxpools == B_FALSE || data_sz == VNET_2K) { 27407529SSriharsha.Basavapatna@Sun.COM /* 27417529SSriharsha.Basavapatna@Sun.COM * Receive buffer pool allocation based on mtu is disabled. 27427529SSriharsha.Basavapatna@Sun.COM * Use the default mechanism of standard size pool allocation. 27437529SSriharsha.Basavapatna@Sun.COM */ 27447529SSriharsha.Basavapatna@Sun.COM sz1 = VGEN_DBLK_SZ_128; 27457529SSriharsha.Basavapatna@Sun.COM sz2 = VGEN_DBLK_SZ_256; 27467529SSriharsha.Basavapatna@Sun.COM sz3 = VGEN_DBLK_SZ_2048; 27477529SSriharsha.Basavapatna@Sun.COM ldcp->max_rxpool_size = sz3; 27487529SSriharsha.Basavapatna@Sun.COM 27497529SSriharsha.Basavapatna@Sun.COM status = vio_init_multipools(&ldcp->vmp, VGEN_NUM_VMPOOLS, 27507529SSriharsha.Basavapatna@Sun.COM sz1, sz2, sz3, 27517529SSriharsha.Basavapatna@Sun.COM vgen_nrbufs1, vgen_nrbufs2, vgen_nrbufs3); 27527529SSriharsha.Basavapatna@Sun.COM 27537529SSriharsha.Basavapatna@Sun.COM return (status); 27547529SSriharsha.Basavapatna@Sun.COM } 27557529SSriharsha.Basavapatna@Sun.COM 27567529SSriharsha.Basavapatna@Sun.COM switch (data_sz) { 27577529SSriharsha.Basavapatna@Sun.COM 27587529SSriharsha.Basavapatna@Sun.COM case VNET_4K: 27597529SSriharsha.Basavapatna@Sun.COM 27607529SSriharsha.Basavapatna@Sun.COM sz1 = VGEN_DBLK_SZ_128; 27617529SSriharsha.Basavapatna@Sun.COM sz2 = VGEN_DBLK_SZ_256; 27627529SSriharsha.Basavapatna@Sun.COM sz3 = VGEN_DBLK_SZ_2048; 27637529SSriharsha.Basavapatna@Sun.COM sz4 = sz3 << 1; /* 4K */ 27647529SSriharsha.Basavapatna@Sun.COM ldcp->max_rxpool_size = sz4; 27657529SSriharsha.Basavapatna@Sun.COM 27667529SSriharsha.Basavapatna@Sun.COM status = vio_init_multipools(&ldcp->vmp, VGEN_NUM_VMPOOLS + 1, 27677529SSriharsha.Basavapatna@Sun.COM sz1, sz2, sz3, sz4, 27687529SSriharsha.Basavapatna@Sun.COM vgen_nrbufs1, vgen_nrbufs2, vgen_nrbufs3, vgen_nrbufs4); 27697529SSriharsha.Basavapatna@Sun.COM break; 27707529SSriharsha.Basavapatna@Sun.COM 27717529SSriharsha.Basavapatna@Sun.COM default: /* data_sz: 4K+ to 16K */ 27727529SSriharsha.Basavapatna@Sun.COM 27737529SSriharsha.Basavapatna@Sun.COM sz1 = VGEN_DBLK_SZ_256; 27747529SSriharsha.Basavapatna@Sun.COM sz2 = VGEN_DBLK_SZ_2048; 27757529SSriharsha.Basavapatna@Sun.COM sz3 = data_sz >> 1; /* Jumbo-size/2 */ 27767529SSriharsha.Basavapatna@Sun.COM sz4 = data_sz; /* Jumbo-size */ 27777529SSriharsha.Basavapatna@Sun.COM ldcp->max_rxpool_size = sz4; 27787529SSriharsha.Basavapatna@Sun.COM 27797529SSriharsha.Basavapatna@Sun.COM status = vio_init_multipools(&ldcp->vmp, VGEN_NUM_VMPOOLS + 1, 27807529SSriharsha.Basavapatna@Sun.COM sz1, sz2, sz3, sz4, 27817529SSriharsha.Basavapatna@Sun.COM vgen_nrbufs1, vgen_nrbufs2, vgen_nrbufs3, vgen_nrbufs4); 27827529SSriharsha.Basavapatna@Sun.COM break; 27837529SSriharsha.Basavapatna@Sun.COM 27847529SSriharsha.Basavapatna@Sun.COM } 27857529SSriharsha.Basavapatna@Sun.COM 27867529SSriharsha.Basavapatna@Sun.COM return (status); 27877529SSriharsha.Basavapatna@Sun.COM } 27887529SSriharsha.Basavapatna@Sun.COM 27891991Sheppo /* attach the channel corresponding to the given ldc_id to the port */ 27901991Sheppo static int 27911991Sheppo vgen_ldc_attach(vgen_port_t *portp, uint64_t ldc_id) 27921991Sheppo { 27931991Sheppo vgen_t *vgenp; 27941991Sheppo vgen_ldclist_t *ldclp; 27951991Sheppo vgen_ldc_t *ldcp, **prev_ldcp; 27961991Sheppo ldc_attr_t attr; 27971991Sheppo int status; 27981991Sheppo ldc_status_t istatus; 27995373Sraghuram char kname[MAXNAMELEN]; 28005373Sraghuram int instance; 28014647Sraghuram enum {AST_init = 0x0, AST_ldc_alloc = 0x1, 28024647Sraghuram AST_mutex_init = 0x2, AST_ldc_init = 0x4, 28034647Sraghuram AST_ldc_reg_cb = 0x8, AST_alloc_tx_ring = 0x10, 28045935Ssb155480 AST_create_rxmblks = 0x20, 28055935Ssb155480 AST_create_rcv_thread = 0x40} attach_state; 28061991Sheppo 28071991Sheppo attach_state = AST_init; 28081991Sheppo vgenp = portp->vgenp; 28091991Sheppo ldclp = &portp->ldclist; 28101991Sheppo 28111991Sheppo ldcp = kmem_zalloc(sizeof (vgen_ldc_t), KM_NOSLEEP); 28121991Sheppo if (ldcp == NULL) { 28131991Sheppo goto ldc_attach_failed; 28141991Sheppo } 28151991Sheppo ldcp->ldc_id = ldc_id; 28161991Sheppo ldcp->portp = portp; 28171991Sheppo 28181991Sheppo attach_state |= AST_ldc_alloc; 28191991Sheppo 28201991Sheppo mutex_init(&ldcp->txlock, NULL, MUTEX_DRIVER, NULL); 28211991Sheppo mutex_init(&ldcp->cblock, NULL, MUTEX_DRIVER, NULL); 28221991Sheppo mutex_init(&ldcp->tclock, NULL, MUTEX_DRIVER, NULL); 28234647Sraghuram mutex_init(&ldcp->wrlock, NULL, MUTEX_DRIVER, NULL); 28244647Sraghuram mutex_init(&ldcp->rxlock, NULL, MUTEX_DRIVER, NULL); 28251991Sheppo 28261991Sheppo attach_state |= AST_mutex_init; 28271991Sheppo 28281991Sheppo attr.devclass = LDC_DEV_NT; 28296495Sspeer attr.instance = vgenp->instance; 28301991Sheppo attr.mode = LDC_MODE_UNRELIABLE; 28312410Slm66018 attr.mtu = vnet_ldc_mtu; 28321991Sheppo status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle); 28331991Sheppo if (status != 0) { 28344647Sraghuram DWARN(vgenp, ldcp, "ldc_init failed,rv (%d)\n", status); 28351991Sheppo goto ldc_attach_failed; 28361991Sheppo } 28371991Sheppo attach_state |= AST_ldc_init; 28381991Sheppo 28394647Sraghuram if (vgen_rcv_thread_enabled) { 28404647Sraghuram ldcp->rcv_thr_flags = 0; 28414647Sraghuram 28424647Sraghuram mutex_init(&ldcp->rcv_thr_lock, NULL, MUTEX_DRIVER, NULL); 28434647Sraghuram cv_init(&ldcp->rcv_thr_cv, NULL, CV_DRIVER, NULL); 28444647Sraghuram ldcp->rcv_thread = thread_create(NULL, 2 * DEFAULTSTKSZ, 28454647Sraghuram vgen_ldc_rcv_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri); 28464647Sraghuram 28474647Sraghuram attach_state |= AST_create_rcv_thread; 28484647Sraghuram if (ldcp->rcv_thread == NULL) { 28494647Sraghuram DWARN(vgenp, ldcp, "Failed to create worker thread"); 28504647Sraghuram goto ldc_attach_failed; 28514647Sraghuram } 28524647Sraghuram } 28534647Sraghuram 28541991Sheppo status = ldc_reg_callback(ldcp->ldc_handle, vgen_ldc_cb, (caddr_t)ldcp); 28551991Sheppo if (status != 0) { 28564647Sraghuram DWARN(vgenp, ldcp, "ldc_reg_callback failed, rv (%d)\n", 28574647Sraghuram status); 28581991Sheppo goto ldc_attach_failed; 28591991Sheppo } 28605935Ssb155480 /* 28615935Ssb155480 * allocate a message for ldc_read()s, big enough to hold ctrl and 28625935Ssb155480 * data msgs, including raw data msgs used to recv priority frames. 28635935Ssb155480 */ 28646419Ssb155480 ldcp->msglen = VIO_PKT_DATA_HDRSIZE + vgenp->max_frame_size; 28655935Ssb155480 ldcp->ldcmsg = kmem_alloc(ldcp->msglen, KM_SLEEP); 28661991Sheppo attach_state |= AST_ldc_reg_cb; 28671991Sheppo 28681991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 28691991Sheppo ASSERT(istatus == LDC_INIT); 28701991Sheppo ldcp->ldc_status = istatus; 28711991Sheppo 28721991Sheppo /* allocate transmit resources */ 28731991Sheppo status = vgen_alloc_tx_ring(ldcp); 28741991Sheppo if (status != 0) { 28751991Sheppo goto ldc_attach_failed; 28761991Sheppo } 28771991Sheppo attach_state |= AST_alloc_tx_ring; 28781991Sheppo 28792336Snarayan /* allocate receive resources */ 28807529SSriharsha.Basavapatna@Sun.COM status = vgen_init_multipools(ldcp); 28812336Snarayan if (status != 0) { 28829217SWentao.Yang@Sun.COM /* 28839217SWentao.Yang@Sun.COM * We do not return failure if receive mblk pools can't be 28849217SWentao.Yang@Sun.COM * allocated; instead allocb(9F) will be used to dynamically 28859217SWentao.Yang@Sun.COM * allocate buffers during receive. 28869217SWentao.Yang@Sun.COM */ 28879217SWentao.Yang@Sun.COM DWARN(vgenp, ldcp, 28889217SWentao.Yang@Sun.COM "vnet%d: status(%d), failed to allocate rx mblk pools for " 28899217SWentao.Yang@Sun.COM "channel(0x%lx)\n", 28909217SWentao.Yang@Sun.COM vgenp->instance, status, ldcp->ldc_id); 28919217SWentao.Yang@Sun.COM } else { 28929217SWentao.Yang@Sun.COM attach_state |= AST_create_rxmblks; 28939217SWentao.Yang@Sun.COM } 28942336Snarayan 28951991Sheppo /* Setup kstats for the channel */ 28966495Sspeer instance = vgenp->instance; 28975373Sraghuram (void) sprintf(kname, "vnetldc0x%lx", ldcp->ldc_id); 28985373Sraghuram ldcp->ksp = vgen_setup_kstats("vnet", instance, kname, &ldcp->stats); 28995373Sraghuram if (ldcp->ksp == NULL) { 29001991Sheppo goto ldc_attach_failed; 29011991Sheppo } 29021991Sheppo 29031991Sheppo /* initialize vgen_versions supported */ 29041991Sheppo bcopy(vgen_versions, ldcp->vgen_versions, sizeof (ldcp->vgen_versions)); 29055935Ssb155480 vgen_reset_vnet_proto_ops(ldcp); 29061991Sheppo 29071991Sheppo /* link it into the list of channels for this port */ 29081991Sheppo WRITE_ENTER(&ldclp->rwlock); 29091991Sheppo prev_ldcp = (vgen_ldc_t **)(&ldclp->headp); 29101991Sheppo ldcp->nextp = *prev_ldcp; 29111991Sheppo *prev_ldcp = ldcp; 29121991Sheppo RW_EXIT(&ldclp->rwlock); 29131991Sheppo 29141991Sheppo ldcp->flags |= CHANNEL_ATTACHED; 29151991Sheppo return (DDI_SUCCESS); 29161991Sheppo 29171991Sheppo ldc_attach_failed: 29184647Sraghuram if (attach_state & AST_ldc_reg_cb) { 29194647Sraghuram (void) ldc_unreg_callback(ldcp->ldc_handle); 29205935Ssb155480 kmem_free(ldcp->ldcmsg, ldcp->msglen); 29214647Sraghuram } 29224647Sraghuram if (attach_state & AST_create_rcv_thread) { 29234647Sraghuram if (ldcp->rcv_thread != NULL) { 29244647Sraghuram vgen_stop_rcv_thread(ldcp); 29254647Sraghuram } 29264647Sraghuram mutex_destroy(&ldcp->rcv_thr_lock); 29274647Sraghuram cv_destroy(&ldcp->rcv_thr_cv); 29284647Sraghuram } 29292336Snarayan if (attach_state & AST_create_rxmblks) { 29304647Sraghuram vio_mblk_pool_t *fvmp = NULL; 29314647Sraghuram vio_destroy_multipools(&ldcp->vmp, &fvmp); 29324647Sraghuram ASSERT(fvmp == NULL); 29332336Snarayan } 29341991Sheppo if (attach_state & AST_alloc_tx_ring) { 29351991Sheppo vgen_free_tx_ring(ldcp); 29361991Sheppo } 29371991Sheppo if (attach_state & AST_ldc_init) { 29381991Sheppo (void) ldc_fini(ldcp->ldc_handle); 29391991Sheppo } 29401991Sheppo if (attach_state & AST_mutex_init) { 29411991Sheppo mutex_destroy(&ldcp->tclock); 29421991Sheppo mutex_destroy(&ldcp->txlock); 29431991Sheppo mutex_destroy(&ldcp->cblock); 29444647Sraghuram mutex_destroy(&ldcp->wrlock); 29454647Sraghuram mutex_destroy(&ldcp->rxlock); 29461991Sheppo } 29471991Sheppo if (attach_state & AST_ldc_alloc) { 29481991Sheppo KMEM_FREE(ldcp); 29491991Sheppo } 29501991Sheppo return (DDI_FAILURE); 29511991Sheppo } 29521991Sheppo 29531991Sheppo /* detach a channel from the port */ 29541991Sheppo static void 29551991Sheppo vgen_ldc_detach(vgen_ldc_t *ldcp) 29561991Sheppo { 29571991Sheppo vgen_port_t *portp; 29581991Sheppo vgen_t *vgenp; 29591991Sheppo vgen_ldc_t *pldcp; 29601991Sheppo vgen_ldc_t **prev_ldcp; 29611991Sheppo vgen_ldclist_t *ldclp; 29621991Sheppo 29631991Sheppo portp = ldcp->portp; 29641991Sheppo vgenp = portp->vgenp; 29651991Sheppo ldclp = &portp->ldclist; 29661991Sheppo 29671991Sheppo prev_ldcp = (vgen_ldc_t **)&ldclp->headp; 29681991Sheppo for (; (pldcp = *prev_ldcp) != NULL; prev_ldcp = &pldcp->nextp) { 29691991Sheppo if (pldcp == ldcp) { 29701991Sheppo break; 29711991Sheppo } 29721991Sheppo } 29731991Sheppo 29741991Sheppo if (pldcp == NULL) { 29751991Sheppo /* invalid ldcp? */ 29761991Sheppo return; 29771991Sheppo } 29781991Sheppo 29791991Sheppo if (ldcp->ldc_status != LDC_INIT) { 29804647Sraghuram DWARN(vgenp, ldcp, "ldc_status is not INIT\n"); 29811991Sheppo } 29821991Sheppo 29831991Sheppo if (ldcp->flags & CHANNEL_ATTACHED) { 29841991Sheppo ldcp->flags &= ~(CHANNEL_ATTACHED); 29851991Sheppo 29864647Sraghuram (void) ldc_unreg_callback(ldcp->ldc_handle); 29874647Sraghuram if (ldcp->rcv_thread != NULL) { 29884647Sraghuram /* First stop the receive thread */ 29894647Sraghuram vgen_stop_rcv_thread(ldcp); 29904647Sraghuram mutex_destroy(&ldcp->rcv_thr_lock); 29914647Sraghuram cv_destroy(&ldcp->rcv_thr_cv); 29924647Sraghuram } 29935935Ssb155480 kmem_free(ldcp->ldcmsg, ldcp->msglen); 29944647Sraghuram 29955373Sraghuram vgen_destroy_kstats(ldcp->ksp); 29965373Sraghuram ldcp->ksp = NULL; 29975373Sraghuram 29984647Sraghuram /* 29994647Sraghuram * if we cannot reclaim all mblks, put this 30004647Sraghuram * on the list of pools(vgenp->rmp) to be reclaimed when the 30014647Sraghuram * device gets detached (see vgen_uninit()). 30024647Sraghuram */ 30034647Sraghuram vio_destroy_multipools(&ldcp->vmp, &vgenp->rmp); 30042336Snarayan 30051991Sheppo /* free transmit resources */ 30061991Sheppo vgen_free_tx_ring(ldcp); 30072336Snarayan 30081991Sheppo (void) ldc_fini(ldcp->ldc_handle); 30091991Sheppo mutex_destroy(&ldcp->tclock); 30101991Sheppo mutex_destroy(&ldcp->txlock); 30111991Sheppo mutex_destroy(&ldcp->cblock); 30124647Sraghuram mutex_destroy(&ldcp->wrlock); 30134647Sraghuram mutex_destroy(&ldcp->rxlock); 30141991Sheppo 30151991Sheppo /* unlink it from the list */ 30161991Sheppo *prev_ldcp = ldcp->nextp; 30171991Sheppo KMEM_FREE(ldcp); 30181991Sheppo } 30191991Sheppo } 30201991Sheppo 30211991Sheppo /* 30221991Sheppo * This function allocates transmit resources for the channel. 30231991Sheppo * The resources consist of a transmit descriptor ring and an associated 30241991Sheppo * transmit buffer ring. 30251991Sheppo */ 30261991Sheppo static int 30271991Sheppo vgen_alloc_tx_ring(vgen_ldc_t *ldcp) 30281991Sheppo { 30291991Sheppo void *tbufp; 30301991Sheppo ldc_mem_info_t minfo; 30311991Sheppo uint32_t txdsize; 30321991Sheppo uint32_t tbufsize; 30331991Sheppo int status; 30344647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 30351991Sheppo 30361991Sheppo ldcp->num_txds = vnet_ntxds; 30371991Sheppo txdsize = sizeof (vnet_public_desc_t); 30381991Sheppo tbufsize = sizeof (vgen_private_desc_t); 30391991Sheppo 30401991Sheppo /* allocate transmit buffer ring */ 30411991Sheppo tbufp = kmem_zalloc(ldcp->num_txds * tbufsize, KM_NOSLEEP); 30421991Sheppo if (tbufp == NULL) { 30431991Sheppo return (DDI_FAILURE); 30441991Sheppo } 30451991Sheppo 30461991Sheppo /* create transmit descriptor ring */ 30471991Sheppo status = ldc_mem_dring_create(ldcp->num_txds, txdsize, 30481991Sheppo &ldcp->tx_dhandle); 30491991Sheppo if (status) { 30504647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_create() failed\n"); 30511991Sheppo kmem_free(tbufp, ldcp->num_txds * tbufsize); 30521991Sheppo return (DDI_FAILURE); 30531991Sheppo } 30541991Sheppo 30551991Sheppo /* get the addr of descripror ring */ 30561991Sheppo status = ldc_mem_dring_info(ldcp->tx_dhandle, &minfo); 30571991Sheppo if (status) { 30584647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_info() failed\n"); 30591991Sheppo kmem_free(tbufp, ldcp->num_txds * tbufsize); 30601991Sheppo (void) ldc_mem_dring_destroy(ldcp->tx_dhandle); 30611991Sheppo ldcp->tbufp = NULL; 30621991Sheppo return (DDI_FAILURE); 30631991Sheppo } 30641991Sheppo ldcp->txdp = (vnet_public_desc_t *)(minfo.vaddr); 30651991Sheppo ldcp->tbufp = tbufp; 30661991Sheppo 30671991Sheppo ldcp->txdendp = &((ldcp->txdp)[ldcp->num_txds]); 30681991Sheppo ldcp->tbufendp = &((ldcp->tbufp)[ldcp->num_txds]); 30691991Sheppo 30701991Sheppo return (DDI_SUCCESS); 30711991Sheppo } 30721991Sheppo 30731991Sheppo /* Free transmit resources for the channel */ 30741991Sheppo static void 30751991Sheppo vgen_free_tx_ring(vgen_ldc_t *ldcp) 30761991Sheppo { 30771991Sheppo int tbufsize = sizeof (vgen_private_desc_t); 30781991Sheppo 30791991Sheppo /* free transmit descriptor ring */ 30801991Sheppo (void) ldc_mem_dring_destroy(ldcp->tx_dhandle); 30811991Sheppo 30821991Sheppo /* free transmit buffer ring */ 30831991Sheppo kmem_free(ldcp->tbufp, ldcp->num_txds * tbufsize); 30841991Sheppo ldcp->txdp = ldcp->txdendp = NULL; 30851991Sheppo ldcp->tbufp = ldcp->tbufendp = NULL; 30861991Sheppo } 30871991Sheppo 30881991Sheppo /* enable transmit/receive on the channels for the port */ 30891991Sheppo static void 30901991Sheppo vgen_init_ldcs(vgen_port_t *portp) 30911991Sheppo { 30921991Sheppo vgen_ldclist_t *ldclp = &portp->ldclist; 30931991Sheppo vgen_ldc_t *ldcp; 30941991Sheppo 30951991Sheppo READ_ENTER(&ldclp->rwlock); 30961991Sheppo ldcp = ldclp->headp; 30971991Sheppo for (; ldcp != NULL; ldcp = ldcp->nextp) { 30981991Sheppo (void) vgen_ldc_init(ldcp); 30991991Sheppo } 31001991Sheppo RW_EXIT(&ldclp->rwlock); 31011991Sheppo } 31021991Sheppo 31031991Sheppo /* stop transmit/receive on the channels for the port */ 31041991Sheppo static void 31051991Sheppo vgen_uninit_ldcs(vgen_port_t *portp) 31061991Sheppo { 31071991Sheppo vgen_ldclist_t *ldclp = &portp->ldclist; 31081991Sheppo vgen_ldc_t *ldcp; 31091991Sheppo 31101991Sheppo READ_ENTER(&ldclp->rwlock); 31111991Sheppo ldcp = ldclp->headp; 31121991Sheppo for (; ldcp != NULL; ldcp = ldcp->nextp) { 31131991Sheppo vgen_ldc_uninit(ldcp); 31141991Sheppo } 31151991Sheppo RW_EXIT(&ldclp->rwlock); 31161991Sheppo } 31171991Sheppo 31181991Sheppo /* enable transmit/receive on the channel */ 31191991Sheppo static int 31201991Sheppo vgen_ldc_init(vgen_ldc_t *ldcp) 31211991Sheppo { 31224647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 31231991Sheppo ldc_status_t istatus; 31241991Sheppo int rv; 31252109Slm66018 uint32_t retries = 0; 31264647Sraghuram enum { ST_init = 0x0, ST_ldc_open = 0x1, 31274647Sraghuram ST_init_tbufs = 0x2, ST_cb_enable = 0x4} init_state; 31281991Sheppo init_state = ST_init; 31291991Sheppo 31304647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 31311991Sheppo LDC_LOCK(ldcp); 31321991Sheppo 31331991Sheppo rv = ldc_open(ldcp->ldc_handle); 31341991Sheppo if (rv != 0) { 31354647Sraghuram DWARN(vgenp, ldcp, "ldc_open failed: rv(%d)\n", rv); 31361991Sheppo goto ldcinit_failed; 31371991Sheppo } 31381991Sheppo init_state |= ST_ldc_open; 31391991Sheppo 31401991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 31411991Sheppo if (istatus != LDC_OPEN && istatus != LDC_READY) { 31424647Sraghuram DWARN(vgenp, ldcp, "status(%d) is not OPEN/READY\n", istatus); 31431991Sheppo goto ldcinit_failed; 31441991Sheppo } 31451991Sheppo ldcp->ldc_status = istatus; 31461991Sheppo 31471991Sheppo rv = vgen_init_tbufs(ldcp); 31481991Sheppo if (rv != 0) { 31494647Sraghuram DWARN(vgenp, ldcp, "vgen_init_tbufs() failed\n"); 31501991Sheppo goto ldcinit_failed; 31511991Sheppo } 31521991Sheppo init_state |= ST_init_tbufs; 31531991Sheppo 31542748Slm66018 rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_ENABLE); 31552748Slm66018 if (rv != 0) { 31564647Sraghuram DWARN(vgenp, ldcp, "ldc_set_cb_mode failed: rv(%d)\n", rv); 31572748Slm66018 goto ldcinit_failed; 31582748Slm66018 } 31592748Slm66018 31602748Slm66018 init_state |= ST_cb_enable; 31612748Slm66018 31622109Slm66018 do { 31632109Slm66018 rv = ldc_up(ldcp->ldc_handle); 31642109Slm66018 if ((rv != 0) && (rv == EWOULDBLOCK)) { 31654647Sraghuram DBG2(vgenp, ldcp, "ldc_up err rv(%d)\n", rv); 31662109Slm66018 drv_usecwait(VGEN_LDC_UP_DELAY); 31672109Slm66018 } 31682109Slm66018 if (retries++ >= vgen_ldcup_retries) 31692109Slm66018 break; 31702109Slm66018 } while (rv == EWOULDBLOCK); 31711991Sheppo 31721991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 31732793Slm66018 if (istatus == LDC_UP) { 31744647Sraghuram DWARN(vgenp, ldcp, "status(%d) is UP\n", istatus); 31751991Sheppo } 31762793Slm66018 31771991Sheppo ldcp->ldc_status = istatus; 31781991Sheppo 31791991Sheppo /* initialize transmit watchdog timeout */ 31801991Sheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp, 31811991Sheppo drv_usectohz(vnet_ldcwd_interval * 1000)); 31821991Sheppo 31832793Slm66018 ldcp->hphase = -1; 31841991Sheppo ldcp->flags |= CHANNEL_STARTED; 31851991Sheppo 31862793Slm66018 /* if channel is already UP - start handshake */ 31872793Slm66018 if (istatus == LDC_UP) { 31882793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 31892793Slm66018 if (ldcp->portp != vgenp->vsw_portp) { 31902793Slm66018 /* 31916495Sspeer * As the channel is up, use this port from now on. 31922793Slm66018 */ 31936495Sspeer (void) atomic_swap_32( 31946495Sspeer &ldcp->portp->use_vsw_port, B_FALSE); 31952793Slm66018 } 31962793Slm66018 31972793Slm66018 /* Initialize local session id */ 31982793Slm66018 ldcp->local_sid = ddi_get_lbolt(); 31992793Slm66018 32002793Slm66018 /* clear peer session id */ 32012793Slm66018 ldcp->peer_sid = 0; 32022793Slm66018 ldcp->hretries = 0; 32032793Slm66018 32042793Slm66018 /* Initiate Handshake process with peer ldc endpoint */ 32052793Slm66018 vgen_reset_hphase(ldcp); 32062793Slm66018 32072793Slm66018 mutex_exit(&ldcp->tclock); 32082793Slm66018 mutex_exit(&ldcp->txlock); 32094647Sraghuram mutex_exit(&ldcp->wrlock); 32105708Sraghuram mutex_exit(&ldcp->rxlock); 32112793Slm66018 vgen_handshake(vh_nextphase(ldcp)); 32122793Slm66018 mutex_exit(&ldcp->cblock); 32132793Slm66018 } else { 32142793Slm66018 LDC_UNLOCK(ldcp); 32152793Slm66018 } 32162793Slm66018 32171991Sheppo return (DDI_SUCCESS); 32181991Sheppo 32191991Sheppo ldcinit_failed: 32202748Slm66018 if (init_state & ST_cb_enable) { 32212748Slm66018 (void) ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE); 32222748Slm66018 } 32231991Sheppo if (init_state & ST_init_tbufs) { 32241991Sheppo vgen_uninit_tbufs(ldcp); 32251991Sheppo } 32261991Sheppo if (init_state & ST_ldc_open) { 32271991Sheppo (void) ldc_close(ldcp->ldc_handle); 32281991Sheppo } 32291991Sheppo LDC_UNLOCK(ldcp); 32304647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 32311991Sheppo return (DDI_FAILURE); 32321991Sheppo } 32331991Sheppo 32341991Sheppo /* stop transmit/receive on the channel */ 32351991Sheppo static void 32361991Sheppo vgen_ldc_uninit(vgen_ldc_t *ldcp) 32371991Sheppo { 32384647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 32391991Sheppo int rv; 32408623SSriharsha.Basavapatna@Sun.COM uint_t retries = 0; 32411991Sheppo 32424647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 32431991Sheppo LDC_LOCK(ldcp); 32441991Sheppo 32451991Sheppo if ((ldcp->flags & CHANNEL_STARTED) == 0) { 32461991Sheppo LDC_UNLOCK(ldcp); 32474647Sraghuram DWARN(vgenp, ldcp, "CHANNEL_STARTED flag is not set\n"); 32481991Sheppo return; 32491991Sheppo } 32501991Sheppo 32511991Sheppo /* disable further callbacks */ 32521991Sheppo rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE); 32531991Sheppo if (rv != 0) { 32544647Sraghuram DWARN(vgenp, ldcp, "ldc_set_cb_mode failed\n"); 32551991Sheppo } 32561991Sheppo 32576495Sspeer if (vgenp->vsw_portp == ldcp->portp) { 32586495Sspeer vio_net_report_err_t rep_err = 32596495Sspeer ldcp->portp->vcb.vio_net_report_err; 32606495Sspeer rep_err(ldcp->portp->vhp, VIO_NET_RES_DOWN); 32616495Sspeer } 32626495Sspeer 32633653Snarayan /* 32643653Snarayan * clear handshake done bit and wait for pending tx and cb to finish. 32653653Snarayan * release locks before untimeout(9F) is invoked to cancel timeouts. 32663653Snarayan */ 32671991Sheppo ldcp->hphase &= ~(VH_DONE); 32681991Sheppo LDC_UNLOCK(ldcp); 32693653Snarayan 32703653Snarayan /* cancel handshake watchdog timeout */ 32713653Snarayan if (ldcp->htid) { 32723653Snarayan (void) untimeout(ldcp->htid); 32733653Snarayan ldcp->htid = 0; 32743653Snarayan } 32753653Snarayan 32767572SWentao.Yang@Sun.COM if (ldcp->cancel_htid) { 32777572SWentao.Yang@Sun.COM (void) untimeout(ldcp->cancel_htid); 32787572SWentao.Yang@Sun.COM ldcp->cancel_htid = 0; 32797572SWentao.Yang@Sun.COM } 32807572SWentao.Yang@Sun.COM 32813653Snarayan /* cancel transmit watchdog timeout */ 32821991Sheppo if (ldcp->wd_tid) { 32831991Sheppo (void) untimeout(ldcp->wd_tid); 32841991Sheppo ldcp->wd_tid = 0; 32851991Sheppo } 32861991Sheppo 32873653Snarayan drv_usecwait(1000); 32883653Snarayan 32898623SSriharsha.Basavapatna@Sun.COM if (ldcp->rcv_thread != NULL) { 32908623SSriharsha.Basavapatna@Sun.COM /* 32918623SSriharsha.Basavapatna@Sun.COM * Note that callbacks have been disabled already(above). The 32928623SSriharsha.Basavapatna@Sun.COM * drain function takes care of the condition when an already 32938623SSriharsha.Basavapatna@Sun.COM * executing callback signals the worker to start processing or 32948623SSriharsha.Basavapatna@Sun.COM * the worker has already been signalled and is in the middle of 32958623SSriharsha.Basavapatna@Sun.COM * processing. 32968623SSriharsha.Basavapatna@Sun.COM */ 32978623SSriharsha.Basavapatna@Sun.COM vgen_drain_rcv_thread(ldcp); 32988623SSriharsha.Basavapatna@Sun.COM } 32998623SSriharsha.Basavapatna@Sun.COM 33003653Snarayan /* acquire locks again; any pending transmits and callbacks are done */ 33013653Snarayan LDC_LOCK(ldcp); 33023653Snarayan 33033653Snarayan vgen_reset_hphase(ldcp); 33043653Snarayan 33051991Sheppo vgen_uninit_tbufs(ldcp); 33061991Sheppo 33078623SSriharsha.Basavapatna@Sun.COM /* close the channel - retry on EAGAIN */ 33088623SSriharsha.Basavapatna@Sun.COM while ((rv = ldc_close(ldcp->ldc_handle)) == EAGAIN) { 33098623SSriharsha.Basavapatna@Sun.COM if (++retries > vgen_ldccl_retries) { 33108623SSriharsha.Basavapatna@Sun.COM break; 33118623SSriharsha.Basavapatna@Sun.COM } 33128623SSriharsha.Basavapatna@Sun.COM drv_usecwait(VGEN_LDC_CLOSE_DELAY); 33138623SSriharsha.Basavapatna@Sun.COM } 33141991Sheppo if (rv != 0) { 33158623SSriharsha.Basavapatna@Sun.COM cmn_err(CE_NOTE, 33168623SSriharsha.Basavapatna@Sun.COM "!vnet%d: Error(%d) closing the channel(0x%lx)\n", 33178623SSriharsha.Basavapatna@Sun.COM vgenp->instance, rv, ldcp->ldc_id); 33188623SSriharsha.Basavapatna@Sun.COM } 33198623SSriharsha.Basavapatna@Sun.COM 33201991Sheppo ldcp->ldc_status = LDC_INIT; 33211991Sheppo ldcp->flags &= ~(CHANNEL_STARTED); 33221991Sheppo 33231991Sheppo LDC_UNLOCK(ldcp); 33241991Sheppo 33254647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 33261991Sheppo } 33271991Sheppo 33281991Sheppo /* Initialize the transmit buffer ring for the channel */ 33291991Sheppo static int 33301991Sheppo vgen_init_tbufs(vgen_ldc_t *ldcp) 33311991Sheppo { 33321991Sheppo vgen_private_desc_t *tbufp; 33331991Sheppo vnet_public_desc_t *txdp; 33341991Sheppo vio_dring_entry_hdr_t *hdrp; 33351991Sheppo int i; 33361991Sheppo int rv; 33372109Slm66018 caddr_t datap = NULL; 33382109Slm66018 int ci; 33392109Slm66018 uint32_t ncookies; 33406419Ssb155480 size_t data_sz; 33416419Ssb155480 vgen_t *vgenp; 33426419Ssb155480 33436419Ssb155480 vgenp = LDC_TO_VGEN(ldcp); 33441991Sheppo 33451991Sheppo bzero(ldcp->tbufp, sizeof (*tbufp) * (ldcp->num_txds)); 33461991Sheppo bzero(ldcp->txdp, sizeof (*txdp) * (ldcp->num_txds)); 33471991Sheppo 33487529SSriharsha.Basavapatna@Sun.COM /* 33497529SSriharsha.Basavapatna@Sun.COM * In order to ensure that the number of ldc cookies per descriptor is 33507529SSriharsha.Basavapatna@Sun.COM * limited to be within the default MAX_COOKIES (2), we take the steps 33517529SSriharsha.Basavapatna@Sun.COM * outlined below: 33527529SSriharsha.Basavapatna@Sun.COM * 33537529SSriharsha.Basavapatna@Sun.COM * Align the entire data buffer area to 8K and carve out per descriptor 33547529SSriharsha.Basavapatna@Sun.COM * data buffers starting from this 8K aligned base address. 33557529SSriharsha.Basavapatna@Sun.COM * 33567529SSriharsha.Basavapatna@Sun.COM * We round up the mtu specified to be a multiple of 2K or 4K. 33577529SSriharsha.Basavapatna@Sun.COM * For sizes up to 12K we round up the size to the next 2K. 33587529SSriharsha.Basavapatna@Sun.COM * For sizes > 12K we round up to the next 4K (otherwise sizes such as 33597529SSriharsha.Basavapatna@Sun.COM * 14K could end up needing 3 cookies, with the buffer spread across 33607529SSriharsha.Basavapatna@Sun.COM * 3 8K pages: 8K+6K, 2K+8K+2K, 6K+8K, ...). 33617529SSriharsha.Basavapatna@Sun.COM */ 33626419Ssb155480 data_sz = vgenp->max_frame_size + VNET_IPALIGN + VNET_LDCALIGN; 33637529SSriharsha.Basavapatna@Sun.COM if (data_sz <= VNET_12K) { 33647529SSriharsha.Basavapatna@Sun.COM data_sz = VNET_ROUNDUP_2K(data_sz); 33657529SSriharsha.Basavapatna@Sun.COM } else { 33667529SSriharsha.Basavapatna@Sun.COM data_sz = VNET_ROUNDUP_4K(data_sz); 33677529SSriharsha.Basavapatna@Sun.COM } 33687529SSriharsha.Basavapatna@Sun.COM 33697529SSriharsha.Basavapatna@Sun.COM /* allocate extra 8K bytes for alignment */ 33707529SSriharsha.Basavapatna@Sun.COM ldcp->tx_data_sz = (data_sz * ldcp->num_txds) + VNET_8K; 33716419Ssb155480 datap = kmem_zalloc(ldcp->tx_data_sz, KM_SLEEP); 33722109Slm66018 ldcp->tx_datap = datap; 33732109Slm66018 33747529SSriharsha.Basavapatna@Sun.COM 33757529SSriharsha.Basavapatna@Sun.COM /* align the starting address of the data area to 8K */ 33767529SSriharsha.Basavapatna@Sun.COM datap = (caddr_t)VNET_ROUNDUP_8K((uintptr_t)datap); 33777529SSriharsha.Basavapatna@Sun.COM 33781991Sheppo /* 33792109Slm66018 * for each private descriptor, allocate a ldc mem_handle which is 33801991Sheppo * required to map the data during transmit, set the flags 33811991Sheppo * to free (available for use by transmit routine). 33821991Sheppo */ 33831991Sheppo 33841991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 33852109Slm66018 33861991Sheppo tbufp = &(ldcp->tbufp[i]); 33871991Sheppo rv = ldc_mem_alloc_handle(ldcp->ldc_handle, 33884650Sraghuram &(tbufp->memhandle)); 33891991Sheppo if (rv) { 33901991Sheppo tbufp->memhandle = 0; 33911991Sheppo goto init_tbufs_failed; 33921991Sheppo } 33932109Slm66018 33942109Slm66018 /* 33952109Slm66018 * bind ldc memhandle to the corresponding transmit buffer. 33962109Slm66018 */ 33972109Slm66018 ci = ncookies = 0; 33982109Slm66018 rv = ldc_mem_bind_handle(tbufp->memhandle, 33996419Ssb155480 (caddr_t)datap, data_sz, LDC_SHADOW_MAP, 34002109Slm66018 LDC_MEM_R, &(tbufp->memcookie[ci]), &ncookies); 34012109Slm66018 if (rv != 0) { 34022109Slm66018 goto init_tbufs_failed; 34032109Slm66018 } 34042109Slm66018 34052109Slm66018 /* 34062109Slm66018 * successful in binding the handle to tx data buffer. 34072109Slm66018 * set datap in the private descr to this buffer. 34082109Slm66018 */ 34092109Slm66018 tbufp->datap = datap; 34102109Slm66018 34112109Slm66018 if ((ncookies == 0) || 34124650Sraghuram (ncookies > MAX_COOKIES)) { 34132109Slm66018 goto init_tbufs_failed; 34142109Slm66018 } 34152109Slm66018 34162109Slm66018 for (ci = 1; ci < ncookies; ci++) { 34172109Slm66018 rv = ldc_mem_nextcookie(tbufp->memhandle, 34184650Sraghuram &(tbufp->memcookie[ci])); 34192109Slm66018 if (rv != 0) { 34202109Slm66018 goto init_tbufs_failed; 34212109Slm66018 } 34222109Slm66018 } 34232109Slm66018 34242109Slm66018 tbufp->ncookies = ncookies; 34256419Ssb155480 datap += data_sz; 34262109Slm66018 34271991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 34281991Sheppo txdp = &(ldcp->txdp[i]); 34291991Sheppo hdrp = &txdp->hdr; 34301991Sheppo hdrp->dstate = VIO_DESC_FREE; 34311991Sheppo hdrp->ack = B_FALSE; 34321991Sheppo tbufp->descp = txdp; 34332109Slm66018 34341991Sheppo } 34351991Sheppo 34361991Sheppo /* reset tbuf walking pointers */ 34371991Sheppo ldcp->next_tbufp = ldcp->tbufp; 34381991Sheppo ldcp->cur_tbufp = ldcp->tbufp; 34391991Sheppo 34401991Sheppo /* initialize tx seqnum and index */ 34411991Sheppo ldcp->next_txseq = VNET_ISS; 34421991Sheppo ldcp->next_txi = 0; 34431991Sheppo 34442336Snarayan ldcp->resched_peer = B_TRUE; 34454647Sraghuram ldcp->resched_peer_txi = 0; 34462336Snarayan 34471991Sheppo return (DDI_SUCCESS); 34481991Sheppo 34491991Sheppo init_tbufs_failed:; 34501991Sheppo vgen_uninit_tbufs(ldcp); 34511991Sheppo return (DDI_FAILURE); 34521991Sheppo } 34531991Sheppo 34541991Sheppo /* Uninitialize transmit buffer ring for the channel */ 34551991Sheppo static void 34561991Sheppo vgen_uninit_tbufs(vgen_ldc_t *ldcp) 34571991Sheppo { 34581991Sheppo vgen_private_desc_t *tbufp = ldcp->tbufp; 34591991Sheppo int i; 34601991Sheppo 34611991Sheppo /* for each tbuf (priv_desc), free ldc mem_handle */ 34621991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 34631991Sheppo 34641991Sheppo tbufp = &(ldcp->tbufp[i]); 34651991Sheppo 34662109Slm66018 if (tbufp->datap) { /* if bound to a ldc memhandle */ 34671991Sheppo (void) ldc_mem_unbind_handle(tbufp->memhandle); 34682109Slm66018 tbufp->datap = NULL; 34691991Sheppo } 34701991Sheppo if (tbufp->memhandle) { 34711991Sheppo (void) ldc_mem_free_handle(tbufp->memhandle); 34721991Sheppo tbufp->memhandle = 0; 34731991Sheppo } 34741991Sheppo } 34751991Sheppo 34762109Slm66018 if (ldcp->tx_datap) { 34772109Slm66018 /* prealloc'd tx data buffer */ 34786419Ssb155480 kmem_free(ldcp->tx_datap, ldcp->tx_data_sz); 34792109Slm66018 ldcp->tx_datap = NULL; 34806419Ssb155480 ldcp->tx_data_sz = 0; 34812109Slm66018 } 34822109Slm66018 34832748Slm66018 bzero(ldcp->tbufp, sizeof (vgen_private_desc_t) * (ldcp->num_txds)); 34842748Slm66018 bzero(ldcp->txdp, sizeof (vnet_public_desc_t) * (ldcp->num_txds)); 34851991Sheppo } 34861991Sheppo 34871991Sheppo /* clobber tx descriptor ring */ 34881991Sheppo static void 34891991Sheppo vgen_clobber_tbufs(vgen_ldc_t *ldcp) 34901991Sheppo { 34911991Sheppo vnet_public_desc_t *txdp; 34921991Sheppo vgen_private_desc_t *tbufp; 34934647Sraghuram vio_dring_entry_hdr_t *hdrp; 34944647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 34951991Sheppo int i; 34961991Sheppo #ifdef DEBUG 34971991Sheppo int ndone = 0; 34981991Sheppo #endif 34991991Sheppo 35001991Sheppo for (i = 0; i < ldcp->num_txds; i++) { 35011991Sheppo 35021991Sheppo tbufp = &(ldcp->tbufp[i]); 35031991Sheppo txdp = tbufp->descp; 35041991Sheppo hdrp = &txdp->hdr; 35051991Sheppo 35061991Sheppo if (tbufp->flags & VGEN_PRIV_DESC_BUSY) { 35071991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 35081991Sheppo #ifdef DEBUG 35091991Sheppo if (hdrp->dstate == VIO_DESC_DONE) 35101991Sheppo ndone++; 35111991Sheppo #endif 35121991Sheppo hdrp->dstate = VIO_DESC_FREE; 35131991Sheppo hdrp->ack = B_FALSE; 35141991Sheppo } 35151991Sheppo } 35161991Sheppo /* reset tbuf walking pointers */ 35171991Sheppo ldcp->next_tbufp = ldcp->tbufp; 35181991Sheppo ldcp->cur_tbufp = ldcp->tbufp; 35191991Sheppo 35201991Sheppo /* reset tx seqnum and index */ 35211991Sheppo ldcp->next_txseq = VNET_ISS; 35221991Sheppo ldcp->next_txi = 0; 35232336Snarayan 35242336Snarayan ldcp->resched_peer = B_TRUE; 35254647Sraghuram ldcp->resched_peer_txi = 0; 35264647Sraghuram 35274647Sraghuram DBG2(vgenp, ldcp, "num descrs done (%d)\n", ndone); 35281991Sheppo } 35291991Sheppo 35301991Sheppo /* clobber receive descriptor ring */ 35311991Sheppo static void 35321991Sheppo vgen_clobber_rxds(vgen_ldc_t *ldcp) 35331991Sheppo { 35341991Sheppo ldcp->rx_dhandle = 0; 35351991Sheppo bzero(&ldcp->rx_dcookie, sizeof (ldcp->rx_dcookie)); 35361991Sheppo ldcp->rxdp = NULL; 35371991Sheppo ldcp->next_rxi = 0; 35381991Sheppo ldcp->num_rxds = 0; 35391991Sheppo ldcp->next_rxseq = VNET_ISS; 35401991Sheppo } 35411991Sheppo 35421991Sheppo /* initialize receive descriptor ring */ 35431991Sheppo static int 35441991Sheppo vgen_init_rxds(vgen_ldc_t *ldcp, uint32_t num_desc, uint32_t desc_size, 35451991Sheppo ldc_mem_cookie_t *dcookie, uint32_t ncookies) 35461991Sheppo { 35471991Sheppo int rv; 35481991Sheppo ldc_mem_info_t minfo; 35491991Sheppo 35501991Sheppo rv = ldc_mem_dring_map(ldcp->ldc_handle, dcookie, ncookies, num_desc, 35516845Sha137994 desc_size, LDC_DIRECT_MAP, &(ldcp->rx_dhandle)); 35521991Sheppo if (rv != 0) { 35531991Sheppo return (DDI_FAILURE); 35541991Sheppo } 35551991Sheppo 35561991Sheppo /* 35571991Sheppo * sucessfully mapped, now try to 35581991Sheppo * get info about the mapped dring 35591991Sheppo */ 35601991Sheppo rv = ldc_mem_dring_info(ldcp->rx_dhandle, &minfo); 35611991Sheppo if (rv != 0) { 35621991Sheppo (void) ldc_mem_dring_unmap(ldcp->rx_dhandle); 35631991Sheppo return (DDI_FAILURE); 35641991Sheppo } 35651991Sheppo 35661991Sheppo /* 35671991Sheppo * save ring address, number of descriptors. 35681991Sheppo */ 35691991Sheppo ldcp->rxdp = (vnet_public_desc_t *)(minfo.vaddr); 35701991Sheppo bcopy(dcookie, &(ldcp->rx_dcookie), sizeof (*dcookie)); 35711991Sheppo ldcp->num_rxdcookies = ncookies; 35721991Sheppo ldcp->num_rxds = num_desc; 35731991Sheppo ldcp->next_rxi = 0; 35741991Sheppo ldcp->next_rxseq = VNET_ISS; 35756845Sha137994 ldcp->dring_mtype = minfo.mtype; 35761991Sheppo 35771991Sheppo return (DDI_SUCCESS); 35781991Sheppo } 35791991Sheppo 35801991Sheppo /* get channel statistics */ 35811991Sheppo static uint64_t 35822311Sseb vgen_ldc_stat(vgen_ldc_t *ldcp, uint_t stat) 35831991Sheppo { 35841991Sheppo vgen_stats_t *statsp; 35851991Sheppo uint64_t val; 35861991Sheppo 35871991Sheppo val = 0; 35885373Sraghuram statsp = &ldcp->stats; 35891991Sheppo switch (stat) { 35901991Sheppo 35911991Sheppo case MAC_STAT_MULTIRCV: 35921991Sheppo val = statsp->multircv; 35931991Sheppo break; 35941991Sheppo 35951991Sheppo case MAC_STAT_BRDCSTRCV: 35961991Sheppo val = statsp->brdcstrcv; 35971991Sheppo break; 35981991Sheppo 35991991Sheppo case MAC_STAT_MULTIXMT: 36001991Sheppo val = statsp->multixmt; 36011991Sheppo break; 36021991Sheppo 36031991Sheppo case MAC_STAT_BRDCSTXMT: 36041991Sheppo val = statsp->brdcstxmt; 36051991Sheppo break; 36061991Sheppo 36071991Sheppo case MAC_STAT_NORCVBUF: 36081991Sheppo val = statsp->norcvbuf; 36091991Sheppo break; 36101991Sheppo 36111991Sheppo case MAC_STAT_IERRORS: 36121991Sheppo val = statsp->ierrors; 36131991Sheppo break; 36141991Sheppo 36151991Sheppo case MAC_STAT_NOXMTBUF: 36161991Sheppo val = statsp->noxmtbuf; 36171991Sheppo break; 36181991Sheppo 36191991Sheppo case MAC_STAT_OERRORS: 36201991Sheppo val = statsp->oerrors; 36211991Sheppo break; 36221991Sheppo 36231991Sheppo case MAC_STAT_COLLISIONS: 36241991Sheppo break; 36251991Sheppo 36261991Sheppo case MAC_STAT_RBYTES: 36271991Sheppo val = statsp->rbytes; 36281991Sheppo break; 36291991Sheppo 36301991Sheppo case MAC_STAT_IPACKETS: 36311991Sheppo val = statsp->ipackets; 36321991Sheppo break; 36331991Sheppo 36341991Sheppo case MAC_STAT_OBYTES: 36351991Sheppo val = statsp->obytes; 36361991Sheppo break; 36371991Sheppo 36381991Sheppo case MAC_STAT_OPACKETS: 36391991Sheppo val = statsp->opackets; 36401991Sheppo break; 36411991Sheppo 36421991Sheppo /* stats not relevant to ldc, return 0 */ 36431991Sheppo case MAC_STAT_IFSPEED: 36442311Sseb case ETHER_STAT_ALIGN_ERRORS: 36452311Sseb case ETHER_STAT_FCS_ERRORS: 36462311Sseb case ETHER_STAT_FIRST_COLLISIONS: 36472311Sseb case ETHER_STAT_MULTI_COLLISIONS: 36482311Sseb case ETHER_STAT_DEFER_XMTS: 36492311Sseb case ETHER_STAT_TX_LATE_COLLISIONS: 36502311Sseb case ETHER_STAT_EX_COLLISIONS: 36512311Sseb case ETHER_STAT_MACXMT_ERRORS: 36522311Sseb case ETHER_STAT_CARRIER_ERRORS: 36532311Sseb case ETHER_STAT_TOOLONG_ERRORS: 36542311Sseb case ETHER_STAT_XCVR_ADDR: 36552311Sseb case ETHER_STAT_XCVR_ID: 36562311Sseb case ETHER_STAT_XCVR_INUSE: 36572311Sseb case ETHER_STAT_CAP_1000FDX: 36582311Sseb case ETHER_STAT_CAP_1000HDX: 36592311Sseb case ETHER_STAT_CAP_100FDX: 36602311Sseb case ETHER_STAT_CAP_100HDX: 36612311Sseb case ETHER_STAT_CAP_10FDX: 36622311Sseb case ETHER_STAT_CAP_10HDX: 36632311Sseb case ETHER_STAT_CAP_ASMPAUSE: 36642311Sseb case ETHER_STAT_CAP_PAUSE: 36652311Sseb case ETHER_STAT_CAP_AUTONEG: 36662311Sseb case ETHER_STAT_ADV_CAP_1000FDX: 36672311Sseb case ETHER_STAT_ADV_CAP_1000HDX: 36682311Sseb case ETHER_STAT_ADV_CAP_100FDX: 36692311Sseb case ETHER_STAT_ADV_CAP_100HDX: 36702311Sseb case ETHER_STAT_ADV_CAP_10FDX: 36712311Sseb case ETHER_STAT_ADV_CAP_10HDX: 36722311Sseb case ETHER_STAT_ADV_CAP_ASMPAUSE: 36732311Sseb case ETHER_STAT_ADV_CAP_PAUSE: 36742311Sseb case ETHER_STAT_ADV_CAP_AUTONEG: 36752311Sseb case ETHER_STAT_LP_CAP_1000FDX: 36762311Sseb case ETHER_STAT_LP_CAP_1000HDX: 36772311Sseb case ETHER_STAT_LP_CAP_100FDX: 36782311Sseb case ETHER_STAT_LP_CAP_100HDX: 36792311Sseb case ETHER_STAT_LP_CAP_10FDX: 36802311Sseb case ETHER_STAT_LP_CAP_10HDX: 36812311Sseb case ETHER_STAT_LP_CAP_ASMPAUSE: 36822311Sseb case ETHER_STAT_LP_CAP_PAUSE: 36832311Sseb case ETHER_STAT_LP_CAP_AUTONEG: 36842311Sseb case ETHER_STAT_LINK_ASMPAUSE: 36852311Sseb case ETHER_STAT_LINK_PAUSE: 36862311Sseb case ETHER_STAT_LINK_AUTONEG: 36872311Sseb case ETHER_STAT_LINK_DUPLEX: 36881991Sheppo default: 36891991Sheppo val = 0; 36901991Sheppo break; 36911991Sheppo 36921991Sheppo } 36931991Sheppo return (val); 36941991Sheppo } 36951991Sheppo 36962793Slm66018 /* 36976495Sspeer * LDC channel is UP, start handshake process with peer. 36982793Slm66018 */ 36992793Slm66018 static void 37006495Sspeer vgen_handle_evt_up(vgen_ldc_t *ldcp) 37012793Slm66018 { 37022793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 37034647Sraghuram 37044647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 37052793Slm66018 37062793Slm66018 ASSERT(MUTEX_HELD(&ldcp->cblock)); 37072793Slm66018 37082793Slm66018 if (ldcp->portp != vgenp->vsw_portp) { 37092793Slm66018 /* 37106495Sspeer * As the channel is up, use this port from now on. 37112793Slm66018 */ 37126495Sspeer (void) atomic_swap_32(&ldcp->portp->use_vsw_port, B_FALSE); 37132793Slm66018 } 37142793Slm66018 37152793Slm66018 /* Initialize local session id */ 37162793Slm66018 ldcp->local_sid = ddi_get_lbolt(); 37172793Slm66018 37182793Slm66018 /* clear peer session id */ 37192793Slm66018 ldcp->peer_sid = 0; 37202793Slm66018 ldcp->hretries = 0; 37212793Slm66018 37222793Slm66018 if (ldcp->hphase != VH_PHASE0) { 37232793Slm66018 vgen_handshake_reset(ldcp); 37242793Slm66018 } 37252793Slm66018 37262793Slm66018 /* Initiate Handshake process with peer ldc endpoint */ 37272793Slm66018 vgen_handshake(vh_nextphase(ldcp)); 37282793Slm66018 37294647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 37302793Slm66018 } 37312793Slm66018 37322793Slm66018 /* 37332793Slm66018 * LDC channel is Reset, terminate connection with peer and try to 37342793Slm66018 * bring the channel up again. 37352793Slm66018 */ 37362793Slm66018 static void 37376495Sspeer vgen_handle_evt_reset(vgen_ldc_t *ldcp) 37382793Slm66018 { 37392793Slm66018 ldc_status_t istatus; 37402793Slm66018 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 37412793Slm66018 int rv; 37422793Slm66018 37434647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 37442793Slm66018 37452793Slm66018 ASSERT(MUTEX_HELD(&ldcp->cblock)); 37462793Slm66018 37472793Slm66018 if ((ldcp->portp != vgenp->vsw_portp) && 37484650Sraghuram (vgenp->vsw_portp != NULL)) { 37492793Slm66018 /* 37506495Sspeer * As the channel is down, use the switch port until 37516495Sspeer * the channel becomes ready to be used. 37522793Slm66018 */ 37536495Sspeer (void) atomic_swap_32(&ldcp->portp->use_vsw_port, B_TRUE); 37546495Sspeer } 37556495Sspeer 37566495Sspeer if (vgenp->vsw_portp == ldcp->portp) { 37576495Sspeer vio_net_report_err_t rep_err = 37586495Sspeer ldcp->portp->vcb.vio_net_report_err; 37596495Sspeer 37606495Sspeer /* Post a reset message */ 37616495Sspeer rep_err(ldcp->portp->vhp, VIO_NET_RES_DOWN); 37622793Slm66018 } 37632793Slm66018 37642793Slm66018 if (ldcp->hphase != VH_PHASE0) { 37652793Slm66018 vgen_handshake_reset(ldcp); 37662793Slm66018 } 37672793Slm66018 37682793Slm66018 /* try to bring the channel up */ 37692793Slm66018 rv = ldc_up(ldcp->ldc_handle); 37702793Slm66018 if (rv != 0) { 37714647Sraghuram DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv); 37722793Slm66018 } 37732793Slm66018 37742793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 37754647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 37762793Slm66018 } else { 37772793Slm66018 ldcp->ldc_status = istatus; 37782793Slm66018 } 37792793Slm66018 37802793Slm66018 /* if channel is already UP - restart handshake */ 37812793Slm66018 if (ldcp->ldc_status == LDC_UP) { 37826495Sspeer vgen_handle_evt_up(ldcp); 37832793Slm66018 } 37842793Slm66018 37854647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 37862793Slm66018 } 37872793Slm66018 37881991Sheppo /* Interrupt handler for the channel */ 37891991Sheppo static uint_t 37901991Sheppo vgen_ldc_cb(uint64_t event, caddr_t arg) 37911991Sheppo { 37921991Sheppo _NOTE(ARGUNUSED(event)) 37931991Sheppo vgen_ldc_t *ldcp; 37941991Sheppo vgen_t *vgenp; 37951991Sheppo ldc_status_t istatus; 37961991Sheppo vgen_stats_t *statsp; 37977572SWentao.Yang@Sun.COM timeout_id_t cancel_htid = 0; 37987572SWentao.Yang@Sun.COM uint_t ret = LDC_SUCCESS; 37991991Sheppo 38001991Sheppo ldcp = (vgen_ldc_t *)arg; 38011991Sheppo vgenp = LDC_TO_VGEN(ldcp); 38025373Sraghuram statsp = &ldcp->stats; 38031991Sheppo 38044647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 38051991Sheppo 38061991Sheppo mutex_enter(&ldcp->cblock); 38071991Sheppo statsp->callbacks++; 38081991Sheppo if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) { 38094647Sraghuram DWARN(vgenp, ldcp, "status(%d) is LDC_INIT\n", 38104647Sraghuram ldcp->ldc_status); 38111991Sheppo mutex_exit(&ldcp->cblock); 38121991Sheppo return (LDC_SUCCESS); 38131991Sheppo } 38141991Sheppo 38152793Slm66018 /* 38167572SWentao.Yang@Sun.COM * cache cancel_htid before the events specific 38177572SWentao.Yang@Sun.COM * code may overwrite it. Do not clear ldcp->cancel_htid 38187572SWentao.Yang@Sun.COM * as it is also used to indicate the timer to quit immediately. 38197572SWentao.Yang@Sun.COM */ 38207572SWentao.Yang@Sun.COM cancel_htid = ldcp->cancel_htid; 38217572SWentao.Yang@Sun.COM 38227572SWentao.Yang@Sun.COM /* 38232793Slm66018 * NOTE: not using switch() as event could be triggered by 38242793Slm66018 * a state change and a read request. Also the ordering of the 38252793Slm66018 * check for the event types is deliberate. 38262793Slm66018 */ 38272793Slm66018 if (event & LDC_EVT_UP) { 38282793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 38294647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 38305708Sraghuram /* status couldn't be determined */ 38317572SWentao.Yang@Sun.COM ret = LDC_FAILURE; 38327572SWentao.Yang@Sun.COM goto ldc_cb_ret; 38332793Slm66018 } 38345708Sraghuram ldcp->ldc_status = istatus; 38355708Sraghuram if (ldcp->ldc_status != LDC_UP) { 38365708Sraghuram DWARN(vgenp, ldcp, "LDC_EVT_UP received " 38375708Sraghuram " but ldc status is not UP(0x%x)\n", 38385708Sraghuram ldcp->ldc_status); 38395708Sraghuram /* spurious interrupt, return success */ 38407572SWentao.Yang@Sun.COM goto ldc_cb_ret; 38415708Sraghuram } 38424647Sraghuram DWARN(vgenp, ldcp, "event(%lx) UP, status(%d)\n", 38434647Sraghuram event, ldcp->ldc_status); 38442793Slm66018 38456495Sspeer vgen_handle_evt_up(ldcp); 38462793Slm66018 38472793Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0); 38482793Slm66018 } 38492793Slm66018 38505708Sraghuram /* Handle RESET/DOWN before READ event */ 38515708Sraghuram if (event & (LDC_EVT_RESET | LDC_EVT_DOWN)) { 38525708Sraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 38535708Sraghuram DWARN(vgenp, ldcp, "ldc_status error\n"); 38545708Sraghuram /* status couldn't be determined */ 38557572SWentao.Yang@Sun.COM ret = LDC_FAILURE; 38567572SWentao.Yang@Sun.COM goto ldc_cb_ret; 38575708Sraghuram } 38585708Sraghuram ldcp->ldc_status = istatus; 38595708Sraghuram DWARN(vgenp, ldcp, "event(%lx) RESET/DOWN, status(%d)\n", 38605708Sraghuram event, ldcp->ldc_status); 38615708Sraghuram 38626495Sspeer vgen_handle_evt_reset(ldcp); 38635708Sraghuram 38645708Sraghuram /* 38655708Sraghuram * As the channel is down/reset, ignore READ event 38665708Sraghuram * but print a debug warning message. 38675708Sraghuram */ 38685708Sraghuram if (event & LDC_EVT_READ) { 38695708Sraghuram DWARN(vgenp, ldcp, 38705708Sraghuram "LDC_EVT_READ set along with RESET/DOWN\n"); 38715708Sraghuram event &= ~LDC_EVT_READ; 38725708Sraghuram } 38735708Sraghuram } 38745708Sraghuram 38752793Slm66018 if (event & LDC_EVT_READ) { 38764647Sraghuram DBG2(vgenp, ldcp, "event(%lx) READ, status(%d)\n", 38774647Sraghuram event, ldcp->ldc_status); 38782793Slm66018 38792793Slm66018 ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0); 38804647Sraghuram 38814647Sraghuram if (ldcp->rcv_thread != NULL) { 38824647Sraghuram /* 38834647Sraghuram * If the receive thread is enabled, then 38844647Sraghuram * wakeup the receive thread to process the 38854647Sraghuram * LDC messages. 38864647Sraghuram */ 38874647Sraghuram mutex_exit(&ldcp->cblock); 38884647Sraghuram mutex_enter(&ldcp->rcv_thr_lock); 38894647Sraghuram if (!(ldcp->rcv_thr_flags & VGEN_WTHR_DATARCVD)) { 38904647Sraghuram ldcp->rcv_thr_flags |= VGEN_WTHR_DATARCVD; 38914647Sraghuram cv_signal(&ldcp->rcv_thr_cv); 38924647Sraghuram } 38934647Sraghuram mutex_exit(&ldcp->rcv_thr_lock); 38944647Sraghuram mutex_enter(&ldcp->cblock); 38954647Sraghuram } else { 38964647Sraghuram vgen_handle_evt_read(ldcp); 38974647Sraghuram } 38982793Slm66018 } 38997572SWentao.Yang@Sun.COM 39007572SWentao.Yang@Sun.COM ldc_cb_ret: 39017572SWentao.Yang@Sun.COM /* 39027572SWentao.Yang@Sun.COM * Check to see if the status of cancel_htid has 39037572SWentao.Yang@Sun.COM * changed. If another timer needs to be cancelled, 39047572SWentao.Yang@Sun.COM * then let the next callback to clear it. 39057572SWentao.Yang@Sun.COM */ 39067572SWentao.Yang@Sun.COM if (cancel_htid == 0) { 39077572SWentao.Yang@Sun.COM cancel_htid = ldcp->cancel_htid; 39087572SWentao.Yang@Sun.COM } 39092793Slm66018 mutex_exit(&ldcp->cblock); 39104647Sraghuram 39117572SWentao.Yang@Sun.COM if (cancel_htid) { 39124647Sraghuram /* 39134647Sraghuram * Cancel handshake timer. 39144647Sraghuram * untimeout(9F) will not return until the pending callback is 39154647Sraghuram * cancelled or has run. No problems will result from calling 39164647Sraghuram * untimeout if the handler has already completed. 39174647Sraghuram * If the timeout handler did run, then it would just 39184647Sraghuram * return as cancel_htid is set. 39194647Sraghuram */ 39207572SWentao.Yang@Sun.COM DBG2(vgenp, ldcp, "calling cance_htid =0x%X \n", cancel_htid); 39217572SWentao.Yang@Sun.COM (void) untimeout(cancel_htid); 39227572SWentao.Yang@Sun.COM mutex_enter(&ldcp->cblock); 39237572SWentao.Yang@Sun.COM /* clear it only if its the same as the one we cancelled */ 39247572SWentao.Yang@Sun.COM if (ldcp->cancel_htid == cancel_htid) { 39257572SWentao.Yang@Sun.COM ldcp->cancel_htid = 0; 39267572SWentao.Yang@Sun.COM } 39277572SWentao.Yang@Sun.COM mutex_exit(&ldcp->cblock); 39284647Sraghuram } 39294647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 39307572SWentao.Yang@Sun.COM return (ret); 39314647Sraghuram } 39324647Sraghuram 39334647Sraghuram static void 39344647Sraghuram vgen_handle_evt_read(vgen_ldc_t *ldcp) 39354647Sraghuram { 39364647Sraghuram int rv; 39375935Ssb155480 uint64_t *ldcmsg; 39384647Sraghuram size_t msglen; 39394647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 39404647Sraghuram vio_msg_tag_t *tagp; 39414647Sraghuram ldc_status_t istatus; 39424647Sraghuram boolean_t has_data; 39434647Sraghuram 39444647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 39454647Sraghuram 39465935Ssb155480 ldcmsg = ldcp->ldcmsg; 39474647Sraghuram /* 39484647Sraghuram * If the receive thread is enabled, then the cblock 39494647Sraghuram * need to be acquired here. If not, the vgen_ldc_cb() 39504647Sraghuram * calls this function with cblock held already. 39514647Sraghuram */ 39524647Sraghuram if (ldcp->rcv_thread != NULL) { 39534647Sraghuram mutex_enter(&ldcp->cblock); 39544647Sraghuram } else { 39554647Sraghuram ASSERT(MUTEX_HELD(&ldcp->cblock)); 39564647Sraghuram } 39574647Sraghuram 39584647Sraghuram vgen_evt_read: 39591991Sheppo do { 39605935Ssb155480 msglen = ldcp->msglen; 39615935Ssb155480 rv = ldc_read(ldcp->ldc_handle, (caddr_t)ldcmsg, &msglen); 39621991Sheppo 39631991Sheppo if (rv != 0) { 39644647Sraghuram DWARN(vgenp, ldcp, "err rv(%d) len(%d)\n", 39654647Sraghuram rv, msglen); 39662793Slm66018 if (rv == ECONNRESET) 39674647Sraghuram goto vgen_evtread_error; 39681991Sheppo break; 39691991Sheppo } 39701991Sheppo if (msglen == 0) { 39714647Sraghuram DBG2(vgenp, ldcp, "ldc_read NODATA"); 39721991Sheppo break; 39731991Sheppo } 39744647Sraghuram DBG2(vgenp, ldcp, "ldc_read msglen(%d)", msglen); 39751991Sheppo 39761991Sheppo tagp = (vio_msg_tag_t *)ldcmsg; 39771991Sheppo 39781991Sheppo if (ldcp->peer_sid) { 39791991Sheppo /* 39801991Sheppo * check sid only after we have received peer's sid 39811991Sheppo * in the version negotiate msg. 39821991Sheppo */ 39831991Sheppo #ifdef DEBUG 39841991Sheppo if (vgen_hdbg & HDBG_BAD_SID) { 39851991Sheppo /* simulate bad sid condition */ 39861991Sheppo tagp->vio_sid = 0; 39871991Sheppo vgen_hdbg &= ~(HDBG_BAD_SID); 39881991Sheppo } 39891991Sheppo #endif 39902793Slm66018 rv = vgen_check_sid(ldcp, tagp); 39912793Slm66018 if (rv != VGEN_SUCCESS) { 39921991Sheppo /* 39931991Sheppo * If sid mismatch is detected, 39941991Sheppo * reset the channel. 39951991Sheppo */ 39961991Sheppo ldcp->need_ldc_reset = B_TRUE; 39974647Sraghuram goto vgen_evtread_error; 39981991Sheppo } 39991991Sheppo } 40001991Sheppo 40011991Sheppo switch (tagp->vio_msgtype) { 40021991Sheppo case VIO_TYPE_CTRL: 40032793Slm66018 rv = vgen_handle_ctrlmsg(ldcp, tagp); 40041991Sheppo break; 40051991Sheppo 40061991Sheppo case VIO_TYPE_DATA: 40075935Ssb155480 rv = vgen_handle_datamsg(ldcp, tagp, msglen); 40081991Sheppo break; 40091991Sheppo 40101991Sheppo case VIO_TYPE_ERR: 40111991Sheppo vgen_handle_errmsg(ldcp, tagp); 40121991Sheppo break; 40131991Sheppo 40141991Sheppo default: 40154647Sraghuram DWARN(vgenp, ldcp, "Unknown VIO_TYPE(%x)\n", 40164647Sraghuram tagp->vio_msgtype); 40171991Sheppo break; 40181991Sheppo } 40191991Sheppo 40204647Sraghuram /* 40214647Sraghuram * If an error is encountered, stop processing and 40224647Sraghuram * handle the error. 40234647Sraghuram */ 40244647Sraghuram if (rv != 0) { 40254647Sraghuram goto vgen_evtread_error; 40262793Slm66018 } 40272793Slm66018 40281991Sheppo } while (msglen); 40291991Sheppo 40304647Sraghuram /* check once more before exiting */ 40314647Sraghuram rv = ldc_chkq(ldcp->ldc_handle, &has_data); 40324647Sraghuram if ((rv == 0) && (has_data == B_TRUE)) { 40334647Sraghuram DTRACE_PROBE(vgen_chkq); 40344647Sraghuram goto vgen_evt_read; 40354647Sraghuram } 40364647Sraghuram 40374647Sraghuram vgen_evtread_error: 40384647Sraghuram if (rv == ECONNRESET) { 40394647Sraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 40404647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 40414647Sraghuram } else { 40424647Sraghuram ldcp->ldc_status = istatus; 40434647Sraghuram } 40446495Sspeer vgen_handle_evt_reset(ldcp); 40454647Sraghuram } else if (rv) { 40464647Sraghuram vgen_handshake_retry(ldcp); 40474647Sraghuram } 40484647Sraghuram 40494647Sraghuram /* 40507572SWentao.Yang@Sun.COM * If the receive thread is enabled, then cancel the 40514647Sraghuram * handshake timeout here. 40524647Sraghuram */ 40534647Sraghuram if (ldcp->rcv_thread != NULL) { 40547572SWentao.Yang@Sun.COM timeout_id_t cancel_htid = ldcp->cancel_htid; 40557572SWentao.Yang@Sun.COM 40564647Sraghuram mutex_exit(&ldcp->cblock); 40577572SWentao.Yang@Sun.COM if (cancel_htid) { 40584647Sraghuram /* 40594647Sraghuram * Cancel handshake timer. untimeout(9F) will 40604647Sraghuram * not return until the pending callback is cancelled 40614647Sraghuram * or has run. No problems will result from calling 40624647Sraghuram * untimeout if the handler has already completed. 40634647Sraghuram * If the timeout handler did run, then it would just 40644647Sraghuram * return as cancel_htid is set. 40654647Sraghuram */ 40667572SWentao.Yang@Sun.COM DBG2(vgenp, ldcp, "calling cance_htid =0x%X \n", 40677572SWentao.Yang@Sun.COM cancel_htid); 40687572SWentao.Yang@Sun.COM (void) untimeout(cancel_htid); 40697572SWentao.Yang@Sun.COM 40707572SWentao.Yang@Sun.COM /* 40717572SWentao.Yang@Sun.COM * clear it only if its the same as the one we 40727572SWentao.Yang@Sun.COM * cancelled 40737572SWentao.Yang@Sun.COM */ 40747572SWentao.Yang@Sun.COM mutex_enter(&ldcp->cblock); 40757572SWentao.Yang@Sun.COM if (ldcp->cancel_htid == cancel_htid) { 40767572SWentao.Yang@Sun.COM ldcp->cancel_htid = 0; 40777572SWentao.Yang@Sun.COM } 40787572SWentao.Yang@Sun.COM mutex_exit(&ldcp->cblock); 40794647Sraghuram } 40804647Sraghuram } 40814647Sraghuram 40824647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 40831991Sheppo } 40841991Sheppo 40851991Sheppo /* vgen handshake functions */ 40861991Sheppo 40871991Sheppo /* change the hphase for the channel to the next phase */ 40881991Sheppo static vgen_ldc_t * 40891991Sheppo vh_nextphase(vgen_ldc_t *ldcp) 40901991Sheppo { 40911991Sheppo if (ldcp->hphase == VH_PHASE3) { 40921991Sheppo ldcp->hphase = VH_DONE; 40931991Sheppo } else { 40941991Sheppo ldcp->hphase++; 40951991Sheppo } 40961991Sheppo return (ldcp); 40971991Sheppo } 40981991Sheppo 40991991Sheppo /* 41001991Sheppo * wrapper routine to send the given message over ldc using ldc_write(). 41011991Sheppo */ 41021991Sheppo static int 41031991Sheppo vgen_sendmsg(vgen_ldc_t *ldcp, caddr_t msg, size_t msglen, 41041991Sheppo boolean_t caller_holds_lock) 41051991Sheppo { 41065935Ssb155480 int rv; 41075935Ssb155480 size_t len; 41085935Ssb155480 uint32_t retries = 0; 41095935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 41105935Ssb155480 vio_msg_tag_t *tagp = (vio_msg_tag_t *)msg; 41115935Ssb155480 vio_dring_msg_t *dmsg; 41125935Ssb155480 vio_raw_data_msg_t *rmsg; 41135935Ssb155480 boolean_t data_msg = B_FALSE; 41141991Sheppo 41151991Sheppo len = msglen; 41161991Sheppo if ((len == 0) || (msg == NULL)) 41171991Sheppo return (VGEN_FAILURE); 41181991Sheppo 41191991Sheppo if (!caller_holds_lock) { 41204647Sraghuram mutex_enter(&ldcp->wrlock); 41211991Sheppo } 41221991Sheppo 41235935Ssb155480 if (tagp->vio_subtype == VIO_SUBTYPE_INFO) { 41245935Ssb155480 if (tagp->vio_subtype_env == VIO_DRING_DATA) { 41255935Ssb155480 dmsg = (vio_dring_msg_t *)tagp; 41265935Ssb155480 dmsg->seq_num = ldcp->next_txseq; 41275935Ssb155480 data_msg = B_TRUE; 41285935Ssb155480 } else if (tagp->vio_subtype_env == VIO_PKT_DATA) { 41295935Ssb155480 rmsg = (vio_raw_data_msg_t *)tagp; 41305935Ssb155480 rmsg->seq_num = ldcp->next_txseq; 41315935Ssb155480 data_msg = B_TRUE; 41325935Ssb155480 } 41335935Ssb155480 } 41345935Ssb155480 41351991Sheppo do { 41361991Sheppo len = msglen; 41371991Sheppo rv = ldc_write(ldcp->ldc_handle, (caddr_t)msg, &len); 41381991Sheppo if (retries++ >= vgen_ldcwr_retries) 41391991Sheppo break; 41401991Sheppo } while (rv == EWOULDBLOCK); 41411991Sheppo 41425935Ssb155480 if (rv == 0 && data_msg == B_TRUE) { 41435935Ssb155480 ldcp->next_txseq++; 41445935Ssb155480 } 41455935Ssb155480 41461991Sheppo if (!caller_holds_lock) { 41474647Sraghuram mutex_exit(&ldcp->wrlock); 41481991Sheppo } 41491991Sheppo 41502793Slm66018 if (rv != 0) { 41514647Sraghuram DWARN(vgenp, ldcp, "ldc_write failed: rv(%d)\n", 41524647Sraghuram rv, msglen); 41532793Slm66018 return (rv); 41542793Slm66018 } 41552793Slm66018 41562793Slm66018 if (len != msglen) { 41574647Sraghuram DWARN(vgenp, ldcp, "ldc_write failed: rv(%d) msglen (%d)\n", 41584647Sraghuram rv, msglen); 41591991Sheppo return (VGEN_FAILURE); 41601991Sheppo } 41612793Slm66018 41621991Sheppo return (VGEN_SUCCESS); 41631991Sheppo } 41641991Sheppo 41651991Sheppo /* send version negotiate message to the peer over ldc */ 41661991Sheppo static int 41671991Sheppo vgen_send_version_negotiate(vgen_ldc_t *ldcp) 41681991Sheppo { 41694647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 41701991Sheppo vio_ver_msg_t vermsg; 41711991Sheppo vio_msg_tag_t *tagp = &vermsg.tag; 41721991Sheppo int rv; 41731991Sheppo 41741991Sheppo bzero(&vermsg, sizeof (vermsg)); 41751991Sheppo 41761991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 41771991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 41781991Sheppo tagp->vio_subtype_env = VIO_VER_INFO; 41791991Sheppo tagp->vio_sid = ldcp->local_sid; 41801991Sheppo 41811991Sheppo /* get version msg payload from ldcp->local */ 41821991Sheppo vermsg.ver_major = ldcp->local_hparams.ver_major; 41831991Sheppo vermsg.ver_minor = ldcp->local_hparams.ver_minor; 41841991Sheppo vermsg.dev_class = ldcp->local_hparams.dev_class; 41851991Sheppo 41861991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vermsg), B_FALSE); 41871991Sheppo if (rv != VGEN_SUCCESS) { 41884647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 41892793Slm66018 return (rv); 41901991Sheppo } 41911991Sheppo 41921991Sheppo ldcp->hstate |= VER_INFO_SENT; 41934647Sraghuram DBG2(vgenp, ldcp, "VER_INFO_SENT ver(%d,%d)\n", 41944647Sraghuram vermsg.ver_major, vermsg.ver_minor); 41951991Sheppo 41961991Sheppo return (VGEN_SUCCESS); 41971991Sheppo } 41981991Sheppo 41991991Sheppo /* send attr info message to the peer over ldc */ 42001991Sheppo static int 42011991Sheppo vgen_send_attr_info(vgen_ldc_t *ldcp) 42021991Sheppo { 42034647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 42041991Sheppo vnet_attr_msg_t attrmsg; 42051991Sheppo vio_msg_tag_t *tagp = &attrmsg.tag; 42061991Sheppo int rv; 42071991Sheppo 42081991Sheppo bzero(&attrmsg, sizeof (attrmsg)); 42091991Sheppo 42101991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 42111991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 42121991Sheppo tagp->vio_subtype_env = VIO_ATTR_INFO; 42131991Sheppo tagp->vio_sid = ldcp->local_sid; 42141991Sheppo 42151991Sheppo /* get attr msg payload from ldcp->local */ 42161991Sheppo attrmsg.mtu = ldcp->local_hparams.mtu; 42171991Sheppo attrmsg.addr = ldcp->local_hparams.addr; 42181991Sheppo attrmsg.addr_type = ldcp->local_hparams.addr_type; 42191991Sheppo attrmsg.xfer_mode = ldcp->local_hparams.xfer_mode; 42201991Sheppo attrmsg.ack_freq = ldcp->local_hparams.ack_freq; 42211991Sheppo 42221991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (attrmsg), B_FALSE); 42231991Sheppo if (rv != VGEN_SUCCESS) { 42244647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 42252793Slm66018 return (rv); 42261991Sheppo } 42271991Sheppo 42281991Sheppo ldcp->hstate |= ATTR_INFO_SENT; 42294647Sraghuram DBG2(vgenp, ldcp, "ATTR_INFO_SENT\n"); 42301991Sheppo 42311991Sheppo return (VGEN_SUCCESS); 42321991Sheppo } 42331991Sheppo 42341991Sheppo /* send descriptor ring register message to the peer over ldc */ 42351991Sheppo static int 42361991Sheppo vgen_send_dring_reg(vgen_ldc_t *ldcp) 42371991Sheppo { 42384647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 42391991Sheppo vio_dring_reg_msg_t msg; 42401991Sheppo vio_msg_tag_t *tagp = &msg.tag; 42411991Sheppo int rv; 42421991Sheppo 42431991Sheppo bzero(&msg, sizeof (msg)); 42441991Sheppo 42451991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 42461991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 42471991Sheppo tagp->vio_subtype_env = VIO_DRING_REG; 42481991Sheppo tagp->vio_sid = ldcp->local_sid; 42491991Sheppo 42501991Sheppo /* get dring info msg payload from ldcp->local */ 42511991Sheppo bcopy(&(ldcp->local_hparams.dring_cookie), (msg.cookie), 42524650Sraghuram sizeof (ldc_mem_cookie_t)); 42531991Sheppo msg.ncookies = ldcp->local_hparams.num_dcookies; 42541991Sheppo msg.num_descriptors = ldcp->local_hparams.num_desc; 42551991Sheppo msg.descriptor_size = ldcp->local_hparams.desc_size; 42561991Sheppo 42571991Sheppo /* 42581991Sheppo * dring_ident is set to 0. After mapping the dring, peer sets this 42591991Sheppo * value and sends it in the ack, which is saved in 42601991Sheppo * vgen_handle_dring_reg(). 42611991Sheppo */ 42621991Sheppo msg.dring_ident = 0; 42631991Sheppo 42641991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (msg), B_FALSE); 42651991Sheppo if (rv != VGEN_SUCCESS) { 42664647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 42672793Slm66018 return (rv); 42681991Sheppo } 42691991Sheppo 42701991Sheppo ldcp->hstate |= DRING_INFO_SENT; 42714647Sraghuram DBG2(vgenp, ldcp, "DRING_INFO_SENT \n"); 42721991Sheppo 42731991Sheppo return (VGEN_SUCCESS); 42741991Sheppo } 42751991Sheppo 42761991Sheppo static int 42771991Sheppo vgen_send_rdx_info(vgen_ldc_t *ldcp) 42781991Sheppo { 42794647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 42801991Sheppo vio_rdx_msg_t rdxmsg; 42811991Sheppo vio_msg_tag_t *tagp = &rdxmsg.tag; 42821991Sheppo int rv; 42831991Sheppo 42841991Sheppo bzero(&rdxmsg, sizeof (rdxmsg)); 42851991Sheppo 42861991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 42871991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 42881991Sheppo tagp->vio_subtype_env = VIO_RDX; 42891991Sheppo tagp->vio_sid = ldcp->local_sid; 42901991Sheppo 42911991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (rdxmsg), B_FALSE); 42921991Sheppo if (rv != VGEN_SUCCESS) { 42934647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 42942793Slm66018 return (rv); 42951991Sheppo } 42961991Sheppo 42971991Sheppo ldcp->hstate |= RDX_INFO_SENT; 42984647Sraghuram DBG2(vgenp, ldcp, "RDX_INFO_SENT\n"); 42991991Sheppo 43001991Sheppo return (VGEN_SUCCESS); 43011991Sheppo } 43021991Sheppo 43031991Sheppo /* send descriptor ring data message to the peer over ldc */ 43041991Sheppo static int 43052336Snarayan vgen_send_dring_data(vgen_ldc_t *ldcp, uint32_t start, int32_t end) 43061991Sheppo { 43074647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 43081991Sheppo vio_dring_msg_t dringmsg, *msgp = &dringmsg; 43091991Sheppo vio_msg_tag_t *tagp = &msgp->tag; 43105373Sraghuram vgen_stats_t *statsp = &ldcp->stats; 43111991Sheppo int rv; 43121991Sheppo 43131991Sheppo bzero(msgp, sizeof (*msgp)); 43141991Sheppo 43151991Sheppo tagp->vio_msgtype = VIO_TYPE_DATA; 43161991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 43171991Sheppo tagp->vio_subtype_env = VIO_DRING_DATA; 43181991Sheppo tagp->vio_sid = ldcp->local_sid; 43191991Sheppo 43201991Sheppo msgp->dring_ident = ldcp->local_hparams.dring_ident; 43211991Sheppo msgp->start_idx = start; 43221991Sheppo msgp->end_idx = end; 43231991Sheppo 43241991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (dringmsg), B_TRUE); 43251991Sheppo if (rv != VGEN_SUCCESS) { 43264647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 43272793Slm66018 return (rv); 43281991Sheppo } 43291991Sheppo 43305373Sraghuram statsp->dring_data_msgs++; 43312336Snarayan 43324647Sraghuram DBG2(vgenp, ldcp, "DRING_DATA_SENT \n"); 43331991Sheppo 43341991Sheppo return (VGEN_SUCCESS); 43351991Sheppo } 43361991Sheppo 43371991Sheppo /* send multicast addr info message to vsw */ 43381991Sheppo static int 43391991Sheppo vgen_send_mcast_info(vgen_ldc_t *ldcp) 43401991Sheppo { 43411991Sheppo vnet_mcast_msg_t mcastmsg; 43421991Sheppo vnet_mcast_msg_t *msgp; 43431991Sheppo vio_msg_tag_t *tagp; 43441991Sheppo vgen_t *vgenp; 43451991Sheppo struct ether_addr *mca; 43461991Sheppo int rv; 43471991Sheppo int i; 43481991Sheppo uint32_t size; 43491991Sheppo uint32_t mccount; 43501991Sheppo uint32_t n; 43511991Sheppo 43521991Sheppo msgp = &mcastmsg; 43531991Sheppo tagp = &msgp->tag; 43541991Sheppo vgenp = LDC_TO_VGEN(ldcp); 43551991Sheppo 43561991Sheppo mccount = vgenp->mccount; 43571991Sheppo i = 0; 43581991Sheppo 43591991Sheppo do { 43601991Sheppo tagp->vio_msgtype = VIO_TYPE_CTRL; 43611991Sheppo tagp->vio_subtype = VIO_SUBTYPE_INFO; 43621991Sheppo tagp->vio_subtype_env = VNET_MCAST_INFO; 43631991Sheppo tagp->vio_sid = ldcp->local_sid; 43641991Sheppo 43651991Sheppo n = ((mccount >= VNET_NUM_MCAST) ? VNET_NUM_MCAST : mccount); 43661991Sheppo size = n * sizeof (struct ether_addr); 43671991Sheppo 43681991Sheppo mca = &(vgenp->mctab[i]); 43691991Sheppo bcopy(mca, (msgp->mca), size); 43701991Sheppo msgp->set = B_TRUE; 43711991Sheppo msgp->count = n; 43721991Sheppo 43731991Sheppo rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), 43741991Sheppo B_FALSE); 43751991Sheppo if (rv != VGEN_SUCCESS) { 43764647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg err(%d)\n", rv); 43772793Slm66018 return (rv); 43781991Sheppo } 43791991Sheppo 43801991Sheppo mccount -= n; 43811991Sheppo i += n; 43821991Sheppo 43831991Sheppo } while (mccount); 43841991Sheppo 43851991Sheppo return (VGEN_SUCCESS); 43861991Sheppo } 43871991Sheppo 43881991Sheppo /* Initiate Phase 2 of handshake */ 43891991Sheppo static int 43901991Sheppo vgen_handshake_phase2(vgen_ldc_t *ldcp) 43911991Sheppo { 43921991Sheppo int rv; 43932793Slm66018 uint32_t ncookies = 0; 43944647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 43954647Sraghuram 43961991Sheppo #ifdef DEBUG 43971991Sheppo if (vgen_hdbg & HDBG_OUT_STATE) { 43981991Sheppo /* simulate out of state condition */ 43991991Sheppo vgen_hdbg &= ~(HDBG_OUT_STATE); 44001991Sheppo rv = vgen_send_rdx_info(ldcp); 44011991Sheppo return (rv); 44021991Sheppo } 44031991Sheppo if (vgen_hdbg & HDBG_TIMEOUT) { 44041991Sheppo /* simulate timeout condition */ 44051991Sheppo vgen_hdbg &= ~(HDBG_TIMEOUT); 44061991Sheppo return (VGEN_SUCCESS); 44071991Sheppo } 44081991Sheppo #endif 44092793Slm66018 rv = vgen_send_attr_info(ldcp); 44102793Slm66018 if (rv != VGEN_SUCCESS) { 44111991Sheppo return (rv); 44121991Sheppo } 44132793Slm66018 44142793Slm66018 /* Bind descriptor ring to the channel */ 44152793Slm66018 if (ldcp->num_txdcookies == 0) { 44162793Slm66018 rv = ldc_mem_dring_bind(ldcp->ldc_handle, ldcp->tx_dhandle, 44176845Sha137994 LDC_DIRECT_MAP | LDC_SHADOW_MAP, LDC_MEM_RW, 44186845Sha137994 &ldcp->tx_dcookie, &ncookies); 44192793Slm66018 if (rv != 0) { 44204647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_bind failed " 44214650Sraghuram "rv(%x)\n", rv); 44222793Slm66018 return (rv); 44232793Slm66018 } 44242793Slm66018 ASSERT(ncookies == 1); 44252793Slm66018 ldcp->num_txdcookies = ncookies; 44262793Slm66018 } 44272793Slm66018 44282793Slm66018 /* update local dring_info params */ 44292793Slm66018 bcopy(&(ldcp->tx_dcookie), &(ldcp->local_hparams.dring_cookie), 44304650Sraghuram sizeof (ldc_mem_cookie_t)); 44312793Slm66018 ldcp->local_hparams.num_dcookies = ldcp->num_txdcookies; 44322793Slm66018 ldcp->local_hparams.num_desc = ldcp->num_txds; 44332793Slm66018 ldcp->local_hparams.desc_size = sizeof (vnet_public_desc_t); 44342793Slm66018 44352793Slm66018 rv = vgen_send_dring_reg(ldcp); 44362793Slm66018 if (rv != VGEN_SUCCESS) { 44371991Sheppo return (rv); 44381991Sheppo } 44391991Sheppo 44401991Sheppo return (VGEN_SUCCESS); 44411991Sheppo } 44421991Sheppo 44431991Sheppo /* 44445935Ssb155480 * Set vnet-protocol-version dependent functions based on version. 44455935Ssb155480 */ 44465935Ssb155480 static void 44475935Ssb155480 vgen_set_vnet_proto_ops(vgen_ldc_t *ldcp) 44485935Ssb155480 { 44495935Ssb155480 vgen_hparams_t *lp = &ldcp->local_hparams; 44505935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 44515935Ssb155480 44527529SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 4)) { 44536419Ssb155480 /* 44547529SSriharsha.Basavapatna@Sun.COM * If the version negotiated with peer is >= 1.4(Jumbo Frame 44557529SSriharsha.Basavapatna@Sun.COM * Support), set the mtu in our attributes to max_frame_size. 44566419Ssb155480 */ 44576419Ssb155480 lp->mtu = vgenp->max_frame_size; 44587529SSriharsha.Basavapatna@Sun.COM } else if (VGEN_VER_EQ(ldcp, 1, 3)) { 44597529SSriharsha.Basavapatna@Sun.COM /* 44607529SSriharsha.Basavapatna@Sun.COM * If the version negotiated with peer is == 1.3 (Vlan Tag 44617529SSriharsha.Basavapatna@Sun.COM * Support) set the attr.mtu to ETHERMAX + VLAN_TAGSZ. 44627529SSriharsha.Basavapatna@Sun.COM */ 44637529SSriharsha.Basavapatna@Sun.COM lp->mtu = ETHERMAX + VLAN_TAGSZ; 44646419Ssb155480 } else { 44656419Ssb155480 vgen_port_t *portp = ldcp->portp; 44666419Ssb155480 vnet_t *vnetp = vgenp->vnetp; 44676419Ssb155480 /* 44686419Ssb155480 * Pre-1.3 peers expect max frame size of ETHERMAX. 44696419Ssb155480 * We can negotiate that size with those peers provided the 44706419Ssb155480 * following conditions are true: 44716419Ssb155480 * - Only pvid is defined for our peer and there are no vids. 44726419Ssb155480 * - pvids are equal. 44736419Ssb155480 * If the above conditions are true, then we can send/recv only 44746419Ssb155480 * untagged frames of max size ETHERMAX. 44756419Ssb155480 */ 44767529SSriharsha.Basavapatna@Sun.COM if (portp->nvids == 0 && portp->pvid == vnetp->pvid) { 44776419Ssb155480 lp->mtu = ETHERMAX; 44786419Ssb155480 } 44796419Ssb155480 } 44806419Ssb155480 44816419Ssb155480 if (VGEN_VER_GTEQ(ldcp, 1, 2)) { 44826419Ssb155480 /* Versions >= 1.2 */ 44835935Ssb155480 44845935Ssb155480 if (VGEN_PRI_ETH_DEFINED(vgenp)) { 44855935Ssb155480 /* 44865935Ssb155480 * enable priority routines and pkt mode only if 44875935Ssb155480 * at least one pri-eth-type is specified in MD. 44885935Ssb155480 */ 44895935Ssb155480 44905935Ssb155480 ldcp->tx = vgen_ldcsend; 44915935Ssb155480 ldcp->rx_pktdata = vgen_handle_pkt_data; 44925935Ssb155480 44935935Ssb155480 /* set xfer mode for vgen_send_attr_info() */ 44945935Ssb155480 lp->xfer_mode = VIO_PKT_MODE | VIO_DRING_MODE_V1_2; 44955935Ssb155480 44965935Ssb155480 } else { 44975935Ssb155480 /* no priority eth types defined in MD */ 44985935Ssb155480 44995935Ssb155480 ldcp->tx = vgen_ldcsend_dring; 45005935Ssb155480 ldcp->rx_pktdata = vgen_handle_pkt_data_nop; 45015935Ssb155480 45025935Ssb155480 /* set xfer mode for vgen_send_attr_info() */ 45035935Ssb155480 lp->xfer_mode = VIO_DRING_MODE_V1_2; 45045935Ssb155480 45055935Ssb155480 } 45065935Ssb155480 } else { 45075935Ssb155480 /* Versions prior to 1.2 */ 45085935Ssb155480 45095935Ssb155480 vgen_reset_vnet_proto_ops(ldcp); 45105935Ssb155480 } 45115935Ssb155480 } 45125935Ssb155480 45135935Ssb155480 /* 45145935Ssb155480 * Reset vnet-protocol-version dependent functions to pre-v1.2. 45155935Ssb155480 */ 45165935Ssb155480 static void 45175935Ssb155480 vgen_reset_vnet_proto_ops(vgen_ldc_t *ldcp) 45185935Ssb155480 { 45195935Ssb155480 vgen_hparams_t *lp = &ldcp->local_hparams; 45205935Ssb155480 45215935Ssb155480 ldcp->tx = vgen_ldcsend_dring; 45225935Ssb155480 ldcp->rx_pktdata = vgen_handle_pkt_data_nop; 45235935Ssb155480 45245935Ssb155480 /* set xfer mode for vgen_send_attr_info() */ 45255935Ssb155480 lp->xfer_mode = VIO_DRING_MODE_V1_0; 45265935Ssb155480 } 45275935Ssb155480 45286419Ssb155480 static void 45296419Ssb155480 vgen_vlan_unaware_port_reset(vgen_port_t *portp) 45306419Ssb155480 { 45316419Ssb155480 vgen_ldclist_t *ldclp; 45326419Ssb155480 vgen_ldc_t *ldcp; 45336419Ssb155480 vgen_t *vgenp = portp->vgenp; 45346419Ssb155480 vnet_t *vnetp = vgenp->vnetp; 45356419Ssb155480 45366419Ssb155480 ldclp = &portp->ldclist; 45376419Ssb155480 45386419Ssb155480 READ_ENTER(&ldclp->rwlock); 45396419Ssb155480 45406419Ssb155480 /* 45416419Ssb155480 * NOTE: for now, we will assume we have a single channel. 45426419Ssb155480 */ 45436419Ssb155480 if (ldclp->headp == NULL) { 45446419Ssb155480 RW_EXIT(&ldclp->rwlock); 45456419Ssb155480 return; 45466419Ssb155480 } 45476419Ssb155480 ldcp = ldclp->headp; 45486419Ssb155480 45496419Ssb155480 mutex_enter(&ldcp->cblock); 45506419Ssb155480 45516419Ssb155480 /* 45526419Ssb155480 * If the peer is vlan_unaware(ver < 1.3), reset channel and terminate 45536419Ssb155480 * the connection. See comments in vgen_set_vnet_proto_ops(). 45546419Ssb155480 */ 45556419Ssb155480 if (ldcp->hphase == VH_DONE && VGEN_VER_LT(ldcp, 1, 3) && 45566419Ssb155480 (portp->nvids != 0 || portp->pvid != vnetp->pvid)) { 45576419Ssb155480 ldcp->need_ldc_reset = B_TRUE; 45586419Ssb155480 vgen_handshake_retry(ldcp); 45596419Ssb155480 } 45606419Ssb155480 45616419Ssb155480 mutex_exit(&ldcp->cblock); 45626419Ssb155480 45636419Ssb155480 RW_EXIT(&ldclp->rwlock); 45646419Ssb155480 } 45656419Ssb155480 45666419Ssb155480 static void 45676419Ssb155480 vgen_reset_vlan_unaware_ports(vgen_t *vgenp) 45686419Ssb155480 { 45696419Ssb155480 vgen_port_t *portp; 45706419Ssb155480 vgen_portlist_t *plistp; 45716419Ssb155480 45726419Ssb155480 plistp = &(vgenp->vgenports); 45736419Ssb155480 READ_ENTER(&plistp->rwlock); 45746419Ssb155480 45756419Ssb155480 for (portp = plistp->headp; portp != NULL; portp = portp->nextp) { 45766419Ssb155480 45776419Ssb155480 vgen_vlan_unaware_port_reset(portp); 45786419Ssb155480 45796419Ssb155480 } 45806419Ssb155480 45816419Ssb155480 RW_EXIT(&plistp->rwlock); 45826419Ssb155480 } 45836419Ssb155480 45845935Ssb155480 /* 45851991Sheppo * This function resets the handshake phase to VH_PHASE0(pre-handshake phase). 45861991Sheppo * This can happen after a channel comes up (status: LDC_UP) or 45871991Sheppo * when handshake gets terminated due to various conditions. 45881991Sheppo */ 45891991Sheppo static void 45901991Sheppo vgen_reset_hphase(vgen_ldc_t *ldcp) 45911991Sheppo { 45924647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 45931991Sheppo ldc_status_t istatus; 45942793Slm66018 int rv; 45951991Sheppo 45964647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 45971991Sheppo /* reset hstate and hphase */ 45981991Sheppo ldcp->hstate = 0; 45991991Sheppo ldcp->hphase = VH_PHASE0; 46001991Sheppo 46015935Ssb155480 vgen_reset_vnet_proto_ops(ldcp); 46025935Ssb155480 46033653Snarayan /* 46043653Snarayan * Save the id of pending handshake timer in cancel_htid. 46053653Snarayan * This will be checked in vgen_ldc_cb() and the handshake timer will 46063653Snarayan * be cancelled after releasing cblock. 46073653Snarayan */ 46081991Sheppo if (ldcp->htid) { 46093653Snarayan ldcp->cancel_htid = ldcp->htid; 46101991Sheppo ldcp->htid = 0; 46111991Sheppo } 46121991Sheppo 46131991Sheppo if (ldcp->local_hparams.dring_ready) { 46141991Sheppo ldcp->local_hparams.dring_ready = B_FALSE; 46152793Slm66018 } 46162793Slm66018 46172793Slm66018 /* Unbind tx descriptor ring from the channel */ 46182793Slm66018 if (ldcp->num_txdcookies) { 46192793Slm66018 rv = ldc_mem_dring_unbind(ldcp->tx_dhandle); 46202793Slm66018 if (rv != 0) { 46214647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_unbind failed\n"); 46222793Slm66018 } 46232793Slm66018 ldcp->num_txdcookies = 0; 46241991Sheppo } 46251991Sheppo 46261991Sheppo if (ldcp->peer_hparams.dring_ready) { 46271991Sheppo ldcp->peer_hparams.dring_ready = B_FALSE; 46281991Sheppo /* Unmap peer's dring */ 46291991Sheppo (void) ldc_mem_dring_unmap(ldcp->rx_dhandle); 46301991Sheppo vgen_clobber_rxds(ldcp); 46311991Sheppo } 46321991Sheppo 46331991Sheppo vgen_clobber_tbufs(ldcp); 46341991Sheppo 46351991Sheppo /* 46361991Sheppo * clear local handshake params and initialize. 46371991Sheppo */ 46381991Sheppo bzero(&(ldcp->local_hparams), sizeof (ldcp->local_hparams)); 46391991Sheppo 46401991Sheppo /* set version to the highest version supported */ 46411991Sheppo ldcp->local_hparams.ver_major = 46424650Sraghuram ldcp->vgen_versions[0].ver_major; 46431991Sheppo ldcp->local_hparams.ver_minor = 46444650Sraghuram ldcp->vgen_versions[0].ver_minor; 46451991Sheppo ldcp->local_hparams.dev_class = VDEV_NETWORK; 46461991Sheppo 46471991Sheppo /* set attr_info params */ 46486419Ssb155480 ldcp->local_hparams.mtu = vgenp->max_frame_size; 46491991Sheppo ldcp->local_hparams.addr = 46505462Swentaoy vnet_macaddr_strtoul(vgenp->macaddr); 46511991Sheppo ldcp->local_hparams.addr_type = ADDR_TYPE_MAC; 46525935Ssb155480 ldcp->local_hparams.xfer_mode = VIO_DRING_MODE_V1_0; 46531991Sheppo ldcp->local_hparams.ack_freq = 0; /* don't need acks */ 46541991Sheppo 46551991Sheppo /* 46562793Slm66018 * Note: dring is created, but not bound yet. 46572793Slm66018 * local dring_info params will be updated when we bind the dring in 46582793Slm66018 * vgen_handshake_phase2(). 46591991Sheppo * dring_ident is set to 0. After mapping the dring, peer sets this 46601991Sheppo * value and sends it in the ack, which is saved in 46611991Sheppo * vgen_handle_dring_reg(). 46621991Sheppo */ 46631991Sheppo ldcp->local_hparams.dring_ident = 0; 46641991Sheppo 46651991Sheppo /* clear peer_hparams */ 46661991Sheppo bzero(&(ldcp->peer_hparams), sizeof (ldcp->peer_hparams)); 46671991Sheppo 46681991Sheppo /* reset the channel if required */ 46691991Sheppo if (ldcp->need_ldc_reset) { 46704647Sraghuram DWARN(vgenp, ldcp, "Doing Channel Reset...\n"); 46711991Sheppo ldcp->need_ldc_reset = B_FALSE; 46722410Slm66018 (void) ldc_down(ldcp->ldc_handle); 46731991Sheppo (void) ldc_status(ldcp->ldc_handle, &istatus); 46744647Sraghuram DBG2(vgenp, ldcp, "Reset Done,ldc_status(%x)\n", istatus); 46751991Sheppo ldcp->ldc_status = istatus; 46762793Slm66018 46771991Sheppo /* clear sids */ 46781991Sheppo ldcp->local_sid = 0; 46791991Sheppo ldcp->peer_sid = 0; 46802793Slm66018 46812793Slm66018 /* try to bring the channel up */ 46822793Slm66018 rv = ldc_up(ldcp->ldc_handle); 46832793Slm66018 if (rv != 0) { 46844647Sraghuram DWARN(vgenp, ldcp, "ldc_up err rv(%d)\n", rv); 46852793Slm66018 } 46862793Slm66018 46872793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 46884647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 46892793Slm66018 } else { 46902793Slm66018 ldcp->ldc_status = istatus; 46912793Slm66018 } 46921991Sheppo } 46931991Sheppo } 46941991Sheppo 46951991Sheppo /* wrapper function for vgen_reset_hphase */ 46961991Sheppo static void 46971991Sheppo vgen_handshake_reset(vgen_ldc_t *ldcp) 46981991Sheppo { 46991991Sheppo ASSERT(MUTEX_HELD(&ldcp->cblock)); 47004647Sraghuram mutex_enter(&ldcp->rxlock); 47014647Sraghuram mutex_enter(&ldcp->wrlock); 47021991Sheppo mutex_enter(&ldcp->txlock); 47031991Sheppo mutex_enter(&ldcp->tclock); 47041991Sheppo 47051991Sheppo vgen_reset_hphase(ldcp); 47061991Sheppo 47071991Sheppo mutex_exit(&ldcp->tclock); 47081991Sheppo mutex_exit(&ldcp->txlock); 47094647Sraghuram mutex_exit(&ldcp->wrlock); 47104647Sraghuram mutex_exit(&ldcp->rxlock); 47111991Sheppo } 47121991Sheppo 47131991Sheppo /* 47141991Sheppo * Initiate handshake with the peer by sending various messages 47151991Sheppo * based on the handshake-phase that the channel is currently in. 47161991Sheppo */ 47171991Sheppo static void 47181991Sheppo vgen_handshake(vgen_ldc_t *ldcp) 47191991Sheppo { 47201991Sheppo uint32_t hphase = ldcp->hphase; 47211991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 47222793Slm66018 ldc_status_t istatus; 47232793Slm66018 int rv = 0; 47241991Sheppo 47251991Sheppo switch (hphase) { 47261991Sheppo 47271991Sheppo case VH_PHASE1: 47281991Sheppo 47291991Sheppo /* 47301991Sheppo * start timer, for entire handshake process, turn this timer 47311991Sheppo * off if all phases of handshake complete successfully and 47321991Sheppo * hphase goes to VH_DONE(below) or 47331991Sheppo * vgen_reset_hphase() gets called or 47341991Sheppo * channel is reset due to errors or 47351991Sheppo * vgen_ldc_uninit() is invoked(vgen_stop). 47361991Sheppo */ 47377572SWentao.Yang@Sun.COM ASSERT(ldcp->htid == 0); 47381991Sheppo ldcp->htid = timeout(vgen_hwatchdog, (caddr_t)ldcp, 47395171Ssb155480 drv_usectohz(vgen_hwd_interval * MICROSEC)); 47401991Sheppo 47411991Sheppo /* Phase 1 involves negotiating the version */ 47422793Slm66018 rv = vgen_send_version_negotiate(ldcp); 47431991Sheppo break; 47441991Sheppo 47451991Sheppo case VH_PHASE2: 47462793Slm66018 rv = vgen_handshake_phase2(ldcp); 47471991Sheppo break; 47481991Sheppo 47491991Sheppo case VH_PHASE3: 47502793Slm66018 rv = vgen_send_rdx_info(ldcp); 47511991Sheppo break; 47521991Sheppo 47531991Sheppo case VH_DONE: 47543653Snarayan /* 47553653Snarayan * Save the id of pending handshake timer in cancel_htid. 47563653Snarayan * This will be checked in vgen_ldc_cb() and the handshake 47573653Snarayan * timer will be cancelled after releasing cblock. 47583653Snarayan */ 47591991Sheppo if (ldcp->htid) { 47603653Snarayan ldcp->cancel_htid = ldcp->htid; 47611991Sheppo ldcp->htid = 0; 47621991Sheppo } 47631991Sheppo ldcp->hretries = 0; 47644647Sraghuram DBG1(vgenp, ldcp, "Handshake Done\n"); 47651991Sheppo 47665171Ssb155480 if (ldcp->portp == vgenp->vsw_portp) { 47675171Ssb155480 /* 47685171Ssb155480 * If this channel(port) is connected to vsw, 47695171Ssb155480 * need to sync multicast table with vsw. 47705171Ssb155480 */ 47711991Sheppo mutex_exit(&ldcp->cblock); 47721991Sheppo 47731991Sheppo mutex_enter(&vgenp->lock); 47742793Slm66018 rv = vgen_send_mcast_info(ldcp); 47751991Sheppo mutex_exit(&vgenp->lock); 47761991Sheppo 47771991Sheppo mutex_enter(&ldcp->cblock); 47782793Slm66018 if (rv != VGEN_SUCCESS) 47792793Slm66018 break; 47801991Sheppo } 47812793Slm66018 47822793Slm66018 /* 47832793Slm66018 * Check if mac layer should be notified to restart 47842793Slm66018 * transmissions. This can happen if the channel got 47852793Slm66018 * reset and vgen_clobber_tbufs() is called, while 47862793Slm66018 * need_resched is set. 47872793Slm66018 */ 47882793Slm66018 mutex_enter(&ldcp->tclock); 47892793Slm66018 if (ldcp->need_resched) { 47906495Sspeer vio_net_tx_update_t vtx_update = 47916495Sspeer ldcp->portp->vcb.vio_net_tx_update; 47926495Sspeer 47932793Slm66018 ldcp->need_resched = B_FALSE; 47946495Sspeer vtx_update(ldcp->portp->vhp); 47952793Slm66018 } 47962793Slm66018 mutex_exit(&ldcp->tclock); 47972793Slm66018 47981991Sheppo break; 47991991Sheppo 48001991Sheppo default: 48011991Sheppo break; 48021991Sheppo } 48032793Slm66018 48042793Slm66018 if (rv == ECONNRESET) { 48052793Slm66018 if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 48064647Sraghuram DWARN(vgenp, ldcp, "ldc_status err\n"); 48072793Slm66018 } else { 48082793Slm66018 ldcp->ldc_status = istatus; 48092793Slm66018 } 48106495Sspeer vgen_handle_evt_reset(ldcp); 48112793Slm66018 } else if (rv) { 48122793Slm66018 vgen_handshake_reset(ldcp); 48132793Slm66018 } 48141991Sheppo } 48151991Sheppo 48161991Sheppo /* 48171991Sheppo * Check if the current handshake phase has completed successfully and 48181991Sheppo * return the status. 48191991Sheppo */ 48201991Sheppo static int 48211991Sheppo vgen_handshake_done(vgen_ldc_t *ldcp) 48221991Sheppo { 48234647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 48241991Sheppo uint32_t hphase = ldcp->hphase; 48251991Sheppo int status = 0; 48261991Sheppo 48271991Sheppo switch (hphase) { 48281991Sheppo 48291991Sheppo case VH_PHASE1: 48301991Sheppo /* 48311991Sheppo * Phase1 is done, if version negotiation 48321991Sheppo * completed successfully. 48331991Sheppo */ 48341991Sheppo status = ((ldcp->hstate & VER_NEGOTIATED) == 48354650Sraghuram VER_NEGOTIATED); 48361991Sheppo break; 48371991Sheppo 48381991Sheppo case VH_PHASE2: 48391991Sheppo /* 48401991Sheppo * Phase 2 is done, if attr info and dring info 48411991Sheppo * have been exchanged successfully. 48421991Sheppo */ 48431991Sheppo status = (((ldcp->hstate & ATTR_INFO_EXCHANGED) == 48444650Sraghuram ATTR_INFO_EXCHANGED) && 48454650Sraghuram ((ldcp->hstate & DRING_INFO_EXCHANGED) == 48464650Sraghuram DRING_INFO_EXCHANGED)); 48471991Sheppo break; 48481991Sheppo 48491991Sheppo case VH_PHASE3: 48501991Sheppo /* Phase 3 is done, if rdx msg has been exchanged */ 48511991Sheppo status = ((ldcp->hstate & RDX_EXCHANGED) == 48524650Sraghuram RDX_EXCHANGED); 48531991Sheppo break; 48541991Sheppo 48551991Sheppo default: 48561991Sheppo break; 48571991Sheppo } 48581991Sheppo 48591991Sheppo if (status == 0) { 48601991Sheppo return (VGEN_FAILURE); 48611991Sheppo } 48624647Sraghuram DBG2(vgenp, ldcp, "PHASE(%d)\n", hphase); 48631991Sheppo return (VGEN_SUCCESS); 48641991Sheppo } 48651991Sheppo 48661991Sheppo /* retry handshake on failure */ 48671991Sheppo static void 48681991Sheppo vgen_handshake_retry(vgen_ldc_t *ldcp) 48691991Sheppo { 48701991Sheppo /* reset handshake phase */ 48711991Sheppo vgen_handshake_reset(ldcp); 48723653Snarayan 48733653Snarayan /* handshake retry is specified and the channel is UP */ 48743653Snarayan if (vgen_max_hretries && (ldcp->ldc_status == LDC_UP)) { 48753653Snarayan if (ldcp->hretries++ < vgen_max_hretries) { 48763653Snarayan ldcp->local_sid = ddi_get_lbolt(); 48771991Sheppo vgen_handshake(vh_nextphase(ldcp)); 48783653Snarayan } 48791991Sheppo } 48801991Sheppo } 48811991Sheppo 48821991Sheppo /* 48831991Sheppo * Handle a version info msg from the peer or an ACK/NACK from the peer 48841991Sheppo * to a version info msg that we sent. 48851991Sheppo */ 48862793Slm66018 static int 48871991Sheppo vgen_handle_version_negotiate(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 48881991Sheppo { 48894647Sraghuram vgen_t *vgenp; 48901991Sheppo vio_ver_msg_t *vermsg = (vio_ver_msg_t *)tagp; 48911991Sheppo int ack = 0; 48921991Sheppo int failed = 0; 48931991Sheppo int idx; 48941991Sheppo vgen_ver_t *versions = ldcp->vgen_versions; 48952793Slm66018 int rv = 0; 48961991Sheppo 48974647Sraghuram vgenp = LDC_TO_VGEN(ldcp); 48984647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 48991991Sheppo switch (tagp->vio_subtype) { 49001991Sheppo case VIO_SUBTYPE_INFO: 49011991Sheppo 49021991Sheppo /* Cache sid of peer if this is the first time */ 49031991Sheppo if (ldcp->peer_sid == 0) { 49044647Sraghuram DBG2(vgenp, ldcp, "Caching peer_sid(%x)\n", 49054647Sraghuram tagp->vio_sid); 49061991Sheppo ldcp->peer_sid = tagp->vio_sid; 49071991Sheppo } 49081991Sheppo 49091991Sheppo if (ldcp->hphase != VH_PHASE1) { 49101991Sheppo /* 49111991Sheppo * If we are not already in VH_PHASE1, reset to 49121991Sheppo * pre-handshake state, and initiate handshake 49131991Sheppo * to the peer too. 49141991Sheppo */ 49151991Sheppo vgen_handshake_reset(ldcp); 49161991Sheppo vgen_handshake(vh_nextphase(ldcp)); 49171991Sheppo } 49181991Sheppo ldcp->hstate |= VER_INFO_RCVD; 49191991Sheppo 49201991Sheppo /* save peer's requested values */ 49211991Sheppo ldcp->peer_hparams.ver_major = vermsg->ver_major; 49221991Sheppo ldcp->peer_hparams.ver_minor = vermsg->ver_minor; 49231991Sheppo ldcp->peer_hparams.dev_class = vermsg->dev_class; 49241991Sheppo 49251991Sheppo if ((vermsg->dev_class != VDEV_NETWORK) && 49261991Sheppo (vermsg->dev_class != VDEV_NETWORK_SWITCH)) { 49271991Sheppo /* unsupported dev_class, send NACK */ 49281991Sheppo 49294647Sraghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n"); 49302793Slm66018 49311991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 49321991Sheppo tagp->vio_sid = ldcp->local_sid; 49331991Sheppo /* send reply msg back to peer */ 49342793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, 49351991Sheppo sizeof (*vermsg), B_FALSE); 49362793Slm66018 if (rv != VGEN_SUCCESS) { 49372793Slm66018 return (rv); 49382793Slm66018 } 49392793Slm66018 return (VGEN_FAILURE); 49401991Sheppo } 49411991Sheppo 49424647Sraghuram DBG2(vgenp, ldcp, "VER_INFO_RCVD, ver(%d,%d)\n", 49434647Sraghuram vermsg->ver_major, vermsg->ver_minor); 49441991Sheppo 49451991Sheppo idx = 0; 49461991Sheppo 49471991Sheppo for (;;) { 49481991Sheppo 49491991Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 49501991Sheppo 49511991Sheppo /* nack with next lower version */ 49521991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 49531991Sheppo vermsg->ver_major = versions[idx].ver_major; 49541991Sheppo vermsg->ver_minor = versions[idx].ver_minor; 49551991Sheppo break; 49561991Sheppo } 49571991Sheppo 49581991Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 49591991Sheppo 49601991Sheppo /* major version match - ACK version */ 49611991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 49621991Sheppo ack = 1; 49631991Sheppo 49641991Sheppo /* 49651991Sheppo * lower minor version to the one this endpt 49661991Sheppo * supports, if necessary 49671991Sheppo */ 49681991Sheppo if (vermsg->ver_minor > 49691991Sheppo versions[idx].ver_minor) { 49701991Sheppo vermsg->ver_minor = 49714650Sraghuram versions[idx].ver_minor; 49721991Sheppo ldcp->peer_hparams.ver_minor = 49734650Sraghuram versions[idx].ver_minor; 49741991Sheppo } 49751991Sheppo break; 49761991Sheppo } 49771991Sheppo 49781991Sheppo idx++; 49791991Sheppo 49801991Sheppo if (idx == VGEN_NUM_VER) { 49811991Sheppo 49821991Sheppo /* no version match - send NACK */ 49831991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 49841991Sheppo vermsg->ver_major = 0; 49851991Sheppo vermsg->ver_minor = 0; 49861991Sheppo failed = 1; 49871991Sheppo break; 49881991Sheppo } 49891991Sheppo 49901991Sheppo } 49911991Sheppo 49921991Sheppo tagp->vio_sid = ldcp->local_sid; 49931991Sheppo 49941991Sheppo /* send reply msg back to peer */ 49952793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*vermsg), 49962793Slm66018 B_FALSE); 49972793Slm66018 if (rv != VGEN_SUCCESS) { 49982793Slm66018 return (rv); 49991991Sheppo } 50001991Sheppo 50011991Sheppo if (ack) { 50021991Sheppo ldcp->hstate |= VER_ACK_SENT; 50034647Sraghuram DBG2(vgenp, ldcp, "VER_ACK_SENT, ver(%d,%d) \n", 50044647Sraghuram vermsg->ver_major, vermsg->ver_minor); 50051991Sheppo } 50061991Sheppo if (failed) { 50074647Sraghuram DWARN(vgenp, ldcp, "Negotiation Failed\n"); 50082793Slm66018 return (VGEN_FAILURE); 50091991Sheppo } 50101991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 50111991Sheppo 50121991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 50131991Sheppo 50141991Sheppo /* local and peer versions match? */ 50151991Sheppo ASSERT((ldcp->local_hparams.ver_major == 50164650Sraghuram ldcp->peer_hparams.ver_major) && 50174650Sraghuram (ldcp->local_hparams.ver_minor == 50184650Sraghuram ldcp->peer_hparams.ver_minor)); 50191991Sheppo 50205935Ssb155480 vgen_set_vnet_proto_ops(ldcp); 50215935Ssb155480 50221991Sheppo /* move to the next phase */ 50231991Sheppo vgen_handshake(vh_nextphase(ldcp)); 50241991Sheppo } 50251991Sheppo 50261991Sheppo break; 50271991Sheppo 50281991Sheppo case VIO_SUBTYPE_ACK: 50291991Sheppo 50301991Sheppo if (ldcp->hphase != VH_PHASE1) { 50311991Sheppo /* This should not happen. */ 50324647Sraghuram DWARN(vgenp, ldcp, "Invalid Phase(%u)\n", ldcp->hphase); 50332793Slm66018 return (VGEN_FAILURE); 50341991Sheppo } 50351991Sheppo 50361991Sheppo /* SUCCESS - we have agreed on a version */ 50371991Sheppo ldcp->local_hparams.ver_major = vermsg->ver_major; 50381991Sheppo ldcp->local_hparams.ver_minor = vermsg->ver_minor; 50391991Sheppo ldcp->hstate |= VER_ACK_RCVD; 50401991Sheppo 50414647Sraghuram DBG2(vgenp, ldcp, "VER_ACK_RCVD, ver(%d,%d) \n", 50424647Sraghuram vermsg->ver_major, vermsg->ver_minor); 50431991Sheppo 50441991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 50451991Sheppo 50461991Sheppo /* VER_ACK_SENT and VER_ACK_RCVD */ 50471991Sheppo 50481991Sheppo /* local and peer versions match? */ 50491991Sheppo ASSERT((ldcp->local_hparams.ver_major == 50504650Sraghuram ldcp->peer_hparams.ver_major) && 50514650Sraghuram (ldcp->local_hparams.ver_minor == 50524650Sraghuram ldcp->peer_hparams.ver_minor)); 50531991Sheppo 50545935Ssb155480 vgen_set_vnet_proto_ops(ldcp); 50555935Ssb155480 50561991Sheppo /* move to the next phase */ 50571991Sheppo vgen_handshake(vh_nextphase(ldcp)); 50581991Sheppo } 50591991Sheppo break; 50601991Sheppo 50611991Sheppo case VIO_SUBTYPE_NACK: 50621991Sheppo 50631991Sheppo if (ldcp->hphase != VH_PHASE1) { 50641991Sheppo /* This should not happen. */ 50654647Sraghuram DWARN(vgenp, ldcp, "VER_NACK_RCVD Invalid " 50664647Sraghuram "Phase(%u)\n", ldcp->hphase); 50672793Slm66018 return (VGEN_FAILURE); 50681991Sheppo } 50691991Sheppo 50704647Sraghuram DBG2(vgenp, ldcp, "VER_NACK_RCVD next ver(%d,%d)\n", 50714647Sraghuram vermsg->ver_major, vermsg->ver_minor); 50721991Sheppo 50731991Sheppo /* check if version in NACK is zero */ 50741991Sheppo if (vermsg->ver_major == 0 && vermsg->ver_minor == 0) { 50751991Sheppo /* 50761991Sheppo * Version Negotiation has failed. 50771991Sheppo */ 50784647Sraghuram DWARN(vgenp, ldcp, "Version Negotiation Failed\n"); 50792793Slm66018 return (VGEN_FAILURE); 50801991Sheppo } 50811991Sheppo 50821991Sheppo idx = 0; 50831991Sheppo 50841991Sheppo for (;;) { 50851991Sheppo 50861991Sheppo if (vermsg->ver_major > versions[idx].ver_major) { 50871991Sheppo /* select next lower version */ 50881991Sheppo 50891991Sheppo ldcp->local_hparams.ver_major = 50904650Sraghuram versions[idx].ver_major; 50911991Sheppo ldcp->local_hparams.ver_minor = 50924650Sraghuram versions[idx].ver_minor; 50931991Sheppo break; 50941991Sheppo } 50951991Sheppo 50961991Sheppo if (vermsg->ver_major == versions[idx].ver_major) { 50971991Sheppo /* major version match */ 50981991Sheppo 50991991Sheppo ldcp->local_hparams.ver_major = 51004650Sraghuram versions[idx].ver_major; 51011991Sheppo 51021991Sheppo ldcp->local_hparams.ver_minor = 51034650Sraghuram versions[idx].ver_minor; 51041991Sheppo break; 51051991Sheppo } 51061991Sheppo 51071991Sheppo idx++; 51081991Sheppo 51091991Sheppo if (idx == VGEN_NUM_VER) { 51101991Sheppo /* 51111991Sheppo * no version match. 51121991Sheppo * Version Negotiation has failed. 51131991Sheppo */ 51144647Sraghuram DWARN(vgenp, ldcp, 51154647Sraghuram "Version Negotiation Failed\n"); 51162793Slm66018 return (VGEN_FAILURE); 51171991Sheppo } 51181991Sheppo 51191991Sheppo } 51201991Sheppo 51212793Slm66018 rv = vgen_send_version_negotiate(ldcp); 51222793Slm66018 if (rv != VGEN_SUCCESS) { 51232793Slm66018 return (rv); 51241991Sheppo } 51251991Sheppo 51261991Sheppo break; 51271991Sheppo } 51282793Slm66018 51294647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 51302793Slm66018 return (VGEN_SUCCESS); 51311991Sheppo } 51321991Sheppo 51331991Sheppo /* Check if the attributes are supported */ 51341991Sheppo static int 51351991Sheppo vgen_check_attr_info(vgen_ldc_t *ldcp, vnet_attr_msg_t *msg) 51361991Sheppo { 51375935Ssb155480 vgen_hparams_t *lp = &ldcp->local_hparams; 51385935Ssb155480 51397529SSriharsha.Basavapatna@Sun.COM if ((msg->addr_type != ADDR_TYPE_MAC) || 51405935Ssb155480 (msg->ack_freq > 64) || 51415935Ssb155480 (msg->xfer_mode != lp->xfer_mode)) { 51421991Sheppo return (VGEN_FAILURE); 51431991Sheppo } 51441991Sheppo 51457529SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_LT(ldcp, 1, 4)) { 51467529SSriharsha.Basavapatna@Sun.COM /* versions < 1.4, mtu must match */ 51477529SSriharsha.Basavapatna@Sun.COM if (msg->mtu != lp->mtu) { 51487529SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE); 51497529SSriharsha.Basavapatna@Sun.COM } 51507529SSriharsha.Basavapatna@Sun.COM } else { 51517529SSriharsha.Basavapatna@Sun.COM /* Ver >= 1.4, validate mtu of the peer is at least ETHERMAX */ 51527529SSriharsha.Basavapatna@Sun.COM if (msg->mtu < ETHERMAX) { 51537529SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE); 51547529SSriharsha.Basavapatna@Sun.COM } 51557529SSriharsha.Basavapatna@Sun.COM } 51567529SSriharsha.Basavapatna@Sun.COM 51571991Sheppo return (VGEN_SUCCESS); 51581991Sheppo } 51591991Sheppo 51601991Sheppo /* 51611991Sheppo * Handle an attribute info msg from the peer or an ACK/NACK from the peer 51621991Sheppo * to an attr info msg that we sent. 51631991Sheppo */ 51642793Slm66018 static int 51651991Sheppo vgen_handle_attr_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 51661991Sheppo { 51677529SSriharsha.Basavapatna@Sun.COM vgen_t *vgenp = LDC_TO_VGEN(ldcp); 51687529SSriharsha.Basavapatna@Sun.COM vnet_attr_msg_t *msg = (vnet_attr_msg_t *)tagp; 51697529SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams; 51707529SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *rp = &ldcp->peer_hparams; 51717529SSriharsha.Basavapatna@Sun.COM int ack = 1; 51722793Slm66018 int rv = 0; 51737529SSriharsha.Basavapatna@Sun.COM uint32_t mtu; 51741991Sheppo 51754647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 51761991Sheppo if (ldcp->hphase != VH_PHASE2) { 51774647Sraghuram DWARN(vgenp, ldcp, "Rcvd ATTR_INFO subtype(%d)," 51784647Sraghuram " Invalid Phase(%u)\n", 51794647Sraghuram tagp->vio_subtype, ldcp->hphase); 51802793Slm66018 return (VGEN_FAILURE); 51811991Sheppo } 51821991Sheppo switch (tagp->vio_subtype) { 51831991Sheppo case VIO_SUBTYPE_INFO: 51841991Sheppo 51854647Sraghuram DBG2(vgenp, ldcp, "ATTR_INFO_RCVD \n"); 51861991Sheppo ldcp->hstate |= ATTR_INFO_RCVD; 51871991Sheppo 51881991Sheppo /* save peer's values */ 51897529SSriharsha.Basavapatna@Sun.COM rp->mtu = msg->mtu; 51907529SSriharsha.Basavapatna@Sun.COM rp->addr = msg->addr; 51917529SSriharsha.Basavapatna@Sun.COM rp->addr_type = msg->addr_type; 51927529SSriharsha.Basavapatna@Sun.COM rp->xfer_mode = msg->xfer_mode; 51937529SSriharsha.Basavapatna@Sun.COM rp->ack_freq = msg->ack_freq; 51947529SSriharsha.Basavapatna@Sun.COM 51957529SSriharsha.Basavapatna@Sun.COM rv = vgen_check_attr_info(ldcp, msg); 51967529SSriharsha.Basavapatna@Sun.COM if (rv == VGEN_FAILURE) { 51971991Sheppo /* unsupported attr, send NACK */ 51987529SSriharsha.Basavapatna@Sun.COM ack = 0; 51991991Sheppo } else { 52007529SSriharsha.Basavapatna@Sun.COM 52017529SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 4)) { 52027529SSriharsha.Basavapatna@Sun.COM 52037529SSriharsha.Basavapatna@Sun.COM /* 52047529SSriharsha.Basavapatna@Sun.COM * Versions >= 1.4: 52057529SSriharsha.Basavapatna@Sun.COM * The mtu is negotiated down to the 52067529SSriharsha.Basavapatna@Sun.COM * minimum of our mtu and peer's mtu. 52077529SSriharsha.Basavapatna@Sun.COM */ 52087529SSriharsha.Basavapatna@Sun.COM mtu = MIN(msg->mtu, vgenp->max_frame_size); 52097529SSriharsha.Basavapatna@Sun.COM 52107529SSriharsha.Basavapatna@Sun.COM /* 52117529SSriharsha.Basavapatna@Sun.COM * If we have received an ack for the attr info 52127529SSriharsha.Basavapatna@Sun.COM * that we sent, then check if the mtu computed 52137529SSriharsha.Basavapatna@Sun.COM * above matches the mtu that the peer had ack'd 52147529SSriharsha.Basavapatna@Sun.COM * (saved in local hparams). If they don't 52157529SSriharsha.Basavapatna@Sun.COM * match, we fail the handshake. 52167529SSriharsha.Basavapatna@Sun.COM */ 52177529SSriharsha.Basavapatna@Sun.COM if (ldcp->hstate & ATTR_ACK_RCVD) { 52187529SSriharsha.Basavapatna@Sun.COM if (mtu != lp->mtu) { 52197529SSriharsha.Basavapatna@Sun.COM /* send NACK */ 52207529SSriharsha.Basavapatna@Sun.COM ack = 0; 52217529SSriharsha.Basavapatna@Sun.COM } 52227529SSriharsha.Basavapatna@Sun.COM } else { 52237529SSriharsha.Basavapatna@Sun.COM /* 52247529SSriharsha.Basavapatna@Sun.COM * Save the mtu computed above in our 52257529SSriharsha.Basavapatna@Sun.COM * attr parameters, so it gets sent in 52267529SSriharsha.Basavapatna@Sun.COM * the attr info from us to the peer. 52277529SSriharsha.Basavapatna@Sun.COM */ 52287529SSriharsha.Basavapatna@Sun.COM lp->mtu = mtu; 52297529SSriharsha.Basavapatna@Sun.COM } 52307529SSriharsha.Basavapatna@Sun.COM 52317529SSriharsha.Basavapatna@Sun.COM /* save the MIN mtu in the msg to be replied */ 52327529SSriharsha.Basavapatna@Sun.COM msg->mtu = mtu; 52337529SSriharsha.Basavapatna@Sun.COM 52347529SSriharsha.Basavapatna@Sun.COM } 52357529SSriharsha.Basavapatna@Sun.COM } 52367529SSriharsha.Basavapatna@Sun.COM 52377529SSriharsha.Basavapatna@Sun.COM 52387529SSriharsha.Basavapatna@Sun.COM if (ack) { 52391991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 52407529SSriharsha.Basavapatna@Sun.COM } else { 52417529SSriharsha.Basavapatna@Sun.COM tagp->vio_subtype = VIO_SUBTYPE_NACK; 52421991Sheppo } 52431991Sheppo tagp->vio_sid = ldcp->local_sid; 52441991Sheppo 52451991Sheppo /* send reply msg back to peer */ 52467529SSriharsha.Basavapatna@Sun.COM rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg), 52472793Slm66018 B_FALSE); 52482793Slm66018 if (rv != VGEN_SUCCESS) { 52492793Slm66018 return (rv); 52501991Sheppo } 52511991Sheppo 52521991Sheppo if (ack) { 52531991Sheppo ldcp->hstate |= ATTR_ACK_SENT; 52544647Sraghuram DBG2(vgenp, ldcp, "ATTR_ACK_SENT \n"); 52551991Sheppo } else { 52561991Sheppo /* failed */ 52574647Sraghuram DWARN(vgenp, ldcp, "ATTR_NACK_SENT \n"); 52582793Slm66018 return (VGEN_FAILURE); 52591991Sheppo } 52601991Sheppo 52611991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 52621991Sheppo vgen_handshake(vh_nextphase(ldcp)); 52631991Sheppo } 52641991Sheppo 52651991Sheppo break; 52661991Sheppo 52671991Sheppo case VIO_SUBTYPE_ACK: 52681991Sheppo 52697529SSriharsha.Basavapatna@Sun.COM if (VGEN_VER_GTEQ(ldcp, 1, 4)) { 52707529SSriharsha.Basavapatna@Sun.COM /* 52717529SSriharsha.Basavapatna@Sun.COM * Versions >= 1.4: 52727529SSriharsha.Basavapatna@Sun.COM * The ack msg sent by the peer contains the minimum of 52737529SSriharsha.Basavapatna@Sun.COM * our mtu (that we had sent in our attr info) and the 52747529SSriharsha.Basavapatna@Sun.COM * peer's mtu. 52757529SSriharsha.Basavapatna@Sun.COM * 52767529SSriharsha.Basavapatna@Sun.COM * If we have sent an ack for the attr info msg from 52777529SSriharsha.Basavapatna@Sun.COM * the peer, check if the mtu that was computed then 52787529SSriharsha.Basavapatna@Sun.COM * (saved in local hparams) matches the mtu that the 52797529SSriharsha.Basavapatna@Sun.COM * peer has ack'd. If they don't match, we fail the 52807529SSriharsha.Basavapatna@Sun.COM * handshake. 52817529SSriharsha.Basavapatna@Sun.COM */ 52827529SSriharsha.Basavapatna@Sun.COM if (ldcp->hstate & ATTR_ACK_SENT) { 52837529SSriharsha.Basavapatna@Sun.COM if (lp->mtu != msg->mtu) { 52847529SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE); 52857529SSriharsha.Basavapatna@Sun.COM } 52867529SSriharsha.Basavapatna@Sun.COM } else { 52877529SSriharsha.Basavapatna@Sun.COM /* 52887529SSriharsha.Basavapatna@Sun.COM * If the mtu ack'd by the peer is > our mtu 52897529SSriharsha.Basavapatna@Sun.COM * fail handshake. Otherwise, save the mtu, so 52907529SSriharsha.Basavapatna@Sun.COM * we can validate it when we receive attr info 52917529SSriharsha.Basavapatna@Sun.COM * from our peer. 52927529SSriharsha.Basavapatna@Sun.COM */ 52937529SSriharsha.Basavapatna@Sun.COM if (msg->mtu > lp->mtu) { 52947529SSriharsha.Basavapatna@Sun.COM return (VGEN_FAILURE); 52957529SSriharsha.Basavapatna@Sun.COM } 52967529SSriharsha.Basavapatna@Sun.COM if (msg->mtu <= lp->mtu) { 52977529SSriharsha.Basavapatna@Sun.COM lp->mtu = msg->mtu; 52987529SSriharsha.Basavapatna@Sun.COM } 52997529SSriharsha.Basavapatna@Sun.COM } 53007529SSriharsha.Basavapatna@Sun.COM } 53017529SSriharsha.Basavapatna@Sun.COM 53021991Sheppo ldcp->hstate |= ATTR_ACK_RCVD; 53031991Sheppo 53044647Sraghuram DBG2(vgenp, ldcp, "ATTR_ACK_RCVD \n"); 53051991Sheppo 53061991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 53071991Sheppo vgen_handshake(vh_nextphase(ldcp)); 53081991Sheppo } 53091991Sheppo break; 53101991Sheppo 53111991Sheppo case VIO_SUBTYPE_NACK: 53121991Sheppo 53134647Sraghuram DBG2(vgenp, ldcp, "ATTR_NACK_RCVD \n"); 53142793Slm66018 return (VGEN_FAILURE); 53151991Sheppo } 53164647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 53172793Slm66018 return (VGEN_SUCCESS); 53181991Sheppo } 53191991Sheppo 53201991Sheppo /* Check if the dring info msg is ok */ 53211991Sheppo static int 53221991Sheppo vgen_check_dring_reg(vio_dring_reg_msg_t *msg) 53231991Sheppo { 53241991Sheppo /* check if msg contents are ok */ 53251991Sheppo if ((msg->num_descriptors < 128) || (msg->descriptor_size < 53261991Sheppo sizeof (vnet_public_desc_t))) { 53271991Sheppo return (VGEN_FAILURE); 53281991Sheppo } 53291991Sheppo return (VGEN_SUCCESS); 53301991Sheppo } 53311991Sheppo 53321991Sheppo /* 53331991Sheppo * Handle a descriptor ring register msg from the peer or an ACK/NACK from 53341991Sheppo * the peer to a dring register msg that we sent. 53351991Sheppo */ 53362793Slm66018 static int 53371991Sheppo vgen_handle_dring_reg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 53381991Sheppo { 53391991Sheppo vio_dring_reg_msg_t *msg = (vio_dring_reg_msg_t *)tagp; 53401991Sheppo ldc_mem_cookie_t dcookie; 53414647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 53421991Sheppo int ack = 0; 53431991Sheppo int rv = 0; 53441991Sheppo 53454647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 53461991Sheppo if (ldcp->hphase < VH_PHASE2) { 53471991Sheppo /* dring_info can be rcvd in any of the phases after Phase1 */ 53484647Sraghuram DWARN(vgenp, ldcp, 53494647Sraghuram "Rcvd DRING_INFO Subtype (%d), Invalid Phase(%u)\n", 53504650Sraghuram tagp->vio_subtype, ldcp->hphase); 53512793Slm66018 return (VGEN_FAILURE); 53521991Sheppo } 53531991Sheppo switch (tagp->vio_subtype) { 53541991Sheppo case VIO_SUBTYPE_INFO: 53551991Sheppo 53564647Sraghuram DBG2(vgenp, ldcp, "DRING_INFO_RCVD \n"); 53571991Sheppo ldcp->hstate |= DRING_INFO_RCVD; 53581991Sheppo bcopy((msg->cookie), &dcookie, sizeof (dcookie)); 53591991Sheppo 53601991Sheppo ASSERT(msg->ncookies == 1); 53611991Sheppo 53621991Sheppo if (vgen_check_dring_reg(msg) == VGEN_SUCCESS) { 53631991Sheppo /* 53641991Sheppo * verified dring info msg to be ok, 53651991Sheppo * now try to map the remote dring. 53661991Sheppo */ 53671991Sheppo rv = vgen_init_rxds(ldcp, msg->num_descriptors, 53681991Sheppo msg->descriptor_size, &dcookie, 53691991Sheppo msg->ncookies); 53701991Sheppo if (rv == DDI_SUCCESS) { 53711991Sheppo /* now we can ack the peer */ 53721991Sheppo ack = 1; 53731991Sheppo } 53741991Sheppo } 53751991Sheppo if (ack == 0) { 53761991Sheppo /* failed, send NACK */ 53771991Sheppo tagp->vio_subtype = VIO_SUBTYPE_NACK; 53781991Sheppo } else { 53791991Sheppo if (!(ldcp->peer_hparams.dring_ready)) { 53801991Sheppo 53811991Sheppo /* save peer's dring_info values */ 53821991Sheppo bcopy(&dcookie, 53831991Sheppo &(ldcp->peer_hparams.dring_cookie), 53841991Sheppo sizeof (dcookie)); 53851991Sheppo ldcp->peer_hparams.num_desc = 53864650Sraghuram msg->num_descriptors; 53871991Sheppo ldcp->peer_hparams.desc_size = 53884650Sraghuram msg->descriptor_size; 53891991Sheppo ldcp->peer_hparams.num_dcookies = 53904650Sraghuram msg->ncookies; 53911991Sheppo 53921991Sheppo /* set dring_ident for the peer */ 53931991Sheppo ldcp->peer_hparams.dring_ident = 53944650Sraghuram (uint64_t)ldcp->rxdp; 53951991Sheppo /* return the dring_ident in ack msg */ 53961991Sheppo msg->dring_ident = 53974650Sraghuram (uint64_t)ldcp->rxdp; 53981991Sheppo 53991991Sheppo ldcp->peer_hparams.dring_ready = B_TRUE; 54001991Sheppo } 54011991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 54021991Sheppo } 54031991Sheppo tagp->vio_sid = ldcp->local_sid; 54041991Sheppo /* send reply msg back to peer */ 54052793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msg), 54062793Slm66018 B_FALSE); 54072793Slm66018 if (rv != VGEN_SUCCESS) { 54082793Slm66018 return (rv); 54091991Sheppo } 54101991Sheppo 54111991Sheppo if (ack) { 54121991Sheppo ldcp->hstate |= DRING_ACK_SENT; 54134647Sraghuram DBG2(vgenp, ldcp, "DRING_ACK_SENT"); 54141991Sheppo } else { 54154647Sraghuram DWARN(vgenp, ldcp, "DRING_NACK_SENT"); 54162793Slm66018 return (VGEN_FAILURE); 54171991Sheppo } 54181991Sheppo 54191991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 54201991Sheppo vgen_handshake(vh_nextphase(ldcp)); 54211991Sheppo } 54221991Sheppo 54231991Sheppo break; 54241991Sheppo 54251991Sheppo case VIO_SUBTYPE_ACK: 54261991Sheppo 54271991Sheppo ldcp->hstate |= DRING_ACK_RCVD; 54281991Sheppo 54294647Sraghuram DBG2(vgenp, ldcp, "DRING_ACK_RCVD"); 54301991Sheppo 54311991Sheppo if (!(ldcp->local_hparams.dring_ready)) { 54321991Sheppo /* local dring is now ready */ 54331991Sheppo ldcp->local_hparams.dring_ready = B_TRUE; 54341991Sheppo 54351991Sheppo /* save dring_ident acked by peer */ 54361991Sheppo ldcp->local_hparams.dring_ident = 54374650Sraghuram msg->dring_ident; 54381991Sheppo } 54391991Sheppo 54401991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 54411991Sheppo vgen_handshake(vh_nextphase(ldcp)); 54421991Sheppo } 54431991Sheppo 54441991Sheppo break; 54451991Sheppo 54461991Sheppo case VIO_SUBTYPE_NACK: 54471991Sheppo 54484647Sraghuram DBG2(vgenp, ldcp, "DRING_NACK_RCVD"); 54492793Slm66018 return (VGEN_FAILURE); 54501991Sheppo } 54514647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 54522793Slm66018 return (VGEN_SUCCESS); 54531991Sheppo } 54541991Sheppo 54551991Sheppo /* 54561991Sheppo * Handle a rdx info msg from the peer or an ACK/NACK 54571991Sheppo * from the peer to a rdx info msg that we sent. 54581991Sheppo */ 54592793Slm66018 static int 54601991Sheppo vgen_handle_rdx_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 54611991Sheppo { 54622793Slm66018 int rv = 0; 54634647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 54644647Sraghuram 54654647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 54661991Sheppo if (ldcp->hphase != VH_PHASE3) { 54674647Sraghuram DWARN(vgenp, ldcp, 54684647Sraghuram "Rcvd RDX_INFO Subtype (%d), Invalid Phase(%u)\n", 54694650Sraghuram tagp->vio_subtype, ldcp->hphase); 54702793Slm66018 return (VGEN_FAILURE); 54711991Sheppo } 54721991Sheppo switch (tagp->vio_subtype) { 54731991Sheppo case VIO_SUBTYPE_INFO: 54741991Sheppo 54754647Sraghuram DBG2(vgenp, ldcp, "RDX_INFO_RCVD \n"); 54761991Sheppo ldcp->hstate |= RDX_INFO_RCVD; 54771991Sheppo 54781991Sheppo tagp->vio_subtype = VIO_SUBTYPE_ACK; 54791991Sheppo tagp->vio_sid = ldcp->local_sid; 54801991Sheppo /* send reply msg back to peer */ 54812793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (vio_rdx_msg_t), 54822793Slm66018 B_FALSE); 54832793Slm66018 if (rv != VGEN_SUCCESS) { 54842793Slm66018 return (rv); 54851991Sheppo } 54861991Sheppo 54871991Sheppo ldcp->hstate |= RDX_ACK_SENT; 54884647Sraghuram DBG2(vgenp, ldcp, "RDX_ACK_SENT \n"); 54891991Sheppo 54901991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 54911991Sheppo vgen_handshake(vh_nextphase(ldcp)); 54921991Sheppo } 54931991Sheppo 54941991Sheppo break; 54951991Sheppo 54961991Sheppo case VIO_SUBTYPE_ACK: 54971991Sheppo 54981991Sheppo ldcp->hstate |= RDX_ACK_RCVD; 54991991Sheppo 55004647Sraghuram DBG2(vgenp, ldcp, "RDX_ACK_RCVD \n"); 55011991Sheppo 55021991Sheppo if (vgen_handshake_done(ldcp) == VGEN_SUCCESS) { 55031991Sheppo vgen_handshake(vh_nextphase(ldcp)); 55041991Sheppo } 55051991Sheppo break; 55061991Sheppo 55071991Sheppo case VIO_SUBTYPE_NACK: 55081991Sheppo 55094647Sraghuram DBG2(vgenp, ldcp, "RDX_NACK_RCVD \n"); 55102793Slm66018 return (VGEN_FAILURE); 55111991Sheppo } 55124647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 55132793Slm66018 return (VGEN_SUCCESS); 55141991Sheppo } 55151991Sheppo 55161991Sheppo /* Handle ACK/NACK from vsw to a set multicast msg that we sent */ 55172793Slm66018 static int 55181991Sheppo vgen_handle_mcast_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 55191991Sheppo { 55201991Sheppo vgen_t *vgenp = LDC_TO_VGEN(ldcp); 55211991Sheppo vnet_mcast_msg_t *msgp = (vnet_mcast_msg_t *)tagp; 55221991Sheppo struct ether_addr *addrp; 55231991Sheppo int count; 55241991Sheppo int i; 55251991Sheppo 55264647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 55271991Sheppo switch (tagp->vio_subtype) { 55281991Sheppo 55291991Sheppo case VIO_SUBTYPE_INFO: 55301991Sheppo 55311991Sheppo /* vnet shouldn't recv set mcast msg, only vsw handles it */ 55324647Sraghuram DWARN(vgenp, ldcp, "rcvd SET_MCAST_INFO \n"); 55331991Sheppo break; 55341991Sheppo 55351991Sheppo case VIO_SUBTYPE_ACK: 55361991Sheppo 55371991Sheppo /* success adding/removing multicast addr */ 55384647Sraghuram DBG1(vgenp, ldcp, "rcvd SET_MCAST_ACK \n"); 55391991Sheppo break; 55401991Sheppo 55411991Sheppo case VIO_SUBTYPE_NACK: 55421991Sheppo 55434647Sraghuram DWARN(vgenp, ldcp, "rcvd SET_MCAST_NACK \n"); 55441991Sheppo if (!(msgp->set)) { 55451991Sheppo /* multicast remove request failed */ 55461991Sheppo break; 55471991Sheppo } 55481991Sheppo 55491991Sheppo /* multicast add request failed */ 55501991Sheppo for (count = 0; count < msgp->count; count++) { 55511991Sheppo addrp = &(msgp->mca[count]); 55521991Sheppo 55531991Sheppo /* delete address from the table */ 55541991Sheppo for (i = 0; i < vgenp->mccount; i++) { 55551991Sheppo if (ether_cmp(addrp, 55561991Sheppo &(vgenp->mctab[i])) == 0) { 55571991Sheppo if (vgenp->mccount > 1) { 55584647Sraghuram int t = vgenp->mccount - 1; 55591991Sheppo vgenp->mctab[i] = 55604650Sraghuram vgenp->mctab[t]; 55611991Sheppo } 55621991Sheppo vgenp->mccount--; 55631991Sheppo break; 55641991Sheppo } 55651991Sheppo } 55661991Sheppo } 55671991Sheppo break; 55681991Sheppo 55691991Sheppo } 55704647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 55712793Slm66018 55722793Slm66018 return (VGEN_SUCCESS); 55731991Sheppo } 55741991Sheppo 55751991Sheppo /* handler for control messages received from the peer ldc end-point */ 55762793Slm66018 static int 55771991Sheppo vgen_handle_ctrlmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 55781991Sheppo { 55792793Slm66018 int rv = 0; 55804647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 55814647Sraghuram 55824647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 55831991Sheppo switch (tagp->vio_subtype_env) { 55841991Sheppo 55851991Sheppo case VIO_VER_INFO: 55862793Slm66018 rv = vgen_handle_version_negotiate(ldcp, tagp); 55871991Sheppo break; 55881991Sheppo 55891991Sheppo case VIO_ATTR_INFO: 55902793Slm66018 rv = vgen_handle_attr_info(ldcp, tagp); 55911991Sheppo break; 55921991Sheppo 55931991Sheppo case VIO_DRING_REG: 55942793Slm66018 rv = vgen_handle_dring_reg(ldcp, tagp); 55951991Sheppo break; 55961991Sheppo 55971991Sheppo case VIO_RDX: 55982793Slm66018 rv = vgen_handle_rdx_info(ldcp, tagp); 55991991Sheppo break; 56001991Sheppo 56011991Sheppo case VNET_MCAST_INFO: 56022793Slm66018 rv = vgen_handle_mcast_info(ldcp, tagp); 56031991Sheppo break; 56041991Sheppo 56056495Sspeer case VIO_DDS_INFO: 56066495Sspeer rv = vgen_dds_rx(ldcp, tagp); 56076495Sspeer break; 56081991Sheppo } 56092793Slm66018 56104647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 56112793Slm66018 return (rv); 56121991Sheppo } 56131991Sheppo 56141991Sheppo /* handler for data messages received from the peer ldc end-point */ 56152793Slm66018 static int 56165935Ssb155480 vgen_handle_datamsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t msglen) 56171991Sheppo { 56182793Slm66018 int rv = 0; 56194647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 56204647Sraghuram 56214647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 56221991Sheppo 56231991Sheppo if (ldcp->hphase != VH_DONE) 56242793Slm66018 return (rv); 56255935Ssb155480 56265935Ssb155480 if (tagp->vio_subtype == VIO_SUBTYPE_INFO) { 56275935Ssb155480 rv = vgen_check_datamsg_seq(ldcp, tagp); 56285935Ssb155480 if (rv != 0) { 56295935Ssb155480 return (rv); 56305935Ssb155480 } 56315935Ssb155480 } 56325935Ssb155480 56331991Sheppo switch (tagp->vio_subtype_env) { 56341991Sheppo case VIO_DRING_DATA: 56354647Sraghuram rv = vgen_handle_dring_data(ldcp, tagp); 56361991Sheppo break; 56375935Ssb155480 56385935Ssb155480 case VIO_PKT_DATA: 56395935Ssb155480 ldcp->rx_pktdata((void *)ldcp, (void *)tagp, msglen); 56405935Ssb155480 break; 56411991Sheppo default: 56421991Sheppo break; 56431991Sheppo } 56441991Sheppo 56454647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 56462793Slm66018 return (rv); 56471991Sheppo } 56481991Sheppo 56495935Ssb155480 /* 56505935Ssb155480 * dummy pkt data handler function for vnet protocol version 1.0 56515935Ssb155480 */ 56525935Ssb155480 static void 56535935Ssb155480 vgen_handle_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen) 56545935Ssb155480 { 56555935Ssb155480 _NOTE(ARGUNUSED(arg1, arg2, msglen)) 56565935Ssb155480 } 56575935Ssb155480 56585935Ssb155480 /* 56595935Ssb155480 * This function handles raw pkt data messages received over the channel. 56605935Ssb155480 * Currently, only priority-eth-type frames are received through this mechanism. 56615935Ssb155480 * In this case, the frame(data) is present within the message itself which 56625935Ssb155480 * is copied into an mblk before sending it up the stack. 56635935Ssb155480 */ 56645935Ssb155480 static void 56655935Ssb155480 vgen_handle_pkt_data(void *arg1, void *arg2, uint32_t msglen) 56665935Ssb155480 { 56675935Ssb155480 vgen_ldc_t *ldcp = (vgen_ldc_t *)arg1; 56685935Ssb155480 vio_raw_data_msg_t *pkt = (vio_raw_data_msg_t *)arg2; 56695935Ssb155480 uint32_t size; 56705935Ssb155480 mblk_t *mp; 56715935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 56725935Ssb155480 vgen_stats_t *statsp = &ldcp->stats; 56736419Ssb155480 vgen_hparams_t *lp = &ldcp->local_hparams; 56746495Sspeer vio_net_rx_cb_t vrx_cb; 56755935Ssb155480 56765935Ssb155480 ASSERT(MUTEX_HELD(&ldcp->cblock)); 56775935Ssb155480 56785935Ssb155480 mutex_exit(&ldcp->cblock); 56795935Ssb155480 56805935Ssb155480 size = msglen - VIO_PKT_DATA_HDRSIZE; 56816419Ssb155480 if (size < ETHERMIN || size > lp->mtu) { 56825935Ssb155480 (void) atomic_inc_32(&statsp->rx_pri_fail); 56835935Ssb155480 goto exit; 56845935Ssb155480 } 56855935Ssb155480 56865935Ssb155480 mp = vio_multipool_allocb(&ldcp->vmp, size); 56875935Ssb155480 if (mp == NULL) { 56885935Ssb155480 mp = allocb(size, BPRI_MED); 56895935Ssb155480 if (mp == NULL) { 56905935Ssb155480 (void) atomic_inc_32(&statsp->rx_pri_fail); 56915935Ssb155480 DWARN(vgenp, ldcp, "allocb failure, " 56925935Ssb155480 "unable to process priority frame\n"); 56935935Ssb155480 goto exit; 56945935Ssb155480 } 56955935Ssb155480 } 56965935Ssb155480 56975935Ssb155480 /* copy the frame from the payload of raw data msg into the mblk */ 56985935Ssb155480 bcopy(pkt->data, mp->b_rptr, size); 56995935Ssb155480 mp->b_wptr = mp->b_rptr + size; 57005935Ssb155480 57015935Ssb155480 /* update stats */ 57025935Ssb155480 (void) atomic_inc_64(&statsp->rx_pri_packets); 57035935Ssb155480 (void) atomic_add_64(&statsp->rx_pri_bytes, size); 57045935Ssb155480 57056495Sspeer /* send up; call vrx_cb() as cblock is already released */ 57066495Sspeer vrx_cb = ldcp->portp->vcb.vio_net_rx_cb; 57076495Sspeer vrx_cb(ldcp->portp->vhp, mp); 57085935Ssb155480 57095935Ssb155480 exit: 57105935Ssb155480 mutex_enter(&ldcp->cblock); 57115935Ssb155480 } 57125935Ssb155480 57132793Slm66018 static int 57142336Snarayan vgen_send_dring_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp, uint32_t start, 57152336Snarayan int32_t end, uint8_t pstate) 57162336Snarayan { 57174647Sraghuram int rv = 0; 57184647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 57192336Snarayan vio_dring_msg_t *msgp = (vio_dring_msg_t *)tagp; 57202336Snarayan 57212336Snarayan tagp->vio_subtype = VIO_SUBTYPE_ACK; 57222336Snarayan tagp->vio_sid = ldcp->local_sid; 57232336Snarayan msgp->start_idx = start; 57242336Snarayan msgp->end_idx = end; 57252336Snarayan msgp->dring_process_state = pstate; 57262793Slm66018 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, sizeof (*msgp), B_FALSE); 57272793Slm66018 if (rv != VGEN_SUCCESS) { 57284647Sraghuram DWARN(vgenp, ldcp, "vgen_sendmsg failed\n"); 57292336Snarayan } 57302793Slm66018 return (rv); 57312336Snarayan } 57322336Snarayan 57332793Slm66018 static int 57344647Sraghuram vgen_handle_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 57351991Sheppo { 57362793Slm66018 int rv = 0; 57374647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 57384647Sraghuram 57394647Sraghuram 57404647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 57411991Sheppo switch (tagp->vio_subtype) { 57421991Sheppo 57431991Sheppo case VIO_SUBTYPE_INFO: 57441991Sheppo /* 57454647Sraghuram * To reduce the locking contention, release the 57464647Sraghuram * cblock here and re-acquire it once we are done 57474647Sraghuram * receiving packets. 57481991Sheppo */ 57494647Sraghuram mutex_exit(&ldcp->cblock); 57504647Sraghuram mutex_enter(&ldcp->rxlock); 57514647Sraghuram rv = vgen_handle_dring_data_info(ldcp, tagp); 57524647Sraghuram mutex_exit(&ldcp->rxlock); 57534647Sraghuram mutex_enter(&ldcp->cblock); 57544647Sraghuram break; 57554647Sraghuram 57564647Sraghuram case VIO_SUBTYPE_ACK: 57574647Sraghuram rv = vgen_handle_dring_data_ack(ldcp, tagp); 57584647Sraghuram break; 57594647Sraghuram 57604647Sraghuram case VIO_SUBTYPE_NACK: 57614647Sraghuram rv = vgen_handle_dring_data_nack(ldcp, tagp); 57624647Sraghuram break; 57634647Sraghuram } 57644647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 57654647Sraghuram return (rv); 57664647Sraghuram } 57674647Sraghuram 57684647Sraghuram static int 57694647Sraghuram vgen_handle_dring_data_info(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 57704647Sraghuram { 57714647Sraghuram uint32_t start; 57724647Sraghuram int32_t end; 57734647Sraghuram int rv = 0; 57744647Sraghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp; 57754647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 57764647Sraghuram #ifdef VGEN_HANDLE_LOST_PKTS 57775373Sraghuram vgen_stats_t *statsp = &ldcp->stats; 57784647Sraghuram uint32_t rxi; 57794647Sraghuram int n; 57804647Sraghuram #endif 57814647Sraghuram 57824647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 57834647Sraghuram 57844647Sraghuram start = dringmsg->start_idx; 57854647Sraghuram end = dringmsg->end_idx; 57864647Sraghuram /* 57874647Sraghuram * received a data msg, which contains the start and end 57884647Sraghuram * indices of the descriptors within the rx ring holding data, 57894647Sraghuram * the seq_num of data packet corresponding to the start index, 57904647Sraghuram * and the dring_ident. 57914647Sraghuram * We can now read the contents of each of these descriptors 57924647Sraghuram * and gather data from it. 57934647Sraghuram */ 57944647Sraghuram DBG1(vgenp, ldcp, "INFO: start(%d), end(%d)\n", 57954650Sraghuram start, end); 57964647Sraghuram 57974647Sraghuram /* validate rx start and end indeces */ 57984647Sraghuram if (!(CHECK_RXI(start, ldcp)) || ((end != -1) && 57994647Sraghuram !(CHECK_RXI(end, ldcp)))) { 58004647Sraghuram DWARN(vgenp, ldcp, "Invalid Rx start(%d) or end(%d)\n", 58014647Sraghuram start, end); 58024647Sraghuram /* drop the message if invalid index */ 58034647Sraghuram return (rv); 58044647Sraghuram } 58054647Sraghuram 58064647Sraghuram /* validate dring_ident */ 58074647Sraghuram if (dringmsg->dring_ident != ldcp->peer_hparams.dring_ident) { 58084647Sraghuram DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n", 58094647Sraghuram dringmsg->dring_ident); 58104647Sraghuram /* invalid dring_ident, drop the msg */ 58114647Sraghuram return (rv); 58124647Sraghuram } 58131991Sheppo #ifdef DEBUG 58144647Sraghuram if (vgen_trigger_rxlost) { 58154647Sraghuram /* drop this msg to simulate lost pkts for debugging */ 58164647Sraghuram vgen_trigger_rxlost = 0; 58174647Sraghuram return (rv); 58184647Sraghuram } 58191991Sheppo #endif 58201991Sheppo 58211991Sheppo #ifdef VGEN_HANDLE_LOST_PKTS 58221991Sheppo 58234647Sraghuram /* receive start index doesn't match expected index */ 58244647Sraghuram if (ldcp->next_rxi != start) { 58254647Sraghuram DWARN(vgenp, ldcp, "next_rxi(%d) != start(%d)\n", 58264647Sraghuram ldcp->next_rxi, start); 58274647Sraghuram 58284647Sraghuram /* calculate the number of pkts lost */ 58294647Sraghuram if (start >= ldcp->next_rxi) { 58304647Sraghuram n = start - ldcp->next_rxi; 58314647Sraghuram } else { 58324647Sraghuram n = ldcp->num_rxds - (ldcp->next_rxi - start); 58334647Sraghuram } 58344647Sraghuram 58355935Ssb155480 statsp->rx_lost_pkts += n; 58365935Ssb155480 tagp->vio_subtype = VIO_SUBTYPE_NACK; 58375935Ssb155480 tagp->vio_sid = ldcp->local_sid; 58385935Ssb155480 /* indicate the range of lost descriptors */ 58395935Ssb155480 dringmsg->start_idx = ldcp->next_rxi; 58405935Ssb155480 rxi = start; 58415935Ssb155480 DECR_RXI(rxi, ldcp); 58425935Ssb155480 dringmsg->end_idx = rxi; 58435935Ssb155480 /* dring ident is left unchanged */ 58445935Ssb155480 rv = vgen_sendmsg(ldcp, (caddr_t)tagp, 58455935Ssb155480 sizeof (*dringmsg), B_FALSE); 58465935Ssb155480 if (rv != VGEN_SUCCESS) { 58475935Ssb155480 DWARN(vgenp, ldcp, 58485935Ssb155480 "vgen_sendmsg failed, stype:NACK\n"); 58494647Sraghuram return (rv); 58501991Sheppo } 58511991Sheppo /* 58525935Ssb155480 * treat this range of descrs/pkts as dropped 58535935Ssb155480 * and set the new expected value of next_rxi 58545935Ssb155480 * and continue(below) to process from the new 58555935Ssb155480 * start index. 58561991Sheppo */ 58575935Ssb155480 ldcp->next_rxi = start; 58584647Sraghuram } 58594647Sraghuram 58604647Sraghuram #endif /* VGEN_HANDLE_LOST_PKTS */ 58614647Sraghuram 58624647Sraghuram /* Now receive messages */ 58634647Sraghuram rv = vgen_process_dring_data(ldcp, tagp); 58644647Sraghuram 58654647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 58664647Sraghuram return (rv); 58674647Sraghuram } 58684647Sraghuram 58694647Sraghuram static int 58704647Sraghuram vgen_process_dring_data(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 58714647Sraghuram { 58724647Sraghuram boolean_t set_ack_start = B_FALSE; 58734647Sraghuram uint32_t start; 58744647Sraghuram uint32_t ack_end; 58754647Sraghuram uint32_t next_rxi; 58764647Sraghuram uint32_t rxi; 58774647Sraghuram int count = 0; 58784647Sraghuram int rv = 0; 58794647Sraghuram uint32_t retries = 0; 58804647Sraghuram vgen_stats_t *statsp; 58816845Sha137994 vnet_public_desc_t rxd; 58824647Sraghuram vio_dring_entry_hdr_t *hdrp; 58834647Sraghuram mblk_t *bp = NULL; 58844647Sraghuram mblk_t *bpt = NULL; 58854647Sraghuram uint32_t ack_start; 58864647Sraghuram boolean_t rxd_err = B_FALSE; 58874647Sraghuram mblk_t *mp = NULL; 58884647Sraghuram size_t nbytes; 58894647Sraghuram boolean_t ack_needed = B_FALSE; 58904647Sraghuram size_t nread; 58914647Sraghuram uint64_t off = 0; 58924647Sraghuram struct ether_header *ehp; 58934647Sraghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp; 58944647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 58957529SSriharsha.Basavapatna@Sun.COM vgen_hparams_t *lp = &ldcp->local_hparams; 58964647Sraghuram 58974647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 58984647Sraghuram 58995373Sraghuram statsp = &ldcp->stats; 59004647Sraghuram start = dringmsg->start_idx; 59014647Sraghuram 59024647Sraghuram /* 59034647Sraghuram * start processing the descriptors from the specified 59044647Sraghuram * start index, up to the index a descriptor is not ready 59054647Sraghuram * to be processed or we process the entire descriptor ring 59064647Sraghuram * and wrap around upto the start index. 59074647Sraghuram */ 59084647Sraghuram 59094647Sraghuram /* need to set the start index of descriptors to be ack'd */ 59104647Sraghuram set_ack_start = B_TRUE; 59114647Sraghuram 59124647Sraghuram /* index upto which we have ack'd */ 59134647Sraghuram ack_end = start; 59144647Sraghuram DECR_RXI(ack_end, ldcp); 59154647Sraghuram 59164647Sraghuram next_rxi = rxi = start; 59174647Sraghuram do { 59184647Sraghuram vgen_recv_retry: 59196845Sha137994 rv = vnet_dring_entry_copy(&(ldcp->rxdp[rxi]), &rxd, 59206845Sha137994 ldcp->dring_mtype, ldcp->rx_dhandle, rxi, rxi); 59214647Sraghuram if (rv != 0) { 59224647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_dring_acquire() failed" 59234647Sraghuram " rv(%d)\n", rv); 59244647Sraghuram statsp->ierrors++; 59254647Sraghuram return (rv); 59264647Sraghuram } 59274647Sraghuram 59286845Sha137994 hdrp = &rxd.hdr; 59294647Sraghuram 59304647Sraghuram if (hdrp->dstate != VIO_DESC_READY) { 59314647Sraghuram /* 59325935Ssb155480 * Before waiting and retry here, send up 59335935Ssb155480 * the packets that are received already 59344647Sraghuram */ 59354647Sraghuram if (bp != NULL) { 59364647Sraghuram DTRACE_PROBE1(vgen_rcv_msgs, int, count); 59375935Ssb155480 vgen_rx(ldcp, bp); 59384647Sraghuram count = 0; 59394647Sraghuram bp = bpt = NULL; 59404647Sraghuram } 59414647Sraghuram /* 59424647Sraghuram * descriptor is not ready. 59434647Sraghuram * retry descriptor acquire, stop processing 59444647Sraghuram * after max # retries. 59454647Sraghuram */ 59464647Sraghuram if (retries == vgen_recv_retries) 59474647Sraghuram break; 59484647Sraghuram retries++; 59494647Sraghuram drv_usecwait(vgen_recv_delay); 59504647Sraghuram goto vgen_recv_retry; 59514647Sraghuram } 59524647Sraghuram retries = 0; 59534647Sraghuram 59544647Sraghuram if (set_ack_start) { 59554647Sraghuram /* 59564647Sraghuram * initialize the start index of the range 59574647Sraghuram * of descriptors to be ack'd. 59584647Sraghuram */ 59594647Sraghuram ack_start = rxi; 59604647Sraghuram set_ack_start = B_FALSE; 59614647Sraghuram } 59624647Sraghuram 59636845Sha137994 if ((rxd.nbytes < ETHERMIN) || 59647529SSriharsha.Basavapatna@Sun.COM (rxd.nbytes > lp->mtu) || 59656845Sha137994 (rxd.ncookies == 0) || 59666845Sha137994 (rxd.ncookies > MAX_COOKIES)) { 59674647Sraghuram rxd_err = B_TRUE; 59684647Sraghuram } else { 59694647Sraghuram /* 59704647Sraghuram * Try to allocate an mblk from the free pool 59714647Sraghuram * of recv mblks for the channel. 59724647Sraghuram * If this fails, use allocb(). 59734647Sraghuram */ 59746845Sha137994 nbytes = (VNET_IPALIGN + rxd.nbytes + 7) & ~7; 59757529SSriharsha.Basavapatna@Sun.COM if (nbytes > ldcp->max_rxpool_size) { 59766845Sha137994 mp = allocb(VNET_IPALIGN + rxd.nbytes + 8, 59774647Sraghuram BPRI_MED); 59787529SSriharsha.Basavapatna@Sun.COM } else { 59797529SSriharsha.Basavapatna@Sun.COM mp = vio_multipool_allocb(&ldcp->vmp, nbytes); 59807529SSriharsha.Basavapatna@Sun.COM if (mp == NULL) { 59817529SSriharsha.Basavapatna@Sun.COM statsp->rx_vio_allocb_fail++; 59827529SSriharsha.Basavapatna@Sun.COM /* 59837529SSriharsha.Basavapatna@Sun.COM * Data buffer returned by allocb(9F) 59847529SSriharsha.Basavapatna@Sun.COM * is 8byte aligned. We allocate extra 59857529SSriharsha.Basavapatna@Sun.COM * 8 bytes to ensure size is multiple 59867529SSriharsha.Basavapatna@Sun.COM * of 8 bytes for ldc_mem_copy(). 59877529SSriharsha.Basavapatna@Sun.COM */ 59887529SSriharsha.Basavapatna@Sun.COM mp = allocb(VNET_IPALIGN + 59897529SSriharsha.Basavapatna@Sun.COM rxd.nbytes + 8, BPRI_MED); 59907529SSriharsha.Basavapatna@Sun.COM } 59911991Sheppo } 59924647Sraghuram } 59934647Sraghuram if ((rxd_err) || (mp == NULL)) { 59944647Sraghuram /* 59954647Sraghuram * rxd_err or allocb() failure, 59964647Sraghuram * drop this packet, get next. 59974647Sraghuram */ 59984647Sraghuram if (rxd_err) { 59992793Slm66018 statsp->ierrors++; 60004647Sraghuram rxd_err = B_FALSE; 60014647Sraghuram } else { 60024647Sraghuram statsp->rx_allocb_fail++; 60032793Slm66018 } 60042793Slm66018 60052793Slm66018 ack_needed = hdrp->ack; 60064647Sraghuram 60074647Sraghuram /* set descriptor done bit */ 60086845Sha137994 rv = vnet_dring_entry_set_dstate(&(ldcp->rxdp[rxi]), 60096845Sha137994 ldcp->dring_mtype, ldcp->rx_dhandle, rxi, rxi, 60106845Sha137994 VIO_DESC_DONE); 60112793Slm66018 if (rv != 0) { 60124647Sraghuram DWARN(vgenp, ldcp, 60136845Sha137994 "vnet_dring_entry_set_dstate err rv(%d)\n", 60146845Sha137994 rv); 60154647Sraghuram return (rv); 60162793Slm66018 } 60172336Snarayan 60182793Slm66018 if (ack_needed) { 60192793Slm66018 ack_needed = B_FALSE; 60201991Sheppo /* 60212336Snarayan * sender needs ack for this packet, 60222336Snarayan * ack pkts upto this index. 60231991Sheppo */ 60242336Snarayan ack_end = rxi; 60252336Snarayan 60262793Slm66018 rv = vgen_send_dring_ack(ldcp, tagp, 60274647Sraghuram ack_start, ack_end, 60284647Sraghuram VIO_DP_ACTIVE); 60292793Slm66018 if (rv != VGEN_SUCCESS) { 60302793Slm66018 goto error_ret; 60312793Slm66018 } 60322336Snarayan 60332336Snarayan /* need to set new ack start index */ 60342336Snarayan set_ack_start = B_TRUE; 60351991Sheppo } 60364647Sraghuram goto vgen_next_rxi; 60374647Sraghuram } 60384647Sraghuram 60394647Sraghuram nread = nbytes; 60404647Sraghuram rv = ldc_mem_copy(ldcp->ldc_handle, 60414647Sraghuram (caddr_t)mp->b_rptr, off, &nread, 60426845Sha137994 rxd.memcookie, rxd.ncookies, LDC_COPY_IN); 60434647Sraghuram 60444647Sraghuram /* if ldc_mem_copy() failed */ 60454647Sraghuram if (rv) { 60464647Sraghuram DWARN(vgenp, ldcp, "ldc_mem_copy err rv(%d)\n", rv); 60474647Sraghuram statsp->ierrors++; 60484647Sraghuram freemsg(mp); 60494647Sraghuram goto error_ret; 60504647Sraghuram } 60514647Sraghuram 60524647Sraghuram ack_needed = hdrp->ack; 60536845Sha137994 60546845Sha137994 rv = vnet_dring_entry_set_dstate(&(ldcp->rxdp[rxi]), 60556845Sha137994 ldcp->dring_mtype, ldcp->rx_dhandle, rxi, rxi, 60566845Sha137994 VIO_DESC_DONE); 60574647Sraghuram if (rv != 0) { 60584647Sraghuram DWARN(vgenp, ldcp, 60596845Sha137994 "vnet_dring_entry_set_dstate err rv(%d)\n", rv); 60604647Sraghuram goto error_ret; 60614647Sraghuram } 60624647Sraghuram 60634647Sraghuram mp->b_rptr += VNET_IPALIGN; 60644647Sraghuram 60654647Sraghuram if (ack_needed) { 60664647Sraghuram ack_needed = B_FALSE; 60674647Sraghuram /* 60684647Sraghuram * sender needs ack for this packet, 60694647Sraghuram * ack pkts upto this index. 60704647Sraghuram */ 60714647Sraghuram ack_end = rxi; 60724647Sraghuram 60734647Sraghuram rv = vgen_send_dring_ack(ldcp, tagp, 60744647Sraghuram ack_start, ack_end, VIO_DP_ACTIVE); 60754647Sraghuram if (rv != VGEN_SUCCESS) { 60764647Sraghuram goto error_ret; 60771991Sheppo } 60781991Sheppo 60794647Sraghuram /* need to set new ack start index */ 60804647Sraghuram set_ack_start = B_TRUE; 60814647Sraghuram } 60824647Sraghuram 60834647Sraghuram if (nread != nbytes) { 60844647Sraghuram DWARN(vgenp, ldcp, 60854647Sraghuram "ldc_mem_copy nread(%lx), nbytes(%lx)\n", 60864647Sraghuram nread, nbytes); 60874647Sraghuram statsp->ierrors++; 60884647Sraghuram freemsg(mp); 60894647Sraghuram goto vgen_next_rxi; 60904647Sraghuram } 60914647Sraghuram 60924647Sraghuram /* point to the actual end of data */ 60936845Sha137994 mp->b_wptr = mp->b_rptr + rxd.nbytes; 60944647Sraghuram 60954647Sraghuram /* update stats */ 60964647Sraghuram statsp->ipackets++; 60976845Sha137994 statsp->rbytes += rxd.nbytes; 60984647Sraghuram ehp = (struct ether_header *)mp->b_rptr; 60994647Sraghuram if (IS_BROADCAST(ehp)) 61004647Sraghuram statsp->brdcstrcv++; 61014647Sraghuram else if (IS_MULTICAST(ehp)) 61024647Sraghuram statsp->multircv++; 61034647Sraghuram 61044647Sraghuram /* build a chain of received packets */ 61054647Sraghuram if (bp == NULL) { 61064647Sraghuram /* first pkt */ 61074647Sraghuram bp = mp; 61084647Sraghuram bpt = bp; 61094647Sraghuram bpt->b_next = NULL; 61104647Sraghuram } else { 61114647Sraghuram mp->b_next = NULL; 61124647Sraghuram bpt->b_next = mp; 61134647Sraghuram bpt = mp; 61144647Sraghuram } 61154647Sraghuram 61164647Sraghuram if (count++ > vgen_chain_len) { 61174647Sraghuram DTRACE_PROBE1(vgen_rcv_msgs, int, count); 61185935Ssb155480 vgen_rx(ldcp, bp); 61194647Sraghuram count = 0; 61204647Sraghuram bp = bpt = NULL; 61214647Sraghuram } 61222336Snarayan 61232336Snarayan vgen_next_rxi: 61244647Sraghuram /* update end index of range of descrs to be ack'd */ 61254647Sraghuram ack_end = rxi; 61264647Sraghuram 61274647Sraghuram /* update the next index to be processed */ 61284647Sraghuram INCR_RXI(next_rxi, ldcp); 61294647Sraghuram if (next_rxi == start) { 61302336Snarayan /* 61314647Sraghuram * processed the entire descriptor ring upto 61324647Sraghuram * the index at which we started. 61332336Snarayan */ 61342336Snarayan break; 61352336Snarayan } 61362336Snarayan 61374647Sraghuram rxi = next_rxi; 61384647Sraghuram 61394647Sraghuram _NOTE(CONSTCOND) 61404647Sraghuram } while (1); 61414647Sraghuram 61424647Sraghuram /* 61434647Sraghuram * send an ack message to peer indicating that we have stopped 61444647Sraghuram * processing descriptors. 61454647Sraghuram */ 61464647Sraghuram if (set_ack_start) { 61472336Snarayan /* 61484647Sraghuram * We have ack'd upto some index and we have not 61494647Sraghuram * processed any descriptors beyond that index. 61504647Sraghuram * Use the last ack'd index as both the start and 61514647Sraghuram * end of range of descrs being ack'd. 61524647Sraghuram * Note: This results in acking the last index twice 61534647Sraghuram * and should be harmless. 61542336Snarayan */ 61554647Sraghuram ack_start = ack_end; 61564647Sraghuram } 61574647Sraghuram 61584647Sraghuram rv = vgen_send_dring_ack(ldcp, tagp, ack_start, ack_end, 61594647Sraghuram VIO_DP_STOPPED); 61604647Sraghuram if (rv != VGEN_SUCCESS) { 61614647Sraghuram goto error_ret; 61624647Sraghuram } 61634647Sraghuram 61645935Ssb155480 /* save new recv index of next dring msg */ 61654647Sraghuram ldcp->next_rxi = next_rxi; 61664647Sraghuram 61674647Sraghuram error_ret: 61685935Ssb155480 /* send up packets received so far */ 61694647Sraghuram if (bp != NULL) { 61704647Sraghuram DTRACE_PROBE1(vgen_rcv_msgs, int, count); 61715935Ssb155480 vgen_rx(ldcp, bp); 61724647Sraghuram bp = bpt = NULL; 61734647Sraghuram } 61744647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 61754647Sraghuram return (rv); 61764647Sraghuram 61774647Sraghuram } 61784647Sraghuram 61794647Sraghuram static int 61804647Sraghuram vgen_handle_dring_data_ack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 61814647Sraghuram { 61824647Sraghuram int rv = 0; 61834647Sraghuram uint32_t start; 61844647Sraghuram int32_t end; 61854647Sraghuram uint32_t txi; 61864647Sraghuram boolean_t ready_txd = B_FALSE; 61874647Sraghuram vgen_stats_t *statsp; 61884647Sraghuram vgen_private_desc_t *tbufp; 61894647Sraghuram vnet_public_desc_t *txdp; 61904647Sraghuram vio_dring_entry_hdr_t *hdrp; 61914647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 61924647Sraghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp; 61934647Sraghuram 61944647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 61954647Sraghuram start = dringmsg->start_idx; 61964647Sraghuram end = dringmsg->end_idx; 61975373Sraghuram statsp = &ldcp->stats; 61984647Sraghuram 61994647Sraghuram /* 62004647Sraghuram * received an ack corresponding to a specific descriptor for 62014647Sraghuram * which we had set the ACK bit in the descriptor (during 62024647Sraghuram * transmit). This enables us to reclaim descriptors. 62034647Sraghuram */ 62044647Sraghuram 62054647Sraghuram DBG2(vgenp, ldcp, "ACK: start(%d), end(%d)\n", start, end); 62064647Sraghuram 62074647Sraghuram /* validate start and end indeces in the tx ack msg */ 62084647Sraghuram if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) { 62094647Sraghuram /* drop the message if invalid index */ 62104647Sraghuram DWARN(vgenp, ldcp, "Invalid Tx ack start(%d) or end(%d)\n", 62114647Sraghuram start, end); 62124647Sraghuram return (rv); 62134647Sraghuram } 62144647Sraghuram /* validate dring_ident */ 62154647Sraghuram if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) { 62164647Sraghuram /* invalid dring_ident, drop the msg */ 62174647Sraghuram DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n", 62184647Sraghuram dringmsg->dring_ident); 62194647Sraghuram return (rv); 62204647Sraghuram } 62214647Sraghuram statsp->dring_data_acks++; 62224647Sraghuram 62234647Sraghuram /* reclaim descriptors that are done */ 62244647Sraghuram vgen_reclaim(ldcp); 62254647Sraghuram 62264647Sraghuram if (dringmsg->dring_process_state != VIO_DP_STOPPED) { 62272336Snarayan /* 62284647Sraghuram * receiver continued processing descriptors after 62294647Sraghuram * sending us the ack. 62302336Snarayan */ 62314647Sraghuram return (rv); 62324647Sraghuram } 62334647Sraghuram 62344647Sraghuram statsp->dring_stopped_acks++; 62354647Sraghuram 62364647Sraghuram /* receiver stopped processing descriptors */ 62374647Sraghuram mutex_enter(&ldcp->wrlock); 62384647Sraghuram mutex_enter(&ldcp->tclock); 62394647Sraghuram 62404647Sraghuram /* 62414647Sraghuram * determine if there are any pending tx descriptors 62424647Sraghuram * ready to be processed by the receiver(peer) and if so, 62434647Sraghuram * send a message to the peer to restart receiving. 62444647Sraghuram */ 62454647Sraghuram ready_txd = B_FALSE; 62464647Sraghuram 62474647Sraghuram /* 62484647Sraghuram * using the end index of the descriptor range for which 62494647Sraghuram * we received the ack, check if the next descriptor is 62504647Sraghuram * ready. 62514647Sraghuram */ 62524647Sraghuram txi = end; 62534647Sraghuram INCR_TXI(txi, ldcp); 62544647Sraghuram tbufp = &ldcp->tbufp[txi]; 62554647Sraghuram txdp = tbufp->descp; 62564647Sraghuram hdrp = &txdp->hdr; 62574647Sraghuram if (hdrp->dstate == VIO_DESC_READY) { 62584647Sraghuram ready_txd = B_TRUE; 62594647Sraghuram } else { 62604647Sraghuram /* 62614647Sraghuram * descr next to the end of ack'd descr range is not 62624647Sraghuram * ready. 62634647Sraghuram * starting from the current reclaim index, check 62644647Sraghuram * if any descriptor is ready. 62654647Sraghuram */ 62664647Sraghuram 62674647Sraghuram txi = ldcp->cur_tbufp - ldcp->tbufp; 62682336Snarayan tbufp = &ldcp->tbufp[txi]; 62694647Sraghuram 62702336Snarayan txdp = tbufp->descp; 62712336Snarayan hdrp = &txdp->hdr; 62722336Snarayan if (hdrp->dstate == VIO_DESC_READY) { 62732336Snarayan ready_txd = B_TRUE; 62744647Sraghuram } 62754647Sraghuram 62764647Sraghuram } 62774647Sraghuram 62784647Sraghuram if (ready_txd) { 62794647Sraghuram /* 62804647Sraghuram * we have tx descriptor(s) ready to be 62814647Sraghuram * processed by the receiver. 62824647Sraghuram * send a message to the peer with the start index 62834647Sraghuram * of ready descriptors. 62844647Sraghuram */ 62854647Sraghuram rv = vgen_send_dring_data(ldcp, txi, -1); 62864647Sraghuram if (rv != VGEN_SUCCESS) { 62874647Sraghuram ldcp->resched_peer = B_TRUE; 62884647Sraghuram ldcp->resched_peer_txi = txi; 62894647Sraghuram mutex_exit(&ldcp->tclock); 62904647Sraghuram mutex_exit(&ldcp->wrlock); 62914647Sraghuram return (rv); 62922336Snarayan } 62934647Sraghuram } else { 62944647Sraghuram /* 62954647Sraghuram * no ready tx descriptors. set the flag to send a 62964647Sraghuram * message to peer when tx descriptors are ready in 62974647Sraghuram * transmit routine. 62984647Sraghuram */ 62994647Sraghuram ldcp->resched_peer = B_TRUE; 63004647Sraghuram ldcp->resched_peer_txi = ldcp->cur_tbufp - ldcp->tbufp; 63014647Sraghuram } 63024647Sraghuram 63034647Sraghuram mutex_exit(&ldcp->tclock); 63044647Sraghuram mutex_exit(&ldcp->wrlock); 63054647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 63064647Sraghuram return (rv); 63074647Sraghuram } 63084647Sraghuram 63094647Sraghuram static int 63104647Sraghuram vgen_handle_dring_data_nack(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 63114647Sraghuram { 63124647Sraghuram int rv = 0; 63134647Sraghuram uint32_t start; 63144647Sraghuram int32_t end; 63154647Sraghuram uint32_t txi; 63164647Sraghuram vnet_public_desc_t *txdp; 63174647Sraghuram vio_dring_entry_hdr_t *hdrp; 63184647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 63194647Sraghuram vio_dring_msg_t *dringmsg = (vio_dring_msg_t *)tagp; 63204647Sraghuram 63214647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 63224647Sraghuram start = dringmsg->start_idx; 63234647Sraghuram end = dringmsg->end_idx; 63244647Sraghuram 63254647Sraghuram /* 63264647Sraghuram * peer sent a NACK msg to indicate lost packets. 63274647Sraghuram * The start and end correspond to the range of descriptors 63284647Sraghuram * for which the peer didn't receive a dring data msg and so 63294647Sraghuram * didn't receive the corresponding data. 63304647Sraghuram */ 63314647Sraghuram DWARN(vgenp, ldcp, "NACK: start(%d), end(%d)\n", start, end); 63324647Sraghuram 63334647Sraghuram /* validate start and end indeces in the tx nack msg */ 63344647Sraghuram if (!(CHECK_TXI(start, ldcp)) || !(CHECK_TXI(end, ldcp))) { 63354647Sraghuram /* drop the message if invalid index */ 63364647Sraghuram DWARN(vgenp, ldcp, "Invalid Tx nack start(%d) or end(%d)\n", 63374647Sraghuram start, end); 63384647Sraghuram return (rv); 63394647Sraghuram } 63404647Sraghuram /* validate dring_ident */ 63414647Sraghuram if (dringmsg->dring_ident != ldcp->local_hparams.dring_ident) { 63424647Sraghuram /* invalid dring_ident, drop the msg */ 63434647Sraghuram DWARN(vgenp, ldcp, "Invalid dring ident 0x%x\n", 63444647Sraghuram dringmsg->dring_ident); 63454647Sraghuram return (rv); 63464647Sraghuram } 63474647Sraghuram mutex_enter(&ldcp->txlock); 63484647Sraghuram mutex_enter(&ldcp->tclock); 63494647Sraghuram 63504647Sraghuram if (ldcp->next_tbufp == ldcp->cur_tbufp) { 63514647Sraghuram /* no busy descriptors, bogus nack ? */ 63522336Snarayan mutex_exit(&ldcp->tclock); 63532336Snarayan mutex_exit(&ldcp->txlock); 63544647Sraghuram return (rv); 63554647Sraghuram } 63561991Sheppo 63574647Sraghuram /* we just mark the descrs as done so they can be reclaimed */ 63584647Sraghuram for (txi = start; txi <= end; ) { 63594647Sraghuram txdp = &(ldcp->txdp[txi]); 63604647Sraghuram hdrp = &txdp->hdr; 63614647Sraghuram if (hdrp->dstate == VIO_DESC_READY) 63624647Sraghuram hdrp->dstate = VIO_DESC_DONE; 63634647Sraghuram INCR_TXI(txi, ldcp); 63644647Sraghuram } 63654647Sraghuram mutex_exit(&ldcp->tclock); 63664647Sraghuram mutex_exit(&ldcp->txlock); 63674647Sraghuram DBG1(vgenp, ldcp, "exit rv(%d)\n", rv); 63682793Slm66018 return (rv); 63691991Sheppo } 63701991Sheppo 63711991Sheppo static void 63721991Sheppo vgen_reclaim(vgen_ldc_t *ldcp) 63731991Sheppo { 63742336Snarayan mutex_enter(&ldcp->tclock); 63752336Snarayan 63761991Sheppo vgen_reclaim_dring(ldcp); 63771991Sheppo ldcp->reclaim_lbolt = ddi_get_lbolt(); 63782336Snarayan 63791991Sheppo mutex_exit(&ldcp->tclock); 63801991Sheppo } 63811991Sheppo 63821991Sheppo /* 63831991Sheppo * transmit reclaim function. starting from the current reclaim index 63841991Sheppo * look for descriptors marked DONE and reclaim the descriptor and the 63851991Sheppo * corresponding buffers (tbuf). 63861991Sheppo */ 63871991Sheppo static void 63881991Sheppo vgen_reclaim_dring(vgen_ldc_t *ldcp) 63891991Sheppo { 63905022Sraghuram int count = 0; 63911991Sheppo vnet_public_desc_t *txdp; 63921991Sheppo vgen_private_desc_t *tbufp; 63931991Sheppo vio_dring_entry_hdr_t *hdrp; 63941991Sheppo 63951991Sheppo #ifdef DEBUG 63961991Sheppo if (vgen_trigger_txtimeout) 63971991Sheppo return; 63981991Sheppo #endif 63991991Sheppo 64001991Sheppo tbufp = ldcp->cur_tbufp; 64011991Sheppo txdp = tbufp->descp; 64021991Sheppo hdrp = &txdp->hdr; 64031991Sheppo 64041991Sheppo while ((hdrp->dstate == VIO_DESC_DONE) && 64051991Sheppo (tbufp != ldcp->next_tbufp)) { 64061991Sheppo tbufp->flags = VGEN_PRIV_DESC_FREE; 64071991Sheppo hdrp->dstate = VIO_DESC_FREE; 64081991Sheppo hdrp->ack = B_FALSE; 64091991Sheppo 64101991Sheppo tbufp = NEXTTBUF(ldcp, tbufp); 64111991Sheppo txdp = tbufp->descp; 64121991Sheppo hdrp = &txdp->hdr; 64135022Sraghuram count++; 64141991Sheppo } 64151991Sheppo 64161991Sheppo ldcp->cur_tbufp = tbufp; 64171991Sheppo 64181991Sheppo /* 64191991Sheppo * Check if mac layer should be notified to restart transmissions 64201991Sheppo */ 64215022Sraghuram if ((ldcp->need_resched) && (count > 0)) { 64226495Sspeer vio_net_tx_update_t vtx_update = 64236495Sspeer ldcp->portp->vcb.vio_net_tx_update; 64246495Sspeer 64251991Sheppo ldcp->need_resched = B_FALSE; 64266495Sspeer vtx_update(ldcp->portp->vhp); 64271991Sheppo } 64281991Sheppo } 64291991Sheppo 64301991Sheppo /* return the number of pending transmits for the channel */ 64311991Sheppo static int 64321991Sheppo vgen_num_txpending(vgen_ldc_t *ldcp) 64331991Sheppo { 64341991Sheppo int n; 64351991Sheppo 64361991Sheppo if (ldcp->next_tbufp >= ldcp->cur_tbufp) { 64371991Sheppo n = ldcp->next_tbufp - ldcp->cur_tbufp; 64381991Sheppo } else { 64391991Sheppo /* cur_tbufp > next_tbufp */ 64401991Sheppo n = ldcp->num_txds - (ldcp->cur_tbufp - ldcp->next_tbufp); 64411991Sheppo } 64421991Sheppo 64431991Sheppo return (n); 64441991Sheppo } 64451991Sheppo 64461991Sheppo /* determine if the transmit descriptor ring is full */ 64471991Sheppo static int 64481991Sheppo vgen_tx_dring_full(vgen_ldc_t *ldcp) 64491991Sheppo { 64501991Sheppo vgen_private_desc_t *tbufp; 64511991Sheppo vgen_private_desc_t *ntbufp; 64521991Sheppo 64531991Sheppo tbufp = ldcp->next_tbufp; 64541991Sheppo ntbufp = NEXTTBUF(ldcp, tbufp); 64551991Sheppo if (ntbufp == ldcp->cur_tbufp) { /* out of tbufs/txds */ 64561991Sheppo return (VGEN_SUCCESS); 64571991Sheppo } 64581991Sheppo return (VGEN_FAILURE); 64591991Sheppo } 64601991Sheppo 64611991Sheppo /* determine if timeout condition has occured */ 64621991Sheppo static int 64631991Sheppo vgen_ldc_txtimeout(vgen_ldc_t *ldcp) 64641991Sheppo { 64651991Sheppo if (((ddi_get_lbolt() - ldcp->reclaim_lbolt) > 64664650Sraghuram drv_usectohz(vnet_ldcwd_txtimeout * 1000)) && 64674650Sraghuram (vnet_ldcwd_txtimeout) && 64684650Sraghuram (vgen_tx_dring_full(ldcp) == VGEN_SUCCESS)) { 64691991Sheppo return (VGEN_SUCCESS); 64701991Sheppo } else { 64711991Sheppo return (VGEN_FAILURE); 64721991Sheppo } 64731991Sheppo } 64741991Sheppo 64751991Sheppo /* transmit watchdog timeout handler */ 64761991Sheppo static void 64771991Sheppo vgen_ldc_watchdog(void *arg) 64781991Sheppo { 64791991Sheppo vgen_ldc_t *ldcp; 64802336Snarayan vgen_t *vgenp; 64811991Sheppo int rv; 64821991Sheppo 64831991Sheppo ldcp = (vgen_ldc_t *)arg; 64842336Snarayan vgenp = LDC_TO_VGEN(ldcp); 64851991Sheppo 64861991Sheppo rv = vgen_ldc_txtimeout(ldcp); 64871991Sheppo if (rv == VGEN_SUCCESS) { 64884647Sraghuram DWARN(vgenp, ldcp, "transmit timeout\n"); 64891991Sheppo #ifdef DEBUG 64901991Sheppo if (vgen_trigger_txtimeout) { 64911991Sheppo /* tx timeout triggered for debugging */ 64921991Sheppo vgen_trigger_txtimeout = 0; 64931991Sheppo } 64941991Sheppo #endif 64951991Sheppo mutex_enter(&ldcp->cblock); 64962793Slm66018 ldcp->need_ldc_reset = B_TRUE; 64973653Snarayan vgen_handshake_retry(ldcp); 64981991Sheppo mutex_exit(&ldcp->cblock); 64991991Sheppo if (ldcp->need_resched) { 65006495Sspeer vio_net_tx_update_t vtx_update = 65016495Sspeer ldcp->portp->vcb.vio_net_tx_update; 65026495Sspeer 65031991Sheppo ldcp->need_resched = B_FALSE; 65046495Sspeer vtx_update(ldcp->portp->vhp); 65051991Sheppo } 65061991Sheppo } 65071991Sheppo 65081991Sheppo ldcp->wd_tid = timeout(vgen_ldc_watchdog, (caddr_t)ldcp, 65091991Sheppo drv_usectohz(vnet_ldcwd_interval * 1000)); 65101991Sheppo } 65111991Sheppo 65121991Sheppo /* handler for error messages received from the peer ldc end-point */ 65131991Sheppo static void 65141991Sheppo vgen_handle_errmsg(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 65151991Sheppo { 65161991Sheppo _NOTE(ARGUNUSED(ldcp, tagp)) 65171991Sheppo } 65181991Sheppo 65195935Ssb155480 static int 65205935Ssb155480 vgen_check_datamsg_seq(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 65215935Ssb155480 { 65225935Ssb155480 vio_raw_data_msg_t *rmsg; 65235935Ssb155480 vio_dring_msg_t *dmsg; 65245935Ssb155480 uint64_t seq_num; 65255935Ssb155480 vgen_t *vgenp = LDC_TO_VGEN(ldcp); 65265935Ssb155480 65275935Ssb155480 if (tagp->vio_subtype_env == VIO_DRING_DATA) { 65285935Ssb155480 dmsg = (vio_dring_msg_t *)tagp; 65295935Ssb155480 seq_num = dmsg->seq_num; 65305935Ssb155480 } else if (tagp->vio_subtype_env == VIO_PKT_DATA) { 65315935Ssb155480 rmsg = (vio_raw_data_msg_t *)tagp; 65325935Ssb155480 seq_num = rmsg->seq_num; 65335935Ssb155480 } else { 65345935Ssb155480 return (EINVAL); 65355935Ssb155480 } 65365935Ssb155480 65375935Ssb155480 if (seq_num != ldcp->next_rxseq) { 65385935Ssb155480 65395935Ssb155480 /* seqnums don't match */ 65405935Ssb155480 DWARN(vgenp, ldcp, 65415935Ssb155480 "next_rxseq(0x%lx) != seq_num(0x%lx)\n", 65425935Ssb155480 ldcp->next_rxseq, seq_num); 65435935Ssb155480 65445935Ssb155480 ldcp->need_ldc_reset = B_TRUE; 65455935Ssb155480 return (EINVAL); 65465935Ssb155480 65475935Ssb155480 } 65485935Ssb155480 65495935Ssb155480 ldcp->next_rxseq++; 65505935Ssb155480 65515935Ssb155480 return (0); 65525935Ssb155480 } 65535935Ssb155480 65541991Sheppo /* Check if the session id in the received message is valid */ 65551991Sheppo static int 65561991Sheppo vgen_check_sid(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 65571991Sheppo { 65584647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 65594647Sraghuram 65601991Sheppo if (tagp->vio_sid != ldcp->peer_sid) { 65614647Sraghuram DWARN(vgenp, ldcp, "sid mismatch: expected(%x), rcvd(%x)\n", 65624647Sraghuram ldcp->peer_sid, tagp->vio_sid); 65631991Sheppo return (VGEN_FAILURE); 65641991Sheppo } 65651991Sheppo else 65661991Sheppo return (VGEN_SUCCESS); 65671991Sheppo } 65681991Sheppo 65691991Sheppo static caddr_t 65701991Sheppo vgen_print_ethaddr(uint8_t *a, char *ebuf) 65711991Sheppo { 65721991Sheppo (void) sprintf(ebuf, 65734650Sraghuram "%x:%x:%x:%x:%x:%x", a[0], a[1], a[2], a[3], a[4], a[5]); 65741991Sheppo return (ebuf); 65751991Sheppo } 65761991Sheppo 65771991Sheppo /* Handshake watchdog timeout handler */ 65781991Sheppo static void 65791991Sheppo vgen_hwatchdog(void *arg) 65801991Sheppo { 65811991Sheppo vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 65824647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 65834647Sraghuram 65844647Sraghuram DWARN(vgenp, ldcp, 65854647Sraghuram "handshake timeout ldc(%lx) phase(%x) state(%x)\n", 65864647Sraghuram ldcp->hphase, ldcp->hstate); 65871991Sheppo 65881991Sheppo mutex_enter(&ldcp->cblock); 65893653Snarayan if (ldcp->cancel_htid) { 65903653Snarayan ldcp->cancel_htid = 0; 65913653Snarayan mutex_exit(&ldcp->cblock); 65923653Snarayan return; 65933653Snarayan } 65941991Sheppo ldcp->htid = 0; 65952841Snarayan ldcp->need_ldc_reset = B_TRUE; 65961991Sheppo vgen_handshake_retry(ldcp); 65971991Sheppo mutex_exit(&ldcp->cblock); 65981991Sheppo } 65991991Sheppo 66001991Sheppo static void 66011991Sheppo vgen_print_hparams(vgen_hparams_t *hp) 66021991Sheppo { 66031991Sheppo uint8_t addr[6]; 66041991Sheppo char ea[6]; 66051991Sheppo ldc_mem_cookie_t *dc; 66061991Sheppo 66071991Sheppo cmn_err(CE_CONT, "version_info:\n"); 66081991Sheppo cmn_err(CE_CONT, 66091991Sheppo "\tver_major: %d, ver_minor: %d, dev_class: %d\n", 66101991Sheppo hp->ver_major, hp->ver_minor, hp->dev_class); 66111991Sheppo 66125462Swentaoy vnet_macaddr_ultostr(hp->addr, addr); 66131991Sheppo cmn_err(CE_CONT, "attr_info:\n"); 66141991Sheppo cmn_err(CE_CONT, "\tMTU: %lx, addr: %s\n", hp->mtu, 66151991Sheppo vgen_print_ethaddr(addr, ea)); 66161991Sheppo cmn_err(CE_CONT, 66171991Sheppo "\taddr_type: %x, xfer_mode: %x, ack_freq: %x\n", 66181991Sheppo hp->addr_type, hp->xfer_mode, hp->ack_freq); 66191991Sheppo 66201991Sheppo dc = &hp->dring_cookie; 66211991Sheppo cmn_err(CE_CONT, "dring_info:\n"); 66221991Sheppo cmn_err(CE_CONT, 66231991Sheppo "\tlength: %d, dsize: %d\n", hp->num_desc, hp->desc_size); 66241991Sheppo cmn_err(CE_CONT, 66251991Sheppo "\tldc_addr: 0x%lx, ldc_size: %ld\n", 66261991Sheppo dc->addr, dc->size); 66271991Sheppo cmn_err(CE_CONT, "\tdring_ident: 0x%lx\n", hp->dring_ident); 66281991Sheppo } 66291991Sheppo 66301991Sheppo static void 66311991Sheppo vgen_print_ldcinfo(vgen_ldc_t *ldcp) 66321991Sheppo { 66331991Sheppo vgen_hparams_t *hp; 66341991Sheppo 66351991Sheppo cmn_err(CE_CONT, "Channel Information:\n"); 66361991Sheppo cmn_err(CE_CONT, 66371991Sheppo "\tldc_id: 0x%lx, ldc_status: 0x%x\n", 66381991Sheppo ldcp->ldc_id, ldcp->ldc_status); 66391991Sheppo cmn_err(CE_CONT, 66401991Sheppo "\tlocal_sid: 0x%x, peer_sid: 0x%x\n", 66411991Sheppo ldcp->local_sid, ldcp->peer_sid); 66421991Sheppo cmn_err(CE_CONT, 66431991Sheppo "\thphase: 0x%x, hstate: 0x%x\n", 66441991Sheppo ldcp->hphase, ldcp->hstate); 66451991Sheppo 66461991Sheppo cmn_err(CE_CONT, "Local handshake params:\n"); 66471991Sheppo hp = &ldcp->local_hparams; 66481991Sheppo vgen_print_hparams(hp); 66491991Sheppo 66501991Sheppo cmn_err(CE_CONT, "Peer handshake params:\n"); 66511991Sheppo hp = &ldcp->peer_hparams; 66521991Sheppo vgen_print_hparams(hp); 66531991Sheppo } 66544647Sraghuram 66554647Sraghuram /* 66565935Ssb155480 * Send received packets up the stack. 66574647Sraghuram */ 66584647Sraghuram static void 66595935Ssb155480 vgen_rx(vgen_ldc_t *ldcp, mblk_t *bp) 66604647Sraghuram { 66616495Sspeer vio_net_rx_cb_t vrx_cb = ldcp->portp->vcb.vio_net_rx_cb; 66624647Sraghuram 66634647Sraghuram if (ldcp->rcv_thread != NULL) { 66645935Ssb155480 ASSERT(MUTEX_HELD(&ldcp->rxlock)); 66655935Ssb155480 mutex_exit(&ldcp->rxlock); 66664647Sraghuram } else { 66675935Ssb155480 ASSERT(MUTEX_HELD(&ldcp->cblock)); 66685935Ssb155480 mutex_exit(&ldcp->cblock); 66695935Ssb155480 } 66705935Ssb155480 66716495Sspeer vrx_cb(ldcp->portp->vhp, bp); 66725935Ssb155480 66734647Sraghuram if (ldcp->rcv_thread != NULL) { 66745935Ssb155480 mutex_enter(&ldcp->rxlock); 66755935Ssb155480 } else { 66765935Ssb155480 mutex_enter(&ldcp->cblock); 66775935Ssb155480 } 66784647Sraghuram } 66794647Sraghuram 66804647Sraghuram /* 66814647Sraghuram * vgen_ldc_rcv_worker -- A per LDC worker thread to receive data. 66824647Sraghuram * This thread is woken up by the LDC interrupt handler to process 66834647Sraghuram * LDC packets and receive data. 66844647Sraghuram */ 66854647Sraghuram static void 66864647Sraghuram vgen_ldc_rcv_worker(void *arg) 66874647Sraghuram { 66884647Sraghuram callb_cpr_t cprinfo; 66894647Sraghuram vgen_ldc_t *ldcp = (vgen_ldc_t *)arg; 66904647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 66914647Sraghuram 66924647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 66934647Sraghuram CALLB_CPR_INIT(&cprinfo, &ldcp->rcv_thr_lock, callb_generic_cpr, 66944650Sraghuram "vnet_rcv_thread"); 66954647Sraghuram mutex_enter(&ldcp->rcv_thr_lock); 66964647Sraghuram while (!(ldcp->rcv_thr_flags & VGEN_WTHR_STOP)) { 66974647Sraghuram 66984647Sraghuram CALLB_CPR_SAFE_BEGIN(&cprinfo); 66994647Sraghuram /* 67004647Sraghuram * Wait until the data is received or a stop 67014647Sraghuram * request is received. 67024647Sraghuram */ 67034647Sraghuram while (!(ldcp->rcv_thr_flags & 67044647Sraghuram (VGEN_WTHR_DATARCVD | VGEN_WTHR_STOP))) { 67054647Sraghuram cv_wait(&ldcp->rcv_thr_cv, &ldcp->rcv_thr_lock); 67064647Sraghuram } 67074647Sraghuram CALLB_CPR_SAFE_END(&cprinfo, &ldcp->rcv_thr_lock) 67084647Sraghuram 67094647Sraghuram /* 67104647Sraghuram * First process the stop request. 67114647Sraghuram */ 67124647Sraghuram if (ldcp->rcv_thr_flags & VGEN_WTHR_STOP) { 67134647Sraghuram DBG2(vgenp, ldcp, "stopped\n"); 67144647Sraghuram break; 67154647Sraghuram } 67164647Sraghuram ldcp->rcv_thr_flags &= ~VGEN_WTHR_DATARCVD; 67178623SSriharsha.Basavapatna@Sun.COM ldcp->rcv_thr_flags |= VGEN_WTHR_PROCESSING; 67184647Sraghuram mutex_exit(&ldcp->rcv_thr_lock); 67194647Sraghuram DBG2(vgenp, ldcp, "calling vgen_handle_evt_read\n"); 67204647Sraghuram vgen_handle_evt_read(ldcp); 67214647Sraghuram mutex_enter(&ldcp->rcv_thr_lock); 67228623SSriharsha.Basavapatna@Sun.COM ldcp->rcv_thr_flags &= ~VGEN_WTHR_PROCESSING; 67234647Sraghuram } 67244647Sraghuram 67254647Sraghuram /* 67264647Sraghuram * Update the run status and wakeup the thread that 67274647Sraghuram * has sent the stop request. 67284647Sraghuram */ 67299217SWentao.Yang@Sun.COM ldcp->rcv_thr_flags &= ~VGEN_WTHR_STOP; 67309217SWentao.Yang@Sun.COM ldcp->rcv_thread = NULL; 67314647Sraghuram CALLB_CPR_EXIT(&cprinfo); 67329217SWentao.Yang@Sun.COM 67334647Sraghuram thread_exit(); 67344647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 67354647Sraghuram } 67364647Sraghuram 67374647Sraghuram /* vgen_stop_rcv_thread -- Co-ordinate with receive thread to stop it */ 67384647Sraghuram static void 67394647Sraghuram vgen_stop_rcv_thread(vgen_ldc_t *ldcp) 67404647Sraghuram { 67419217SWentao.Yang@Sun.COM kt_did_t tid = 0; 67424647Sraghuram vgen_t *vgenp = LDC_TO_VGEN(ldcp); 67434647Sraghuram 67444647Sraghuram DBG1(vgenp, ldcp, "enter\n"); 67454647Sraghuram /* 67464647Sraghuram * Send a stop request by setting the stop flag and 67474647Sraghuram * wait until the receive thread stops. 67484647Sraghuram */ 67494647Sraghuram mutex_enter(&ldcp->rcv_thr_lock); 67509217SWentao.Yang@Sun.COM if (ldcp->rcv_thread != NULL) { 67519217SWentao.Yang@Sun.COM tid = ldcp->rcv_thread->t_did; 67524647Sraghuram ldcp->rcv_thr_flags |= VGEN_WTHR_STOP; 67534647Sraghuram cv_signal(&ldcp->rcv_thr_cv); 67544647Sraghuram } 67554647Sraghuram mutex_exit(&ldcp->rcv_thr_lock); 67569217SWentao.Yang@Sun.COM 67579217SWentao.Yang@Sun.COM if (tid != 0) { 67589217SWentao.Yang@Sun.COM thread_join(tid); 67599217SWentao.Yang@Sun.COM } 67604647Sraghuram DBG1(vgenp, ldcp, "exit\n"); 67614647Sraghuram } 67624647Sraghuram 67636495Sspeer /* 67648623SSriharsha.Basavapatna@Sun.COM * Wait for the channel rx-queue to be drained by allowing the receive 67658623SSriharsha.Basavapatna@Sun.COM * worker thread to read all messages from the rx-queue of the channel. 67668623SSriharsha.Basavapatna@Sun.COM * Assumption: further callbacks are disabled at this time. 67678623SSriharsha.Basavapatna@Sun.COM */ 67688623SSriharsha.Basavapatna@Sun.COM static void 67698623SSriharsha.Basavapatna@Sun.COM vgen_drain_rcv_thread(vgen_ldc_t *ldcp) 67708623SSriharsha.Basavapatna@Sun.COM { 67718623SSriharsha.Basavapatna@Sun.COM clock_t tm; 67728623SSriharsha.Basavapatna@Sun.COM clock_t wt; 67738623SSriharsha.Basavapatna@Sun.COM clock_t rv; 67748623SSriharsha.Basavapatna@Sun.COM 67758623SSriharsha.Basavapatna@Sun.COM /* 67768623SSriharsha.Basavapatna@Sun.COM * If there is data in ldc rx queue, wait until the rx 67778623SSriharsha.Basavapatna@Sun.COM * worker thread runs and drains all msgs in the queue. 67788623SSriharsha.Basavapatna@Sun.COM */ 67798623SSriharsha.Basavapatna@Sun.COM wt = drv_usectohz(MILLISEC); 67808623SSriharsha.Basavapatna@Sun.COM 67818623SSriharsha.Basavapatna@Sun.COM mutex_enter(&ldcp->rcv_thr_lock); 67828623SSriharsha.Basavapatna@Sun.COM 67838623SSriharsha.Basavapatna@Sun.COM tm = ddi_get_lbolt() + wt; 67848623SSriharsha.Basavapatna@Sun.COM 67858623SSriharsha.Basavapatna@Sun.COM /* 67868623SSriharsha.Basavapatna@Sun.COM * We need to check both bits - DATARCVD and PROCESSING, to be cleared. 67878623SSriharsha.Basavapatna@Sun.COM * If DATARCVD is set, that means the callback has signalled the worker 67888623SSriharsha.Basavapatna@Sun.COM * thread, but the worker hasn't started processing yet. If PROCESSING 67898623SSriharsha.Basavapatna@Sun.COM * is set, that means the thread is awake and processing. Note that the 67908623SSriharsha.Basavapatna@Sun.COM * DATARCVD state can only be seen once, as the assumption is that 67918623SSriharsha.Basavapatna@Sun.COM * further callbacks have been disabled at this point. 67928623SSriharsha.Basavapatna@Sun.COM */ 67938623SSriharsha.Basavapatna@Sun.COM while (ldcp->rcv_thr_flags & 67948623SSriharsha.Basavapatna@Sun.COM (VGEN_WTHR_DATARCVD | VGEN_WTHR_PROCESSING)) { 67958623SSriharsha.Basavapatna@Sun.COM rv = cv_timedwait(&ldcp->rcv_thr_cv, &ldcp->rcv_thr_lock, tm); 67968623SSriharsha.Basavapatna@Sun.COM if (rv == -1) { /* timeout */ 67978623SSriharsha.Basavapatna@Sun.COM /* 67988623SSriharsha.Basavapatna@Sun.COM * Note that the only way we return is due to a timeout; 67998623SSriharsha.Basavapatna@Sun.COM * we set the new time to wait, before we go back and 68008623SSriharsha.Basavapatna@Sun.COM * check the condition. The other(unlikely) possibility 68018623SSriharsha.Basavapatna@Sun.COM * is a premature wakeup(see cv_timedwait(9F)) in which 68028623SSriharsha.Basavapatna@Sun.COM * case we just continue to use the same time to wait. 68038623SSriharsha.Basavapatna@Sun.COM */ 68048623SSriharsha.Basavapatna@Sun.COM tm = ddi_get_lbolt() + wt; 68058623SSriharsha.Basavapatna@Sun.COM } 68068623SSriharsha.Basavapatna@Sun.COM } 68078623SSriharsha.Basavapatna@Sun.COM 68088623SSriharsha.Basavapatna@Sun.COM mutex_exit(&ldcp->rcv_thr_lock); 68098623SSriharsha.Basavapatna@Sun.COM } 68108623SSriharsha.Basavapatna@Sun.COM 68118623SSriharsha.Basavapatna@Sun.COM /* 68126495Sspeer * vgen_dds_rx -- post DDS messages to vnet. 68136495Sspeer */ 68146495Sspeer static int 68156495Sspeer vgen_dds_rx(vgen_ldc_t *ldcp, vio_msg_tag_t *tagp) 68166495Sspeer { 68176495Sspeer vio_dds_msg_t *dmsg = (vio_dds_msg_t *)tagp; 68186495Sspeer vgen_t *vgenp = LDC_TO_VGEN(ldcp); 68196495Sspeer 68206495Sspeer if (dmsg->dds_class != DDS_VNET_NIU) { 68216495Sspeer DWARN(vgenp, ldcp, "Unknown DDS class, dropping"); 68226495Sspeer return (EBADMSG); 68236495Sspeer } 68246495Sspeer vnet_dds_rx(vgenp->vnetp, dmsg); 68256495Sspeer return (0); 68266495Sspeer } 68276495Sspeer 68286495Sspeer /* 68296495Sspeer * vgen_dds_tx -- an interface called by vnet to send DDS messages. 68306495Sspeer */ 68316495Sspeer int 68326495Sspeer vgen_dds_tx(void *arg, void *msg) 68336495Sspeer { 68346495Sspeer vgen_t *vgenp = arg; 68356495Sspeer vio_dds_msg_t *dmsg = msg; 68366495Sspeer vgen_portlist_t *plistp = &vgenp->vgenports; 68376495Sspeer vgen_ldc_t *ldcp; 68386495Sspeer vgen_ldclist_t *ldclp; 68396495Sspeer int rv = EIO; 68406495Sspeer 68416495Sspeer 68426495Sspeer READ_ENTER(&plistp->rwlock); 68436495Sspeer ldclp = &(vgenp->vsw_portp->ldclist); 68446495Sspeer READ_ENTER(&ldclp->rwlock); 68456495Sspeer ldcp = ldclp->headp; 68466495Sspeer if ((ldcp == NULL) || (ldcp->hphase != VH_DONE)) { 68476495Sspeer goto vgen_dsend_exit; 68486495Sspeer } 68496495Sspeer 68506495Sspeer dmsg->tag.vio_sid = ldcp->local_sid; 68516495Sspeer rv = vgen_sendmsg(ldcp, (caddr_t)dmsg, sizeof (vio_dds_msg_t), B_FALSE); 68526495Sspeer if (rv != VGEN_SUCCESS) { 68536495Sspeer rv = EIO; 68546495Sspeer } else { 68556495Sspeer rv = 0; 68566495Sspeer } 68576495Sspeer 68586495Sspeer vgen_dsend_exit: 68596495Sspeer RW_EXIT(&ldclp->rwlock); 68606495Sspeer RW_EXIT(&plistp->rwlock); 68616495Sspeer return (rv); 68626495Sspeer 68636495Sspeer } 68646495Sspeer 68654647Sraghuram #if DEBUG 68664647Sraghuram 68674647Sraghuram /* 68684647Sraghuram * Print debug messages - set to 0xf to enable all msgs 68694647Sraghuram */ 68704647Sraghuram static void 68714647Sraghuram debug_printf(const char *fname, vgen_t *vgenp, 68724647Sraghuram vgen_ldc_t *ldcp, const char *fmt, ...) 68734647Sraghuram { 68744647Sraghuram char buf[256]; 68754647Sraghuram char *bufp = buf; 68764647Sraghuram va_list ap; 68774647Sraghuram 68784647Sraghuram if ((vgenp != NULL) && (vgenp->vnetp != NULL)) { 68794647Sraghuram (void) sprintf(bufp, "vnet%d:", 68804650Sraghuram ((vnet_t *)(vgenp->vnetp))->instance); 68814647Sraghuram bufp += strlen(bufp); 68824647Sraghuram } 68834647Sraghuram if (ldcp != NULL) { 68844647Sraghuram (void) sprintf(bufp, "ldc(%ld):", ldcp->ldc_id); 68854647Sraghuram bufp += strlen(bufp); 68864647Sraghuram } 68874647Sraghuram (void) sprintf(bufp, "%s: ", fname); 68884647Sraghuram bufp += strlen(bufp); 68894647Sraghuram 68904647Sraghuram va_start(ap, fmt); 68914647Sraghuram (void) vsprintf(bufp, fmt, ap); 68924647Sraghuram va_end(ap); 68934647Sraghuram 68944647Sraghuram if ((ldcp == NULL) ||(vgendbg_ldcid == -1) || 68954647Sraghuram (vgendbg_ldcid == ldcp->ldc_id)) { 68964647Sraghuram cmn_err(CE_CONT, "%s\n", buf); 68974647Sraghuram } 68984647Sraghuram } 68994647Sraghuram #endif 6900