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>
71c1c61f44Ssb #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);
88c1c61f44Ssb int vsw_port_attach(vsw_port_t *portp);
8906db247cSraghuram vsw_port_t *vsw_lookup_port(vsw_t *vswp, int p_instance);
90c1c61f44Ssb 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 *);
106f0ca1d9aSsb static void vsw_set_vnet_proto_ops(vsw_ldc_t *ldcp);
107f0ca1d9aSsb 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 *);
121f0ca1d9aSsb static void vsw_process_data_pkt(vsw_ldc_t *, void *, vio_msg_tag_t *,
122f0ca1d9aSsb uint32_t);
123f0ca1d9aSsb static void vsw_process_pkt_data_nop(void *, void *, uint32_t);
124f0ca1d9aSsb static void vsw_process_pkt_data(void *, void *, uint32_t);
12506db247cSraghuram static void vsw_process_data_ibnd_pkt(vsw_ldc_t *, void *);
126f0ca1d9aSsb 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 *);
132f0ca1d9aSsb static void vsw_ldcsend_pkt(vsw_ldc_t *ldcp, mblk_t *mp);
133f0ca1d9aSsb static int vsw_ldcsend(vsw_ldc_t *ldcp, mblk_t *mp, uint32_t retries);
134f0ca1d9aSsb static int vsw_ldctx_pri(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count);
135f0ca1d9aSsb 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);
15434f94fbcSWENTAO 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);
181c1c61f44Ssb extern void vsw_fdbe_add(vsw_t *vswp, void *port);
182c1c61f44Ssb extern void vsw_fdbe_del(vsw_t *vswp, struct ether_addr *eaddr);
183c1c61f44Ssb extern void vsw_create_vlans(void *arg, int type);
184c1c61f44Ssb extern void vsw_destroy_vlans(void *arg, int type);
185c1c61f44Ssb extern void vsw_vlan_add_ids(void *arg, int type);
186c1c61f44Ssb extern void vsw_vlan_remove_ids(void *arg, int type);
187c1c61f44Ssb extern boolean_t vsw_frame_lookup_vid(void *arg, int caller,
188c1c61f44Ssb struct ether_header *ehp, uint16_t *vidp);
189c1c61f44Ssb extern mblk_t *vsw_vlan_frame_pretag(void *arg, int type, mblk_t *mp);
190c1c61f44Ssb extern uint32_t vsw_vlan_frame_untag(void *arg, int type, mblk_t **np,
191c1c61f44Ssb mblk_t **npt);
192c1c61f44Ssb 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;
235f0ca1d9aSsb extern uint32_t vsw_max_tx_qcount;
236f0ca1d9aSsb extern boolean_t vsw_obp_ver_proto_workaround;
23751aa9d07Ssb extern uint32_t vsw_publish_macaddr_count;
23834f94fbcSWENTAO 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
249f0ca1d9aSsb #define VSW_VER_EQ(ldcp, major, minor) \
250f0ca1d9aSsb ((ldcp)->lane_out.ver_major == (major) && \
251f0ca1d9aSsb (ldcp)->lane_out.ver_minor == (minor))
252f0ca1d9aSsb
253f0ca1d9aSsb #define VSW_VER_LT(ldcp, major, minor) \
254f0ca1d9aSsb (((ldcp)->lane_out.ver_major < (major)) || \
255f0ca1d9aSsb ((ldcp)->lane_out.ver_major == (major) && \
256f0ca1d9aSsb (ldcp)->lane_out.ver_minor < (minor)))
25706db247cSraghuram
258c1c61f44Ssb #define VSW_VER_GTEQ(ldcp, major, minor) \
259c1c61f44Ssb (((ldcp)->lane_out.ver_major > (major)) || \
260c1c61f44Ssb ((ldcp)->lane_out.ver_major == (major) && \
261c1c61f44Ssb (ldcp)->lane_out.ver_minor >= (minor)))
262c1c61f44Ssb
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
282*6e472272SToomas Soome * 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
vsw_port_attach(vsw_port_t * port)327c1c61f44Ssb vsw_port_attach(vsw_port_t *port)
32806db247cSraghuram {
329c1c61f44Ssb vsw_t *vswp = port->p_vswp;
33006db247cSraghuram vsw_port_list_t *plist = &vswp->plist;
331c1c61f44Ssb vsw_port_t *p, **pp;
332c1c61f44Ssb int nids = port->num_ldcs;
333c1c61f44Ssb uint64_t *ldcids;
334da14cebeSEric Cheng int rv;
33506db247cSraghuram
336c1c61f44Ssb D1(vswp, "%s: enter : port %d", __func__, port->p_instance);
33706db247cSraghuram
33806db247cSraghuram /* port already exists? */
33906db247cSraghuram READ_ENTER(&plist->lockrw);
340c1c61f44Ssb for (p = plist->head; p != NULL; p = p->p_next) {
341c1c61f44Ssb if (p->p_instance == port->p_instance) {
34206db247cSraghuram DWARN(vswp, "%s: port instance %d already attached",
343c1c61f44Ssb __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);
359c1c61f44Ssb 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) {
3627bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: ldc_attach failed", __func__);
3637bd3a2e2SSriharsha Basavapatna 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
37806db247cSraghuram /* create the fdb entry for this port/mac address */
379c1c61f44Ssb vsw_fdbe_add(vswp, port);
380c1c61f44Ssb
381c1c61f44Ssb vsw_create_vlans(port, VSW_VNETPORT);
382c1c61f44Ssb
383c1c61f44Ssb WRITE_ENTER(&plist->lockrw);
38406db247cSraghuram
38506db247cSraghuram /* link it into the list of ports for this vsw instance */
386c1c61f44Ssb pp = (vsw_port_t **)(&plist->head);
387c1c61f44Ssb port->p_next = *pp;
388c1c61f44Ssb *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
39851aa9d07Ssb /* announce macaddr of vnet to the physical switch */
39951aa9d07Ssb if (vsw_publish_macaddr_count != 0) { /* enabled */
400da14cebeSEric Cheng vsw_publish_macaddr(vswp, port);
40151aa9d07Ssb }
40251aa9d07Ssb
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
vsw_port_detach(vsw_t * vswp,int p_instance)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
455c1c61f44Ssb /* Remove the fdb entry for this port/mac address */
456c1c61f44Ssb vsw_fdbe_del(vswp, &(port->p_macaddr));
457c1c61f44Ssb vsw_destroy_vlans(port, VSW_VNETPORT);
458c1c61f44Ssb
459c1c61f44Ssb /* Remove any multicast addresses.. */
460c1c61f44Ssb vsw_del_mcst_port(port);
461c1c61f44Ssb
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
vsw_detach_ports(vsw_t * vswp)47206db247cSraghuram vsw_detach_ports(vsw_t *vswp)
47306db247cSraghuram {
474*6e472272SToomas Soome 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 */
491c1c61f44Ssb vsw_fdbe_del(vswp, &(port->p_macaddr));
492c1c61f44Ssb 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
vsw_port_delete(vsw_port_t * port)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);
539c1c61f44Ssb
54006db247cSraghuram cv_destroy(&port->state_cv);
54106db247cSraghuram mutex_destroy(&port->state_lock);
54206db247cSraghuram
543c1c61f44Ssb if (port->num_ldcs != 0) {
544c1c61f44Ssb kmem_free(port->ldc_ids, port->num_ldcs * sizeof (uint64_t));
545c1c61f44Ssb port->num_ldcs = 0;
546c1c61f44Ssb }
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
vsw_ldc_attach(vsw_port_t * port,uint64_t ldc_id)56306db247cSraghuram vsw_ldc_attach(vsw_port_t *port, uint64_t ldc_id)
56406db247cSraghuram {
565*6e472272SToomas Soome vsw_t *vswp = port->p_vswp;
566*6e472272SToomas Soome vsw_ldc_t *ldcp = NULL;
567*6e472272SToomas Soome ldc_attr_t attr;
56806db247cSraghuram ldc_status_t istatus;
569*6e472272SToomas Soome 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 }
646f0ca1d9aSsb /*
647f0ca1d9aSsb * allocate a message for ldc_read()s, big enough to hold ctrl and
648f0ca1d9aSsb * data msgs, including raw data msgs used to recv priority frames.
649f0ca1d9aSsb */
650c1c61f44Ssb ldcp->msglen = VIO_PKT_DATA_HDRSIZE + vswp->max_frame_size;
651f0ca1d9aSsb 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
667f0ca1d9aSsb vsw_reset_vnet_proto_ops(ldcp);
668f0ca1d9aSsb
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);
687f0ca1d9aSsb 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
vsw_ldc_detach(vsw_ldc_t * ldcp)7207bd3a2e2SSriharsha Basavapatna vsw_ldc_detach(vsw_ldc_t *ldcp)
72106db247cSraghuram {
722*6e472272SToomas Soome int rv;
723*6e472272SToomas Soome 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 }
734f0ca1d9aSsb 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;
744f0ca1d9aSsb 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;
776*6e472272SToomas Soome ldcp->ldc_handle = 0;
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
vsw_ldc_init(vsw_ldc_t * ldcp)80106db247cSraghuram vsw_ldc_init(vsw_ldc_t *ldcp)
80206db247cSraghuram {
803*6e472272SToomas Soome 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
vsw_ldc_uninit(vsw_ldc_t * ldcp)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
vsw_ldc_drain(vsw_ldc_t * ldcp)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
9497bd3a2e2SSriharsha Basavapatna /*
9507bd3a2e2SSriharsha Basavapatna * If we can unregister the channel callback then we
9517bd3a2e2SSriharsha Basavapatna * know that there is no callback either running or
9527bd3a2e2SSriharsha Basavapatna * scheduled to run for this channel so move on to next
9537bd3a2e2SSriharsha Basavapatna * channel in the list.
9547bd3a2e2SSriharsha Basavapatna */
9557bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->drain_cv_lock);
95606db247cSraghuram
9577bd3a2e2SSriharsha Basavapatna /* prompt active callbacks to quit */
9587bd3a2e2SSriharsha Basavapatna ldcp->drain_state = VSW_LDC_DRAINING;
95906db247cSraghuram
9607bd3a2e2SSriharsha Basavapatna if ((ldc_unreg_callback(ldcp->ldc_handle)) == 0) {
9617bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: unreg callback for chan %ld", __func__,
9627bd3a2e2SSriharsha Basavapatna ldcp->ldc_id);
9637bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->drain_cv_lock);
9647bd3a2e2SSriharsha Basavapatna } else {
96506db247cSraghuram /*
9667bd3a2e2SSriharsha Basavapatna * If we end up here we know that either 1) a callback
9677bd3a2e2SSriharsha Basavapatna * is currently executing, 2) is about to start (i.e.
9687bd3a2e2SSriharsha Basavapatna * the ldc framework has set the active flag but
9697bd3a2e2SSriharsha Basavapatna * has not actually invoked the callback yet, or 3)
9707bd3a2e2SSriharsha Basavapatna * has finished and has returned to the ldc framework
9717bd3a2e2SSriharsha Basavapatna * but the ldc framework has not yet cleared the
9727bd3a2e2SSriharsha Basavapatna * active bit.
9737bd3a2e2SSriharsha Basavapatna *
9747bd3a2e2SSriharsha Basavapatna * 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);
97906db247cSraghuram }
9807bd3a2e2SSriharsha Basavapatna
9817bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->drain_cv_lock);
9827bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: unreg callback for chan %ld after "
9837bd3a2e2SSriharsha Basavapatna "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
vsw_drain_port_taskq(vsw_port_t * port)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
vsw_marker_task(void * arg)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 *
vsw_lookup_port(vsw_t * vswp,int p_instance)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
1069c1c61f44Ssb void
vsw_vlan_unaware_port_reset(vsw_port_t * portp)1070c1c61f44Ssb vsw_vlan_unaware_port_reset(vsw_port_t *portp)
1071c1c61f44Ssb {
10727bd3a2e2SSriharsha Basavapatna vsw_ldc_t *ldcp = portp->ldcp;
1073c1c61f44Ssb
1074c1c61f44Ssb mutex_enter(&ldcp->ldc_cblock);
1075c1c61f44Ssb
1076c1c61f44Ssb /*
1077c1c61f44Ssb * If the peer is vlan_unaware(ver < 1.3), reset channel and terminate
1078c1c61f44Ssb * the connection. See comments in vsw_set_vnet_proto_ops().
1079c1c61f44Ssb */
1080c1c61f44Ssb if (ldcp->hphase == VSW_MILESTONE4 && VSW_VER_LT(ldcp, 1, 3) &&
1081c1c61f44Ssb portp->nvids != 0) {
1082c1c61f44Ssb vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
1083c1c61f44Ssb }
1084c1c61f44Ssb
1085c1c61f44Ssb mutex_exit(&ldcp->ldc_cblock);
1086c1c61f44Ssb }
1087c1c61f44Ssb
1088678453a8Sspeer void
vsw_hio_port_reset(vsw_port_t * portp,boolean_t immediate)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 {
1105cdfc78adSraghuram vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
1106cdfc78adSraghuram }
1107678453a8Sspeer }
1108678453a8Sspeer
1109678453a8Sspeer mutex_exit(&ldcp->ldc_cblock);
1110678453a8Sspeer }
1111678453a8Sspeer
11127b1f684aSSriharsha Basavapatna void
vsw_port_reset(vsw_port_t * portp)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
vsw_reset_ports(vsw_t * vswp)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
vsw_send_physlink_msg(vsw_ldc_t * ldcp,link_state_t plink_state)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
vsw_port_physlink_update(vsw_port_t * portp)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
vsw_physlink_update_ports(vsw_t * vswp)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
vsw_plist_del_node(vsw_t * vswp,vsw_port_t * port)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
vsw_ldc_cb(uint64_t event,caddr_t arg)123806db247cSraghuram vsw_ldc_cb(uint64_t event, caddr_t arg)
123906db247cSraghuram {
124006db247cSraghuram vsw_ldc_t *ldcp = (vsw_ldc_t *)arg;
1241*6e472272SToomas Soome 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);
1249*6e472272SToomas Soome if ((ldcp->ldc_status == LDC_INIT) || (ldcp->ldc_handle == 0)) {
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
vsw_ldc_reinit(vsw_ldc_t * ldcp)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;
1347f0ca1d9aSsb
1348f0ca1d9aSsb 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
vsw_process_conn_evt(vsw_ldc_t * ldcp,uint16_t evt)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
vsw_conn_task(void * arg)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
1532f0ca1d9aSsb if (vsw_obp_ver_proto_workaround == B_FALSE &&
1533f0ca1d9aSsb (ddi_taskq_dispatch(vswp->taskq_p, vsw_send_ver, ldcp,
1534f0ca1d9aSsb 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
vsw_check_flag(vsw_ldc_t * ldcp,int dir,uint64_t flag)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
vsw_next_milestone(vsw_ldc_t * ldcp)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
1726f0ca1d9aSsb vsw_set_vnet_proto_ops(ldcp);
1727f0ca1d9aSsb
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
17487bd3a2e2SSriharsha Basavapatna ldcp->hphase = VSW_MILESTONE2;
174906db247cSraghuram
17507bd3a2e2SSriharsha Basavapatna /*
17517bd3a2e2SSriharsha Basavapatna * If the peer device has said it wishes to
17527bd3a2e2SSriharsha Basavapatna * use descriptor rings then we send it our ring
17537bd3a2e2SSriharsha Basavapatna * info, otherwise we just set up a private ring
17547bd3a2e2SSriharsha Basavapatna * which we use an internal buffer
17557bd3a2e2SSriharsha Basavapatna */
17567bd3a2e2SSriharsha Basavapatna if ((VSW_VER_GTEQ(ldcp, 1, 2) &&
17577bd3a2e2SSriharsha Basavapatna (lane_in->xfer_mode & VIO_DRING_MODE_V1_2)) ||
17587bd3a2e2SSriharsha Basavapatna (VSW_VER_LT(ldcp, 1, 2) &&
17597bd3a2e2SSriharsha Basavapatna (lane_in->xfer_mode == VIO_DRING_MODE_V1_0))) {
17607bd3a2e2SSriharsha Basavapatna vsw_send_dring_info(ldcp);
17617bd3a2e2SSriharsha Basavapatna break;
176206db247cSraghuram }
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 */
1781c1c61f44Ssb if ((VSW_VER_GTEQ(ldcp, 1, 2) &&
17827bd3a2e2SSriharsha Basavapatna (lane_in->xfer_mode & VIO_DRING_MODE_V1_2)) ||
1783f0ca1d9aSsb (VSW_VER_LT(ldcp, 1, 2) &&
17847bd3a2e2SSriharsha Basavapatna (lane_in->xfer_mode ==
1785f0ca1d9aSsb VIO_DRING_MODE_V1_0))) {
17867bd3a2e2SSriharsha Basavapatna if (!(lane_in->lstate & VSW_DRING_ACK_SENT))
1787f0ca1d9aSsb break;
1788f0ca1d9aSsb }
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
vsw_supported_version(vio_ver_msg_t * vp)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
1893f0ca1d9aSsb /*
1894f0ca1d9aSsb * If the message contains a higher major version number, set
1895f0ca1d9aSsb * the message's major/minor versions to the current values
1896f0ca1d9aSsb * and return false, so this message will get resent with
1897f0ca1d9aSsb * these values.
1898f0ca1d9aSsb */
189906db247cSraghuram if (vsw_versions[i].ver_major < vp->ver_major) {
1900f0ca1d9aSsb D2(NULL, "%s: adjusting major and minor "
1901f0ca1d9aSsb "values to %d, %d\n",
1902f0ca1d9aSsb __func__, vsw_versions[i].ver_major,
1903f0ca1d9aSsb vsw_versions[i].ver_minor);
1904f0ca1d9aSsb vp->ver_major = vsw_versions[i].ver_major;
1905f0ca1d9aSsb 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
1919f0ca1d9aSsb /*
1920f0ca1d9aSsb * Set vnet-protocol-version dependent functions based on version.
1921f0ca1d9aSsb */
1922f0ca1d9aSsb static void
vsw_set_vnet_proto_ops(vsw_ldc_t * ldcp)1923f0ca1d9aSsb vsw_set_vnet_proto_ops(vsw_ldc_t *ldcp)
1924f0ca1d9aSsb {
1925f0ca1d9aSsb vsw_t *vswp = ldcp->ldc_vswp;
1926f0ca1d9aSsb lane_t *lp = &ldcp->lane_out;
1927f0ca1d9aSsb
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
194334f94fbcSWENTAO YANG * below) on this guest or on the peer guest. This info is determined
194434f94fbcSWENTAO YANG * as part of attr exchange phase of handshake. Hence, we setup these
194534f94fbcSWENTAO 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 */
195334f94fbcSWENTAO 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)) {
1966c1c61f44Ssb /*
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.
1969c1c61f44Ssb */
1970c1c61f44Ssb 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;
1977c1c61f44Ssb } else {
1978c1c61f44Ssb vsw_port_t *portp = ldcp->ldc_port;
1979c1c61f44Ssb /*
1980c1c61f44Ssb * 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.
1987c1c61f44Ssb */
19887b1f684aSSriharsha Basavapatna if (portp->nvids == 0) {
1989c1c61f44Ssb lp->mtu = ETHERMAX;
1990c1c61f44Ssb }
1991c1c61f44Ssb }
1992c1c61f44Ssb
19937bd3a2e2SSriharsha Basavapatna /*
19947bd3a2e2SSriharsha Basavapatna * Setup version dependent data processing functions.
19957bd3a2e2SSriharsha Basavapatna */
1996c1c61f44Ssb if (VSW_VER_GTEQ(ldcp, 1, 2)) {
1997c1c61f44Ssb /* Versions >= 1.2 */
1998f0ca1d9aSsb
1999f0ca1d9aSsb if (VSW_PRI_ETH_DEFINED(vswp)) {
2000f0ca1d9aSsb /*
2001f0ca1d9aSsb * enable priority routines and pkt mode only if
2002f0ca1d9aSsb * at least one pri-eth-type is specified in MD.
2003f0ca1d9aSsb */
2004f0ca1d9aSsb ldcp->tx = vsw_ldctx_pri;
2005f0ca1d9aSsb ldcp->rx_pktdata = vsw_process_pkt_data;
2006f0ca1d9aSsb
2007f0ca1d9aSsb /* set xfer mode for vsw_send_attr() */
2008f0ca1d9aSsb lp->xfer_mode = VIO_PKT_MODE | VIO_DRING_MODE_V1_2;
2009f0ca1d9aSsb } else {
2010f0ca1d9aSsb /* no priority eth types defined in MD */
2011f0ca1d9aSsb
2012f0ca1d9aSsb ldcp->tx = vsw_ldctx;
2013f0ca1d9aSsb ldcp->rx_pktdata = vsw_process_pkt_data_nop;
2014f0ca1d9aSsb
2015f0ca1d9aSsb /* set xfer mode for vsw_send_attr() */
2016f0ca1d9aSsb lp->xfer_mode = VIO_DRING_MODE_V1_2;
2017f0ca1d9aSsb }
2018c1c61f44Ssb
2019f0ca1d9aSsb } else {
2020f0ca1d9aSsb /* Versions prior to 1.2 */
2021f0ca1d9aSsb
2022f0ca1d9aSsb vsw_reset_vnet_proto_ops(ldcp);
2023f0ca1d9aSsb }
2024f0ca1d9aSsb }
2025f0ca1d9aSsb
2026f0ca1d9aSsb /*
2027f0ca1d9aSsb * Reset vnet-protocol-version dependent functions to v1.0.
2028f0ca1d9aSsb */
2029f0ca1d9aSsb static void
vsw_reset_vnet_proto_ops(vsw_ldc_t * ldcp)2030f0ca1d9aSsb vsw_reset_vnet_proto_ops(vsw_ldc_t *ldcp)
2031f0ca1d9aSsb {
2032f0ca1d9aSsb lane_t *lp = &ldcp->lane_out;
2033f0ca1d9aSsb
2034f0ca1d9aSsb ldcp->tx = vsw_ldctx;
2035f0ca1d9aSsb ldcp->rx_pktdata = vsw_process_pkt_data_nop;
2036f0ca1d9aSsb
2037f0ca1d9aSsb /* set xfer mode for vsw_send_attr() */
2038f0ca1d9aSsb lp->xfer_mode = VIO_DRING_MODE_V1_0;
2039f0ca1d9aSsb }
2040f0ca1d9aSsb
20417bd3a2e2SSriharsha Basavapatna static void
vsw_process_evt_read(vsw_ldc_t * ldcp)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
207106db247cSraghuram /*
207206db247cSraghuram * Main routine for processing messages received over LDC.
207306db247cSraghuram */
20747bd3a2e2SSriharsha Basavapatna void
vsw_process_pkt(void * arg)207506db247cSraghuram vsw_process_pkt(void *arg)
207606db247cSraghuram {
207706db247cSraghuram vsw_ldc_t *ldcp = (vsw_ldc_t *)arg;
2078*6e472272SToomas Soome vsw_t *vswp = ldcp->ldc_vswp;
207906db247cSraghuram size_t msglen;
2080f0ca1d9aSsb vio_msg_tag_t *tagp;
2081f0ca1d9aSsb uint64_t *ldcmsg;
2082*6e472272SToomas Soome 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
2089f0ca1d9aSsb ldcmsg = ldcp->ldcmsg;
209006db247cSraghuram /*
209106db247cSraghuram * If channel is up read messages until channel is empty.
209206db247cSraghuram */
209306db247cSraghuram do {
2094f0ca1d9aSsb msglen = ldcp->msglen;
2095f0ca1d9aSsb 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 */
2121f0ca1d9aSsb tagp = (vio_msg_tag_t *)ldcmsg;
212206db247cSraghuram
2123f0ca1d9aSsb 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:
2128f0ca1d9aSsb vsw_process_data_pkt(ldcp, ldcmsg, tagp, msglen);
212906db247cSraghuram break;
213006db247cSraghuram case VIO_TYPE_ERR:
2131f0ca1d9aSsb vsw_process_err_pkt(ldcp, ldcmsg, tagp);
213206db247cSraghuram break;
213306db247cSraghuram default:
213406db247cSraghuram DERR(vswp, "%s: Unknown tag(%lx) ", __func__,
2135f0ca1d9aSsb "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
vsw_dispatch_ctrl_task(vsw_ldc_t * ldcp,void * cpkt,vio_msg_tag_t * tagp,int msglen)21477bd3a2e2SSriharsha Basavapatna vsw_dispatch_ctrl_task(vsw_ldc_t *ldcp, void *cpkt, vio_msg_tag_t *tagp,
2148*6e472272SToomas Soome 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 */
2161f0ca1d9aSsb if ((tagp->vio_subtype_env == VIO_RDX) &&
2162f0ca1d9aSsb (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
vsw_process_ctrl_pkt(void * arg)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;
2224*6e472272SToomas Soome 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
vsw_process_ctrl_ver_pkt(vsw_ldc_t * ldcp,void * pkt)230506db247cSraghuram vsw_process_ctrl_ver_pkt(vsw_ldc_t *ldcp, void *pkt)
230606db247cSraghuram {
230706db247cSraghuram vio_ver_msg_t *ver_pkt;
2308*6e472272SToomas Soome 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;
2385f0ca1d9aSsb
2386f0ca1d9aSsb if (vsw_obp_ver_proto_workaround == B_TRUE) {
2387f0ca1d9aSsb /*
2388f0ca1d9aSsb * Send a version info message
2389f0ca1d9aSsb * using the accepted version that
2390f0ca1d9aSsb * we are about to ack. Also note that
2391f0ca1d9aSsb * we send our ver info before we ack.
2392f0ca1d9aSsb * Otherwise, as soon as receiving the
2393f0ca1d9aSsb * ack, obp sends attr info msg, which
2394f0ca1d9aSsb * breaks vsw_check_flag() invoked
2395f0ca1d9aSsb * from vsw_process_ctrl_attr_pkt();
2396f0ca1d9aSsb * as we also need VSW_VER_ACK_RECV to
2397f0ca1d9aSsb * be set in lane_out.lstate, before
2398f0ca1d9aSsb * we can receive attr info.
2399f0ca1d9aSsb */
2400f0ca1d9aSsb vsw_send_ver(ldcp);
2401f0ca1d9aSsb }
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 */
2436f0ca1d9aSsb ldcp->lane_out.ver_major = ver_pkt->ver_major;
2437f0ca1d9aSsb 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
vsw_process_attr_info(vsw_ldc_t * ldcp,vnet_attr_msg_t * msg)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
25197bd3a2e2SSriharsha Basavapatna 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 }
252406db247cSraghuram
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 }
253006db247cSraghuram
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
25387bd3a2e2SSriharsha Basavapatna /*
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.
25427bd3a2e2SSriharsha Basavapatna */
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 &&
258034f94fbcSWENTAO 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);
26117b1f684aSSriharsha 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;
26197b1f684aSSriharsha Basavapatna }
26207b1f684aSSriharsha Basavapatna
26217bd3a2e2SSriharsha Basavapatna /* save the negotiated dring mode in the msg to be replied */
26227bd3a2e2SSriharsha Basavapatna msg->options = dring_mode;
26237bd3a2e2SSriharsha Basavapatna }
262406db247cSraghuram
26257bd3a2e2SSriharsha Basavapatna /*
26267bd3a2e2SSriharsha Basavapatna * Process MTU attribute.
26277bd3a2e2SSriharsha Basavapatna */
26287bd3a2e2SSriharsha Basavapatna if (VSW_VER_GTEQ(ldcp, 1, 4)) {
262906db247cSraghuram /*
26307bd3a2e2SSriharsha 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.
263306db247cSraghuram */
26347bd3a2e2SSriharsha Basavapatna if (msg->mtu < ETHERMAX) {
26357bd3a2e2SSriharsha Basavapatna return (1);
26367bd3a2e2SSriharsha Basavapatna }
26377bd3a2e2SSriharsha Basavapatna
26387bd3a2e2SSriharsha Basavapatna mtu = MIN(msg->mtu, vswp->max_frame_size);
26391107ea93SSriharsha Basavapatna
26401107ea93SSriharsha Basavapatna /*
26417bd3a2e2SSriharsha Basavapatna * If we have received an ack for the attr info
26427bd3a2e2SSriharsha Basavapatna * that we sent, then check if the mtu computed
26437bd3a2e2SSriharsha Basavapatna * above matches the mtu that the peer had ack'd
26447bd3a2e2SSriharsha Basavapatna * (saved in local hparams). If they don't
26457bd3a2e2SSriharsha Basavapatna * match, we fail the handshake.
26461107ea93SSriharsha Basavapatna */
26477bd3a2e2SSriharsha Basavapatna if (lane_out->lstate & VSW_ATTR_ACK_RECV) {
26487bd3a2e2SSriharsha Basavapatna if (mtu != lane_out->mtu) {
26497bd3a2e2SSriharsha Basavapatna /* send NACK */
26507bd3a2e2SSriharsha Basavapatna return (1);
26511107ea93SSriharsha Basavapatna }
26521107ea93SSriharsha Basavapatna } else {
26531107ea93SSriharsha Basavapatna /*
26547bd3a2e2SSriharsha Basavapatna * Save the mtu computed above in our
26557bd3a2e2SSriharsha Basavapatna * attr parameters, so it gets sent in
26567bd3a2e2SSriharsha Basavapatna * the attr info from us to the peer.
26571107ea93SSriharsha Basavapatna */
26587bd3a2e2SSriharsha Basavapatna lane_out->mtu = mtu;
26591107ea93SSriharsha Basavapatna }
26607b1f684aSSriharsha 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);
266906db247cSraghuram }
26707bd3a2e2SSriharsha Basavapatna }
267106db247cSraghuram
26727bd3a2e2SSriharsha Basavapatna /*
26737bd3a2e2SSriharsha Basavapatna * Otherwise store attributes for this lane and update
26747bd3a2e2SSriharsha Basavapatna * lane state.
26757bd3a2e2SSriharsha Basavapatna */
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;
2683c1c61f44Ssb
26847bd3a2e2SSriharsha Basavapatna /*
26857bd3a2e2SSriharsha Basavapatna * Check if the client has requested physlink state updates.
26867bd3a2e2SSriharsha Basavapatna * If there is a physical device bound to this vswitch (L2
26877bd3a2e2SSriharsha Basavapatna * mode), set the ack bits to indicate it is supported.
26887bd3a2e2SSriharsha Basavapatna * Otherwise, set the nack bits.
26897bd3a2e2SSriharsha Basavapatna */
26907bd3a2e2SSriharsha Basavapatna if (VSW_VER_GTEQ(ldcp, 1, 5)) { /* Protocol ver >= 1.5 */
26917bd3a2e2SSriharsha Basavapatna
26927bd3a2e2SSriharsha Basavapatna /* Does the vnet need phys link state updates ? */
26937bd3a2e2SSriharsha Basavapatna if ((lane_in->physlink_update &
26947bd3a2e2SSriharsha Basavapatna PHYSLINK_UPDATE_STATE_MASK) ==
26957bd3a2e2SSriharsha Basavapatna PHYSLINK_UPDATE_STATE) {
26967bd3a2e2SSriharsha Basavapatna
26977bd3a2e2SSriharsha Basavapatna if (vswp->smode & VSW_LAYER2) {
26987bd3a2e2SSriharsha Basavapatna /* is a net-dev assigned to us ? */
26997bd3a2e2SSriharsha Basavapatna msg->physlink_update =
27007bd3a2e2SSriharsha Basavapatna PHYSLINK_UPDATE_STATE_ACK;
27017bd3a2e2SSriharsha Basavapatna ldcp->pls_negotiated = B_TRUE;
27027bd3a2e2SSriharsha Basavapatna } else {
27037bd3a2e2SSriharsha Basavapatna /* not in L2 mode */
27047bd3a2e2SSriharsha Basavapatna msg->physlink_update =
27057bd3a2e2SSriharsha Basavapatna PHYSLINK_UPDATE_STATE_NACK;
27067bd3a2e2SSriharsha Basavapatna ldcp->pls_negotiated = B_FALSE;
27077bd3a2e2SSriharsha Basavapatna }
270806db247cSraghuram
27097bd3a2e2SSriharsha Basavapatna } else {
27107bd3a2e2SSriharsha Basavapatna msg->physlink_update =
27117bd3a2e2SSriharsha Basavapatna PHYSLINK_UPDATE_NONE;
27127bd3a2e2SSriharsha Basavapatna ldcp->pls_negotiated = B_FALSE;
271306db247cSraghuram }
2714678453a8Sspeer
27157bd3a2e2SSriharsha Basavapatna } else {
2716678453a8Sspeer /*
27177bd3a2e2SSriharsha Basavapatna * physlink_update bits are ignored
27187bd3a2e2SSriharsha Basavapatna * if set by clients < v1.5 protocol.
2719678453a8Sspeer */
27207bd3a2e2SSriharsha Basavapatna msg->physlink_update = PHYSLINK_UPDATE_NONE;
27217bd3a2e2SSriharsha Basavapatna ldcp->pls_negotiated = B_FALSE;
27227bd3a2e2SSriharsha Basavapatna }
2723678453a8Sspeer
27247bd3a2e2SSriharsha Basavapatna macaddr = lane_in->addr;
27257bd3a2e2SSriharsha Basavapatna for (i = ETHERADDRL - 1; i >= 0; i--) {
27267bd3a2e2SSriharsha Basavapatna port->p_macaddr.ether_addr_octet[i] = macaddr & 0xFF;
27277bd3a2e2SSriharsha Basavapatna macaddr >>= 8;
27287bd3a2e2SSriharsha Basavapatna }
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 */
27357bd3a2e2SSriharsha Basavapatna mutex_enter(&port->tx_lock);
273606db247cSraghuram
27377bd3a2e2SSriharsha Basavapatna if ((VSW_VER_GTEQ(ldcp, 1, 2) &&
27387bd3a2e2SSriharsha Basavapatna (lane_in->xfer_mode & VIO_DRING_MODE_V1_2)) ||
27397bd3a2e2SSriharsha Basavapatna (VSW_VER_LT(ldcp, 1, 2) &&
27407bd3a2e2SSriharsha Basavapatna (lane_in->xfer_mode == VIO_DRING_MODE_V1_0))) {
27417bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: mode = VIO_DRING_MODE", __func__);
27427bd3a2e2SSriharsha Basavapatna port->transmit = vsw_dringsend;
27437bd3a2e2SSriharsha Basavapatna } else if (lane_in->xfer_mode == VIO_DESC_MODE) {
27447bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: mode = VIO_DESC_MODE", __func__);
27457bd3a2e2SSriharsha Basavapatna vsw_create_privring(ldcp);
27467bd3a2e2SSriharsha Basavapatna port->transmit = vsw_descrsend;
27477bd3a2e2SSriharsha Basavapatna lane_out->xfer_mode = VIO_DESC_MODE;
27487bd3a2e2SSriharsha Basavapatna }
274906db247cSraghuram
27507bd3a2e2SSriharsha Basavapatna /*
27517bd3a2e2SSriharsha Basavapatna * HybridIO is supported only vnet, not by OBP.
27527bd3a2e2SSriharsha Basavapatna * So, set hio_capable to true only when in DRING mode.
27537bd3a2e2SSriharsha Basavapatna */
27547bd3a2e2SSriharsha Basavapatna if (VSW_VER_GTEQ(ldcp, 1, 3) &&
27557bd3a2e2SSriharsha Basavapatna (lane_in->xfer_mode != VIO_DESC_MODE)) {
27567bd3a2e2SSriharsha Basavapatna (void) atomic_swap_32(&port->p_hio_capable, B_TRUE);
27577bd3a2e2SSriharsha Basavapatna } else {
27587bd3a2e2SSriharsha Basavapatna (void) atomic_swap_32(&port->p_hio_capable, B_FALSE);
27597bd3a2e2SSriharsha Basavapatna }
276006db247cSraghuram
27617bd3a2e2SSriharsha Basavapatna mutex_exit(&port->tx_lock);
276206db247cSraghuram
27637bd3a2e2SSriharsha Basavapatna return (0);
27647bd3a2e2SSriharsha Basavapatna }
276506db247cSraghuram
27667bd3a2e2SSriharsha Basavapatna static int
vsw_process_attr_ack(vsw_ldc_t * ldcp,vnet_attr_msg_t * msg)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;
27727bd3a2e2SSriharsha Basavapatna
27737bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
27747bd3a2e2SSriharsha Basavapatna
27757bd3a2e2SSriharsha Basavapatna if (vsw_check_flag(ldcp, OUTBOUND, VSW_ATTR_ACK_RECV)) {
27767bd3a2e2SSriharsha Basavapatna return (1);
27777bd3a2e2SSriharsha Basavapatna }
27787bd3a2e2SSriharsha Basavapatna
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) {
27907b1f684aSSriharsha Basavapatna /*
27917b1f684aSSriharsha 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.
27967b1f684aSSriharsha 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) {
28027b1f684aSSriharsha Basavapatna /*
28037bd3a2e2SSriharsha Basavapatna * Peer ack'd with a mode that we don't
28047bd3a2e2SSriharsha Basavapatna * support; we fail the handshake.
28057b1f684aSSriharsha 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);
28157b1f684aSSriharsha Basavapatna }
281606db247cSraghuram
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 }
282406db247cSraghuram
28257bd3a2e2SSriharsha Basavapatna /*
28267bd3a2e2SSriharsha Basavapatna * Process MTU attribute.
28277bd3a2e2SSriharsha Basavapatna */
28287bd3a2e2SSriharsha Basavapatna if (VSW_VER_GTEQ(ldcp, 1, 4)) {
28297bd3a2e2SSriharsha Basavapatna /*
28307bd3a2e2SSriharsha Basavapatna * Versions >= 1.4:
28317bd3a2e2SSriharsha Basavapatna * The ack msg sent by the peer contains the minimum of
28327bd3a2e2SSriharsha Basavapatna * our mtu (that we had sent in our attr info) and the
28337bd3a2e2SSriharsha Basavapatna * peer's mtu.
28347bd3a2e2SSriharsha Basavapatna *
28357bd3a2e2SSriharsha Basavapatna * If we have sent an ack for the attr info msg from
28367bd3a2e2SSriharsha Basavapatna * the peer, check if the mtu that was computed then
28377bd3a2e2SSriharsha Basavapatna * (saved in lane_out params) matches the mtu that the
28387bd3a2e2SSriharsha Basavapatna * peer has ack'd. If they don't match, we fail the
28397bd3a2e2SSriharsha Basavapatna * handshake.
28407bd3a2e2SSriharsha Basavapatna */
28417bd3a2e2SSriharsha Basavapatna if (lane_in->lstate & VSW_ATTR_ACK_SENT) {
28427bd3a2e2SSriharsha Basavapatna if (lane_out->mtu != msg->mtu) {
28437bd3a2e2SSriharsha Basavapatna return (1);
28447bd3a2e2SSriharsha Basavapatna }
28457bd3a2e2SSriharsha Basavapatna } else {
28467bd3a2e2SSriharsha Basavapatna /*
28477bd3a2e2SSriharsha Basavapatna * If the mtu ack'd by the peer is > our mtu
28487bd3a2e2SSriharsha Basavapatna * fail handshake. Otherwise, save the mtu, so
28497bd3a2e2SSriharsha Basavapatna * we can validate it when we receive attr info
28507bd3a2e2SSriharsha Basavapatna * from our peer.
28517bd3a2e2SSriharsha Basavapatna */
28527bd3a2e2SSriharsha Basavapatna if (msg->mtu <= lane_out->mtu) {
28537bd3a2e2SSriharsha Basavapatna lane_out->mtu = msg->mtu;
28547bd3a2e2SSriharsha Basavapatna } else {
28557bd3a2e2SSriharsha Basavapatna return (1);
28567bd3a2e2SSriharsha Basavapatna }
28577bd3a2e2SSriharsha Basavapatna }
285806db247cSraghuram }
285906db247cSraghuram
28607bd3a2e2SSriharsha Basavapatna return (0);
286106db247cSraghuram }
286206db247cSraghuram
286306db247cSraghuram /*
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.
287106db247cSraghuram *
287206db247cSraghuram * 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.
287506db247cSraghuram *
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.
287806db247cSraghuram *
287906db247cSraghuram */
288006db247cSraghuram void
vsw_process_ctrl_attr_pkt(vsw_ldc_t * ldcp,void * pkt)28817bd3a2e2SSriharsha Basavapatna vsw_process_ctrl_attr_pkt(vsw_ldc_t *ldcp, void *pkt)
288206db247cSraghuram {
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);
289006db247cSraghuram
289106db247cSraghuram /*
28927bd3a2e2SSriharsha Basavapatna * We know this is a ctrl/attr packet so
289306db247cSraghuram * cast it into the correct structure.
289406db247cSraghuram */
28957bd3a2e2SSriharsha Basavapatna attr_pkt = (vnet_attr_msg_t *)pkt;
289606db247cSraghuram
28977bd3a2e2SSriharsha Basavapatna switch (attr_pkt->tag.vio_subtype) {
289806db247cSraghuram case VIO_SUBTYPE_INFO:
289906db247cSraghuram
29007bd3a2e2SSriharsha Basavapatna rv = vsw_process_attr_info(ldcp, attr_pkt);
29017bd3a2e2SSriharsha Basavapatna if (rv != 0) {
290206db247cSraghuram 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;
290806db247cSraghuram }
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;
291506db247cSraghuram
29167bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_ACK:
291706db247cSraghuram
29187bd3a2e2SSriharsha Basavapatna rv = vsw_process_attr_ack(ldcp, attr_pkt);
29197bd3a2e2SSriharsha Basavapatna if (rv != 0) {
292006db247cSraghuram return;
292106db247cSraghuram }
29227bd3a2e2SSriharsha Basavapatna lane_out->lstate |= VSW_ATTR_ACK_RECV;
29237bd3a2e2SSriharsha Basavapatna vsw_next_milestone(ldcp);
29247bd3a2e2SSriharsha Basavapatna break;
292506db247cSraghuram
29267bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_NACK:
29277bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
292806db247cSraghuram
29297bd3a2e2SSriharsha Basavapatna if (vsw_check_flag(ldcp, OUTBOUND, VSW_ATTR_NACK_RECV))
29307bd3a2e2SSriharsha Basavapatna return;
293106db247cSraghuram
29327bd3a2e2SSriharsha Basavapatna lane_out->lstate |= VSW_ATTR_NACK_RECV;
29337bd3a2e2SSriharsha Basavapatna vsw_next_milestone(ldcp);
29347bd3a2e2SSriharsha Basavapatna break;
293506db247cSraghuram
29367bd3a2e2SSriharsha Basavapatna default:
29377bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: unknown vio_subtype %x\n", __func__,
29387bd3a2e2SSriharsha Basavapatna attr_pkt->tag.vio_subtype);
29397bd3a2e2SSriharsha Basavapatna }
2940bbfa0259Sha
29417bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld) exit", __func__, ldcp->ldc_id);
29427bd3a2e2SSriharsha Basavapatna }
294306db247cSraghuram
29447bd3a2e2SSriharsha Basavapatna static int
vsw_process_dring_reg_info(vsw_ldc_t * ldcp,vio_msg_tag_t * tagp)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;
295106db247cSraghuram
29527bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
295306db247cSraghuram
29547bd3a2e2SSriharsha Basavapatna rv = vsw_check_flag(ldcp, INBOUND, VSW_DRING_INFO_RECV);
29557bd3a2e2SSriharsha Basavapatna if (rv != 0) {
29567bd3a2e2SSriharsha Basavapatna return (1);
29577bd3a2e2SSriharsha Basavapatna }
295806db247cSraghuram
29597bd3a2e2SSriharsha Basavapatna if (VSW_VER_GTEQ(ldcp, 1, 6) &&
29607bd3a2e2SSriharsha Basavapatna (lp->dring_mode != ((vio_dring_reg_msg_t *)tagp)->options)) {
296106db247cSraghuram /*
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.
296606db247cSraghuram */
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 }
297206db247cSraghuram
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 }
298006db247cSraghuram
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);
298906db247cSraghuram }
29907bd3a2e2SSriharsha Basavapatna }
29917bd3a2e2SSriharsha Basavapatna
29927bd3a2e2SSriharsha Basavapatna return (0);
29937bd3a2e2SSriharsha Basavapatna }
299406db247cSraghuram
29957bd3a2e2SSriharsha Basavapatna static int
vsw_process_dring_reg_ack(vsw_ldc_t * ldcp,vio_msg_tag_t * tagp)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;
300006db247cSraghuram
30017bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
300206db247cSraghuram
30037bd3a2e2SSriharsha Basavapatna if (vsw_check_flag(ldcp, OUTBOUND, VSW_DRING_ACK_RECV)) {
30047bd3a2e2SSriharsha Basavapatna return (1);
30057bd3a2e2SSriharsha Basavapatna }
300606db247cSraghuram
30077bd3a2e2SSriharsha Basavapatna dp = ldcp->lane_out.dringp;
300806db247cSraghuram
30097bd3a2e2SSriharsha Basavapatna /* save dring_ident acked by peer */
30107bd3a2e2SSriharsha Basavapatna dp->ident = ((vio_dring_reg_msg_t *)tagp)->dring_ident;
301106db247cSraghuram
30127bd3a2e2SSriharsha Basavapatna return (0);
30137bd3a2e2SSriharsha Basavapatna }
301406db247cSraghuram
30157bd3a2e2SSriharsha Basavapatna /*
30167bd3a2e2SSriharsha Basavapatna * Process a dring info packet. We can end up here either because our peer
30177bd3a2e2SSriharsha Basavapatna * has ACK/NACK'ed back to an earlier DRING msg we had sent it, or our
30187bd3a2e2SSriharsha Basavapatna * peer has sent us a dring INFO message.
30197bd3a2e2SSriharsha Basavapatna *
30207bd3a2e2SSriharsha Basavapatna * If we get a valid/acceptable INFO packet (and we have already negotiated
30217bd3a2e2SSriharsha Basavapatna * a version) we ACK back and update the lane state, otherwise we NACK back.
30227bd3a2e2SSriharsha Basavapatna *
30237bd3a2e2SSriharsha Basavapatna * FUTURE: nothing to stop client from sending us info on multiple dring's
30247bd3a2e2SSriharsha Basavapatna * but for the moment we will just use the first one we are given.
30257bd3a2e2SSriharsha Basavapatna *
30267bd3a2e2SSriharsha Basavapatna */
30277bd3a2e2SSriharsha Basavapatna void
vsw_process_ctrl_dring_reg_pkt(vsw_ldc_t * ldcp,void * pkt)30287bd3a2e2SSriharsha Basavapatna vsw_process_ctrl_dring_reg_pkt(vsw_ldc_t *ldcp, void *pkt)
30297bd3a2e2SSriharsha Basavapatna {
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;
30347bd3a2e2SSriharsha Basavapatna 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
30387bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
303906db247cSraghuram
30407bd3a2e2SSriharsha Basavapatna switch (tagp->vio_subtype) {
30417bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_INFO:
30427bd3a2e2SSriharsha Basavapatna rv = vsw_process_dring_reg_info(ldcp, tagp);
30437bd3a2e2SSriharsha Basavapatna if (rv != 0) {
30447bd3a2e2SSriharsha Basavapatna 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);
30577bd3a2e2SSriharsha Basavapatna } else {
30587bd3a2e2SSriharsha Basavapatna msgsize = sizeof (vio_dring_reg_msg_t);
30597bd3a2e2SSriharsha Basavapatna }
30607bd3a2e2SSriharsha Basavapatna (void) vsw_send_msg(ldcp, (void *)tagp, msgsize, B_TRUE);
30617bd3a2e2SSriharsha Basavapatna vsw_next_milestone(ldcp);
30627bd3a2e2SSriharsha Basavapatna break;
306306db247cSraghuram
30647bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_ACK:
30657bd3a2e2SSriharsha Basavapatna rv = vsw_process_dring_reg_ack(ldcp, tagp);
30667bd3a2e2SSriharsha Basavapatna if (rv != 0) {
30677bd3a2e2SSriharsha Basavapatna return;
30687bd3a2e2SSriharsha Basavapatna }
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
vsw_process_ctrl_dring_unreg_pkt(vsw_ldc_t * ldcp,void * pkt)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
vsw_process_ctrl_mcst_pkt(vsw_ldc_t * ldcp,void * pkt)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
vsw_process_ctrl_rdx_pkt(vsw_ldc_t * ldcp,void * pkt)326906db247cSraghuram vsw_process_ctrl_rdx_pkt(vsw_ldc_t *ldcp, void *pkt)
32707bd3a2e2SSriharsha Basavapatna {
32717bd3a2e2SSriharsha Basavapatna vio_rdx_msg_t *rdx_pkt;
32727bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp;
327306db247cSraghuram
32747bd3a2e2SSriharsha Basavapatna /*
32757bd3a2e2SSriharsha Basavapatna * We know this is a ctrl/rdx packet so
32767bd3a2e2SSriharsha Basavapatna * cast it into the correct structure.
32777bd3a2e2SSriharsha Basavapatna */
32787bd3a2e2SSriharsha Basavapatna rdx_pkt = (vio_rdx_msg_t *)pkt;
327906db247cSraghuram
32807bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
328106db247cSraghuram
32827bd3a2e2SSriharsha Basavapatna switch (rdx_pkt->tag.vio_subtype) {
32837bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_INFO:
32847bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: VIO_SUBTYPE_INFO", __func__);
3285bbfa0259Sha
32867bd3a2e2SSriharsha Basavapatna if (vsw_check_flag(ldcp, OUTBOUND, VSW_RDX_INFO_RECV))
32877bd3a2e2SSriharsha Basavapatna return;
3288bbfa0259Sha
32897bd3a2e2SSriharsha Basavapatna rdx_pkt->tag.vio_sid = ldcp->local_session;
32907bd3a2e2SSriharsha Basavapatna rdx_pkt->tag.vio_subtype = VIO_SUBTYPE_ACK;
329106db247cSraghuram
32927bd3a2e2SSriharsha Basavapatna DUMP_TAG_PTR((vio_msg_tag_t *)rdx_pkt);
329306db247cSraghuram
32947bd3a2e2SSriharsha Basavapatna ldcp->lane_out.lstate |= VSW_RDX_ACK_SENT;
329506db247cSraghuram
32967bd3a2e2SSriharsha Basavapatna (void) vsw_send_msg(ldcp, (void *)rdx_pkt,
32977bd3a2e2SSriharsha Basavapatna sizeof (vio_rdx_msg_t), B_TRUE);
329806db247cSraghuram
32997bd3a2e2SSriharsha Basavapatna vsw_next_milestone(ldcp);
33007bd3a2e2SSriharsha Basavapatna break;
330106db247cSraghuram
33027bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_ACK:
330306db247cSraghuram /*
33047bd3a2e2SSriharsha Basavapatna * Should be handled in-band by callback handler.
330506db247cSraghuram */
33067bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: Unexpected VIO_SUBTYPE_ACK", __func__);
33077bd3a2e2SSriharsha Basavapatna vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
33087bd3a2e2SSriharsha Basavapatna break;
330906db247cSraghuram
33107bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_NACK:
33117bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
331206db247cSraghuram
33137bd3a2e2SSriharsha Basavapatna if (vsw_check_flag(ldcp, INBOUND, VSW_RDX_NACK_RECV))
33147bd3a2e2SSriharsha Basavapatna return;
331506db247cSraghuram
33167bd3a2e2SSriharsha Basavapatna ldcp->lane_in.lstate |= VSW_RDX_NACK_RECV;
33177bd3a2e2SSriharsha Basavapatna vsw_next_milestone(ldcp);
331806db247cSraghuram break;
331906db247cSraghuram
33207bd3a2e2SSriharsha Basavapatna default:
33217bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__,
33227bd3a2e2SSriharsha Basavapatna rdx_pkt->tag.vio_subtype);
33237bd3a2e2SSriharsha Basavapatna }
332406db247cSraghuram
33257bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
33267bd3a2e2SSriharsha Basavapatna }
332706db247cSraghuram
33287bd3a2e2SSriharsha Basavapatna static void
vsw_process_physlink_msg(vsw_ldc_t * ldcp,void * pkt)33297bd3a2e2SSriharsha Basavapatna vsw_process_physlink_msg(vsw_ldc_t *ldcp, void *pkt)
33307bd3a2e2SSriharsha Basavapatna {
33317bd3a2e2SSriharsha Basavapatna vnet_physlink_msg_t *msgp;
33327bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp;
333306db247cSraghuram
33347bd3a2e2SSriharsha Basavapatna msgp = (vnet_physlink_msg_t *)pkt;
333506db247cSraghuram
33367bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld) enter", __func__, ldcp->ldc_id);
333706db247cSraghuram
33387bd3a2e2SSriharsha Basavapatna switch (msgp->tag.vio_subtype) {
33397bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_INFO:
334006db247cSraghuram
33417bd3a2e2SSriharsha Basavapatna /* vsw shouldn't recv physlink info */
33427bd3a2e2SSriharsha Basavapatna DWARN(vswp, "%s: Unexpected VIO_SUBTYPE_INFO", __func__);
33437bd3a2e2SSriharsha Basavapatna break;
334406db247cSraghuram
33457bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_ACK:
334606db247cSraghuram
33477bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: VIO_SUBTYPE_ACK", __func__);
33487bd3a2e2SSriharsha Basavapatna break;
334906db247cSraghuram
33507bd3a2e2SSriharsha Basavapatna case VIO_SUBTYPE_NACK:
335106db247cSraghuram
33527bd3a2e2SSriharsha Basavapatna D2(vswp, "%s: VIO_SUBTYPE_NACK", __func__);
33537bd3a2e2SSriharsha Basavapatna break;
335406db247cSraghuram
33557bd3a2e2SSriharsha Basavapatna default:
33567bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: Unknown vio_subtype %x\n", __func__,
33577bd3a2e2SSriharsha Basavapatna msgp->tag.vio_subtype);
33587bd3a2e2SSriharsha Basavapatna }
335906db247cSraghuram
33607bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
33617bd3a2e2SSriharsha Basavapatna }
336206db247cSraghuram
33637bd3a2e2SSriharsha Basavapatna static void
vsw_process_data_pkt(vsw_ldc_t * ldcp,void * dpkt,vio_msg_tag_t * tagp,uint32_t msglen)33647bd3a2e2SSriharsha Basavapatna vsw_process_data_pkt(vsw_ldc_t *ldcp, void *dpkt, vio_msg_tag_t *tagp,
3365*6e472272SToomas Soome uint32_t msglen)
33667bd3a2e2SSriharsha Basavapatna {
33677bd3a2e2SSriharsha Basavapatna uint16_t env = tagp->vio_subtype_env;
33687bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp;
33697bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_out;
33707bd3a2e2SSriharsha Basavapatna uint8_t dring_mode = lp->dring_mode;
337106db247cSraghuram
33727bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
337306db247cSraghuram
33747bd3a2e2SSriharsha Basavapatna /* session id check */
33757bd3a2e2SSriharsha Basavapatna if (ldcp->session_status & VSW_PEER_SESSION) {
33767bd3a2e2SSriharsha Basavapatna if (ldcp->peer_session != tagp->vio_sid) {
33777bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s (chan %d): invalid session id (%llx)",
33787bd3a2e2SSriharsha Basavapatna __func__, ldcp->ldc_id, tagp->vio_sid);
33797bd3a2e2SSriharsha Basavapatna vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
33807bd3a2e2SSriharsha Basavapatna return;
33817bd3a2e2SSriharsha Basavapatna }
33827bd3a2e2SSriharsha Basavapatna }
338306db247cSraghuram
33847bd3a2e2SSriharsha Basavapatna /*
33857bd3a2e2SSriharsha Basavapatna * It is an error for us to be getting data packets
33867bd3a2e2SSriharsha Basavapatna * before the handshake has completed.
33877bd3a2e2SSriharsha Basavapatna */
33887bd3a2e2SSriharsha Basavapatna if (ldcp->hphase != VSW_MILESTONE4) {
33897bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: got data packet before handshake complete "
33907bd3a2e2SSriharsha Basavapatna "hphase %d (%x: %x)", __func__, ldcp->hphase,
33917bd3a2e2SSriharsha Basavapatna ldcp->lane_in.lstate, ldcp->lane_out.lstate);
33927bd3a2e2SSriharsha Basavapatna DUMP_FLAGS(ldcp->lane_in.lstate);
33937bd3a2e2SSriharsha Basavapatna DUMP_FLAGS(ldcp->lane_out.lstate);
33947bd3a2e2SSriharsha Basavapatna vsw_process_conn_evt(ldcp, VSW_CONN_RESTART);
33957bd3a2e2SSriharsha Basavapatna return;
33967bd3a2e2SSriharsha Basavapatna }
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 */
34077bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->ldc_cblock);
34087bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->ldc_rxlock);
34097bd3a2e2SSriharsha Basavapatna }
341006db247cSraghuram
34117bd3a2e2SSriharsha Basavapatna /*
34127bd3a2e2SSriharsha Basavapatna * Switch on vio_subtype envelope, then let lower routines
34137bd3a2e2SSriharsha Basavapatna * decide if its an INFO, ACK or NACK packet.
34147bd3a2e2SSriharsha Basavapatna */
34157bd3a2e2SSriharsha Basavapatna if (env == VIO_DRING_DATA) {
34167bd3a2e2SSriharsha Basavapatna ldcp->rx_dringdata(ldcp, dpkt);
34177bd3a2e2SSriharsha Basavapatna } else if (env == VIO_PKT_DATA) {
34187bd3a2e2SSriharsha Basavapatna ldcp->rx_pktdata(ldcp, dpkt, msglen);
34197bd3a2e2SSriharsha Basavapatna } else if (env == VIO_DESC_DATA) {
34207bd3a2e2SSriharsha Basavapatna vsw_process_data_ibnd_pkt(ldcp, dpkt);
34217bd3a2e2SSriharsha Basavapatna } else {
34227bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: unknown vio_subtype_env (%x)\n",
34237bd3a2e2SSriharsha Basavapatna __func__, env);
34247bd3a2e2SSriharsha Basavapatna }
342506db247cSraghuram
34267bd3a2e2SSriharsha Basavapatna if (dring_mode == VIO_TX_DRING) {
34277bd3a2e2SSriharsha Basavapatna mutex_exit(&ldcp->ldc_rxlock);
34287bd3a2e2SSriharsha Basavapatna mutex_enter(&ldcp->ldc_cblock);
342906db247cSraghuram }
343006db247cSraghuram
34317bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld): exit", __func__, ldcp->ldc_id);
343206db247cSraghuram }
343306db247cSraghuram
343406db247cSraghuram /*
3435f0ca1d9aSsb * dummy pkt data handler function for vnet protocol version 1.0
3436f0ca1d9aSsb */
3437f0ca1d9aSsb static void
vsw_process_pkt_data_nop(void * arg1,void * arg2,uint32_t msglen)3438f0ca1d9aSsb vsw_process_pkt_data_nop(void *arg1, void *arg2, uint32_t msglen)
3439f0ca1d9aSsb {
3440f0ca1d9aSsb _NOTE(ARGUNUSED(arg1, arg2, msglen))
3441f0ca1d9aSsb }
3442f0ca1d9aSsb
3443f0ca1d9aSsb /*
3444f0ca1d9aSsb * This function handles raw pkt data messages received over the channel.
3445f0ca1d9aSsb * Currently, only priority-eth-type frames are received through this mechanism.
3446f0ca1d9aSsb * In this case, the frame(data) is present within the message itself which
3447f0ca1d9aSsb * is copied into an mblk before switching it.
344806db247cSraghuram */
344906db247cSraghuram static void
vsw_process_pkt_data(void * arg1,void * arg2,uint32_t msglen)3450f0ca1d9aSsb vsw_process_pkt_data(void *arg1, void *arg2, uint32_t msglen)
345106db247cSraghuram {
3452f0ca1d9aSsb vsw_ldc_t *ldcp = (vsw_ldc_t *)arg1;
3453f0ca1d9aSsb vio_raw_data_msg_t *dpkt = (vio_raw_data_msg_t *)arg2;
3454f0ca1d9aSsb uint32_t size;
3455f0ca1d9aSsb mblk_t *mp;
34567bd3a2e2SSriharsha Basavapatna vio_mblk_t *vmp;
3457f0ca1d9aSsb vsw_t *vswp = ldcp->ldc_vswp;
3458f0ca1d9aSsb vgen_stats_t *statsp = &ldcp->ldc_stats;
3459c1c61f44Ssb lane_t *lp = &ldcp->lane_out;
3460f0ca1d9aSsb
3461f0ca1d9aSsb size = msglen - VIO_PKT_DATA_HDRSIZE;
3462c1c61f44Ssb if (size < ETHERMIN || size > lp->mtu) {
3463f0ca1d9aSsb (void) atomic_inc_32(&statsp->rx_pri_fail);
3464f0ca1d9aSsb DWARN(vswp, "%s(%lld) invalid size(%d)\n", __func__,
3465f0ca1d9aSsb ldcp->ldc_id, size);
3466f0ca1d9aSsb return;
3467f0ca1d9aSsb }
3468f0ca1d9aSsb
34697bd3a2e2SSriharsha Basavapatna vmp = vio_multipool_allocb(&ldcp->vmp, size + VLAN_TAGSZ);
34707bd3a2e2SSriharsha Basavapatna if (vmp == NULL) {
3471c1c61f44Ssb mp = allocb(size + VLAN_TAGSZ, BPRI_MED);
3472f0ca1d9aSsb if (mp == NULL) {
3473f0ca1d9aSsb (void) atomic_inc_32(&statsp->rx_pri_fail);
3474f0ca1d9aSsb DWARN(vswp, "%s(%lld) allocb failure, "
3475f0ca1d9aSsb "unable to process priority frame\n", __func__,
3476f0ca1d9aSsb ldcp->ldc_id);
3477f0ca1d9aSsb return;
3478f0ca1d9aSsb }
34797bd3a2e2SSriharsha Basavapatna } else {
34807bd3a2e2SSriharsha Basavapatna mp = vmp->mp;
3481f0ca1d9aSsb }
3482f0ca1d9aSsb
3483c1c61f44Ssb /* skip over the extra space for vlan tag */
3484c1c61f44Ssb mp->b_rptr += VLAN_TAGSZ;
3485c1c61f44Ssb
3486f0ca1d9aSsb /* copy the frame from the payload of raw data msg into the mblk */
3487f0ca1d9aSsb bcopy(dpkt->data, mp->b_rptr, size);
3488f0ca1d9aSsb mp->b_wptr = mp->b_rptr + size;
348906db247cSraghuram
34907bd3a2e2SSriharsha Basavapatna if (vmp != NULL) {
34917bd3a2e2SSriharsha Basavapatna vmp->state = VIO_MBLK_HAS_DATA;
34927bd3a2e2SSriharsha Basavapatna }
34937bd3a2e2SSriharsha Basavapatna
3494f0ca1d9aSsb /* update stats */
3495f0ca1d9aSsb (void) atomic_inc_64(&statsp->rx_pri_packets);
3496f0ca1d9aSsb (void) atomic_add_64(&statsp->rx_pri_bytes, size);
3497f0ca1d9aSsb
3498c1c61f44Ssb /*
3499c1c61f44Ssb * VLAN_TAGSZ of extra space has been pre-alloc'd if tag is needed.
3500c1c61f44Ssb */
3501c1c61f44Ssb (void) vsw_vlan_frame_pretag(ldcp->ldc_port, VSW_VNETPORT, mp);
3502c1c61f44Ssb
3503f0ca1d9aSsb /* switch the frame to destination */
3504f0ca1d9aSsb 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
vsw_process_data_ibnd_pkt(vsw_ldc_t * ldcp,void * pkt)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
3561c1c61f44Ssb /* alloc extra space for VLAN_TAG */
3562c1c61f44Ssb 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
3570c1c61f44Ssb /* skip over the extra space for VLAN_TAG */
3571c1c61f44Ssb mp->b_rptr += 8;
3572c1c61f44Ssb
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
3601c1c61f44Ssb /*
3602c1c61f44Ssb * there is extra space alloc'd for VLAN_TAG
3603c1c61f44Ssb */
3604c1c61f44Ssb (void) vsw_vlan_frame_pretag(ldcp->ldc_port, VSW_VNETPORT, mp);
3605c1c61f44Ssb
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
vsw_process_err_pkt(vsw_ldc_t * ldcp,void * epkt,vio_msg_tag_t * tagp)3726f0ca1d9aSsb 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;
3731f0ca1d9aSsb 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
vsw_portsend(vsw_port_t * port,mblk_t * mp)3746da14cebeSEric Cheng vsw_portsend(vsw_port_t *port, mblk_t *mp)
374706db247cSraghuram {
3748da14cebeSEric Cheng mblk_t *mpt;
3749da14cebeSEric Cheng int count;
3750*6e472272SToomas Soome 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);
3756c1c61f44Ssb }
3757f0ca1d9aSsb return (status);
3758f0ca1d9aSsb }
3759f0ca1d9aSsb
3760f0ca1d9aSsb /*
3761f0ca1d9aSsb * Break up frames into 2 seperate chains: normal and
3762f0ca1d9aSsb * priority, based on the frame type. The number of
3763f0ca1d9aSsb * priority frames is also counted and returned.
3764f0ca1d9aSsb *
3765f0ca1d9aSsb * Params:
3766*6e472272SToomas Soome * vswp: pointer to the instance of vsw
3767f0ca1d9aSsb * np: head of packet chain to be broken
3768f0ca1d9aSsb * npt: tail of packet chain to be broken
3769f0ca1d9aSsb *
3770f0ca1d9aSsb * Returns:
3771f0ca1d9aSsb * np: head of normal data packets
3772f0ca1d9aSsb * npt: tail of normal data packets
3773f0ca1d9aSsb * hp: head of high priority packets
3774f0ca1d9aSsb * hpt: tail of high priority packets
3775f0ca1d9aSsb */
3776f0ca1d9aSsb static uint32_t
vsw_get_pri_packets(vsw_t * vswp,mblk_t ** np,mblk_t ** npt,mblk_t ** hp,mblk_t ** hpt)3777f0ca1d9aSsb vsw_get_pri_packets(vsw_t *vswp, mblk_t **np, mblk_t **npt,
3778*6e472272SToomas Soome mblk_t **hp, mblk_t **hpt)
3779f0ca1d9aSsb {
3780f0ca1d9aSsb mblk_t *tmp = NULL;
3781f0ca1d9aSsb mblk_t *smp = NULL;
3782f0ca1d9aSsb mblk_t *hmp = NULL; /* high prio pkts head */
3783f0ca1d9aSsb mblk_t *hmpt = NULL; /* high prio pkts tail */
3784f0ca1d9aSsb mblk_t *nmp = NULL; /* normal pkts head */
3785f0ca1d9aSsb mblk_t *nmpt = NULL; /* normal pkts tail */
3786f0ca1d9aSsb uint32_t count = 0;
3787f0ca1d9aSsb int i;
3788f0ca1d9aSsb struct ether_header *ehp;
3789f0ca1d9aSsb uint32_t num_types;
3790f0ca1d9aSsb uint16_t *types;
3791f0ca1d9aSsb
3792f0ca1d9aSsb tmp = *np;
3793f0ca1d9aSsb while (tmp != NULL) {
3794f0ca1d9aSsb
3795f0ca1d9aSsb smp = tmp;
3796f0ca1d9aSsb tmp = tmp->b_next;
3797f0ca1d9aSsb smp->b_next = NULL;
3798f0ca1d9aSsb smp->b_prev = NULL;
3799f0ca1d9aSsb
3800f0ca1d9aSsb ehp = (struct ether_header *)smp->b_rptr;
3801f0ca1d9aSsb num_types = vswp->pri_num_types;
3802f0ca1d9aSsb types = vswp->pri_types;
3803f0ca1d9aSsb for (i = 0; i < num_types; i++) {
3804f0ca1d9aSsb if (ehp->ether_type == types[i]) {
3805f0ca1d9aSsb /* high priority frame */
3806f0ca1d9aSsb
3807f0ca1d9aSsb if (hmp != NULL) {
3808f0ca1d9aSsb hmpt->b_next = smp;
3809f0ca1d9aSsb hmpt = smp;
3810f0ca1d9aSsb } else {
3811f0ca1d9aSsb hmp = hmpt = smp;
3812f0ca1d9aSsb }
3813f0ca1d9aSsb count++;
3814f0ca1d9aSsb break;
3815f0ca1d9aSsb }
3816f0ca1d9aSsb }
3817f0ca1d9aSsb if (i == num_types) {
3818f0ca1d9aSsb /* normal data frame */
3819f0ca1d9aSsb
3820f0ca1d9aSsb if (nmp != NULL) {
3821f0ca1d9aSsb nmpt->b_next = smp;
3822f0ca1d9aSsb nmpt = smp;
3823f0ca1d9aSsb } else {
3824f0ca1d9aSsb nmp = nmpt = smp;
3825f0ca1d9aSsb }
3826f0ca1d9aSsb }
3827f0ca1d9aSsb }
3828f0ca1d9aSsb
3829f0ca1d9aSsb *hp = hmp;
3830f0ca1d9aSsb *hpt = hmpt;
3831f0ca1d9aSsb *np = nmp;
3832f0ca1d9aSsb *npt = nmpt;
3833f0ca1d9aSsb
3834f0ca1d9aSsb return (count);
3835f0ca1d9aSsb }
3836f0ca1d9aSsb
3837f0ca1d9aSsb /*
3838f0ca1d9aSsb * Wrapper function to transmit normal and/or priority frames over the channel.
3839f0ca1d9aSsb */
3840f0ca1d9aSsb static int
vsw_ldctx_pri(void * arg,mblk_t * mp,mblk_t * mpt,uint32_t count)3841f0ca1d9aSsb vsw_ldctx_pri(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count)
3842f0ca1d9aSsb {
3843*6e472272SToomas Soome vsw_ldc_t *ldcp = (vsw_ldc_t *)arg;
3844f0ca1d9aSsb mblk_t *tmp;
3845f0ca1d9aSsb mblk_t *smp;
3846f0ca1d9aSsb mblk_t *hmp; /* high prio pkts head */
3847f0ca1d9aSsb mblk_t *hmpt; /* high prio pkts tail */
3848f0ca1d9aSsb mblk_t *nmp; /* normal pkts head */
3849f0ca1d9aSsb mblk_t *nmpt; /* normal pkts tail */
3850f0ca1d9aSsb uint32_t n = 0;
3851f0ca1d9aSsb vsw_t *vswp = ldcp->ldc_vswp;
3852f0ca1d9aSsb
3853f0ca1d9aSsb ASSERT(VSW_PRI_ETH_DEFINED(vswp));
3854f0ca1d9aSsb ASSERT(count != 0);
3855f0ca1d9aSsb
3856f0ca1d9aSsb nmp = mp;
3857f0ca1d9aSsb nmpt = mpt;
3858f0ca1d9aSsb
3859f0ca1d9aSsb /* gather any priority frames from the chain of packets */
3860f0ca1d9aSsb n = vsw_get_pri_packets(vswp, &nmp, &nmpt, &hmp, &hmpt);
3861f0ca1d9aSsb
3862f0ca1d9aSsb /* transmit priority frames */
3863f0ca1d9aSsb tmp = hmp;
3864f0ca1d9aSsb while (tmp != NULL) {
3865f0ca1d9aSsb smp = tmp;
3866f0ca1d9aSsb tmp = tmp->b_next;
3867f0ca1d9aSsb smp->b_next = NULL;
3868f0ca1d9aSsb vsw_ldcsend_pkt(ldcp, smp);
3869f0ca1d9aSsb }
3870f0ca1d9aSsb
3871f0ca1d9aSsb count -= n;
3872f0ca1d9aSsb
3873f0ca1d9aSsb if (count == 0) {
3874f0ca1d9aSsb /* no normal data frames to process */
3875f0ca1d9aSsb return (0);
3876f0ca1d9aSsb }
3877f0ca1d9aSsb
3878f0ca1d9aSsb return (vsw_ldctx(ldcp, nmp, nmpt, count));
3879f0ca1d9aSsb }
3880f0ca1d9aSsb
3881f0ca1d9aSsb /*
3882f0ca1d9aSsb * Wrapper function to transmit normal frames over the channel.
3883f0ca1d9aSsb */
3884f0ca1d9aSsb static int
vsw_ldctx(void * arg,mblk_t * mp,mblk_t * mpt,uint32_t count)3885f0ca1d9aSsb vsw_ldctx(void *arg, mblk_t *mp, mblk_t *mpt, uint32_t count)
3886f0ca1d9aSsb {
3887*6e472272SToomas Soome vsw_ldc_t *ldcp = (vsw_ldc_t *)arg;
3888f0ca1d9aSsb mblk_t *tmp = NULL;
3889f0ca1d9aSsb
3890f0ca1d9aSsb ASSERT(count != 0);
389106db247cSraghuram /*
3892f0ca1d9aSsb * If the TX thread is enabled, then queue the
3893f0ca1d9aSsb * ordinary frames and signal the tx thread.
389406db247cSraghuram */
389506db247cSraghuram if (ldcp->tx_thread != NULL) {
3896f0ca1d9aSsb
389706db247cSraghuram mutex_enter(&ldcp->tx_thr_lock);
3898f0ca1d9aSsb
3899f0ca1d9aSsb if ((ldcp->tx_cnt + count) >= vsw_max_tx_qcount) {
3900f0ca1d9aSsb /*
3901f0ca1d9aSsb * If we reached queue limit,
3902f0ca1d9aSsb * do not queue new packets,
3903f0ca1d9aSsb * drop them.
3904f0ca1d9aSsb */
3905f0ca1d9aSsb ldcp->ldc_stats.tx_qfull += count;
3906f0ca1d9aSsb mutex_exit(&ldcp->tx_thr_lock);
3907f0ca1d9aSsb freemsgchain(mp);
3908f0ca1d9aSsb goto exit;
3909f0ca1d9aSsb }
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 }
3918f0ca1d9aSsb 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
3929f0ca1d9aSsb exit:
3930f0ca1d9aSsb return (0);
3931f0ca1d9aSsb }
393206db247cSraghuram
3933f0ca1d9aSsb /*
3934f0ca1d9aSsb * This function transmits the frame in the payload of a raw data
3935f0ca1d9aSsb * (VIO_PKT_DATA) message. Thus, it provides an Out-Of-Band path to
3936f0ca1d9aSsb * send special frames with high priorities, without going through
3937f0ca1d9aSsb * the normal data path which uses descriptor ring mechanism.
3938f0ca1d9aSsb */
3939f0ca1d9aSsb static void
vsw_ldcsend_pkt(vsw_ldc_t * ldcp,mblk_t * mp)3940f0ca1d9aSsb vsw_ldcsend_pkt(vsw_ldc_t *ldcp, mblk_t *mp)
3941f0ca1d9aSsb {
3942f0ca1d9aSsb vio_raw_data_msg_t *pkt;
3943f0ca1d9aSsb mblk_t *bp;
3944f0ca1d9aSsb mblk_t *nmp = NULL;
39457bd3a2e2SSriharsha Basavapatna vio_mblk_t *vmp;
3946f0ca1d9aSsb caddr_t dst;
3947f0ca1d9aSsb uint32_t mblksz;
3948f0ca1d9aSsb uint32_t size;
3949f0ca1d9aSsb uint32_t nbytes;
3950f0ca1d9aSsb int rv;
3951f0ca1d9aSsb vsw_t *vswp = ldcp->ldc_vswp;
3952f0ca1d9aSsb vgen_stats_t *statsp = &ldcp->ldc_stats;
3953f0ca1d9aSsb
3954f0ca1d9aSsb if ((!(ldcp->lane_out.lstate & VSW_LANE_ACTIVE)) ||
3955*6e472272SToomas Soome (ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == 0)) {
3956f0ca1d9aSsb (void) atomic_inc_32(&statsp->tx_pri_fail);
3957f0ca1d9aSsb DWARN(vswp, "%s(%lld) status(%d) lstate(0x%llx), dropping "
3958f0ca1d9aSsb "packet\n", __func__, ldcp->ldc_id, ldcp->ldc_status,
3959f0ca1d9aSsb ldcp->lane_out.lstate);
3960f0ca1d9aSsb goto send_pkt_exit;
3961f0ca1d9aSsb }
3962f0ca1d9aSsb
3963f0ca1d9aSsb size = msgsize(mp);
3964f0ca1d9aSsb
3965f0ca1d9aSsb /* frame size bigger than available payload len of raw data msg ? */
3966f0ca1d9aSsb if (size > (size_t)(ldcp->msglen - VIO_PKT_DATA_HDRSIZE)) {
3967f0ca1d9aSsb (void) atomic_inc_32(&statsp->tx_pri_fail);
3968f0ca1d9aSsb DWARN(vswp, "%s(%lld) invalid size(%d)\n", __func__,
3969f0ca1d9aSsb ldcp->ldc_id, size);
3970f0ca1d9aSsb goto send_pkt_exit;
3971f0ca1d9aSsb }
3972f0ca1d9aSsb
3973f0ca1d9aSsb if (size < ETHERMIN)
3974f0ca1d9aSsb size = ETHERMIN;
3975f0ca1d9aSsb
3976f0ca1d9aSsb /* alloc space for a raw data message */
39777bd3a2e2SSriharsha Basavapatna vmp = vio_allocb(vswp->pri_tx_vmp);
39787bd3a2e2SSriharsha Basavapatna if (vmp == NULL) {
3979f0ca1d9aSsb (void) atomic_inc_32(&statsp->tx_pri_fail);
3980f0ca1d9aSsb DWARN(vswp, "vio_allocb failed\n");
3981f0ca1d9aSsb goto send_pkt_exit;
39827bd3a2e2SSriharsha Basavapatna } else {
39837bd3a2e2SSriharsha Basavapatna nmp = vmp->mp;
3984f0ca1d9aSsb }
3985f0ca1d9aSsb pkt = (vio_raw_data_msg_t *)nmp->b_rptr;
3986f0ca1d9aSsb
3987f0ca1d9aSsb /* copy frame into the payload of raw data message */
3988f0ca1d9aSsb dst = (caddr_t)pkt->data;
3989f0ca1d9aSsb for (bp = mp; bp != NULL; bp = bp->b_cont) {
3990f0ca1d9aSsb mblksz = MBLKL(bp);
3991f0ca1d9aSsb bcopy(bp->b_rptr, dst, mblksz);
3992f0ca1d9aSsb dst += mblksz;
3993f0ca1d9aSsb }
3994f0ca1d9aSsb
39957bd3a2e2SSriharsha Basavapatna vmp->state = VIO_MBLK_HAS_DATA;
39967bd3a2e2SSriharsha Basavapatna
3997f0ca1d9aSsb /* setup the raw data msg */
3998f0ca1d9aSsb pkt->tag.vio_msgtype = VIO_TYPE_DATA;
3999f0ca1d9aSsb pkt->tag.vio_subtype = VIO_SUBTYPE_INFO;
4000f0ca1d9aSsb pkt->tag.vio_subtype_env = VIO_PKT_DATA;
4001f0ca1d9aSsb pkt->tag.vio_sid = ldcp->local_session;
4002f0ca1d9aSsb nbytes = VIO_PKT_DATA_HDRSIZE + size;
4003f0ca1d9aSsb
4004f0ca1d9aSsb /* send the msg over ldc */
4005f0ca1d9aSsb rv = vsw_send_msg(ldcp, (void *)pkt, nbytes, B_TRUE);
4006f0ca1d9aSsb if (rv != 0) {
4007f0ca1d9aSsb (void) atomic_inc_32(&statsp->tx_pri_fail);
4008f0ca1d9aSsb DWARN(vswp, "%s(%lld) Error sending priority frame\n", __func__,
4009f0ca1d9aSsb ldcp->ldc_id);
4010f0ca1d9aSsb goto send_pkt_exit;
4011f0ca1d9aSsb }
4012f0ca1d9aSsb
4013f0ca1d9aSsb /* update stats */
4014f0ca1d9aSsb (void) atomic_inc_64(&statsp->tx_pri_packets);
4015f0ca1d9aSsb (void) atomic_add_64(&statsp->tx_pri_packets, size);
4016f0ca1d9aSsb
4017f0ca1d9aSsb send_pkt_exit:
4018f0ca1d9aSsb if (nmp != NULL)
4019f0ca1d9aSsb freemsg(nmp);
4020f0ca1d9aSsb 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
vsw_ldcsend(vsw_ldc_t * ldcp,mblk_t * mp,uint32_t retries)4032f0ca1d9aSsb vsw_ldcsend(vsw_ldc_t *ldcp, mblk_t *mp, uint32_t retries)
403306db247cSraghuram {
40347bd3a2e2SSriharsha Basavapatna int i;
40357bd3a2e2SSriharsha Basavapatna int rc;
40367bd3a2e2SSriharsha Basavapatna int status = 0;
40377bd3a2e2SSriharsha Basavapatna vsw_port_t *port = ldcp->ldc_port;
40387bd3a2e2SSriharsha Basavapatna 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) &&
4071c1c61f44Ssb ((VSW_VER_GTEQ(ldcp, 1, 2) &&
4072f0ca1d9aSsb (ldcp->lane_out.xfer_mode & VIO_DRING_MODE_V1_2)) ||
4073f0ca1d9aSsb ((VSW_VER_LT(ldcp, 1, 2) &&
4074f0ca1d9aSsb (ldcp->lane_out.xfer_mode == VIO_DRING_MODE_V1_0))))) {
407506db247cSraghuram
40767bd3a2e2SSriharsha Basavapatna /* Need to reclaim in TxDring mode. */
40777bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_TX_DRING) {
40787bd3a2e2SSriharsha Basavapatna rc = vsw_reclaim_dring(dp, dp->end_idx);
40797bd3a2e2SSriharsha Basavapatna }
408006db247cSraghuram
40817bd3a2e2SSriharsha Basavapatna } else {
40827bd3a2e2SSriharsha Basavapatna /*
40837bd3a2e2SSriharsha Basavapatna * If there is no dring or the xfer_mode is
40847bd3a2e2SSriharsha Basavapatna * set to DESC_MODE(ie., OBP), then simply break here.
40857bd3a2e2SSriharsha Basavapatna */
40867bd3a2e2SSriharsha Basavapatna break;
40877bd3a2e2SSriharsha Basavapatna }
408806db247cSraghuram
408906db247cSraghuram /*
40907bd3a2e2SSriharsha Basavapatna * Delay only if none were reclaimed
40917bd3a2e2SSriharsha Basavapatna * and its not the last retry.
409206db247cSraghuram */
40937bd3a2e2SSriharsha Basavapatna if ((rc == 0) && (i < retries)) {
40947bd3a2e2SSriharsha Basavapatna delay(drv_usectohz(vsw_ldc_tx_delay));
409506db247cSraghuram }
409606db247cSraghuram }
40977bd3a2e2SSriharsha Basavapatna freemsg(mp);
409806db247cSraghuram return (status);
409906db247cSraghuram }
410006db247cSraghuram
410106db247cSraghuram /*
410206db247cSraghuram * Send an in-band descriptor message over ldc.
410306db247cSraghuram */
410406db247cSraghuram static int
vsw_descrsend(vsw_ldc_t * ldcp,mblk_t * mp)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;
4117c1c61f44Ssb 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)) ||
4124*6e472272SToomas Soome (ldcp->ldc_status != LDC_UP) || (ldcp->ldc_handle == 0)) {
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);
4146c1c61f44Ssb 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
vsw_send_ver(void * arg)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
4229f0ca1d9aSsb if (vsw_obp_ver_proto_workaround == B_FALSE) {
4230f0ca1d9aSsb ver_msg.ver_major = vsw_versions[0].ver_major;
4231f0ca1d9aSsb ver_msg.ver_minor = vsw_versions[0].ver_minor;
4232f0ca1d9aSsb } else {
4233f0ca1d9aSsb /* use the major,minor that we've ack'd */
4234f0ca1d9aSsb lane_t *lpi = &ldcp->lane_in;
4235f0ca1d9aSsb ver_msg.ver_major = lpi->ver_major;
4236f0ca1d9aSsb ver_msg.ver_minor = lpi->ver_minor;
4237f0ca1d9aSsb }
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
vsw_send_attr(vsw_ldc_t * ldcp)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
vsw_send_dring_info(vsw_ldc_t * ldcp)428906db247cSraghuram vsw_send_dring_info(vsw_ldc_t *ldcp)
429006db247cSraghuram {
42917bd3a2e2SSriharsha Basavapatna int msgsize;
42927bd3a2e2SSriharsha Basavapatna void *msg;
42937bd3a2e2SSriharsha Basavapatna 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;
430206db247cSraghuram
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) {
43107bd3a2e2SSriharsha Basavapatna return;
43117bd3a2e2SSriharsha Basavapatna }
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
vsw_send_rdx(vsw_ldc_t * ldcp)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 *
vsw_del_addr(uint8_t devtype,void * arg,uint64_t addr)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) {
43887bd3a2e2SSriharsha Basavapatna /* list head */
43897bd3a2e2SSriharsha Basavapatna if (devtype == VSW_VNETPORT)
43907bd3a2e2SSriharsha Basavapatna port->mcap = curr_p->nextp;
43917bd3a2e2SSriharsha Basavapatna else
43927bd3a2e2SSriharsha Basavapatna vswp->mcap = curr_p->nextp;
43937bd3a2e2SSriharsha Basavapatna } else {
43947bd3a2e2SSriharsha Basavapatna prev_p->nextp = curr_p->nextp;
439506db247cSraghuram }
43967bd3a2e2SSriharsha Basavapatna break;
43977bd3a2e2SSriharsha Basavapatna } else {
43987bd3a2e2SSriharsha Basavapatna prev_p = curr_p;
43997bd3a2e2SSriharsha Basavapatna curr_p = curr_p->nextp;
440006db247cSraghuram }
440106db247cSraghuram }
440206db247cSraghuram
44037bd3a2e2SSriharsha Basavapatna if (devtype == VSW_VNETPORT)
44047bd3a2e2SSriharsha Basavapatna mutex_exit(&port->mca_lock);
44057bd3a2e2SSriharsha Basavapatna else
44067bd3a2e2SSriharsha Basavapatna mutex_exit(&vswp->mca_lock);
440706db247cSraghuram
44087bd3a2e2SSriharsha Basavapatna D1(NULL, "%s: exit", __func__);
440906db247cSraghuram
44107bd3a2e2SSriharsha Basavapatna return (curr_p);
441106db247cSraghuram }
441206db247cSraghuram
441306db247cSraghuram /*
44147bd3a2e2SSriharsha Basavapatna * Create a ring consisting of just a private portion and link
44157bd3a2e2SSriharsha Basavapatna * it into the list of rings for the outbound lane.
441606db247cSraghuram *
44177bd3a2e2SSriharsha Basavapatna * These type of rings are used primarily for temporary data
44187bd3a2e2SSriharsha Basavapatna * storage (i.e. as data buffers).
441906db247cSraghuram */
44207bd3a2e2SSriharsha Basavapatna void
vsw_create_privring(vsw_ldc_t * ldcp)44217bd3a2e2SSriharsha Basavapatna vsw_create_privring(vsw_ldc_t *ldcp)
442206db247cSraghuram {
44237bd3a2e2SSriharsha Basavapatna dring_info_t *dp;
44247bd3a2e2SSriharsha Basavapatna vsw_t *vswp = ldcp->ldc_vswp;
442506db247cSraghuram
44267bd3a2e2SSriharsha Basavapatna D1(vswp, "%s(%lld): enter", __func__, ldcp->ldc_id);
442706db247cSraghuram
44287bd3a2e2SSriharsha Basavapatna dp = kmem_zalloc(sizeof (dring_info_t), KM_SLEEP);
44297bd3a2e2SSriharsha Basavapatna 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
44337bd3a2e2SSriharsha Basavapatna /* no public section */
44347bd3a2e2SSriharsha Basavapatna dp->pub_addr = NULL;
44357bd3a2e2SSriharsha Basavapatna 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)) {
44407bd3a2e2SSriharsha Basavapatna DERR(vswp, "%s: setup of ring failed", __func__);
44417bd3a2e2SSriharsha Basavapatna vsw_destroy_tx_dring(ldcp);
44427bd3a2e2SSriharsha Basavapatna return;
444306db247cSraghuram }
444406db247cSraghuram
44457bd3a2e2SSriharsha Basavapatna /* haven't used any descriptors yet */
44467bd3a2e2SSriharsha Basavapatna dp->end_idx = 0;
44477bd3a2e2SSriharsha Basavapatna dp->restart_reqd = B_TRUE;
444806db247cSraghuram
44497bd3a2e2SSriharsha Basavapatna 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
vsw_set_lane_attr(vsw_t * vswp,lane_t * lp)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
4466c1c61f44Ssb lp->mtu = vswp->max_frame_size;
446706db247cSraghuram lp->addr_type = ADDR_TYPE_MAC;
4468f0ca1d9aSsb lp->xfer_mode = VIO_DRING_MODE_V1_0;
446906db247cSraghuram lp->ack_freq = 0; /* for shared mode */
4470f0ca1d9aSsb 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 *
vsw_map_dring(vsw_ldc_t * ldcp,void * pkt)44777bd3a2e2SSriharsha Basavapatna vsw_map_dring(vsw_ldc_t *ldcp, void *pkt)
447806db247cSraghuram {
44797bd3a2e2SSriharsha Basavapatna dring_info_t *dp = NULL;
44807bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_out;
448106db247cSraghuram
44827bd3a2e2SSriharsha Basavapatna if (lp->dring_mode == VIO_RX_DRING_DATA) {
44837bd3a2e2SSriharsha Basavapatna /*
44847bd3a2e2SSriharsha Basavapatna * In RxDringData mode, dring that we map in
44857bd3a2e2SSriharsha Basavapatna * becomes our transmit descriptor ring.
44867bd3a2e2SSriharsha Basavapatna */
44877bd3a2e2SSriharsha Basavapatna dp = vsw_map_tx_dring(ldcp, pkt);
44887bd3a2e2SSriharsha 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);
449406db247cSraghuram }
44957bd3a2e2SSriharsha Basavapatna return (dp);
44967bd3a2e2SSriharsha Basavapatna }
449706db247cSraghuram
44987bd3a2e2SSriharsha Basavapatna /*
44997bd3a2e2SSriharsha Basavapatna * Common dring mapping function used in both TxDring and RxDringData modes.
45007bd3a2e2SSriharsha Basavapatna */
45017bd3a2e2SSriharsha Basavapatna dring_info_t *
vsw_map_dring_cmn(vsw_ldc_t * ldcp,vio_dring_reg_msg_t * dring_pkt)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;
450806db247cSraghuram
450906db247cSraghuram /*
45107bd3a2e2SSriharsha Basavapatna * If the dring params are unacceptable then we NACK back.
451106db247cSraghuram */
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);
451806db247cSraghuram }
451906db247cSraghuram
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
452706db247cSraghuram /*
45287bd3a2e2SSriharsha Basavapatna * Note: should only get one cookie. Enforced in
45297bd3a2e2SSriharsha Basavapatna * the ldc layer.
453006db247cSraghuram */
45317bd3a2e2SSriharsha Basavapatna bcopy(&dring_pkt->cookie[0], &dp->dring_cookie[0],
45327bd3a2e2SSriharsha Basavapatna sizeof (ldc_mem_cookie_t));
453306db247cSraghuram
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;
453906db247cSraghuram }
454006db247cSraghuram
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;
454706db247cSraghuram
45487bd3a2e2SSriharsha Basavapatna /* cache the dring mtype */
45497bd3a2e2SSriharsha Basavapatna dp->dring_mtype = minfo.mtype;
455006db247cSraghuram
45517bd3a2e2SSriharsha Basavapatna /* no private section as we are importing */
45527bd3a2e2SSriharsha Basavapatna dp->priv_addr = NULL;
455306db247cSraghuram
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++;
455906db247cSraghuram
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;
456606db247cSraghuram
45677bd3a2e2SSriharsha Basavapatna return (dp);
45687bd3a2e2SSriharsha Basavapatna fail:
4569*6e472272SToomas Soome if (dp->dring_handle != 0) {
45707bd3a2e2SSriharsha Basavapatna (void) ldc_mem_dring_unmap(dp->dring_handle);
457106db247cSraghuram }
45727bd3a2e2SSriharsha Basavapatna kmem_free(dp, sizeof (*dp));
45737bd3a2e2SSriharsha Basavapatna return (NULL);
457406db247cSraghuram }
457506db247cSraghuram
457606db247cSraghuram /*
45777bd3a2e2SSriharsha Basavapatna * Unmap the descriptor ring exported by the peer.
457806db247cSraghuram */
45797bd3a2e2SSriharsha Basavapatna static void
vsw_unmap_dring(vsw_ldc_t * ldcp)45807bd3a2e2SSriharsha Basavapatna vsw_unmap_dring(vsw_ldc_t *ldcp)
458106db247cSraghuram {
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);
458606db247cSraghuram } else {
45877bd3a2e2SSriharsha Basavapatna vsw_unmap_rx_dring(ldcp);
458806db247cSraghuram }
458906db247cSraghuram }
459006db247cSraghuram
459106db247cSraghuram /*
45927bd3a2e2SSriharsha Basavapatna * Map the shared memory data buffer area exported by the peer.
45937bd3a2e2SSriharsha Basavapatna * Used in RxDringData mode only.
459406db247cSraghuram */
459506db247cSraghuram static int
vsw_map_data(vsw_ldc_t * ldcp,dring_info_t * dp,void * pkt)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;
460334f94fbcSWENTAO YANG ldc_mem_info_t minfo;
46047bd3a2e2SSriharsha Basavapatna
46057bd3a2e2SSriharsha Basavapatna /* skip over dring cookies */
46067bd3a2e2SSriharsha Basavapatna ASSERT(msg->ncookies == 1);
46077bd3a2e2SSriharsha Basavapatna buf += (msg->ncookies * sizeof (ldc_mem_cookie_t));
46087bd3a2e2SSriharsha Basavapatna
46097bd3a2e2SSriharsha Basavapatna emsg = (vio_dring_reg_ext_msg_t *)buf;
46107bd3a2e2SSriharsha Basavapatna if (emsg->data_ncookies > VNET_DATA_AREA_COOKIES) {
46117bd3a2e2SSriharsha Basavapatna return (1);
46127bd3a2e2SSriharsha Basavapatna }
46137bd3a2e2SSriharsha Basavapatna
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);
463706db247cSraghuram return (1);
463806db247cSraghuram }
463906db247cSraghuram
464034f94fbcSWENTAO YANG /* get the map info */
464134f94fbcSWENTAO YANG rv = ldc_mem_info(dp->data_handle, &minfo);
464234f94fbcSWENTAO YANG if (rv != 0) {
464334f94fbcSWENTAO YANG cmn_err(CE_WARN, "ldc_mem_info failed\n");
464434f94fbcSWENTAO YANG DWARN(vswp, "%s (%lld) ldc_mem_info() failed: %d\n",
464534f94fbcSWENTAO YANG __func__, ldcp->ldc_id, rv);
464634f94fbcSWENTAO YANG return (1);
464734f94fbcSWENTAO YANG }
464834f94fbcSWENTAO YANG
464934f94fbcSWENTAO YANG if (minfo.mtype != LDC_DIRECT_MAP) {
465034f94fbcSWENTAO YANG DWARN(vswp, "%s (%lld) mtype(%d) is not direct map\n",
465134f94fbcSWENTAO YANG __func__, ldcp->ldc_id, minfo.mtype);
465234f94fbcSWENTAO YANG return (1);
465334f94fbcSWENTAO YANG }
465434f94fbcSWENTAO 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
vsw_free_lane_resources(vsw_ldc_t * ldcp,uint64_t dir)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;
4687f0ca1d9aSsb lp->seq_num = VNET_ISS;
468806db247cSraghuram
46897bd3a2e2SSriharsha Basavapatna if (dir == INBOUND) {
46907bd3a2e2SSriharsha Basavapatna /* Unmap the remote dring which is imported from the peer */
46917bd3a2e2SSriharsha Basavapatna vsw_unmap_dring(ldcp);
46927bd3a2e2SSriharsha Basavapatna } 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 */
470306db247cSraghuram static void
vsw_destroy_dring(vsw_ldc_t * ldcp)47047bd3a2e2SSriharsha Basavapatna vsw_destroy_dring(vsw_ldc_t *ldcp)
470506db247cSraghuram {
47067bd3a2e2SSriharsha Basavapatna lane_t *lp = &ldcp->lane_out;
47076f09f0feSWENTAO YANG
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);
47126f09f0feSWENTAO YANG }
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
vsw_ldc_tx_worker(void * arg)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;
4756f0ca1d9aSsb 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
vsw_stop_tx_thread(vsw_ldc_t * ldcp)478206db247cSraghuram vsw_stop_tx_thread(vsw_ldc_t *ldcp)
478306db247cSraghuram {
47846f09f0feSWENTAO YANG kt_did_t tid = 0;
47856f09f0feSWENTAO YANG 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
480734f94fbcSWENTAO YANG static int
vsw_mapin_avail(vsw_ldc_t * ldcp)480834f94fbcSWENTAO YANG vsw_mapin_avail(vsw_ldc_t *ldcp)
480934f94fbcSWENTAO YANG {
481034f94fbcSWENTAO YANG int rv;
481134f94fbcSWENTAO YANG ldc_info_t info;
481234f94fbcSWENTAO YANG uint64_t mapin_sz_req;
481334f94fbcSWENTAO YANG uint64_t dblk_sz;
481434f94fbcSWENTAO YANG vsw_t *vswp = ldcp->ldc_vswp;
481534f94fbcSWENTAO YANG
481634f94fbcSWENTAO YANG rv = ldc_info(ldcp->ldc_handle, &info);
481734f94fbcSWENTAO YANG if (rv != 0) {
481834f94fbcSWENTAO YANG return (B_FALSE);
481934f94fbcSWENTAO YANG }
482034f94fbcSWENTAO YANG
482134f94fbcSWENTAO YANG dblk_sz = RXDRING_DBLK_SZ(vswp->max_frame_size);
482234f94fbcSWENTAO YANG mapin_sz_req = (VSW_RXDRING_NRBUFS * dblk_sz);
482334f94fbcSWENTAO YANG
482434f94fbcSWENTAO YANG if (info.direct_map_size_max >= mapin_sz_req) {
482534f94fbcSWENTAO YANG return (B_TRUE);
482634f94fbcSWENTAO YANG }
482734f94fbcSWENTAO YANG
482834f94fbcSWENTAO YANG return (B_FALSE);
482934f94fbcSWENTAO YANG }
483034f94fbcSWENTAO YANG
483106db247cSraghuram /*
483206db247cSraghuram * Debugging routines
483306db247cSraghuram */
483406db247cSraghuram static void
display_state(void)483506db247cSraghuram display_state(void)
483606db247cSraghuram {
483706db247cSraghuram vsw_t *vswp;
483806db247cSraghuram vsw_port_list_t *plist;
4839*6e472272SToomas Soome vsw_port_t *port;
4840*6e472272SToomas Soome vsw_ldc_t *ldcp;
4841*6e472272SToomas Soome 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",
4853c1c61f44Ssb port->p_instance, port->num_ldcs);
48547bd3a2e2SSriharsha Basavapatna ldcp = port->ldcp;
48557bd3a2e2SSriharsha Basavapatna cmn_err(CE_CONT, "chan %lu : dev %d : "
48567bd3a2e2SSriharsha Basavapatna "status %d : phase %u\n",
48577bd3a2e2SSriharsha Basavapatna ldcp->ldc_id, ldcp->dev_class,
48587bd3a2e2SSriharsha Basavapatna ldcp->ldc_status, ldcp->hphase);
48597bd3a2e2SSriharsha Basavapatna cmn_err(CE_CONT, "chan %lu : lsession %lu : "
48607bd3a2e2SSriharsha Basavapatna "psession %lu\n", ldcp->ldc_id,
48617bd3a2e2SSriharsha Basavapatna ldcp->local_session, ldcp->peer_session);
48627bd3a2e2SSriharsha Basavapatna
48637bd3a2e2SSriharsha Basavapatna cmn_err(CE_CONT, "Inbound lane:\n");
48647bd3a2e2SSriharsha Basavapatna display_lane(&ldcp->lane_in);
48657bd3a2e2SSriharsha Basavapatna cmn_err(CE_CONT, "Outbound lane:\n");
48667bd3a2e2SSriharsha Basavapatna display_lane(&ldcp->lane_out);
486706db247cSraghuram }
486806db247cSraghuram RW_EXIT(&plist->lockrw);
486906db247cSraghuram }
487006db247cSraghuram cmn_err(CE_NOTE, "***** system state *****");
487106db247cSraghuram }
487206db247cSraghuram
487306db247cSraghuram static void
display_lane(lane_t * lp)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");
48857bd3a2e2SSriharsha Basavapatna cmn_err(CE_CONT, "\tnum_desc %u : dsize %u\n",
48867bd3a2e2SSriharsha Basavapatna drp->num_descriptors, drp->descriptor_size);
48877bd3a2e2SSriharsha Basavapatna cmn_err(CE_CONT, "\thandle 0x%lx\n", drp->dring_handle);
48887bd3a2e2SSriharsha Basavapatna cmn_err(CE_CONT, "\tpub_addr 0x%lx : priv_addr 0x%lx\n",
48897bd3a2e2SSriharsha Basavapatna (uint64_t)drp->pub_addr, (uint64_t)drp->priv_addr);
48907bd3a2e2SSriharsha Basavapatna cmn_err(CE_CONT, "\tident 0x%lx : end_idx %lu\n",
48917bd3a2e2SSriharsha Basavapatna drp->ident, drp->end_idx);
48927bd3a2e2SSriharsha Basavapatna display_ring(drp);
489306db247cSraghuram }
489406db247cSraghuram
489506db247cSraghuram static void
display_ring(dring_info_t * dringp)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
dump_flags(uint64_t state)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