106db247cSraghuram /* 206db247cSraghuram * CDDL HEADER START 306db247cSraghuram * 406db247cSraghuram * The contents of this file are subject to the terms of the 506db247cSraghuram * Common Development and Distribution License (the "License"). 606db247cSraghuram * You may not use this file except in compliance with the License. 706db247cSraghuram * 806db247cSraghuram * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 906db247cSraghuram * or http://www.opensolaris.org/os/licensing. 1006db247cSraghuram * See the License for the specific language governing permissions 1106db247cSraghuram * and limitations under the License. 1206db247cSraghuram * 1306db247cSraghuram * When distributing Covered Code, include this CDDL HEADER in each 1406db247cSraghuram * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1506db247cSraghuram * If applicable, add the following below this CDDL HEADER, with the 1606db247cSraghuram * fields enclosed by brackets "[]" replaced with your own identifying 1706db247cSraghuram * information: Portions Copyright [yyyy] [name of copyright owner] 1806db247cSraghuram * 1906db247cSraghuram * CDDL HEADER END 2006db247cSraghuram */ 2106db247cSraghuram 2206db247cSraghuram /* 23a862df29SSriharsha Basavapatna * Copyright (c) 2007, 2010, Oracle and/or its affiliates. All rights reserved. 2406db247cSraghuram */ 2506db247cSraghuram 2606db247cSraghuram #include <sys/types.h> 2706db247cSraghuram #include <sys/errno.h> 2806db247cSraghuram #include <sys/debug.h> 2906db247cSraghuram #include <sys/time.h> 3006db247cSraghuram #include <sys/sysmacros.h> 3106db247cSraghuram #include <sys/systm.h> 3206db247cSraghuram #include <sys/user.h> 3306db247cSraghuram #include <sys/stropts.h> 3406db247cSraghuram #include <sys/stream.h> 3506db247cSraghuram #include <sys/strlog.h> 3606db247cSraghuram #include <sys/strsubr.h> 3706db247cSraghuram #include <sys/cmn_err.h> 3806db247cSraghuram #include <sys/cpu.h> 3906db247cSraghuram #include <sys/kmem.h> 4006db247cSraghuram #include <sys/conf.h> 4106db247cSraghuram #include <sys/ddi.h> 4206db247cSraghuram #include <sys/sunddi.h> 4306db247cSraghuram #include <sys/ksynch.h> 4406db247cSraghuram #include <sys/stat.h> 4506db247cSraghuram #include <sys/kstat.h> 4606db247cSraghuram #include <sys/vtrace.h> 4706db247cSraghuram #include <sys/strsun.h> 4806db247cSraghuram #include <sys/dlpi.h> 4906db247cSraghuram #include <sys/ethernet.h> 5006db247cSraghuram #include <net/if.h> 5106db247cSraghuram #include <sys/varargs.h> 5206db247cSraghuram #include <sys/machsystm.h> 5306db247cSraghuram #include <sys/modctl.h> 5406db247cSraghuram #include <sys/modhash.h> 5506db247cSraghuram #include <sys/mac.h> 5606db247cSraghuram #include <sys/mac_ether.h> 5706db247cSraghuram #include <sys/taskq.h> 5806db247cSraghuram #include <sys/note.h> 5906db247cSraghuram #include <sys/mach_descrip.h> 6006db247cSraghuram #include <sys/mdeg.h> 6106db247cSraghuram #include <sys/ldc.h> 6206db247cSraghuram #include <sys/vsw_fdb.h> 6306db247cSraghuram #include <sys/vsw.h> 6406db247cSraghuram #include <sys/vio_mailbox.h> 6506db247cSraghuram #include <sys/vnet_mailbox.h> 6606db247cSraghuram #include <sys/vnet_common.h> 6706db247cSraghuram #include <sys/vio_util.h> 6806db247cSraghuram #include <sys/sdt.h> 6906db247cSraghuram #include <sys/atomic.h> 7006db247cSraghuram #include <sys/callb.h> 71c1c61f44Ssb155480 #include <sys/vlan.h> 7206db247cSraghuram 7306db247cSraghuram /* Port add/deletion/etc routines */ 746f09f0feSWENTAO YANG static void vsw_port_delete(vsw_port_t *port); 7506db247cSraghuram static int vsw_ldc_attach(vsw_port_t *port, uint64_t ldc_id); 767bd3a2e2SSriharsha Basavapatna static void vsw_ldc_detach(vsw_ldc_t *ldcp); 7706db247cSraghuram static int vsw_ldc_init(vsw_ldc_t *ldcp); 786f09f0feSWENTAO YANG static void vsw_ldc_uninit(vsw_ldc_t *ldcp); 797bd3a2e2SSriharsha Basavapatna static void vsw_ldc_drain(vsw_ldc_t *ldcp); 806f09f0feSWENTAO YANG static void vsw_drain_port_taskq(vsw_port_t *port); 8106db247cSraghuram static void vsw_marker_task(void *); 8206db247cSraghuram static int vsw_plist_del_node(vsw_t *, vsw_port_t *port); 836f09f0feSWENTAO YANG void vsw_detach_ports(vsw_t *vswp); 8406db247cSraghuram int vsw_port_add(vsw_t *vswp, md_t *mdp, mde_cookie_t *node); 8506db247cSraghuram mcst_addr_t *vsw_del_addr(uint8_t devtype, void *arg, uint64_t addr); 8606db247cSraghuram int vsw_port_detach(vsw_t *vswp, int p_instance); 87da14cebeSEric Cheng int vsw_portsend(vsw_port_t *port, mblk_t *mp); 88c1c61f44Ssb155480 int vsw_port_attach(vsw_port_t *portp); 8906db247cSraghuram vsw_port_t *vsw_lookup_port(vsw_t *vswp, int p_instance); 90c1c61f44Ssb155480 void vsw_vlan_unaware_port_reset(vsw_port_t *portp); 91cdfc78adSraghuram void vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate); 927b1f684aSSriharsha Basavapatna void vsw_reset_ports(vsw_t *vswp); 937b1f684aSSriharsha Basavapatna void vsw_port_reset(vsw_port_t *portp); 941107ea93SSriharsha Basavapatna void vsw_physlink_update_ports(vsw_t *vswp); 951107ea93SSriharsha Basavapatna static void vsw_port_physlink_update(vsw_port_t *portp); 9606db247cSraghuram 9706db247cSraghuram /* Interrupt routines */ 9806db247cSraghuram static uint_t vsw_ldc_cb(uint64_t cb, caddr_t arg); 9906db247cSraghuram 10006db247cSraghuram /* Handshake routines */ 10106db247cSraghuram static void vsw_ldc_reinit(vsw_ldc_t *); 10206db247cSraghuram static void vsw_conn_task(void *); 10306db247cSraghuram static int vsw_check_flag(vsw_ldc_t *, int, uint64_t); 10406db247cSraghuram static void vsw_next_milestone(vsw_ldc_t *); 10506db247cSraghuram static int vsw_supported_version(vio_ver_msg_t *); 106f0ca1d9aSsb155480 static void vsw_set_vnet_proto_ops(vsw_ldc_t *ldcp); 107f0ca1d9aSsb155480 static void vsw_reset_vnet_proto_ops(vsw_ldc_t *ldcp); 1087bd3a2e2SSriharsha Basavapatna void vsw_process_conn_evt(vsw_ldc_t *, uint16_t); 10906db247cSraghuram 11006db247cSraghuram /* Data processing routines */ 1117bd3a2e2SSriharsha Basavapatna void vsw_process_pkt(void *); 1127bd3a2e2SSriharsha Basavapatna static void vsw_dispatch_ctrl_task(vsw_ldc_t *, void *, vio_msg_tag_t *, int); 11306db247cSraghuram static void vsw_process_ctrl_pkt(void *); 11406db247cSraghuram static void vsw_process_ctrl_ver_pkt(vsw_ldc_t *, void *); 11506db247cSraghuram static void vsw_process_ctrl_attr_pkt(vsw_ldc_t *, void *); 11606db247cSraghuram static void vsw_process_ctrl_mcst_pkt(vsw_ldc_t *, void *); 11706db247cSraghuram static void vsw_process_ctrl_dring_reg_pkt(vsw_ldc_t *, void *); 11806db247cSraghuram static void vsw_process_ctrl_dring_unreg_pkt(vsw_ldc_t *, void *); 11906db247cSraghuram static void vsw_process_ctrl_rdx_pkt(vsw_ldc_t *, void *); 1201107ea93SSriharsha Basavapatna static void vsw_process_physlink_msg(vsw_ldc_t *, void *); 121f0ca1d9aSsb155480 static void vsw_process_data_pkt(vsw_ldc_t *, void *, vio_msg_tag_t *, 122f0ca1d9aSsb155480 uint32_t); 123f0ca1d9aSsb155480 static void vsw_process_pkt_data_nop(void *, void *, uint32_t); 124f0ca1d9aSsb155480 static void vsw_process_pkt_data(void *, void *, uint32_t); 12506db247cSraghuram static void vsw_process_data_ibnd_pkt(vsw_ldc_t *, void *); 126f0ca1d9aSsb155480 static void vsw_process_err_pkt(vsw_ldc_t *, void *, vio_msg_tag_t *); 1277bd3a2e2SSriharsha Basavapatna static void vsw_process_evt_read(vsw_ldc_t *ldcp); 1287bd3a2e2SSriharsha Basavapatna static void vsw_ldc_rcv(vsw_ldc_t *ldcp); 12906db247cSraghuram 13006db247cSraghuram /* Switching/data transmit routines */ 13106db247cSraghuram static int vsw_descrsend(vsw_ldc_t *, mblk_t *); 132f0ca1d9aSsb155480 static void vsw_ldcsend_pkt(vsw_ldc_t *ldcp, mblk_t *mp); 133f0ca1d9aSsb155480 static int vsw_ldcsend(vsw_ldc_t *ldcp, mblk_t *mp, uint32_t retries); 134f0ca1d9aSsb155480 static int vsw_ldctx_pri(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count); 135f0ca1d9aSsb155480 static int vsw_ldctx(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count); 13606db247cSraghuram 13706db247cSraghuram /* Packet creation routines */ 13806db247cSraghuram static void vsw_send_ver(void *); 13906db247cSraghuram static void vsw_send_attr(vsw_ldc_t *); 14006db247cSraghuram static void vsw_send_dring_info(vsw_ldc_t *); 14106db247cSraghuram static void vsw_send_rdx(vsw_ldc_t *); 1421107ea93SSriharsha Basavapatna static void vsw_send_physlink_msg(vsw_ldc_t *ldcp, link_state_t plink_state); 14306db247cSraghuram 14406db247cSraghuram /* Dring routines */ 14506db247cSraghuram static void vsw_create_privring(vsw_ldc_t *); 1467bd3a2e2SSriharsha Basavapatna static dring_info_t *vsw_map_dring(vsw_ldc_t *ldcp, void *pkt); 1477bd3a2e2SSriharsha Basavapatna static void vsw_unmap_dring(vsw_ldc_t *ldcp); 1487bd3a2e2SSriharsha Basavapatna static void vsw_destroy_dring(vsw_ldc_t *ldcp); 1497bd3a2e2SSriharsha Basavapatna static void vsw_free_lane_resources(vsw_ldc_t *, uint64_t); 1507bd3a2e2SSriharsha Basavapatna static int vsw_map_data(vsw_ldc_t *ldcp, dring_info_t *dp, void *pkt); 15106db247cSraghuram static void vsw_set_lane_attr(vsw_t *, lane_t *); 1527bd3a2e2SSriharsha Basavapatna dring_info_t *vsw_map_dring_cmn(vsw_ldc_t *ldcp, 1537bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *dring_pkt); 154*34f94fbcSWENTAO YANG static int vsw_mapin_avail(vsw_ldc_t *ldcp); 15506db247cSraghuram 1567bd3a2e2SSriharsha Basavapatna /* tx/msg/rcv thread routines */ 15706db247cSraghuram static void vsw_stop_tx_thread(vsw_ldc_t *ldcp); 15806db247cSraghuram static void vsw_ldc_tx_worker(void *arg); 15906db247cSraghuram 16006db247cSraghuram /* Misc support routines */ 16106db247cSraghuram static void vsw_save_lmacaddr(vsw_t *vswp, uint64_t macaddr); 16206db247cSraghuram static int vsw_get_same_dest_list(struct ether_header *ehp, 16306db247cSraghuram mblk_t **rhead, mblk_t **rtail, mblk_t **mpp); 16406db247cSraghuram static mblk_t *vsw_dupmsgchain(mblk_t *mp); 16506db247cSraghuram 16606db247cSraghuram /* Debugging routines */ 16706db247cSraghuram static void dump_flags(uint64_t); 16806db247cSraghuram static void display_state(void); 16906db247cSraghuram static void display_lane(lane_t *); 17006db247cSraghuram static void display_ring(dring_info_t *); 17106db247cSraghuram 17206db247cSraghuram /* 17306db247cSraghuram * Functions imported from other files. 17406db247cSraghuram */ 17506db247cSraghuram extern int vsw_set_hw(vsw_t *, vsw_port_t *, int); 176da14cebeSEric Cheng extern void vsw_unset_hw(vsw_t *, vsw_port_t *, int); 17706db247cSraghuram extern int vsw_add_rem_mcst(vnet_mcast_msg_t *mcst_pkt, vsw_port_t *port); 17806db247cSraghuram extern void vsw_del_mcst_port(vsw_port_t *port); 17906db247cSraghuram extern int vsw_add_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg); 18006db247cSraghuram extern int vsw_del_mcst(vsw_t *vswp, uint8_t devtype, uint64_t addr, void *arg); 181c1c61f44Ssb155480 extern void vsw_fdbe_add(vsw_t *vswp, void *port); 182c1c61f44Ssb155480 extern void vsw_fdbe_del(vsw_t *vswp, struct ether_addr *eaddr); 183c1c61f44Ssb155480 extern void vsw_create_vlans(void *arg, int type); 184c1c61f44Ssb155480 extern void vsw_destroy_vlans(void *arg, int type); 185c1c61f44Ssb155480 extern void vsw_vlan_add_ids(void *arg, int type); 186c1c61f44Ssb155480 extern void vsw_vlan_remove_ids(void *arg, int type); 187c1c61f44Ssb155480 extern boolean_t vsw_frame_lookup_vid(void *arg, int caller, 188c1c61f44Ssb155480 struct ether_header *ehp, uint16_t *vidp); 189c1c61f44Ssb155480 extern mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp); 190c1c61f44Ssb155480 extern uint32_t vsw_vlan_frame_untag(void *arg, int type, mblk_t **np, 191c1c61f44Ssb155480 mblk_t **npt); 192c1c61f44Ssb155480 extern boolean_t vsw_vlan_lookup(mod_hash_t *vlan_hashp, uint16_t vid); 193678453a8Sspeer extern void vsw_hio_start(vsw_t *vswp, vsw_ldc_t *ldcp); 194678453a8Sspeer extern void vsw_hio_stop(vsw_t *vswp, vsw_ldc_t *ldcp); 195678453a8Sspeer extern void vsw_process_dds_msg(vsw_t *vswp, vsw_ldc_t *ldcp, void *msg); 196678453a8Sspeer extern void vsw_hio_stop_port(vsw_port_t *portp); 197da14cebeSEric Cheng extern void vsw_publish_macaddr(vsw_t *vswp, vsw_port_t *portp); 198da14cebeSEric Cheng extern int vsw_mac_client_init(vsw_t *vswp, vsw_port_t *port, int type); 199da14cebeSEric Cheng extern void vsw_mac_client_cleanup(vsw_t *vswp, vsw_port_t *port, int type); 20034b64c01SWENTAO YANG extern void vsw_destroy_rxpools(void *arg); 2017bd3a2e2SSriharsha Basavapatna extern void vsw_stop_msg_thread(vsw_ldc_t *ldcp); 2027bd3a2e2SSriharsha Basavapatna extern int vsw_send_msg(vsw_ldc_t *, void *, int, boolean_t); 2037bd3a2e2SSriharsha Basavapatna extern int vsw_dringsend(vsw_ldc_t *, mblk_t *); 2047bd3a2e2SSriharsha Basavapatna extern int vsw_reclaim_dring(dring_info_t *dp, int start); 2057bd3a2e2SSriharsha Basavapatna extern int vsw_dring_find_free_desc(dring_info_t *, vsw_private_desc_t **, 2067bd3a2e2SSriharsha Basavapatna int *); 2077bd3a2e2SSriharsha Basavapatna extern vio_dring_reg_msg_t *vsw_create_tx_dring_info(vsw_ldc_t *); 2087bd3a2e2SSriharsha Basavapatna extern int vsw_setup_tx_dring(vsw_ldc_t *ldcp, dring_info_t *dp); 2097bd3a2e2SSriharsha Basavapatna extern void vsw_destroy_tx_dring(vsw_ldc_t *ldcp); 2107bd3a2e2SSriharsha Basavapatna extern dring_info_t *vsw_map_rx_dring(vsw_ldc_t *ldcp, void *pkt); 2117bd3a2e2SSriharsha Basavapatna extern void vsw_unmap_rx_dring(vsw_ldc_t *ldcp); 2127bd3a2e2SSriharsha Basavapatna extern void vsw_ldc_msg_worker(void *arg); 2137bd3a2e2SSriharsha Basavapatna extern void vsw_process_dringdata(void *, void *); 2147bd3a2e2SSriharsha Basavapatna extern vio_dring_reg_msg_t *vsw_create_rx_dring_info(vsw_ldc_t *); 2157bd3a2e2SSriharsha Basavapatna extern void vsw_destroy_rx_dring(vsw_ldc_t *ldcp); 2167bd3a2e2SSriharsha Basavapatna extern dring_info_t *vsw_map_tx_dring(vsw_ldc_t *ldcp, void *pkt); 2177bd3a2e2SSriharsha Basavapatna extern void vsw_unmap_tx_dring(vsw_ldc_t *ldcp); 2187bd3a2e2SSriharsha Basavapatna extern void vsw_ldc_rcv_worker(void *arg); 2197bd3a2e2SSriharsha Basavapatna extern void vsw_stop_rcv_thread(vsw_ldc_t *ldcp); 2207bd3a2e2SSriharsha Basavapatna extern int vsw_dringsend_shm(vsw_ldc_t *, mblk_t *); 2217bd3a2e2SSriharsha Basavapatna extern void vsw_process_dringdata_shm(void *, void *); 22206db247cSraghuram 22306db247cSraghuram /* 22406db247cSraghuram * Tunables used in this file. 22506db247cSraghuram */ 22606db247cSraghuram extern int vsw_num_handshakes; 22706db247cSraghuram extern int vsw_ldc_tx_delay; 22806db247cSraghuram extern int vsw_ldc_tx_retries; 2296f09f0feSWENTAO YANG extern int vsw_ldc_retries; 2306f09f0feSWENTAO YANG extern int vsw_ldc_delay; 23106db247cSraghuram extern boolean_t vsw_ldc_rxthr_enabled; 23206db247cSraghuram extern boolean_t vsw_ldc_txthr_enabled; 2337bd3a2e2SSriharsha Basavapatna extern uint32_t vsw_num_descriptors; 2347bd3a2e2SSriharsha Basavapatna extern uint8_t vsw_dring_mode; 235f0ca1d9aSsb155480 extern uint32_t vsw_max_tx_qcount; 236f0ca1d9aSsb155480 extern boolean_t vsw_obp_ver_proto_workaround; 23751aa9d07Ssb155480 extern uint32_t vsw_publish_macaddr_count; 238*34f94fbcSWENTAO YANG extern uint32_t vsw_nrbufs_factor; 23906db247cSraghuram 24006db247cSraghuram #define LDC_ENTER_LOCK(ldcp) \ 24106db247cSraghuram mutex_enter(&((ldcp)->ldc_cblock));\ 24206db247cSraghuram mutex_enter(&((ldcp)->ldc_rxlock));\ 24306db247cSraghuram mutex_enter(&((ldcp)->ldc_txlock)); 24406db247cSraghuram #define LDC_EXIT_LOCK(ldcp) \ 24506db247cSraghuram mutex_exit(&((ldcp)->ldc_txlock));\ 24606db247cSraghuram mutex_exit(&((ldcp)->ldc_rxlock));\ 24706db247cSraghuram mutex_exit(&((ldcp)->ldc_cblock)); 24806db247cSraghuram 249f0ca1d9aSsb155480 #define VSW_VER_EQ(ldcp, major, minor) \ 250f0ca1d9aSsb155480 ((ldcp)->lane_out.ver_major == (major) && \ 251f0ca1d9aSsb155480 (ldcp)->lane_out.ver_minor == (minor)) 252f0ca1d9aSsb155480 253f0ca1d9aSsb155480 #define VSW_VER_LT(ldcp, major, minor) \ 254f0ca1d9aSsb155480 (((ldcp)->lane_out.ver_major < (major)) || \ 255f0ca1d9aSsb155480 ((ldcp)->lane_out.ver_major == (major) && \ 256f0ca1d9aSsb155480 (ldcp)->lane_out.ver_minor < (minor))) 25706db247cSraghuram 258c1c61f44Ssb155480 #define VSW_VER_GTEQ(ldcp, major, minor) \ 259c1c61f44Ssb155480 (((ldcp)->lane_out.ver_major > (major)) || \ 260c1c61f44Ssb155480 ((ldcp)->lane_out.ver_major == (major) && \ 261c1c61f44Ssb155480 (ldcp)->lane_out.ver_minor >= (minor))) 262c1c61f44Ssb155480 2637bd3a2e2SSriharsha Basavapatna #define VSW_VER_LTEQ(ldcp, major, minor) \ 2647bd3a2e2SSriharsha Basavapatna (((ldcp)->lane_out.ver_major < (major)) || \ 2657bd3a2e2SSriharsha Basavapatna ((ldcp)->lane_out.ver_major == (major) && \ 2667bd3a2e2SSriharsha Basavapatna (ldcp)->lane_out.ver_minor <= (minor))) 2677bd3a2e2SSriharsha Basavapatna 2681107ea93SSriharsha Basavapatna /* 2691107ea93SSriharsha Basavapatna * VIO Protocol Version Info: 2701107ea93SSriharsha Basavapatna * 2711107ea93SSriharsha Basavapatna * The version specified below represents the version of protocol currently 2721107ea93SSriharsha Basavapatna * supported in the driver. It means the driver can negotiate with peers with 2731107ea93SSriharsha Basavapatna * versions <= this version. Here is a summary of the feature(s) that are 2741107ea93SSriharsha Basavapatna * supported at each version of the protocol: 2751107ea93SSriharsha Basavapatna * 2761107ea93SSriharsha Basavapatna * 1.0 Basic VIO protocol. 2771107ea93SSriharsha Basavapatna * 1.1 vDisk protocol update (no virtual network update). 2781107ea93SSriharsha Basavapatna * 1.2 Support for priority frames (priority-ether-types). 2791107ea93SSriharsha Basavapatna * 1.3 VLAN and HybridIO support. 2801107ea93SSriharsha Basavapatna * 1.4 Jumbo Frame support. 2811107ea93SSriharsha Basavapatna * 1.5 Link State Notification support with optional support 2821107ea93SSriharsha Basavapatna * for Physical Link information. 2837bd3a2e2SSriharsha Basavapatna * 1.6 Support for RxDringData mode. 2841107ea93SSriharsha Basavapatna */ 2857bd3a2e2SSriharsha Basavapatna static ver_sup_t vsw_versions[] = { {1, 6} }; 28606db247cSraghuram 28706db247cSraghuram /* 28806db247cSraghuram * For the moment the state dump routines have their own 28906db247cSraghuram * private flag. 29006db247cSraghuram */ 29106db247cSraghuram #define DUMP_STATE 0 29206db247cSraghuram 29306db247cSraghuram #if DUMP_STATE 29406db247cSraghuram 29506db247cSraghuram #define DUMP_TAG(tag) \ 29606db247cSraghuram { \ 29706db247cSraghuram D1(NULL, "DUMP_TAG: type 0x%llx", (tag).vio_msgtype); \ 29806db247cSraghuram D1(NULL, "DUMP_TAG: stype 0x%llx", (tag).vio_subtype); \ 29906db247cSraghuram D1(NULL, "DUMP_TAG: senv 0x%llx", (tag).vio_subtype_env); \ 30006db247cSraghuram } 30106db247cSraghuram 30206db247cSraghuram #define DUMP_TAG_PTR(tag) \ 30306db247cSraghuram { \ 30406db247cSraghuram D1(NULL, "DUMP_TAG: type 0x%llx", (tag)->vio_msgtype); \ 30506db247cSraghuram D1(NULL, "DUMP_TAG: stype 0x%llx", (tag)->vio_subtype); \ 30606db247cSraghuram D1(NULL, "DUMP_TAG: senv 0x%llx", (tag)->vio_subtype_env); \ 30706db247cSraghuram } 30806db247cSraghuram 30906db247cSraghuram #define DUMP_FLAGS(flags) dump_flags(flags); 31006db247cSraghuram #define DISPLAY_STATE() display_state() 31106db247cSraghuram 31206db247cSraghuram #else 31306db247cSraghuram 31406db247cSraghuram #define DUMP_TAG(tag) 31506db247cSraghuram #define DUMP_TAG_PTR(tag) 31606db247cSraghuram #define DUMP_FLAGS(state) 31706db247cSraghuram #define DISPLAY_STATE() 31806db247cSraghuram 31906db247cSraghuram #endif /* DUMP_STATE */ 32006db247cSraghuram 32106db247cSraghuram /* 32206db247cSraghuram * Attach the specified port. 32306db247cSraghuram * 32406db247cSraghuram * Returns 0 on success, 1 on failure. 32506db247cSraghuram */ 32606db247cSraghuram int 327c1c61f44Ssb155480 vsw_port_attach(vsw_port_t *port) 32806db247cSraghuram { 329c1c61f44Ssb155480 vsw_t *vswp = port->p_vswp; 33006db247cSraghuram vsw_port_list_t *plist = &vswp->plist; 331c1c61f44Ssb155480 vsw_port_t *p, **pp; 332c1c61f44Ssb155480 int nids = port->num_ldcs; 333c1c61f44Ssb155480 uint64_t *ldcids; 334da14cebeSEric Cheng int rv; 33506db247cSraghuram 336c1c61f44Ssb155480 D1(vswp, "%s: enter : port %d", __func__, port->p_instance); 33706db247cSraghuram 33806db247cSraghuram /* port already exists? */ 33906db247cSraghuram READ_ENTER(&plist->lockrw); 340c1c61f44Ssb155480 for (p = plist->head; p != NULL; p = p->p_next) { 341c1c61f44Ssb155480 if (p->p_instance == port->p_instance) { 34206db247cSraghuram DWARN(vswp, "%s: port instance %d already attached", 343c1c61f44Ssb155480 __func__, p->p_instance); 34406db247cSraghuram RW_EXIT(&plist->lockrw); 34506db247cSraghuram return (1); 34606db247cSraghuram } 34706db247cSraghuram } 34806db247cSraghuram RW_EXIT(&plist->lockrw); 34906db247cSraghuram 35006db247cSraghuram mutex_init(&port->tx_lock, NULL, MUTEX_DRIVER, NULL); 35106db247cSraghuram mutex_init(&port->mca_lock, NULL, MUTEX_DRIVER, NULL); 352da14cebeSEric Cheng rw_init(&port->maccl_rwlock, NULL, RW_DRIVER, NULL); 35306db247cSraghuram 35406db247cSraghuram mutex_init(&port->state_lock, NULL, MUTEX_DRIVER, NULL); 35506db247cSraghuram cv_init(&port->state_cv, NULL, CV_DRIVER, NULL); 35606db247cSraghuram port->state = VSW_PORT_INIT; 35706db247cSraghuram 35806db247cSraghuram D2(vswp, "%s: %d nids", __func__, nids); 359c1c61f44Ssb155480 ldcids = port->ldc_ids; 3607bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: ldcid (%llx)", __func__, (uint64_t)ldcids[0]); 3617bd3a2e2SSriharsha Basavapatna if (vsw_ldc_attach(port, (uint64_t)ldcids[0]) != 0) { 36206db247cSraghuram DERR(vswp, "%s: ldc_attach failed", __func__); 363da14cebeSEric Cheng goto exit_error; 36406db247cSraghuram } 36506db247cSraghuram 36606db247cSraghuram if (vswp->switching_setup_done == B_TRUE) { 36706db247cSraghuram /* 368da14cebeSEric Cheng * If the underlying network device has been setup, 369da14cebeSEric Cheng * then open a mac client and porgram the mac address 370da14cebeSEric Cheng * for this port. 37106db247cSraghuram */ 372da14cebeSEric Cheng rv = vsw_mac_client_init(vswp, port, VSW_VNETPORT); 373da14cebeSEric Cheng if (rv != 0) { 374da14cebeSEric Cheng goto exit_error; 375da14cebeSEric Cheng } 37606db247cSraghuram } 37706db247cSraghuram 378c1c61f44Ssb155480 /* create the fdb entry for this port/mac address */ 379c1c61f44Ssb155480 vsw_fdbe_add(vswp, port); 380c1c61f44Ssb155480 381c1c61f44Ssb155480 vsw_create_vlans(port, VSW_VNETPORT); 382c1c61f44Ssb155480 38306db247cSraghuram WRITE_ENTER(&plist->lockrw); 38406db247cSraghuram 38506db247cSraghuram /* link it into the list of ports for this vsw instance */ 386c1c61f44Ssb155480 pp = (vsw_port_t **)(&plist->head); 387c1c61f44Ssb155480 port->p_next = *pp; 388c1c61f44Ssb155480 *pp = port; 38906db247cSraghuram plist->num_ports++; 39006db247cSraghuram 39106db247cSraghuram RW_EXIT(&plist->lockrw); 39206db247cSraghuram 39306db247cSraghuram /* 39406db247cSraghuram * Initialise the port and any ldc's under it. 39506db247cSraghuram */ 3967bd3a2e2SSriharsha Basavapatna (void) vsw_ldc_init(port->ldcp); 39706db247cSraghuram 39851aa9d07Ssb155480 /* announce macaddr of vnet to the physical switch */ 39951aa9d07Ssb155480 if (vsw_publish_macaddr_count != 0) { /* enabled */ 400da14cebeSEric Cheng vsw_publish_macaddr(vswp, port); 40151aa9d07Ssb155480 } 40251aa9d07Ssb155480 40306db247cSraghuram D1(vswp, "%s: exit", __func__); 40406db247cSraghuram return (0); 405da14cebeSEric Cheng 406da14cebeSEric Cheng exit_error: 407da14cebeSEric Cheng 408da14cebeSEric Cheng cv_destroy(&port->state_cv); 409da14cebeSEric Cheng mutex_destroy(&port->state_lock); 410da14cebeSEric Cheng 411da14cebeSEric Cheng rw_destroy(&port->maccl_rwlock); 412da14cebeSEric Cheng mutex_destroy(&port->tx_lock); 413da14cebeSEric Cheng mutex_destroy(&port->mca_lock); 414da14cebeSEric Cheng kmem_free(port, sizeof (vsw_port_t)); 415da14cebeSEric Cheng return (1); 41606db247cSraghuram } 41706db247cSraghuram 41806db247cSraghuram /* 41906db247cSraghuram * Detach the specified port. 42006db247cSraghuram * 42106db247cSraghuram * Returns 0 on success, 1 on failure. 42206db247cSraghuram */ 42306db247cSraghuram int 42406db247cSraghuram vsw_port_detach(vsw_t *vswp, int p_instance) 42506db247cSraghuram { 42606db247cSraghuram vsw_port_t *port = NULL; 42706db247cSraghuram vsw_port_list_t *plist = &vswp->plist; 42806db247cSraghuram 42906db247cSraghuram D1(vswp, "%s: enter: port id %d", __func__, p_instance); 43006db247cSraghuram 43106db247cSraghuram WRITE_ENTER(&plist->lockrw); 43206db247cSraghuram 43306db247cSraghuram if ((port = vsw_lookup_port(vswp, p_instance)) == NULL) { 43406db247cSraghuram RW_EXIT(&plist->lockrw); 43506db247cSraghuram return (1); 43606db247cSraghuram } 43706db247cSraghuram 43806db247cSraghuram if (vsw_plist_del_node(vswp, port)) { 43906db247cSraghuram RW_EXIT(&plist->lockrw); 44006db247cSraghuram return (1); 44106db247cSraghuram } 44206db247cSraghuram 443678453a8Sspeer /* cleanup any HybridIO for this port */ 444678453a8Sspeer vsw_hio_stop_port(port); 445678453a8Sspeer 44606db247cSraghuram /* 44706db247cSraghuram * No longer need to hold writer lock on port list now 44806db247cSraghuram * that we have unlinked the target port from the list. 44906db247cSraghuram */ 45006db247cSraghuram RW_EXIT(&plist->lockrw); 45106db247cSraghuram 452da14cebeSEric Cheng /* Cleanup and close the mac client */ 453da14cebeSEric Cheng vsw_mac_client_cleanup(vswp, port, VSW_VNETPORT); 454da14cebeSEric Cheng 455c1c61f44Ssb155480 /* Remove the fdb entry for this port/mac address */ 456c1c61f44Ssb155480 vsw_fdbe_del(vswp, &(port->p_macaddr)); 457c1c61f44Ssb155480 vsw_destroy_vlans(port, VSW_VNETPORT); 458c1c61f44Ssb155480 459c1c61f44Ssb155480 /* Remove any multicast addresses.. */ 460c1c61f44Ssb155480 vsw_del_mcst_port(port); 461c1c61f44Ssb155480 4626f09f0feSWENTAO YANG vsw_port_delete(port); 46306db247cSraghuram 46406db247cSraghuram D1(vswp, "%s: exit: p_instance(%d)", __func__, p_instance); 46506db247cSraghuram return (0); 46606db247cSraghuram } 46706db247cSraghuram 46806db247cSraghuram /* 46906db247cSraghuram * Detach all active ports. 47006db247cSraghuram */ 4716f09f0feSWENTAO YANG void 47206db247cSraghuram vsw_detach_ports(vsw_t *vswp) 47306db247cSraghuram { 47406db247cSraghuram vsw_port_list_t *plist = &vswp->plist; 47506db247cSraghuram vsw_port_t *port = NULL; 47606db247cSraghuram 47706db247cSraghuram D1(vswp, "%s: enter", __func__); 47806db247cSraghuram 47906db247cSraghuram WRITE_ENTER(&plist->lockrw); 48006db247cSraghuram 48106db247cSraghuram while ((port = plist->head) != NULL) { 4826f09f0feSWENTAO YANG (void) vsw_plist_del_node(vswp, port); 4836f09f0feSWENTAO YANG 4846f09f0feSWENTAO YANG /* cleanup any HybridIO for this port */ 4856f09f0feSWENTAO YANG vsw_hio_stop_port(port); 48606db247cSraghuram 487da14cebeSEric Cheng /* Cleanup and close the mac client */ 488da14cebeSEric Cheng vsw_mac_client_cleanup(vswp, port, VSW_VNETPORT); 48906db247cSraghuram 49006db247cSraghuram /* Remove the fdb entry for this port/mac address */ 491c1c61f44Ssb155480 vsw_fdbe_del(vswp, &(port->p_macaddr)); 492c1c61f44Ssb155480 vsw_destroy_vlans(port, VSW_VNETPORT); 49306db247cSraghuram 49406db247cSraghuram /* Remove any multicast addresses.. */ 49506db247cSraghuram vsw_del_mcst_port(port); 49606db247cSraghuram 49706db247cSraghuram /* 49806db247cSraghuram * No longer need to hold the lock on the port list 49906db247cSraghuram * now that we have unlinked the target port from the 50006db247cSraghuram * list. 50106db247cSraghuram */ 50206db247cSraghuram RW_EXIT(&plist->lockrw); 5036f09f0feSWENTAO YANG vsw_port_delete(port); 50406db247cSraghuram WRITE_ENTER(&plist->lockrw); 50506db247cSraghuram } 50606db247cSraghuram RW_EXIT(&plist->lockrw); 50706db247cSraghuram 50806db247cSraghuram D1(vswp, "%s: exit", __func__); 50906db247cSraghuram } 51006db247cSraghuram 51106db247cSraghuram /* 51206db247cSraghuram * Delete the specified port. 51306db247cSraghuram */ 5146f09f0feSWENTAO YANG static void 51506db247cSraghuram vsw_port_delete(vsw_port_t *port) 51606db247cSraghuram { 51706db247cSraghuram vsw_t *vswp = port->p_vswp; 51806db247cSraghuram 51906db247cSraghuram D1(vswp, "%s: enter : port id %d", __func__, port->p_instance); 52006db247cSraghuram 5217bd3a2e2SSriharsha Basavapatna vsw_ldc_uninit(port->ldcp); 52206db247cSraghuram 52306db247cSraghuram /* 52406db247cSraghuram * Wait for any pending ctrl msg tasks which reference this 52506db247cSraghuram * port to finish. 52606db247cSraghuram */ 5276f09f0feSWENTAO YANG vsw_drain_port_taskq(port); 52806db247cSraghuram 52906db247cSraghuram /* 53006db247cSraghuram * Wait for any active callbacks to finish 53106db247cSraghuram */ 5327bd3a2e2SSriharsha Basavapatna vsw_ldc_drain(port->ldcp); 53306db247cSraghuram 5347bd3a2e2SSriharsha Basavapatna vsw_ldc_detach(port->ldcp); 53506db247cSraghuram 536da14cebeSEric Cheng rw_destroy(&port->maccl_rwlock); 53706db247cSraghuram mutex_destroy(&port->mca_lock); 53806db247cSraghuram mutex_destroy(&port->tx_lock); 539c1c61f44Ssb155480 54006db247cSraghuram cv_destroy(&port->state_cv); 54106db247cSraghuram mutex_destroy(&port->state_lock); 54206db247cSraghuram 543c1c61f44Ssb155480 if (port->num_ldcs != 0) { 544c1c61f44Ssb155480 kmem_free(port->ldc_ids, port->num_ldcs * sizeof (uint64_t)); 545c1c61f44Ssb155480 port->num_ldcs = 0; 546c1c61f44Ssb155480 } 547da14cebeSEric Cheng 548da14cebeSEric Cheng if (port->nvids != 0) { 549da14cebeSEric Cheng kmem_free(port->vids, sizeof (vsw_vlanid_t) * port->nvids); 550da14cebeSEric Cheng } 551da14cebeSEric Cheng 55206db247cSraghuram kmem_free(port, sizeof (vsw_port_t)); 55306db247cSraghuram 55406db247cSraghuram D1(vswp, "%s: exit", __func__); 55506db247cSraghuram } 55606db247cSraghuram 55706db247cSraghuram /* 55806db247cSraghuram * Attach a logical domain channel (ldc) under a specified port. 55906db247cSraghuram * 56006db247cSraghuram * Returns 0 on success, 1 on failure. 56106db247cSraghuram */ 56206db247cSraghuram static int 56306db247cSraghuram vsw_ldc_attach(vsw_port_t *port, uint64_t ldc_id) 56406db247cSraghuram { 56506db247cSraghuram vsw_t *vswp = port->p_vswp; 56606db247cSraghuram vsw_ldc_t *ldcp = NULL; 56706db247cSraghuram ldc_attr_t attr; 56806db247cSraghuram ldc_status_t istatus; 56906db247cSraghuram int status = DDI_FAILURE; 57006db247cSraghuram char kname[MAXNAMELEN]; 5717b1f684aSSriharsha Basavapatna enum { PROG_init = 0x0, 5727bd3a2e2SSriharsha Basavapatna PROG_callback = 0x1, 5737bd3a2e2SSriharsha Basavapatna PROG_tx_thread = 0x2} 57406db247cSraghuram progress; 57506db247cSraghuram 57606db247cSraghuram progress = PROG_init; 57706db247cSraghuram 57806db247cSraghuram D1(vswp, "%s: enter", __func__); 57906db247cSraghuram 58006db247cSraghuram ldcp = kmem_zalloc(sizeof (vsw_ldc_t), KM_NOSLEEP); 58106db247cSraghuram if (ldcp == NULL) { 58206db247cSraghuram DERR(vswp, "%s: kmem_zalloc failed", __func__); 58306db247cSraghuram return (1); 58406db247cSraghuram } 58506db247cSraghuram ldcp->ldc_id = ldc_id; 58606db247cSraghuram 58706db247cSraghuram mutex_init(&ldcp->ldc_txlock, NULL, MUTEX_DRIVER, NULL); 58806db247cSraghuram mutex_init(&ldcp->ldc_rxlock, NULL, MUTEX_DRIVER, NULL); 58906db247cSraghuram mutex_init(&ldcp->ldc_cblock, NULL, MUTEX_DRIVER, NULL); 5907bd3a2e2SSriharsha Basavapatna ldcp->msg_thr_flags = 0; 5917bd3a2e2SSriharsha Basavapatna mutex_init(&ldcp->msg_thr_lock, NULL, MUTEX_DRIVER, NULL); 5927bd3a2e2SSriharsha Basavapatna cv_init(&ldcp->msg_thr_cv, NULL, CV_DRIVER, NULL); 5937bd3a2e2SSriharsha Basavapatna ldcp->rcv_thr_flags = 0; 5947bd3a2e2SSriharsha Basavapatna mutex_init(&ldcp->rcv_thr_lock, NULL, MUTEX_DRIVER, NULL); 5957bd3a2e2SSriharsha Basavapatna cv_init(&ldcp->rcv_thr_cv, NULL, CV_DRIVER, NULL); 59606db247cSraghuram mutex_init(&ldcp->drain_cv_lock, NULL, MUTEX_DRIVER, NULL); 59706db247cSraghuram cv_init(&ldcp->drain_cv, NULL, CV_DRIVER, NULL); 59806db247cSraghuram 59906db247cSraghuram /* required for handshake with peer */ 60006db247cSraghuram ldcp->local_session = (uint64_t)ddi_get_lbolt(); 60106db247cSraghuram ldcp->peer_session = 0; 60206db247cSraghuram ldcp->session_status = 0; 60306db247cSraghuram ldcp->hss_id = 1; /* Initial handshake session id */ 6047bd3a2e2SSriharsha Basavapatna ldcp->hphase = VSW_MILESTONE0; 60506db247cSraghuram 606678453a8Sspeer (void) atomic_swap_32(&port->p_hio_capable, B_FALSE); 607678453a8Sspeer 60806db247cSraghuram /* only set for outbound lane, inbound set by peer */ 60906db247cSraghuram vsw_set_lane_attr(vswp, &ldcp->lane_out); 61006db247cSraghuram 61106db247cSraghuram attr.devclass = LDC_DEV_NT_SVC; 61206db247cSraghuram attr.instance = ddi_get_instance(vswp->dip); 61306db247cSraghuram attr.mode = LDC_MODE_UNRELIABLE; 61406db247cSraghuram attr.mtu = VSW_LDC_MTU; 61506db247cSraghuram status = ldc_init(ldc_id, &attr, &ldcp->ldc_handle); 61606db247cSraghuram if (status != 0) { 61706db247cSraghuram DERR(vswp, "%s(%lld): ldc_init failed, rv (%d)", 61806db247cSraghuram __func__, ldc_id, status); 61906db247cSraghuram goto ldc_attach_fail; 62006db247cSraghuram } 62106db247cSraghuram 62206db247cSraghuram if (vsw_ldc_txthr_enabled) { 62306db247cSraghuram ldcp->tx_thr_flags = 0; 62406db247cSraghuram ldcp->tx_mhead = ldcp->tx_mtail = NULL; 62506db247cSraghuram 62606db247cSraghuram mutex_init(&ldcp->tx_thr_lock, NULL, MUTEX_DRIVER, NULL); 62706db247cSraghuram cv_init(&ldcp->tx_thr_cv, NULL, CV_DRIVER, NULL); 62806db247cSraghuram ldcp->tx_thread = thread_create(NULL, 2 * DEFAULTSTKSZ, 62906db247cSraghuram vsw_ldc_tx_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri); 63006db247cSraghuram 63106db247cSraghuram progress |= PROG_tx_thread; 63206db247cSraghuram if (ldcp->tx_thread == NULL) { 63306db247cSraghuram DWARN(vswp, "%s(%lld): Failed to create worker thread", 63406db247cSraghuram __func__, ldc_id); 63506db247cSraghuram goto ldc_attach_fail; 63606db247cSraghuram } 63706db247cSraghuram } 63806db247cSraghuram 63906db247cSraghuram status = ldc_reg_callback(ldcp->ldc_handle, vsw_ldc_cb, (caddr_t)ldcp); 64006db247cSraghuram if (status != 0) { 64106db247cSraghuram DERR(vswp, "%s(%lld): ldc_reg_callback failed, rv (%d)", 64206db247cSraghuram __func__, ldc_id, status); 64306db247cSraghuram (void) ldc_fini(ldcp->ldc_handle); 64406db247cSraghuram goto ldc_attach_fail; 64506db247cSraghuram } 646f0ca1d9aSsb155480 /* 647f0ca1d9aSsb155480 * allocate a message for ldc_read()s, big enough to hold ctrl and 648f0ca1d9aSsb155480 * data msgs, including raw data msgs used to recv priority frames. 649f0ca1d9aSsb155480 */ 650c1c61f44Ssb155480 ldcp->msglen = VIO_PKT_DATA_HDRSIZE + vswp->max_frame_size; 651f0ca1d9aSsb155480 ldcp->ldcmsg = kmem_alloc(ldcp->msglen, KM_SLEEP); 65206db247cSraghuram 65306db247cSraghuram progress |= PROG_callback; 65406db247cSraghuram 65506db247cSraghuram mutex_init(&ldcp->status_lock, NULL, MUTEX_DRIVER, NULL); 65606db247cSraghuram 65706db247cSraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 65806db247cSraghuram DERR(vswp, "%s: ldc_status failed", __func__); 65906db247cSraghuram mutex_destroy(&ldcp->status_lock); 66006db247cSraghuram goto ldc_attach_fail; 66106db247cSraghuram } 66206db247cSraghuram 66306db247cSraghuram ldcp->ldc_status = istatus; 66406db247cSraghuram ldcp->ldc_port = port; 66506db247cSraghuram ldcp->ldc_vswp = vswp; 66606db247cSraghuram 667f0ca1d9aSsb155480 vsw_reset_vnet_proto_ops(ldcp); 668f0ca1d9aSsb155480 66906db247cSraghuram (void) sprintf(kname, "%sldc0x%lx", DRV_NAME, ldcp->ldc_id); 67006db247cSraghuram ldcp->ksp = vgen_setup_kstats(DRV_NAME, vswp->instance, 67106db247cSraghuram kname, &ldcp->ldc_stats); 67206db247cSraghuram if (ldcp->ksp == NULL) { 67306db247cSraghuram DERR(vswp, "%s: kstats setup failed", __func__); 67406db247cSraghuram goto ldc_attach_fail; 67506db247cSraghuram } 67606db247cSraghuram 6777bd3a2e2SSriharsha Basavapatna /* link it into this port */ 6787bd3a2e2SSriharsha Basavapatna port->ldcp = ldcp; 67906db247cSraghuram 68006db247cSraghuram D1(vswp, "%s: exit", __func__); 68106db247cSraghuram return (0); 68206db247cSraghuram 68306db247cSraghuram ldc_attach_fail: 68406db247cSraghuram 68506db247cSraghuram if (progress & PROG_callback) { 68606db247cSraghuram (void) ldc_unreg_callback(ldcp->ldc_handle); 687f0ca1d9aSsb155480 kmem_free(ldcp->ldcmsg, ldcp->msglen); 68806db247cSraghuram } 68906db247cSraghuram 69006db247cSraghuram if (progress & PROG_tx_thread) { 69106db247cSraghuram if (ldcp->tx_thread != NULL) { 69206db247cSraghuram vsw_stop_tx_thread(ldcp); 69306db247cSraghuram } 69406db247cSraghuram mutex_destroy(&ldcp->tx_thr_lock); 69506db247cSraghuram cv_destroy(&ldcp->tx_thr_cv); 69606db247cSraghuram } 69706db247cSraghuram if (ldcp->ksp != NULL) { 69806db247cSraghuram vgen_destroy_kstats(ldcp->ksp); 69906db247cSraghuram } 7007bd3a2e2SSriharsha Basavapatna mutex_destroy(&ldcp->msg_thr_lock); 7017bd3a2e2SSriharsha Basavapatna mutex_destroy(&ldcp->rcv_thr_lock); 70206db247cSraghuram mutex_destroy(&ldcp->ldc_txlock); 70306db247cSraghuram mutex_destroy(&ldcp->ldc_rxlock); 70406db247cSraghuram mutex_destroy(&ldcp->ldc_cblock); 70506db247cSraghuram mutex_destroy(&ldcp->drain_cv_lock); 7067bd3a2e2SSriharsha Basavapatna cv_destroy(&ldcp->msg_thr_cv); 7077bd3a2e2SSriharsha Basavapatna cv_destroy(&ldcp->rcv_thr_cv); 70806db247cSraghuram cv_destroy(&ldcp->drain_cv); 70906db247cSraghuram 71006db247cSraghuram kmem_free(ldcp, sizeof (vsw_ldc_t)); 71106db247cSraghuram 71206db247cSraghuram return (1); 71306db247cSraghuram } 71406db247cSraghuram 71506db247cSraghuram /* 71606db247cSraghuram * Detach a logical domain channel (ldc) belonging to a 71706db247cSraghuram * particular port. 71806db247cSraghuram */ 7196f09f0feSWENTAO YANG static void 7207bd3a2e2SSriharsha Basavapatna vsw_ldc_detach(vsw_ldc_t *ldcp) 72106db247cSraghuram { 72206db247cSraghuram int rv; 7237bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_port->p_vswp; 7246f09f0feSWENTAO YANG int retries = 0; 72506db247cSraghuram 72606db247cSraghuram D2(vswp, "%s: detaching channel %lld", __func__, ldcp->ldc_id); 72706db247cSraghuram 7287bd3a2e2SSriharsha Basavapatna /* Stop msg/rcv thread */ 7297bd3a2e2SSriharsha Basavapatna if (ldcp->rcv_thread != NULL) { 7307bd3a2e2SSriharsha Basavapatna vsw_stop_rcv_thread(ldcp); 7317bd3a2e2SSriharsha Basavapatna } else if (ldcp->msg_thread != NULL) { 7327bd3a2e2SSriharsha Basavapatna vsw_stop_msg_thread(ldcp); 73306db247cSraghuram } 734f0ca1d9aSsb155480 kmem_free(ldcp->ldcmsg, ldcp->msglen); 73506db247cSraghuram 73606db247cSraghuram /* Stop the tx thread */ 73706db247cSraghuram if (ldcp->tx_thread != NULL) { 73806db247cSraghuram vsw_stop_tx_thread(ldcp); 73906db247cSraghuram mutex_destroy(&ldcp->tx_thr_lock); 74006db247cSraghuram cv_destroy(&ldcp->tx_thr_cv); 74106db247cSraghuram if (ldcp->tx_mhead != NULL) { 74206db247cSraghuram freemsgchain(ldcp->tx_mhead); 74306db247cSraghuram ldcp->tx_mhead = ldcp->tx_mtail = NULL; 744f0ca1d9aSsb155480 ldcp->tx_cnt = 0; 74506db247cSraghuram } 74606db247cSraghuram } 74706db247cSraghuram 74806db247cSraghuram /* Destory kstats */ 74906db247cSraghuram vgen_destroy_kstats(ldcp->ksp); 75006db247cSraghuram 75106db247cSraghuram /* 75206db247cSraghuram * Before we can close the channel we must release any mapped 75306db247cSraghuram * resources (e.g. drings). 75406db247cSraghuram */ 75506db247cSraghuram vsw_free_lane_resources(ldcp, INBOUND); 75606db247cSraghuram vsw_free_lane_resources(ldcp, OUTBOUND); 75706db247cSraghuram 75806db247cSraghuram /* 7596f09f0feSWENTAO YANG * Close the channel, retry on EAAGIN. 76006db247cSraghuram */ 7616f09f0feSWENTAO YANG while ((rv = ldc_close(ldcp->ldc_handle)) == EAGAIN) { 7626f09f0feSWENTAO YANG if (++retries > vsw_ldc_retries) { 7636f09f0feSWENTAO YANG break; 7646f09f0feSWENTAO YANG } 7656f09f0feSWENTAO YANG drv_usecwait(vsw_ldc_delay); 7666f09f0feSWENTAO YANG } 7676f09f0feSWENTAO YANG if (rv != 0) { 7686f09f0feSWENTAO YANG cmn_err(CE_NOTE, 7696f09f0feSWENTAO YANG "!vsw%d: Error(%d) closing the channel(0x%lx)\n", 7706f09f0feSWENTAO YANG vswp->instance, rv, ldcp->ldc_id); 77106db247cSraghuram } 77206db247cSraghuram 77306db247cSraghuram (void) ldc_fini(ldcp->ldc_handle); 77406db247cSraghuram 77506db247cSraghuram ldcp->ldc_status = LDC_INIT; 77606db247cSraghuram ldcp->ldc_handle = NULL; 77706db247cSraghuram ldcp->ldc_vswp = NULL; 77806db247cSraghuram 7797bd3a2e2SSriharsha Basavapatna mutex_destroy(&ldcp->msg_thr_lock); 7807bd3a2e2SSriharsha Basavapatna mutex_destroy(&ldcp->rcv_thr_lock); 78106db247cSraghuram mutex_destroy(&ldcp->ldc_txlock); 78206db247cSraghuram mutex_destroy(&ldcp->ldc_rxlock); 78306db247cSraghuram mutex_destroy(&ldcp->ldc_cblock); 78406db247cSraghuram mutex_destroy(&ldcp->drain_cv_lock); 78506db247cSraghuram mutex_destroy(&ldcp->status_lock); 7867bd3a2e2SSriharsha Basavapatna cv_destroy(&ldcp->msg_thr_cv); 7877bd3a2e2SSriharsha Basavapatna cv_destroy(&ldcp->rcv_thr_cv); 7887bd3a2e2SSriharsha Basavapatna cv_destroy(&ldcp->drain_cv); 78906db247cSraghuram 79006db247cSraghuram kmem_free(ldcp, sizeof (vsw_ldc_t)); 79106db247cSraghuram } 79206db247cSraghuram 79306db247cSraghuram /* 79406db247cSraghuram * Open and attempt to bring up the channel. Note that channel 79506db247cSraghuram * can only be brought up if peer has also opened channel. 79606db247cSraghuram * 79706db247cSraghuram * Returns 0 if can open and bring up channel, otherwise 79806db247cSraghuram * returns 1. 79906db247cSraghuram */ 80006db247cSraghuram static int 80106db247cSraghuram vsw_ldc_init(vsw_ldc_t *ldcp) 80206db247cSraghuram { 80306db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 80406db247cSraghuram ldc_status_t istatus = 0; 80506db247cSraghuram int rv; 80606db247cSraghuram 80706db247cSraghuram D1(vswp, "%s: enter", __func__); 80806db247cSraghuram 80906db247cSraghuram LDC_ENTER_LOCK(ldcp); 81006db247cSraghuram 81106db247cSraghuram /* don't start at 0 in case clients don't like that */ 81206db247cSraghuram ldcp->next_ident = 1; 81306db247cSraghuram 81406db247cSraghuram rv = ldc_open(ldcp->ldc_handle); 81506db247cSraghuram if (rv != 0) { 81606db247cSraghuram DERR(vswp, "%s: ldc_open failed: id(%lld) rv(%d)", 81706db247cSraghuram __func__, ldcp->ldc_id, rv); 81806db247cSraghuram LDC_EXIT_LOCK(ldcp); 81906db247cSraghuram return (1); 82006db247cSraghuram } 82106db247cSraghuram 82206db247cSraghuram if (ldc_status(ldcp->ldc_handle, &istatus) != 0) { 82306db247cSraghuram DERR(vswp, "%s: unable to get status", __func__); 82406db247cSraghuram LDC_EXIT_LOCK(ldcp); 82506db247cSraghuram return (1); 82606db247cSraghuram 82706db247cSraghuram } else if (istatus != LDC_OPEN && istatus != LDC_READY) { 82806db247cSraghuram DERR(vswp, "%s: id (%lld) status(%d) is not OPEN/READY", 82906db247cSraghuram __func__, ldcp->ldc_id, istatus); 83006db247cSraghuram LDC_EXIT_LOCK(ldcp); 83106db247cSraghuram return (1); 83206db247cSraghuram } 83306db247cSraghuram 83406db247cSraghuram mutex_enter(&ldcp->status_lock); 83506db247cSraghuram ldcp->ldc_status = istatus; 83606db247cSraghuram mutex_exit(&ldcp->status_lock); 83706db247cSraghuram 83806db247cSraghuram rv = ldc_up(ldcp->ldc_handle); 83906db247cSraghuram if (rv != 0) { 84006db247cSraghuram /* 84106db247cSraghuram * Not a fatal error for ldc_up() to fail, as peer 84206db247cSraghuram * end point may simply not be ready yet. 84306db247cSraghuram */ 84406db247cSraghuram D2(vswp, "%s: ldc_up err id(%lld) rv(%d)", __func__, 84506db247cSraghuram ldcp->ldc_id, rv); 84606db247cSraghuram LDC_EXIT_LOCK(ldcp); 84706db247cSraghuram return (1); 84806db247cSraghuram } 84906db247cSraghuram 85006db247cSraghuram /* 85106db247cSraghuram * ldc_up() call is non-blocking so need to explicitly 85206db247cSraghuram * check channel status to see if in fact the channel 85306db247cSraghuram * is UP. 85406db247cSraghuram */ 85506db247cSraghuram mutex_enter(&ldcp->status_lock); 85606db247cSraghuram if (ldc_status(ldcp->ldc_handle, &ldcp->ldc_status) != 0) { 85706db247cSraghuram DERR(vswp, "%s: unable to get status", __func__); 85806db247cSraghuram mutex_exit(&ldcp->status_lock); 85906db247cSraghuram LDC_EXIT_LOCK(ldcp); 86006db247cSraghuram return (1); 86106db247cSraghuram 86206db247cSraghuram } 86306db247cSraghuram 86406db247cSraghuram if (ldcp->ldc_status == LDC_UP) { 86506db247cSraghuram D2(vswp, "%s: channel %ld now UP (%ld)", __func__, 86606db247cSraghuram ldcp->ldc_id, istatus); 86706db247cSraghuram mutex_exit(&ldcp->status_lock); 86806db247cSraghuram LDC_EXIT_LOCK(ldcp); 86906db247cSraghuram 87006db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_UP); 87106db247cSraghuram return (0); 87206db247cSraghuram } 87306db247cSraghuram 87406db247cSraghuram mutex_exit(&ldcp->status_lock); 87506db247cSraghuram LDC_EXIT_LOCK(ldcp); 87606db247cSraghuram 87706db247cSraghuram D1(vswp, "%s: exit", __func__); 87806db247cSraghuram return (0); 87906db247cSraghuram } 88006db247cSraghuram 88106db247cSraghuram /* disable callbacks on the channel */ 8826f09f0feSWENTAO YANG static void 88306db247cSraghuram vsw_ldc_uninit(vsw_ldc_t *ldcp) 88406db247cSraghuram { 88506db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 88606db247cSraghuram int rv; 88706db247cSraghuram 88806db247cSraghuram D1(vswp, "vsw_ldc_uninit: enter: id(%lx)\n", ldcp->ldc_id); 88906db247cSraghuram 89006db247cSraghuram LDC_ENTER_LOCK(ldcp); 89106db247cSraghuram 89206db247cSraghuram rv = ldc_set_cb_mode(ldcp->ldc_handle, LDC_CB_DISABLE); 89306db247cSraghuram if (rv != 0) { 8946f09f0feSWENTAO YANG cmn_err(CE_NOTE, "!vsw_ldc_uninit(%ld): error disabling " 89506db247cSraghuram "interrupts (rv = %d)\n", ldcp->ldc_id, rv); 89606db247cSraghuram } 89706db247cSraghuram 89806db247cSraghuram mutex_enter(&ldcp->status_lock); 89906db247cSraghuram ldcp->ldc_status = LDC_INIT; 90006db247cSraghuram mutex_exit(&ldcp->status_lock); 90106db247cSraghuram 90206db247cSraghuram LDC_EXIT_LOCK(ldcp); 90306db247cSraghuram 90406db247cSraghuram D1(vswp, "vsw_ldc_uninit: exit: id(%lx)", ldcp->ldc_id); 90506db247cSraghuram } 90606db247cSraghuram 90706db247cSraghuram /* 90806db247cSraghuram * Wait until the callback(s) associated with the ldcs under the specified 90906db247cSraghuram * port have completed. 91006db247cSraghuram * 91106db247cSraghuram * Prior to this function being invoked each channel under this port 91206db247cSraghuram * should have been quiesced via ldc_set_cb_mode(DISABLE). 91306db247cSraghuram * 91406db247cSraghuram * A short explaination of what we are doing below.. 91506db247cSraghuram * 91606db247cSraghuram * The simplest approach would be to have a reference counter in 91706db247cSraghuram * the ldc structure which is increment/decremented by the callbacks as 91806db247cSraghuram * they use the channel. The drain function could then simply disable any 91906db247cSraghuram * further callbacks and do a cv_wait for the ref to hit zero. Unfortunately 92006db247cSraghuram * there is a tiny window here - before the callback is able to get the lock 92106db247cSraghuram * on the channel it is interrupted and this function gets to execute. It 92206db247cSraghuram * sees that the ref count is zero and believes its free to delete the 92306db247cSraghuram * associated data structures. 92406db247cSraghuram * 92506db247cSraghuram * We get around this by taking advantage of the fact that before the ldc 92606db247cSraghuram * framework invokes a callback it sets a flag to indicate that there is a 92706db247cSraghuram * callback active (or about to become active). If when we attempt to 92806db247cSraghuram * unregister a callback when this active flag is set then the unregister 92906db247cSraghuram * will fail with EWOULDBLOCK. 93006db247cSraghuram * 93106db247cSraghuram * If the unregister fails we do a cv_timedwait. We will either be signaled 93206db247cSraghuram * by the callback as it is exiting (note we have to wait a short period to 93306db247cSraghuram * allow the callback to return fully to the ldc framework and it to clear 93406db247cSraghuram * the active flag), or by the timer expiring. In either case we again attempt 93506db247cSraghuram * the unregister. We repeat this until we can succesfully unregister the 93606db247cSraghuram * callback. 93706db247cSraghuram * 93806db247cSraghuram * The reason we use a cv_timedwait rather than a simple cv_wait is to catch 93906db247cSraghuram * the case where the callback has finished but the ldc framework has not yet 94006db247cSraghuram * cleared the active flag. In this case we would never get a cv_signal. 94106db247cSraghuram */ 9426f09f0feSWENTAO YANG static void 9437bd3a2e2SSriharsha Basavapatna vsw_ldc_drain(vsw_ldc_t *ldcp) 94406db247cSraghuram { 9457bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_port->p_vswp; 94606db247cSraghuram 94706db247cSraghuram D1(vswp, "%s: enter", __func__); 94806db247cSraghuram 94906db247cSraghuram /* 95006db247cSraghuram * If we can unregister the channel callback then we 95106db247cSraghuram * know that there is no callback either running or 95206db247cSraghuram * scheduled to run for this channel so move on to next 95306db247cSraghuram * channel in the list. 95406db247cSraghuram */ 95506db247cSraghuram mutex_enter(&ldcp->drain_cv_lock); 95606db247cSraghuram 95706db247cSraghuram /* prompt active callbacks to quit */ 95806db247cSraghuram ldcp->drain_state = VSW_LDC_DRAINING; 95906db247cSraghuram 96006db247cSraghuram if ((ldc_unreg_callback(ldcp->ldc_handle)) == 0) { 96106db247cSraghuram D2(vswp, "%s: unreg callback for chan %ld", __func__, 96206db247cSraghuram ldcp->ldc_id); 96306db247cSraghuram mutex_exit(&ldcp->drain_cv_lock); 96406db247cSraghuram } else { 96506db247cSraghuram /* 96606db247cSraghuram * If we end up here we know that either 1) a callback 96706db247cSraghuram * is currently executing, 2) is about to start (i.e. 96806db247cSraghuram * the ldc framework has set the active flag but 96906db247cSraghuram * has not actually invoked the callback yet, or 3) 97006db247cSraghuram * has finished and has returned to the ldc framework 97106db247cSraghuram * but the ldc framework has not yet cleared the 97206db247cSraghuram * active bit. 97306db247cSraghuram * 97406db247cSraghuram * Wait for it to finish. 97506db247cSraghuram */ 9767bd3a2e2SSriharsha Basavapatna while (ldc_unreg_callback(ldcp->ldc_handle) == EWOULDBLOCK) { 9777bd3a2e2SSriharsha Basavapatna (void) cv_timedwait(&ldcp->drain_cv, 9787bd3a2e2SSriharsha Basavapatna &ldcp->drain_cv_lock, ddi_get_lbolt() + hz); 9797bd3a2e2SSriharsha Basavapatna } 98006db247cSraghuram 98106db247cSraghuram mutex_exit(&ldcp->drain_cv_lock); 98206db247cSraghuram D2(vswp, "%s: unreg callback for chan %ld after " 98306db247cSraghuram "timeout", __func__, ldcp->ldc_id); 98406db247cSraghuram } 98506db247cSraghuram 98606db247cSraghuram D1(vswp, "%s: exit", __func__); 98706db247cSraghuram } 98806db247cSraghuram 98906db247cSraghuram /* 99006db247cSraghuram * Wait until all tasks which reference this port have completed. 99106db247cSraghuram * 99206db247cSraghuram * Prior to this function being invoked each channel under this port 99306db247cSraghuram * should have been quiesced via ldc_set_cb_mode(DISABLE). 99406db247cSraghuram */ 9956f09f0feSWENTAO YANG static void 99606db247cSraghuram vsw_drain_port_taskq(vsw_port_t *port) 99706db247cSraghuram { 99806db247cSraghuram vsw_t *vswp = port->p_vswp; 99906db247cSraghuram 100006db247cSraghuram D1(vswp, "%s: enter", __func__); 100106db247cSraghuram 100206db247cSraghuram /* 100306db247cSraghuram * Mark the port as in the process of being detached, and 100406db247cSraghuram * dispatch a marker task to the queue so we know when all 100506db247cSraghuram * relevant tasks have completed. 100606db247cSraghuram */ 100706db247cSraghuram mutex_enter(&port->state_lock); 100806db247cSraghuram port->state = VSW_PORT_DETACHING; 100906db247cSraghuram 101006db247cSraghuram if ((vswp->taskq_p == NULL) || 101106db247cSraghuram (ddi_taskq_dispatch(vswp->taskq_p, vsw_marker_task, 101206db247cSraghuram port, DDI_NOSLEEP) != DDI_SUCCESS)) { 10136f09f0feSWENTAO YANG cmn_err(CE_NOTE, "!vsw%d: unable to dispatch marker task", 10146f09f0feSWENTAO YANG vswp->instance); 101506db247cSraghuram mutex_exit(&port->state_lock); 10166f09f0feSWENTAO YANG return; 101706db247cSraghuram } 101806db247cSraghuram 101906db247cSraghuram /* 102006db247cSraghuram * Wait for the marker task to finish. 102106db247cSraghuram */ 102206db247cSraghuram while (port->state != VSW_PORT_DETACHABLE) 102306db247cSraghuram cv_wait(&port->state_cv, &port->state_lock); 102406db247cSraghuram 102506db247cSraghuram mutex_exit(&port->state_lock); 102606db247cSraghuram 102706db247cSraghuram D1(vswp, "%s: exit", __func__); 102806db247cSraghuram } 102906db247cSraghuram 103006db247cSraghuram static void 103106db247cSraghuram vsw_marker_task(void *arg) 103206db247cSraghuram { 103306db247cSraghuram vsw_port_t *port = arg; 103406db247cSraghuram vsw_t *vswp = port->p_vswp; 103506db247cSraghuram 103606db247cSraghuram D1(vswp, "%s: enter", __func__); 103706db247cSraghuram 103806db247cSraghuram mutex_enter(&port->state_lock); 103906db247cSraghuram 104006db247cSraghuram /* 104106db247cSraghuram * No further tasks should be dispatched which reference 104206db247cSraghuram * this port so ok to mark it as safe to detach. 104306db247cSraghuram */ 104406db247cSraghuram port->state = VSW_PORT_DETACHABLE; 104506db247cSraghuram 104606db247cSraghuram cv_signal(&port->state_cv); 104706db247cSraghuram 104806db247cSraghuram mutex_exit(&port->state_lock); 104906db247cSraghuram 105006db247cSraghuram D1(vswp, "%s: exit", __func__); 105106db247cSraghuram } 105206db247cSraghuram 105306db247cSraghuram vsw_port_t * 105406db247cSraghuram vsw_lookup_port(vsw_t *vswp, int p_instance) 105506db247cSraghuram { 105606db247cSraghuram vsw_port_list_t *plist = &vswp->plist; 105706db247cSraghuram vsw_port_t *port; 105806db247cSraghuram 105906db247cSraghuram for (port = plist->head; port != NULL; port = port->p_next) { 106006db247cSraghuram if (port->p_instance == p_instance) { 106106db247cSraghuram D2(vswp, "vsw_lookup_port: found p_instance\n"); 106206db247cSraghuram return (port); 106306db247cSraghuram } 106406db247cSraghuram } 106506db247cSraghuram 106606db247cSraghuram return (NULL); 106706db247cSraghuram } 106806db247cSraghuram 1069c1c61f44Ssb155480 void 1070c1c61f44Ssb155480 vsw_vlan_unaware_port_reset(vsw_port_t *portp) 1071c1c61f44Ssb155480 { 10727bd3a2e2SSriharsha Basavapatna vsw_ldc_t *ldcp = portp->ldcp; 1073c1c61f44Ssb155480 1074c1c61f44Ssb155480 mutex_enter(&ldcp->ldc_cblock); 1075c1c61f44Ssb155480 1076c1c61f44Ssb155480 /* 1077c1c61f44Ssb155480 * If the peer is vlan_unaware(ver < 1.3), reset channel and terminate 1078c1c61f44Ssb155480 * the connection. See comments in vsw_set_vnet_proto_ops(). 1079c1c61f44Ssb155480 */ 1080c1c61f44Ssb155480 if (ldcp->hphase == VSW_MILESTONE4 && VSW_VER_LT(ldcp, 1, 3) && 1081c1c61f44Ssb155480 portp->nvids != 0) { 1082c1c61f44Ssb155480 vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 1083c1c61f44Ssb155480 } 1084c1c61f44Ssb155480 1085c1c61f44Ssb155480 mutex_exit(&ldcp->ldc_cblock); 1086c1c61f44Ssb155480 } 1087c1c61f44Ssb155480 1088678453a8Sspeer void 1089cdfc78adSraghuram vsw_hio_port_reset(vsw_port_t *portp, boolean_t immediate) 1090678453a8Sspeer { 10917bd3a2e2SSriharsha Basavapatna vsw_ldc_t *ldcp = portp->ldcp; 1092678453a8Sspeer 1093678453a8Sspeer mutex_enter(&ldcp->ldc_cblock); 1094678453a8Sspeer 1095678453a8Sspeer /* 1096678453a8Sspeer * If the peer is HybridIO capable (ver >= 1.3), reset channel 1097678453a8Sspeer * to trigger re-negotiation, which inturn trigger HybridIO 1098678453a8Sspeer * setup/cleanup. 1099678453a8Sspeer */ 1100678453a8Sspeer if ((ldcp->hphase == VSW_MILESTONE4) && 1101678453a8Sspeer (portp->p_hio_capable == B_TRUE)) { 1102cdfc78adSraghuram if (immediate == B_TRUE) { 1103cdfc78adSraghuram (void) ldc_down(ldcp->ldc_handle); 1104cdfc78adSraghuram } else { 1105678453a8Sspeer vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 1106678453a8Sspeer } 1107cdfc78adSraghuram } 1108678453a8Sspeer 1109678453a8Sspeer mutex_exit(&ldcp->ldc_cblock); 1110678453a8Sspeer } 1111678453a8Sspeer 11127b1f684aSSriharsha Basavapatna void 11137b1f684aSSriharsha Basavapatna vsw_port_reset(vsw_port_t *portp) 11147b1f684aSSriharsha Basavapatna { 11157bd3a2e2SSriharsha Basavapatna vsw_ldc_t *ldcp = portp->ldcp; 11167b1f684aSSriharsha Basavapatna 11177b1f684aSSriharsha Basavapatna mutex_enter(&ldcp->ldc_cblock); 11187b1f684aSSriharsha Basavapatna 11197b1f684aSSriharsha Basavapatna /* 11207b1f684aSSriharsha Basavapatna * reset channel and terminate the connection. 11217b1f684aSSriharsha Basavapatna */ 11227b1f684aSSriharsha Basavapatna vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 11237b1f684aSSriharsha Basavapatna 11247b1f684aSSriharsha Basavapatna mutex_exit(&ldcp->ldc_cblock); 11257b1f684aSSriharsha Basavapatna } 11267b1f684aSSriharsha Basavapatna 11277b1f684aSSriharsha Basavapatna void 11287b1f684aSSriharsha Basavapatna vsw_reset_ports(vsw_t *vswp) 11297b1f684aSSriharsha Basavapatna { 11307b1f684aSSriharsha Basavapatna vsw_port_list_t *plist = &vswp->plist; 11317b1f684aSSriharsha Basavapatna vsw_port_t *portp; 11327b1f684aSSriharsha Basavapatna 11337b1f684aSSriharsha Basavapatna READ_ENTER(&plist->lockrw); 11347b1f684aSSriharsha Basavapatna for (portp = plist->head; portp != NULL; portp = portp->p_next) { 11357b1f684aSSriharsha Basavapatna if ((portp->p_hio_capable) && (portp->p_hio_enabled)) { 11367b1f684aSSriharsha Basavapatna vsw_hio_stop_port(portp); 11377b1f684aSSriharsha Basavapatna } 11387b1f684aSSriharsha Basavapatna vsw_port_reset(portp); 11397b1f684aSSriharsha Basavapatna } 11407b1f684aSSriharsha Basavapatna RW_EXIT(&plist->lockrw); 11417b1f684aSSriharsha Basavapatna } 11427b1f684aSSriharsha Basavapatna 11431107ea93SSriharsha Basavapatna static void 11441107ea93SSriharsha Basavapatna vsw_send_physlink_msg(vsw_ldc_t *ldcp, link_state_t plink_state) 11451107ea93SSriharsha Basavapatna { 11461107ea93SSriharsha Basavapatna vnet_physlink_msg_t msg; 11471107ea93SSriharsha Basavapatna vnet_physlink_msg_t *msgp = &msg; 11481107ea93SSriharsha Basavapatna uint32_t physlink_info = 0; 11491107ea93SSriharsha Basavapatna 11501107ea93SSriharsha Basavapatna if (plink_state == LINK_STATE_UP) { 11511107ea93SSriharsha Basavapatna physlink_info |= VNET_PHYSLINK_STATE_UP; 11521107ea93SSriharsha Basavapatna } else { 11531107ea93SSriharsha Basavapatna physlink_info |= VNET_PHYSLINK_STATE_DOWN; 11541107ea93SSriharsha Basavapatna } 11551107ea93SSriharsha Basavapatna 11561107ea93SSriharsha Basavapatna msgp->tag.vio_msgtype = VIO_TYPE_CTRL; 11571107ea93SSriharsha Basavapatna msgp->tag.vio_subtype = VIO_SUBTYPE_INFO; 11581107ea93SSriharsha Basavapatna msgp->tag.vio_subtype_env = VNET_PHYSLINK_INFO; 11591107ea93SSriharsha Basavapatna msgp->tag.vio_sid = ldcp->local_session; 11601107ea93SSriharsha Basavapatna msgp->physlink_info = physlink_info; 11611107ea93SSriharsha Basavapatna 11621107ea93SSriharsha Basavapatna (void) vsw_send_msg(ldcp, msgp, sizeof (msg), B_TRUE); 11631107ea93SSriharsha Basavapatna } 11641107ea93SSriharsha Basavapatna 11651107ea93SSriharsha Basavapatna static void 11661107ea93SSriharsha Basavapatna vsw_port_physlink_update(vsw_port_t *portp) 11671107ea93SSriharsha Basavapatna { 11681107ea93SSriharsha Basavapatna vsw_ldc_t *ldcp; 11691107ea93SSriharsha Basavapatna vsw_t *vswp; 11701107ea93SSriharsha Basavapatna 11711107ea93SSriharsha Basavapatna vswp = portp->p_vswp; 11727bd3a2e2SSriharsha Basavapatna ldcp = portp->ldcp; 11731107ea93SSriharsha Basavapatna 11741107ea93SSriharsha Basavapatna mutex_enter(&ldcp->ldc_cblock); 11751107ea93SSriharsha Basavapatna 11761107ea93SSriharsha Basavapatna /* 11771107ea93SSriharsha Basavapatna * If handshake has completed successfully and if the vnet device 11781107ea93SSriharsha Basavapatna * has negotiated to get physical link state updates, send a message 11791107ea93SSriharsha Basavapatna * with the current state. 11801107ea93SSriharsha Basavapatna */ 11811107ea93SSriharsha Basavapatna if (ldcp->hphase == VSW_MILESTONE4 && ldcp->pls_negotiated == B_TRUE) { 11821107ea93SSriharsha Basavapatna vsw_send_physlink_msg(ldcp, vswp->phys_link_state); 11831107ea93SSriharsha Basavapatna } 11841107ea93SSriharsha Basavapatna 11851107ea93SSriharsha Basavapatna mutex_exit(&ldcp->ldc_cblock); 11861107ea93SSriharsha Basavapatna } 11871107ea93SSriharsha Basavapatna 11881107ea93SSriharsha Basavapatna void 11891107ea93SSriharsha Basavapatna vsw_physlink_update_ports(vsw_t *vswp) 11901107ea93SSriharsha Basavapatna { 11911107ea93SSriharsha Basavapatna vsw_port_list_t *plist = &vswp->plist; 11921107ea93SSriharsha Basavapatna vsw_port_t *portp; 11931107ea93SSriharsha Basavapatna 11941107ea93SSriharsha Basavapatna READ_ENTER(&plist->lockrw); 11951107ea93SSriharsha Basavapatna for (portp = plist->head; portp != NULL; portp = portp->p_next) { 11961107ea93SSriharsha Basavapatna vsw_port_physlink_update(portp); 11971107ea93SSriharsha Basavapatna } 11981107ea93SSriharsha Basavapatna RW_EXIT(&plist->lockrw); 11991107ea93SSriharsha Basavapatna } 12007b1f684aSSriharsha Basavapatna 120106db247cSraghuram /* 120206db247cSraghuram * Search for and remove the specified port from the port 120306db247cSraghuram * list. Returns 0 if able to locate and remove port, otherwise 120406db247cSraghuram * returns 1. 120506db247cSraghuram */ 120606db247cSraghuram static int 120706db247cSraghuram vsw_plist_del_node(vsw_t *vswp, vsw_port_t *port) 120806db247cSraghuram { 120906db247cSraghuram vsw_port_list_t *plist = &vswp->plist; 121006db247cSraghuram vsw_port_t *curr_p, *prev_p; 121106db247cSraghuram 121206db247cSraghuram if (plist->head == NULL) 121306db247cSraghuram return (1); 121406db247cSraghuram 121506db247cSraghuram curr_p = prev_p = plist->head; 121606db247cSraghuram 121706db247cSraghuram while (curr_p != NULL) { 121806db247cSraghuram if (curr_p == port) { 121906db247cSraghuram if (prev_p == curr_p) { 122006db247cSraghuram plist->head = curr_p->p_next; 122106db247cSraghuram } else { 122206db247cSraghuram prev_p->p_next = curr_p->p_next; 122306db247cSraghuram } 122406db247cSraghuram plist->num_ports--; 122506db247cSraghuram break; 122606db247cSraghuram } else { 122706db247cSraghuram prev_p = curr_p; 122806db247cSraghuram curr_p = curr_p->p_next; 122906db247cSraghuram } 123006db247cSraghuram } 123106db247cSraghuram return (0); 123206db247cSraghuram } 123306db247cSraghuram 123406db247cSraghuram /* 123506db247cSraghuram * Interrupt handler for ldc messages. 123606db247cSraghuram */ 123706db247cSraghuram static uint_t 123806db247cSraghuram vsw_ldc_cb(uint64_t event, caddr_t arg) 123906db247cSraghuram { 124006db247cSraghuram vsw_ldc_t *ldcp = (vsw_ldc_t *)arg; 124106db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 124206db247cSraghuram 124306db247cSraghuram D1(vswp, "%s: enter: ldcid (%lld)\n", __func__, ldcp->ldc_id); 124406db247cSraghuram 124506db247cSraghuram mutex_enter(&ldcp->ldc_cblock); 124606db247cSraghuram ldcp->ldc_stats.callbacks++; 124706db247cSraghuram 124806db247cSraghuram mutex_enter(&ldcp->status_lock); 124906db247cSraghuram if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == NULL)) { 125006db247cSraghuram mutex_exit(&ldcp->status_lock); 125106db247cSraghuram mutex_exit(&ldcp->ldc_cblock); 125206db247cSraghuram return (LDC_SUCCESS); 125306db247cSraghuram } 125406db247cSraghuram mutex_exit(&ldcp->status_lock); 125506db247cSraghuram 125606db247cSraghuram if (event & LDC_EVT_UP) { 125706db247cSraghuram /* 125806db247cSraghuram * Channel has come up. 125906db247cSraghuram */ 126006db247cSraghuram D2(vswp, "%s: id(%ld) event(%llx) UP: status(%ld)", 126106db247cSraghuram __func__, ldcp->ldc_id, event, ldcp->ldc_status); 126206db247cSraghuram 126306db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_UP); 126406db247cSraghuram 126506db247cSraghuram ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0); 126606db247cSraghuram } 126706db247cSraghuram 126806db247cSraghuram if (event & LDC_EVT_READ) { 126906db247cSraghuram /* 127006db247cSraghuram * Data available for reading. 127106db247cSraghuram */ 127206db247cSraghuram D2(vswp, "%s: id(ld) event(%llx) data READ", 127306db247cSraghuram __func__, ldcp->ldc_id, event); 127406db247cSraghuram 12757bd3a2e2SSriharsha Basavapatna vsw_process_evt_read(ldcp); 127606db247cSraghuram 127706db247cSraghuram ASSERT((event & (LDC_EVT_RESET | LDC_EVT_DOWN)) == 0); 127806db247cSraghuram 127906db247cSraghuram goto vsw_cb_exit; 128006db247cSraghuram } 128106db247cSraghuram 128206db247cSraghuram if (event & (LDC_EVT_DOWN | LDC_EVT_RESET)) { 128306db247cSraghuram D2(vswp, "%s: id(%ld) event (%lx) DOWN/RESET: status(%ld)", 128406db247cSraghuram __func__, ldcp->ldc_id, event, ldcp->ldc_status); 128506db247cSraghuram 128606db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESET); 128706db247cSraghuram } 128806db247cSraghuram 128906db247cSraghuram /* 129006db247cSraghuram * Catch either LDC_EVT_WRITE which we don't support or any 129106db247cSraghuram * unknown event. 129206db247cSraghuram */ 129306db247cSraghuram if (event & 129406db247cSraghuram ~(LDC_EVT_UP | LDC_EVT_RESET | LDC_EVT_DOWN | LDC_EVT_READ)) { 129506db247cSraghuram DERR(vswp, "%s: id(%ld) Unexpected event=(%llx) status(%ld)", 129606db247cSraghuram __func__, ldcp->ldc_id, event, ldcp->ldc_status); 129706db247cSraghuram } 129806db247cSraghuram 129906db247cSraghuram vsw_cb_exit: 130006db247cSraghuram mutex_exit(&ldcp->ldc_cblock); 130106db247cSraghuram 130206db247cSraghuram /* 130306db247cSraghuram * Let the drain function know we are finishing if it 130406db247cSraghuram * is waiting. 130506db247cSraghuram */ 130606db247cSraghuram mutex_enter(&ldcp->drain_cv_lock); 130706db247cSraghuram if (ldcp->drain_state == VSW_LDC_DRAINING) 130806db247cSraghuram cv_signal(&ldcp->drain_cv); 130906db247cSraghuram mutex_exit(&ldcp->drain_cv_lock); 131006db247cSraghuram 131106db247cSraghuram return (LDC_SUCCESS); 131206db247cSraghuram } 131306db247cSraghuram 131406db247cSraghuram /* 131506db247cSraghuram * Reinitialise data structures associated with the channel. 131606db247cSraghuram */ 131706db247cSraghuram static void 131806db247cSraghuram vsw_ldc_reinit(vsw_ldc_t *ldcp) 131906db247cSraghuram { 132006db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 132106db247cSraghuram vsw_port_t *port; 132206db247cSraghuram 132306db247cSraghuram D1(vswp, "%s: enter", __func__); 132406db247cSraghuram 132506db247cSraghuram port = ldcp->ldc_port; 132606db247cSraghuram 132706db247cSraghuram D2(vswp, "%s: in 0x%llx : out 0x%llx", __func__, 132806db247cSraghuram ldcp->lane_in.lstate, ldcp->lane_out.lstate); 132906db247cSraghuram 133006db247cSraghuram vsw_free_lane_resources(ldcp, INBOUND); 133106db247cSraghuram vsw_free_lane_resources(ldcp, OUTBOUND); 133206db247cSraghuram 133306db247cSraghuram ldcp->lane_in.lstate = 0; 133406db247cSraghuram ldcp->lane_out.lstate = 0; 133506db247cSraghuram 133606db247cSraghuram /* 133706db247cSraghuram * Remove parent port from any multicast groups 133806db247cSraghuram * it may have registered with. Client must resend 133906db247cSraghuram * multicast add command after handshake completes. 134006db247cSraghuram */ 134106db247cSraghuram vsw_del_mcst_port(port); 134206db247cSraghuram 134306db247cSraghuram ldcp->peer_session = 0; 134406db247cSraghuram ldcp->session_status = 0; 134506db247cSraghuram ldcp->hcnt = 0; 134606db247cSraghuram ldcp->hphase = VSW_MILESTONE0; 1347f0ca1d9aSsb155480 1348f0ca1d9aSsb155480 vsw_reset_vnet_proto_ops(ldcp); 134906db247cSraghuram 135006db247cSraghuram D1(vswp, "%s: exit", __func__); 135106db247cSraghuram } 135206db247cSraghuram 135306db247cSraghuram /* 135406db247cSraghuram * Process a connection event. 135506db247cSraghuram */ 13567bd3a2e2SSriharsha Basavapatna void 135706db247cSraghuram vsw_process_conn_evt(vsw_ldc_t *ldcp, uint16_t evt) 135806db247cSraghuram { 135906db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 136006db247cSraghuram vsw_conn_evt_t *conn = NULL; 136106db247cSraghuram 136206db247cSraghuram D1(vswp, "%s: enter", __func__); 136306db247cSraghuram 136406db247cSraghuram /* 136506db247cSraghuram * Check if either a reset or restart event is pending 136606db247cSraghuram * or in progress. If so just return. 136706db247cSraghuram * 136806db247cSraghuram * A VSW_CONN_RESET event originates either with a LDC_RESET_EVT 136906db247cSraghuram * being received by the callback handler, or a ECONNRESET error 137006db247cSraghuram * code being returned from a ldc_read() or ldc_write() call. 137106db247cSraghuram * 137206db247cSraghuram * A VSW_CONN_RESTART event occurs when some error checking code 137306db247cSraghuram * decides that there is a problem with data from the channel, 137406db247cSraghuram * and that the handshake should be restarted. 137506db247cSraghuram */ 137606db247cSraghuram if (((evt == VSW_CONN_RESET) || (evt == VSW_CONN_RESTART)) && 137706db247cSraghuram (ldstub((uint8_t *)&ldcp->reset_active))) 137806db247cSraghuram return; 137906db247cSraghuram 138006db247cSraghuram /* 138106db247cSraghuram * If it is an LDC_UP event we first check the recorded 138206db247cSraghuram * state of the channel. If this is UP then we know that 138306db247cSraghuram * the channel moving to the UP state has already been dealt 138406db247cSraghuram * with and don't need to dispatch a new task. 138506db247cSraghuram * 138606db247cSraghuram * The reason for this check is that when we do a ldc_up(), 138706db247cSraghuram * depending on the state of the peer, we may or may not get 138806db247cSraghuram * a LDC_UP event. As we can't depend on getting a LDC_UP evt 138906db247cSraghuram * every time we do ldc_up() we explicitly check the channel 139006db247cSraghuram * status to see has it come up (ldc_up() is asynch and will 139106db247cSraghuram * complete at some undefined time), and take the appropriate 139206db247cSraghuram * action. 139306db247cSraghuram * 139406db247cSraghuram * The flip side of this is that we may get a LDC_UP event 139506db247cSraghuram * when we have already seen that the channel is up and have 139606db247cSraghuram * dealt with that. 139706db247cSraghuram */ 139806db247cSraghuram mutex_enter(&ldcp->status_lock); 139906db247cSraghuram if (evt == VSW_CONN_UP) { 140006db247cSraghuram if ((ldcp->ldc_status == LDC_UP) || (ldcp->reset_active != 0)) { 140106db247cSraghuram mutex_exit(&ldcp->status_lock); 140206db247cSraghuram return; 140306db247cSraghuram } 140406db247cSraghuram } 140506db247cSraghuram mutex_exit(&ldcp->status_lock); 140606db247cSraghuram 140706db247cSraghuram /* 140806db247cSraghuram * The transaction group id allows us to identify and discard 140906db247cSraghuram * any tasks which are still pending on the taskq and refer 141006db247cSraghuram * to the handshake session we are about to restart or reset. 141106db247cSraghuram * These stale messages no longer have any real meaning. 141206db247cSraghuram */ 141306db247cSraghuram (void) atomic_inc_32(&ldcp->hss_id); 141406db247cSraghuram 141506db247cSraghuram ASSERT(vswp->taskq_p != NULL); 141606db247cSraghuram 141706db247cSraghuram if ((conn = kmem_zalloc(sizeof (vsw_conn_evt_t), KM_NOSLEEP)) == NULL) { 141806db247cSraghuram cmn_err(CE_WARN, "!vsw%d: unable to allocate memory for" 141906db247cSraghuram " connection event", vswp->instance); 142006db247cSraghuram goto err_exit; 142106db247cSraghuram } 142206db247cSraghuram 142306db247cSraghuram conn->evt = evt; 142406db247cSraghuram conn->ldcp = ldcp; 142506db247cSraghuram 142606db247cSraghuram if (ddi_taskq_dispatch(vswp->taskq_p, vsw_conn_task, conn, 142706db247cSraghuram DDI_NOSLEEP) != DDI_SUCCESS) { 142806db247cSraghuram cmn_err(CE_WARN, "!vsw%d: Can't dispatch connection task", 142906db247cSraghuram vswp->instance); 143006db247cSraghuram 143106db247cSraghuram kmem_free(conn, sizeof (vsw_conn_evt_t)); 143206db247cSraghuram goto err_exit; 143306db247cSraghuram } 143406db247cSraghuram 143506db247cSraghuram D1(vswp, "%s: exit", __func__); 143606db247cSraghuram return; 143706db247cSraghuram 143806db247cSraghuram err_exit: 143906db247cSraghuram /* 144006db247cSraghuram * Have mostly likely failed due to memory shortage. Clear the flag so 144106db247cSraghuram * that future requests will at least be attempted and will hopefully 144206db247cSraghuram * succeed. 144306db247cSraghuram */ 144406db247cSraghuram if ((evt == VSW_CONN_RESET) || (evt == VSW_CONN_RESTART)) 144506db247cSraghuram ldcp->reset_active = 0; 144606db247cSraghuram } 144706db247cSraghuram 144806db247cSraghuram /* 144906db247cSraghuram * Deal with events relating to a connection. Invoked from a taskq. 145006db247cSraghuram */ 145106db247cSraghuram static void 145206db247cSraghuram vsw_conn_task(void *arg) 145306db247cSraghuram { 145406db247cSraghuram vsw_conn_evt_t *conn = (vsw_conn_evt_t *)arg; 145506db247cSraghuram vsw_ldc_t *ldcp = NULL; 1456678453a8Sspeer vsw_port_t *portp; 145706db247cSraghuram vsw_t *vswp = NULL; 145806db247cSraghuram uint16_t evt; 145906db247cSraghuram ldc_status_t curr_status; 146006db247cSraghuram 146106db247cSraghuram ldcp = conn->ldcp; 146206db247cSraghuram evt = conn->evt; 146306db247cSraghuram vswp = ldcp->ldc_vswp; 1464678453a8Sspeer portp = ldcp->ldc_port; 146506db247cSraghuram 146606db247cSraghuram D1(vswp, "%s: enter", __func__); 146706db247cSraghuram 146806db247cSraghuram /* can safely free now have copied out data */ 146906db247cSraghuram kmem_free(conn, sizeof (vsw_conn_evt_t)); 147006db247cSraghuram 14717bd3a2e2SSriharsha Basavapatna if (ldcp->rcv_thread != NULL) { 14727bd3a2e2SSriharsha Basavapatna vsw_stop_rcv_thread(ldcp); 14737bd3a2e2SSriharsha Basavapatna } else if (ldcp->msg_thread != NULL) { 14747bd3a2e2SSriharsha Basavapatna vsw_stop_msg_thread(ldcp); 14757bd3a2e2SSriharsha Basavapatna } 14767bd3a2e2SSriharsha Basavapatna 147706db247cSraghuram mutex_enter(&ldcp->status_lock); 147806db247cSraghuram if (ldc_status(ldcp->ldc_handle, &curr_status) != 0) { 147906db247cSraghuram cmn_err(CE_WARN, "!vsw%d: Unable to read status of " 148006db247cSraghuram "channel %ld", vswp->instance, ldcp->ldc_id); 148106db247cSraghuram mutex_exit(&ldcp->status_lock); 148206db247cSraghuram return; 148306db247cSraghuram } 148406db247cSraghuram 148506db247cSraghuram /* 148606db247cSraghuram * If we wish to restart the handshake on this channel, then if 148706db247cSraghuram * the channel is UP we bring it DOWN to flush the underlying 148806db247cSraghuram * ldc queue. 148906db247cSraghuram */ 149006db247cSraghuram if ((evt == VSW_CONN_RESTART) && (curr_status == LDC_UP)) 149106db247cSraghuram (void) ldc_down(ldcp->ldc_handle); 149206db247cSraghuram 1493cdfc78adSraghuram if ((portp->p_hio_capable) && (portp->p_hio_enabled)) { 1494678453a8Sspeer vsw_hio_stop(vswp, ldcp); 1495678453a8Sspeer } 1496678453a8Sspeer 149706db247cSraghuram /* 149806db247cSraghuram * re-init all the associated data structures. 149906db247cSraghuram */ 150006db247cSraghuram vsw_ldc_reinit(ldcp); 150106db247cSraghuram 150206db247cSraghuram /* 150306db247cSraghuram * Bring the channel back up (note it does no harm to 150406db247cSraghuram * do this even if the channel is already UP, Just 150506db247cSraghuram * becomes effectively a no-op). 150606db247cSraghuram */ 150706db247cSraghuram (void) ldc_up(ldcp->ldc_handle); 150806db247cSraghuram 150906db247cSraghuram /* 151006db247cSraghuram * Check if channel is now UP. This will only happen if 151106db247cSraghuram * peer has also done a ldc_up(). 151206db247cSraghuram */ 151306db247cSraghuram if (ldc_status(ldcp->ldc_handle, &curr_status) != 0) { 151406db247cSraghuram cmn_err(CE_WARN, "!vsw%d: Unable to read status of " 151506db247cSraghuram "channel %ld", vswp->instance, ldcp->ldc_id); 151606db247cSraghuram mutex_exit(&ldcp->status_lock); 151706db247cSraghuram return; 151806db247cSraghuram } 151906db247cSraghuram 152006db247cSraghuram ldcp->ldc_status = curr_status; 152106db247cSraghuram 152206db247cSraghuram /* channel UP so restart handshake by sending version info */ 152306db247cSraghuram if (curr_status == LDC_UP) { 152406db247cSraghuram if (ldcp->hcnt++ > vsw_num_handshakes) { 152506db247cSraghuram cmn_err(CE_WARN, "!vsw%d: exceeded number of permitted" 152606db247cSraghuram " handshake attempts (%d) on channel %ld", 152706db247cSraghuram vswp->instance, ldcp->hcnt, ldcp->ldc_id); 152806db247cSraghuram mutex_exit(&ldcp->status_lock); 152906db247cSraghuram return; 153006db247cSraghuram } 153106db247cSraghuram 1532f0ca1d9aSsb155480 if (vsw_obp_ver_proto_workaround == B_FALSE && 1533f0ca1d9aSsb155480 (ddi_taskq_dispatch(vswp->taskq_p, vsw_send_ver, ldcp, 1534f0ca1d9aSsb155480 DDI_NOSLEEP) != DDI_SUCCESS)) { 153506db247cSraghuram cmn_err(CE_WARN, "!vsw%d: Can't dispatch version task", 153606db247cSraghuram vswp->instance); 153706db247cSraghuram 153806db247cSraghuram /* 153906db247cSraghuram * Don't count as valid restart attempt if couldn't 154006db247cSraghuram * send version msg. 154106db247cSraghuram */ 154206db247cSraghuram if (ldcp->hcnt > 0) 154306db247cSraghuram ldcp->hcnt--; 154406db247cSraghuram } 154506db247cSraghuram } 154606db247cSraghuram 154706db247cSraghuram /* 154806db247cSraghuram * Mark that the process is complete by clearing the flag. 154906db247cSraghuram * 155006db247cSraghuram * Note is it possible that the taskq dispatch above may have failed, 155106db247cSraghuram * most likely due to memory shortage. We still clear the flag so 155206db247cSraghuram * future attempts will at least be attempted and will hopefully 155306db247cSraghuram * succeed. 155406db247cSraghuram */ 155506db247cSraghuram if ((evt == VSW_CONN_RESET) || (evt == VSW_CONN_RESTART)) 155606db247cSraghuram ldcp->reset_active = 0; 155706db247cSraghuram 155806db247cSraghuram mutex_exit(&ldcp->status_lock); 155906db247cSraghuram 156006db247cSraghuram D1(vswp, "%s: exit", __func__); 156106db247cSraghuram } 156206db247cSraghuram 156306db247cSraghuram /* 156406db247cSraghuram * returns 0 if legal for event signified by flag to have 156506db247cSraghuram * occured at the time it did. Otherwise returns 1. 156606db247cSraghuram */ 156706db247cSraghuram int 156806db247cSraghuram vsw_check_flag(vsw_ldc_t *ldcp, int dir, uint64_t flag) 156906db247cSraghuram { 157006db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 157106db247cSraghuram uint64_t state; 157206db247cSraghuram uint64_t phase; 157306db247cSraghuram 157406db247cSraghuram if (dir == INBOUND) 157506db247cSraghuram state = ldcp->lane_in.lstate; 157606db247cSraghuram else 157706db247cSraghuram state = ldcp->lane_out.lstate; 157806db247cSraghuram 157906db247cSraghuram phase = ldcp->hphase; 158006db247cSraghuram 158106db247cSraghuram switch (flag) { 158206db247cSraghuram case VSW_VER_INFO_RECV: 158306db247cSraghuram if (phase > VSW_MILESTONE0) { 158406db247cSraghuram DERR(vswp, "vsw_check_flag (%d): VER_INFO_RECV" 158506db247cSraghuram " when in state %d\n", ldcp->ldc_id, phase); 158606db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 158706db247cSraghuram return (1); 158806db247cSraghuram } 158906db247cSraghuram break; 159006db247cSraghuram 159106db247cSraghuram case VSW_VER_ACK_RECV: 159206db247cSraghuram case VSW_VER_NACK_RECV: 159306db247cSraghuram if (!(state & VSW_VER_INFO_SENT)) { 159406db247cSraghuram DERR(vswp, "vsw_check_flag (%d): spurious VER_ACK or " 159506db247cSraghuram "VER_NACK when in state %d\n", ldcp->ldc_id, phase); 159606db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 159706db247cSraghuram return (1); 159806db247cSraghuram } else 159906db247cSraghuram state &= ~VSW_VER_INFO_SENT; 160006db247cSraghuram break; 160106db247cSraghuram 160206db247cSraghuram case VSW_ATTR_INFO_RECV: 160306db247cSraghuram if ((phase < VSW_MILESTONE1) || (phase >= VSW_MILESTONE2)) { 160406db247cSraghuram DERR(vswp, "vsw_check_flag (%d): ATTR_INFO_RECV" 160506db247cSraghuram " when in state %d\n", ldcp->ldc_id, phase); 160606db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 160706db247cSraghuram return (1); 160806db247cSraghuram } 160906db247cSraghuram break; 161006db247cSraghuram 161106db247cSraghuram case VSW_ATTR_ACK_RECV: 161206db247cSraghuram case VSW_ATTR_NACK_RECV: 161306db247cSraghuram if (!(state & VSW_ATTR_INFO_SENT)) { 161406db247cSraghuram DERR(vswp, "vsw_check_flag (%d): spurious ATTR_ACK" 161506db247cSraghuram " or ATTR_NACK when in state %d\n", 161606db247cSraghuram ldcp->ldc_id, phase); 161706db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 161806db247cSraghuram return (1); 161906db247cSraghuram } else 162006db247cSraghuram state &= ~VSW_ATTR_INFO_SENT; 162106db247cSraghuram break; 162206db247cSraghuram 162306db247cSraghuram case VSW_DRING_INFO_RECV: 162406db247cSraghuram if (phase < VSW_MILESTONE1) { 162506db247cSraghuram DERR(vswp, "vsw_check_flag (%d): DRING_INFO_RECV" 162606db247cSraghuram " when in state %d\n", ldcp->ldc_id, phase); 162706db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 162806db247cSraghuram return (1); 162906db247cSraghuram } 163006db247cSraghuram break; 163106db247cSraghuram 163206db247cSraghuram case VSW_DRING_ACK_RECV: 163306db247cSraghuram case VSW_DRING_NACK_RECV: 163406db247cSraghuram if (!(state & VSW_DRING_INFO_SENT)) { 163506db247cSraghuram DERR(vswp, "vsw_check_flag (%d): spurious DRING_ACK " 163606db247cSraghuram " or DRING_NACK when in state %d\n", 163706db247cSraghuram ldcp->ldc_id, phase); 163806db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 163906db247cSraghuram return (1); 164006db247cSraghuram } else 164106db247cSraghuram state &= ~VSW_DRING_INFO_SENT; 164206db247cSraghuram break; 164306db247cSraghuram 164406db247cSraghuram case VSW_RDX_INFO_RECV: 164506db247cSraghuram if (phase < VSW_MILESTONE3) { 164606db247cSraghuram DERR(vswp, "vsw_check_flag (%d): RDX_INFO_RECV" 164706db247cSraghuram " when in state %d\n", ldcp->ldc_id, phase); 164806db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 164906db247cSraghuram return (1); 165006db247cSraghuram } 165106db247cSraghuram break; 165206db247cSraghuram 165306db247cSraghuram case VSW_RDX_ACK_RECV: 165406db247cSraghuram case VSW_RDX_NACK_RECV: 165506db247cSraghuram if (!(state & VSW_RDX_INFO_SENT)) { 165606db247cSraghuram DERR(vswp, "vsw_check_flag (%d): spurious RDX_ACK or " 165706db247cSraghuram "RDX_NACK when in state %d\n", ldcp->ldc_id, phase); 165806db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 165906db247cSraghuram return (1); 166006db247cSraghuram } else 166106db247cSraghuram state &= ~VSW_RDX_INFO_SENT; 166206db247cSraghuram break; 166306db247cSraghuram 166406db247cSraghuram case VSW_MCST_INFO_RECV: 166506db247cSraghuram if (phase < VSW_MILESTONE3) { 166606db247cSraghuram DERR(vswp, "vsw_check_flag (%d): VSW_MCST_INFO_RECV" 166706db247cSraghuram " when in state %d\n", ldcp->ldc_id, phase); 166806db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 166906db247cSraghuram return (1); 167006db247cSraghuram } 167106db247cSraghuram break; 167206db247cSraghuram 167306db247cSraghuram default: 167406db247cSraghuram DERR(vswp, "vsw_check_flag (%lld): unknown flag (%llx)", 167506db247cSraghuram ldcp->ldc_id, flag); 167606db247cSraghuram return (1); 167706db247cSraghuram } 167806db247cSraghuram 167906db247cSraghuram if (dir == INBOUND) 168006db247cSraghuram ldcp->lane_in.lstate = state; 168106db247cSraghuram else 168206db247cSraghuram ldcp->lane_out.lstate = state; 168306db247cSraghuram 168406db247cSraghuram D1(vswp, "vsw_check_flag (chan %lld): exit", ldcp->ldc_id); 168506db247cSraghuram 168606db247cSraghuram return (0); 168706db247cSraghuram } 168806db247cSraghuram 168906db247cSraghuram void 169006db247cSraghuram vsw_next_milestone(vsw_ldc_t *ldcp) 169106db247cSraghuram { 169206db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 1693678453a8Sspeer vsw_port_t *portp = ldcp->ldc_port; 16947bd3a2e2SSriharsha Basavapatna lane_t *lane_out = &ldcp->lane_out; 16957bd3a2e2SSriharsha Basavapatna lane_t *lane_in = &ldcp->lane_in; 169606db247cSraghuram 169706db247cSraghuram D1(vswp, "%s (chan %lld): enter (phase %ld)", __func__, 169806db247cSraghuram ldcp->ldc_id, ldcp->hphase); 169906db247cSraghuram 17007bd3a2e2SSriharsha Basavapatna DUMP_FLAGS(lane_in->lstate); 17017bd3a2e2SSriharsha Basavapatna DUMP_FLAGS(lane_out->lstate); 170206db247cSraghuram 170306db247cSraghuram switch (ldcp->hphase) { 170406db247cSraghuram 170506db247cSraghuram case VSW_MILESTONE0: 170606db247cSraghuram /* 170706db247cSraghuram * If we haven't started to handshake with our peer, 170806db247cSraghuram * start to do so now. 170906db247cSraghuram */ 17107bd3a2e2SSriharsha Basavapatna if (lane_out->lstate == 0) { 171106db247cSraghuram D2(vswp, "%s: (chan %lld) starting handshake " 171206db247cSraghuram "with peer", __func__, ldcp->ldc_id); 171306db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_UP); 171406db247cSraghuram } 171506db247cSraghuram 171606db247cSraghuram /* 171706db247cSraghuram * Only way to pass this milestone is to have successfully 171806db247cSraghuram * negotiated version info. 171906db247cSraghuram */ 17207bd3a2e2SSriharsha Basavapatna if ((lane_in->lstate & VSW_VER_ACK_SENT) && 17217bd3a2e2SSriharsha Basavapatna (lane_out->lstate & VSW_VER_ACK_RECV)) { 172206db247cSraghuram 172306db247cSraghuram D2(vswp, "%s: (chan %lld) leaving milestone 0", 172406db247cSraghuram __func__, ldcp->ldc_id); 172506db247cSraghuram 1726f0ca1d9aSsb155480 vsw_set_vnet_proto_ops(ldcp); 1727f0ca1d9aSsb155480 172806db247cSraghuram /* 172906db247cSraghuram * Next milestone is passed when attribute 173006db247cSraghuram * information has been successfully exchanged. 173106db247cSraghuram */ 173206db247cSraghuram ldcp->hphase = VSW_MILESTONE1; 173306db247cSraghuram vsw_send_attr(ldcp); 173406db247cSraghuram 173506db247cSraghuram } 173606db247cSraghuram break; 173706db247cSraghuram 173806db247cSraghuram case VSW_MILESTONE1: 173906db247cSraghuram /* 174006db247cSraghuram * Only way to pass this milestone is to have successfully 17417bd3a2e2SSriharsha Basavapatna * negotiated attribute information, in both directions. 174206db247cSraghuram */ 17437bd3a2e2SSriharsha Basavapatna if (!((lane_in->lstate & VSW_ATTR_ACK_SENT) && 17447bd3a2e2SSriharsha Basavapatna (lane_out->lstate & VSW_ATTR_ACK_RECV))) { 17457bd3a2e2SSriharsha Basavapatna break; 17467bd3a2e2SSriharsha Basavapatna } 174706db247cSraghuram 174806db247cSraghuram ldcp->hphase = VSW_MILESTONE2; 174906db247cSraghuram 175006db247cSraghuram /* 175106db247cSraghuram * If the peer device has said it wishes to 175206db247cSraghuram * use descriptor rings then we send it our ring 175306db247cSraghuram * info, otherwise we just set up a private ring 175406db247cSraghuram * which we use an internal buffer 175506db247cSraghuram */ 1756c1c61f44Ssb155480 if ((VSW_VER_GTEQ(ldcp, 1, 2) && 17577bd3a2e2SSriharsha Basavapatna (lane_in->xfer_mode & VIO_DRING_MODE_V1_2)) || 1758f0ca1d9aSsb155480 (VSW_VER_LT(ldcp, 1, 2) && 17597bd3a2e2SSriharsha Basavapatna (lane_in->xfer_mode == VIO_DRING_MODE_V1_0))) { 176006db247cSraghuram vsw_send_dring_info(ldcp); 176106db247cSraghuram break; 17627bd3a2e2SSriharsha Basavapatna } 17637bd3a2e2SSriharsha Basavapatna 17647bd3a2e2SSriharsha Basavapatna /* 17657bd3a2e2SSriharsha Basavapatna * The peer doesn't operate in dring mode; we 17667bd3a2e2SSriharsha Basavapatna * can simply fallthru to the RDX phase from 17677bd3a2e2SSriharsha Basavapatna * here. 17687bd3a2e2SSriharsha Basavapatna */ 17697bd3a2e2SSriharsha Basavapatna /*FALLTHRU*/ 177006db247cSraghuram 177106db247cSraghuram case VSW_MILESTONE2: 177206db247cSraghuram /* 177306db247cSraghuram * If peer has indicated in its attribute message that 177406db247cSraghuram * it wishes to use descriptor rings then the only way 177506db247cSraghuram * to pass this milestone is for us to have received 177606db247cSraghuram * valid dring info. 177706db247cSraghuram * 177806db247cSraghuram * If peer is not using descriptor rings then just fall 177906db247cSraghuram * through. 178006db247cSraghuram */ 1781c1c61f44Ssb155480 if ((VSW_VER_GTEQ(ldcp, 1, 2) && 17827bd3a2e2SSriharsha Basavapatna (lane_in->xfer_mode & VIO_DRING_MODE_V1_2)) || 1783f0ca1d9aSsb155480 (VSW_VER_LT(ldcp, 1, 2) && 17847bd3a2e2SSriharsha Basavapatna (lane_in->xfer_mode == 1785f0ca1d9aSsb155480 VIO_DRING_MODE_V1_0))) { 17867bd3a2e2SSriharsha Basavapatna if (!(lane_in->lstate & VSW_DRING_ACK_SENT)) 178706db247cSraghuram break; 1788f0ca1d9aSsb155480 } 178906db247cSraghuram 179006db247cSraghuram D2(vswp, "%s: (chan %lld) leaving milestone 2", 179106db247cSraghuram __func__, ldcp->ldc_id); 179206db247cSraghuram 179306db247cSraghuram ldcp->hphase = VSW_MILESTONE3; 179406db247cSraghuram vsw_send_rdx(ldcp); 179506db247cSraghuram break; 179606db247cSraghuram 179706db247cSraghuram case VSW_MILESTONE3: 179806db247cSraghuram /* 179906db247cSraghuram * Pass this milestone when all paramaters have been 180006db247cSraghuram * successfully exchanged and RDX sent in both directions. 180106db247cSraghuram * 18027bd3a2e2SSriharsha Basavapatna * Mark the relevant lane as available to transmit data. In 18037bd3a2e2SSriharsha Basavapatna * RxDringData mode, lane_in is associated with transmit and 18047bd3a2e2SSriharsha Basavapatna * lane_out is associated with receive. It is the reverse in 18057bd3a2e2SSriharsha Basavapatna * TxDring mode. 180606db247cSraghuram */ 18077bd3a2e2SSriharsha Basavapatna if ((lane_out->lstate & VSW_RDX_ACK_SENT) && 18087bd3a2e2SSriharsha Basavapatna (lane_in->lstate & VSW_RDX_ACK_RECV)) { 180906db247cSraghuram 181006db247cSraghuram D2(vswp, "%s: (chan %lld) leaving milestone 3", 181106db247cSraghuram __func__, ldcp->ldc_id); 181206db247cSraghuram D2(vswp, "%s: ** handshake complete (0x%llx : " 18137bd3a2e2SSriharsha Basavapatna "0x%llx) **", __func__, lane_in->lstate, 18147bd3a2e2SSriharsha Basavapatna lane_out->lstate); 18157bd3a2e2SSriharsha Basavapatna if (lane_out->dring_mode == VIO_RX_DRING_DATA) { 18167bd3a2e2SSriharsha Basavapatna lane_in->lstate |= VSW_LANE_ACTIVE; 18177bd3a2e2SSriharsha Basavapatna } else { 18187bd3a2e2SSriharsha Basavapatna lane_out->lstate |= VSW_LANE_ACTIVE; 18197bd3a2e2SSriharsha Basavapatna } 182006db247cSraghuram ldcp->hphase = VSW_MILESTONE4; 182106db247cSraghuram ldcp->hcnt = 0; 182206db247cSraghuram DISPLAY_STATE(); 1823678453a8Sspeer /* Start HIO if enabled and capable */ 1824678453a8Sspeer if ((portp->p_hio_enabled) && (portp->p_hio_capable)) { 1825678453a8Sspeer D2(vswp, "%s: start HybridIO setup", __func__); 1826678453a8Sspeer vsw_hio_start(vswp, ldcp); 1827678453a8Sspeer } 18281107ea93SSriharsha Basavapatna 18291107ea93SSriharsha Basavapatna if (ldcp->pls_negotiated == B_TRUE) { 18301107ea93SSriharsha Basavapatna /* 18311107ea93SSriharsha Basavapatna * The vnet device has negotiated to get phys 18321107ea93SSriharsha Basavapatna * link updates. Now that the handshake with 18331107ea93SSriharsha Basavapatna * the vnet device is complete, send an initial 18341107ea93SSriharsha Basavapatna * update with the current physical link state. 18351107ea93SSriharsha Basavapatna */ 18361107ea93SSriharsha Basavapatna vsw_send_physlink_msg(ldcp, 18371107ea93SSriharsha Basavapatna vswp->phys_link_state); 18381107ea93SSriharsha Basavapatna } 18391107ea93SSriharsha Basavapatna 184006db247cSraghuram } else { 184106db247cSraghuram D2(vswp, "%s: still in milestone 3 (0x%llx : 0x%llx)", 18427bd3a2e2SSriharsha Basavapatna __func__, lane_in->lstate, 18437bd3a2e2SSriharsha Basavapatna lane_out->lstate); 184406db247cSraghuram } 184506db247cSraghuram break; 184606db247cSraghuram 184706db247cSraghuram case VSW_MILESTONE4: 184806db247cSraghuram D2(vswp, "%s: (chan %lld) in milestone 4", __func__, 184906db247cSraghuram ldcp->ldc_id); 185006db247cSraghuram break; 185106db247cSraghuram 185206db247cSraghuram default: 185306db247cSraghuram DERR(vswp, "%s: (chan %lld) Unknown Phase %x", __func__, 185406db247cSraghuram ldcp->ldc_id, ldcp->hphase); 185506db247cSraghuram } 185606db247cSraghuram 185706db247cSraghuram D1(vswp, "%s (chan %lld): exit (phase %ld)", __func__, ldcp->ldc_id, 185806db247cSraghuram ldcp->hphase); 185906db247cSraghuram } 186006db247cSraghuram 186106db247cSraghuram /* 186206db247cSraghuram * Check if major version is supported. 186306db247cSraghuram * 186406db247cSraghuram * Returns 0 if finds supported major number, and if necessary 186506db247cSraghuram * adjusts the minor field. 186606db247cSraghuram * 186706db247cSraghuram * Returns 1 if can't match major number exactly. Sets mjor/minor 186806db247cSraghuram * to next lowest support values, or to zero if no other values possible. 186906db247cSraghuram */ 187006db247cSraghuram static int 187106db247cSraghuram vsw_supported_version(vio_ver_msg_t *vp) 187206db247cSraghuram { 187306db247cSraghuram int i; 187406db247cSraghuram 187506db247cSraghuram D1(NULL, "vsw_supported_version: enter"); 187606db247cSraghuram 187706db247cSraghuram for (i = 0; i < VSW_NUM_VER; i++) { 187806db247cSraghuram if (vsw_versions[i].ver_major == vp->ver_major) { 187906db247cSraghuram /* 188006db247cSraghuram * Matching or lower major version found. Update 188106db247cSraghuram * minor number if necessary. 188206db247cSraghuram */ 188306db247cSraghuram if (vp->ver_minor > vsw_versions[i].ver_minor) { 188406db247cSraghuram D2(NULL, "%s: adjusting minor value from %d " 188506db247cSraghuram "to %d", __func__, vp->ver_minor, 188606db247cSraghuram vsw_versions[i].ver_minor); 188706db247cSraghuram vp->ver_minor = vsw_versions[i].ver_minor; 188806db247cSraghuram } 188906db247cSraghuram 189006db247cSraghuram return (0); 189106db247cSraghuram } 189206db247cSraghuram 1893f0ca1d9aSsb155480 /* 1894f0ca1d9aSsb155480 * If the message contains a higher major version number, set 1895f0ca1d9aSsb155480 * the message's major/minor versions to the current values 1896f0ca1d9aSsb155480 * and return false, so this message will get resent with 1897f0ca1d9aSsb155480 * these values. 1898f0ca1d9aSsb155480 */ 189906db247cSraghuram if (vsw_versions[i].ver_major < vp->ver_major) { 1900f0ca1d9aSsb155480 D2(NULL, "%s: adjusting major and minor " 1901f0ca1d9aSsb155480 "values to %d, %d\n", 1902f0ca1d9aSsb155480 __func__, vsw_versions[i].ver_major, 190306db247cSraghuram vsw_versions[i].ver_minor); 1904f0ca1d9aSsb155480 vp->ver_major = vsw_versions[i].ver_major; 190506db247cSraghuram vp->ver_minor = vsw_versions[i].ver_minor; 190606db247cSraghuram return (1); 190706db247cSraghuram } 190806db247cSraghuram } 190906db247cSraghuram 191006db247cSraghuram /* No match was possible, zero out fields */ 191106db247cSraghuram vp->ver_major = 0; 191206db247cSraghuram vp->ver_minor = 0; 191306db247cSraghuram 191406db247cSraghuram D1(NULL, "vsw_supported_version: exit"); 191506db247cSraghuram 191606db247cSraghuram return (1); 191706db247cSraghuram } 191806db247cSraghuram 191906db247cSraghuram /* 1920f0ca1d9aSsb155480 * Set vnet-protocol-version dependent functions based on version. 1921f0ca1d9aSsb155480 */ 1922f0ca1d9aSsb155480 static void 1923f0ca1d9aSsb155480 vsw_set_vnet_proto_ops(vsw_ldc_t *ldcp) 1924f0ca1d9aSsb155480 { 1925f0ca1d9aSsb155480 vsw_t *vswp = ldcp->ldc_vswp; 1926f0ca1d9aSsb155480 lane_t *lp = &ldcp->lane_out; 1927f0ca1d9aSsb155480 19287bd3a2e2SSriharsha Basavapatna /* 19297bd3a2e2SSriharsha Basavapatna * Setup the appropriate dring data processing routine and any 19307bd3a2e2SSriharsha Basavapatna * associated thread based on the version. 19317bd3a2e2SSriharsha Basavapatna * 19327bd3a2e2SSriharsha Basavapatna * In versions < 1.6, we support only TxDring mode. In this mode, the 19337bd3a2e2SSriharsha Basavapatna * msg worker thread processes all types of VIO msgs (ctrl and data). 19347bd3a2e2SSriharsha Basavapatna * 19357bd3a2e2SSriharsha Basavapatna * In versions >= 1.6, we also support RxDringData mode. In this mode, 19367bd3a2e2SSriharsha Basavapatna * the rcv worker thread processes dring data messages (msgtype: 19377bd3a2e2SSriharsha Basavapatna * VIO_TYPE_DATA, subtype: VIO_SUBTYPE_INFO, env: VIO_DRING_DATA). The 19387bd3a2e2SSriharsha Basavapatna * rest of the data messages (including acks) and ctrl messages are 19397bd3a2e2SSriharsha Basavapatna * handled directly by the callback (intr) thread. 19407bd3a2e2SSriharsha Basavapatna * 19417bd3a2e2SSriharsha Basavapatna * However, for versions >= 1.6, we could still fallback to TxDring 19427bd3a2e2SSriharsha Basavapatna * mode. This could happen if RxDringData mode has been disabled (see 1943*34f94fbcSWENTAO YANG * below) on this guest or on the peer guest. This info is determined 1944*34f94fbcSWENTAO YANG * as part of attr exchange phase of handshake. Hence, we setup these 1945*34f94fbcSWENTAO YANG * pointers for v1.6 after attr msg phase completes during handshake. 19467bd3a2e2SSriharsha Basavapatna */ 19477bd3a2e2SSriharsha Basavapatna if (VSW_VER_GTEQ(ldcp, 1, 6)) { 19487bd3a2e2SSriharsha Basavapatna /* 19497bd3a2e2SSriharsha Basavapatna * Set data dring mode for vsw_send_attr(). We setup msg worker 19507bd3a2e2SSriharsha Basavapatna * thread in TxDring mode or rcv worker thread in RxDringData 19517bd3a2e2SSriharsha Basavapatna * mode when attr phase of handshake completes. 19527bd3a2e2SSriharsha Basavapatna */ 1953*34f94fbcSWENTAO YANG if (vsw_mapin_avail(ldcp) == B_TRUE) { 19547bd3a2e2SSriharsha Basavapatna lp->dring_mode = (VIO_RX_DRING_DATA | VIO_TX_DRING); 19557bd3a2e2SSriharsha Basavapatna } else { 19567bd3a2e2SSriharsha Basavapatna lp->dring_mode = VIO_TX_DRING; 19577bd3a2e2SSriharsha Basavapatna } 19587bd3a2e2SSriharsha Basavapatna } else { 19597bd3a2e2SSriharsha Basavapatna lp->dring_mode = VIO_TX_DRING; 19607bd3a2e2SSriharsha Basavapatna } 19617bd3a2e2SSriharsha Basavapatna 19627bd3a2e2SSriharsha Basavapatna /* 19637bd3a2e2SSriharsha Basavapatna * Setup the MTU for attribute negotiation based on the version. 19647bd3a2e2SSriharsha Basavapatna */ 19657b1f684aSSriharsha Basavapatna if (VSW_VER_GTEQ(ldcp, 1, 4)) { 1966c1c61f44Ssb155480 /* 19677b1f684aSSriharsha Basavapatna * If the version negotiated with peer is >= 1.4(Jumbo Frame 19687b1f684aSSriharsha Basavapatna * Support), set the mtu in our attributes to max_frame_size. 1969c1c61f44Ssb155480 */ 1970c1c61f44Ssb155480 lp->mtu = vswp->max_frame_size; 19717b1f684aSSriharsha Basavapatna } else if (VSW_VER_EQ(ldcp, 1, 3)) { 19727b1f684aSSriharsha Basavapatna /* 19737b1f684aSSriharsha Basavapatna * If the version negotiated with peer is == 1.3 (Vlan Tag 19747b1f684aSSriharsha Basavapatna * Support) set the attr.mtu to ETHERMAX + VLAN_TAGSZ. 19757b1f684aSSriharsha Basavapatna */ 19767b1f684aSSriharsha Basavapatna lp->mtu = ETHERMAX + VLAN_TAGSZ; 1977c1c61f44Ssb155480 } else { 1978c1c61f44Ssb155480 vsw_port_t *portp = ldcp->ldc_port; 1979c1c61f44Ssb155480 /* 1980c1c61f44Ssb155480 * Pre-1.3 peers expect max frame size of ETHERMAX. 19817b1f684aSSriharsha Basavapatna * We can negotiate that size with those peers provided only 19827b1f684aSSriharsha Basavapatna * pvid is defined for our peer and there are no vids. Then we 19837b1f684aSSriharsha Basavapatna * can send/recv only untagged frames of max size ETHERMAX. 19847b1f684aSSriharsha Basavapatna * Note that pvid of the peer can be different, as vsw has to 19857b1f684aSSriharsha Basavapatna * serve the vnet in that vlan even if itself is not assigned 19867b1f684aSSriharsha Basavapatna * to that vlan. 1987c1c61f44Ssb155480 */ 19887b1f684aSSriharsha Basavapatna if (portp->nvids == 0) { 1989c1c61f44Ssb155480 lp->mtu = ETHERMAX; 1990c1c61f44Ssb155480 } 1991c1c61f44Ssb155480 } 1992c1c61f44Ssb155480 19937bd3a2e2SSriharsha Basavapatna /* 19947bd3a2e2SSriharsha Basavapatna * Setup version dependent data processing functions. 19957bd3a2e2SSriharsha Basavapatna */ 1996c1c61f44Ssb155480 if (VSW_VER_GTEQ(ldcp, 1, 2)) { 1997c1c61f44Ssb155480 /* Versions >= 1.2 */ 1998f0ca1d9aSsb155480 1999f0ca1d9aSsb155480 if (VSW_PRI_ETH_DEFINED(vswp)) { 2000f0ca1d9aSsb155480 /* 2001f0ca1d9aSsb155480 * enable priority routines and pkt mode only if 2002f0ca1d9aSsb155480 * at least one pri-eth-type is specified in MD. 2003f0ca1d9aSsb155480 */ 2004f0ca1d9aSsb155480 ldcp->tx = vsw_ldctx_pri; 2005f0ca1d9aSsb155480 ldcp->rx_pktdata = vsw_process_pkt_data; 2006f0ca1d9aSsb155480 2007f0ca1d9aSsb155480 /* set xfer mode for vsw_send_attr() */ 2008f0ca1d9aSsb155480 lp->xfer_mode = VIO_PKT_MODE | VIO_DRING_MODE_V1_2; 2009f0ca1d9aSsb155480 } else { 2010f0ca1d9aSsb155480 /* no priority eth types defined in MD */ 2011f0ca1d9aSsb155480 2012f0ca1d9aSsb155480 ldcp->tx = vsw_ldctx; 2013f0ca1d9aSsb155480 ldcp->rx_pktdata = vsw_process_pkt_data_nop; 2014f0ca1d9aSsb155480 2015f0ca1d9aSsb155480 /* set xfer mode for vsw_send_attr() */ 2016f0ca1d9aSsb155480 lp->xfer_mode = VIO_DRING_MODE_V1_2; 2017f0ca1d9aSsb155480 } 2018c1c61f44Ssb155480 2019f0ca1d9aSsb155480 } else { 2020f0ca1d9aSsb155480 /* Versions prior to 1.2 */ 2021f0ca1d9aSsb155480 2022f0ca1d9aSsb155480 vsw_reset_vnet_proto_ops(ldcp); 2023f0ca1d9aSsb155480 } 2024f0ca1d9aSsb155480 } 2025f0ca1d9aSsb155480 2026f0ca1d9aSsb155480 /* 2027f0ca1d9aSsb155480 * Reset vnet-protocol-version dependent functions to v1.0. 2028f0ca1d9aSsb155480 */ 2029f0ca1d9aSsb155480 static void 2030f0ca1d9aSsb155480 vsw_reset_vnet_proto_ops(vsw_ldc_t *ldcp) 2031f0ca1d9aSsb155480 { 2032f0ca1d9aSsb155480 lane_t *lp = &ldcp->lane_out; 2033f0ca1d9aSsb155480 2034f0ca1d9aSsb155480 ldcp->tx = vsw_ldctx; 2035f0ca1d9aSsb155480 ldcp->rx_pktdata = vsw_process_pkt_data_nop; 2036f0ca1d9aSsb155480 2037f0ca1d9aSsb155480 /* set xfer mode for vsw_send_attr() */ 2038f0ca1d9aSsb155480 lp->xfer_mode = VIO_DRING_MODE_V1_0; 2039f0ca1d9aSsb155480 } 2040f0ca1d9aSsb155480 20417bd3a2e2SSriharsha Basavapatna static void 20427bd3a2e2SSriharsha Basavapatna vsw_process_evt_read(vsw_ldc_t *ldcp) 20437bd3a2e2SSriharsha Basavapatna { 20447bd3a2e2SSriharsha Basavapatna if (ldcp->msg_thread != NULL) { 20457bd3a2e2SSriharsha Basavapatna /* 20467bd3a2e2SSriharsha Basavapatna * TxDring mode; wakeup message worker 20477bd3a2e2SSriharsha Basavapatna * thread to process the VIO messages. 20487bd3a2e2SSriharsha Basavapatna */ 20497bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->ldc_cblock); 20507bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->msg_thr_lock); 20517bd3a2e2SSriharsha Basavapatna if (!(ldcp->msg_thr_flags & VSW_WTHR_DATARCVD)) { 20527bd3a2e2SSriharsha Basavapatna ldcp->msg_thr_flags |= VSW_WTHR_DATARCVD; 20537bd3a2e2SSriharsha Basavapatna cv_signal(&ldcp->msg_thr_cv); 20547bd3a2e2SSriharsha Basavapatna } 20557bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->msg_thr_lock); 20567bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->ldc_cblock); 20577bd3a2e2SSriharsha Basavapatna } else { 20587bd3a2e2SSriharsha Basavapatna /* 20597bd3a2e2SSriharsha Basavapatna * We invoke vsw_process_pkt() in the context of the LDC 20607bd3a2e2SSriharsha Basavapatna * callback (vsw_ldc_cb()) during handshake, until the dring 20617bd3a2e2SSriharsha Basavapatna * mode is negotiated. After the dring mode is negotiated, the 20627bd3a2e2SSriharsha Basavapatna * msgs are processed by the msg worker thread (above case) if 20637bd3a2e2SSriharsha Basavapatna * the dring mode is TxDring. Otherwise (in RxDringData mode) 20647bd3a2e2SSriharsha Basavapatna * we continue to process the msgs directly in the callback 20657bd3a2e2SSriharsha Basavapatna * context. 20667bd3a2e2SSriharsha Basavapatna */ 20677bd3a2e2SSriharsha Basavapatna vsw_process_pkt(ldcp); 20687bd3a2e2SSriharsha Basavapatna } 20697bd3a2e2SSriharsha Basavapatna } 20707bd3a2e2SSriharsha Basavapatna 2071f0ca1d9aSsb155480 /* 207206db247cSraghuram * Main routine for processing messages received over LDC. 207306db247cSraghuram */ 20747bd3a2e2SSriharsha Basavapatna void 207506db247cSraghuram vsw_process_pkt(void *arg) 207606db247cSraghuram { 207706db247cSraghuram vsw_ldc_t *ldcp = (vsw_ldc_t *)arg; 207806db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 207906db247cSraghuram size_t msglen; 2080f0ca1d9aSsb155480 vio_msg_tag_t *tagp; 2081f0ca1d9aSsb155480 uint64_t *ldcmsg; 208206db247cSraghuram int rv = 0; 208306db247cSraghuram 208406db247cSraghuram 208506db247cSraghuram D1(vswp, "%s enter: ldcid (%lld)\n", __func__, ldcp->ldc_id); 208606db247cSraghuram 208706db247cSraghuram ASSERT(MUTEX_HELD(&ldcp->ldc_cblock)); 208806db247cSraghuram 2089f0ca1d9aSsb155480 ldcmsg = ldcp->ldcmsg; 209006db247cSraghuram /* 209106db247cSraghuram * If channel is up read messages until channel is empty. 209206db247cSraghuram */ 209306db247cSraghuram do { 2094f0ca1d9aSsb155480 msglen = ldcp->msglen; 2095f0ca1d9aSsb155480 rv = ldc_read(ldcp->ldc_handle, (caddr_t)ldcmsg, &msglen); 209606db247cSraghuram 209706db247cSraghuram if (rv != 0) { 209806db247cSraghuram DERR(vswp, "%s :ldc_read err id(%lld) rv(%d) len(%d)\n", 209906db247cSraghuram __func__, ldcp->ldc_id, rv, msglen); 210006db247cSraghuram } 210106db247cSraghuram 210206db247cSraghuram /* channel has been reset */ 210306db247cSraghuram if (rv == ECONNRESET) { 210406db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESET); 210506db247cSraghuram break; 210606db247cSraghuram } 210706db247cSraghuram 210806db247cSraghuram if (msglen == 0) { 210906db247cSraghuram D2(vswp, "%s: ldc_read id(%lld) NODATA", __func__, 211006db247cSraghuram ldcp->ldc_id); 211106db247cSraghuram break; 211206db247cSraghuram } 211306db247cSraghuram 211406db247cSraghuram D2(vswp, "%s: ldc_read id(%lld): msglen(%d)", __func__, 211506db247cSraghuram ldcp->ldc_id, msglen); 211606db247cSraghuram 211706db247cSraghuram /* 211806db247cSraghuram * Figure out what sort of packet we have gotten by 211906db247cSraghuram * examining the msg tag, and then switch it appropriately. 212006db247cSraghuram */ 2121f0ca1d9aSsb155480 tagp = (vio_msg_tag_t *)ldcmsg; 212206db247cSraghuram 2123f0ca1d9aSsb155480 switch (tagp->vio_msgtype) { 212406db247cSraghuram case VIO_TYPE_CTRL: 21257bd3a2e2SSriharsha Basavapatna vsw_dispatch_ctrl_task(ldcp, ldcmsg, tagp, msglen); 212606db247cSraghuram break; 212706db247cSraghuram case VIO_TYPE_DATA: 2128f0ca1d9aSsb155480 vsw_process_data_pkt(ldcp, ldcmsg, tagp, msglen); 212906db247cSraghuram break; 213006db247cSraghuram case VIO_TYPE_ERR: 2131f0ca1d9aSsb155480 vsw_process_err_pkt(ldcp, ldcmsg, tagp); 213206db247cSraghuram break; 213306db247cSraghuram default: 213406db247cSraghuram DERR(vswp, "%s: Unknown tag(%lx) ", __func__, 2135f0ca1d9aSsb155480 "id(%lx)\n", tagp->vio_msgtype, ldcp->ldc_id); 213606db247cSraghuram break; 213706db247cSraghuram } 213806db247cSraghuram } while (msglen); 213906db247cSraghuram 214006db247cSraghuram D1(vswp, "%s exit: ldcid (%lld)\n", __func__, ldcp->ldc_id); 214106db247cSraghuram } 214206db247cSraghuram 214306db247cSraghuram /* 214406db247cSraghuram * Dispatch a task to process a VIO control message. 214506db247cSraghuram */ 214606db247cSraghuram static void 21477bd3a2e2SSriharsha Basavapatna vsw_dispatch_ctrl_task(vsw_ldc_t *ldcp, void *cpkt, vio_msg_tag_t *tagp, 21487bd3a2e2SSriharsha Basavapatna int msglen) 214906db247cSraghuram { 215006db247cSraghuram vsw_ctrl_task_t *ctaskp = NULL; 215106db247cSraghuram vsw_port_t *port = ldcp->ldc_port; 215206db247cSraghuram vsw_t *vswp = port->p_vswp; 215306db247cSraghuram 215406db247cSraghuram D1(vswp, "%s: enter", __func__); 215506db247cSraghuram 215606db247cSraghuram /* 215706db247cSraghuram * We need to handle RDX ACK messages in-band as once they 215806db247cSraghuram * are exchanged it is possible that we will get an 215906db247cSraghuram * immediate (legitimate) data packet. 216006db247cSraghuram */ 2161f0ca1d9aSsb155480 if ((tagp->vio_subtype_env == VIO_RDX) && 2162f0ca1d9aSsb155480 (tagp->vio_subtype == VIO_SUBTYPE_ACK)) { 216306db247cSraghuram 216406db247cSraghuram if (vsw_check_flag(ldcp, INBOUND, VSW_RDX_ACK_RECV)) 216506db247cSraghuram return; 216606db247cSraghuram 216706db247cSraghuram ldcp->lane_in.lstate |= VSW_RDX_ACK_RECV; 216806db247cSraghuram D2(vswp, "%s (%ld) handling RDX_ACK in place " 216906db247cSraghuram "(ostate 0x%llx : hphase %d)", __func__, 217006db247cSraghuram ldcp->ldc_id, ldcp->lane_in.lstate, ldcp->hphase); 217106db247cSraghuram vsw_next_milestone(ldcp); 217206db247cSraghuram return; 217306db247cSraghuram } 217406db247cSraghuram 217506db247cSraghuram ctaskp = kmem_alloc(sizeof (vsw_ctrl_task_t), KM_NOSLEEP); 217606db247cSraghuram 217706db247cSraghuram if (ctaskp == NULL) { 217806db247cSraghuram DERR(vswp, "%s: unable to alloc space for ctrl msg", __func__); 217906db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 218006db247cSraghuram return; 218106db247cSraghuram } 218206db247cSraghuram 218306db247cSraghuram ctaskp->ldcp = ldcp; 21847bd3a2e2SSriharsha Basavapatna bcopy((def_msg_t *)cpkt, &ctaskp->pktp, msglen); 218506db247cSraghuram ctaskp->hss_id = ldcp->hss_id; 218606db247cSraghuram 218706db247cSraghuram /* 218806db247cSraghuram * Dispatch task to processing taskq if port is not in 218906db247cSraghuram * the process of being detached. 219006db247cSraghuram */ 219106db247cSraghuram mutex_enter(&port->state_lock); 219206db247cSraghuram if (port->state == VSW_PORT_INIT) { 219306db247cSraghuram if ((vswp->taskq_p == NULL) || 219406db247cSraghuram (ddi_taskq_dispatch(vswp->taskq_p, vsw_process_ctrl_pkt, 219506db247cSraghuram ctaskp, DDI_NOSLEEP) != DDI_SUCCESS)) { 2196a248ff60SWENTAO YANG mutex_exit(&port->state_lock); 219706db247cSraghuram DERR(vswp, "%s: unable to dispatch task to taskq", 219806db247cSraghuram __func__); 219906db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 2200a248ff60SWENTAO YANG kmem_free(ctaskp, sizeof (vsw_ctrl_task_t)); 220106db247cSraghuram return; 220206db247cSraghuram } 220306db247cSraghuram } else { 2204a248ff60SWENTAO YANG kmem_free(ctaskp, sizeof (vsw_ctrl_task_t)); 220506db247cSraghuram DWARN(vswp, "%s: port %d detaching, not dispatching " 220606db247cSraghuram "task", __func__, port->p_instance); 220706db247cSraghuram } 220806db247cSraghuram 220906db247cSraghuram mutex_exit(&port->state_lock); 221006db247cSraghuram 221106db247cSraghuram D2(vswp, "%s: dispatched task to taskq for chan %d", __func__, 221206db247cSraghuram ldcp->ldc_id); 221306db247cSraghuram D1(vswp, "%s: exit", __func__); 221406db247cSraghuram } 221506db247cSraghuram 221606db247cSraghuram /* 221706db247cSraghuram * Process a VIO ctrl message. Invoked from taskq. 221806db247cSraghuram */ 221906db247cSraghuram static void 222006db247cSraghuram vsw_process_ctrl_pkt(void *arg) 222106db247cSraghuram { 222206db247cSraghuram vsw_ctrl_task_t *ctaskp = (vsw_ctrl_task_t *)arg; 222306db247cSraghuram vsw_ldc_t *ldcp = ctaskp->ldcp; 222406db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 222506db247cSraghuram vio_msg_tag_t tag; 222606db247cSraghuram uint16_t env; 222706db247cSraghuram 222806db247cSraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id); 222906db247cSraghuram 223006db247cSraghuram bcopy(&ctaskp->pktp, &tag, sizeof (vio_msg_tag_t)); 223106db247cSraghuram env = tag.vio_subtype_env; 223206db247cSraghuram 223306db247cSraghuram /* stale pkt check */ 223406db247cSraghuram if (ctaskp->hss_id < ldcp->hss_id) { 223506db247cSraghuram DWARN(vswp, "%s: discarding stale packet belonging to earlier" 223606db247cSraghuram " (%ld) handshake session", __func__, ctaskp->hss_id); 2237a248ff60SWENTAO YANG kmem_free(ctaskp, sizeof (vsw_ctrl_task_t)); 223806db247cSraghuram return; 223906db247cSraghuram } 224006db247cSraghuram 224106db247cSraghuram /* session id check */ 224206db247cSraghuram if (ldcp->session_status & VSW_PEER_SESSION) { 224306db247cSraghuram if (ldcp->peer_session != tag.vio_sid) { 224406db247cSraghuram DERR(vswp, "%s (chan %d): invalid session id (%llx)", 224506db247cSraghuram __func__, ldcp->ldc_id, tag.vio_sid); 224606db247cSraghuram kmem_free(ctaskp, sizeof (vsw_ctrl_task_t)); 224706db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 224806db247cSraghuram return; 224906db247cSraghuram } 225006db247cSraghuram } 225106db247cSraghuram 225206db247cSraghuram /* 225306db247cSraghuram * Switch on vio_subtype envelope, then let lower routines 225406db247cSraghuram * decide if its an INFO, ACK or NACK packet. 225506db247cSraghuram */ 225606db247cSraghuram switch (env) { 225706db247cSraghuram case VIO_VER_INFO: 225806db247cSraghuram vsw_process_ctrl_ver_pkt(ldcp, &ctaskp->pktp); 225906db247cSraghuram break; 226006db247cSraghuram case VIO_DRING_REG: 226106db247cSraghuram vsw_process_ctrl_dring_reg_pkt(ldcp, &ctaskp->pktp); 226206db247cSraghuram break; 226306db247cSraghuram case VIO_DRING_UNREG: 226406db247cSraghuram vsw_process_ctrl_dring_unreg_pkt(ldcp, &ctaskp->pktp); 226506db247cSraghuram break; 226606db247cSraghuram case VIO_ATTR_INFO: 226706db247cSraghuram vsw_process_ctrl_attr_pkt(ldcp, &ctaskp->pktp); 226806db247cSraghuram break; 226906db247cSraghuram case VNET_MCAST_INFO: 227006db247cSraghuram vsw_process_ctrl_mcst_pkt(ldcp, &ctaskp->pktp); 227106db247cSraghuram break; 227206db247cSraghuram case VIO_RDX: 227306db247cSraghuram vsw_process_ctrl_rdx_pkt(ldcp, &ctaskp->pktp); 227406db247cSraghuram break; 2275678453a8Sspeer case VIO_DDS_INFO: 2276678453a8Sspeer vsw_process_dds_msg(vswp, ldcp, &ctaskp->pktp); 2277678453a8Sspeer break; 22781107ea93SSriharsha Basavapatna 22791107ea93SSriharsha Basavapatna case VNET_PHYSLINK_INFO: 22801107ea93SSriharsha Basavapatna vsw_process_physlink_msg(ldcp, &ctaskp->pktp); 22811107ea93SSriharsha Basavapatna break; 228206db247cSraghuram default: 228306db247cSraghuram DERR(vswp, "%s: unknown vio_subtype_env (%x)\n", __func__, env); 228406db247cSraghuram } 228506db247cSraghuram 228606db247cSraghuram kmem_free(ctaskp, sizeof (vsw_ctrl_task_t)); 228706db247cSraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id); 228806db247cSraghuram } 228906db247cSraghuram 229006db247cSraghuram /* 229106db247cSraghuram * Version negotiation. We can end up here either because our peer 229206db247cSraghuram * has responded to a handshake message we have sent it, or our peer 229306db247cSraghuram * has initiated a handshake with us. If its the former then can only 229406db247cSraghuram * be ACK or NACK, if its the later can only be INFO. 229506db247cSraghuram * 229606db247cSraghuram * If its an ACK we move to the next stage of the handshake, namely 229706db247cSraghuram * attribute exchange. If its a NACK we see if we can specify another 229806db247cSraghuram * version, if we can't we stop. 229906db247cSraghuram * 230006db247cSraghuram * If it is an INFO we reset all params associated with communication 230106db247cSraghuram * in that direction over this channel (remember connection is 230206db247cSraghuram * essentially 2 independent simplex channels). 230306db247cSraghuram */ 230406db247cSraghuram void 230506db247cSraghuram vsw_process_ctrl_ver_pkt(vsw_ldc_t *ldcp, void *pkt) 230606db247cSraghuram { 230706db247cSraghuram vio_ver_msg_t *ver_pkt; 230806db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 230906db247cSraghuram 231006db247cSraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id); 231106db247cSraghuram 231206db247cSraghuram /* 231306db247cSraghuram * We know this is a ctrl/version packet so 231406db247cSraghuram * cast it into the correct structure. 231506db247cSraghuram */ 231606db247cSraghuram ver_pkt = (vio_ver_msg_t *)pkt; 231706db247cSraghuram 231806db247cSraghuram switch (ver_pkt->tag.vio_subtype) { 231906db247cSraghuram case VIO_SUBTYPE_INFO: 232006db247cSraghuram D2(vswp, "vsw_process_ctrl_ver_pkt: VIO_SUBTYPE_INFO\n"); 232106db247cSraghuram 232206db247cSraghuram /* 232306db247cSraghuram * Record the session id, which we will use from now 232406db247cSraghuram * until we see another VER_INFO msg. Even then the 232506db247cSraghuram * session id in most cases will be unchanged, execpt 232606db247cSraghuram * if channel was reset. 232706db247cSraghuram */ 232806db247cSraghuram if ((ldcp->session_status & VSW_PEER_SESSION) && 232906db247cSraghuram (ldcp->peer_session != ver_pkt->tag.vio_sid)) { 233006db247cSraghuram DERR(vswp, "%s: updating session id for chan %lld " 233106db247cSraghuram "from %llx to %llx", __func__, ldcp->ldc_id, 233206db247cSraghuram ldcp->peer_session, ver_pkt->tag.vio_sid); 233306db247cSraghuram } 233406db247cSraghuram 233506db247cSraghuram ldcp->peer_session = ver_pkt->tag.vio_sid; 233606db247cSraghuram ldcp->session_status |= VSW_PEER_SESSION; 233706db247cSraghuram 233806db247cSraghuram /* Legal message at this time ? */ 233906db247cSraghuram if (vsw_check_flag(ldcp, INBOUND, VSW_VER_INFO_RECV)) 234006db247cSraghuram return; 234106db247cSraghuram 234206db247cSraghuram /* 234306db247cSraghuram * First check the device class. Currently only expect 234406db247cSraghuram * to be talking to a network device. In the future may 234506db247cSraghuram * also talk to another switch. 234606db247cSraghuram */ 234706db247cSraghuram if (ver_pkt->dev_class != VDEV_NETWORK) { 234806db247cSraghuram DERR(vswp, "%s: illegal device class %d", __func__, 234906db247cSraghuram ver_pkt->dev_class); 235006db247cSraghuram 235106db247cSraghuram ver_pkt->tag.vio_sid = ldcp->local_session; 235206db247cSraghuram ver_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK; 235306db247cSraghuram 235406db247cSraghuram DUMP_TAG_PTR((vio_msg_tag_t *)ver_pkt); 235506db247cSraghuram 235606db247cSraghuram (void) vsw_send_msg(ldcp, (void *)ver_pkt, 235706db247cSraghuram sizeof (vio_ver_msg_t), B_TRUE); 235806db247cSraghuram 235906db247cSraghuram ldcp->lane_in.lstate |= VSW_VER_NACK_SENT; 236006db247cSraghuram vsw_next_milestone(ldcp); 236106db247cSraghuram return; 236206db247cSraghuram } else { 236306db247cSraghuram ldcp->dev_class = ver_pkt->dev_class; 236406db247cSraghuram } 236506db247cSraghuram 236606db247cSraghuram /* 236706db247cSraghuram * Now check the version. 236806db247cSraghuram */ 236906db247cSraghuram if (vsw_supported_version(ver_pkt) == 0) { 237006db247cSraghuram /* 237106db247cSraghuram * Support this major version and possibly 237206db247cSraghuram * adjusted minor version. 237306db247cSraghuram */ 237406db247cSraghuram 237506db247cSraghuram D2(vswp, "%s: accepted ver %d:%d", __func__, 237606db247cSraghuram ver_pkt->ver_major, ver_pkt->ver_minor); 237706db247cSraghuram 237806db247cSraghuram /* Store accepted values */ 237906db247cSraghuram ldcp->lane_in.ver_major = ver_pkt->ver_major; 238006db247cSraghuram ldcp->lane_in.ver_minor = ver_pkt->ver_minor; 238106db247cSraghuram 238206db247cSraghuram ver_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK; 238306db247cSraghuram 238406db247cSraghuram ldcp->lane_in.lstate |= VSW_VER_ACK_SENT; 2385f0ca1d9aSsb155480 2386f0ca1d9aSsb155480 if (vsw_obp_ver_proto_workaround == B_TRUE) { 2387f0ca1d9aSsb155480 /* 2388f0ca1d9aSsb155480 * Send a version info message 2389f0ca1d9aSsb155480 * using the accepted version that 2390f0ca1d9aSsb155480 * we are about to ack. Also note that 2391f0ca1d9aSsb155480 * we send our ver info before we ack. 2392f0ca1d9aSsb155480 * Otherwise, as soon as receiving the 2393f0ca1d9aSsb155480 * ack, obp sends attr info msg, which 2394f0ca1d9aSsb155480 * breaks vsw_check_flag() invoked 2395f0ca1d9aSsb155480 * from vsw_process_ctrl_attr_pkt(); 2396f0ca1d9aSsb155480 * as we also need VSW_VER_ACK_RECV to 2397f0ca1d9aSsb155480 * be set in lane_out.lstate, before 2398f0ca1d9aSsb155480 * we can receive attr info. 2399f0ca1d9aSsb155480 */ 2400f0ca1d9aSsb155480 vsw_send_ver(ldcp); 2401f0ca1d9aSsb155480 } 240206db247cSraghuram } else { 240306db247cSraghuram /* 240406db247cSraghuram * NACK back with the next lower major/minor 240506db247cSraghuram * pairing we support (if don't suuport any more 240606db247cSraghuram * versions then they will be set to zero. 240706db247cSraghuram */ 240806db247cSraghuram 240906db247cSraghuram D2(vswp, "%s: replying with ver %d:%d", __func__, 241006db247cSraghuram ver_pkt->ver_major, ver_pkt->ver_minor); 241106db247cSraghuram 241206db247cSraghuram /* Store updated values */ 241306db247cSraghuram ldcp->lane_in.ver_major = ver_pkt->ver_major; 241406db247cSraghuram ldcp->lane_in.ver_minor = ver_pkt->ver_minor; 241506db247cSraghuram 241606db247cSraghuram ver_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK; 241706db247cSraghuram 241806db247cSraghuram ldcp->lane_in.lstate |= VSW_VER_NACK_SENT; 241906db247cSraghuram } 242006db247cSraghuram 242106db247cSraghuram DUMP_TAG_PTR((vio_msg_tag_t *)ver_pkt); 242206db247cSraghuram ver_pkt->tag.vio_sid = ldcp->local_session; 242306db247cSraghuram (void) vsw_send_msg(ldcp, (void *)ver_pkt, 242406db247cSraghuram sizeof (vio_ver_msg_t), B_TRUE); 242506db247cSraghuram 242606db247cSraghuram vsw_next_milestone(ldcp); 242706db247cSraghuram break; 242806db247cSraghuram 242906db247cSraghuram case VIO_SUBTYPE_ACK: 243006db247cSraghuram D2(vswp, "%s: VIO_SUBTYPE_ACK\n", __func__); 243106db247cSraghuram 243206db247cSraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_VER_ACK_RECV)) 243306db247cSraghuram return; 243406db247cSraghuram 243506db247cSraghuram /* Store updated values */ 2436f0ca1d9aSsb155480 ldcp->lane_out.ver_major = ver_pkt->ver_major; 2437f0ca1d9aSsb155480 ldcp->lane_out.ver_minor = ver_pkt->ver_minor; 243806db247cSraghuram 243906db247cSraghuram ldcp->lane_out.lstate |= VSW_VER_ACK_RECV; 244006db247cSraghuram vsw_next_milestone(ldcp); 244106db247cSraghuram 244206db247cSraghuram break; 244306db247cSraghuram 244406db247cSraghuram case VIO_SUBTYPE_NACK: 244506db247cSraghuram D2(vswp, "%s: VIO_SUBTYPE_NACK\n", __func__); 244606db247cSraghuram 244706db247cSraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_VER_NACK_RECV)) 244806db247cSraghuram return; 244906db247cSraghuram 245006db247cSraghuram /* 245106db247cSraghuram * If our peer sent us a NACK with the ver fields set to 245206db247cSraghuram * zero then there is nothing more we can do. Otherwise see 245306db247cSraghuram * if we support either the version suggested, or a lesser 245406db247cSraghuram * one. 245506db247cSraghuram */ 245606db247cSraghuram if ((ver_pkt->ver_major == 0) && (ver_pkt->ver_minor == 0)) { 245706db247cSraghuram DERR(vswp, "%s: peer unable to negotiate any " 245806db247cSraghuram "further.", __func__); 245906db247cSraghuram ldcp->lane_out.lstate |= VSW_VER_NACK_RECV; 246006db247cSraghuram vsw_next_milestone(ldcp); 246106db247cSraghuram return; 246206db247cSraghuram } 246306db247cSraghuram 246406db247cSraghuram /* 246506db247cSraghuram * Check to see if we support this major version or 246606db247cSraghuram * a lower one. If we don't then maj/min will be set 246706db247cSraghuram * to zero. 246806db247cSraghuram */ 246906db247cSraghuram (void) vsw_supported_version(ver_pkt); 247006db247cSraghuram if ((ver_pkt->ver_major == 0) && (ver_pkt->ver_minor == 0)) { 247106db247cSraghuram /* Nothing more we can do */ 247206db247cSraghuram DERR(vswp, "%s: version negotiation failed.\n", 247306db247cSraghuram __func__); 247406db247cSraghuram ldcp->lane_out.lstate |= VSW_VER_NACK_RECV; 247506db247cSraghuram vsw_next_milestone(ldcp); 247606db247cSraghuram } else { 247706db247cSraghuram /* found a supported major version */ 247806db247cSraghuram ldcp->lane_out.ver_major = ver_pkt->ver_major; 247906db247cSraghuram ldcp->lane_out.ver_minor = ver_pkt->ver_minor; 248006db247cSraghuram 248106db247cSraghuram D2(vswp, "%s: resending with updated values (%x, %x)", 248206db247cSraghuram __func__, ver_pkt->ver_major, ver_pkt->ver_minor); 248306db247cSraghuram 248406db247cSraghuram ldcp->lane_out.lstate |= VSW_VER_INFO_SENT; 248506db247cSraghuram ver_pkt->tag.vio_sid = ldcp->local_session; 248606db247cSraghuram ver_pkt->tag.vio_subtype = VIO_SUBTYPE_INFO; 248706db247cSraghuram 248806db247cSraghuram DUMP_TAG_PTR((vio_msg_tag_t *)ver_pkt); 248906db247cSraghuram 249006db247cSraghuram (void) vsw_send_msg(ldcp, (void *)ver_pkt, 249106db247cSraghuram sizeof (vio_ver_msg_t), B_TRUE); 249206db247cSraghuram 249306db247cSraghuram vsw_next_milestone(ldcp); 249406db247cSraghuram 249506db247cSraghuram } 249606db247cSraghuram break; 249706db247cSraghuram 249806db247cSraghuram default: 249906db247cSraghuram DERR(vswp, "%s: unknown vio_subtype %x\n", __func__, 250006db247cSraghuram ver_pkt->tag.vio_subtype); 250106db247cSraghuram } 250206db247cSraghuram 250306db247cSraghuram D1(vswp, "%s(%lld): exit\n", __func__, ldcp->ldc_id); 250406db247cSraghuram } 250506db247cSraghuram 25067bd3a2e2SSriharsha Basavapatna static int 25077bd3a2e2SSriharsha Basavapatna vsw_process_attr_info(vsw_ldc_t *ldcp, vnet_attr_msg_t *msg) 250806db247cSraghuram { 250906db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 251006db247cSraghuram vsw_port_t *port = ldcp->ldc_port; 25117bd3a2e2SSriharsha Basavapatna struct ether_addr ea; 251206db247cSraghuram uint64_t macaddr = 0; 25137b1f684aSSriharsha Basavapatna lane_t *lane_out = &ldcp->lane_out; 25147b1f684aSSriharsha Basavapatna lane_t *lane_in = &ldcp->lane_in; 25157b1f684aSSriharsha Basavapatna uint32_t mtu; 251606db247cSraghuram int i; 25177bd3a2e2SSriharsha Basavapatna uint8_t dring_mode; 251806db247cSraghuram 251906db247cSraghuram D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__); 252006db247cSraghuram 25217bd3a2e2SSriharsha Basavapatna if (vsw_check_flag(ldcp, INBOUND, VSW_ATTR_INFO_RECV)) { 25227bd3a2e2SSriharsha Basavapatna return (1); 25237bd3a2e2SSriharsha Basavapatna } 25247bd3a2e2SSriharsha Basavapatna 25257bd3a2e2SSriharsha Basavapatna if ((msg->xfer_mode != VIO_DESC_MODE) && 25267bd3a2e2SSriharsha Basavapatna (msg->xfer_mode != lane_out->xfer_mode)) { 25277bd3a2e2SSriharsha Basavapatna D2(NULL, "%s: unknown mode %x\n", __func__, msg->xfer_mode); 25287bd3a2e2SSriharsha Basavapatna return (1); 25297bd3a2e2SSriharsha Basavapatna } 25307bd3a2e2SSriharsha Basavapatna 25317bd3a2e2SSriharsha Basavapatna /* Only support MAC addresses at moment. */ 25327bd3a2e2SSriharsha Basavapatna if ((msg->addr_type != ADDR_TYPE_MAC) || (msg->addr == 0)) { 25337bd3a2e2SSriharsha Basavapatna D2(NULL, "%s: invalid addr_type %x, or address 0x%llx\n", 25347bd3a2e2SSriharsha Basavapatna __func__, msg->addr_type, msg->addr); 25357bd3a2e2SSriharsha Basavapatna return (1); 25367bd3a2e2SSriharsha Basavapatna } 253706db247cSraghuram 253806db247cSraghuram /* 25397bd3a2e2SSriharsha Basavapatna * MAC address supplied by device should match that stored 25407bd3a2e2SSriharsha Basavapatna * in the vsw-port OBP node. Need to decide what to do if they 25417bd3a2e2SSriharsha Basavapatna * don't match, for the moment just warn but don't fail. 254206db247cSraghuram */ 25437bd3a2e2SSriharsha Basavapatna vnet_macaddr_ultostr(msg->addr, ea.ether_addr_octet); 25447bd3a2e2SSriharsha Basavapatna if (ether_cmp(&ea, &port->p_macaddr) != 0) { 25457bd3a2e2SSriharsha Basavapatna DERR(NULL, "%s: device supplied address " 25467bd3a2e2SSriharsha Basavapatna "0x%llx doesn't match node address 0x%llx\n", 25477bd3a2e2SSriharsha Basavapatna __func__, msg->addr, port->p_macaddr); 25487bd3a2e2SSriharsha Basavapatna } 254906db247cSraghuram 25507bd3a2e2SSriharsha Basavapatna /* 25517bd3a2e2SSriharsha Basavapatna * Ack freq only makes sense in pkt mode, in shared 25527bd3a2e2SSriharsha Basavapatna * mode the ring descriptors say whether or not to 25537bd3a2e2SSriharsha Basavapatna * send back an ACK. 25547bd3a2e2SSriharsha Basavapatna */ 25557bd3a2e2SSriharsha Basavapatna if ((VSW_VER_GTEQ(ldcp, 1, 2) && 25567bd3a2e2SSriharsha Basavapatna (msg->xfer_mode & VIO_DRING_MODE_V1_2)) || 25577bd3a2e2SSriharsha Basavapatna (VSW_VER_LT(ldcp, 1, 2) && 25587bd3a2e2SSriharsha Basavapatna (msg->xfer_mode == VIO_DRING_MODE_V1_0))) { 25597bd3a2e2SSriharsha Basavapatna if (msg->ack_freq > 0) { 25607bd3a2e2SSriharsha Basavapatna D2(NULL, "%s: non zero ack freq in SHM mode\n", 25617bd3a2e2SSriharsha Basavapatna __func__); 25627bd3a2e2SSriharsha Basavapatna return (1); 25637bd3a2e2SSriharsha Basavapatna } 25647bd3a2e2SSriharsha Basavapatna } 256506db247cSraghuram 25667bd3a2e2SSriharsha Basavapatna /* 25677bd3a2e2SSriharsha Basavapatna * Process dring mode attribute. 25687bd3a2e2SSriharsha Basavapatna */ 25697bd3a2e2SSriharsha Basavapatna if (VSW_VER_GTEQ(ldcp, 1, 6)) { 25707bd3a2e2SSriharsha Basavapatna /* 25717bd3a2e2SSriharsha Basavapatna * Versions >= 1.6: 25727bd3a2e2SSriharsha Basavapatna * Though we are operating in v1.6 mode, it is possible that 25737bd3a2e2SSriharsha Basavapatna * RxDringData mode has been disabled either on this guest or 25747bd3a2e2SSriharsha Basavapatna * on the peer guest. If so, we revert to pre v1.6 behavior of 25757bd3a2e2SSriharsha Basavapatna * TxDring mode. But this must be agreed upon in both 25767bd3a2e2SSriharsha Basavapatna * directions of attr exchange. We first determine the mode 25777bd3a2e2SSriharsha Basavapatna * that can be negotiated. 25787bd3a2e2SSriharsha Basavapatna */ 25797bd3a2e2SSriharsha Basavapatna if ((msg->options & VIO_RX_DRING_DATA) != 0 && 2580*34f94fbcSWENTAO YANG vsw_mapin_avail(ldcp) == B_TRUE) { 25817bd3a2e2SSriharsha Basavapatna /* 25827bd3a2e2SSriharsha Basavapatna * The peer is capable of handling RxDringData AND we 25837bd3a2e2SSriharsha Basavapatna * are also capable of it; we enable RxDringData mode 25847bd3a2e2SSriharsha Basavapatna * on this channel. 25857bd3a2e2SSriharsha Basavapatna */ 25867bd3a2e2SSriharsha Basavapatna dring_mode = VIO_RX_DRING_DATA; 25877bd3a2e2SSriharsha Basavapatna } else if ((msg->options & VIO_TX_DRING) != 0) { 25887bd3a2e2SSriharsha Basavapatna /* 25897bd3a2e2SSriharsha Basavapatna * If the peer is capable of TxDring mode, we 25907bd3a2e2SSriharsha Basavapatna * negotiate TxDring mode on this channel. 25917bd3a2e2SSriharsha Basavapatna */ 25927bd3a2e2SSriharsha Basavapatna dring_mode = VIO_TX_DRING; 25937b1f684aSSriharsha Basavapatna } else { 25947bd3a2e2SSriharsha Basavapatna /* 25957bd3a2e2SSriharsha Basavapatna * We support only VIO_TX_DRING and VIO_RX_DRING_DATA 25967bd3a2e2SSriharsha Basavapatna * modes. We don't support VIO_RX_DRING mode. 25977bd3a2e2SSriharsha Basavapatna */ 25987bd3a2e2SSriharsha Basavapatna return (1); 25997bd3a2e2SSriharsha Basavapatna } 26007b1f684aSSriharsha Basavapatna 26017bd3a2e2SSriharsha Basavapatna /* 26027bd3a2e2SSriharsha Basavapatna * If we have received an ack for the attr info that we sent, 26037bd3a2e2SSriharsha Basavapatna * then check if the dring mode matches what the peer had ack'd 26047bd3a2e2SSriharsha Basavapatna * (saved in lane_out). If they don't match, we fail the 26057bd3a2e2SSriharsha Basavapatna * handshake. 26067bd3a2e2SSriharsha Basavapatna */ 26077bd3a2e2SSriharsha Basavapatna if (lane_out->lstate & VSW_ATTR_ACK_RECV) { 26087bd3a2e2SSriharsha Basavapatna if (msg->options != lane_out->dring_mode) { 26097bd3a2e2SSriharsha Basavapatna /* send NACK */ 26107bd3a2e2SSriharsha Basavapatna return (1); 26117bd3a2e2SSriharsha Basavapatna } 26127bd3a2e2SSriharsha Basavapatna } else { 26137bd3a2e2SSriharsha Basavapatna /* 26147bd3a2e2SSriharsha Basavapatna * Save the negotiated dring mode in our attr 26157bd3a2e2SSriharsha Basavapatna * parameters, so it gets sent in the attr info from us 26167bd3a2e2SSriharsha Basavapatna * to the peer. 26177bd3a2e2SSriharsha Basavapatna */ 26187bd3a2e2SSriharsha Basavapatna lane_out->dring_mode = dring_mode; 26197bd3a2e2SSriharsha Basavapatna } 26207bd3a2e2SSriharsha Basavapatna 26217bd3a2e2SSriharsha Basavapatna /* save the negotiated dring mode in the msg to be replied */ 26227bd3a2e2SSriharsha Basavapatna msg->options = dring_mode; 26237bd3a2e2SSriharsha Basavapatna } 26247bd3a2e2SSriharsha Basavapatna 26257bd3a2e2SSriharsha Basavapatna /* 26267bd3a2e2SSriharsha Basavapatna * Process MTU attribute. 26277bd3a2e2SSriharsha Basavapatna */ 26287b1f684aSSriharsha Basavapatna if (VSW_VER_GTEQ(ldcp, 1, 4)) { 26297b1f684aSSriharsha Basavapatna /* 26307b1f684aSSriharsha Basavapatna * Versions >= 1.4: 26317bd3a2e2SSriharsha Basavapatna * Validate mtu of the peer is at least ETHERMAX. Then, the mtu 26327bd3a2e2SSriharsha Basavapatna * is negotiated down to the minimum of our mtu and peer's mtu. 26337b1f684aSSriharsha Basavapatna */ 26347bd3a2e2SSriharsha Basavapatna if (msg->mtu < ETHERMAX) { 26357bd3a2e2SSriharsha Basavapatna return (1); 26367bd3a2e2SSriharsha Basavapatna } 26377bd3a2e2SSriharsha Basavapatna 26387bd3a2e2SSriharsha Basavapatna mtu = MIN(msg->mtu, vswp->max_frame_size); 26397b1f684aSSriharsha Basavapatna 26407b1f684aSSriharsha Basavapatna /* 26417b1f684aSSriharsha Basavapatna * If we have received an ack for the attr info 26427b1f684aSSriharsha Basavapatna * that we sent, then check if the mtu computed 26437b1f684aSSriharsha Basavapatna * above matches the mtu that the peer had ack'd 26447b1f684aSSriharsha Basavapatna * (saved in local hparams). If they don't 26457b1f684aSSriharsha Basavapatna * match, we fail the handshake. 26467b1f684aSSriharsha Basavapatna */ 26477b1f684aSSriharsha Basavapatna if (lane_out->lstate & VSW_ATTR_ACK_RECV) { 26487b1f684aSSriharsha Basavapatna if (mtu != lane_out->mtu) { 26497b1f684aSSriharsha Basavapatna /* send NACK */ 26507bd3a2e2SSriharsha Basavapatna return (1); 26517b1f684aSSriharsha Basavapatna } 26527b1f684aSSriharsha Basavapatna } else { 26537b1f684aSSriharsha Basavapatna /* 26547b1f684aSSriharsha Basavapatna * Save the mtu computed above in our 26557b1f684aSSriharsha Basavapatna * attr parameters, so it gets sent in 26567b1f684aSSriharsha Basavapatna * the attr info from us to the peer. 26577b1f684aSSriharsha Basavapatna */ 26587b1f684aSSriharsha Basavapatna lane_out->mtu = mtu; 26597b1f684aSSriharsha Basavapatna } 26607bd3a2e2SSriharsha Basavapatna 26617bd3a2e2SSriharsha Basavapatna /* save the MIN mtu in the msg to be replied */ 26627bd3a2e2SSriharsha Basavapatna msg->mtu = mtu; 26637bd3a2e2SSriharsha Basavapatna } else { 26647bd3a2e2SSriharsha Basavapatna /* Versions < 1.4, mtu must match */ 26657bd3a2e2SSriharsha Basavapatna if (msg->mtu != lane_out->mtu) { 26667bd3a2e2SSriharsha Basavapatna D2(NULL, "%s: invalid MTU (0x%llx)\n", 26677bd3a2e2SSriharsha Basavapatna __func__, msg->mtu); 26687bd3a2e2SSriharsha Basavapatna return (1); 26697b1f684aSSriharsha Basavapatna } 267006db247cSraghuram } 267106db247cSraghuram 267206db247cSraghuram /* 267306db247cSraghuram * Otherwise store attributes for this lane and update 267406db247cSraghuram * lane state. 267506db247cSraghuram */ 26767bd3a2e2SSriharsha Basavapatna lane_in->mtu = msg->mtu; 26777bd3a2e2SSriharsha Basavapatna lane_in->addr = msg->addr; 26787bd3a2e2SSriharsha Basavapatna lane_in->addr_type = msg->addr_type; 26797bd3a2e2SSriharsha Basavapatna lane_in->xfer_mode = msg->xfer_mode; 26807bd3a2e2SSriharsha Basavapatna lane_in->ack_freq = msg->ack_freq; 26817bd3a2e2SSriharsha Basavapatna lane_in->physlink_update = msg->physlink_update; 26827bd3a2e2SSriharsha Basavapatna lane_in->dring_mode = msg->options; 26831107ea93SSriharsha Basavapatna 26841107ea93SSriharsha Basavapatna /* 26851107ea93SSriharsha Basavapatna * Check if the client has requested physlink state updates. 26861107ea93SSriharsha Basavapatna * If there is a physical device bound to this vswitch (L2 26871107ea93SSriharsha Basavapatna * mode), set the ack bits to indicate it is supported. 26881107ea93SSriharsha Basavapatna * Otherwise, set the nack bits. 26891107ea93SSriharsha Basavapatna */ 26901107ea93SSriharsha Basavapatna if (VSW_VER_GTEQ(ldcp, 1, 5)) { /* Protocol ver >= 1.5 */ 26911107ea93SSriharsha Basavapatna 26921107ea93SSriharsha Basavapatna /* Does the vnet need phys link state updates ? */ 26931107ea93SSriharsha Basavapatna if ((lane_in->physlink_update & 26941107ea93SSriharsha Basavapatna PHYSLINK_UPDATE_STATE_MASK) == 26951107ea93SSriharsha Basavapatna PHYSLINK_UPDATE_STATE) { 26961107ea93SSriharsha Basavapatna 26971107ea93SSriharsha Basavapatna if (vswp->smode & VSW_LAYER2) { 26981107ea93SSriharsha Basavapatna /* is a net-dev assigned to us ? */ 26997bd3a2e2SSriharsha Basavapatna msg->physlink_update = 27001107ea93SSriharsha Basavapatna PHYSLINK_UPDATE_STATE_ACK; 27011107ea93SSriharsha Basavapatna ldcp->pls_negotiated = B_TRUE; 27021107ea93SSriharsha Basavapatna } else { 27031107ea93SSriharsha Basavapatna /* not in L2 mode */ 27047bd3a2e2SSriharsha Basavapatna msg->physlink_update = 27051107ea93SSriharsha Basavapatna PHYSLINK_UPDATE_STATE_NACK; 27061107ea93SSriharsha Basavapatna ldcp->pls_negotiated = B_FALSE; 27071107ea93SSriharsha Basavapatna } 27081107ea93SSriharsha Basavapatna 27091107ea93SSriharsha Basavapatna } else { 27107bd3a2e2SSriharsha Basavapatna msg->physlink_update = 27111107ea93SSriharsha Basavapatna PHYSLINK_UPDATE_NONE; 27121107ea93SSriharsha Basavapatna ldcp->pls_negotiated = B_FALSE; 27131107ea93SSriharsha Basavapatna } 27141107ea93SSriharsha Basavapatna 27151107ea93SSriharsha Basavapatna } else { 27161107ea93SSriharsha Basavapatna /* 27171107ea93SSriharsha Basavapatna * physlink_update bits are ignored 27181107ea93SSriharsha Basavapatna * if set by clients < v1.5 protocol. 27191107ea93SSriharsha Basavapatna */ 27207bd3a2e2SSriharsha Basavapatna msg->physlink_update = PHYSLINK_UPDATE_NONE; 27211107ea93SSriharsha Basavapatna ldcp->pls_negotiated = B_FALSE; 27221107ea93SSriharsha Basavapatna } 272306db247cSraghuram 27247b1f684aSSriharsha Basavapatna macaddr = lane_in->addr; 272506db247cSraghuram for (i = ETHERADDRL - 1; i >= 0; i--) { 272606db247cSraghuram port->p_macaddr.ether_addr_octet[i] = macaddr & 0xFF; 272706db247cSraghuram macaddr >>= 8; 272806db247cSraghuram } 272906db247cSraghuram 27307bd3a2e2SSriharsha Basavapatna /* 27317bd3a2e2SSriharsha Basavapatna * Setup device specific xmit routines. Note this could be changed 27327bd3a2e2SSriharsha Basavapatna * further in vsw_send_dring_info() for versions >= 1.6 if operating in 27337bd3a2e2SSriharsha Basavapatna * RxDringData mode. 27347bd3a2e2SSriharsha Basavapatna */ 273506db247cSraghuram mutex_enter(&port->tx_lock); 27367bd3a2e2SSriharsha Basavapatna 2737c1c61f44Ssb155480 if ((VSW_VER_GTEQ(ldcp, 1, 2) && 27387b1f684aSSriharsha Basavapatna (lane_in->xfer_mode & VIO_DRING_MODE_V1_2)) || 2739f0ca1d9aSsb155480 (VSW_VER_LT(ldcp, 1, 2) && 27407b1f684aSSriharsha Basavapatna (lane_in->xfer_mode == VIO_DRING_MODE_V1_0))) { 274106db247cSraghuram D2(vswp, "%s: mode = VIO_DRING_MODE", __func__); 274206db247cSraghuram port->transmit = vsw_dringsend; 27437b1f684aSSriharsha Basavapatna } else if (lane_in->xfer_mode == VIO_DESC_MODE) { 274406db247cSraghuram D2(vswp, "%s: mode = VIO_DESC_MODE", __func__); 274506db247cSraghuram vsw_create_privring(ldcp); 274606db247cSraghuram port->transmit = vsw_descrsend; 27477b1f684aSSriharsha Basavapatna lane_out->xfer_mode = VIO_DESC_MODE; 274806db247cSraghuram } 2749678453a8Sspeer 2750678453a8Sspeer /* 2751678453a8Sspeer * HybridIO is supported only vnet, not by OBP. 2752678453a8Sspeer * So, set hio_capable to true only when in DRING mode. 2753678453a8Sspeer */ 2754678453a8Sspeer if (VSW_VER_GTEQ(ldcp, 1, 3) && 27557b1f684aSSriharsha Basavapatna (lane_in->xfer_mode != VIO_DESC_MODE)) { 2756678453a8Sspeer (void) atomic_swap_32(&port->p_hio_capable, B_TRUE); 2757678453a8Sspeer } else { 2758678453a8Sspeer (void) atomic_swap_32(&port->p_hio_capable, B_FALSE); 2759678453a8Sspeer } 2760678453a8Sspeer 276106db247cSraghuram mutex_exit(&port->tx_lock); 276206db247cSraghuram 27637bd3a2e2SSriharsha Basavapatna return (0); 27647bd3a2e2SSriharsha Basavapatna } 276506db247cSraghuram 27667bd3a2e2SSriharsha Basavapatna static int 27677bd3a2e2SSriharsha Basavapatna vsw_process_attr_ack(vsw_ldc_t *ldcp, vnet_attr_msg_t *msg) 27687bd3a2e2SSriharsha Basavapatna { 27697bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 27707bd3a2e2SSriharsha Basavapatna lane_t *lane_out = &ldcp->lane_out; 27717bd3a2e2SSriharsha Basavapatna lane_t *lane_in = &ldcp->lane_in; 277206db247cSraghuram 277306db247cSraghuram D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__); 277406db247cSraghuram 27757bd3a2e2SSriharsha Basavapatna if (vsw_check_flag(ldcp, OUTBOUND, VSW_ATTR_ACK_RECV)) { 27767bd3a2e2SSriharsha Basavapatna return (1); 27777bd3a2e2SSriharsha Basavapatna } 277806db247cSraghuram 27797bd3a2e2SSriharsha Basavapatna /* 27807bd3a2e2SSriharsha Basavapatna * Process dring mode attribute. 27817bd3a2e2SSriharsha Basavapatna */ 27827bd3a2e2SSriharsha Basavapatna if (VSW_VER_GTEQ(ldcp, 1, 6)) { 27837bd3a2e2SSriharsha Basavapatna /* 27847bd3a2e2SSriharsha Basavapatna * Versions >= 1.6: 27857bd3a2e2SSriharsha Basavapatna * The ack msg sent by the peer contains the negotiated dring 27867bd3a2e2SSriharsha Basavapatna * mode between our capability (that we had sent in our attr 27877bd3a2e2SSriharsha Basavapatna * info) and the peer's capability. 27887bd3a2e2SSriharsha Basavapatna */ 27897bd3a2e2SSriharsha Basavapatna if (lane_in->lstate & VSW_ATTR_ACK_SENT) { 27907bd3a2e2SSriharsha Basavapatna /* 27917bd3a2e2SSriharsha Basavapatna * If we have sent an ack for the attr info msg from 27927bd3a2e2SSriharsha Basavapatna * the peer, check if the dring mode that was 27937bd3a2e2SSriharsha Basavapatna * negotiated then (saved in lane_out) matches the 27947bd3a2e2SSriharsha Basavapatna * mode that the peer has ack'd. If they don't match, 27957bd3a2e2SSriharsha Basavapatna * we fail the handshake. 27967bd3a2e2SSriharsha Basavapatna */ 27977bd3a2e2SSriharsha Basavapatna if (lane_out->dring_mode != msg->options) { 27987bd3a2e2SSriharsha Basavapatna return (1); 27997bd3a2e2SSriharsha Basavapatna } 28007bd3a2e2SSriharsha Basavapatna } else { 28017bd3a2e2SSriharsha Basavapatna if ((msg->options & lane_out->dring_mode) == 0) { 28027bd3a2e2SSriharsha Basavapatna /* 28037bd3a2e2SSriharsha Basavapatna * Peer ack'd with a mode that we don't 28047bd3a2e2SSriharsha Basavapatna * support; we fail the handshake. 28057bd3a2e2SSriharsha Basavapatna */ 28067bd3a2e2SSriharsha Basavapatna return (1); 28077bd3a2e2SSriharsha Basavapatna } 28087bd3a2e2SSriharsha Basavapatna if ((msg->options & (VIO_TX_DRING|VIO_RX_DRING_DATA)) 28097bd3a2e2SSriharsha Basavapatna == (VIO_TX_DRING|VIO_RX_DRING_DATA)) { 28107bd3a2e2SSriharsha Basavapatna /* 28117bd3a2e2SSriharsha Basavapatna * Peer must ack with only one negotiated mode. 28127bd3a2e2SSriharsha Basavapatna * Otherwise fail handshake. 28137bd3a2e2SSriharsha Basavapatna */ 28147bd3a2e2SSriharsha Basavapatna return (1); 28157bd3a2e2SSriharsha Basavapatna } 28167bd3a2e2SSriharsha Basavapatna 28177bd3a2e2SSriharsha Basavapatna /* 28187bd3a2e2SSriharsha Basavapatna * Save the negotiated mode, so we can validate it when 28197bd3a2e2SSriharsha Basavapatna * we receive attr info from the peer. 28207bd3a2e2SSriharsha Basavapatna */ 28217bd3a2e2SSriharsha Basavapatna lane_out->dring_mode = msg->options; 28227bd3a2e2SSriharsha Basavapatna } 28237bd3a2e2SSriharsha Basavapatna } 28247bd3a2e2SSriharsha Basavapatna 28257bd3a2e2SSriharsha Basavapatna /* 28267bd3a2e2SSriharsha Basavapatna * Process MTU attribute. 28277bd3a2e2SSriharsha Basavapatna */ 28287b1f684aSSriharsha Basavapatna if (VSW_VER_GTEQ(ldcp, 1, 4)) { 28297b1f684aSSriharsha Basavapatna /* 28307b1f684aSSriharsha Basavapatna * Versions >= 1.4: 28317b1f684aSSriharsha Basavapatna * The ack msg sent by the peer contains the minimum of 28327b1f684aSSriharsha Basavapatna * our mtu (that we had sent in our attr info) and the 28337b1f684aSSriharsha Basavapatna * peer's mtu. 28347b1f684aSSriharsha Basavapatna * 28357b1f684aSSriharsha Basavapatna * If we have sent an ack for the attr info msg from 28367b1f684aSSriharsha Basavapatna * the peer, check if the mtu that was computed then 28377b1f684aSSriharsha Basavapatna * (saved in lane_out params) matches the mtu that the 28387b1f684aSSriharsha Basavapatna * peer has ack'd. If they don't match, we fail the 28397b1f684aSSriharsha Basavapatna * handshake. 28407b1f684aSSriharsha Basavapatna */ 28417b1f684aSSriharsha Basavapatna if (lane_in->lstate & VSW_ATTR_ACK_SENT) { 28427bd3a2e2SSriharsha Basavapatna if (lane_out->mtu != msg->mtu) { 28437bd3a2e2SSriharsha Basavapatna return (1); 28447b1f684aSSriharsha Basavapatna } 28457b1f684aSSriharsha Basavapatna } else { 28467b1f684aSSriharsha Basavapatna /* 28477b1f684aSSriharsha Basavapatna * If the mtu ack'd by the peer is > our mtu 28487b1f684aSSriharsha Basavapatna * fail handshake. Otherwise, save the mtu, so 28497b1f684aSSriharsha Basavapatna * we can validate it when we receive attr info 28507b1f684aSSriharsha Basavapatna * from our peer. 28517b1f684aSSriharsha Basavapatna */ 28527bd3a2e2SSriharsha Basavapatna if (msg->mtu <= lane_out->mtu) { 28537bd3a2e2SSriharsha Basavapatna lane_out->mtu = msg->mtu; 28547bd3a2e2SSriharsha Basavapatna } else { 28557bd3a2e2SSriharsha Basavapatna return (1); 28567b1f684aSSriharsha Basavapatna } 28577b1f684aSSriharsha Basavapatna } 28587b1f684aSSriharsha Basavapatna } 28597b1f684aSSriharsha Basavapatna 28607bd3a2e2SSriharsha Basavapatna return (0); 28617bd3a2e2SSriharsha Basavapatna } 28627bd3a2e2SSriharsha Basavapatna 28637bd3a2e2SSriharsha Basavapatna /* 28647bd3a2e2SSriharsha Basavapatna * Process an attribute packet. We can end up here either because our peer 28657bd3a2e2SSriharsha Basavapatna * has ACK/NACK'ed back to an earlier ATTR msg we had sent it, or our 28667bd3a2e2SSriharsha Basavapatna * peer has sent us an attribute INFO message 28677bd3a2e2SSriharsha Basavapatna * 28687bd3a2e2SSriharsha Basavapatna * If its an ACK we then move to the next stage of the handshake which 28697bd3a2e2SSriharsha Basavapatna * is to send our descriptor ring info to our peer. If its a NACK then 28707bd3a2e2SSriharsha Basavapatna * there is nothing more we can (currently) do. 28717bd3a2e2SSriharsha Basavapatna * 28727bd3a2e2SSriharsha Basavapatna * If we get a valid/acceptable INFO packet (and we have already negotiated 28737bd3a2e2SSriharsha Basavapatna * a version) we ACK back and set channel state to ATTR_RECV, otherwise we 28747bd3a2e2SSriharsha Basavapatna * NACK back and reset channel state to INACTIV. 28757bd3a2e2SSriharsha Basavapatna * 28767bd3a2e2SSriharsha Basavapatna * FUTURE: in time we will probably negotiate over attributes, but for 28777bd3a2e2SSriharsha Basavapatna * the moment unacceptable attributes are regarded as a fatal error. 28787bd3a2e2SSriharsha Basavapatna * 28797bd3a2e2SSriharsha Basavapatna */ 28807bd3a2e2SSriharsha Basavapatna void 28817bd3a2e2SSriharsha Basavapatna vsw_process_ctrl_attr_pkt(vsw_ldc_t *ldcp, void *pkt) 28827bd3a2e2SSriharsha Basavapatna { 28837bd3a2e2SSriharsha Basavapatna vnet_attr_msg_t *attr_pkt; 28847bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 28857bd3a2e2SSriharsha Basavapatna lane_t *lane_out = &ldcp->lane_out; 28867bd3a2e2SSriharsha Basavapatna lane_t *lane_in = &ldcp->lane_in; 28877bd3a2e2SSriharsha Basavapatna int rv; 28887bd3a2e2SSriharsha Basavapatna 28897bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id); 28907bd3a2e2SSriharsha Basavapatna 28917bd3a2e2SSriharsha Basavapatna /* 28927bd3a2e2SSriharsha Basavapatna * We know this is a ctrl/attr packet so 28937bd3a2e2SSriharsha Basavapatna * cast it into the correct structure. 28947bd3a2e2SSriharsha Basavapatna */ 28957bd3a2e2SSriharsha Basavapatna attr_pkt = (vnet_attr_msg_t *)pkt; 28967bd3a2e2SSriharsha Basavapatna 28977bd3a2e2SSriharsha Basavapatna switch (attr_pkt->tag.vio_subtype) { 28987bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_INFO: 28997bd3a2e2SSriharsha Basavapatna 29007bd3a2e2SSriharsha Basavapatna rv = vsw_process_attr_info(ldcp, attr_pkt); 29017bd3a2e2SSriharsha Basavapatna if (rv != 0) { 29027bd3a2e2SSriharsha Basavapatna vsw_free_lane_resources(ldcp, INBOUND); 29037bd3a2e2SSriharsha Basavapatna attr_pkt->tag.vio_subtype = VIO_SUBTYPE_NACK; 29047bd3a2e2SSriharsha Basavapatna ldcp->lane_in.lstate |= VSW_ATTR_NACK_SENT; 29057bd3a2e2SSriharsha Basavapatna } else { 29067bd3a2e2SSriharsha Basavapatna attr_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK; 29077bd3a2e2SSriharsha Basavapatna lane_in->lstate |= VSW_ATTR_ACK_SENT; 29087bd3a2e2SSriharsha Basavapatna } 29097bd3a2e2SSriharsha Basavapatna attr_pkt->tag.vio_sid = ldcp->local_session; 29107bd3a2e2SSriharsha Basavapatna DUMP_TAG_PTR((vio_msg_tag_t *)attr_pkt); 29117bd3a2e2SSriharsha Basavapatna (void) vsw_send_msg(ldcp, (void *)attr_pkt, 29127bd3a2e2SSriharsha Basavapatna sizeof (vnet_attr_msg_t), B_TRUE); 29137bd3a2e2SSriharsha Basavapatna vsw_next_milestone(ldcp); 29147bd3a2e2SSriharsha Basavapatna break; 29157bd3a2e2SSriharsha Basavapatna 29167bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_ACK: 29177bd3a2e2SSriharsha Basavapatna 29187bd3a2e2SSriharsha Basavapatna rv = vsw_process_attr_ack(ldcp, attr_pkt); 29197bd3a2e2SSriharsha Basavapatna if (rv != 0) { 29207bd3a2e2SSriharsha Basavapatna return; 29217bd3a2e2SSriharsha Basavapatna } 29227b1f684aSSriharsha Basavapatna lane_out->lstate |= VSW_ATTR_ACK_RECV; 292306db247cSraghuram vsw_next_milestone(ldcp); 292406db247cSraghuram break; 292506db247cSraghuram 292606db247cSraghuram case VIO_SUBTYPE_NACK: 292706db247cSraghuram D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__); 292806db247cSraghuram 292906db247cSraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_ATTR_NACK_RECV)) 293006db247cSraghuram return; 293106db247cSraghuram 29327b1f684aSSriharsha Basavapatna lane_out->lstate |= VSW_ATTR_NACK_RECV; 293306db247cSraghuram vsw_next_milestone(ldcp); 293406db247cSraghuram break; 293506db247cSraghuram 293606db247cSraghuram default: 293706db247cSraghuram DERR(vswp, "%s: unknown vio_subtype %x\n", __func__, 293806db247cSraghuram attr_pkt->tag.vio_subtype); 293906db247cSraghuram } 294006db247cSraghuram 294106db247cSraghuram D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id); 294206db247cSraghuram } 294306db247cSraghuram 29447bd3a2e2SSriharsha Basavapatna static int 29457bd3a2e2SSriharsha Basavapatna vsw_process_dring_reg_info(vsw_ldc_t *ldcp, vio_msg_tag_t *tagp) 29467bd3a2e2SSriharsha Basavapatna { 29477bd3a2e2SSriharsha Basavapatna int rv; 29487bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 29497bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_out; 29507bd3a2e2SSriharsha Basavapatna dring_info_t *dp = NULL; 29517bd3a2e2SSriharsha Basavapatna 29527bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__); 29537bd3a2e2SSriharsha Basavapatna 29547bd3a2e2SSriharsha Basavapatna rv = vsw_check_flag(ldcp, INBOUND, VSW_DRING_INFO_RECV); 29557bd3a2e2SSriharsha Basavapatna if (rv != 0) { 29567bd3a2e2SSriharsha Basavapatna return (1); 29577bd3a2e2SSriharsha Basavapatna } 29587bd3a2e2SSriharsha Basavapatna 29597bd3a2e2SSriharsha Basavapatna if (VSW_VER_GTEQ(ldcp, 1, 6) && 29607bd3a2e2SSriharsha Basavapatna (lp->dring_mode != ((vio_dring_reg_msg_t *)tagp)->options)) { 29617bd3a2e2SSriharsha Basavapatna /* 29627bd3a2e2SSriharsha Basavapatna * The earlier version of Solaris vnet driver doesn't set the 29637bd3a2e2SSriharsha Basavapatna * option (VIO_TX_DRING in its case) correctly in its dring reg 29647bd3a2e2SSriharsha Basavapatna * message. We workaround that here by doing the check only 29657bd3a2e2SSriharsha Basavapatna * for versions >= v1.6. 29667bd3a2e2SSriharsha Basavapatna */ 29677bd3a2e2SSriharsha Basavapatna DWARN(vswp, "%s(%lld): Rcvd dring reg option (%d), " 29687bd3a2e2SSriharsha Basavapatna "negotiated mode (%d)\n", __func__, ldcp->ldc_id, 29697bd3a2e2SSriharsha Basavapatna ((vio_dring_reg_msg_t *)tagp)->options, lp->dring_mode); 29707bd3a2e2SSriharsha Basavapatna return (1); 29717bd3a2e2SSriharsha Basavapatna } 29727bd3a2e2SSriharsha Basavapatna 29737bd3a2e2SSriharsha Basavapatna /* 29747bd3a2e2SSriharsha Basavapatna * Map dring exported by the peer. 29757bd3a2e2SSriharsha Basavapatna */ 29767bd3a2e2SSriharsha Basavapatna dp = vsw_map_dring(ldcp, (void *)tagp); 29777bd3a2e2SSriharsha Basavapatna if (dp == NULL) { 29787bd3a2e2SSriharsha Basavapatna return (1); 29797bd3a2e2SSriharsha Basavapatna } 29807bd3a2e2SSriharsha Basavapatna 29817bd3a2e2SSriharsha Basavapatna /* 29827bd3a2e2SSriharsha Basavapatna * Map data buffers exported by the peer if we are in RxDringData mode. 29837bd3a2e2SSriharsha Basavapatna */ 29847bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 29857bd3a2e2SSriharsha Basavapatna rv = vsw_map_data(ldcp, dp, (void *)tagp); 29867bd3a2e2SSriharsha Basavapatna if (rv != 0) { 29877bd3a2e2SSriharsha Basavapatna vsw_unmap_dring(ldcp); 29887bd3a2e2SSriharsha Basavapatna return (1); 29897bd3a2e2SSriharsha Basavapatna } 29907bd3a2e2SSriharsha Basavapatna } 29917bd3a2e2SSriharsha Basavapatna 29927bd3a2e2SSriharsha Basavapatna return (0); 29937bd3a2e2SSriharsha Basavapatna } 29947bd3a2e2SSriharsha Basavapatna 29957bd3a2e2SSriharsha Basavapatna static int 29967bd3a2e2SSriharsha Basavapatna vsw_process_dring_reg_ack(vsw_ldc_t *ldcp, vio_msg_tag_t *tagp) 29977bd3a2e2SSriharsha Basavapatna { 29987bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 29997bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 30007bd3a2e2SSriharsha Basavapatna 30017bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__); 30027bd3a2e2SSriharsha Basavapatna 30037bd3a2e2SSriharsha Basavapatna if (vsw_check_flag(ldcp, OUTBOUND, VSW_DRING_ACK_RECV)) { 30047bd3a2e2SSriharsha Basavapatna return (1); 30057bd3a2e2SSriharsha Basavapatna } 30067bd3a2e2SSriharsha Basavapatna 30077bd3a2e2SSriharsha Basavapatna dp = ldcp->lane_out.dringp; 30087bd3a2e2SSriharsha Basavapatna 30097bd3a2e2SSriharsha Basavapatna /* save dring_ident acked by peer */ 30107bd3a2e2SSriharsha Basavapatna dp->ident = ((vio_dring_reg_msg_t *)tagp)->dring_ident; 30117bd3a2e2SSriharsha Basavapatna 30127bd3a2e2SSriharsha Basavapatna return (0); 30137bd3a2e2SSriharsha Basavapatna } 30147bd3a2e2SSriharsha Basavapatna 301506db247cSraghuram /* 301606db247cSraghuram * Process a dring info packet. We can end up here either because our peer 301706db247cSraghuram * has ACK/NACK'ed back to an earlier DRING msg we had sent it, or our 301806db247cSraghuram * peer has sent us a dring INFO message. 301906db247cSraghuram * 302006db247cSraghuram * If we get a valid/acceptable INFO packet (and we have already negotiated 302106db247cSraghuram * a version) we ACK back and update the lane state, otherwise we NACK back. 302206db247cSraghuram * 302306db247cSraghuram * FUTURE: nothing to stop client from sending us info on multiple dring's 302406db247cSraghuram * but for the moment we will just use the first one we are given. 302506db247cSraghuram * 302606db247cSraghuram */ 302706db247cSraghuram void 302806db247cSraghuram vsw_process_ctrl_dring_reg_pkt(vsw_ldc_t *ldcp, void *pkt) 302906db247cSraghuram { 30307bd3a2e2SSriharsha Basavapatna int rv; 30317bd3a2e2SSriharsha Basavapatna int msgsize; 30327bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 30337bd3a2e2SSriharsha Basavapatna vio_msg_tag_t *tagp = (vio_msg_tag_t *)pkt; 303406db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 30357bd3a2e2SSriharsha Basavapatna lane_t *lane_out = &ldcp->lane_out; 30367bd3a2e2SSriharsha Basavapatna lane_t *lane_in = &ldcp->lane_in; 303706db247cSraghuram 303806db247cSraghuram D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id); 303906db247cSraghuram 30407bd3a2e2SSriharsha Basavapatna switch (tagp->vio_subtype) { 304106db247cSraghuram case VIO_SUBTYPE_INFO: 30427bd3a2e2SSriharsha Basavapatna rv = vsw_process_dring_reg_info(ldcp, tagp); 30437bd3a2e2SSriharsha Basavapatna if (rv != 0) { 304406db247cSraghuram vsw_free_lane_resources(ldcp, INBOUND); 30457bd3a2e2SSriharsha Basavapatna tagp->vio_subtype = VIO_SUBTYPE_NACK; 30467bd3a2e2SSriharsha Basavapatna lane_in->lstate |= VSW_DRING_NACK_SENT; 304706db247cSraghuram } else { 30487bd3a2e2SSriharsha Basavapatna tagp->vio_subtype = VIO_SUBTYPE_ACK; 30497bd3a2e2SSriharsha Basavapatna lane_in->lstate |= VSW_DRING_ACK_SENT; 305006db247cSraghuram } 30517bd3a2e2SSriharsha Basavapatna tagp->vio_sid = ldcp->local_session; 30527bd3a2e2SSriharsha Basavapatna DUMP_TAG_PTR(tagp); 30537bd3a2e2SSriharsha Basavapatna if (lane_out->dring_mode == VIO_RX_DRING_DATA) { 30547bd3a2e2SSriharsha Basavapatna dp = lane_in->dringp; 30557bd3a2e2SSriharsha Basavapatna msgsize = 30567bd3a2e2SSriharsha Basavapatna VNET_DRING_REG_EXT_MSG_SIZE(dp->data_ncookies); 305706db247cSraghuram } else { 30587bd3a2e2SSriharsha Basavapatna msgsize = sizeof (vio_dring_reg_msg_t); 305906db247cSraghuram } 30607bd3a2e2SSriharsha Basavapatna (void) vsw_send_msg(ldcp, (void *)tagp, msgsize, B_TRUE); 306106db247cSraghuram vsw_next_milestone(ldcp); 306206db247cSraghuram break; 306306db247cSraghuram 306406db247cSraghuram case VIO_SUBTYPE_ACK: 30657bd3a2e2SSriharsha Basavapatna rv = vsw_process_dring_reg_ack(ldcp, tagp); 30667bd3a2e2SSriharsha Basavapatna if (rv != 0) { 306706db247cSraghuram return; 306806db247cSraghuram } 30697bd3a2e2SSriharsha Basavapatna lane_out->lstate |= VSW_DRING_ACK_RECV; 307006db247cSraghuram vsw_next_milestone(ldcp); 307106db247cSraghuram break; 307206db247cSraghuram 307306db247cSraghuram case VIO_SUBTYPE_NACK: 307406db247cSraghuram D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__); 307506db247cSraghuram 307606db247cSraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_DRING_NACK_RECV)) 307706db247cSraghuram return; 307806db247cSraghuram 30797bd3a2e2SSriharsha Basavapatna lane_out->lstate |= VSW_DRING_NACK_RECV; 308006db247cSraghuram vsw_next_milestone(ldcp); 308106db247cSraghuram break; 308206db247cSraghuram 308306db247cSraghuram default: 308406db247cSraghuram DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__, 30857bd3a2e2SSriharsha Basavapatna tagp->vio_subtype); 308606db247cSraghuram } 308706db247cSraghuram 308806db247cSraghuram D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id); 308906db247cSraghuram } 309006db247cSraghuram 309106db247cSraghuram /* 309206db247cSraghuram * Process a request from peer to unregister a dring. 309306db247cSraghuram * 309406db247cSraghuram * For the moment we just restart the handshake if our 309506db247cSraghuram * peer endpoint attempts to unregister a dring. 309606db247cSraghuram */ 309706db247cSraghuram void 309806db247cSraghuram vsw_process_ctrl_dring_unreg_pkt(vsw_ldc_t *ldcp, void *pkt) 309906db247cSraghuram { 310006db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 310106db247cSraghuram vio_dring_unreg_msg_t *dring_pkt; 310206db247cSraghuram 310306db247cSraghuram /* 310406db247cSraghuram * We know this is a ctrl/dring packet so 310506db247cSraghuram * cast it into the correct structure. 310606db247cSraghuram */ 310706db247cSraghuram dring_pkt = (vio_dring_unreg_msg_t *)pkt; 310806db247cSraghuram 310906db247cSraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id); 311006db247cSraghuram 311106db247cSraghuram switch (dring_pkt->tag.vio_subtype) { 311206db247cSraghuram case VIO_SUBTYPE_INFO: 311306db247cSraghuram D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__); 311406db247cSraghuram 311506db247cSraghuram DWARN(vswp, "%s: restarting handshake..", __func__); 311606db247cSraghuram break; 311706db247cSraghuram 311806db247cSraghuram case VIO_SUBTYPE_ACK: 311906db247cSraghuram D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__); 312006db247cSraghuram 312106db247cSraghuram DWARN(vswp, "%s: restarting handshake..", __func__); 312206db247cSraghuram break; 312306db247cSraghuram 312406db247cSraghuram case VIO_SUBTYPE_NACK: 312506db247cSraghuram D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__); 312606db247cSraghuram 312706db247cSraghuram DWARN(vswp, "%s: restarting handshake..", __func__); 312806db247cSraghuram break; 312906db247cSraghuram 313006db247cSraghuram default: 313106db247cSraghuram DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__, 313206db247cSraghuram dring_pkt->tag.vio_subtype); 313306db247cSraghuram } 313406db247cSraghuram 313506db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 313606db247cSraghuram 313706db247cSraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id); 313806db247cSraghuram } 313906db247cSraghuram 314006db247cSraghuram #define SND_MCST_NACK(ldcp, pkt) \ 314106db247cSraghuram pkt->tag.vio_subtype = VIO_SUBTYPE_NACK; \ 314206db247cSraghuram pkt->tag.vio_sid = ldcp->local_session; \ 314306db247cSraghuram (void) vsw_send_msg(ldcp, (void *)pkt, \ 314406db247cSraghuram sizeof (vnet_mcast_msg_t), B_TRUE); 314506db247cSraghuram 314606db247cSraghuram /* 314706db247cSraghuram * Process a multicast request from a vnet. 314806db247cSraghuram * 314906db247cSraghuram * Vnet's specify a multicast address that they are interested in. This 315006db247cSraghuram * address is used as a key into the hash table which forms the multicast 315106db247cSraghuram * forwarding database (mFDB). 315206db247cSraghuram * 315306db247cSraghuram * The table keys are the multicast addresses, while the table entries 315406db247cSraghuram * are pointers to lists of ports which wish to receive packets for the 315506db247cSraghuram * specified multicast address. 315606db247cSraghuram * 315706db247cSraghuram * When a multicast packet is being switched we use the address as a key 315806db247cSraghuram * into the hash table, and then walk the appropriate port list forwarding 315906db247cSraghuram * the pkt to each port in turn. 316006db247cSraghuram * 316106db247cSraghuram * If a vnet is no longer interested in a particular multicast grouping 316206db247cSraghuram * we simply find the correct location in the hash table and then delete 316306db247cSraghuram * the relevant port from the port list. 316406db247cSraghuram * 316506db247cSraghuram * To deal with the case whereby a port is being deleted without first 316606db247cSraghuram * removing itself from the lists in the hash table, we maintain a list 316706db247cSraghuram * of multicast addresses the port has registered an interest in, within 316806db247cSraghuram * the port structure itself. We then simply walk that list of addresses 316906db247cSraghuram * using them as keys into the hash table and remove the port from the 317006db247cSraghuram * appropriate lists. 317106db247cSraghuram */ 317206db247cSraghuram static void 317306db247cSraghuram vsw_process_ctrl_mcst_pkt(vsw_ldc_t *ldcp, void *pkt) 317406db247cSraghuram { 317506db247cSraghuram vnet_mcast_msg_t *mcst_pkt; 317606db247cSraghuram vsw_port_t *port = ldcp->ldc_port; 317706db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 317806db247cSraghuram int i; 317906db247cSraghuram 318006db247cSraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id); 318106db247cSraghuram 318206db247cSraghuram /* 318306db247cSraghuram * We know this is a ctrl/mcast packet so 318406db247cSraghuram * cast it into the correct structure. 318506db247cSraghuram */ 318606db247cSraghuram mcst_pkt = (vnet_mcast_msg_t *)pkt; 318706db247cSraghuram 318806db247cSraghuram switch (mcst_pkt->tag.vio_subtype) { 318906db247cSraghuram case VIO_SUBTYPE_INFO: 319006db247cSraghuram D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__); 319106db247cSraghuram 319206db247cSraghuram /* 319306db247cSraghuram * Check if in correct state to receive a multicast 319406db247cSraghuram * message (i.e. handshake complete). If not reset 319506db247cSraghuram * the handshake. 319606db247cSraghuram */ 319706db247cSraghuram if (vsw_check_flag(ldcp, INBOUND, VSW_MCST_INFO_RECV)) 319806db247cSraghuram return; 319906db247cSraghuram 320006db247cSraghuram /* 320106db247cSraghuram * Before attempting to add or remove address check 320206db247cSraghuram * that they are valid multicast addresses. 320306db247cSraghuram * If not, then NACK back. 320406db247cSraghuram */ 320506db247cSraghuram for (i = 0; i < mcst_pkt->count; i++) { 320606db247cSraghuram if ((mcst_pkt->mca[i].ether_addr_octet[0] & 01) != 1) { 320706db247cSraghuram DERR(vswp, "%s: invalid multicast address", 320806db247cSraghuram __func__); 320906db247cSraghuram SND_MCST_NACK(ldcp, mcst_pkt); 321006db247cSraghuram return; 321106db247cSraghuram } 321206db247cSraghuram } 321306db247cSraghuram 321406db247cSraghuram /* 321506db247cSraghuram * Now add/remove the addresses. If this fails we 321606db247cSraghuram * NACK back. 321706db247cSraghuram */ 321806db247cSraghuram if (vsw_add_rem_mcst(mcst_pkt, port) != 0) { 321906db247cSraghuram SND_MCST_NACK(ldcp, mcst_pkt); 322006db247cSraghuram return; 322106db247cSraghuram } 322206db247cSraghuram 322306db247cSraghuram mcst_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK; 322406db247cSraghuram mcst_pkt->tag.vio_sid = ldcp->local_session; 322506db247cSraghuram 322606db247cSraghuram DUMP_TAG_PTR((vio_msg_tag_t *)mcst_pkt); 322706db247cSraghuram 322806db247cSraghuram (void) vsw_send_msg(ldcp, (void *)mcst_pkt, 322906db247cSraghuram sizeof (vnet_mcast_msg_t), B_TRUE); 323006db247cSraghuram break; 323106db247cSraghuram 323206db247cSraghuram case VIO_SUBTYPE_ACK: 323306db247cSraghuram DWARN(vswp, "%s: VIO_SUBTYPE_ACK", __func__); 323406db247cSraghuram 323506db247cSraghuram /* 323606db247cSraghuram * We shouldn't ever get a multicast ACK message as 323706db247cSraghuram * at the moment we never request multicast addresses 323806db247cSraghuram * to be set on some other device. This may change in 323906db247cSraghuram * the future if we have cascading switches. 324006db247cSraghuram */ 324106db247cSraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_MCST_ACK_RECV)) 324206db247cSraghuram return; 324306db247cSraghuram 324406db247cSraghuram /* Do nothing */ 324506db247cSraghuram break; 324606db247cSraghuram 324706db247cSraghuram case VIO_SUBTYPE_NACK: 324806db247cSraghuram DWARN(vswp, "%s: VIO_SUBTYPE_NACK", __func__); 324906db247cSraghuram 325006db247cSraghuram /* 325106db247cSraghuram * We shouldn't get a multicast NACK packet for the 325206db247cSraghuram * same reasons as we shouldn't get a ACK packet. 325306db247cSraghuram */ 325406db247cSraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_MCST_NACK_RECV)) 325506db247cSraghuram return; 325606db247cSraghuram 325706db247cSraghuram /* Do nothing */ 325806db247cSraghuram break; 325906db247cSraghuram 326006db247cSraghuram default: 326106db247cSraghuram DERR(vswp, "%s: unknown vio_subtype %x\n", __func__, 326206db247cSraghuram mcst_pkt->tag.vio_subtype); 326306db247cSraghuram } 326406db247cSraghuram 326506db247cSraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id); 326606db247cSraghuram } 326706db247cSraghuram 326806db247cSraghuram static void 326906db247cSraghuram vsw_process_ctrl_rdx_pkt(vsw_ldc_t *ldcp, void *pkt) 327006db247cSraghuram { 327106db247cSraghuram vio_rdx_msg_t *rdx_pkt; 327206db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 327306db247cSraghuram 327406db247cSraghuram /* 327506db247cSraghuram * We know this is a ctrl/rdx packet so 327606db247cSraghuram * cast it into the correct structure. 327706db247cSraghuram */ 327806db247cSraghuram rdx_pkt = (vio_rdx_msg_t *)pkt; 327906db247cSraghuram 328006db247cSraghuram D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id); 328106db247cSraghuram 328206db247cSraghuram switch (rdx_pkt->tag.vio_subtype) { 328306db247cSraghuram case VIO_SUBTYPE_INFO: 328406db247cSraghuram D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__); 328506db247cSraghuram 328606db247cSraghuram if (vsw_check_flag(ldcp, OUTBOUND, VSW_RDX_INFO_RECV)) 328706db247cSraghuram return; 328806db247cSraghuram 328906db247cSraghuram rdx_pkt->tag.vio_sid = ldcp->local_session; 329006db247cSraghuram rdx_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK; 329106db247cSraghuram 329206db247cSraghuram DUMP_TAG_PTR((vio_msg_tag_t *)rdx_pkt); 329306db247cSraghuram 329406db247cSraghuram ldcp->lane_out.lstate |= VSW_RDX_ACK_SENT; 329506db247cSraghuram 329606db247cSraghuram (void) vsw_send_msg(ldcp, (void *)rdx_pkt, 329706db247cSraghuram sizeof (vio_rdx_msg_t), B_TRUE); 329806db247cSraghuram 329906db247cSraghuram vsw_next_milestone(ldcp); 330006db247cSraghuram break; 330106db247cSraghuram 330206db247cSraghuram case VIO_SUBTYPE_ACK: 330306db247cSraghuram /* 330406db247cSraghuram * Should be handled in-band by callback handler. 330506db247cSraghuram */ 330606db247cSraghuram DERR(vswp, "%s: Unexpected VIO_SUBTYPE_ACK", __func__); 330706db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 330806db247cSraghuram break; 330906db247cSraghuram 331006db247cSraghuram case VIO_SUBTYPE_NACK: 331106db247cSraghuram D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__); 331206db247cSraghuram 331306db247cSraghuram if (vsw_check_flag(ldcp, INBOUND, VSW_RDX_NACK_RECV)) 331406db247cSraghuram return; 331506db247cSraghuram 331606db247cSraghuram ldcp->lane_in.lstate |= VSW_RDX_NACK_RECV; 331706db247cSraghuram vsw_next_milestone(ldcp); 331806db247cSraghuram break; 331906db247cSraghuram 332006db247cSraghuram default: 332106db247cSraghuram DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__, 332206db247cSraghuram rdx_pkt->tag.vio_subtype); 332306db247cSraghuram } 332406db247cSraghuram 332506db247cSraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id); 332606db247cSraghuram } 332706db247cSraghuram 332806db247cSraghuram static void 33291107ea93SSriharsha Basavapatna vsw_process_physlink_msg(vsw_ldc_t *ldcp, void *pkt) 33301107ea93SSriharsha Basavapatna { 33311107ea93SSriharsha Basavapatna vnet_physlink_msg_t *msgp; 33321107ea93SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 33331107ea93SSriharsha Basavapatna 33341107ea93SSriharsha Basavapatna msgp = (vnet_physlink_msg_t *)pkt; 33351107ea93SSriharsha Basavapatna 33361107ea93SSriharsha Basavapatna D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id); 33371107ea93SSriharsha Basavapatna 33381107ea93SSriharsha Basavapatna switch (msgp->tag.vio_subtype) { 33391107ea93SSriharsha Basavapatna case VIO_SUBTYPE_INFO: 33401107ea93SSriharsha Basavapatna 33411107ea93SSriharsha Basavapatna /* vsw shouldn't recv physlink info */ 33421107ea93SSriharsha Basavapatna DWARN(vswp, "%s: Unexpected VIO_SUBTYPE_INFO", __func__); 33431107ea93SSriharsha Basavapatna break; 33441107ea93SSriharsha Basavapatna 33451107ea93SSriharsha Basavapatna case VIO_SUBTYPE_ACK: 33461107ea93SSriharsha Basavapatna 33471107ea93SSriharsha Basavapatna D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__); 33481107ea93SSriharsha Basavapatna break; 33491107ea93SSriharsha Basavapatna 33501107ea93SSriharsha Basavapatna case VIO_SUBTYPE_NACK: 33511107ea93SSriharsha Basavapatna 33521107ea93SSriharsha Basavapatna D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__); 33531107ea93SSriharsha Basavapatna break; 33541107ea93SSriharsha Basavapatna 33551107ea93SSriharsha Basavapatna default: 33561107ea93SSriharsha Basavapatna DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__, 33571107ea93SSriharsha Basavapatna msgp->tag.vio_subtype); 33581107ea93SSriharsha Basavapatna } 33591107ea93SSriharsha Basavapatna 33601107ea93SSriharsha Basavapatna D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id); 33611107ea93SSriharsha Basavapatna } 33621107ea93SSriharsha Basavapatna 33631107ea93SSriharsha Basavapatna static void 3364f0ca1d9aSsb155480 vsw_process_data_pkt(vsw_ldc_t *ldcp, void *dpkt, vio_msg_tag_t *tagp, 3365f0ca1d9aSsb155480 uint32_t msglen) 336606db247cSraghuram { 3367f0ca1d9aSsb155480 uint16_t env = tagp->vio_subtype_env; 336806db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 33697bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_out; 33707bd3a2e2SSriharsha Basavapatna uint8_t dring_mode = lp->dring_mode; 337106db247cSraghuram 337206db247cSraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id); 337306db247cSraghuram 337406db247cSraghuram /* session id check */ 337506db247cSraghuram if (ldcp->session_status & VSW_PEER_SESSION) { 3376f0ca1d9aSsb155480 if (ldcp->peer_session != tagp->vio_sid) { 337706db247cSraghuram DERR(vswp, "%s (chan %d): invalid session id (%llx)", 3378f0ca1d9aSsb155480 __func__, ldcp->ldc_id, tagp->vio_sid); 337906db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 338006db247cSraghuram return; 338106db247cSraghuram } 338206db247cSraghuram } 338306db247cSraghuram 338406db247cSraghuram /* 338506db247cSraghuram * It is an error for us to be getting data packets 338606db247cSraghuram * before the handshake has completed. 338706db247cSraghuram */ 338806db247cSraghuram if (ldcp->hphase != VSW_MILESTONE4) { 338906db247cSraghuram DERR(vswp, "%s: got data packet before handshake complete " 339006db247cSraghuram "hphase %d (%x: %x)", __func__, ldcp->hphase, 339106db247cSraghuram ldcp->lane_in.lstate, ldcp->lane_out.lstate); 339206db247cSraghuram DUMP_FLAGS(ldcp->lane_in.lstate); 339306db247cSraghuram DUMP_FLAGS(ldcp->lane_out.lstate); 339406db247cSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART); 339506db247cSraghuram return; 339606db247cSraghuram } 33977bd3a2e2SSriharsha Basavapatna if (dring_mode == VIO_TX_DRING) { 339806db247cSraghuram /* 33997bd3a2e2SSriharsha Basavapatna * To reduce the locking contention, release the ldc_cblock 34007bd3a2e2SSriharsha Basavapatna * here and re-acquire it once we are done receiving packets. 34017bd3a2e2SSriharsha Basavapatna * We do this only in TxDring mode to allow further callbaks to 34027bd3a2e2SSriharsha Basavapatna * continue while the msg worker thread processes the messages. 34037bd3a2e2SSriharsha Basavapatna * In RxDringData mode, we process the messages in the callback 34047bd3a2e2SSriharsha Basavapatna * itself and wake up rcv worker thread to process only data 34057bd3a2e2SSriharsha Basavapatna * info messages. 340606db247cSraghuram */ 340706db247cSraghuram mutex_exit(&ldcp->ldc_cblock); 340806db247cSraghuram mutex_enter(&ldcp->ldc_rxlock); 34097bd3a2e2SSriharsha Basavapatna } 341006db247cSraghuram 341106db247cSraghuram /* 341206db247cSraghuram * Switch on vio_subtype envelope, then let lower routines 341306db247cSraghuram * decide if its an INFO, ACK or NACK packet. 341406db247cSraghuram */ 341506db247cSraghuram if (env == VIO_DRING_DATA) { 34167bd3a2e2SSriharsha Basavapatna ldcp->rx_dringdata(ldcp, dpkt); 341706db247cSraghuram } else if (env == VIO_PKT_DATA) { 3418f0ca1d9aSsb155480 ldcp->rx_pktdata(ldcp, dpkt, msglen); 341906db247cSraghuram } else if (env == VIO_DESC_DATA) { 342006db247cSraghuram vsw_process_data_ibnd_pkt(ldcp, dpkt); 342106db247cSraghuram } else { 34227bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: unknown vio_subtype_env (%x)\n", 34237bd3a2e2SSriharsha Basavapatna __func__, env); 342406db247cSraghuram } 342506db247cSraghuram 34267bd3a2e2SSriharsha Basavapatna if (dring_mode == VIO_TX_DRING) { 342706db247cSraghuram mutex_exit(&ldcp->ldc_rxlock); 342806db247cSraghuram mutex_enter(&ldcp->ldc_cblock); 34297bd3a2e2SSriharsha Basavapatna } 343006db247cSraghuram 343106db247cSraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id); 343206db247cSraghuram } 343306db247cSraghuram 343406db247cSraghuram /* 3435f0ca1d9aSsb155480 * dummy pkt data handler function for vnet protocol version 1.0 343606db247cSraghuram */ 343706db247cSraghuram static void 3438f0ca1d9aSsb155480 vsw_process_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen) 343906db247cSraghuram { 3440f0ca1d9aSsb155480 _NOTE(ARGUNUSED(arg1, arg2, msglen)) 3441f0ca1d9aSsb155480 } 344206db247cSraghuram 3443f0ca1d9aSsb155480 /* 3444f0ca1d9aSsb155480 * This function handles raw pkt data messages received over the channel. 3445f0ca1d9aSsb155480 * Currently, only priority-eth-type frames are received through this mechanism. 3446f0ca1d9aSsb155480 * In this case, the frame(data) is present within the message itself which 3447f0ca1d9aSsb155480 * is copied into an mblk before switching it. 3448f0ca1d9aSsb155480 */ 3449f0ca1d9aSsb155480 static void 3450f0ca1d9aSsb155480 vsw_process_pkt_data(void *arg1, void *arg2, uint32_t msglen) 3451f0ca1d9aSsb155480 { 3452f0ca1d9aSsb155480 vsw_ldc_t *ldcp = (vsw_ldc_t *)arg1; 3453f0ca1d9aSsb155480 vio_raw_data_msg_t *dpkt = (vio_raw_data_msg_t *)arg2; 3454f0ca1d9aSsb155480 uint32_t size; 3455f0ca1d9aSsb155480 mblk_t *mp; 34567bd3a2e2SSriharsha Basavapatna vio_mblk_t *vmp; 3457f0ca1d9aSsb155480 vsw_t *vswp = ldcp->ldc_vswp; 3458f0ca1d9aSsb155480 vgen_stats_t *statsp = &ldcp->ldc_stats; 3459c1c61f44Ssb155480 lane_t *lp = &ldcp->lane_out; 3460f0ca1d9aSsb155480 3461f0ca1d9aSsb155480 size = msglen - VIO_PKT_DATA_HDRSIZE; 3462c1c61f44Ssb155480 if (size < ETHERMIN || size > lp->mtu) { 3463f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->rx_pri_fail); 3464f0ca1d9aSsb155480 DWARN(vswp, "%s(%lld) invalid size(%d)\n", __func__, 3465f0ca1d9aSsb155480 ldcp->ldc_id, size); 3466f0ca1d9aSsb155480 return; 3467f0ca1d9aSsb155480 } 3468f0ca1d9aSsb155480 34697bd3a2e2SSriharsha Basavapatna vmp = vio_multipool_allocb(&ldcp->vmp, size + VLAN_TAGSZ); 34707bd3a2e2SSriharsha Basavapatna if (vmp == NULL) { 3471c1c61f44Ssb155480 mp = allocb(size + VLAN_TAGSZ, BPRI_MED); 3472f0ca1d9aSsb155480 if (mp == NULL) { 3473f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->rx_pri_fail); 3474f0ca1d9aSsb155480 DWARN(vswp, "%s(%lld) allocb failure, " 3475f0ca1d9aSsb155480 "unable to process priority frame\n", __func__, 3476f0ca1d9aSsb155480 ldcp->ldc_id); 3477f0ca1d9aSsb155480 return; 3478f0ca1d9aSsb155480 } 34797bd3a2e2SSriharsha Basavapatna } else { 34807bd3a2e2SSriharsha Basavapatna mp = vmp->mp; 3481f0ca1d9aSsb155480 } 3482f0ca1d9aSsb155480 3483c1c61f44Ssb155480 /* skip over the extra space for vlan tag */ 3484c1c61f44Ssb155480 mp->b_rptr += VLAN_TAGSZ; 3485c1c61f44Ssb155480 3486f0ca1d9aSsb155480 /* copy the frame from the payload of raw data msg into the mblk */ 3487f0ca1d9aSsb155480 bcopy(dpkt->data, mp->b_rptr, size); 3488f0ca1d9aSsb155480 mp->b_wptr = mp->b_rptr + size; 3489f0ca1d9aSsb155480 34907bd3a2e2SSriharsha Basavapatna if (vmp != NULL) { 34917bd3a2e2SSriharsha Basavapatna vmp->state = VIO_MBLK_HAS_DATA; 34927bd3a2e2SSriharsha Basavapatna } 34937bd3a2e2SSriharsha Basavapatna 3494f0ca1d9aSsb155480 /* update stats */ 3495f0ca1d9aSsb155480 (void) atomic_inc_64(&statsp->rx_pri_packets); 3496f0ca1d9aSsb155480 (void) atomic_add_64(&statsp->rx_pri_bytes, size); 3497f0ca1d9aSsb155480 3498c1c61f44Ssb155480 /* 3499c1c61f44Ssb155480 * VLAN_TAGSZ of extra space has been pre-alloc'd if tag is needed. 3500c1c61f44Ssb155480 */ 3501c1c61f44Ssb155480 (void) vsw_vlan_frame_pretag(ldcp->ldc_port, VSW_VNETPORT, mp); 3502c1c61f44Ssb155480 3503f0ca1d9aSsb155480 /* switch the frame to destination */ 3504f0ca1d9aSsb155480 vswp->vsw_switch_frame(vswp, mp, VSW_VNETPORT, ldcp->ldc_port, NULL); 350506db247cSraghuram } 350606db247cSraghuram 350706db247cSraghuram /* 350806db247cSraghuram * Process an in-band descriptor message (most likely from 350906db247cSraghuram * OBP). 351006db247cSraghuram */ 351106db247cSraghuram static void 351206db247cSraghuram vsw_process_data_ibnd_pkt(vsw_ldc_t *ldcp, void *pkt) 351306db247cSraghuram { 351406db247cSraghuram vnet_ibnd_desc_t *ibnd_desc; 351506db247cSraghuram dring_info_t *dp = NULL; 351606db247cSraghuram vsw_private_desc_t *priv_addr = NULL; 351706db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 351806db247cSraghuram mblk_t *mp = NULL; 351906db247cSraghuram size_t nbytes = 0; 352006db247cSraghuram size_t off = 0; 352106db247cSraghuram uint64_t idx = 0; 352206db247cSraghuram uint32_t num = 1, len, datalen = 0; 352306db247cSraghuram uint64_t ncookies = 0; 352406db247cSraghuram int i, rv; 352506db247cSraghuram int j = 0; 352606db247cSraghuram 352706db247cSraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id); 352806db247cSraghuram 352906db247cSraghuram ibnd_desc = (vnet_ibnd_desc_t *)pkt; 353006db247cSraghuram 353106db247cSraghuram switch (ibnd_desc->hdr.tag.vio_subtype) { 353206db247cSraghuram case VIO_SUBTYPE_INFO: 353306db247cSraghuram D1(vswp, "%s: VIO_SUBTYPE_INFO", __func__); 353406db247cSraghuram 353506db247cSraghuram if (vsw_check_flag(ldcp, INBOUND, VSW_DRING_INFO_RECV)) 353606db247cSraghuram return; 353706db247cSraghuram 353806db247cSraghuram /* 353906db247cSraghuram * Data is padded to align on a 8 byte boundary, 354006db247cSraghuram * nbytes is actual data length, i.e. minus that 354106db247cSraghuram * padding. 354206db247cSraghuram */ 354306db247cSraghuram datalen = ibnd_desc->nbytes; 354406db247cSraghuram 354506db247cSraghuram D2(vswp, "%s(%lld): processing inband desc : " 354606db247cSraghuram ": datalen 0x%lx", __func__, ldcp->ldc_id, datalen); 354706db247cSraghuram 354806db247cSraghuram ncookies = ibnd_desc->ncookies; 354906db247cSraghuram 355006db247cSraghuram /* 355106db247cSraghuram * allocb(9F) returns an aligned data block. We 355206db247cSraghuram * need to ensure that we ask ldc for an aligned 355306db247cSraghuram * number of bytes also. 355406db247cSraghuram */ 355506db247cSraghuram nbytes = datalen; 355606db247cSraghuram if (nbytes & 0x7) { 355706db247cSraghuram off = 8 - (nbytes & 0x7); 355806db247cSraghuram nbytes += off; 355906db247cSraghuram } 356006db247cSraghuram 3561c1c61f44Ssb155480 /* alloc extra space for VLAN_TAG */ 3562c1c61f44Ssb155480 mp = allocb(datalen + 8, BPRI_MED); 356306db247cSraghuram if (mp == NULL) { 356406db247cSraghuram DERR(vswp, "%s(%lld): allocb failed", 356506db247cSraghuram __func__, ldcp->ldc_id); 356606db247cSraghuram ldcp->ldc_stats.rx_allocb_fail++; 356706db247cSraghuram return; 356806db247cSraghuram } 356906db247cSraghuram 3570c1c61f44Ssb155480 /* skip over the extra space for VLAN_TAG */ 3571c1c61f44Ssb155480 mp->b_rptr += 8; 3572c1c61f44Ssb155480 357306db247cSraghuram rv = ldc_mem_copy(ldcp->ldc_handle, (caddr_t)mp->b_rptr, 357406db247cSraghuram 0, &nbytes, ibnd_desc->memcookie, (uint64_t)ncookies, 357506db247cSraghuram LDC_COPY_IN); 357606db247cSraghuram 357706db247cSraghuram if (rv != 0) { 357806db247cSraghuram DERR(vswp, "%s(%d): unable to copy in data from " 357906db247cSraghuram "%d cookie(s)", __func__, ldcp->ldc_id, ncookies); 358006db247cSraghuram freemsg(mp); 358106db247cSraghuram ldcp->ldc_stats.ierrors++; 358206db247cSraghuram return; 358306db247cSraghuram } 358406db247cSraghuram 358506db247cSraghuram D2(vswp, "%s(%d): copied in %ld bytes using %d cookies", 358606db247cSraghuram __func__, ldcp->ldc_id, nbytes, ncookies); 358706db247cSraghuram 358806db247cSraghuram /* point to the actual end of data */ 358906db247cSraghuram mp->b_wptr = mp->b_rptr + datalen; 359006db247cSraghuram ldcp->ldc_stats.ipackets++; 359106db247cSraghuram ldcp->ldc_stats.rbytes += datalen; 359206db247cSraghuram 359306db247cSraghuram /* 359406db247cSraghuram * We ACK back every in-band descriptor message we process 359506db247cSraghuram */ 359606db247cSraghuram ibnd_desc->hdr.tag.vio_subtype = VIO_SUBTYPE_ACK; 359706db247cSraghuram ibnd_desc->hdr.tag.vio_sid = ldcp->local_session; 359806db247cSraghuram (void) vsw_send_msg(ldcp, (void *)ibnd_desc, 359906db247cSraghuram sizeof (vnet_ibnd_desc_t), B_TRUE); 360006db247cSraghuram 3601c1c61f44Ssb155480 /* 3602c1c61f44Ssb155480 * there is extra space alloc'd for VLAN_TAG 3603c1c61f44Ssb155480 */ 3604c1c61f44Ssb155480 (void) vsw_vlan_frame_pretag(ldcp->ldc_port, VSW_VNETPORT, mp); 3605c1c61f44Ssb155480 360606db247cSraghuram /* send the packet to be switched */ 360706db247cSraghuram vswp->vsw_switch_frame(vswp, mp, VSW_VNETPORT, 360806db247cSraghuram ldcp->ldc_port, NULL); 360906db247cSraghuram 361006db247cSraghuram break; 361106db247cSraghuram 361206db247cSraghuram case VIO_SUBTYPE_ACK: 361306db247cSraghuram D1(vswp, "%s: VIO_SUBTYPE_ACK", __func__); 361406db247cSraghuram 361506db247cSraghuram /* Verify the ACK is valid */ 361606db247cSraghuram idx = ibnd_desc->hdr.desc_handle; 361706db247cSraghuram 36187bd3a2e2SSriharsha Basavapatna if (idx >= vsw_num_descriptors) { 361906db247cSraghuram cmn_err(CE_WARN, "!vsw%d: corrupted ACK received " 362006db247cSraghuram "(idx %ld)", vswp->instance, idx); 362106db247cSraghuram return; 362206db247cSraghuram } 362306db247cSraghuram 362406db247cSraghuram if ((dp = ldcp->lane_out.dringp) == NULL) { 362506db247cSraghuram DERR(vswp, "%s: no dring found", __func__); 362606db247cSraghuram return; 362706db247cSraghuram } 362806db247cSraghuram 362906db247cSraghuram len = dp->num_descriptors; 363006db247cSraghuram /* 363106db247cSraghuram * If the descriptor we are being ACK'ed for is not the 363206db247cSraghuram * one we expected, then pkts were lost somwhere, either 363306db247cSraghuram * when we tried to send a msg, or a previous ACK msg from 363406db247cSraghuram * our peer. In either case we now reclaim the descriptors 363506db247cSraghuram * in the range from the last ACK we received up to the 363606db247cSraghuram * current ACK. 363706db247cSraghuram */ 363806db247cSraghuram if (idx != dp->last_ack_recv) { 363906db247cSraghuram DWARN(vswp, "%s: dropped pkts detected, (%ld, %ld)", 364006db247cSraghuram __func__, dp->last_ack_recv, idx); 364106db247cSraghuram num = idx >= dp->last_ack_recv ? 364206db247cSraghuram idx - dp->last_ack_recv + 1: 364306db247cSraghuram (len - dp->last_ack_recv + 1) + idx; 364406db247cSraghuram } 364506db247cSraghuram 364606db247cSraghuram /* 364706db247cSraghuram * When we sent the in-band message to our peer we 364806db247cSraghuram * marked the copy in our private ring as READY. We now 364906db247cSraghuram * check that the descriptor we are being ACK'ed for is in 365006db247cSraghuram * fact READY, i.e. it is one we have shared with our peer. 365106db247cSraghuram * 365206db247cSraghuram * If its not we flag an error, but still reset the descr 365306db247cSraghuram * back to FREE. 365406db247cSraghuram */ 365506db247cSraghuram for (i = dp->last_ack_recv; j < num; i = (i + 1) % len, j++) { 365606db247cSraghuram priv_addr = (vsw_private_desc_t *)dp->priv_addr + i; 365706db247cSraghuram mutex_enter(&priv_addr->dstate_lock); 365806db247cSraghuram if (priv_addr->dstate != VIO_DESC_READY) { 365906db247cSraghuram DERR(vswp, "%s: (%ld) desc at index %ld not " 366006db247cSraghuram "READY (0x%lx)", __func__, 366106db247cSraghuram ldcp->ldc_id, idx, priv_addr->dstate); 366206db247cSraghuram DERR(vswp, "%s: bound %d: ncookies %ld : " 366306db247cSraghuram "datalen %ld", __func__, 366406db247cSraghuram priv_addr->bound, priv_addr->ncookies, 366506db247cSraghuram priv_addr->datalen); 366606db247cSraghuram } 366706db247cSraghuram D2(vswp, "%s: (%lld) freeing descp at %lld", __func__, 366806db247cSraghuram ldcp->ldc_id, idx); 366906db247cSraghuram /* release resources associated with sent msg */ 367006db247cSraghuram priv_addr->datalen = 0; 367106db247cSraghuram priv_addr->dstate = VIO_DESC_FREE; 367206db247cSraghuram mutex_exit(&priv_addr->dstate_lock); 367306db247cSraghuram } 367406db247cSraghuram /* update to next expected value */ 367506db247cSraghuram dp->last_ack_recv = (idx + 1) % dp->num_descriptors; 367606db247cSraghuram 367706db247cSraghuram break; 367806db247cSraghuram 367906db247cSraghuram case VIO_SUBTYPE_NACK: 368006db247cSraghuram DERR(vswp, "%s: VIO_SUBTYPE_NACK", __func__); 368106db247cSraghuram 368206db247cSraghuram /* 368306db247cSraghuram * We should only get a NACK if our peer doesn't like 368406db247cSraghuram * something about a message we have sent it. If this 368506db247cSraghuram * happens we just release the resources associated with 368606db247cSraghuram * the message. (We are relying on higher layers to decide 368706db247cSraghuram * whether or not to resend. 368806db247cSraghuram */ 368906db247cSraghuram 369006db247cSraghuram /* limit check */ 369106db247cSraghuram idx = ibnd_desc->hdr.desc_handle; 369206db247cSraghuram 36937bd3a2e2SSriharsha Basavapatna if (idx >= vsw_num_descriptors) { 369406db247cSraghuram DERR(vswp, "%s: corrupted NACK received (idx %lld)", 369506db247cSraghuram __func__, idx); 369606db247cSraghuram return; 369706db247cSraghuram } 369806db247cSraghuram 369906db247cSraghuram if ((dp = ldcp->lane_out.dringp) == NULL) { 370006db247cSraghuram DERR(vswp, "%s: no dring found", __func__); 370106db247cSraghuram return; 370206db247cSraghuram } 370306db247cSraghuram 370406db247cSraghuram priv_addr = (vsw_private_desc_t *)dp->priv_addr; 370506db247cSraghuram 370606db247cSraghuram /* move to correct location in ring */ 370706db247cSraghuram priv_addr += idx; 370806db247cSraghuram 370906db247cSraghuram /* release resources associated with sent msg */ 371006db247cSraghuram mutex_enter(&priv_addr->dstate_lock); 371106db247cSraghuram priv_addr->datalen = 0; 371206db247cSraghuram priv_addr->dstate = VIO_DESC_FREE; 371306db247cSraghuram mutex_exit(&priv_addr->dstate_lock); 371406db247cSraghuram 371506db247cSraghuram break; 371606db247cSraghuram 371706db247cSraghuram default: 371806db247cSraghuram DERR(vswp, "%s(%lld): Unknown vio_subtype %x\n", __func__, 371906db247cSraghuram ldcp->ldc_id, ibnd_desc->hdr.tag.vio_subtype); 372006db247cSraghuram } 372106db247cSraghuram 372206db247cSraghuram D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id); 372306db247cSraghuram } 372406db247cSraghuram 372506db247cSraghuram static void 3726f0ca1d9aSsb155480 vsw_process_err_pkt(vsw_ldc_t *ldcp, void *epkt, vio_msg_tag_t *tagp) 372706db247cSraghuram { 372806db247cSraghuram _NOTE(ARGUNUSED(epkt)) 372906db247cSraghuram 373006db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 3731f0ca1d9aSsb155480 uint16_t env = tagp->vio_subtype_env; 373206db247cSraghuram 373306db247cSraghuram D1(vswp, "%s (%lld): enter\n", __func__, ldcp->ldc_id); 373406db247cSraghuram 373506db247cSraghuram /* 373606db247cSraghuram * Error vio_subtypes have yet to be defined. So for 373706db247cSraghuram * the moment we can't do anything. 373806db247cSraghuram */ 373906db247cSraghuram D2(vswp, "%s: (%x) vio_subtype env", __func__, env); 374006db247cSraghuram 374106db247cSraghuram D1(vswp, "%s (%lld): exit\n", __func__, ldcp->ldc_id); 374206db247cSraghuram } 374306db247cSraghuram 374406db247cSraghuram /* transmit the packet over the given port */ 374506db247cSraghuram int 3746da14cebeSEric Cheng vsw_portsend(vsw_port_t *port, mblk_t *mp) 374706db247cSraghuram { 3748da14cebeSEric Cheng mblk_t *mpt; 3749da14cebeSEric Cheng int count; 37507bd3a2e2SSriharsha Basavapatna vsw_ldc_t *ldcp = port->ldcp; 375106db247cSraghuram int status = 0; 375206db247cSraghuram 3753da14cebeSEric Cheng count = vsw_vlan_frame_untag(port, VSW_VNETPORT, &mp, &mpt); 3754da14cebeSEric Cheng if (count != 0) { 3755da14cebeSEric Cheng status = ldcp->tx(ldcp, mp, mpt, count); 3756c1c61f44Ssb155480 } 3757f0ca1d9aSsb155480 return (status); 3758f0ca1d9aSsb155480 } 3759f0ca1d9aSsb155480 376006db247cSraghuram /* 3761f0ca1d9aSsb155480 * Break up frames into 2 seperate chains: normal and 3762f0ca1d9aSsb155480 * priority, based on the frame type. The number of 3763f0ca1d9aSsb155480 * priority frames is also counted and returned. 3764f0ca1d9aSsb155480 * 3765f0ca1d9aSsb155480 * Params: 3766f0ca1d9aSsb155480 * vswp: pointer to the instance of vsw 3767f0ca1d9aSsb155480 * np: head of packet chain to be broken 3768f0ca1d9aSsb155480 * npt: tail of packet chain to be broken 3769f0ca1d9aSsb155480 * 3770f0ca1d9aSsb155480 * Returns: 3771f0ca1d9aSsb155480 * np: head of normal data packets 3772f0ca1d9aSsb155480 * npt: tail of normal data packets 3773f0ca1d9aSsb155480 * hp: head of high priority packets 3774f0ca1d9aSsb155480 * hpt: tail of high priority packets 3775f0ca1d9aSsb155480 */ 3776f0ca1d9aSsb155480 static uint32_t 3777f0ca1d9aSsb155480 vsw_get_pri_packets(vsw_t *vswp, mblk_t **np, mblk_t **npt, 3778f0ca1d9aSsb155480 mblk_t **hp, mblk_t **hpt) 3779f0ca1d9aSsb155480 { 3780f0ca1d9aSsb155480 mblk_t *tmp = NULL; 3781f0ca1d9aSsb155480 mblk_t *smp = NULL; 3782f0ca1d9aSsb155480 mblk_t *hmp = NULL; /* high prio pkts head */ 3783f0ca1d9aSsb155480 mblk_t *hmpt = NULL; /* high prio pkts tail */ 3784f0ca1d9aSsb155480 mblk_t *nmp = NULL; /* normal pkts head */ 3785f0ca1d9aSsb155480 mblk_t *nmpt = NULL; /* normal pkts tail */ 3786f0ca1d9aSsb155480 uint32_t count = 0; 3787f0ca1d9aSsb155480 int i; 3788f0ca1d9aSsb155480 struct ether_header *ehp; 3789f0ca1d9aSsb155480 uint32_t num_types; 3790f0ca1d9aSsb155480 uint16_t *types; 3791f0ca1d9aSsb155480 3792f0ca1d9aSsb155480 tmp = *np; 3793f0ca1d9aSsb155480 while (tmp != NULL) { 3794f0ca1d9aSsb155480 3795f0ca1d9aSsb155480 smp = tmp; 3796f0ca1d9aSsb155480 tmp = tmp->b_next; 3797f0ca1d9aSsb155480 smp->b_next = NULL; 3798f0ca1d9aSsb155480 smp->b_prev = NULL; 3799f0ca1d9aSsb155480 3800f0ca1d9aSsb155480 ehp = (struct ether_header *)smp->b_rptr; 3801f0ca1d9aSsb155480 num_types = vswp->pri_num_types; 3802f0ca1d9aSsb155480 types = vswp->pri_types; 3803f0ca1d9aSsb155480 for (i = 0; i < num_types; i++) { 3804f0ca1d9aSsb155480 if (ehp->ether_type == types[i]) { 3805f0ca1d9aSsb155480 /* high priority frame */ 3806f0ca1d9aSsb155480 3807f0ca1d9aSsb155480 if (hmp != NULL) { 3808f0ca1d9aSsb155480 hmpt->b_next = smp; 3809f0ca1d9aSsb155480 hmpt = smp; 3810f0ca1d9aSsb155480 } else { 3811f0ca1d9aSsb155480 hmp = hmpt = smp; 3812f0ca1d9aSsb155480 } 3813f0ca1d9aSsb155480 count++; 3814f0ca1d9aSsb155480 break; 3815f0ca1d9aSsb155480 } 3816f0ca1d9aSsb155480 } 3817f0ca1d9aSsb155480 if (i == num_types) { 3818f0ca1d9aSsb155480 /* normal data frame */ 3819f0ca1d9aSsb155480 3820f0ca1d9aSsb155480 if (nmp != NULL) { 3821f0ca1d9aSsb155480 nmpt->b_next = smp; 3822f0ca1d9aSsb155480 nmpt = smp; 3823f0ca1d9aSsb155480 } else { 3824f0ca1d9aSsb155480 nmp = nmpt = smp; 3825f0ca1d9aSsb155480 } 3826f0ca1d9aSsb155480 } 3827f0ca1d9aSsb155480 } 3828f0ca1d9aSsb155480 3829f0ca1d9aSsb155480 *hp = hmp; 3830f0ca1d9aSsb155480 *hpt = hmpt; 3831f0ca1d9aSsb155480 *np = nmp; 3832f0ca1d9aSsb155480 *npt = nmpt; 3833f0ca1d9aSsb155480 3834f0ca1d9aSsb155480 return (count); 3835f0ca1d9aSsb155480 } 3836f0ca1d9aSsb155480 3837f0ca1d9aSsb155480 /* 3838f0ca1d9aSsb155480 * Wrapper function to transmit normal and/or priority frames over the channel. 3839f0ca1d9aSsb155480 */ 3840f0ca1d9aSsb155480 static int 3841f0ca1d9aSsb155480 vsw_ldctx_pri(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count) 3842f0ca1d9aSsb155480 { 3843f0ca1d9aSsb155480 vsw_ldc_t *ldcp = (vsw_ldc_t *)arg; 3844f0ca1d9aSsb155480 mblk_t *tmp; 3845f0ca1d9aSsb155480 mblk_t *smp; 3846f0ca1d9aSsb155480 mblk_t *hmp; /* high prio pkts head */ 3847f0ca1d9aSsb155480 mblk_t *hmpt; /* high prio pkts tail */ 3848f0ca1d9aSsb155480 mblk_t *nmp; /* normal pkts head */ 3849f0ca1d9aSsb155480 mblk_t *nmpt; /* normal pkts tail */ 3850f0ca1d9aSsb155480 uint32_t n = 0; 3851f0ca1d9aSsb155480 vsw_t *vswp = ldcp->ldc_vswp; 3852f0ca1d9aSsb155480 3853f0ca1d9aSsb155480 ASSERT(VSW_PRI_ETH_DEFINED(vswp)); 3854f0ca1d9aSsb155480 ASSERT(count != 0); 3855f0ca1d9aSsb155480 3856f0ca1d9aSsb155480 nmp = mp; 3857f0ca1d9aSsb155480 nmpt = mpt; 3858f0ca1d9aSsb155480 3859f0ca1d9aSsb155480 /* gather any priority frames from the chain of packets */ 3860f0ca1d9aSsb155480 n = vsw_get_pri_packets(vswp, &nmp, &nmpt, &hmp, &hmpt); 3861f0ca1d9aSsb155480 3862f0ca1d9aSsb155480 /* transmit priority frames */ 3863f0ca1d9aSsb155480 tmp = hmp; 3864f0ca1d9aSsb155480 while (tmp != NULL) { 3865f0ca1d9aSsb155480 smp = tmp; 3866f0ca1d9aSsb155480 tmp = tmp->b_next; 3867f0ca1d9aSsb155480 smp->b_next = NULL; 3868f0ca1d9aSsb155480 vsw_ldcsend_pkt(ldcp, smp); 3869f0ca1d9aSsb155480 } 3870f0ca1d9aSsb155480 3871f0ca1d9aSsb155480 count -= n; 3872f0ca1d9aSsb155480 3873f0ca1d9aSsb155480 if (count == 0) { 3874f0ca1d9aSsb155480 /* no normal data frames to process */ 3875f0ca1d9aSsb155480 return (0); 3876f0ca1d9aSsb155480 } 3877f0ca1d9aSsb155480 3878f0ca1d9aSsb155480 return (vsw_ldctx(ldcp, nmp, nmpt, count)); 3879f0ca1d9aSsb155480 } 3880f0ca1d9aSsb155480 3881f0ca1d9aSsb155480 /* 3882f0ca1d9aSsb155480 * Wrapper function to transmit normal frames over the channel. 3883f0ca1d9aSsb155480 */ 3884f0ca1d9aSsb155480 static int 3885f0ca1d9aSsb155480 vsw_ldctx(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count) 3886f0ca1d9aSsb155480 { 3887f0ca1d9aSsb155480 vsw_ldc_t *ldcp = (vsw_ldc_t *)arg; 3888f0ca1d9aSsb155480 mblk_t *tmp = NULL; 3889f0ca1d9aSsb155480 3890f0ca1d9aSsb155480 ASSERT(count != 0); 3891f0ca1d9aSsb155480 /* 3892f0ca1d9aSsb155480 * If the TX thread is enabled, then queue the 3893f0ca1d9aSsb155480 * ordinary frames and signal the tx thread. 389406db247cSraghuram */ 389506db247cSraghuram if (ldcp->tx_thread != NULL) { 3896f0ca1d9aSsb155480 389706db247cSraghuram mutex_enter(&ldcp->tx_thr_lock); 3898f0ca1d9aSsb155480 3899f0ca1d9aSsb155480 if ((ldcp->tx_cnt + count) >= vsw_max_tx_qcount) { 3900f0ca1d9aSsb155480 /* 3901f0ca1d9aSsb155480 * If we reached queue limit, 3902f0ca1d9aSsb155480 * do not queue new packets, 3903f0ca1d9aSsb155480 * drop them. 3904f0ca1d9aSsb155480 */ 3905f0ca1d9aSsb155480 ldcp->ldc_stats.tx_qfull += count; 3906f0ca1d9aSsb155480 mutex_exit(&ldcp->tx_thr_lock); 3907f0ca1d9aSsb155480 freemsgchain(mp); 3908f0ca1d9aSsb155480 goto exit; 3909f0ca1d9aSsb155480 } 391006db247cSraghuram if (ldcp->tx_mhead == NULL) { 391106db247cSraghuram ldcp->tx_mhead = mp; 391206db247cSraghuram ldcp->tx_mtail = mpt; 391306db247cSraghuram cv_signal(&ldcp->tx_thr_cv); 391406db247cSraghuram } else { 391506db247cSraghuram ldcp->tx_mtail->b_next = mp; 391606db247cSraghuram ldcp->tx_mtail = mpt; 391706db247cSraghuram } 3918f0ca1d9aSsb155480 ldcp->tx_cnt += count; 391906db247cSraghuram mutex_exit(&ldcp->tx_thr_lock); 392006db247cSraghuram } else { 392106db247cSraghuram while (mp != NULL) { 392206db247cSraghuram tmp = mp->b_next; 392306db247cSraghuram mp->b_next = mp->b_prev = NULL; 392406db247cSraghuram (void) vsw_ldcsend(ldcp, mp, 1); 392506db247cSraghuram mp = tmp; 392606db247cSraghuram } 392706db247cSraghuram } 392806db247cSraghuram 3929f0ca1d9aSsb155480 exit: 3930f0ca1d9aSsb155480 return (0); 3931f0ca1d9aSsb155480 } 393206db247cSraghuram 3933f0ca1d9aSsb155480 /* 3934f0ca1d9aSsb155480 * This function transmits the frame in the payload of a raw data 3935f0ca1d9aSsb155480 * (VIO_PKT_DATA) message. Thus, it provides an Out-Of-Band path to 3936f0ca1d9aSsb155480 * send special frames with high priorities, without going through 3937f0ca1d9aSsb155480 * the normal data path which uses descriptor ring mechanism. 3938f0ca1d9aSsb155480 */ 3939f0ca1d9aSsb155480 static void 3940f0ca1d9aSsb155480 vsw_ldcsend_pkt(vsw_ldc_t *ldcp, mblk_t *mp) 3941f0ca1d9aSsb155480 { 3942f0ca1d9aSsb155480 vio_raw_data_msg_t *pkt; 3943f0ca1d9aSsb155480 mblk_t *bp; 3944f0ca1d9aSsb155480 mblk_t *nmp = NULL; 39457bd3a2e2SSriharsha Basavapatna vio_mblk_t *vmp; 3946f0ca1d9aSsb155480 caddr_t dst; 3947f0ca1d9aSsb155480 uint32_t mblksz; 3948f0ca1d9aSsb155480 uint32_t size; 3949f0ca1d9aSsb155480 uint32_t nbytes; 3950f0ca1d9aSsb155480 int rv; 3951f0ca1d9aSsb155480 vsw_t *vswp = ldcp->ldc_vswp; 3952f0ca1d9aSsb155480 vgen_stats_t *statsp = &ldcp->ldc_stats; 3953f0ca1d9aSsb155480 3954f0ca1d9aSsb155480 if ((!(ldcp->lane_out.lstate & VSW_LANE_ACTIVE)) || 3955f0ca1d9aSsb155480 (ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == NULL)) { 3956f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 3957f0ca1d9aSsb155480 DWARN(vswp, "%s(%lld) status(%d) lstate(0x%llx), dropping " 3958f0ca1d9aSsb155480 "packet\n", __func__, ldcp->ldc_id, ldcp->ldc_status, 3959f0ca1d9aSsb155480 ldcp->lane_out.lstate); 3960f0ca1d9aSsb155480 goto send_pkt_exit; 3961f0ca1d9aSsb155480 } 3962f0ca1d9aSsb155480 3963f0ca1d9aSsb155480 size = msgsize(mp); 3964f0ca1d9aSsb155480 3965f0ca1d9aSsb155480 /* frame size bigger than available payload len of raw data msg ? */ 3966f0ca1d9aSsb155480 if (size > (size_t)(ldcp->msglen - VIO_PKT_DATA_HDRSIZE)) { 3967f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 3968f0ca1d9aSsb155480 DWARN(vswp, "%s(%lld) invalid size(%d)\n", __func__, 3969f0ca1d9aSsb155480 ldcp->ldc_id, size); 3970f0ca1d9aSsb155480 goto send_pkt_exit; 3971f0ca1d9aSsb155480 } 3972f0ca1d9aSsb155480 3973f0ca1d9aSsb155480 if (size < ETHERMIN) 3974f0ca1d9aSsb155480 size = ETHERMIN; 3975f0ca1d9aSsb155480 3976f0ca1d9aSsb155480 /* alloc space for a raw data message */ 39777bd3a2e2SSriharsha Basavapatna vmp = vio_allocb(vswp->pri_tx_vmp); 39787bd3a2e2SSriharsha Basavapatna if (vmp == NULL) { 3979f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 3980f0ca1d9aSsb155480 DWARN(vswp, "vio_allocb failed\n"); 3981f0ca1d9aSsb155480 goto send_pkt_exit; 39827bd3a2e2SSriharsha Basavapatna } else { 39837bd3a2e2SSriharsha Basavapatna nmp = vmp->mp; 3984f0ca1d9aSsb155480 } 3985f0ca1d9aSsb155480 pkt = (vio_raw_data_msg_t *)nmp->b_rptr; 3986f0ca1d9aSsb155480 3987f0ca1d9aSsb155480 /* copy frame into the payload of raw data message */ 3988f0ca1d9aSsb155480 dst = (caddr_t)pkt->data; 3989f0ca1d9aSsb155480 for (bp = mp; bp != NULL; bp = bp->b_cont) { 3990f0ca1d9aSsb155480 mblksz = MBLKL(bp); 3991f0ca1d9aSsb155480 bcopy(bp->b_rptr, dst, mblksz); 3992f0ca1d9aSsb155480 dst += mblksz; 3993f0ca1d9aSsb155480 } 3994f0ca1d9aSsb155480 39957bd3a2e2SSriharsha Basavapatna vmp->state = VIO_MBLK_HAS_DATA; 39967bd3a2e2SSriharsha Basavapatna 3997f0ca1d9aSsb155480 /* setup the raw data msg */ 3998f0ca1d9aSsb155480 pkt->tag.vio_msgtype = VIO_TYPE_DATA; 3999f0ca1d9aSsb155480 pkt->tag.vio_subtype = VIO_SUBTYPE_INFO; 4000f0ca1d9aSsb155480 pkt->tag.vio_subtype_env = VIO_PKT_DATA; 4001f0ca1d9aSsb155480 pkt->tag.vio_sid = ldcp->local_session; 4002f0ca1d9aSsb155480 nbytes = VIO_PKT_DATA_HDRSIZE + size; 4003f0ca1d9aSsb155480 4004f0ca1d9aSsb155480 /* send the msg over ldc */ 4005f0ca1d9aSsb155480 rv = vsw_send_msg(ldcp, (void *)pkt, nbytes, B_TRUE); 4006f0ca1d9aSsb155480 if (rv != 0) { 4007f0ca1d9aSsb155480 (void) atomic_inc_32(&statsp->tx_pri_fail); 4008f0ca1d9aSsb155480 DWARN(vswp, "%s(%lld) Error sending priority frame\n", __func__, 4009f0ca1d9aSsb155480 ldcp->ldc_id); 4010f0ca1d9aSsb155480 goto send_pkt_exit; 4011f0ca1d9aSsb155480 } 4012f0ca1d9aSsb155480 4013f0ca1d9aSsb155480 /* update stats */ 4014f0ca1d9aSsb155480 (void) atomic_inc_64(&statsp->tx_pri_packets); 4015f0ca1d9aSsb155480 (void) atomic_add_64(&statsp->tx_pri_packets, size); 4016f0ca1d9aSsb155480 4017f0ca1d9aSsb155480 send_pkt_exit: 4018f0ca1d9aSsb155480 if (nmp != NULL) 4019f0ca1d9aSsb155480 freemsg(nmp); 4020f0ca1d9aSsb155480 freemsg(mp); 402106db247cSraghuram } 402206db247cSraghuram 402306db247cSraghuram /* 402406db247cSraghuram * Transmit the packet over the given LDC channel. 402506db247cSraghuram * 402606db247cSraghuram * The 'retries' argument indicates how many times a packet 402706db247cSraghuram * is retried before it is dropped. Note, the retry is done 402806db247cSraghuram * only for a resource related failure, for all other failures 402906db247cSraghuram * the packet is dropped immediately. 403006db247cSraghuram */ 403106db247cSraghuram static int 4032f0ca1d9aSsb155480 vsw_ldcsend(vsw_ldc_t *ldcp, mblk_t *mp, uint32_t retries) 403306db247cSraghuram { 403406db247cSraghuram int i; 403506db247cSraghuram int rc; 403606db247cSraghuram int status = 0; 403706db247cSraghuram vsw_port_t *port = ldcp->ldc_port; 403806db247cSraghuram dring_info_t *dp = NULL; 40397bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_out; 404006db247cSraghuram 404106db247cSraghuram for (i = 0; i < retries; ) { 404206db247cSraghuram /* 404306db247cSraghuram * Send the message out using the appropriate 404406db247cSraghuram * transmit function which will free mblock when it 404506db247cSraghuram * is finished with it. 404606db247cSraghuram */ 404706db247cSraghuram mutex_enter(&port->tx_lock); 404806db247cSraghuram if (port->transmit != NULL) { 404906db247cSraghuram status = (*port->transmit)(ldcp, mp); 405006db247cSraghuram } 405106db247cSraghuram if (status == LDC_TX_SUCCESS) { 405206db247cSraghuram mutex_exit(&port->tx_lock); 405306db247cSraghuram break; 405406db247cSraghuram } 405506db247cSraghuram i++; /* increment the counter here */ 405606db247cSraghuram 405706db247cSraghuram /* If its the last retry, then update the oerror */ 405806db247cSraghuram if ((i == retries) && (status == LDC_TX_NORESOURCES)) { 405906db247cSraghuram ldcp->ldc_stats.oerrors++; 406006db247cSraghuram } 406106db247cSraghuram mutex_exit(&port->tx_lock); 406206db247cSraghuram 406306db247cSraghuram if (status != LDC_TX_NORESOURCES) { 406406db247cSraghuram /* 406506db247cSraghuram * No retrying required for errors un-related 406606db247cSraghuram * to resources. 406706db247cSraghuram */ 406806db247cSraghuram break; 406906db247cSraghuram } 4070aba2c384Sraghuram if (((dp = ldcp->lane_out.dringp) != NULL) && 4071c1c61f44Ssb155480 ((VSW_VER_GTEQ(ldcp, 1, 2) && 4072f0ca1d9aSsb155480 (ldcp->lane_out.xfer_mode & VIO_DRING_MODE_V1_2)) || 4073f0ca1d9aSsb155480 ((VSW_VER_LT(ldcp, 1, 2) && 4074f0ca1d9aSsb155480 (ldcp->lane_out.xfer_mode == VIO_DRING_MODE_V1_0))))) { 40757bd3a2e2SSriharsha Basavapatna 40767bd3a2e2SSriharsha Basavapatna /* Need to reclaim in TxDring mode. */ 40777bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_TX_DRING) { 4078aba2c384Sraghuram rc = vsw_reclaim_dring(dp, dp->end_idx); 40797bd3a2e2SSriharsha Basavapatna } 40807bd3a2e2SSriharsha Basavapatna 4081aba2c384Sraghuram } else { 4082aba2c384Sraghuram /* 4083aba2c384Sraghuram * If there is no dring or the xfer_mode is 4084aba2c384Sraghuram * set to DESC_MODE(ie., OBP), then simply break here. 4085aba2c384Sraghuram */ 408606db247cSraghuram break; 408706db247cSraghuram } 408806db247cSraghuram 408906db247cSraghuram /* 409006db247cSraghuram * Delay only if none were reclaimed 409106db247cSraghuram * and its not the last retry. 409206db247cSraghuram */ 409306db247cSraghuram if ((rc == 0) && (i < retries)) { 409406db247cSraghuram delay(drv_usectohz(vsw_ldc_tx_delay)); 409506db247cSraghuram } 409606db247cSraghuram } 409706db247cSraghuram freemsg(mp); 409806db247cSraghuram return (status); 409906db247cSraghuram } 410006db247cSraghuram 410106db247cSraghuram /* 410206db247cSraghuram * Send an in-band descriptor message over ldc. 410306db247cSraghuram */ 410406db247cSraghuram static int 410506db247cSraghuram vsw_descrsend(vsw_ldc_t *ldcp, mblk_t *mp) 410606db247cSraghuram { 410706db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 410806db247cSraghuram vnet_ibnd_desc_t ibnd_msg; 410906db247cSraghuram vsw_private_desc_t *priv_desc = NULL; 411006db247cSraghuram dring_info_t *dp = NULL; 411106db247cSraghuram size_t n, size = 0; 411206db247cSraghuram caddr_t bufp; 411306db247cSraghuram mblk_t *bp; 411406db247cSraghuram int idx, i; 411506db247cSraghuram int status = LDC_TX_SUCCESS; 411606db247cSraghuram static int warn_msg = 1; 4117c1c61f44Ssb155480 lane_t *lp = &ldcp->lane_out; 411806db247cSraghuram 411906db247cSraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id); 412006db247cSraghuram 412106db247cSraghuram ASSERT(mp != NULL); 412206db247cSraghuram 412306db247cSraghuram if ((!(ldcp->lane_out.lstate & VSW_LANE_ACTIVE)) || 412406db247cSraghuram (ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == NULL)) { 412506db247cSraghuram DERR(vswp, "%s(%lld) status(%d) state (0x%llx), dropping pkt", 412606db247cSraghuram __func__, ldcp->ldc_id, ldcp->ldc_status, 412706db247cSraghuram ldcp->lane_out.lstate); 412806db247cSraghuram ldcp->ldc_stats.oerrors++; 412906db247cSraghuram return (LDC_TX_FAILURE); 413006db247cSraghuram } 413106db247cSraghuram 413206db247cSraghuram /* 41337bd3a2e2SSriharsha Basavapatna * The dring here is as an internal buffer, 41347bd3a2e2SSriharsha Basavapatna * rather than a transfer channel. 413506db247cSraghuram */ 413606db247cSraghuram if ((dp = ldcp->lane_out.dringp) == NULL) { 413706db247cSraghuram DERR(vswp, "%s(%lld): no dring for outbound lane", 413806db247cSraghuram __func__, ldcp->ldc_id); 413906db247cSraghuram DERR(vswp, "%s(%lld) status(%d) state (0x%llx)", __func__, 414006db247cSraghuram ldcp->ldc_id, ldcp->ldc_status, ldcp->lane_out.lstate); 414106db247cSraghuram ldcp->ldc_stats.oerrors++; 414206db247cSraghuram return (LDC_TX_FAILURE); 414306db247cSraghuram } 414406db247cSraghuram 414506db247cSraghuram size = msgsize(mp); 4146c1c61f44Ssb155480 if (size > (size_t)lp->mtu) { 414706db247cSraghuram DERR(vswp, "%s(%lld) invalid size (%ld)\n", __func__, 414806db247cSraghuram ldcp->ldc_id, size); 414906db247cSraghuram ldcp->ldc_stats.oerrors++; 415006db247cSraghuram return (LDC_TX_FAILURE); 415106db247cSraghuram } 415206db247cSraghuram 415306db247cSraghuram /* 415406db247cSraghuram * Find a free descriptor in our buffer ring 415506db247cSraghuram */ 415606db247cSraghuram if (vsw_dring_find_free_desc(dp, &priv_desc, &idx) != 0) { 415706db247cSraghuram if (warn_msg) { 415806db247cSraghuram DERR(vswp, "%s(%lld): no descriptor available for ring " 415906db247cSraghuram "at 0x%llx", __func__, ldcp->ldc_id, dp); 416006db247cSraghuram warn_msg = 0; 416106db247cSraghuram } 416206db247cSraghuram 416306db247cSraghuram /* nothing more we can do */ 416406db247cSraghuram status = LDC_TX_NORESOURCES; 416506db247cSraghuram goto vsw_descrsend_free_exit; 416606db247cSraghuram } else { 416706db247cSraghuram D2(vswp, "%s(%lld): free private descriptor found at pos " 416806db247cSraghuram "%ld addr 0x%x\n", __func__, ldcp->ldc_id, idx, priv_desc); 416906db247cSraghuram warn_msg = 1; 417006db247cSraghuram } 417106db247cSraghuram 417206db247cSraghuram /* copy data into the descriptor */ 417306db247cSraghuram bufp = priv_desc->datap; 417406db247cSraghuram for (bp = mp, n = 0; bp != NULL; bp = bp->b_cont) { 417506db247cSraghuram n = MBLKL(bp); 417606db247cSraghuram bcopy(bp->b_rptr, bufp, n); 417706db247cSraghuram bufp += n; 417806db247cSraghuram } 417906db247cSraghuram 418006db247cSraghuram priv_desc->datalen = (size < (size_t)ETHERMIN) ? ETHERMIN : size; 418106db247cSraghuram 418206db247cSraghuram /* create and send the in-band descp msg */ 418306db247cSraghuram ibnd_msg.hdr.tag.vio_msgtype = VIO_TYPE_DATA; 418406db247cSraghuram ibnd_msg.hdr.tag.vio_subtype = VIO_SUBTYPE_INFO; 418506db247cSraghuram ibnd_msg.hdr.tag.vio_subtype_env = VIO_DESC_DATA; 418606db247cSraghuram ibnd_msg.hdr.tag.vio_sid = ldcp->local_session; 418706db247cSraghuram 418806db247cSraghuram /* 418906db247cSraghuram * Copy the mem cookies describing the data from the 419006db247cSraghuram * private region of the descriptor ring into the inband 419106db247cSraghuram * descriptor. 419206db247cSraghuram */ 419306db247cSraghuram for (i = 0; i < priv_desc->ncookies; i++) { 419406db247cSraghuram bcopy(&priv_desc->memcookie[i], &ibnd_msg.memcookie[i], 419506db247cSraghuram sizeof (ldc_mem_cookie_t)); 419606db247cSraghuram } 419706db247cSraghuram 419806db247cSraghuram ibnd_msg.hdr.desc_handle = idx; 419906db247cSraghuram ibnd_msg.ncookies = priv_desc->ncookies; 420006db247cSraghuram ibnd_msg.nbytes = size; 420106db247cSraghuram 420206db247cSraghuram ldcp->ldc_stats.opackets++; 420306db247cSraghuram ldcp->ldc_stats.obytes += size; 420406db247cSraghuram 420506db247cSraghuram (void) vsw_send_msg(ldcp, (void *)&ibnd_msg, 420606db247cSraghuram sizeof (vnet_ibnd_desc_t), B_TRUE); 420706db247cSraghuram 420806db247cSraghuram vsw_descrsend_free_exit: 420906db247cSraghuram 421006db247cSraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id); 421106db247cSraghuram return (status); 421206db247cSraghuram } 421306db247cSraghuram 421406db247cSraghuram static void 421506db247cSraghuram vsw_send_ver(void *arg) 421606db247cSraghuram { 421706db247cSraghuram vsw_ldc_t *ldcp = (vsw_ldc_t *)arg; 421806db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 421906db247cSraghuram lane_t *lp = &ldcp->lane_out; 422006db247cSraghuram vio_ver_msg_t ver_msg; 422106db247cSraghuram 422206db247cSraghuram D1(vswp, "%s enter", __func__); 422306db247cSraghuram 422406db247cSraghuram ver_msg.tag.vio_msgtype = VIO_TYPE_CTRL; 422506db247cSraghuram ver_msg.tag.vio_subtype = VIO_SUBTYPE_INFO; 422606db247cSraghuram ver_msg.tag.vio_subtype_env = VIO_VER_INFO; 422706db247cSraghuram ver_msg.tag.vio_sid = ldcp->local_session; 422806db247cSraghuram 4229f0ca1d9aSsb155480 if (vsw_obp_ver_proto_workaround == B_FALSE) { 423006db247cSraghuram ver_msg.ver_major = vsw_versions[0].ver_major; 423106db247cSraghuram ver_msg.ver_minor = vsw_versions[0].ver_minor; 4232f0ca1d9aSsb155480 } else { 4233f0ca1d9aSsb155480 /* use the major,minor that we've ack'd */ 4234f0ca1d9aSsb155480 lane_t *lpi = &ldcp->lane_in; 4235f0ca1d9aSsb155480 ver_msg.ver_major = lpi->ver_major; 4236f0ca1d9aSsb155480 ver_msg.ver_minor = lpi->ver_minor; 4237f0ca1d9aSsb155480 } 423806db247cSraghuram ver_msg.dev_class = VDEV_NETWORK_SWITCH; 423906db247cSraghuram 424006db247cSraghuram lp->lstate |= VSW_VER_INFO_SENT; 424106db247cSraghuram lp->ver_major = ver_msg.ver_major; 424206db247cSraghuram lp->ver_minor = ver_msg.ver_minor; 424306db247cSraghuram 424406db247cSraghuram DUMP_TAG(ver_msg.tag); 424506db247cSraghuram 424606db247cSraghuram (void) vsw_send_msg(ldcp, &ver_msg, sizeof (vio_ver_msg_t), B_TRUE); 424706db247cSraghuram 424806db247cSraghuram D1(vswp, "%s (%d): exit", __func__, ldcp->ldc_id); 424906db247cSraghuram } 425006db247cSraghuram 425106db247cSraghuram static void 425206db247cSraghuram vsw_send_attr(vsw_ldc_t *ldcp) 425306db247cSraghuram { 425406db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 425506db247cSraghuram lane_t *lp = &ldcp->lane_out; 425606db247cSraghuram vnet_attr_msg_t attr_msg; 425706db247cSraghuram 425806db247cSraghuram D1(vswp, "%s (%ld) enter", __func__, ldcp->ldc_id); 425906db247cSraghuram 426006db247cSraghuram /* 426106db247cSraghuram * Subtype is set to INFO by default 426206db247cSraghuram */ 426306db247cSraghuram attr_msg.tag.vio_msgtype = VIO_TYPE_CTRL; 426406db247cSraghuram attr_msg.tag.vio_subtype = VIO_SUBTYPE_INFO; 426506db247cSraghuram attr_msg.tag.vio_subtype_env = VIO_ATTR_INFO; 426606db247cSraghuram attr_msg.tag.vio_sid = ldcp->local_session; 426706db247cSraghuram 426806db247cSraghuram /* payload copied from default settings for lane */ 426906db247cSraghuram attr_msg.mtu = lp->mtu; 427006db247cSraghuram attr_msg.addr_type = lp->addr_type; 427106db247cSraghuram attr_msg.xfer_mode = lp->xfer_mode; 427206db247cSraghuram attr_msg.ack_freq = lp->xfer_mode; 42737bd3a2e2SSriharsha Basavapatna attr_msg.options = lp->dring_mode; 427406db247cSraghuram 427506db247cSraghuram READ_ENTER(&vswp->if_lockrw); 4276f2b610cfSwentaoy attr_msg.addr = vnet_macaddr_strtoul((vswp->if_addr).ether_addr_octet); 427706db247cSraghuram RW_EXIT(&vswp->if_lockrw); 427806db247cSraghuram 427906db247cSraghuram ldcp->lane_out.lstate |= VSW_ATTR_INFO_SENT; 428006db247cSraghuram 428106db247cSraghuram DUMP_TAG(attr_msg.tag); 428206db247cSraghuram 428306db247cSraghuram (void) vsw_send_msg(ldcp, &attr_msg, sizeof (vnet_attr_msg_t), B_TRUE); 428406db247cSraghuram 428506db247cSraghuram D1(vswp, "%s (%ld) exit", __func__, ldcp->ldc_id); 428606db247cSraghuram } 428706db247cSraghuram 428806db247cSraghuram static void 428906db247cSraghuram vsw_send_dring_info(vsw_ldc_t *ldcp) 429006db247cSraghuram { 42917bd3a2e2SSriharsha Basavapatna int msgsize; 42927bd3a2e2SSriharsha Basavapatna void *msg; 429306db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 42947bd3a2e2SSriharsha Basavapatna vsw_port_t *port = ldcp->ldc_port; 42957bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_out; 42967bd3a2e2SSriharsha Basavapatna vgen_stats_t *statsp = &ldcp->ldc_stats; 429706db247cSraghuram 429806db247cSraghuram D1(vswp, "%s: (%ld) enter", __func__, ldcp->ldc_id); 429906db247cSraghuram 43007bd3a2e2SSriharsha Basavapatna /* dring mode has been negotiated in attr phase; save in stats */ 43017bd3a2e2SSriharsha Basavapatna statsp->dring_mode = lp->dring_mode; 43027bd3a2e2SSriharsha Basavapatna 43037bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 43047bd3a2e2SSriharsha Basavapatna /* 43057bd3a2e2SSriharsha Basavapatna * Change the transmit routine for RxDringData mode. 43067bd3a2e2SSriharsha Basavapatna */ 43077bd3a2e2SSriharsha Basavapatna port->transmit = vsw_dringsend_shm; 43087bd3a2e2SSriharsha Basavapatna msg = (void *) vsw_create_rx_dring_info(ldcp); 43097bd3a2e2SSriharsha Basavapatna if (msg == NULL) { 431006db247cSraghuram return; 431106db247cSraghuram } 43127bd3a2e2SSriharsha Basavapatna msgsize = 43137bd3a2e2SSriharsha Basavapatna VNET_DRING_REG_EXT_MSG_SIZE(lp->dringp->data_ncookies); 43147bd3a2e2SSriharsha Basavapatna ldcp->rcv_thread = thread_create(NULL, 2 * DEFAULTSTKSZ, 43157bd3a2e2SSriharsha Basavapatna vsw_ldc_rcv_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri); 43167bd3a2e2SSriharsha Basavapatna ldcp->rx_dringdata = vsw_process_dringdata_shm; 43177bd3a2e2SSriharsha Basavapatna } else { 43187bd3a2e2SSriharsha Basavapatna msg = (void *) vsw_create_tx_dring_info(ldcp); 43197bd3a2e2SSriharsha Basavapatna if (msg == NULL) { 43207bd3a2e2SSriharsha Basavapatna return; 43217bd3a2e2SSriharsha Basavapatna } 43227bd3a2e2SSriharsha Basavapatna msgsize = sizeof (vio_dring_reg_msg_t); 43237bd3a2e2SSriharsha Basavapatna ldcp->msg_thread = thread_create(NULL, 2 * DEFAULTSTKSZ, 43247bd3a2e2SSriharsha Basavapatna vsw_ldc_msg_worker, ldcp, 0, &p0, TS_RUN, maxclsyspri); 43257bd3a2e2SSriharsha Basavapatna ldcp->rx_dringdata = vsw_process_dringdata; 43267bd3a2e2SSriharsha Basavapatna } 432706db247cSraghuram 43287bd3a2e2SSriharsha Basavapatna lp->lstate |= VSW_DRING_INFO_SENT; 43297bd3a2e2SSriharsha Basavapatna DUMP_TAG_PTR((vio_msg_tag_t *)msg); 43307bd3a2e2SSriharsha Basavapatna (void) vsw_send_msg(ldcp, msg, msgsize, B_TRUE); 43317bd3a2e2SSriharsha Basavapatna kmem_free(msg, msgsize); 433206db247cSraghuram 433306db247cSraghuram D1(vswp, "%s: (%ld) exit", __func__, ldcp->ldc_id); 433406db247cSraghuram } 433506db247cSraghuram 433606db247cSraghuram static void 433706db247cSraghuram vsw_send_rdx(vsw_ldc_t *ldcp) 433806db247cSraghuram { 433906db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 434006db247cSraghuram vio_rdx_msg_t rdx_msg; 434106db247cSraghuram 434206db247cSraghuram D1(vswp, "%s (%ld) enter", __func__, ldcp->ldc_id); 434306db247cSraghuram 434406db247cSraghuram rdx_msg.tag.vio_msgtype = VIO_TYPE_CTRL; 434506db247cSraghuram rdx_msg.tag.vio_subtype = VIO_SUBTYPE_INFO; 434606db247cSraghuram rdx_msg.tag.vio_subtype_env = VIO_RDX; 434706db247cSraghuram rdx_msg.tag.vio_sid = ldcp->local_session; 434806db247cSraghuram 434906db247cSraghuram ldcp->lane_in.lstate |= VSW_RDX_INFO_SENT; 435006db247cSraghuram 435106db247cSraghuram DUMP_TAG(rdx_msg.tag); 435206db247cSraghuram 435306db247cSraghuram (void) vsw_send_msg(ldcp, &rdx_msg, sizeof (vio_rdx_msg_t), B_TRUE); 435406db247cSraghuram 435506db247cSraghuram D1(vswp, "%s (%ld) exit", __func__, ldcp->ldc_id); 435606db247cSraghuram } 435706db247cSraghuram 435806db247cSraghuram /* 435906db247cSraghuram * Remove the specified address from the list of address maintained 436006db247cSraghuram * in this port node. 436106db247cSraghuram */ 436206db247cSraghuram mcst_addr_t * 436306db247cSraghuram vsw_del_addr(uint8_t devtype, void *arg, uint64_t addr) 436406db247cSraghuram { 436506db247cSraghuram vsw_t *vswp = NULL; 436606db247cSraghuram vsw_port_t *port = NULL; 436706db247cSraghuram mcst_addr_t *prev_p = NULL; 436806db247cSraghuram mcst_addr_t *curr_p = NULL; 436906db247cSraghuram 437006db247cSraghuram D1(NULL, "%s: enter : devtype %d : addr 0x%llx", 437106db247cSraghuram __func__, devtype, addr); 437206db247cSraghuram 437306db247cSraghuram if (devtype == VSW_VNETPORT) { 437406db247cSraghuram port = (vsw_port_t *)arg; 437506db247cSraghuram mutex_enter(&port->mca_lock); 437606db247cSraghuram prev_p = curr_p = port->mcap; 437706db247cSraghuram } else { 437806db247cSraghuram vswp = (vsw_t *)arg; 437906db247cSraghuram mutex_enter(&vswp->mca_lock); 438006db247cSraghuram prev_p = curr_p = vswp->mcap; 438106db247cSraghuram } 438206db247cSraghuram 438306db247cSraghuram while (curr_p != NULL) { 438406db247cSraghuram if (curr_p->addr == addr) { 438506db247cSraghuram D2(NULL, "%s: address found", __func__); 438606db247cSraghuram /* match found */ 438706db247cSraghuram if (prev_p == curr_p) { 438806db247cSraghuram /* list head */ 438906db247cSraghuram if (devtype == VSW_VNETPORT) 439006db247cSraghuram port->mcap = curr_p->nextp; 439106db247cSraghuram else 439206db247cSraghuram vswp->mcap = curr_p->nextp; 439306db247cSraghuram } else { 439406db247cSraghuram prev_p->nextp = curr_p->nextp; 439506db247cSraghuram } 439606db247cSraghuram break; 439706db247cSraghuram } else { 439806db247cSraghuram prev_p = curr_p; 439906db247cSraghuram curr_p = curr_p->nextp; 440006db247cSraghuram } 440106db247cSraghuram } 440206db247cSraghuram 440306db247cSraghuram if (devtype == VSW_VNETPORT) 440406db247cSraghuram mutex_exit(&port->mca_lock); 440506db247cSraghuram else 440606db247cSraghuram mutex_exit(&vswp->mca_lock); 440706db247cSraghuram 440806db247cSraghuram D1(NULL, "%s: exit", __func__); 440906db247cSraghuram 441006db247cSraghuram return (curr_p); 441106db247cSraghuram } 441206db247cSraghuram 441306db247cSraghuram /* 441406db247cSraghuram * Create a ring consisting of just a private portion and link 441506db247cSraghuram * it into the list of rings for the outbound lane. 441606db247cSraghuram * 441706db247cSraghuram * These type of rings are used primarily for temporary data 441806db247cSraghuram * storage (i.e. as data buffers). 441906db247cSraghuram */ 442006db247cSraghuram void 442106db247cSraghuram vsw_create_privring(vsw_ldc_t *ldcp) 442206db247cSraghuram { 44237bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 442406db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 442506db247cSraghuram 442606db247cSraghuram D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id); 442706db247cSraghuram 442806db247cSraghuram dp = kmem_zalloc(sizeof (dring_info_t), KM_SLEEP); 442906db247cSraghuram mutex_init(&dp->dlock, NULL, MUTEX_DRIVER, NULL); 44307bd3a2e2SSriharsha Basavapatna mutex_init(&dp->restart_lock, NULL, MUTEX_DRIVER, NULL); 44317bd3a2e2SSriharsha Basavapatna ldcp->lane_out.dringp = dp; 443206db247cSraghuram 443306db247cSraghuram /* no public section */ 443406db247cSraghuram dp->pub_addr = NULL; 443506db247cSraghuram dp->priv_addr = kmem_zalloc( 44367bd3a2e2SSriharsha Basavapatna (sizeof (vsw_private_desc_t) * vsw_num_descriptors), KM_SLEEP); 44377bd3a2e2SSriharsha Basavapatna dp->num_descriptors = vsw_num_descriptors; 443806db247cSraghuram 44397bd3a2e2SSriharsha Basavapatna if (vsw_setup_tx_dring(ldcp, dp)) { 444006db247cSraghuram DERR(vswp, "%s: setup of ring failed", __func__); 44417bd3a2e2SSriharsha Basavapatna vsw_destroy_tx_dring(ldcp); 444206db247cSraghuram return; 444306db247cSraghuram } 444406db247cSraghuram 444506db247cSraghuram /* haven't used any descriptors yet */ 444606db247cSraghuram dp->end_idx = 0; 444706db247cSraghuram dp->restart_reqd = B_TRUE; 444806db247cSraghuram 444906db247cSraghuram D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id); 445006db247cSraghuram } 445106db247cSraghuram 445206db247cSraghuram /* 445306db247cSraghuram * Set the default lane attributes. These are copied into 445406db247cSraghuram * the attr msg we send to our peer. If they are not acceptable 445506db247cSraghuram * then (currently) the handshake ends. 445606db247cSraghuram */ 445706db247cSraghuram static void 445806db247cSraghuram vsw_set_lane_attr(vsw_t *vswp, lane_t *lp) 445906db247cSraghuram { 446006db247cSraghuram bzero(lp, sizeof (lane_t)); 446106db247cSraghuram 446206db247cSraghuram READ_ENTER(&vswp->if_lockrw); 446306db247cSraghuram ether_copy(&(vswp->if_addr), &(lp->addr)); 446406db247cSraghuram RW_EXIT(&vswp->if_lockrw); 446506db247cSraghuram 4466c1c61f44Ssb155480 lp->mtu = vswp->max_frame_size; 446706db247cSraghuram lp->addr_type = ADDR_TYPE_MAC; 4468f0ca1d9aSsb155480 lp->xfer_mode = VIO_DRING_MODE_V1_0; 446906db247cSraghuram lp->ack_freq = 0; /* for shared mode */ 4470f0ca1d9aSsb155480 lp->seq_num = VNET_ISS; 447106db247cSraghuram } 447206db247cSraghuram 447306db247cSraghuram /* 44747bd3a2e2SSriharsha Basavapatna * Map the descriptor ring exported by the peer. 447506db247cSraghuram */ 44767bd3a2e2SSriharsha Basavapatna static dring_info_t * 44777bd3a2e2SSriharsha Basavapatna vsw_map_dring(vsw_ldc_t *ldcp, void *pkt) 447806db247cSraghuram { 44797bd3a2e2SSriharsha Basavapatna dring_info_t *dp = NULL; 4480f0ca1d9aSsb155480 lane_t *lp = &ldcp->lane_out; 4481f0ca1d9aSsb155480 44827bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 448306db247cSraghuram /* 44847bd3a2e2SSriharsha Basavapatna * In RxDringData mode, dring that we map in 44857bd3a2e2SSriharsha Basavapatna * becomes our transmit descriptor ring. 448606db247cSraghuram */ 44877bd3a2e2SSriharsha Basavapatna dp = vsw_map_tx_dring(ldcp, pkt); 44887b1f684aSSriharsha Basavapatna } else { 44897bd3a2e2SSriharsha Basavapatna /* 44907bd3a2e2SSriharsha Basavapatna * In TxDring mode, dring that we map in 44917bd3a2e2SSriharsha Basavapatna * becomes our receive descriptor ring. 44927bd3a2e2SSriharsha Basavapatna */ 44937bd3a2e2SSriharsha Basavapatna dp = vsw_map_rx_dring(ldcp, pkt); 44947b1f684aSSriharsha Basavapatna } 44957bd3a2e2SSriharsha Basavapatna return (dp); 449606db247cSraghuram } 449706db247cSraghuram 449806db247cSraghuram /* 44997bd3a2e2SSriharsha Basavapatna * Common dring mapping function used in both TxDring and RxDringData modes. 45007bd3a2e2SSriharsha Basavapatna */ 45017bd3a2e2SSriharsha Basavapatna dring_info_t * 45027bd3a2e2SSriharsha Basavapatna vsw_map_dring_cmn(vsw_ldc_t *ldcp, vio_dring_reg_msg_t *dring_pkt) 45037bd3a2e2SSriharsha Basavapatna { 45047bd3a2e2SSriharsha Basavapatna int rv; 45057bd3a2e2SSriharsha Basavapatna dring_info_t *dp; 45067bd3a2e2SSriharsha Basavapatna ldc_mem_info_t minfo; 45077bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 45087bd3a2e2SSriharsha Basavapatna 45097bd3a2e2SSriharsha Basavapatna /* 45107bd3a2e2SSriharsha Basavapatna * If the dring params are unacceptable then we NACK back. 45117bd3a2e2SSriharsha Basavapatna */ 45127bd3a2e2SSriharsha Basavapatna if ((dring_pkt->num_descriptors == 0) || 45137bd3a2e2SSriharsha Basavapatna (dring_pkt->descriptor_size == 0) || 45147bd3a2e2SSriharsha Basavapatna (dring_pkt->ncookies != 1)) { 45157bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s (%lld): invalid dring info", 45167bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id); 45177bd3a2e2SSriharsha Basavapatna return (NULL); 45187bd3a2e2SSriharsha Basavapatna } 45197bd3a2e2SSriharsha Basavapatna 45207bd3a2e2SSriharsha Basavapatna dp = kmem_zalloc(sizeof (dring_info_t), KM_SLEEP); 45217bd3a2e2SSriharsha Basavapatna 45227bd3a2e2SSriharsha Basavapatna dp->num_descriptors = dring_pkt->num_descriptors; 45237bd3a2e2SSriharsha Basavapatna dp->descriptor_size = dring_pkt->descriptor_size; 45247bd3a2e2SSriharsha Basavapatna dp->options = dring_pkt->options; 45257bd3a2e2SSriharsha Basavapatna dp->dring_ncookies = dring_pkt->ncookies; 45267bd3a2e2SSriharsha Basavapatna 45277bd3a2e2SSriharsha Basavapatna /* 45287bd3a2e2SSriharsha Basavapatna * Note: should only get one cookie. Enforced in 45297bd3a2e2SSriharsha Basavapatna * the ldc layer. 45307bd3a2e2SSriharsha Basavapatna */ 45317bd3a2e2SSriharsha Basavapatna bcopy(&dring_pkt->cookie[0], &dp->dring_cookie[0], 45327bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t)); 45337bd3a2e2SSriharsha Basavapatna 45347bd3a2e2SSriharsha Basavapatna rv = ldc_mem_dring_map(ldcp->ldc_handle, &dp->dring_cookie[0], 45357bd3a2e2SSriharsha Basavapatna dp->dring_ncookies, dp->num_descriptors, dp->descriptor_size, 45367bd3a2e2SSriharsha Basavapatna LDC_DIRECT_MAP, &(dp->dring_handle)); 45377bd3a2e2SSriharsha Basavapatna if (rv != 0) { 45387bd3a2e2SSriharsha Basavapatna goto fail; 45397bd3a2e2SSriharsha Basavapatna } 45407bd3a2e2SSriharsha Basavapatna 45417bd3a2e2SSriharsha Basavapatna rv = ldc_mem_dring_info(dp->dring_handle, &minfo); 45427bd3a2e2SSriharsha Basavapatna if (rv != 0) { 45437bd3a2e2SSriharsha Basavapatna goto fail; 45447bd3a2e2SSriharsha Basavapatna } 45457bd3a2e2SSriharsha Basavapatna /* store the address of the ring */ 45467bd3a2e2SSriharsha Basavapatna dp->pub_addr = minfo.vaddr; 45477bd3a2e2SSriharsha Basavapatna 45487bd3a2e2SSriharsha Basavapatna /* cache the dring mtype */ 45497bd3a2e2SSriharsha Basavapatna dp->dring_mtype = minfo.mtype; 45507bd3a2e2SSriharsha Basavapatna 45517bd3a2e2SSriharsha Basavapatna /* no private section as we are importing */ 45527bd3a2e2SSriharsha Basavapatna dp->priv_addr = NULL; 45537bd3a2e2SSriharsha Basavapatna 45547bd3a2e2SSriharsha Basavapatna /* 45557bd3a2e2SSriharsha Basavapatna * Using simple mono increasing int for ident at the moment. 45567bd3a2e2SSriharsha Basavapatna */ 45577bd3a2e2SSriharsha Basavapatna dp->ident = ldcp->next_ident; 45587bd3a2e2SSriharsha Basavapatna ldcp->next_ident++; 45597bd3a2e2SSriharsha Basavapatna 45607bd3a2e2SSriharsha Basavapatna /* 45617bd3a2e2SSriharsha Basavapatna * Acknowledge it; we send back a unique dring identifier that 45627bd3a2e2SSriharsha Basavapatna * the sending side will use in future to refer to this 45637bd3a2e2SSriharsha Basavapatna * descriptor ring. 45647bd3a2e2SSriharsha Basavapatna */ 45657bd3a2e2SSriharsha Basavapatna dring_pkt->dring_ident = dp->ident; 45667bd3a2e2SSriharsha Basavapatna 45677bd3a2e2SSriharsha Basavapatna return (dp); 45687bd3a2e2SSriharsha Basavapatna fail: 45697bd3a2e2SSriharsha Basavapatna if (dp->dring_handle != NULL) { 45707bd3a2e2SSriharsha Basavapatna (void) ldc_mem_dring_unmap(dp->dring_handle); 45717bd3a2e2SSriharsha Basavapatna } 45727bd3a2e2SSriharsha Basavapatna kmem_free(dp, sizeof (*dp)); 45737bd3a2e2SSriharsha Basavapatna return (NULL); 45747bd3a2e2SSriharsha Basavapatna } 45757bd3a2e2SSriharsha Basavapatna 45767bd3a2e2SSriharsha Basavapatna /* 45777bd3a2e2SSriharsha Basavapatna * Unmap the descriptor ring exported by the peer. 45787bd3a2e2SSriharsha Basavapatna */ 45797bd3a2e2SSriharsha Basavapatna static void 45807bd3a2e2SSriharsha Basavapatna vsw_unmap_dring(vsw_ldc_t *ldcp) 45817bd3a2e2SSriharsha Basavapatna { 45827bd3a2e2SSriharsha Basavapatna lane_t *lane_out = &ldcp->lane_out; 45837bd3a2e2SSriharsha Basavapatna 45847bd3a2e2SSriharsha Basavapatna if (lane_out->dring_mode == VIO_RX_DRING_DATA) { 45857bd3a2e2SSriharsha Basavapatna vsw_unmap_tx_dring(ldcp); 45867bd3a2e2SSriharsha Basavapatna } else { 45877bd3a2e2SSriharsha Basavapatna vsw_unmap_rx_dring(ldcp); 45887bd3a2e2SSriharsha Basavapatna } 45897bd3a2e2SSriharsha Basavapatna } 45907bd3a2e2SSriharsha Basavapatna 45917bd3a2e2SSriharsha Basavapatna /* 45927bd3a2e2SSriharsha Basavapatna * Map the shared memory data buffer area exported by the peer. 45937bd3a2e2SSriharsha Basavapatna * Used in RxDringData mode only. 459406db247cSraghuram */ 459506db247cSraghuram static int 45967bd3a2e2SSriharsha Basavapatna vsw_map_data(vsw_ldc_t *ldcp, dring_info_t *dp, void *pkt) 459706db247cSraghuram { 45987bd3a2e2SSriharsha Basavapatna int rv; 45997bd3a2e2SSriharsha Basavapatna vio_dring_reg_ext_msg_t *emsg; 46007bd3a2e2SSriharsha Basavapatna vio_dring_reg_msg_t *msg = pkt; 46017bd3a2e2SSriharsha Basavapatna uint8_t *buf = (uint8_t *)msg->cookie; 46027bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp; 4603*34f94fbcSWENTAO YANG ldc_mem_info_t minfo; 460406db247cSraghuram 46057bd3a2e2SSriharsha Basavapatna /* skip over dring cookies */ 46067bd3a2e2SSriharsha Basavapatna ASSERT(msg->ncookies == 1); 46077bd3a2e2SSriharsha Basavapatna buf += (msg->ncookies * sizeof (ldc_mem_cookie_t)); 460806db247cSraghuram 46097bd3a2e2SSriharsha Basavapatna emsg = (vio_dring_reg_ext_msg_t *)buf; 46107bd3a2e2SSriharsha Basavapatna if (emsg->data_ncookies > VNET_DATA_AREA_COOKIES) { 461106db247cSraghuram return (1); 461206db247cSraghuram } 461306db247cSraghuram 46147bd3a2e2SSriharsha Basavapatna /* save # of data area cookies */ 46157bd3a2e2SSriharsha Basavapatna dp->data_ncookies = emsg->data_ncookies; 46167bd3a2e2SSriharsha Basavapatna 46177bd3a2e2SSriharsha Basavapatna /* save data area size */ 46187bd3a2e2SSriharsha Basavapatna dp->data_sz = emsg->data_area_size; 46197bd3a2e2SSriharsha Basavapatna 46207bd3a2e2SSriharsha Basavapatna /* allocate ldc mem handle for data area */ 46217bd3a2e2SSriharsha Basavapatna rv = ldc_mem_alloc_handle(ldcp->ldc_handle, &dp->data_handle); 46227bd3a2e2SSriharsha Basavapatna if (rv != 0) { 46237bd3a2e2SSriharsha Basavapatna cmn_err(CE_WARN, "ldc_mem_alloc_handle failed\n"); 46247bd3a2e2SSriharsha Basavapatna DWARN(vswp, "%s (%lld) ldc_mem_alloc_handle() failed: %d\n", 46257bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, rv); 46267bd3a2e2SSriharsha Basavapatna return (1); 46277bd3a2e2SSriharsha Basavapatna } 46287bd3a2e2SSriharsha Basavapatna 46297bd3a2e2SSriharsha Basavapatna /* map the data area */ 46307bd3a2e2SSriharsha Basavapatna rv = ldc_mem_map(dp->data_handle, emsg->data_cookie, 46317bd3a2e2SSriharsha Basavapatna emsg->data_ncookies, LDC_DIRECT_MAP, LDC_MEM_R, 46327bd3a2e2SSriharsha Basavapatna (caddr_t *)&dp->data_addr, NULL); 46337bd3a2e2SSriharsha Basavapatna if (rv != 0) { 46347bd3a2e2SSriharsha Basavapatna cmn_err(CE_WARN, "ldc_mem_map failed\n"); 46357bd3a2e2SSriharsha Basavapatna DWARN(vswp, "%s (%lld) ldc_mem_map() failed: %d\n", 46367bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, rv); 46377bd3a2e2SSriharsha Basavapatna return (1); 46387bd3a2e2SSriharsha Basavapatna } 46397bd3a2e2SSriharsha Basavapatna 4640*34f94fbcSWENTAO YANG /* get the map info */ 4641*34f94fbcSWENTAO YANG rv = ldc_mem_info(dp->data_handle, &minfo); 4642*34f94fbcSWENTAO YANG if (rv != 0) { 4643*34f94fbcSWENTAO YANG cmn_err(CE_WARN, "ldc_mem_info failed\n"); 4644*34f94fbcSWENTAO YANG DWARN(vswp, "%s (%lld) ldc_mem_info() failed: %d\n", 4645*34f94fbcSWENTAO YANG __func__, ldcp->ldc_id, rv); 4646*34f94fbcSWENTAO YANG return (1); 4647*34f94fbcSWENTAO YANG } 4648*34f94fbcSWENTAO YANG 4649*34f94fbcSWENTAO YANG if (minfo.mtype != LDC_DIRECT_MAP) { 4650*34f94fbcSWENTAO YANG DWARN(vswp, "%s (%lld) mtype(%d) is not direct map\n", 4651*34f94fbcSWENTAO YANG __func__, ldcp->ldc_id, minfo.mtype); 4652*34f94fbcSWENTAO YANG return (1); 4653*34f94fbcSWENTAO YANG } 4654*34f94fbcSWENTAO YANG 46557bd3a2e2SSriharsha Basavapatna /* allocate memory for data area cookies */ 46567bd3a2e2SSriharsha Basavapatna dp->data_cookie = kmem_zalloc(emsg->data_ncookies * 46577bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t), KM_SLEEP); 46587bd3a2e2SSriharsha Basavapatna 46597bd3a2e2SSriharsha Basavapatna /* save data area cookies */ 46607bd3a2e2SSriharsha Basavapatna bcopy(emsg->data_cookie, dp->data_cookie, 46617bd3a2e2SSriharsha Basavapatna emsg->data_ncookies * sizeof (ldc_mem_cookie_t)); 46627bd3a2e2SSriharsha Basavapatna 46637bd3a2e2SSriharsha Basavapatna return (0); 466406db247cSraghuram } 466506db247cSraghuram 466606db247cSraghuram /* 46677bd3a2e2SSriharsha Basavapatna * Reset and free all the resources associated with the channel. 466806db247cSraghuram */ 466906db247cSraghuram static void 467006db247cSraghuram vsw_free_lane_resources(vsw_ldc_t *ldcp, uint64_t dir) 467106db247cSraghuram { 46727bd3a2e2SSriharsha Basavapatna lane_t *lp; 467306db247cSraghuram 467406db247cSraghuram D1(ldcp->ldc_vswp, "%s (%lld): enter", __func__, ldcp->ldc_id); 467506db247cSraghuram 467606db247cSraghuram if (dir == INBOUND) { 467706db247cSraghuram D2(ldcp->ldc_vswp, "%s: freeing INBOUND lane" 467806db247cSraghuram " of channel %lld", __func__, ldcp->ldc_id); 467906db247cSraghuram lp = &ldcp->lane_in; 468006db247cSraghuram } else { 468106db247cSraghuram D2(ldcp->ldc_vswp, "%s: freeing OUTBOUND lane" 468206db247cSraghuram " of channel %lld", __func__, ldcp->ldc_id); 468306db247cSraghuram lp = &ldcp->lane_out; 468406db247cSraghuram } 468506db247cSraghuram 468606db247cSraghuram lp->lstate = VSW_LANE_INACTIV; 4687f0ca1d9aSsb155480 lp->seq_num = VNET_ISS; 468806db247cSraghuram 468906db247cSraghuram if (dir == INBOUND) { 46907bd3a2e2SSriharsha Basavapatna /* Unmap the remote dring which is imported from the peer */ 46917bd3a2e2SSriharsha Basavapatna vsw_unmap_dring(ldcp); 469206db247cSraghuram } else { 46937bd3a2e2SSriharsha Basavapatna /* Destroy the local dring which is exported to the peer */ 46947bd3a2e2SSriharsha Basavapatna vsw_destroy_dring(ldcp); 469506db247cSraghuram } 469606db247cSraghuram 469706db247cSraghuram D1(ldcp->ldc_vswp, "%s (%lld): exit", __func__, ldcp->ldc_id); 469806db247cSraghuram } 469906db247cSraghuram 470006db247cSraghuram /* 47017bd3a2e2SSriharsha Basavapatna * Destroy the descriptor ring. 470206db247cSraghuram */ 4703a248ff60SWENTAO YANG static void 47047bd3a2e2SSriharsha Basavapatna vsw_destroy_dring(vsw_ldc_t *ldcp) 470506db247cSraghuram { 47067bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_out; 470706db247cSraghuram 47087bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) { 47097bd3a2e2SSriharsha Basavapatna vsw_destroy_rx_dring(ldcp); 47107bd3a2e2SSriharsha Basavapatna } else { 47117bd3a2e2SSriharsha Basavapatna vsw_destroy_tx_dring(ldcp); 471206db247cSraghuram } 471306db247cSraghuram } 471406db247cSraghuram 471506db247cSraghuram /* 471606db247cSraghuram * vsw_ldc_tx_worker -- A per LDC worker thread to transmit data. 471706db247cSraghuram * This thread is woken up by the vsw_portsend to transmit 471806db247cSraghuram * packets. 471906db247cSraghuram */ 472006db247cSraghuram static void 472106db247cSraghuram vsw_ldc_tx_worker(void *arg) 472206db247cSraghuram { 472306db247cSraghuram callb_cpr_t cprinfo; 472406db247cSraghuram vsw_ldc_t *ldcp = (vsw_ldc_t *)arg; 472506db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 472606db247cSraghuram mblk_t *mp; 472706db247cSraghuram mblk_t *tmp; 472806db247cSraghuram 472906db247cSraghuram D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id); 473006db247cSraghuram CALLB_CPR_INIT(&cprinfo, &ldcp->tx_thr_lock, callb_generic_cpr, 473106db247cSraghuram "vnet_tx_thread"); 473206db247cSraghuram mutex_enter(&ldcp->tx_thr_lock); 473306db247cSraghuram while (!(ldcp->tx_thr_flags & VSW_WTHR_STOP)) { 473406db247cSraghuram 473506db247cSraghuram CALLB_CPR_SAFE_BEGIN(&cprinfo); 473606db247cSraghuram /* 473706db247cSraghuram * Wait until the data is received or a stop 473806db247cSraghuram * request is received. 473906db247cSraghuram */ 474006db247cSraghuram while (!(ldcp->tx_thr_flags & VSW_WTHR_STOP) && 474106db247cSraghuram (ldcp->tx_mhead == NULL)) { 474206db247cSraghuram cv_wait(&ldcp->tx_thr_cv, &ldcp->tx_thr_lock); 474306db247cSraghuram } 474406db247cSraghuram CALLB_CPR_SAFE_END(&cprinfo, &ldcp->tx_thr_lock) 474506db247cSraghuram 474606db247cSraghuram /* 474706db247cSraghuram * First process the stop request. 474806db247cSraghuram */ 474906db247cSraghuram if (ldcp->tx_thr_flags & VSW_WTHR_STOP) { 475006db247cSraghuram D2(vswp, "%s(%lld):tx thread stopped\n", 475106db247cSraghuram __func__, ldcp->ldc_id); 475206db247cSraghuram break; 475306db247cSraghuram } 475406db247cSraghuram mp = ldcp->tx_mhead; 475506db247cSraghuram ldcp->tx_mhead = ldcp->tx_mtail = NULL; 4756f0ca1d9aSsb155480 ldcp->tx_cnt = 0; 475706db247cSraghuram mutex_exit(&ldcp->tx_thr_lock); 475806db247cSraghuram D2(vswp, "%s(%lld):calling vsw_ldcsend\n", 475906db247cSraghuram __func__, ldcp->ldc_id); 476006db247cSraghuram while (mp != NULL) { 476106db247cSraghuram tmp = mp->b_next; 476206db247cSraghuram mp->b_next = mp->b_prev = NULL; 476306db247cSraghuram (void) vsw_ldcsend(ldcp, mp, vsw_ldc_tx_retries); 476406db247cSraghuram mp = tmp; 476506db247cSraghuram } 476606db247cSraghuram mutex_enter(&ldcp->tx_thr_lock); 476706db247cSraghuram } 476806db247cSraghuram 476906db247cSraghuram /* 477006db247cSraghuram * Update the run status and wakeup the thread that 477106db247cSraghuram * has sent the stop request. 477206db247cSraghuram */ 47736f09f0feSWENTAO YANG ldcp->tx_thr_flags &= ~VSW_WTHR_STOP; 47746f09f0feSWENTAO YANG ldcp->tx_thread = NULL; 477506db247cSraghuram CALLB_CPR_EXIT(&cprinfo); 477606db247cSraghuram D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id); 477706db247cSraghuram thread_exit(); 477806db247cSraghuram } 477906db247cSraghuram 478006db247cSraghuram /* vsw_stop_tx_thread -- Co-ordinate with receive thread to stop it */ 478106db247cSraghuram static void 478206db247cSraghuram vsw_stop_tx_thread(vsw_ldc_t *ldcp) 478306db247cSraghuram { 47846f09f0feSWENTAO YANG kt_did_t tid = 0; 478506db247cSraghuram vsw_t *vswp = ldcp->ldc_vswp; 478606db247cSraghuram 478706db247cSraghuram D1(vswp, "%s(%lld):enter\n", __func__, ldcp->ldc_id); 478806db247cSraghuram /* 478906db247cSraghuram * Send a stop request by setting the stop flag and 479006db247cSraghuram * wait until the receive thread stops. 479106db247cSraghuram */ 479206db247cSraghuram mutex_enter(&ldcp->tx_thr_lock); 47936f09f0feSWENTAO YANG if (ldcp->tx_thread != NULL) { 47946f09f0feSWENTAO YANG tid = ldcp->tx_thread->t_did; 479506db247cSraghuram ldcp->tx_thr_flags |= VSW_WTHR_STOP; 479606db247cSraghuram cv_signal(&ldcp->tx_thr_cv); 479706db247cSraghuram } 479806db247cSraghuram mutex_exit(&ldcp->tx_thr_lock); 47996f09f0feSWENTAO YANG 48006f09f0feSWENTAO YANG if (tid != 0) { 48016f09f0feSWENTAO YANG thread_join(tid); 48026f09f0feSWENTAO YANG } 48036f09f0feSWENTAO YANG 480406db247cSraghuram D1(vswp, "%s(%lld):exit\n", __func__, ldcp->ldc_id); 480506db247cSraghuram } 480606db247cSraghuram 4807*34f94fbcSWENTAO YANG static int 4808*34f94fbcSWENTAO YANG vsw_mapin_avail(vsw_ldc_t *ldcp) 4809*34f94fbcSWENTAO YANG { 4810*34f94fbcSWENTAO YANG int rv; 4811*34f94fbcSWENTAO YANG ldc_info_t info; 4812*34f94fbcSWENTAO YANG uint64_t mapin_sz_req; 4813*34f94fbcSWENTAO YANG uint64_t dblk_sz; 4814*34f94fbcSWENTAO YANG vsw_t *vswp = ldcp->ldc_vswp; 4815*34f94fbcSWENTAO YANG 4816*34f94fbcSWENTAO YANG rv = ldc_info(ldcp->ldc_handle, &info); 4817*34f94fbcSWENTAO YANG if (rv != 0) { 4818*34f94fbcSWENTAO YANG return (B_FALSE); 4819*34f94fbcSWENTAO YANG } 4820*34f94fbcSWENTAO YANG 4821*34f94fbcSWENTAO YANG dblk_sz = RXDRING_DBLK_SZ(vswp->max_frame_size); 4822*34f94fbcSWENTAO YANG mapin_sz_req = (VSW_RXDRING_NRBUFS * dblk_sz); 4823*34f94fbcSWENTAO YANG 4824*34f94fbcSWENTAO YANG if (info.direct_map_size_max >= mapin_sz_req) { 4825*34f94fbcSWENTAO YANG return (B_TRUE); 4826*34f94fbcSWENTAO YANG } 4827*34f94fbcSWENTAO YANG 4828*34f94fbcSWENTAO YANG return (B_FALSE); 4829*34f94fbcSWENTAO YANG } 4830*34f94fbcSWENTAO YANG 483106db247cSraghuram /* 483206db247cSraghuram * Debugging routines 483306db247cSraghuram */ 483406db247cSraghuram static void 483506db247cSraghuram display_state(void) 483606db247cSraghuram { 483706db247cSraghuram vsw_t *vswp; 483806db247cSraghuram vsw_port_list_t *plist; 483906db247cSraghuram vsw_port_t *port; 484006db247cSraghuram vsw_ldc_t *ldcp; 484106db247cSraghuram extern vsw_t *vsw_head; 484206db247cSraghuram 484306db247cSraghuram cmn_err(CE_NOTE, "***** system state *****"); 484406db247cSraghuram 484506db247cSraghuram for (vswp = vsw_head; vswp; vswp = vswp->next) { 484606db247cSraghuram plist = &vswp->plist; 484706db247cSraghuram READ_ENTER(&plist->lockrw); 484806db247cSraghuram cmn_err(CE_CONT, "vsw instance %d has %d ports attached\n", 484906db247cSraghuram vswp->instance, plist->num_ports); 485006db247cSraghuram 485106db247cSraghuram for (port = plist->head; port != NULL; port = port->p_next) { 485206db247cSraghuram cmn_err(CE_CONT, "port %d : %d ldcs attached\n", 4853c1c61f44Ssb155480 port->p_instance, port->num_ldcs); 48547bd3a2e2SSriharsha Basavapatna ldcp = port->ldcp; 485506db247cSraghuram cmn_err(CE_CONT, "chan %lu : dev %d : " 485606db247cSraghuram "status %d : phase %u\n", 485706db247cSraghuram ldcp->ldc_id, ldcp->dev_class, 485806db247cSraghuram ldcp->ldc_status, ldcp->hphase); 485906db247cSraghuram cmn_err(CE_CONT, "chan %lu : lsession %lu : " 486006db247cSraghuram "psession %lu\n", ldcp->ldc_id, 486106db247cSraghuram ldcp->local_session, ldcp->peer_session); 486206db247cSraghuram 486306db247cSraghuram cmn_err(CE_CONT, "Inbound lane:\n"); 486406db247cSraghuram display_lane(&ldcp->lane_in); 486506db247cSraghuram cmn_err(CE_CONT, "Outbound lane:\n"); 486606db247cSraghuram display_lane(&ldcp->lane_out); 486706db247cSraghuram } 486806db247cSraghuram RW_EXIT(&plist->lockrw); 486906db247cSraghuram } 487006db247cSraghuram cmn_err(CE_NOTE, "***** system state *****"); 487106db247cSraghuram } 487206db247cSraghuram 487306db247cSraghuram static void 487406db247cSraghuram display_lane(lane_t *lp) 487506db247cSraghuram { 48767bd3a2e2SSriharsha Basavapatna dring_info_t *drp = lp->dringp; 487706db247cSraghuram 487806db247cSraghuram cmn_err(CE_CONT, "ver 0x%x:0x%x : state %lx : mtu 0x%lx\n", 487906db247cSraghuram lp->ver_major, lp->ver_minor, lp->lstate, lp->mtu); 488006db247cSraghuram cmn_err(CE_CONT, "addr_type %d : addr 0x%lx : xmode %d\n", 488106db247cSraghuram lp->addr_type, lp->addr, lp->xfer_mode); 488206db247cSraghuram cmn_err(CE_CONT, "dringp 0x%lx\n", (uint64_t)lp->dringp); 488306db247cSraghuram 488406db247cSraghuram cmn_err(CE_CONT, "Dring info:\n"); 488506db247cSraghuram cmn_err(CE_CONT, "\tnum_desc %u : dsize %u\n", 488606db247cSraghuram drp->num_descriptors, drp->descriptor_size); 48877bd3a2e2SSriharsha Basavapatna cmn_err(CE_CONT, "\thandle 0x%lx\n", drp->dring_handle); 488806db247cSraghuram cmn_err(CE_CONT, "\tpub_addr 0x%lx : priv_addr 0x%lx\n", 488906db247cSraghuram (uint64_t)drp->pub_addr, (uint64_t)drp->priv_addr); 489006db247cSraghuram cmn_err(CE_CONT, "\tident 0x%lx : end_idx %lu\n", 489106db247cSraghuram drp->ident, drp->end_idx); 489206db247cSraghuram display_ring(drp); 489306db247cSraghuram } 489406db247cSraghuram 489506db247cSraghuram static void 489606db247cSraghuram display_ring(dring_info_t *dringp) 489706db247cSraghuram { 489806db247cSraghuram uint64_t i; 489906db247cSraghuram uint64_t priv_count = 0; 490006db247cSraghuram uint64_t pub_count = 0; 490106db247cSraghuram vnet_public_desc_t *pub_addr = NULL; 490206db247cSraghuram vsw_private_desc_t *priv_addr = NULL; 490306db247cSraghuram 49047bd3a2e2SSriharsha Basavapatna for (i = 0; i < vsw_num_descriptors; i++) { 490506db247cSraghuram if (dringp->pub_addr != NULL) { 490606db247cSraghuram pub_addr = (vnet_public_desc_t *)dringp->pub_addr + i; 490706db247cSraghuram 490806db247cSraghuram if (pub_addr->hdr.dstate == VIO_DESC_FREE) 490906db247cSraghuram pub_count++; 491006db247cSraghuram } 491106db247cSraghuram 491206db247cSraghuram if (dringp->priv_addr != NULL) { 491306db247cSraghuram priv_addr = (vsw_private_desc_t *)dringp->priv_addr + i; 491406db247cSraghuram 491506db247cSraghuram if (priv_addr->dstate == VIO_DESC_FREE) 491606db247cSraghuram priv_count++; 491706db247cSraghuram } 491806db247cSraghuram } 491906db247cSraghuram cmn_err(CE_CONT, "\t%lu elements: %lu priv free: %lu pub free\n", 492006db247cSraghuram i, priv_count, pub_count); 492106db247cSraghuram } 492206db247cSraghuram 492306db247cSraghuram static void 492406db247cSraghuram dump_flags(uint64_t state) 492506db247cSraghuram { 492606db247cSraghuram int i; 492706db247cSraghuram 492806db247cSraghuram typedef struct flag_name { 492906db247cSraghuram int flag_val; 493006db247cSraghuram char *flag_name; 493106db247cSraghuram } flag_name_t; 493206db247cSraghuram 493306db247cSraghuram flag_name_t flags[] = { 493406db247cSraghuram VSW_VER_INFO_SENT, "VSW_VER_INFO_SENT", 493506db247cSraghuram VSW_VER_INFO_RECV, "VSW_VER_INFO_RECV", 493606db247cSraghuram VSW_VER_ACK_RECV, "VSW_VER_ACK_RECV", 493706db247cSraghuram VSW_VER_ACK_SENT, "VSW_VER_ACK_SENT", 493806db247cSraghuram VSW_VER_NACK_RECV, "VSW_VER_NACK_RECV", 493906db247cSraghuram VSW_VER_NACK_SENT, "VSW_VER_NACK_SENT", 494006db247cSraghuram VSW_ATTR_INFO_SENT, "VSW_ATTR_INFO_SENT", 494106db247cSraghuram VSW_ATTR_INFO_RECV, "VSW_ATTR_INFO_RECV", 494206db247cSraghuram VSW_ATTR_ACK_SENT, "VSW_ATTR_ACK_SENT", 494306db247cSraghuram VSW_ATTR_ACK_RECV, "VSW_ATTR_ACK_RECV", 494406db247cSraghuram VSW_ATTR_NACK_SENT, "VSW_ATTR_NACK_SENT", 494506db247cSraghuram VSW_ATTR_NACK_RECV, "VSW_ATTR_NACK_RECV", 494606db247cSraghuram VSW_DRING_INFO_SENT, "VSW_DRING_INFO_SENT", 494706db247cSraghuram VSW_DRING_INFO_RECV, "VSW_DRING_INFO_RECV", 494806db247cSraghuram VSW_DRING_ACK_SENT, "VSW_DRING_ACK_SENT", 494906db247cSraghuram VSW_DRING_ACK_RECV, "VSW_DRING_ACK_RECV", 495006db247cSraghuram VSW_DRING_NACK_SENT, "VSW_DRING_NACK_SENT", 495106db247cSraghuram VSW_DRING_NACK_RECV, "VSW_DRING_NACK_RECV", 495206db247cSraghuram VSW_RDX_INFO_SENT, "VSW_RDX_INFO_SENT", 495306db247cSraghuram VSW_RDX_INFO_RECV, "VSW_RDX_INFO_RECV", 495406db247cSraghuram VSW_RDX_ACK_SENT, "VSW_RDX_ACK_SENT", 495506db247cSraghuram VSW_RDX_ACK_RECV, "VSW_RDX_ACK_RECV", 495606db247cSraghuram VSW_RDX_NACK_SENT, "VSW_RDX_NACK_SENT", 495706db247cSraghuram VSW_RDX_NACK_RECV, "VSW_RDX_NACK_RECV", 495806db247cSraghuram VSW_MCST_INFO_SENT, "VSW_MCST_INFO_SENT", 495906db247cSraghuram VSW_MCST_INFO_RECV, "VSW_MCST_INFO_RECV", 496006db247cSraghuram VSW_MCST_ACK_SENT, "VSW_MCST_ACK_SENT", 496106db247cSraghuram VSW_MCST_ACK_RECV, "VSW_MCST_ACK_RECV", 496206db247cSraghuram VSW_MCST_NACK_SENT, "VSW_MCST_NACK_SENT", 496306db247cSraghuram VSW_MCST_NACK_RECV, "VSW_MCST_NACK_RECV", 496406db247cSraghuram VSW_LANE_ACTIVE, "VSW_LANE_ACTIVE"}; 496506db247cSraghuram 496606db247cSraghuram DERR(NULL, "DUMP_FLAGS: %llx\n", state); 496706db247cSraghuram for (i = 0; i < sizeof (flags)/sizeof (flag_name_t); i++) { 496806db247cSraghuram if (state & flags[i].flag_val) 496906db247cSraghuram DERR(NULL, "DUMP_FLAGS %s", flags[i].flag_name); 497006db247cSraghuram } 497106db247cSraghuram } 4972